diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..412eeda78dc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..6dae74742b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Icon must ends with two \r. +Icon + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes diff --git a/Engine Changes.txt b/Engine Changes.txt new file mode 100644 index 00000000000..d4976c10116 --- /dev/null +++ b/Engine Changes.txt @@ -0,0 +1,26 @@ +Feel free to add to this list anything that comes to mind that would be related to modifying the COP source. +If you've implemented a given feature already by experimenting on the CS source, put a star next to it. + +1) Convert to 64-bit (to allow more than 4gb RAM to be used) +2) Multi-thread the engine for up to 4 cores +3) Solve stuttering problem (likely due to LuaJit. Solution would be to upgrade it to newest version and then rewrite all the lua files to conform with it) +4) Solve problem with COP sometimes not loading correctly upon launch on some systems as well as not always exiting properly and still running as a background task. +5) Get BugTrap to spit out better error logs +6) Solve problem with stealth mechanics +7) Fix shadow bug in DX10 where a big world shadow appears and disappears depending on what angle you are in relation to the sun +8) Eliminate usage of precompiled shaders so they can all be modified at will like in SOC +9) When DX12 comes out, add DX12 renderer (doesn't sound like it has much new graphics-wise, but it is crazy faster than DX11) +10) Allow more than 2 ammo types per weapon without screwed up/missing UI ammo count +11) Allow environment mapping for weapons not on DX8 (I found the file responsible, just need someone to implement it) +12) Allow .seq files to be given a stop frame/point (animated blood puddles underneath bodies anyone?) +13) Allow wallmarks to have bump and bump# usage (for glossy blood and for bullet-holes that do things like take small chunks out of cement) +14) Better tessellation in DX11/12. Modify current method plus implement artist controlled displacement mapping or something else that allows more control over usage +15) 3D shell casings (I know this can sorta be done in only LUA, but it would be simpler just to hardcode it) +16) Replace current shadowing system with one with better antialiasing and less "noise" when a character is in an interior and moving around + + +SDK +1) Less errors and crashes, loads of these. +2) Visible level-loaded decals and the ability to see decals that aren't just 'wallmarkblend' type. +3) 'Undo' function that doesn't take minutes to do and actually works properly. +4) Better performance \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000000..ad3cdb347d6 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +Call of Pripyat expansion +========================= + +This repository will soon contain the Stalker: Call of Pripyat source code version 1.6.02. + +In the meantime, it is a place to share ideas on what to implement, gather people that +want to work on the engine, and experiment on the currently released CS source code. \ No newline at end of file diff --git a/all_editors.bpg b/all_editors.bpg new file mode 100644 index 00000000000..79a8b2348d8 --- /dev/null +++ b/all_editors.bpg @@ -0,0 +1,54 @@ +#------------------------------------------------------------------------------ +VERSION = BWS.01 +#------------------------------------------------------------------------------ +!ifndef ROOT +ROOT = $(MAKEDIR)\.. +!endif +#------------------------------------------------------------------------------ +MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$** +DCC = $(ROOT)\bin\dcc32.exe $** +BRCC = $(ROOT)\bin\brcc32.exe $** +#------------------------------------------------------------------------------ +PROJECTS = xrCoreB.dll xrSoundB.dll xrParticlesB.dll xrEPropsB.dll xrECoreB.dll \ + ActorEditor.exe ParticleEditor.exe ShaderEditor.exe LevelEditor.exe +#------------------------------------------------------------------------------ +default: $(PROJECTS) +#------------------------------------------------------------------------------ + +xrCoreB.dll: xrCore\xrCoreB.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +xrSoundB.dll: xrSound\xrSoundB.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +xrParticlesB.dll: xrParticles\xrParticlesB.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +xrEPropsB.dll: editors\xrEProps\xrEPropsB.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +xrECoreB.dll: editors\ECore\xrECoreB.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +ActorEditor.exe: editors\ActorEditor\ActorEditor.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +ParticleEditor.exe: editors\ParticleEditor\ParticleEditor.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +ShaderEditor.exe: editors\ShaderEditor\ShaderEditor.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + +LevelEditor.exe: editors\LevelEditor\LevelEditor.bpr + $(ROOT)\bin\bpr2mak $** + $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak + + diff --git a/all_editors.dsk b/all_editors.dsk new file mode 100644 index 00000000000..67f6d8b60cd --- /dev/null +++ b/all_editors.dsk @@ -0,0 +1,449 @@ +[Closed Files] +File_0=SourceModule,'e:\program files\borland\cbuilder6\include\stl\_alloc.h',0,1,80,1,96,0,0 +File_1=SourceModule,'e:\program files\borland\cbuilder6\include\stl\_set.h',0,1,157,97,168,0,0 +File_2=SourceModule,'X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\ESound_Source.cpp',0,1,1,1,1,0,0 +File_3=SourceModule,'X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\SpawnPoint.cpp',0,1,677,55,704,0,0 +File_4=SourceModule,'X:\stalker_addon\sources\trunk\xrcore\_vector3d.h',0,1,1,1,23,0,0 +File_5=SourceModule,'X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\glow.cpp',0,1,1,1,1,0,0 +File_6=SourceModule,'X:\stalker_addon\sources\trunk\editors\LevelEditor\EditLibrary.cpp',0,1,93,29,109,0,0 +File_7=SourceModule,'X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\GroupObjectUtils.cpp',0,1,170,22,185,0,0 +File_8=SourceModule,'X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\EParticlesObject.cpp',0,1,143,1,155,0,0 + +[Modules] +Module0=X:\stalker_addon\sources\trunk\editors\ECore\Editor\ImageEditor.cpp +Module1=e:\program files\borland\cbuilder6\include\stl\_algobase.c +Module2=X:\stalker_addon\sources\trunk\xrCore\_math.cpp +Module3=X:\stalker_addon\sources\trunk\xrcore\LocatorAPI_defs.h +Module4=X:\stalker_addon\sources\trunk\editors\ECore\Editor\EditObjectEditor.cpp +Module5=X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorTools.cpp +Module6=X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorMain.cpp +Module7=X:\stalker_addon\sources\trunk\Layers\xrRender\SkeletonX.cpp +Count=8 +EditWindowCount=1 + +[X:\stalker_addon\sources\trunk\editors\ECore\Editor\ImageEditor.cpp] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[e:\program files\borland\cbuilder6\include\stl\_algobase.c] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\xrCore\_math.cpp] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\xrcore\LocatorAPI_defs.h] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ECore\Editor\EditObjectEditor.cpp] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorTools.cpp] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorMain.cpp] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\Layers\xrRender\SkeletonX.cpp] +ModuleType=SourceModule +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\all_editors.bpg] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\xrCore\xrCoreB.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\xrSound\xrSoundB.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\xrParticles\xrParticlesB.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\xrEProps\xrEPropsB.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ECore\xrECoreB.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ActorEditor\ActorEditor.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ActorEditor\ActorEditor.todo] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ParticleEditor\ParticleEditor.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ParticleEditor\ParticleEditor.todo] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ShaderEditor\ShaderEditor.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\ShaderEditor\ShaderEditor.todo] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\LevelEditor\LevelEditor.bpr] +FormState=0 +FormOnTop=0 + +[X:\stalker_addon\sources\trunk\editors\LevelEditor\LevelEditor.todo] +FormState=0 +FormOnTop=0 + +[EditWindow0] +ViewCount=8 +CurrentView=5 +View0=0 +View1=1 +View2=2 +View3=3 +View4=4 +View5=5 +View6=6 +View7=7 +CodeExplorer=CodeExplorer@EditWindow0 +MessageView=MessageView@EditWindow0 +ClassHierarchy=ClassHierarchy@EditWindow0 +Create=1 +Visible=1 +State=2 +Left=1283 +Top=124 +Width=309 +Height=863 +MaxLeft=-4 +MaxTop=78 +MaxWidth=1288 +MaxHeight=950 +ClientWidth=1280 +ClientHeight=916 +LeftPanelSize=0 +LeftPanelClients=CodeExplorer@EditWindow0 +LeftPanelData=00000400010000000C000000436F64654578706C6F726572000000000000000000000000000000000001000000000000000000000000FFFFFFFF +RightPanelSize=0 +BottomPanelSize=449 +BottomPanelClients=ProjectManager,MessageView@EditWindow0 +BottomPanelData=0000040000000000000500000000000002C1010000000000000100000000560200001200000050726F6A6563744D616E61676572466F726D0100000000000500000B0000004D6573736167655669657701000000000005000000000000FFFFFFFF + +[View0] +Module=X:\stalker_addon\sources\trunk\xrCore\_math.cpp +CursorX=32 +CursorY=20 +TopLine=19 +LeftCol=1 + +[View1] +Module=X:\stalker_addon\sources\trunk\Layers\xrRender\SkeletonX.cpp +CursorX=1 +CursorY=1 +TopLine=1 +LeftCol=1 + +[View2] +Module=X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorMain.cpp +CursorX=1 +CursorY=515 +TopLine=493 +LeftCol=1 + +[View3] +Module=X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorTools.cpp +CursorX=98 +CursorY=1105 +TopLine=1092 +LeftCol=1 + +[View4] +Module=X:\stalker_addon\sources\trunk\editors\ECore\Editor\EditObjectEditor.cpp +CursorX=21 +CursorY=201 +TopLine=192 +LeftCol=1 + +[View5] +Module=X:\stalker_addon\sources\trunk\editors\ECore\Editor\ImageEditor.cpp +CursorX=27 +CursorY=278 +TopLine=266 +LeftCol=1 + +[View6] +Module=e:\program files\borland\cbuilder6\include\stl\_algobase.c +CursorX=1 +CursorY=173 +TopLine=157 +LeftCol=1 + +[View7] +Module=X:\stalker_addon\sources\trunk\xrcore\LocatorAPI_defs.h +CursorX=6 +CursorY=68 +TopLine=43 +LeftCol=1 + +[Watches] +Count=1 +Watch0='this',256,0,18,1,0,'Watches' + +[Breakpoints] +Count=25 +Breakpoint0='D:\STALKER\sources\engine\editors\ECore\Editor\EditObjectSkin.cpp',22,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint1='D:\STALKER\sources\engine\Layers\xrRender\DetailManager_VS.cpp',306,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint2='D:\STALKER\sources\engine\Layers\xrRender\DetailManager_VS.cpp',221,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint3='D:\STALKER\sources\engine\editors\ActorEditor\UI_ActorTools.cpp',430,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint4='D:\STALKER\sources\engine\editors\LevelEditor\Edit\SpawnPoint.h',78,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint5='D:\STALKER\sources\engine\editors\LevelEditor\Edit\SpawnPoint.cpp',763,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint6='D:\STALKER\sources\engine\editors\LevelEditor\Edit\UI_LevelTools.h',78,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint7='D:\STALKER\sources\engine\editors\ECore\Editor\D3DUtils.cpp',712,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint8='D:\STALKER\sources\engine\editors\ECore\Editor\D3DUtils.cpp',679,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint9='D:\STALKER\sources\engine\editors\ECore\Editor\UI_MainCommand.cpp',315,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint10='X:\stalker_addon\sources\trunk\editors\ECore\Editor\EditObjectIO.cpp',434,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint11='X:\stalker_addon\sources\trunk\editors\ECore\Editor\EditObjectEditor.cpp',342,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint12='X:\stalker_addon\sources\trunk\editors\ECore\Editor\ExportSkeleton.cpp',802,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint13='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\BuilderRemote.cpp',1463,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint14='X:\stalker_addon\sources\trunk\editors\ActorEditor\UI_ActorToolsMotions.cpp',149,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint15='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\CustomObjectAnimation.cpp',43,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint16='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\CustomObjectLE.cpp',105,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint17='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\CustomObjectLE.cpp',128,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint18='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\CustomObjectLE.cpp',137,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint19='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\ESceneObjectControls.cpp',62,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint20='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\GroupObjectUtils.cpp',76,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint21='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\GroupObjectUtils.cpp',110,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint22='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\GroupObjectUtils.cpp',145,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint23='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\GroupObjectUtils.cpp',185,'',0,1,'',1,0,0,'',1,'','','' +Breakpoint24='X:\stalker_addon\sources\trunk\editors\LevelEditor\Edit\SpawnPoint.cpp',614,'',0,1,'',1,0,0,'',1,'','','' + +[AddressBreakpoints] +Count=0 + +[Main Window] +Create=1 +Visible=1 +State=2 +Left=363 +Top=30 +Width=123 +Height=86 +MaxLeft=-4 +MaxTop=-4 +MaxWidth=1288 +MaxHeight=86 +ClientWidth=1280 +ClientHeight=52 + +[ProjectManager] +Create=1 +Visible=1 +State=0 +Left=12 +Top=0 +Width=582 +Height=449 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=582 +ClientHeight=449 +TBDockHeight=449 +LRDockWidth=438 +Dockable=1 + +[CPUWindow] +Create=1 +Visible=0 +State=0 +Left=1653 +Top=335 +Width=533 +Height=353 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=525 +ClientHeight=319 +DumpPane=79 +DisassemblyPane=187 +RegisterPane=231 +FlagPane=64 + +[WatchWindow] +Create=1 +Visible=0 +State=0 +Left=1709 +Top=437 +Width=421 +Height=149 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=413 +ClientHeight=123 +TBDockHeight=149 +LRDockWidth=421 +Dockable=1 + +[CallStackWindow] +Create=1 +Visible=0 +State=0 +Left=1727 +Top=319 +Width=651 +Height=278 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=643 +ClientHeight=252 +TBDockHeight=278 +LRDockWidth=651 +Dockable=1 + +[AlignmentPalette] +Create=1 +Visible=0 +State=0 +Left=200 +Top=107 +Width=156 +Height=84 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=150 +ClientHeight=60 + +[PropertyInspector] +Create=1 +Visible=0 +State=0 +Left=71 +Top=338 +Width=297 +Height=509 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=289 +ClientHeight=483 +TBDockHeight=509 +LRDockWidth=190 +Dockable=1 +SplitPos=85 +ArrangeBy=Name +SelectedItem= +ExpandedItems= +HiddenCategories= + +[ObjectTree] +Create=1 +Visible=0 +State=0 +Left=0 +Top=105 +Width=190 +Height=344 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=182 +ClientHeight=318 +TBDockHeight=344 +LRDockWidth=190 +Dockable=1 + +[CodeguardLog] +Create=1 +Visible=0 +State=0 +Left=191 +Top=108 +Width=448 +Height=190 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=440 +ClientHeight=164 +TBDockHeight=190 +LRDockWidth=448 +Dockable=1 + +[ClassHierarchy@EditWindow0] +Create=1 +Visible=0 +State=0 +Left=218 +Top=113 +Width=403 +Height=284 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=395 +ClientHeight=258 +TBDockHeight=284 +LRDockWidth=403 +Dockable=1 +TreeWidth=121 +Col1Width=120 +Col2Width=120 + +[CodeExplorer@EditWindow0] +Create=1 +Visible=0 +State=0 +Left=0 +Top=12 +Width=170 +Height=736 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=170 +ClientHeight=736 +TBDockHeight=388 +LRDockWidth=170 +Dockable=1 +ClassViewDisplayMode=0 + +[MessageView@EditWindow0] +Create=1 +Visible=1 +State=0 +Left=610 +Top=0 +Width=670 +Height=449 +MaxLeft=-1 +MaxTop=-1 +ClientWidth=670 +ClientHeight=449 +TBDockHeight=449 +LRDockWidth=443 +Dockable=1 + +[DockHosts] +DockHostCount=0 + +[ActiveProject] +ActiveProject=6 + diff --git a/engine.sln b/engine.sln new file mode 100644 index 00000000000..a7e3338bb34 --- /dev/null +++ b/engine.sln @@ -0,0 +1,2055 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bugtrap", "bugtrap", "{6BE93BFF-E2B4-43F2-ADBB-F8971E43CD5A}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dedicated", "dedicated", "{3FC858CB-4888-42FF-ABC5-82DAECB59C2C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd party", "3rd party", "{2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{A074ECE0-24F4-497F-99BD-AD45D5C51382}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BugTrap", "3rd party\bugtrap\bugtrap\BugTrap.vcproj", "{E8CF1ADA-264A-4127-86C2-FD7057D3792C}" + ProjectSection(ProjectDependencies) = postProject + {893279CB-0805-405F-B484-9BB728A18261} = {893279CB-0805-405F-B484-9BB728A18261} + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} = {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rd party\bugtrap\zlib\zlib.vcproj", "{CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ode", "3rd party\ode\contrib\msvc7\ode_default\default.vcproj", "{1BF75FEB-87DD-486C-880B-227987D191C2}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openal32", "3rd party\openal\OpenAL-Windows\Router\Router.vcproj", "{566551F4-4EF1-4CB4-A131-F982E7606907}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrD3D9-Null", "xrD3D9-Null\xrD3D9-Null.vcproj", "{0899B131-F1D4-4876-9BA1-67AC821DB9E1}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrCoreStatic", "xrCore\xrCoreStatic.vcproj", "{F1066EAC-EE25-4C7A-9023-5957A6F7BA27}" + ProjectSection(ProjectDependencies) = postProject + {E8CF1ADA-264A-4127-86C2-FD7057D3792C} = {E8CF1ADA-264A-4127-86C2-FD7057D3792C} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CompressionTest", "utils\CompressionTest\CompressionTest.vcproj", "{C961EA19-716C-4A6D-BB13-689F8FB78B01}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctool", "utils\ctool\ctool.vcproj", "{2FAAC8BA-369F-465E-B465-2235963FD377}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ETools", "utils\ETools\ETools.vcproj", "{65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {F1836CE2-59EF-4189-8B9C-D103A511CB27} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {F1836CE2-59EF-4189-8B9C-D103A511CB27} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {F1836CE2-59EF-4189-8B9C-D103A511CB27} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LWO", "utils\LWO\LWO.vcproj", "{A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrAI", "utils\xrAI\xrAI.vcproj", "{EA5932F3-02FE-4AD3-89E8-7072DC465D25}" + ProjectSection(ProjectDependencies) = postProject + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61} = {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrCompress", "utils\xrCompress\xrCompress.vcproj", "{EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrDO_Light", "utils\xrDO_Light\xrDO_Light.vcproj", "{B730F54D-1199-481A-AAD0-5DB684E067C0}" + ProjectSection(ProjectDependencies) = postProject + {EC924B9B-4991-4931-8623-E1DB9AE005CA} = {EC924B9B-4991-4931-8623-E1DB9AE005CA} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DXT", "utils\xrDXT\DXT.vcproj", "{EBF9B543-0830-4866-9B48-DC0740E87E8A}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrLC", "utils\xrLC\xrLC.vcproj", "{A4ABD75E-825B-4D09-B3B2-2709682E40C8}" + ProjectSection(ProjectDependencies) = postProject + {EC924B9B-4991-4931-8623-E1DB9AE005CA} = {EC924B9B-4991-4931-8623-E1DB9AE005CA} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {F1836CE2-59EF-4189-8B9C-D103A511CB27} + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} = {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} + {94A1C366-3D19-48E6-8170-4ADC2E70DF98} = {94A1C366-3D19-48E6-8170-4ADC2E70DF98} + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} = {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {EBF9B543-0830-4866-9B48-DC0740E87E8A} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {F1836CE2-59EF-4189-8B9C-D103A511CB27} + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} = {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} + {94A1C366-3D19-48E6-8170-4ADC2E70DF98} = {94A1C366-3D19-48E6-8170-4ADC2E70DF98} + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} = {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {EBF9B543-0830-4866-9B48-DC0740E87E8A} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {F1836CE2-59EF-4189-8B9C-D103A511CB27} + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} = {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} + {94A1C366-3D19-48E6-8170-4ADC2E70DF98} = {94A1C366-3D19-48E6-8170-4ADC2E70DF98} + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} = {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {EBF9B543-0830-4866-9B48-DC0740E87E8A} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrQSlim", "utils\xrQSlim\xrQSlim.vcproj", "{F1836CE2-59EF-4189-8B9C-D103A511CB27}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrSE_Factory", "utils\xrSE_Factory\xrSE_Factory.vcproj", "{3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {CC52E0B3-CC35-4934-9302-035B748F3F2C} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {CC52E0B3-CC35-4934-9302-035B748F3F2C} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {CC52E0B3-CC35-4934-9302-035B748F3F2C} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrCDB", "xrCDB\xrCDB.vcproj", "{A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}" + ProjectSection(ProjectDependencies) = postProject + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrCore", "xrCore\xrCore.vcproj", "{A0F7D1FB-59A7-4717-A7E4-96F37E91998E}" + ProjectSection(ProjectDependencies) = postProject + {E8CF1ADA-264A-4127-86C2-FD7057D3792C} = {E8CF1ADA-264A-4127-86C2-FD7057D3792C} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrCPU_Pipe", "xrCPU_Pipe\xrCPU_Pipe.vcproj", "{CA0649DD-D089-423A-981C-46B57A884EB9}" + ProjectSection(ProjectDependencies) = postProject + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrGame", "xrGame\xrGame.vcproj", "{200652A6-043E-4634-8837-87983B3BD5E0}" + ProjectSection(ProjectDependencies) = postProject + {1BF75FEB-87DD-486C-880B-227987D191C2} = {1BF75FEB-87DD-486C-880B-227987D191C2} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7} = {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7} + {435BAC9A-B225-457D-AB40-C9BD0CC8838C} = {435BAC9A-B225-457D-AB40-C9BD0CC8838C} + {94A1C366-3D19-48E6-8170-4ADC2E70DF98} = {94A1C366-3D19-48E6-8170-4ADC2E70DF98} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + {FA169092-EA3E-40C1-8E5A-A2B575700FE8} = {FA169092-EA3E-40C1-8E5A-A2B575700FE8} + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4} = {880CD250-BA77-4DAF-A8D4-552F12DD3AE4} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4} = {880CD250-BA77-4DAF-A8D4-552F12DD3AE4} + {FA169092-EA3E-40C1-8E5A-A2B575700FE8} = {FA169092-EA3E-40C1-8E5A-A2B575700FE8} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {94A1C366-3D19-48E6-8170-4ADC2E70DF98} = {94A1C366-3D19-48E6-8170-4ADC2E70DF98} + {435BAC9A-B225-457D-AB40-C9BD0CC8838C} = {435BAC9A-B225-457D-AB40-C9BD0CC8838C} + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7} = {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {1BF75FEB-87DD-486C-880B-227987D191C2} = {1BF75FEB-87DD-486C-880B-227987D191C2} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {CC52E0B3-CC35-4934-9302-035B748F3F2C} + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA} = {98D24A3D-7666-4C11-9D6E-B10393CE8CBA} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrGameSpy", "xrGameSpy\xrGameSpy.vcproj", "{5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrNetServer", "xrNetServer\xrNetServer.vcproj", "{435BAC9A-B225-457D-AB40-C9BD0CC8838C}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrParticles", "xrParticles\xrParticles.vcproj", "{94A1C366-3D19-48E6-8170-4ADC2E70DF97}" + ProjectSection(ProjectDependencies) = postProject + {CA0649DD-D089-423A-981C-46B57A884EB9} = {CA0649DD-D089-423A-981C-46B57A884EB9} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrRender_R1", "Layers\xrRenderPC_R1\xrRender_R1.vcproj", "{57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}" + ProjectSection(ProjectDependencies) = postProject + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {CA0649DD-D089-423A-981C-46B57A884EB9} = {CA0649DD-D089-423A-981C-46B57A884EB9} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {CC52E0B3-CC35-4934-9302-035B748F3F2C} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrRender_R2", "Layers\xrRenderPC_R2\xrRender_R2.vcproj", "{963BA4E5-499A-454D-B002-1D5ECE0527A6}" + ProjectSection(ProjectDependencies) = postProject + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {CA0649DD-D089-423A-981C-46B57A884EB9} = {CA0649DD-D089-423A-981C-46B57A884EB9} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrSound", "xrSound\xrSound.vcproj", "{CCCA7859-EB86-493E-9B53-C4235F45B3C5}" + ProjectSection(ProjectDependencies) = postProject + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrXMLParser", "xrXMLParser\xrXMLParser.vcproj", "{94A1C366-3D19-48E6-8170-4ADC2E70DF98}" + ProjectSection(ProjectDependencies) = postProject + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {566551F4-4EF1-4CB4-A131-F982E7606907} = {566551F4-4EF1-4CB4-A131-F982E7606907} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {566551F4-4EF1-4CB4-A131-F982E7606907} = {566551F4-4EF1-4CB4-A131-F982E7606907} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "max", "max", "{901F5C6A-BA06-4727-B9BC-762891749A46}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "maya", "maya", "{68CB7CEC-F907-47AD-B624-B8432F53AAE3}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lw", "lw", "{AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Export_70", "plugins\lw\LW_Export70.vcproj", "{F573DE85-0866-4775-955F-6C3241D2AE70}" + ProjectSection(ProjectDependencies) = postProject + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD} = {6BA3121A-ACBC-4685-9246-4549CA1EFFFD} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Export_75", "plugins\lw\LW_Export75.vcproj", "{F573DE85-0866-4775-955F-6C3241D2AE75}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Export_80", "plugins\lw\LW_Export80.vcproj", "{F573DE85-0866-4775-955F-6C3241D2AE80}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Server", "plugins\lw\LW_Server.vcproj", "{6BA3121A-ACBC-4685-9246-4549CA1EFFFD}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Shader_70", "plugins\lw\LW_Shader70.vcproj", "{39EE310B-4F1D-4716-A39F-4AB844DB3670}" + ProjectSection(ProjectDependencies) = postProject + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD} = {6BA3121A-ACBC-4685-9246-4549CA1EFFFD} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Shader_75", "plugins\lw\LW_Shader75.vcproj", "{39EE310B-4F1D-4716-A39F-4AB844DB3675}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LW_Shader_80", "plugins\lw\LW_Shader80.vcproj", "{39EE310B-4F1D-4716-A39F-4AB844DB3680}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Max_Export_60", "plugins\Max\MAX_Export60.vcproj", "{93AD3B7E-71DE-4FA2-90E7-A79782ED4960}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Max_Material_60", "plugins\Max\MAX_Material60.vcproj", "{56AD8F54-F89E-4B5A-93F8-8A617BFD1160}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_45", "plugins\Maya\Maya_Export45.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF67268B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_50", "plugins\Maya\Maya_Export50.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672650}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_70", "plugins\Maya\Maya_Export70.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672670}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_80", "plugins\Maya\Maya_Export80.vcproj", "{B0ED3CE2-1417-46EF-AE39-59BCFF672670}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_85", "plugins\Maya\Maya_Export85.vcproj", "{C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_60", "plugins\Maya\Maya_Export601.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672660}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_45", "plugins\Maya\Maya_Material45.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672045}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_50", "plugins\Maya\Maya_Material50.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672050}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_70", "plugins\Maya\Maya_Material70.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672070}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_80", "plugins\Maya\Maya_Material80.vcproj", "{B0ED3CE2-1417-46EF-AE39-59BCFF672070}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_85", "plugins\Maya\Maya_Material85.vcproj", "{F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_60", "plugins\Maya\Maya_Material601.vcproj", "{B0ED3CE1-1417-46EF-AE39-59BCFF672060}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_2008", "plugins\Maya\Maya_Export2008.vcproj", "{C928FBB1-EDD8-4198-90DC-170A54C2AD72}" + ProjectSection(ProjectDependencies) = postProject + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_2008", "plugins\Maya\Maya_Material2008.vcproj", "{84D91673-C1A1-47FF-9A75-4E73F31F4C63}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrAPI", "Layers\xrAPI\xrAPI.vcproj", "{1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrRender_R3", "Layers\xrRenderPC_R3\xrRender_R3.vcproj", "{3F383D3C-FCD8-4170-990B-EB4833F09248}" + ProjectSection(ProjectDependencies) = postProject + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {94A1C366-3D19-48E6-8170-4ADC2E70DF97} = {94A1C366-3D19-48E6-8170-4ADC2E70DF97} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {CA0649DD-D089-423A-981C-46B57A884EB9} = {CA0649DD-D089-423A-981C-46B57A884EB9} + {2578C6D8-660D-48AE-9322-7422F8664F06} = {2578C6D8-660D-48AE-9322-7422F8664F06} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "editor", "editor", "{2DDE8FE4-6490-4AC5-B020-7E6A203F6318}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "editor", "editor\editor.vcproj", "{492D3DFE-9068-4E7E-A008-7C2420A651C0}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "editor_controls", "editor_controls\editor_controls.vcproj", "{B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrEngine", "xrEngine\xrEngine.vcproj", "{2578C6D8-660D-48AE-9322-7422F8664F06}" + ProjectSection(ProjectDependencies) = postProject + {435BAC9A-B225-457D-AB40-C9BD0CC8838C} = {435BAC9A-B225-457D-AB40-C9BD0CC8838C} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {CC52E0B3-CC35-4934-9302-035B748F3F2C} + {566551F4-4EF1-4CB4-A131-F982E7606907} = {566551F4-4EF1-4CB4-A131-F982E7606907} + {566551F4-4EF1-4CB4-A131-F982E7606907} = {566551F4-4EF1-4CB4-A131-F982E7606907} + {CCCA7859-EB86-493E-9B53-C4235F45B3C5} = {CCCA7859-EB86-493E-9B53-C4235F45B3C5} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luabind.beta7-devel.rc4", "3rd party\luabind\luabind.beta7-devel.rc4.vcproj", "{CC52E0B3-CC35-4934-9302-035B748F3F2C}" + ProjectSection(ProjectDependencies) = postProject + {F6C4F74A-152C-4612-9E3B-D02346234855} = {F6C4F74A-152C-4612-9E3B-D02346234855} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua.JIT.1.1.4", "3rd party\luajit\lua.JIT.1.1.4.vcproj", "{F6C4F74A-152C-4612-9E3B-D02346234855}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrLC_Light", "utils\xrLC_Light\xrLC_Light.vcproj", "{EFB76D6F-0092-439C-A783-C0BE10BD17C9}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {EBF9B543-0830-4866-9B48-DC0740E87E8A} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {EBF9B543-0830-4866-9B48-DC0740E87E8A} + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {EBF9B543-0830-4866-9B48-DC0740E87E8A} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrLC_LightStab", "utils\xrLC_LightStab\xrLC_LightStab.vcproj", "{EC924B9B-4991-4931-8623-E1DB9AE005CA}" + ProjectSection(ProjectDependencies) = postProject + {EFB76D6F-0092-439C-A783-C0BE10BD17C9} = {EFB76D6F-0092-439C-A783-C0BE10BD17C9} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrPhysics", "xrPhysics\xrPhysics.vcproj", "{98D24A3D-7666-4C11-9D6E-B10393CE8CBA}" + ProjectSection(ProjectDependencies) = postProject + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} = {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5} + {1BF75FEB-87DD-486C-880B-227987D191C2} = {1BF75FEB-87DD-486C-880B-227987D191C2} + {CCCA7859-EB86-493E-9B53-C4235F45B3C5} = {CCCA7859-EB86-493E-9B53-C4235F45B3C5} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {1BF75FEB-87DD-486C-880B-227987D191C2} = {1BF75FEB-87DD-486C-880B-227987D191C2} + {CCCA7859-EB86-493E-9B53-C4235F45B3C5} = {CCCA7859-EB86-493E-9B53-C4235F45B3C5} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + {1BF75FEB-87DD-486C-880B-227987D191C2} = {1BF75FEB-87DD-486C-880B-227987D191C2} + {CCCA7859-EB86-493E-9B53-C4235F45B3C5} = {CCCA7859-EB86-493E-9B53-C4235F45B3C5} + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} = {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cximage", "cximage", "{8D7A67B7-7CBA-4E8F-835F-76BD34446767}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CxImage", "3rd party\cximage\CxImage\cximage.vcproj", "{880CD250-BA77-4DAF-A8D4-552F12DD3AE4}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {E6343391-13FC-479E-B62F-1C24F7B85408} = {E6343391-13FC-479E-B62F-1C24F7B85408} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {E6343391-13FC-479E-B62F-1C24F7B85408} = {E6343391-13FC-479E-B62F-1C24F7B85408} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg", "3rd party\cximage\jpeg\Jpeg.vcproj", "{E6343391-13FC-479E-B62F-1C24F7B85408}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Export_2009", "plugins\Maya\Maya_Export2009.vcproj", "{E5F40F9E-C01B-4B97-9BD5-FC24308D8022}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Maya_Material_2009", "plugins\Maya\Maya_Material2009.vcproj", "{FFDF27A8-C198-49ED-BA13-4DA9054266C6}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crypto", "3rd party\crypto\crypto.vcproj", "{FA169092-EA3E-40C1-8E5A-A2B575700FE8}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrRender_R4", "Layers\xrRenderPC_R4\xrRender_R4.vcproj", "{AC9B12ED-A2D7-4337-A981-5BD8430E96D8}" + ProjectSection(ProjectDependencies) = postProject + {CA0649DD-D089-423A-981C-46B57A884EB9} = {CA0649DD-D089-423A-981C-46B57A884EB9} + {FA169092-EA3E-40C1-8E5A-A2B575700FE8} = {FA169092-EA3E-40C1-8E5A-A2B575700FE8} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mp_screenshots_info", "utils\mp_screenshots_info\mp_screenshots_info.vcproj", "{032A10AB-E44C-4751-A290-001EF99E664A}" + ProjectSection(ProjectDependencies) = postProject + {FA169092-EA3E-40C1-8E5A-A2B575700FE8} = {FA169092-EA3E-40C1-8E5A-A2B575700FE8} + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mp_configs_verifyer", "utils\mp_configs_verifyer\mp_configs_verifyer.vcproj", "{1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}" + ProjectSection(ProjectDependencies) = postProject + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} + {FA169092-EA3E-40C1-8E5A-A2B575700FE8} = {FA169092-EA3E-40C1-8E5A-A2B575700FE8} + EndProjectSection + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "3rd party\bugtrap\minizip\minizip.vcproj", "{893279CB-0805-405F-B484-9BB728A18261}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_Dedicated|Win32 = Debug_Dedicated|Win32 + Debug_Dedicated|Xbox 360 = Debug_Dedicated|Xbox 360 + Debug|Win32 = Debug|Win32 + Debug|Xbox 360 = Debug|Xbox 360 + Mixed_Dedicated|Win32 = Mixed_Dedicated|Win32 + Mixed_Dedicated|Xbox 360 = Mixed_Dedicated|Xbox 360 + Mixed|Win32 = Mixed|Win32 + Mixed|Xbox 360 = Mixed|Xbox 360 + Release_Dedicated|Win32 = Release_Dedicated|Win32 + Release_Dedicated|Xbox 360 = Release_Dedicated|Xbox 360 + Release|Win32 = Release|Win32 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug|Win32.Build.0 = Debug|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed|Win32.ActiveCfg = Release|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed|Win32.Build.0 = Release|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed|Xbox 360.ActiveCfg = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Mixed|Xbox 360.Build.0 = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release|Win32.ActiveCfg = Release|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release|Win32.Build.0 = Release|Win32 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {E8CF1ADA-264A-4127-86C2-FD7057D3792C}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug|Win32.ActiveCfg = Debug|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug|Win32.Build.0 = Debug|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed|Win32.ActiveCfg = Release|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed|Win32.Build.0 = Release|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed|Xbox 360.ActiveCfg = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Mixed|Xbox 360.Build.0 = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release|Win32.ActiveCfg = Release|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release|Win32.Build.0 = Release|Win32 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug|Win32.ActiveCfg = Debug|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug|Win32.Build.0 = Debug|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed|Win32.Build.0 = Mixed|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release|Win32.ActiveCfg = Release|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release|Win32.Build.0 = Release|Win32 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {1BF75FEB-87DD-486C-880B-227987D191C2}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug|Win32.ActiveCfg = Debug|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug|Win32.Build.0 = Debug|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed|Win32.ActiveCfg = Release|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed|Win32.Build.0 = Release|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed|Xbox 360.ActiveCfg = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Mixed|Xbox 360.Build.0 = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release|Win32.ActiveCfg = Release|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release|Win32.Build.0 = Release|Win32 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {566551F4-4EF1-4CB4-A131-F982E7606907}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Debug_Dedicated|Win32.ActiveCfg = Release|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Debug|Win32.ActiveCfg = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Debug|Win32.Build.0 = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Mixed_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Mixed|Win32.ActiveCfg = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Mixed|Win32.Build.0 = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Mixed|Xbox 360.ActiveCfg = Debug|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Release|Win32.ActiveCfg = Release|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Release|Win32.Build.0 = Release|Win32 + {0899B131-F1D4-4876-9BA1-67AC821DB9E1}.Release|Xbox 360.ActiveCfg = Release|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Debug|Win32.ActiveCfg = Debug|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Debug|Win32.Build.0 = Debug|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Mixed|Win32.Build.0 = Mixed|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Release|Win32.ActiveCfg = Release|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Release|Win32.Build.0 = Release|Win32 + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27}.Release|Xbox 360.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Debug|Win32.ActiveCfg = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Debug|Win32.Build.0 = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Mixed|Win32.ActiveCfg = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Mixed|Win32.Build.0 = Debug|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Release|Win32.ActiveCfg = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Release|Win32.Build.0 = Release|Win32 + {C961EA19-716C-4A6D-BB13-689F8FB78B01}.Release|Xbox 360.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Debug|Win32.ActiveCfg = Debug|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Debug|Win32.Build.0 = Debug|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Mixed|Win32.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Mixed|Win32.Build.0 = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Release|Win32.ActiveCfg = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Release|Win32.Build.0 = Release|Win32 + {2FAAC8BA-369F-465E-B465-2235963FD377}.Release|Xbox 360.ActiveCfg = Release|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Debug|Win32.ActiveCfg = Debug|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Debug|Win32.Build.0 = Debug|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Mixed|Win32.Build.0 = Mixed|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Release|Win32.ActiveCfg = Release|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Release|Win32.Build.0 = Release|Win32 + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33}.Release|Xbox 360.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Debug|Win32.ActiveCfg = Debug|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Debug|Win32.Build.0 = Debug|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Mixed|Win32.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Mixed|Win32.Build.0 = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Release|Win32.ActiveCfg = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Release|Win32.Build.0 = Release|Win32 + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED}.Release|Xbox 360.ActiveCfg = Release|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Debug|Win32.ActiveCfg = Debug|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Debug|Win32.Build.0 = Debug|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Mixed|Win32.Build.0 = Mixed|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Release|Win32.ActiveCfg = Release|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Release|Win32.Build.0 = Release|Win32 + {EA5932F3-02FE-4AD3-89E8-7072DC465D25}.Release|Xbox 360.ActiveCfg = Release|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Debug|Win32.ActiveCfg = Debug|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Debug|Win32.Build.0 = Debug|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Mixed|Win32.Build.0 = Mixed|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Release|Win32.ActiveCfg = Release|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Release|Win32.Build.0 = Release|Win32 + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Debug|Win32.Build.0 = Debug|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Mixed|Win32.Build.0 = Mixed|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Release|Win32.ActiveCfg = Release|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Release|Win32.Build.0 = Release|Win32 + {B730F54D-1199-481A-AAD0-5DB684E067C0}.Release|Xbox 360.ActiveCfg = Release|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Debug|Win32.ActiveCfg = Debug|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Debug|Win32.Build.0 = Debug|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Mixed|Win32.Build.0 = Mixed|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Release|Win32.ActiveCfg = Release|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Release|Win32.Build.0 = Release|Win32 + {EBF9B543-0830-4866-9B48-DC0740E87E8A}.Release|Xbox 360.ActiveCfg = Release|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Debug|Win32.Build.0 = Debug|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Mixed|Win32.Build.0 = Mixed|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Release|Win32.ActiveCfg = Release|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Release|Win32.Build.0 = Release|Win32 + {A4ABD75E-825B-4D09-B3B2-2709682E40C8}.Release|Xbox 360.ActiveCfg = Release|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Debug|Win32.ActiveCfg = Debug|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Debug|Win32.Build.0 = Debug|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Mixed|Win32.Build.0 = Mixed|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Release|Win32.ActiveCfg = Release|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Release|Win32.Build.0 = Release|Win32 + {F1836CE2-59EF-4189-8B9C-D103A511CB27}.Release|Xbox 360.ActiveCfg = Release|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Debug|Win32.ActiveCfg = Debug|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Debug|Win32.Build.0 = Debug|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Mixed|Win32.Build.0 = Mixed|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Release|Win32.ActiveCfg = Release|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Release|Win32.Build.0 = Release|Win32 + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61}.Release|Xbox 360.ActiveCfg = Release|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug|Win32.ActiveCfg = Debug|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug|Win32.Build.0 = Debug|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed|Win32.Build.0 = Mixed|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release|Win32.ActiveCfg = Release|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release|Win32.Build.0 = Release|Win32 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug|Win32.ActiveCfg = Debug|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug|Win32.Build.0 = Debug|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed|Win32.Build.0 = Mixed|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release|Win32.ActiveCfg = Release|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release|Win32.Build.0 = Release|Win32 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug|Win32.ActiveCfg = Debug|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug|Win32.Build.0 = Debug|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed|Win32.Build.0 = Mixed|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release|Win32.ActiveCfg = Release|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release|Win32.Build.0 = Release|Win32 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {CA0649DD-D089-423A-981C-46B57A884EB9}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug|Win32.ActiveCfg = Debug|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug|Win32.Build.0 = Debug|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed|Win32.ActiveCfg = Debug|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed|Win32.Build.0 = Debug|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release|Win32.ActiveCfg = Release|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release|Win32.Build.0 = Release|Win32 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {200652A6-043E-4634-8837-87983B3BD5E0}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug|Win32.Build.0 = Debug|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed|Win32.ActiveCfg = Debug|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed|Win32.Build.0 = Debug|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed|Xbox 360.ActiveCfg = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Mixed|Xbox 360.Build.0 = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release|Win32.ActiveCfg = Release|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release|Win32.Build.0 = Release|Win32 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {5535F6B4-7AE6-4B66-8AEA-CC31C14D7AB7}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug|Win32.ActiveCfg = Debug|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug|Win32.Build.0 = Debug|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed|Win32.ActiveCfg = Debug|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed|Win32.Build.0 = Debug|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release|Win32.ActiveCfg = Release|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release|Win32.Build.0 = Release|Win32 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug|Win32.ActiveCfg = Debug|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug|Win32.Build.0 = Debug|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed|Win32.Build.0 = Mixed|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release|Win32.ActiveCfg = Release|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release|Win32.Build.0 = Release|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug|Win32.ActiveCfg = Debug|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug|Win32.Build.0 = Debug|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed|Win32.ActiveCfg = Debug|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed|Win32.Build.0 = Debug|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release|Win32.ActiveCfg = Release|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release|Win32.Build.0 = Release|Win32 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug|Win32.ActiveCfg = Debug|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug|Win32.Build.0 = Debug|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed|Win32.ActiveCfg = Debug|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed|Win32.Build.0 = Debug|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release|Win32.ActiveCfg = Release|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release|Win32.Build.0 = Release|Win32 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug|Win32.ActiveCfg = Debug|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug|Win32.Build.0 = Debug|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed|Win32.Build.0 = Mixed|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release|Win32.ActiveCfg = Release|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release|Win32.Build.0 = Release|Win32 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug|Win32.ActiveCfg = Debug|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug|Win32.Build.0 = Debug|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed|Win32.Build.0 = Mixed|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release|Win32.ActiveCfg = Release|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release|Win32.Build.0 = Release|Win32 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Debug|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Debug|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Mixed|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Mixed|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Release|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Release|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE70}.Release|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Debug|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Debug|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Mixed|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Mixed|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Release|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Release|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE75}.Release|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Debug|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Debug|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Mixed|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Mixed|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Release|Win32.ActiveCfg = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Release|Win32.Build.0 = Release|Win32 + {F573DE85-0866-4775-955F-6C3241D2AE80}.Release|Xbox 360.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Debug|Win32.Build.0 = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Mixed|Win32.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Mixed|Win32.Build.0 = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Release|Win32.ActiveCfg = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Release|Win32.Build.0 = Release|Win32 + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD}.Release|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Debug|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Debug|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Mixed|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Mixed|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Release|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Release|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3670}.Release|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Debug|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Debug|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Mixed|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Mixed|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Release|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Release|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3675}.Release|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Debug|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Debug|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Mixed_Dedicated|Win32.Build.0 = Debug|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Mixed|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Mixed|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Release|Win32.ActiveCfg = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Release|Win32.Build.0 = Release|Win32 + {39EE310B-4F1D-4716-A39F-4AB844DB3680}.Release|Xbox 360.ActiveCfg = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Debug|Win32.ActiveCfg = Debug|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Debug|Win32.Build.0 = Debug|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Mixed_Dedicated|Win32.Build.0 = Mixed|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Mixed|Win32.ActiveCfg = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Mixed|Win32.Build.0 = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Release|Win32.ActiveCfg = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Release|Win32.Build.0 = Release|Win32 + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960}.Release|Xbox 360.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Debug|Win32.ActiveCfg = Debug|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Debug|Win32.Build.0 = Debug|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Mixed|Win32.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Mixed|Win32.Build.0 = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Release|Win32.ActiveCfg = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Release|Win32.Build.0 = Release|Win32 + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672650}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672670}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672670}.Release|Xbox 360.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Debug|Win32.Build.0 = Debug|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Mixed|Win32.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Mixed|Win32.Build.0 = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Release|Win32.ActiveCfg = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Release|Win32.Build.0 = Release|Win32 + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672660}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672045}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672050}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672070}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE2-1417-46EF-AE39-59BCFF672070}.Release|Xbox 360.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Debug|Win32.ActiveCfg = Debug|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Debug|Win32.Build.0 = Debug|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Mixed|Win32.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Mixed|Win32.Build.0 = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Release|Win32.ActiveCfg = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Release|Win32.Build.0 = Release|Win32 + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Debug|Win32.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Debug|Win32.Build.0 = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Mixed|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Mixed|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Release|Win32.ActiveCfg = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Release|Win32.Build.0 = Release|Win32 + {B0ED3CE1-1417-46EF-AE39-59BCFF672060}.Release|Xbox 360.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Debug|Win32.ActiveCfg = Debug|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Debug|Win32.Build.0 = Debug|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Mixed|Win32.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Mixed|Win32.Build.0 = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Release|Win32.ActiveCfg = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Release|Win32.Build.0 = Release|Win32 + {C928FBB1-EDD8-4198-90DC-170A54C2AD72}.Release|Xbox 360.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Debug|Win32.ActiveCfg = Debug|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Debug|Win32.Build.0 = Debug|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Mixed|Win32.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Mixed|Win32.Build.0 = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Release|Win32.ActiveCfg = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Release|Win32.Build.0 = Release|Win32 + {84D91673-C1A1-47FF-9A75-4E73F31F4C63}.Release|Xbox 360.ActiveCfg = Release|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug|Win32.ActiveCfg = Debug|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug|Win32.Build.0 = Debug|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed|Win32.ActiveCfg = Debug|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed|Win32.Build.0 = Debug|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed|Xbox 360.ActiveCfg = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Mixed|Xbox 360.Build.0 = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release|Win32.ActiveCfg = Release|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release|Win32.Build.0 = Release|Win32 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Debug|Win32.ActiveCfg = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Debug|Win32.Build.0 = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Mixed|Win32.ActiveCfg = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Mixed|Win32.Build.0 = Debug|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Release|Win32.ActiveCfg = Release|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Release|Win32.Build.0 = Release|Win32 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.Release|Xbox 360.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Debug|Win32.Build.0 = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Mixed|Win32.ActiveCfg = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Mixed|Win32.Build.0 = Debug|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Release|Win32.ActiveCfg = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Release|Win32.Build.0 = Release|Win32 + {492D3DFE-9068-4E7E-A008-7C2420A651C0}.Release|Xbox 360.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Debug|Win32.ActiveCfg = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Debug|Win32.Build.0 = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Mixed|Win32.ActiveCfg = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Mixed|Win32.Build.0 = Debug|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Release|Win32.ActiveCfg = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Release|Win32.Build.0 = Release|Win32 + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48}.Release|Xbox 360.ActiveCfg = Release|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug_Dedicated|Win32.ActiveCfg = Debug_Dedicated|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug_Dedicated|Win32.Build.0 = Debug_Dedicated|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug_Dedicated|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug_Dedicated|Xbox 360.Build.0 = Debug_Dedicated|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug|Win32.ActiveCfg = Debug|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug|Win32.Build.0 = Debug|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed_Dedicated|Win32.ActiveCfg = Mixed_Dedicated|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed_Dedicated|Win32.Build.0 = Mixed_Dedicated|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed_Dedicated|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed_Dedicated|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed|Win32.ActiveCfg = Debug|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed|Win32.Build.0 = Debug|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release_Dedicated|Win32.ActiveCfg = Release_Dedicated|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release_Dedicated|Win32.Build.0 = Release_Dedicated|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release_Dedicated|Xbox 360.ActiveCfg = Release_Dedicated|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release_Dedicated|Xbox 360.Build.0 = Release_Dedicated|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release|Win32.ActiveCfg = Release|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release|Win32.Build.0 = Release|Win32 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {2578C6D8-660D-48AE-9322-7422F8664F06}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug|Win32.ActiveCfg = Debug|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug|Win32.Build.0 = Debug|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed|Win32.ActiveCfg = Debug|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed|Win32.Build.0 = Debug|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed|Xbox 360.ActiveCfg = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Mixed|Xbox 360.Build.0 = Debug|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release|Win32.ActiveCfg = Release|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release|Win32.Build.0 = Release|Win32 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {CC52E0B3-CC35-4934-9302-035B748F3F2C}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Debug|Win32.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Debug|Win32.Build.0 = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Mixed_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Mixed|Win32.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Mixed|Win32.Build.0 = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Mixed|Xbox 360.ActiveCfg = Debug|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Release|Win32.ActiveCfg = Release|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Release|Win32.Build.0 = Release|Win32 + {F6C4F74A-152C-4612-9E3B-D02346234855}.Release|Xbox 360.ActiveCfg = Release|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Debug|Win32.Build.0 = Debug|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Mixed|Win32.Build.0 = Mixed|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Release|Win32.ActiveCfg = Release|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Release|Win32.Build.0 = Release|Win32 + {EFB76D6F-0092-439C-A783-C0BE10BD17C9}.Release|Xbox 360.ActiveCfg = Release|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Debug|Win32.Build.0 = Debug|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Mixed|Win32.Build.0 = Mixed|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Release|Win32.ActiveCfg = Release|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Release|Win32.Build.0 = Release|Win32 + {EC924B9B-4991-4931-8623-E1DB9AE005CA}.Release|Xbox 360.ActiveCfg = Release|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug|Win32.ActiveCfg = Debug|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug|Win32.Build.0 = Debug|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed_Dedicated|Xbox 360.Build.0 = Mixed|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed|Win32.ActiveCfg = Mixed|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed|Win32.Build.0 = Mixed|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed|Xbox 360.ActiveCfg = Mixed|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Mixed|Xbox 360.Build.0 = Mixed|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release|Win32.ActiveCfg = Release|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release|Win32.Build.0 = Release|Win32 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Release|Xbox 360.Build.0 = Release|Xbox 360 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Debug|Win32.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Debug|Win32.Build.0 = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Mixed_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Mixed|Win32.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Mixed|Win32.Build.0 = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Mixed|Xbox 360.ActiveCfg = Debug|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Release|Win32.ActiveCfg = Release|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Release|Win32.Build.0 = Release|Win32 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Release|Xbox 360.ActiveCfg = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Debug|Win32.ActiveCfg = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Debug|Win32.Build.0 = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Mixed|Win32.ActiveCfg = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Mixed|Win32.Build.0 = Debug|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Release|Win32.ActiveCfg = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Release|Win32.Build.0 = Release|Win32 + {E6343391-13FC-479E-B62F-1C24F7B85408}.Release|Xbox 360.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Debug|Win32.ActiveCfg = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Debug|Win32.Build.0 = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Mixed|Win32.ActiveCfg = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Mixed|Win32.Build.0 = Debug|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Release|Win32.ActiveCfg = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Release|Win32.Build.0 = Release|Win32 + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022}.Release|Xbox 360.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Debug_Dedicated|Win32.Build.0 = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Debug|Win32.ActiveCfg = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Debug|Win32.Build.0 = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Mixed_Dedicated|Win32.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Mixed_Dedicated|Win32.Build.0 = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Mixed|Win32.ActiveCfg = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Mixed|Win32.Build.0 = Debug|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Release_Dedicated|Win32.Build.0 = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Release|Win32.ActiveCfg = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Release|Win32.Build.0 = Release|Win32 + {FFDF27A8-C198-49ED-BA13-4DA9054266C6}.Release|Xbox 360.ActiveCfg = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Debug|Win32.ActiveCfg = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Debug|Win32.Build.0 = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Mixed|Win32.ActiveCfg = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Mixed|Win32.Build.0 = Debug|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Release|Win32.ActiveCfg = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Release|Win32.Build.0 = Release|Win32 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Release|Xbox 360.ActiveCfg = Release|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Debug|Win32.Build.0 = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Mixed_Dedicated|Win32.ActiveCfg = Mixed|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Mixed_Dedicated|Xbox 360.ActiveCfg = Mixed|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Mixed|Win32.ActiveCfg = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Mixed|Win32.Build.0 = Debug|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Mixed|Xbox 360.ActiveCfg = Mixed|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Release|Win32.ActiveCfg = Release|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Release|Win32.Build.0 = Release|Win32 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Release|Xbox 360.ActiveCfg = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Debug|Win32.ActiveCfg = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Debug|Win32.Build.0 = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Mixed|Win32.ActiveCfg = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Mixed|Win32.Build.0 = Debug|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Release|Win32.ActiveCfg = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Release|Win32.Build.0 = Release|Win32 + {032A10AB-E44C-4751-A290-001EF99E664A}.Release|Xbox 360.ActiveCfg = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Debug_Dedicated|Win32.ActiveCfg = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Debug|Win32.Build.0 = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Debug|Xbox 360.ActiveCfg = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Mixed_Dedicated|Win32.ActiveCfg = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Mixed|Win32.ActiveCfg = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Mixed|Win32.Build.0 = Debug|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Mixed|Xbox 360.ActiveCfg = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Release_Dedicated|Win32.ActiveCfg = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Release|Win32.ActiveCfg = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Release|Win32.Build.0 = Release|Win32 + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B}.Release|Xbox 360.ActiveCfg = Release|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Debug_Dedicated|Win32.ActiveCfg = Debug|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Debug_Dedicated|Xbox 360.ActiveCfg = Debug|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Debug_Dedicated|Xbox 360.Build.0 = Debug|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Debug|Win32.ActiveCfg = Debug|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Debug|Win32.Build.0 = Debug|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed_Dedicated|Win32.ActiveCfg = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed|Win32.ActiveCfg = Release|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed|Win32.Build.0 = Release|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed|Xbox 360.ActiveCfg = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Mixed|Xbox 360.Build.0 = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Release_Dedicated|Win32.ActiveCfg = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Release_Dedicated|Xbox 360.ActiveCfg = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Release_Dedicated|Xbox 360.Build.0 = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Release|Win32.ActiveCfg = Release|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Release|Win32.Build.0 = Release|Win32 + {893279CB-0805-405F-B484-9BB728A18261}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {893279CB-0805-405F-B484-9BB728A18261}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6BE93BFF-E2B4-43F2-ADBB-F8971E43CD5A} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {1BF75FEB-87DD-486C-880B-227987D191C2} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {566551F4-4EF1-4CB4-A131-F982E7606907} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {CC52E0B3-CC35-4934-9302-035B748F3F2C} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {F6C4F74A-152C-4612-9E3B-D02346234855} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {8D7A67B7-7CBA-4E8F-835F-76BD34446767} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {FA169092-EA3E-40C1-8E5A-A2B575700FE8} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {C961EA19-716C-4A6D-BB13-689F8FB78B01} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {2FAAC8BA-369F-465E-B465-2235963FD377} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {65CBB9D0-FBC6-41A4-8316-F5E9B5D7FB33} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {A6EBBBBB-5FEF-4C20-8460-DFAB11734DED} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {EA5932F3-02FE-4AD3-89E8-7072DC465D25} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {EF76867B-6EB8-4DC0-A1D6-E964FAD6FC7B} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {B730F54D-1199-481A-AAD0-5DB684E067C0} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {EBF9B543-0830-4866-9B48-DC0740E87E8A} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {A4ABD75E-825B-4D09-B3B2-2709682E40C8} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {F1836CE2-59EF-4189-8B9C-D103A511CB27} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {3AD26FD3-4F52-4E22-A4CF-AD4C49E74C61} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {EFB76D6F-0092-439C-A783-C0BE10BD17C9} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {EC924B9B-4991-4931-8623-E1DB9AE005CA} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {032A10AB-E44C-4751-A290-001EF99E664A} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {1924EF23-A05E-40E5-93F2-6CCD64BE1F8B} = {89F6A7EE-3BBE-45D3-A8A8-5D9366CD987B} + {0899B131-F1D4-4876-9BA1-67AC821DB9E1} = {3FC858CB-4888-42FF-ABC5-82DAECB59C2C} + {E8CF1ADA-264A-4127-86C2-FD7057D3792C} = {6BE93BFF-E2B4-43F2-ADBB-F8971E43CD5A} + {CA2604CA-A2AC-49A1-A468-8AB5A2E6CBC9} = {6BE93BFF-E2B4-43F2-ADBB-F8971E43CD5A} + {893279CB-0805-405F-B484-9BB728A18261} = {6BE93BFF-E2B4-43F2-ADBB-F8971E43CD5A} + {F1066EAC-EE25-4C7A-9023-5957A6F7BA27} = {A074ECE0-24F4-497F-99BD-AD45D5C51382} + {901F5C6A-BA06-4727-B9BC-762891749A46} = {A074ECE0-24F4-497F-99BD-AD45D5C51382} + {68CB7CEC-F907-47AD-B624-B8432F53AAE3} = {A074ECE0-24F4-497F-99BD-AD45D5C51382} + {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} = {A074ECE0-24F4-497F-99BD-AD45D5C51382} + {93AD3B7E-71DE-4FA2-90E7-A79782ED4960} = {901F5C6A-BA06-4727-B9BC-762891749A46} + {56AD8F54-F89E-4B5A-93F8-8A617BFD1160} = {901F5C6A-BA06-4727-B9BC-762891749A46} + {B0ED3CE1-1417-46EF-AE39-59BCFF67268B} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672650} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672670} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE2-1417-46EF-AE39-59BCFF672670} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {C2A6CB42-D6EC-4045-9452-B73FE1A4FABB} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672660} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672045} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672050} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672070} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE2-1417-46EF-AE39-59BCFF672070} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {F5FE7239-50EB-4AC0-AD32-6374C1A6DD6C} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {B0ED3CE1-1417-46EF-AE39-59BCFF672060} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {C928FBB1-EDD8-4198-90DC-170A54C2AD72} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {84D91673-C1A1-47FF-9A75-4E73F31F4C63} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {E5F40F9E-C01B-4B97-9BD5-FC24308D8022} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {FFDF27A8-C198-49ED-BA13-4DA9054266C6} = {68CB7CEC-F907-47AD-B624-B8432F53AAE3} + {F573DE85-0866-4775-955F-6C3241D2AE70} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {F573DE85-0866-4775-955F-6C3241D2AE75} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {F573DE85-0866-4775-955F-6C3241D2AE80} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {6BA3121A-ACBC-4685-9246-4549CA1EFFFD} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {39EE310B-4F1D-4716-A39F-4AB844DB3670} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {39EE310B-4F1D-4716-A39F-4AB844DB3675} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {39EE310B-4F1D-4716-A39F-4AB844DB3680} = {AB0D87B3-0937-4B2D-AB01-7A613B3EEF0D} + {492D3DFE-9068-4E7E-A008-7C2420A651C0} = {2DDE8FE4-6490-4AC5-B020-7E6A203F6318} + {B45374AA-C7ED-42CF-BBD3-DEAA2B7ACB48} = {2DDE8FE4-6490-4AC5-B020-7E6A203F6318} + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4} = {8D7A67B7-7CBA-4E8F-835F-76BD34446767} + {E6343391-13FC-479E-B62F-1C24F7B85408} = {8D7A67B7-7CBA-4E8F-835F-76BD34446767} + EndGlobalSection + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/DistributionFunc.cpp b/xrGameSpy/DistributionFunc.cpp new file mode 100644 index 00000000000..4736bc42ac8 --- /dev/null +++ b/xrGameSpy/DistributionFunc.cpp @@ -0,0 +1,74 @@ +// DistributionFunc.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "xrGameSpy_MainDefs.h" + +// WORD: Bit masks for languages +#define SKU_HAS_E 0x0001 // English +#define SKU_HAS_F 0x0002 // French +#define SKU_HAS_I 0x0004 // Italian +#define SKU_HAS_G 0x0008 // German +#define SKU_HAS_S 0x0010 // Spanish +#define SKU_HAS_R 0x0020 // Russian +#define SKU_HAS_P 0x0040 // Polish +#define SKU_HAS_C 0x0080 // Czech +#define SKU_HAS_H 0x0100 // China + +// BYTE: Bit masks for protection +#define SKU_PRT_NONE 0x10 // Without protection +#define SKU_PRT_SECU 0x20 // SecuROM +#define SKU_PRT_STAR 0x40 // StarForce +#define SKU_PRT_PACK 0x80 // Different DB packing algorithm +// and subprotection +#define SKU_SUB_KEYDISK 0x01 // Binding to key-disk +#define SKU_SUB_ONLINE 0x02 // Binding to hardware with online activation + +int GetGameDistribution () +{ + HKEY KeyCDKey = 0; + + long res = RegOpenKeyEx(REGISTRY_BASE, + REGISTRY_PATH, 0, KEY_READ, &KeyCDKey); + +// char KeyValue[1024] = ""; + int KeyValue; + DWORD KeyValueSize = 1024; + DWORD KeyValueType = REG_DWORD; + if (res == ERROR_SUCCESS && KeyCDKey != 0) + { + res = RegQueryValueEx(KeyCDKey, REGISTRY_VALUE_INSTALL_PATCH_ID, NULL, &KeyValueType, (LPBYTE)&KeyValue, &KeyValueSize); + }; + if (KeyCDKey != 0) RegCloseKey(KeyCDKey); + + if (res == ERROR_PATH_NOT_FOUND || + res == ERROR_FILE_NOT_FOUND || + KeyValueSize == 0) + { + return int(0); + }; + + return KeyValue; +} + +/* +int _tmain(int argc, _TCHAR* argv[]) +{ + char *SKUs[] = { + "stk-for-pack-securom-activ-e" , + "stk-for-pack-securom-keydisk-efis" , + "stk-for-pack-securom-keydisk-eg" , + "stk-for-pack-securom-keydisk-p" , + "stk-for-pack-securom-keydisk-c" , + "stk-for-pack-securom-keydisk-h" , + "stk-rus-pack-starforce-keydisk-r" , + "stk-for-pack-noprot-efis" + }; + + for ( int i = 0; i < 8; i ++ ) + printf( "%s : %i\n" , SKUs[ i ] , GetCodeSKU( SKUs[ i ] ) ); + + return 0; +} +*/ + diff --git a/xrGameSpy/GameSpy_Base_Defs.h b/xrGameSpy/GameSpy_Base_Defs.h new file mode 100644 index 00000000000..46f8009d683 --- /dev/null +++ b/xrGameSpy/GameSpy_Base_Defs.h @@ -0,0 +1,44 @@ +#pragma once + +#include "GameSpy_Keys.h" + +#ifdef DEMO_BUILD + #define GAMESPY_GAMENAME "stalkerscd" + #define GAMESPY_GAMEID 1567 + #define GAMESPY_PRODUCTID 10954 +#else + #define GAMESPY_GAMENAME "stalkersc" + #define GAMESPY_GAMEID 1067 + #define GAMESPY_PRODUCTID 10953 +#endif + +#define GAMESPY_MAX_UPDATES 20 + + +#define GAMESPY_PATCHING_VERSIONUNIQUE_ID "test_version_1" +#define GAMESPY_PATCHING_DISTRIBUTION_ID 0 + +#define GAMESPY_BASEPORT 5447 +#define START_PORT 5445 +#define END_PORT START_PORT + 100//GameSpy only process 500 ports + +static unsigned char Fields_Of_Interest[] = +{ + HOSTNAME_KEY, + NUMPLAYERS_KEY, + MAXPLAYERS_KEY, + MAPNAME_KEY, + GAMETYPE_KEY, + PASSWORD_KEY +}; + + + + + + + + + + + diff --git a/xrGameSpy/GameSpy_Patching.cpp b/xrGameSpy/GameSpy_Patching.cpp new file mode 100644 index 00000000000..64e5bc9b5f4 --- /dev/null +++ b/xrGameSpy/GameSpy_Patching.cpp @@ -0,0 +1,58 @@ +#include "StdAfx.h" +#include "GameSpy_Patching.h" +#include "GameSpy_Base_Defs.h" + +CGameSpy_Patching::CGameSpy_Patching() +{ + hGameSpyDLL = NULL; + + LoadGameSpy(); +}; + +CGameSpy_Patching::~CGameSpy_Patching() +{ + if (hGameSpyDLL) + { + FreeLibrary(hGameSpyDLL); + hGameSpyDLL = NULL; + } +}; +void CGameSpy_Patching::LoadGameSpy() +{ + LPCSTR g_name = "xrGameSpy.dll"; + Log ("Loading DLL:",g_name); + hGameSpyDLL = LoadLibrary (g_name); + if (0==hGameSpyDLL) R_CHK (GetLastError()); + R_ASSERT2 (hGameSpyDLL,"GameSpy DLL raised exception during loading or there is no game DLL at all"); + + GAMESPY_LOAD_FN(xrGS_ptCheckForPatch); +} + +void __cdecl GS_ptPatchCallback ( PTBool available, PTBool mandatory, const char * versionName, int fileID, const char * downloadURL, void * param ) +{ + int x=0; + x=x; +}; + +void CGameSpy_Patching::CheckForPatch() +{ + /* + bool res = xrGS_ptCheckForPatch(GAMESPY_PRODUCTID, + GAMESPY_PATCHING_VERSIONUNIQUE_ID, + GAMESPY_PATCHING_DISTRIBUTION_ID, + GS_ptPatchCallback, + PTTrue, + this + ); + */ + + bool res = xrGS_ptCheckForPatch(10953, + "test_version_1", + 0, + GS_ptPatchCallback, + PTTrue, + this + ); + int x=0; + x=x; +}; \ No newline at end of file diff --git a/xrGameSpy/ReadMe.txt b/xrGameSpy/ReadMe.txt new file mode 100644 index 00000000000..261f7b9d8c7 --- /dev/null +++ b/xrGameSpy/ReadMe.txt @@ -0,0 +1,32 @@ +======================================================================== + DYNAMIC LINK LIBRARY : xrGameSpy Project Overview +======================================================================== + +AppWizard has created this xrGameSpy DLL for you. +This file contains a summary of what you will find in each of the files that +make up your xrGameSpy application. + + +xrGameSpy.vcproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +xrGameSpy.cpp + This is the main DLL source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named xrGameSpy.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Chat/changelog.txt b/xrGameSpy/gamespy/Chat/changelog.txt new file mode 100644 index 00000000000..ef872b85685 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/changelog.txt @@ -0,0 +1,131 @@ +Changelog for: GameSpy Chat SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.15.00 RMV RELEASE Released to Developer Site +08-06-2007 1.14.00 RMV RELEASE Released to Developer Site +07-10-2007 1.13.01 RMV FIX Fixed chatc Project files to get rid of Unicode warnings and fixed other compiler warnings +06-28-2007 1.13.00 DDW FEATURE Added UDP relay support +12-15-2006 1.12.00 MJW RELEASE Released to Developer Site +12-11-2006 1.11.40 SN OTHER Added visual studio 2005 projects for samples + SN OTHER Fixed warnings with visual studio 2005 projects +10-05-2006 1.11.39 SAH FIX Updated MacOSX Makefile +09-28-2006 1.11.38 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +09-05-2006 1.11.37 SN FIX Updated Revolution support + Fixed bug in the case where null strings were being ignored. +08-02-2006 1.11.36 SAH RELEASE Releasing to developer site +07-31-2006 1.11.36 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-24-2006 1.11.35 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-06-2006 1.11.34 SAH FIX Fixed PSP project file - the linker file was explicitly included in a project +06-30-2006 1.11.33 SAH FIX Fixed NITRO project & linker command file (for Codewarrior 2.0/NitroSDK 3.1) + SAH FIX Fixed Linux makefile +06-02-2006 1.11.32 SAH FIX Added GS_STATIC_CALLBACK on comparator functions for __fastcall support +05-31-2006 1.11.31 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefiles +05-25-2006 1.11.31 SAH FIX Added some GSI_UNUSED calls to get rid of PSP warnings + SAH FIX Changed PS3 project settings to compile with 084_001 SDK +05-19-2006 1.11.30 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +04-25-2006 1.11.29 SAH RELEASE Releasing to developer site +04-24-2006 1.11.29 SAH FIX Fixed the nitro project to work on test machine, removed unncessary source files +04-20-2006 1.11.28 SAH FIX commented out unused variables to get rid of warnings +01-27-2006 1.11.27 SN RELEASE Releasing to developer site +01-26-2006 1.11.27 SN OTHER Added psp prodg solution and project to sgv +01-09-2006 1.11.27 SN FIX Updated code to use default server address and port +12-13-2005 1.11.26 SN OTHER Updated Visual Studio .NET Projects to use new common dir + Created Visual Studio .NET Solution + Removed old Static Library chat.vcproj +12-02-2005 1.11.26 SN FIX Added a check before freeing variable +11-17-2005 1.11.25 DES FIX Removed unneeded assert. + DES FIX Compatibility fix. + DES FIX Updated Nitro Makefile. +11-14-2005 1.11.24 DES FIX Updated the OSX Makefile. + DES FEATURE Adding GSI_DOMAIN_NAME support. +09-21-2005 1.11.23 DES FEATURE Updated DS support +07-28-2005 1.11.22 SN RELEASE Releasing to developer site. +06-03-2005 1.11.22 SN RELEASE Releasing to developer site. +04-29-2005 1.11.22 SN OTHER Created Visual Studio .NET projects for existing projects. +04-28-2005 1.11.22 SN RELEASE Releasing to developer site. +04-27-2005 1.11.22 DES RELEASE Limited release to Nintendo DS developers. +04-04-2005 1.11.22 SN RELEASE Releasing to developer site. +03-31-2005 1.11.22 SN FIX Added some preprocessor code to stop compiler warnings. +03-14-2005 1.11.21 DES FEATURE Nintendo DS support +11-25-2004 1.11.20 SN FIX Added const qualifiers to function parameters not modified +10-15-2004 1.11.19 SN FEATURE Added SDK side nickname checking +09-20-2004 1.11.18 BED FIX ciUserTableCompareFn now treats NULL parameter as "less than" (Arcade helper) +09-16-2004 1.11.17 SN RELEASE Releasing to developer site. +09-15-2004 1.11.17 DDW FEATURE Added global version var to pass on crypt for Arcade blacklisting +09-13-2004 1.11.16 BED FEATURE Added support for channel mode "e". (Ops obey channel limit) +08-27-2004 1.11.15 DES CLEANUP Removed MacOS style includes + DES CLEANUP General Unicode cleanup + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Fixed warnings under OSX + DES CLEANUP Updated OSX Makefile +08-10-2004 1.11.14 BED FIX ciSocketRecv will now process remaining messages after a disconnect. +08-05-2004 1.11.13 SN RELEASE Releasing to developer site. +07-19-2004 1.11.13 SN FIX Updated code with explicit casts to remove implicit cast error when compiling + at highest level and warnings treated as errors. +06-18-2004 1.11.12 BED RELEASE Releasing to developer site. +06-16-2004 1.11.12 BED FEATURE Added PS2 Insock (LibNet) support +04-19-2004 1.11.11 DDW FIX Fixed USRIP handler - handles message correctly after login +12-08-2003 1.11.10 BED FIX Updated PS2 sample for Sony 3.0. UNICODE no longer defined. +11-10-2003 1.11.09 DES RELEASE Releasing to developer site. +11-07-2003 1.11.09 DES FIX Updated the linux makefile to include the MD5 code. +11-06-2003 1.11.08 BED FIX Removed some unnecessary asserts in Unicode layer. + BED FIX Slight correction in sample callback. + BED FIX Sample no longer includes Leftover from memory leak testing. +10-23-2003 1.11.07 BED FIX Changed StringUtil to accept char* instead of unsigned char* + BED FIX Removed additional warnings for various compilers. +10-22-2003 1.11.06 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-21-2003 1.11.06 BED FIX Added ChatASCII.h to silence all the CodeWarrior prototype warnings + BED FIX Cleaned up other misc warnings. +10-17-2003 1.11.05 DES FIX It now always picks the correct name to use for the socket log. +10-16-2003 1.11.04 BED FIX Switched from UTF8 to Ascii when dealing with nicknames. + DES FIX Always pass the appropriate nick to the chatNickErrorCallback. + FIX Correctly handle chatConnectLogin with a 0 namespaceID. +10-09-2003 1.11.03 BED FIX Switched to gsi_time type instead of unsinged long for PS2 compatibility +10-06-2003 1.11.02 DES FIX chatGet[User|Profile]ID now return values during the connection attempt. +10-01-2003 1.11.01 DES FEATURE Added a reason code for failed connect attempts. + FEATURE Added suggested nicks for a CHAT_INVALID_UNIQUENICK nick errors. +09-30-2003 1.11.00 DES FEATURE Uniquenick support. +09-30-2003 1.10.27 BED FEATURE Update Chat sample to support GSI_UNICODE mode. +09-15-2003 1.10.26 JED FIX Minor change to CONNECTED macro to be more robust. +09-08-2003 1.10.25 BED FEATURE Added UTF-8 Wrapper for UNICODE support. + FIX Fixed crash when chatRetryWithNick was called with NULL. (As directed in the documentation) +07-24-2003 1.10.24 DES RELEASE Releasing to developer site. +07-24-2003 1.10.24 DES FIX Added GSI_UNUSED around an unused param. +07-18-2003 1.10.23 BED FEATURE Added CodeWarrior (PS2) sample project file. + CLEANUP General cleanup to remove CodeWarrior (PS2) warnings. +07-17-2003 1.10.22 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 1.10.21 BED FIX Added a newline at end of chatmain.c + DES FIX Changed two __mips64 checks to _PS2 checks. + BED FEATURE Added ProDG sample project files. +07-14-2003 1.10.20 BED FIX Now using ciNickIsValid to validate nicknames on client side. +07-14-2003 1.10.19 DES FIX Correctly handle being disconnected during the connection attempt. +07-11-2003 1.10.18 BED FIX Updated sample to join nonrestricted channel. +06-26-2003 1.10.17 DES CLEANUP Reduced the initial sizes of the channel and user hash tables. +06-11-2003 1.10.16 DES RELEASE Releasing to developer site. +05-09-2003 1.10.16 DES CLEANUP Removed Dreamcast support. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +05-07-2003 1.10.15 DES RELEASE Releasing to developer site. +04-23-2003 1.10.15 BGW FIX Now handling the case of localtime() returning NULL. +04-17-2003 1.10.14 DES FIX Fix for simultaneous WHO requests on a single user. +04-16-2003 1.10.13 DDW FEATURE Added chatInChannel function exposing ciInChannel functionality +03-19-2003 1.10.12 DES FEATURE IRC logging (IRC_LOG) now uses the nick as part of the filename. +03-12-2003 1.10.11 DES FIX If requesting 0 keys for a channel, correctly request all keys. +03-11-2003 1.10.10 DES FIX chatGetChannelKeys no longer asserts if keys is NULL. + If keys is NULL and num is 0, all keys are returned. +03-03-2003 1.10.09 DES CLEANUP General cleanup to remove warnings. + FEATURE Added chatSetChannelLimit for directly setting a channel limit. +01-09-2003 1.10.08 DES CLEANUP Removed an unneeded assert. +12-19-2002 1.10.07 DES RELEASE Releasing to developer site. +12-19-2002 1.10.07 DES CLEANUP Removed assert.h includes. +12-13-2002 1.10.06 DES FEATURE Added PS2 eenet stack support. +12-05-2002 1.10.05 DES CLEANUP Added some explicit type casting to eliminate warnings. +11-22-2002 1.10.04 DES RELEASE Releasing to developer site. +11-20-2002 1.10.04 DES CLEANUP Cleaned up to remove compiler warings on the PS2. +11-15-2002 1.10.03 DES OTHER Changed chatc to use chatConnectSecure. +11-07-2002 1.10.02 DES FIX Fixed negative hash due to high-ascii characters in hashed string. +10-17-2002 1.10.01 DES RELEASE Limited release on developer site +10-17-2002 1.10.01 DES FIX Fixed bug where incoming data was not processed when disconnected. +09-25-2002 1.10.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/Chat/chat.dsp b/xrGameSpy/gamespy/Chat/chat.dsp new file mode 100644 index 00000000000..a4f7de2fd4f --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chat.dsp @@ -0,0 +1,248 @@ +# Microsoft Developer Studio Project File - Name="chat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=chat - 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 "chat.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 "chat.mak" CFG="chat - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "chat - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "chat - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/chat", JKKAAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "chat - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "chat - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "chat - Win32 Release" +# Name "chat - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\chatCallbacks.c +# End Source File +# Begin Source File + +SOURCE=.\chatChannel.c +# End Source File +# Begin Source File + +SOURCE=.\chatCrypt.c +# End Source File +# Begin Source File + +SOURCE=.\chatHandlers.c +# End Source File +# Begin Source File + +SOURCE=.\chatMain.c +# End Source File +# Begin Source File + +SOURCE=.\chatSocket.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\chat.h +# End Source File +# Begin Source File + +SOURCE=.\chatASCII.h +# End Source File +# Begin Source File + +SOURCE=.\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=.\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=.\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=.\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=.\chatMain.h +# End Source File +# Begin Source File + +SOURCE=.\chatSocket.h +# End Source File +# End Group +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Chat/chat.dsw b/xrGameSpy/gamespy/Chat/chat.dsw new file mode 100644 index 00000000000..7e47f3ea276 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chat.dsw @@ -0,0 +1,69 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "chat"=.\chat.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/chat", JKKAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "chatc"=.\chatc\chatc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat/chatc", RRUAAAAA + .\chatc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "chatty"=.\chatty\chatty.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat/chatty", ELLAAAAA + .\chatty + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat", JKKAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Chat/chat.h b/xrGameSpy/gamespy/Chat/chat.h new file mode 100644 index 00000000000..246d40d32a6 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chat.h @@ -0,0 +1,998 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHAT_H_ +#define _CHAT_H_ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../common/gsCommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + +/************ +** DEFINES ** +************/ +// User and channel message types. +////////////////////////////////// +#define CHAT_MESSAGE 0 +#define CHAT_ACTION 1 +#define CHAT_NOTICE 2 +#define CHAT_UTM 3 +#define CHAT_ATM 4 + +// User modes. +// PANTS|03.12.01 - These are now bitflags! +// Both CHAT_VOICE and CHAT_OP can be set at the same time. +/////////////////////////////////////////////////////////// +#define CHAT_NORMAL 0 +#define CHAT_VOICE 1 +#define CHAT_OP 2 + +// Part reasons (see the chatUserParted callback). +////////////////////////////////////////////////// +#define CHAT_LEFT 0 // The user left the channel. +#define CHAT_QUIT 1 // The user quit the chat network. +#define CHAT_KICKED 2 // The user was kicked from the channel. +#define CHAT_KILLED 3 // The user was kicked off the chat network. + +// Possible nick errors while connecting. +///////////////////////////////////////// +#define CHAT_NICK_OK 0 +#define CHAT_IN_USE 1 +#define CHAT_INVALID 2 +#define CHAT_UNIQUENICK_EXPIRED 3 +#define CHAT_NO_UNIQUENICK 4 +#define CHAT_INVALID_UNIQUENICK 5 +#define CHAT_NICK_TOO_LONG 6 + +// Reasons why a connect attempt could fail. +//////////////////////////////////////////// +#define CHAT_DISCONNECTED 0 +#define CHAT_NICK_ERROR 1 +#define CHAT_LOGIN_FAILED 2 + +/********** +** TYPES ** +**********/ +// Boolean type. +//////////////// +typedef enum { CHATFalse, CHATTrue } CHATBool; + +// A CHAT object represents a client connection to a chat server. +///////////////////////////////////////////////////////////////// +typedef void * CHAT; + +// Object representing a channel's mode. +//////////////////////////////////////// +typedef struct CHATChannelMode +{ + CHATBool InviteOnly; + CHATBool Private; + CHATBool Secret; + CHATBool Moderated; + CHATBool NoExternalMessages; + CHATBool OnlyOpsChangeTopic; + CHATBool OpsObeyChannelLimit; + int Limit; +} CHATChannelMode; + +// The result of a channel enter attempt, +// passed into the chatEnterChannelCallback(). +////////////////////////////////////////////// +typedef enum +{ + CHATEnterSuccess, // The channel was successfully entered. + CHATBadChannelName, // The channel name was invalid. + CHATChannelIsFull, // The channel is at its user limit. + CHATInviteOnlyChannel, // The channel is invite only. + CHATBannedFromChannel, // The local user is banned from this channel. + CHATBadChannelPassword, // The channel has a password, and a bad password (or none) was given. + CHATTooManyChannels, // The server won't allow this user in any more channels. + CHATEnterTimedOut, // The attempt to enter timed out. + CHATBadChannelMask // Not sure if any servers use this, or what it means! (ERR_BADCHANMASK) +} CHATEnterResult; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef GSI_UNICODE +#define chatConnect chatConnectA +#define chatConnectSpecial chatConnectSpecialA +#define chatConnectSecure chatConnectSecureA +#define chatConnectLogin chatConnectLoginA +#define chatConnectPreAuth chatConnectPreAuthA +#define chatRetryWithNick chatRetryWithNickA +#define chatRegisterUniqueNick chatRegisterUniqueNickA +#define chatSendRaw chatSendRawA +#define chatChangeNick chatChangeNickA +#define chatFixNick chatFixNickA +#define chatTranslateNick chatTranslateNickA +#define chatAuthenticateCDKey chatAuthenticateCDKeyA +#define chatEnumChannels chatEnumChannelsA +#define chatEnterChannel chatEnterChannelA +#define chatLeaveChannel chatLeaveChannelA +#define chatSendChannelMessage chatSendChannelMessageA +#define chatSetChannelTopic chatSetChannelTopicA +#define chatGetChannelTopic chatGetChannelTopicA +#define chatSetChannelMode chatSetChannelModeA +#define chatGetChannelMode chatGetChannelModeA +#define chatSetChannelPassword chatSetChannelPasswordA +#define chatGetChannelPassword chatGetChannelPasswordA +#define chatSetChannelLimit chatSetChannelLimitA +#define chatEnumChannelBans chatEnumChannelBansA +#define chatAddChannelBan chatAddChannelBanA +#define chatRemoveChannelBan chatRemoveChannelBanA +#define chatSetChannelGroup chatSetChannelGroupA +#define chatGetChannelNumUsers chatGetChannelNumUsersA +#define chatInChannel chatInChannelA +#define chatEnumUsers chatEnumUsersA +#define chatSendUserMessage chatSendUserMessageA +#define chatGetUserInfo chatGetUserInfoA +#define chatGetBasicUserInfo chatGetBasicUserInfoA +#define chatGetBasicUserInfoNoWait chatGetBasicUserInfoNoWaitA +#define chatGetChannelBasicUserInfo chatGetChannelBasicUserInfoA +#define chatInviteUser chatInviteUserA +#define chatKickUser chatKickUserA +#define chatBanUser chatBanUserA +#define chatSetUserMode chatSetUserModeA +#define chatGetUserMode chatGetUserModeA +#define chatGetUserModeNoWait chatGetUserModeNoWaitA +#define chatSetGlobalKeys chatSetGlobalKeysA +#define chatSetChannelKeys chatSetChannelKeysA +#define chatGetGlobalKeys chatGetGlobalKeysA +#define chatGetChannelKeys chatGetChannelKeysA +#define chatGetNick chatGetNickA +#define chatGetUdpRelay chatGetUdpRelayA +#else +#define chatConnect chatConnectW +#define chatConnectSpecial chatConnectSpecialW +#define chatConnectSecure chatConnectSecureW +#define chatConnectLogin chatConnectLoginW +#define chatConnectPreAuth chatConnectPreAuthW +#define chatRetryWithNick chatRetryWithNickW +#define chatRegisterUniqueNick chatRegisterUniqueNickW +#define chatSendRaw chatSendRawW +#define chatChangeNick chatChangeNickW +#define chatFixNick chatFixNickW +#define chatTranslateNick chatTranslateNickW +#define chatAuthenticateCDKey chatAuthenticateCDKeyW +#define chatEnumChannels chatEnumChannelsW +#define chatEnterChannel chatEnterChannelW +#define chatLeaveChannel chatLeaveChannelW +#define chatSendChannelMessage chatSendChannelMessageW +#define chatSetChannelTopic chatSetChannelTopicW +#define chatGetChannelTopic chatGetChannelTopicW +#define chatSetChannelMode chatSetChannelModeW +#define chatGetChannelMode chatGetChannelModeW +#define chatSetChannelPassword chatSetChannelPasswordW +#define chatGetChannelPassword chatGetChannelPasswordW +#define chatSetChannelLimit chatSetChannelLimitW +#define chatEnumChannelBans chatEnumChannelBansW +#define chatAddChannelBan chatAddChannelBanW +#define chatRemoveChannelBan chatRemoveChannelBanW +#define chatSetChannelGroup chatSetChannelGroupW +#define chatGetChannelNumUsers chatGetChannelNumUsersW +#define chatInChannel chatInChannelW +#define chatEnumUsers chatEnumUsersW +#define chatSendUserMessage chatSendUserMessageW +#define chatGetUserInfo chatGetUserInfoW +#define chatGetBasicUserInfo chatGetBasicUserInfoW +#define chatGetBasicUserInfoNoWait chatGetBasicUserInfoNoWaitW +#define chatGetChannelBasicUserInfo chatGetChannelBasicUserInfoW +#define chatInviteUser chatInviteUserW +#define chatKickUser chatKickUserW +#define chatBanUser chatBanUserW +#define chatSetUserMode chatSetUserModeW +#define chatGetUserMode chatGetUserModeW +#define chatGetUserModeNoWait chatGetUserModeNoWaitW +#define chatSetGlobalKeys chatSetGlobalKeysW +#define chatSetChannelKeys chatSetChannelKeysW +#define chatGetGlobalKeys chatGetGlobalKeysW +#define chatGetChannelKeys chatGetChannelKeysW +#define chatGetNick chatGetNickW +#define chatGetUdpRelay chatGetUdpRelayW +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/********************** +** GLOBALS CALLBACKS ** +**********************/ +// Gets raw incoming network traffic. +///////////////////////////////////// +typedef void (* chatRaw)(CHAT chat, + const gsi_char * raw, + void * param); + +// Called when the client has been disconnected. +//////////////////////////////////////////////// +typedef void (* chatDisconnected)(CHAT chat, + const gsi_char * reason, + void * param); + +// Called when a private message from another user is received. +// If user==NULL, this is a message from the server. +/////////////////////////////////////////////////////////////// +typedef void (* chatPrivateMessage)(CHAT chat, + const gsi_char * user, + const gsi_char * message, + int type, // See defined message types above. + void * param); + +// Called when invited into a channel. +////////////////////////////////////// +typedef void (* chatInvited)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + void * param); + +// A connection's global callbacks. +/////////////////////////////////// +typedef struct chatGlobalCallbacks +{ + chatRaw raw; + chatDisconnected disconnected; + chatPrivateMessage privateMessage; + chatInvited invited; + void * param; +} chatGlobalCallbacks; + +/********************** +** CHANNEL CALLBACKS ** +**********************/ +// Called when a message is received in a channel. +////////////////////////////////////////////////// +typedef void (* chatChannelMessage)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + const gsi_char * message, + int type, // See defined message types above. + void * param); + +// Called when the local client is kicked from a channel. +///////////////////////////////////////////////////////// +typedef void (* chatKicked)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + const gsi_char * reason, + void * param); + +// Called when a user joins a channel we're in. +/////////////////////////////////////////////// +typedef void (* chatUserJoined)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int mode, // See defined user modes above. + void * param); + +// Called when a user parts a channel we're in. +/////////////////////////////////////////////// +typedef void (* chatUserParted)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int why, // See defined part reasons above. + const gsi_char * reason, + const gsi_char * kicker, + void * param); + +// Called when a user in a channel we're in changes nicks. +////////////////////////////////////////////////////////// +typedef void (* chatUserChangedNick)(CHAT chat, + const gsi_char * channel, + const gsi_char * oldNick, + const gsi_char * newNick, + void * param); + +// Called when the topic changes in a channel we're in. +/////////////////////////////////////////////////////// +typedef void (* chatTopicChanged)(CHAT chat, + const gsi_char * channel, + const gsi_char * topic, + void * param); + +// Called when the mode changes in a channel we're in. +////////////////////////////////////////////////////// +typedef void (* chatChannelModeChanged)(CHAT chat, + const gsi_char * channel, + CHATChannelMode * mode, + void * param); + +// Called when a user's mode changes in a channel we're in. +/////////////////////////////////////////////////////////// +typedef void (* chatUserModeChanged)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int mode, // See defined user modes above. + void * param); + +// Called when the user list changes (due to a join or a part) in a channel we're in. +///////////////////////////////////////////////////////////////////////////////////// +typedef void (* chatUserListUpdated)(CHAT chat, + const gsi_char * channel, + void * param); + +// Called when the chat server sends an entire new user list for a channel we're in. +//////////////////////////////////////////////////////////////////////////////////// +typedef void (* chatNewUserList)(CHAT chat, + const gsi_char * channel, + int num, + const gsi_char ** users, + int * modes, + void * param); + +// Called when a user changes a broadcast key in a channel we're in. +//////////////////////////////////////////////////////////////////// +typedef void (* chatBroadcastKeyChanged)(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + const gsi_char * key, + const gsi_char * value, + void * param); + +// A channel's callbacks. +///////////////////////// +typedef struct chatChannelCallbacks +{ + chatChannelMessage channelMessage; + chatKicked kicked; + chatUserJoined userJoined; + chatUserParted userParted; + chatUserChangedNick userChangedNick; + chatTopicChanged topicChanged; + chatChannelModeChanged channelModeChanged; + chatUserModeChanged userModeChanged; + chatUserListUpdated userListUpdated; + chatNewUserList newUserList; + chatBroadcastKeyChanged broadcastKeyChanged; + void * param; +} chatChannelCallbacks; + +/************ +** GENERAL ** +************/ +// Called when a connect attempt completes. +// failureReason is only set if success is CHATFalse. +///////////////////////////////////////////////////// +typedef void (* chatConnectCallback)(CHAT chat, + CHATBool success, + int failureReason, // CHAT_DISCONNECTED, CHAT_NICK_ERROR, etc. + void * param); +// Called if there is an error with the nick while connecting. +// To retry with a new nick, call chatRetryWithNick. +// Otherwise, call chatDisconnect to stop the connection. +// Suggested nicks are only provided if type is CHAT_INVALID_UNIQUENICK. +//////////////////////////////////////////////////////////////////////// +typedef void (* chatNickErrorCallback)(CHAT chat, + int type, // CHAT_IN_USE, CHAT_INVALID, etc. + const gsi_char * nick, + int numSuggestedNicks, + const gsi_char ** suggestedNicks, + void * param); +typedef void (* chatFillInUserCallback)(CHAT chat, + unsigned int IP, // PANTS|08.21.00 - changed from unsigned long + gsi_char user[128], + void * param); +// Connects you to a chat server and returns a CHAT object. +/////////////////////////////////////////////////////////// +CHAT chatConnect(const gsi_char * serverAddress, + int port, + const gsi_char * nick, + const gsi_char * user, + const gsi_char * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectSpecial(const gsi_char * serverAddress, + int port, + const gsi_char * nick, + const gsi_char * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectSecure(const gsi_char * serverAddress, + int port, + const gsi_char * nick, + const gsi_char * name, + const gsi_char * gamename, + const gsi_char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectLogin(const gsi_char * serverAddress, + int port, + int namespaceID, + const gsi_char * email, + const gsi_char * profilenick, + const gsi_char * uniquenick, + const gsi_char * password, + const gsi_char * name, + const gsi_char * gamename, + const gsi_char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectPreAuth(const gsi_char * serverAddress, + int port, + const gsi_char * authtoken, + const gsi_char * partnerchallenge, + const gsi_char * name, + const gsi_char * gamename, + const gsi_char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +// If the chatNickErrorCallback gets called, then this can be called +// with a new nick to retry. If this isn't called, the connection can be +// disconnected with chatDisconnect. If the new nick is successful, then +// the chatConnectCallback will get called. If there's another nick +// error, the chatNickErrorCallback will get called again. +///////////////////////////////////////////////////////////////////////// +void chatRetryWithNick(CHAT chat, + const gsi_char * nick); +// Register a uniquenick. +// Should be called in response to the chatNickErrorCallback being called +// with a type of CHAT_UNIQUENICK_EXPIRED or CHAT_NO_UNIQUENICK. +// If the uniquenick cannot be registered, the chatNickErrorCallback will +// be called again with a type of CHAT_IN_USE or CHAT_INVALID. +///////////////////////////////////////////////////////////////////////// +void chatRegisterUniqueNick(CHAT chat, + int namespaceID, + const gsi_char * uniquenick, + const gsi_char * cdkey); + +// Disconnect the chat connection. +////////////////////////////////// +void chatDisconnect(CHAT chat); + +// Processes the chat connection. +///////////////////////////////// +void chatThink(CHAT chat); + +// Sends raw data, without any interpretation. +////////////////////////////////////////////// +void chatSendRaw(CHAT chat, + const gsi_char * command); + +// Called as a result of a nick change attempt. +/////////////////////////////////////////////// +typedef void (* chatChangeNickCallback)(CHAT chat, + CHATBool success, + const gsi_char * oldNick, + const gsi_char * newNick, + void * param); +// Change the local user's nick. +//////////////////////////////// +void chatChangeNick(CHAT chat, + const gsi_char * newNick, + chatChangeNickCallback callback, + void * param, + CHATBool blocking); + +// Get our local nickname. +////////////////////////// +const gsi_char * chatGetNick(CHAT chat); + +// Copies the oldNick to the newNick, replacing any invalid characters with legal ones. +/////////////////////////////////////////////////////////////////////////////////////// +void chatFixNick(gsi_char * newNick, + const gsi_char * oldNick); + +// Removes the namespace extension from a chat nick. +//////////////////////////////////////////////////// +const gsi_char * chatTranslateNick(gsi_char * nick, + const gsi_char * extension); + +// Gets the local userID. +// Only valid if connected with chatConnectLogin or chatConnectPreAuth. +/////////////////////////////////////////////////////////////////////// +int chatGetUserID(CHAT chat); + +// Gets the local profileID. +// Only valid if connected with chatConnectLogin or chatConnectPreAuth. +/////////////////////////////////////////////////////////////////////// +int chatGetProfileID(CHAT chat); + +// Turn on/off quiet mode. +////////////////////////// +void chatSetQuietMode(CHAT chat, + CHATBool quiet); + +// Called as a result of an authenticate CD key attempt. +//////////////////////////////////////////////////////// +typedef void (* chatAuthenticateCDKeyCallback)(CHAT chat, + int result, + const gsi_char * message, + void * param); + +// Attempts to authenticates a CD key. +////////////////////////////////////// +void chatAuthenticateCDKey(CHAT chat, + const gsi_char * cdkey, + chatAuthenticateCDKeyCallback callback, + void * param, + CHATBool blocking); + +/************* +** CHANNELS ** +*************/ +// Gets called for each channel enumerated. +/////////////////////////////////////////// +typedef void (* chatEnumChannelsCallbackEach)(CHAT chat, + CHATBool success, + int index, + const gsi_char * channel, + const gsi_char * topic, + int numUsers, + void * param); +// Gets called after all channels have been enumerated. +/////////////////////////////////////////////////////// +typedef void (* chatEnumChannelsCallbackAll)(CHAT chat, + CHATBool success, + int numChannels, + const gsi_char ** channels, + const gsi_char ** topics, + int * numUsers, + void * param); +// Enumerates the channels available on a chat server. +////////////////////////////////////////////////////// +void chatEnumChannels(CHAT chat, + const gsi_char * filter, + chatEnumChannelsCallbackEach callbackEach, + chatEnumChannelsCallbackAll callbackAll, + void * param, + CHATBool blocking); + +// Gets called for each channel enumerated. +/////////////////////////////////////////// +typedef void (* chatEnumJoinedChannelsCallback)(CHAT chat, + int index, + const gsi_char * channel, + void * param); + +// Enumerates the channels that we are joined to +////////////////////////////////////////////////////// +void chatEnumJoinedChannels(CHAT chat, + chatEnumJoinedChannelsCallback callback, + void * param); + + + +// Gets called when a channel has been entered. +/////////////////////////////////////////////// +typedef void (* chatEnterChannelCallback)(CHAT chat, + CHATBool success, + CHATEnterResult result, + const gsi_char * channel, + void * param); +// Enters a channel. +//////////////////// +void chatEnterChannel(CHAT chat, + const gsi_char * channel, + const gsi_char * password, + chatChannelCallbacks * callbacks, + chatEnterChannelCallback callback, + void * param, + CHATBool blocking); + +// Leaves a channel. +//////////////////// +void chatLeaveChannel(CHAT chat, + const gsi_char * channel, + const gsi_char * reason); // PANTS|03.13.01 + +// Sends a message to a channel. +//////////////////////////////// +void chatSendChannelMessage(CHAT chat, + const gsi_char * channel, + const gsi_char * message, + int type); + +// Sets the topic in a channel. +/////////////////////////////// +void chatSetChannelTopic(CHAT chat, + const gsi_char * channel, + const gsi_char * topic); + +// Gets called when a channel's topic has been retrieved. +///////////////////////////////////////////////////////// +typedef void (* chatGetChannelTopicCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + const gsi_char * topic, + void * param); +// Gets a channel's topic. +////////////////////////// +void chatGetChannelTopic(CHAT chat, + const gsi_char * channel, + chatGetChannelTopicCallback callback, + void * param, + CHATBool blocking); + +// Sets a channel's mode. +///////////////////////// +void chatSetChannelMode(CHAT chat, + const gsi_char * channel, + CHATChannelMode * mode); + +// Gets called when a channel's mode has been retrieved. +//////////////////////////////////////////////////////// +typedef void (* chatGetChannelModeCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + CHATChannelMode * mode, + void * param); +// Gets a channel's mode. +///////////////////////// +void chatGetChannelMode(CHAT chat, + const gsi_char * channel, + chatGetChannelModeCallback callback, + void * param, + CHATBool blocking); + +// Sets the password in a channel. +////////////////////////////////// +void chatSetChannelPassword(CHAT chat, + const gsi_char * channel, + CHATBool enable, + const gsi_char * password); + +// Called when the channel's password has been retrieved. +///////////////////////////////////////////////////////// +typedef void (* chatGetChannelPasswordCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + CHATBool enabled, + const gsi_char * password, + void * param); +// Gets the password in a channel. +////////////////////////////////// +void chatGetChannelPassword(CHAT chat, + const gsi_char * channel, + chatGetChannelPasswordCallback callback, + void * param, + CHATBool blocking); + +// Set the maximum number of users allowed in a channel. +//////////////////////////////////////////////////////// +void chatSetChannelLimit(CHAT chat, + const gsi_char * channel, + int limit); + +// Called with the list of bans in a channel. +///////////////////////////////////////////// +typedef void (* chatEnumChannelBansCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + int numBans, + const gsi_char ** bans, + void * param); +// Enumerate through the bans in a channel. +/////////////////////////////////////////// +void chatEnumChannelBans(CHAT chat, + const gsi_char * channel, + chatEnumChannelBansCallback callback, + void * param, + CHATBool blocking); + +// Adds a channel ban. +////////////////////// +void chatAddChannelBan(CHAT chat, + const gsi_char * channel, + const gsi_char * ban); + +// Removes a ban string from a channel. +/////////////////////////////////////// +void chatRemoveChannelBan(CHAT chat, + const gsi_char * channel, + const gsi_char * ban); + +// Set the group this channel is a part of. +/////////////////////////////////////////// +void chatSetChannelGroup(CHAT chat, + const gsi_char * channel, + const gsi_char * group); + +// Get the number of users in the channel. +// Returns -1 if we are not in the channel. +/////////////////////////////////////////// +int chatGetChannelNumUsers(CHAT chat, + const gsi_char * channel); + + +// Returns CHATTrue if we are in the channel +/////////////////////////////////////////// +CHATBool chatInChannel(CHAT chat, + const gsi_char * channel); + + +/********** +** USERS ** +**********/ +// Called with the list of users in a channel. +////////////////////////////////////////////// +typedef void (* chatEnumUsersCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, //PANTS|02.11.00|added paramater + int numUsers, + const gsi_char ** users, + int * modes, + void * param); +// Enumerate through the users in a channel. +//////////////////////////////////////////// +void chatEnumUsers(CHAT chat, + const gsi_char * channel, + chatEnumUsersCallback callback, + void * param, + CHATBool blocking); + +// Send a private message to a user. +//////////////////////////////////// +void chatSendUserMessage(CHAT chat, + const gsi_char * user, + const gsi_char * message, + int type); + +// Called with a user's info. +///////////////////////////// +typedef void (* chatGetUserInfoCallback)(CHAT chat, + CHATBool success, + const gsi_char * nick, //PANTS|02.14.2000|added nick and user + const gsi_char * user, + const gsi_char * name, + const gsi_char * address, + int numChannels, + const gsi_char ** channels, + void * param); +// Get a user's info. +///////////////////// +void chatGetUserInfo(CHAT chat, + const gsi_char * user, + chatGetUserInfoCallback callback, + void * param, + CHATBool blocking); + +// Called with a user's basic info. +/////////////////////////////////// +typedef void (* chatGetBasicUserInfoCallback)(CHAT chat, + CHATBool success, + const gsi_char * nick, + const gsi_char * user, + const gsi_char * address, + void * param); + +// Get some basic info on the user. +// PANTS|12.08.2000 +/////////////////////////////////// +void chatGetBasicUserInfo(CHAT chat, + const gsi_char * user, + chatGetBasicUserInfoCallback callback, + void * param, + CHATBool blocking); + +// Get basic info without waiting. +// Returns CHATFalse if the info isn't available. +///////////////////////////////////////////////// +CHATBool chatGetBasicUserInfoNoWait(CHAT chat, + const gsi_char * nick, + const gsi_char ** user, + const gsi_char ** address); + +// Called with a user's basic info for everyone in a channel. +// Called with a NULL nick/user/address at the end. +///////////////////////////////////////////////////////////// +typedef void (* chatGetChannelBasicUserInfoCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + const gsi_char * nick, + const gsi_char * user, + const gsi_char * address, + void * param); + +// Get basic info on all the users in a channel. +// PANTS|12.19.00 +//////////////////////////////////////////////// +void chatGetChannelBasicUserInfo(CHAT chat, + const gsi_char * channel, + chatGetChannelBasicUserInfoCallback callback, + void * param, + CHATBool blocking); + +// Invite a user into a channel. +//////////////////////////////// +void chatInviteUser(CHAT chat, + const gsi_char * channel, + const gsi_char * user); + +// Kick a user from a channel. +////////////////////////////// +void chatKickUser(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + const gsi_char * reason); + +// Ban a user from a channel. +///////////////////////////// +void chatBanUser(CHAT chat, + const gsi_char * channel, + const gsi_char * user); + +// Sets a user's mode in a channel. +/////////////////////////////////// +void chatSetUserMode(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int mode); + +// Called with the user's mode. +/////////////////////////////// +typedef void (* chatGetUserModeCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + const gsi_char * user, + int mode, + void * param); +// Gets a user's mode in a channel. +/////////////////////////////////// +void chatGetUserMode(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + chatGetUserModeCallback callback, + void * param, + CHATBool blocking); + +// Gets a user's mode in a channel. +/////////////////////////////////// +CHATBool chatGetUserModeNoWait(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int * mode); + + +// Called in response to a request for the UDP relay for a channel +//////////////////////////////////////////////////////////////////// +typedef void (* chatGetUdpRelayCallback)(CHAT chat, + const gsi_char * channel, + const gsi_char * udpIp, + unsigned short udpPort, + int udpKey, + void * param); + +// Get the UDP relay address for a channel +/////////////////////////////////// +void chatGetUdpRelay(CHAT chat, + const gsi_char * channel, + chatGetUdpRelayCallback callback, + void * param, + CHATBool blocking); + + +/********* +** KEYS ** +*********/ +// Sets global key/values for the local user. +// Set a value to NULL or "" to clear that key. +/////////////////////////////////////////////// +void chatSetGlobalKeys(CHAT chat, + int num, + const gsi_char ** keys, + const gsi_char ** values); + +// Called with a user's global key/values. +// If used for a set of users, will be +// called with user==NULL when done. +////////////////////////////////////////// +typedef void (* chatGetGlobalKeysCallback)(CHAT chat, + CHATBool success, + const gsi_char * user, + int num, + const gsi_char ** keys, + const gsi_char ** values, + void * param); +// Gets global key/values for a user or users. +// To get the global key/values for one user, pass in that +// user's nick as the target. To get the global key/values +// for every user in a channel, use the channel name as the target. +/////////////////////////////////////////////////////////////////// +void chatGetGlobalKeys(CHAT chat, + const gsi_char * target, + int num, + const gsi_char ** keys, + chatGetGlobalKeysCallback callback, + void * param, + CHATBool blocking); + +// Sets channel key/values. +// If user is NULL or "", the keys will be set on the channel. +// Otherwise, they will be set on the user, +// Only ops can set channel keys on other users. +// Set a value to NULL or "" to clear that key. +////////////////////////////////////////////////////////////// +void chatSetChannelKeys(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int num, + const gsi_char ** keys, + const gsi_char ** values); + +// Called with a user's channel key/values, or a channel's key/values. +// If used for a set of users, will be called with user==NULL when done. +// If used for a channel, will be called once with user==NULL. +//////////////////////////////////////////////////////////////////////// +typedef void (* chatGetChannelKeysCallback)(CHAT chat, + CHATBool success, + const gsi_char * channel, + const gsi_char * user, + int num, + const gsi_char ** keys, + const gsi_char ** values, + void * param); +// Gets channel key/values for a user or users, or for a channel. +// To get the channel key/values for every user in +// a channel, pass in "*" as the user. To get the keys for a channel, +// pass in NULL or "". +////////////////////////////////////////////////////////////////////// +void chatGetChannelKeys(CHAT chat, + const gsi_char * channel, + const gsi_char * user, + int num, + const gsi_char ** keys, + chatGetChannelKeysCallback callback, + void * param, + CHATBool blocking); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This ASCII versions must be available even when GSI_UNICODE is defined +#ifdef GSI_UNICODE +CHATBool chatGetBasicUserInfoNoWaitA(CHAT chat, + const char * nick, + const char ** user, + const char ** address); +#endif +/* +void chatGetBasicUserInfoA(CHAT chat, + const char * user, + chatGetBasicUserInfoCallback callback, + void * param, + CHATBool blocking); +*/ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _CHAT_H_ diff --git a/xrGameSpy/gamespy/Chat/chatASCII.h b/xrGameSpy/gamespy/Chat/chatASCII.h new file mode 100644 index 00000000000..176c3f8a8d2 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatASCII.h @@ -0,0 +1,441 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHATASCII_H_ +#define _CHATASCII_H_ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "chat.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + + +// Connects you to a chat server and returns a CHAT object. +/////////////////////////////////////////////////////////// +CHAT chatConnectA(const char * serverAddress, + int port, + const char * nick, + const char * user, + const char * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectSpecialA(const char * serverAddress, + int port, + const char * nick, + const char * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectSecureA(const char * serverAddress, + int port, + const char * nick, + const char * name, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectLoginA(const char * serverAddress, + int port, + int namespaceID, + const char * email, + const char * profilenick, + const char * uniquenick, + const char * password, + const char * name, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); +CHAT chatConnectPreAuthA(const char * serverAddress, + int port, + const char * authtoken, + const char * partnerchallenge, + const char * name, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking); + +// If the chatNickErrorCallback gets called, then this can be called +// with a new nick to retry. If this isn't called, the connection can be +// disconnected with chatDisconnect. If the new nick is successful, then +// the chatConnectCallback will get called. If there's another nick +// error, the chatNickErrorCallback will get called again. +///////////////////////////////////////////////////////////////////////// +void chatRetryWithNickA(CHAT chat, + const char * nick); + +// Register a uniquenick. +// Should be called in response to the chatNickErrorCallback being called +// with a type of CHAT_UNIQUENICK_EXPIRED or CHAT_NO_UNIQUENICK. +// If the uniquenick cannot be registered, the chatNickErrorCallback will +// be called again with a type of CHAT_IN_USE or CHAT_INVALID. +///////////////////////////////////////////////////////////////////////// +void chatRegisterUniqueNickA(CHAT chat, + int namespaceID, + const char * uniquenick, + const char * cdkey); + +// Sends raw data, without any interpretation. +////////////////////////////////////////////// +void chatSendRawA(CHAT chat, + const char * command); + +// Change the local user's nick. +//////////////////////////////// +void chatChangeNickA(CHAT chat, + const char * newNick, + chatChangeNickCallback callback, + void * param, + CHATBool blocking); + +// Get our local nickname. +////////////////////////// +const char * chatGetNickA(CHAT chat); + +// Copies the oldNick to the newNick, replacing any invalid characters with legal ones. +/////////////////////////////////////////////////////////////////////////////////////// +void chatFixNickA(char * newNick, + const char * oldNick); + +// Removes the namespace extension from a chat nick. +//////////////////////////////////////////////////// +const char * chatTranslateNickA(char * nick, + const char * extension); + +// Attempts to authenticates a CD key. +////////////////////////////////////// +void chatAuthenticateCDKeyA(CHAT chat, + const char * cdkey, + chatAuthenticateCDKeyCallback callback, + void * param, + CHATBool blocking); + +/************* +** CHANNELS ** +*************/ +// Enumerates the channels available on a chat server. +////////////////////////////////////////////////////// +void chatEnumChannelsA(CHAT chat, + const char * filter, + chatEnumChannelsCallbackEach callbackEach, + chatEnumChannelsCallbackAll callbackAll, + void * param, + CHATBool blocking); + +// Enters a channel. +//////////////////// +void chatEnterChannelA(CHAT chat, + const char * channel, + const char * password, + chatChannelCallbacks * callbacks, + chatEnterChannelCallback callback, + void * param, + CHATBool blocking); + +// Leaves a channel. +//////////////////// +void chatLeaveChannelA(CHAT chat, + const char * channel, + const char * reason); // PANTS|03.13.01 + +// Sends a message to a channel. +//////////////////////////////// +void chatSendChannelMessageA(CHAT chat, + const char * channel, + const char * message, + int type); + +// Sets the topic in a channel. +/////////////////////////////// +void chatSetChannelTopicA(CHAT chat, + const char * channel, + const char * topic); + +// Gets a channel's topic. +////////////////////////// +void chatGetChannelTopicA(CHAT chat, + const char * channel, + chatGetChannelTopicCallback callback, + void * param, + CHATBool blocking); + +// Sets a channel's mode. +///////////////////////// +void chatSetChannelModeA(CHAT chat, + const char * channel, + CHATChannelMode * mode); + +// Gets a channel's mode. +///////////////////////// +void chatGetChannelModeA(CHAT chat, + const char * channel, + chatGetChannelModeCallback callback, + void * param, + CHATBool blocking); + +// Sets the password in a channel. +////////////////////////////////// +void chatSetChannelPasswordA(CHAT chat, + const char * channel, + CHATBool enable, + const char * password); + +// Gets the password in a channel. +////////////////////////////////// +void chatGetChannelPasswordA(CHAT chat, + const char * channel, + chatGetChannelPasswordCallback callback, + void * param, + CHATBool blocking); + +// Set the maximum number of users allowed in a channel. +//////////////////////////////////////////////////////// +void chatSetChannelLimitA(CHAT chat, + const char * channel, + int limit); + +// Enumerate through the bans in a channel. +/////////////////////////////////////////// +void chatEnumChannelBansA(CHAT chat, + const char * channel, + chatEnumChannelBansCallback callback, + void * param, + CHATBool blocking); + +// Adds a channel ban. +////////////////////// +void chatAddChannelBanA(CHAT chat, + const char * channel, + const char * ban); + +// Removes a ban string from a channel. +/////////////////////////////////////// +void chatRemoveChannelBanA(CHAT chat, + const char * channel, + const char * ban); + +// Set the group this channel is a part of. +/////////////////////////////////////////// +void chatSetChannelGroupA(CHAT chat, + const char * channel, + const char * group); + +// Get the number of users in the channel. +// Returns -1 if we are not in the channel. +/////////////////////////////////////////// +int chatGetChannelNumUsersA(CHAT chat, + const char * channel); + + +// Returns CHATTrue if we are in the channel +/////////////////////////////////////////// +CHATBool chatInChannelA(CHAT chat, + const char * channel); + + +/********** +** USERS ** +**********/ +// Enumerate through the users in a channel. +//////////////////////////////////////////// +void chatEnumUsersA(CHAT chat, + const char * channel, + chatEnumUsersCallback callback, + void * param, + CHATBool blocking); + +// Send a private message to a user. +//////////////////////////////////// +void chatSendUserMessageA(CHAT chat, + const char * user, + const char * message, + int type); + +// Get a user's info. +///////////////////// +void chatGetUserInfoA(CHAT chat, + const char * user, + chatGetUserInfoCallback callback, + void * param, + CHATBool blocking); + + +// Get some basic info on the user. +// PANTS|12.08.2000 +/////////////////////////////////// +void chatGetBasicUserInfoA(CHAT chat, + const char * user, + chatGetBasicUserInfoCallback callback, + void * param, + CHATBool blocking); + +// Get basic info without waiting. +// Returns CHATFalse if the info isn't available. +///////////////////////////////////////////////// +CHATBool chatGetBasicUserInfoNoWaitA(CHAT chat, + const char * nick, + const char ** user, + const char ** address); + + +// Get basic info on all the users in a channel. +// PANTS|12.19.00 +//////////////////////////////////////////////// +void chatGetChannelBasicUserInfoA(CHAT chat, + const char * channel, + chatGetChannelBasicUserInfoCallback callback, + void * param, + CHATBool blocking); + +// Invite a user into a channel. +//////////////////////////////// +void chatInviteUserA(CHAT chat, + const char * channel, + const char * user); + +// Kick a user from a channel. +////////////////////////////// +void chatKickUserA(CHAT chat, + const char * channel, + const char * user, + const char * reason); + +// Ban a user from a channel. +///////////////////////////// +void chatBanUserA(CHAT chat, + const char * channel, + const char * user); + +// Sets a user's mode in a channel. +/////////////////////////////////// +void chatSetUserModeA(CHAT chat, + const char * channel, + const char * user, + int mode); + +// Gets a user's mode in a channel. +/////////////////////////////////// +void chatGetUserModeA(CHAT chat, + const char * channel, + const char * user, + chatGetUserModeCallback callback, + void * param, + CHATBool blocking); + +// Gets a user's mode in a channel. +/////////////////////////////////// +CHATBool chatGetUserModeNoWaitA(CHAT chat, + const char * channel, + const char * user, + int * mode); + +// Get the UDP relay address for a channel +/////////////////////////////////// +void chatGetUdpRelayA(CHAT chat, + const char * channel, + chatGetUdpRelayCallback callback, + void * param, + CHATBool blocking); +/********* +** KEYS ** +*********/ +// Sets global key/values for the local user. +// Set a value to NULL or "" to clear that key. +/////////////////////////////////////////////// +void chatSetGlobalKeysA(CHAT chat, + int num, + const char ** keys, + const char ** values); + +// Gets global key/values for a user or users. +// To get the global key/values for one user, pass in that +// user's nick as the target. To get the global key/values +// for every user in a channel, use the channel name as the target. +/////////////////////////////////////////////////////////////////// +void chatGetGlobalKeysA(CHAT chat, + const char * target, + int num, + const char ** keys, + chatGetGlobalKeysCallback callback, + void * param, + CHATBool blocking); + +// Sets channel key/values. +// If user is NULL or "", the keys will be set on the channel. +// Otherwise, they will be set on the user, +// Only ops can set channel keys on other users. +// Set a value to NULL or "" to clear that key. +////////////////////////////////////////////////////////////// +void chatSetChannelKeysA(CHAT chat, + const char * channel, + const char * user, + int num, + const char ** keys, + const char ** values); + +// Gets channel key/values for a user or users, or for a channel. +// To get the channel key/values for every user in +// a channel, pass in "*" as the user. To get the keys for a channel, +// pass in NULL or "". +////////////////////////////////////////////////////////////////////// +void chatGetChannelKeysA(CHAT chat, + const char * channel, + const char * user, + int num, + const char ** keys, + chatGetChannelKeysCallback callback, + void * param, + CHATBool blocking); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This ASCII versions must be available even when GSI_UNICODE is defined +CHATBool chatGetBasicUserInfoNoWaitA(CHAT chat, + const char * nick, + const char ** user, + const char ** address); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _CHATASCII_H_ diff --git a/xrGameSpy/gamespy/Chat/chatCallbacks.c b/xrGameSpy/gamespy/Chat/chatCallbacks.c new file mode 100644 index 00000000000..87be45a26ed --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatCallbacks.c @@ -0,0 +1,1654 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include "chatMain.h" +#include "chatCallbacks.h" +#include "chatChannel.h" + +#if defined(_WIN32) +// warning about casting void* to function* +#pragma warning(disable:4055) +#endif + +/************ +** DEFINES ** +************/ +#define ASSERT_DATA(data) assert(data != NULL); assert(data->type >= 0); assert(data->type < CALLBACK_NUM); assert(data->callback != NULL); assert(data->callbackParams != NULL); assert(data->ID >= 0); +#define RAW callbackParams->raw +#define REASON callbackParams->reason +#define USER callbackParams->user +#define MESSAGE callbackParams->message +#define TYPE callbackParams->type +#define CHANNEL callbackParams->channel +#define KICKER callbackParams->kicker +#define KICKEE callbackParams->kickee +#define TOPIC callbackParams->topic +#define MODE callbackParams->mode +#define SUCCESS callbackParams->success +#define INDEX callbackParams->index +#define NUM_USERS callbackParams->numUsers +#define NUM_CHANNELS callbackParams->numChannels +#define CHANNELS callbackParams->channels +#define TOPICS callbackParams->topics +#define ENABLED callbackParams->enabled +#define PASSWORD callbackParams->password +#define USERS callbackParams->users +#define MODES callbackParams->modes +#define ADDRESS callbackParams->address +#define WHY callbackParams->why +#define OLD_NICK callbackParams->oldNick +#define NEW_NICK callbackParams->newNick +#define NUM_BANS callbackParams->numBans +#define BANS callbackParams->bans +#define NICK callbackParams->nick +#define NAME callbackParams->name +#define NUM callbackParams->num +#define KEY callbackParams->key +#define KEYS callbackParams->keys +#define VALUE callbackParams->value +#define VALUES callbackParams->values +#define RESULT callbackParams->result +#define NUM_SUGGESTED_NICKS callbackParams->numSuggestedNicks +#define SUGGESTED_NICKS callbackParams->suggestedNicks +#define COPY(param) if(srcParams->param != NULL)\ + {\ + destParams->param = goastrdup(srcParams->param);\ + if(destParams->param == NULL)\ + {\ + gsifree(destParams);\ + gsifree(data.channel);\ + /*ERRCON*/ return CHATFalse;\ + }\ + } else { destParams->param = srcParams->param; } // remove dangling "if" danger +#define COPY_MODE() if(srcParams->mode != NULL)\ + {\ + destParams->mode = (CHATChannelMode *)gsimalloc(sizeof(CHATChannelMode));\ + if(destParams->mode == NULL)\ + {\ + gsifree(destParams);\ + gsifree(data.channel);\ + /*ERRCON*/ return CHATFalse;\ + }\ + memcpy(destParams->mode, srcParams->mode, sizeof(CHATChannelMode));\ + } else {} // remove dangling "if" danger +#define COPY_STR_ARRAY(array, num) assert(srcParams->num >= 0);\ + if(!srcParams->array)\ + destParams->array = NULL;\ + else\ + {\ + destParams->array = (char **)gsimalloc(sizeof(char *) * srcParams->num);\ + if(destParams->array == NULL)\ + {\ + gsifree(destParams);\ + gsifree(data.channel);\ + /*ERRCON*/ return CHATFalse;\ + }\ + for(i = 0 ; i < srcParams->num ; i++)\ + {\ + if(srcParams->array[i] == NULL)\ + destParams->array[i] = NULL;\ + else\ + {\ + destParams->array[i] = goastrdup(srcParams->array[i]);\ + if(destParams->array[i] == NULL)\ + {\ + for(i-- ; i >= 0 ; i--)\ + gsifree(destParams->array[i]);\ + gsifree(destParams->array);\ + gsifree(destParams);\ + gsifree(data.channel);\ + return CHATFalse;\ + }\ + }\ + }\ + } +#define COPY_INT_ARRAY(array, num) assert(srcParams->num >= 0);\ + if(srcParams->num > 0)\ + {\ + assert(srcParams->array != NULL);\ + len = (int)(sizeof(int) * srcParams->num);\ + destParams->array = (int *)gsimalloc((unsigned int)len);\ + if(destParams->array == NULL)\ + {\ + gsifree(destParams);\ + gsifree(data.channel);\ + /*ERRCON*/ return CHATFalse;\ + }\ + memcpy(destParams->array, srcParams->array, (unsigned int)len);\ + } else {} // remove dangling "if" danger + +#define FREE_STRING_ARRAY(array, num) if (num > 0 && array != NULL)\ + {\ + int i = 0;\ + for (; i < num; i++)\ + gsifree(array[i]);\ + gsifree(array);\ + } else {} // remove dangling "if" danger +/********** +** TYPES ** +**********/ +typedef struct ciCallbackData +{ + int type; + void * callback; + void * callbackParams; + void * param; + int ID; + char * channel; +} ciCallbackData; + +/************** +** FUNCTIONS ** +**************/ +static void ciCallbacksArrayElementFreeFn(void * elem) +{ + ciCallbackData * data = (ciCallbackData *)elem; + GS_ASSERT(data != NULL); + if (data->channel) + gsifree(data->channel); +} + +static void ciFreeCallbackData(ciCallbackData * data) +{ + ASSERT_DATA(data); + + // Find which type of callback it is. + ///////////////////////////////////// + switch(data->type) + { + case CALLBACK_RAW: + { + ciCallbackRawParams * callbackParams = (ciCallbackRawParams *)data->callbackParams; + gsifree(RAW); + break; + } + + case CALLBACK_DISCONNECTED: + { + ciCallbackDisconnectedParams * callbackParams = (ciCallbackDisconnectedParams *)data->callbackParams; + gsifree(REASON); + break; + } + + case CALLBACK_PRIVATE_MESSAGE: + { + ciCallbackPrivateMessageParams * callbackParams = (ciCallbackPrivateMessageParams *)data->callbackParams; + gsifree(USER); + gsifree(MESSAGE); + break; + } + + case CALLBACK_INVITED: + { + ciCallbackInvitedParams * callbackParams = (ciCallbackInvitedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + break; + } + + case CALLBACK_CHANNEL_MESSAGE: + { + ciCallbackChannelMessageParams * callbackParams = (ciCallbackChannelMessageParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + gsifree(MESSAGE); + break; + } + + case CALLBACK_KICKED: + { + ciCallbackKickedParams * callbackParams = (ciCallbackKickedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + gsifree(REASON); + break; + } + + case CALLBACK_USER_JOINED: + { + ciCallbackUserJoinedParams * callbackParams = (ciCallbackUserJoinedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + break; + } + + case CALLBACK_USER_PARTED: + { + ciCallbackUserPartedParams * callbackParams = (ciCallbackUserPartedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + gsifree(REASON); + gsifree(KICKER); + break; + } + + case CALLBACK_USER_CHANGED_NICK: + { + ciCallbackUserChangedNickParams * callbackParams = (ciCallbackUserChangedNickParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(OLD_NICK); + gsifree(NEW_NICK); + break; + } + + case CALLBACK_TOPIC_CHANGED: + { + ciCallbackTopicChangedParams * callbackParams = (ciCallbackTopicChangedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(TOPIC); + break; + } + + case CALLBACK_CHANNEL_MODE_CHANGED: + { + ciCallbackChannelModeChangedParams * callbackParams = (ciCallbackChannelModeChangedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(MODE); + break; + } + + case CALLBACK_USER_MODE_CHANGED: + { + ciCallbackUserModeChangedParams * callbackParams = (ciCallbackUserModeChangedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + break; + } + + case CALLBACK_USER_LIST_UPDATED: + { + ciCallbackUserListUpdatedParams * callbackParams = (ciCallbackUserListUpdatedParams *)data->callbackParams; + gsifree(CHANNEL); + break; + } + + case CALLBACK_ENUM_CHANNELS_EACH: + { + ciCallbackEnumChannelsEachParams * callbackParams = (ciCallbackEnumChannelsEachParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(TOPIC); + break; + } + + case CALLBACK_ENUM_CHANNELS_ALL: + { + int i; + ciCallbackEnumChannelsAllParams * callbackParams = (ciCallbackEnumChannelsAllParams *)data->callbackParams; + for(i = 0 ; i < NUM_CHANNELS ; i++) + { + gsifree(CHANNELS[i]); + gsifree(TOPICS[i]); + } + gsifree(CHANNELS); + gsifree(TOPICS); + gsifree(NUM_USERS); + break; + } + + case CALLBACK_ENTER_CHANNEL: + { + ciCallbackEnterChannelParams * callbackParams = (ciCallbackEnterChannelParams *)data->callbackParams; + gsifree(CHANNEL); + break; + } + + case CALLBACK_GET_CHANNEL_TOPIC: + { + ciCallbackGetChannelTopicParams * callbackParams = (ciCallbackGetChannelTopicParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(TOPIC); + break; + } + + case CALLBACK_GET_CHANNEL_MODE: + { + ciCallbackGetChannelModeParams * callbackParams = (ciCallbackGetChannelModeParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(MODE); + break; + } + + case CALLBACK_GET_UDPRELAY: + { + ciCallbackGetUdpRelayParams * callbackParams = (ciCallbackGetUdpRelayParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(callbackParams->udpIp); + break; + } + + case CALLBACK_GET_CHANNEL_PASSWORD: + { + ciCallbackGetChannelPasswordParams * callbackParams = (ciCallbackGetChannelPasswordParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(PASSWORD); + break; + } + + case CALLBACK_ENUM_USERS: + { + int i; + ciCallbackEnumUsersParams * callbackParams = (ciCallbackEnumUsersParams *)data->callbackParams; + gsifree(CHANNEL); + for(i = 0 ; i < NUM_USERS ; i++) + gsifree(USERS[i]); + gsifree(USERS); + gsifree(MODES); + break; + } + + case CALLBACK_GET_USER_INFO: + { + int i; + ciCallbackGetUserInfoParams * callbackParams = (ciCallbackGetUserInfoParams *)data->callbackParams; + gsifree(NICK); + gsifree(USER); + gsifree(NAME); + gsifree(ADDRESS); + for(i = 0 ; i < NUM_CHANNELS ; i++) + gsifree(CHANNELS[i]); + gsifree(CHANNELS); + break; + } + + case CALLBACK_GET_BASIC_USER_INFO: + { + ciCallbackGetBasicUserInfoParams * callbackParams = (ciCallbackGetBasicUserInfoParams *)data->callbackParams; + gsifree(NICK); + gsifree(USER); + gsifree(ADDRESS); + break; + } + + case CALLBACK_GET_CHANNEL_BASIC_USER_INFO: + { + ciCallbackGetChannelBasicUserInfoParams * callbackParams = (ciCallbackGetChannelBasicUserInfoParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(NICK); + gsifree(USER); + gsifree(ADDRESS); + break; + } + + case CALLBACK_GET_USER_MODE: + { + ciCallbackGetUserModeParams * callbackParams = (ciCallbackGetUserModeParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + break; + } + + case CALLBACK_ENUM_CHANNEL_BANS: + { + int i; + ciCallbackEnumChannelBansParams * callbackParams = (ciCallbackEnumChannelBansParams *)data->callbackParams; + gsifree(CHANNEL); + for(i = 0 ; i < NUM_BANS ; i++) + gsifree(BANS[i]); + gsifree(BANS); + break; + } + + case CALLBACK_NICK_ERROR: + { + int i; + ciCallbackNickErrorParams * callbackParams = (ciCallbackNickErrorParams *)data->callbackParams; + gsifree(NICK); + for(i = 0 ; i < NUM_SUGGESTED_NICKS; i++) + gsifree(SUGGESTED_NICKS[i]); + gsifree(SUGGESTED_NICKS); + break; + } + + case CALLBACK_CHANGE_NICK: + { + ciCallbackChangeNickParams * callbackParams = (ciCallbackChangeNickParams *)data->callbackParams; + gsifree(OLD_NICK); + gsifree(NEW_NICK); + break; + } + + case CALLBACK_NEW_USER_LIST: + { + int i; + ciCallbackNewUserListParams * callbackParams = (ciCallbackNewUserListParams *)data->callbackParams; + gsifree(CHANNEL); + for(i = 0 ; i < NUM_USERS ; i++) + gsifree(USERS[i]); + gsifree(USERS); + gsifree(MODES); + break; + } + + case CALLBACK_BROADCAST_KEY_CHANGED: + { + ciCallbackBroadcastKeyChangedParams * callbackParams = (ciCallbackBroadcastKeyChangedParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + gsifree(KEY); + gsifree(VALUE); + break; + } + + case CALLBACK_GET_GLOBAL_KEYS: + { + int i; + ciCallbackGetGlobalKeysParams * callbackParams = (ciCallbackGetGlobalKeysParams *)data->callbackParams; + gsifree(USER); + for(i = 0 ; i < NUM ; i++) + { + gsifree(KEYS[i]); + if(VALUES) + gsifree(VALUES[i]); + } + gsifree(KEYS); + gsifree(VALUES); + break; + } + + case CALLBACK_GET_CHANNEL_KEYS: + { + int i; + ciCallbackGetChannelKeysParams * callbackParams = (ciCallbackGetChannelKeysParams *)data->callbackParams; + gsifree(CHANNEL); + gsifree(USER); + for(i = 0 ; i < NUM ; i++) + { + gsifree(KEYS[i]); + if(VALUES) + gsifree(VALUES[i]); + } + gsifree(KEYS); + gsifree(VALUES); + break; + } + + case CALLBACK_AUTHENTICATE_CDKEY: + { + ciCallbackAuthenticateCDKeyParams * callbackParams = (ciCallbackAuthenticateCDKeyParams *)data->callbackParams; + gsifree(MESSAGE); + break; + } + + default: + // The type for this callback is messed up. + /////////////////////////////////////////// + assert(0); + } + + // gsifree the params structure. + ///////////////////////////// + gsifree(data->callbackParams); +} + +CHATBool ciInitCallbacks(ciConnection * connection) +{ + // Setup the darray. + //////////////////// + connection->callbackList = ArrayNew(sizeof(ciCallbackData), 128, ciCallbacksArrayElementFreeFn); + if(connection->callbackList == NULL) + return CHATFalse; + + return CHATTrue; +} + +void ciCleanupCallbacks(CHAT chat) +{ + CONNECTION; + + // Cleanup. + /////////// + if(connection->callbackList != NULL) + { + ciCallbackData * data; + int len; + int i; + + // Get the number of callbacks. + /////////////////////////////// + len = ArrayLength(connection->callbackList); + + // gsifree the data. + ///////////////// + for(i = 0 ; i < len ; i++) + { + data = (ciCallbackData *)ArrayNth(connection->callbackList, i); + ASSERT_DATA(data); + + // gsifree the data. + ///////////////// + ciFreeCallbackData(data); + } + + // gsifree the list. + ///////////////// + ArrayFree(connection->callbackList); + } +} + +CHATBool ciAddCallback_(CHAT chat, int type, void * callback, void * callbackParams, void * param, int ID, const char * channel, size_t callbackParamsSize) +{ + ciCallbackData data; + int len; + int i; + CONNECTION; + + assert(type >= 0); + assert(type < CALLBACK_NUM); + assert(connection->callbackList != NULL); + assert(callback != NULL); + assert(callbackParams != NULL); + assert(callbackParamsSize > 0); + assert(ID >= 0); +#ifdef _DEBUG + if(channel != NULL) + assert(channel[0] != '\0'); +#endif + + // Setup the data. + ////////////////// + memset(&data, 0, sizeof(ciCallbackData)); + data.type = type; + data.callback = callback; +#ifndef _DEBUG + data.callbackParams = gsimalloc(callbackParamsSize); +#else + data.callbackParams = gsimalloc(callbackParamsSize + 64); + memset(data.callbackParams, 0xC4, callbackParamsSize + 64); +#endif + if(data.callbackParams == NULL) + return CHATFalse; //ERRCON + memcpy(data.callbackParams, callbackParams, callbackParamsSize); + data.param = param; + data.ID = ID; + if(channel == NULL) + data.channel = NULL; + else + { + len = (int)(strlen(channel) + 1); + data.channel = (char *)gsimalloc((unsigned int)len); + if(data.channel == NULL) + { + gsifree(data.callbackParams); + return CHATFalse; //ERRCON + } + memcpy(data.channel, channel, (unsigned int)len); + } + + // Find which type of callback it is. + ///////////////////////////////////// + switch(data.type) + { + case CALLBACK_RAW: + { + ciCallbackRawParams * destParams = (ciCallbackRawParams *)data.callbackParams; + ciCallbackRawParams * srcParams = (ciCallbackRawParams *)callbackParams; + COPY(raw); + break; + } + + case CALLBACK_DISCONNECTED: + { + ciCallbackDisconnectedParams * destParams = (ciCallbackDisconnectedParams *)data.callbackParams; + ciCallbackDisconnectedParams * srcParams = (ciCallbackDisconnectedParams *)callbackParams; + COPY(reason); + break; + } + + case CALLBACK_PRIVATE_MESSAGE: + { + ciCallbackPrivateMessageParams * destParams = (ciCallbackPrivateMessageParams *)data.callbackParams; + ciCallbackPrivateMessageParams * srcParams = (ciCallbackPrivateMessageParams *)callbackParams; + COPY(user); + COPY(message); + break; + } + + case CALLBACK_INVITED: + { + ciCallbackInvitedParams * destParams = (ciCallbackInvitedParams *)data.callbackParams; + ciCallbackInvitedParams * srcParams = (ciCallbackInvitedParams *)callbackParams; + COPY(channel); + COPY(user); + break; + } + + case CALLBACK_CHANNEL_MESSAGE: + { + ciCallbackChannelMessageParams * destParams = (ciCallbackChannelMessageParams *)data.callbackParams; + ciCallbackChannelMessageParams * srcParams = (ciCallbackChannelMessageParams *)callbackParams; + COPY(channel); + COPY(user); + COPY(message); + break; + } + + case CALLBACK_KICKED: + { + ciCallbackKickedParams * destParams = (ciCallbackKickedParams *)data.callbackParams; + ciCallbackKickedParams * srcParams = (ciCallbackKickedParams *)callbackParams; + COPY(channel); + COPY(user); + COPY(reason); + break; + } + + case CALLBACK_USER_JOINED: + { + ciCallbackUserJoinedParams * destParams = (ciCallbackUserJoinedParams *)data.callbackParams; + ciCallbackUserJoinedParams * srcParams = (ciCallbackUserJoinedParams *)callbackParams; + COPY(channel); + COPY(user); + break; + } + + case CALLBACK_USER_PARTED: + { + ciCallbackUserPartedParams * destParams = (ciCallbackUserPartedParams *)data.callbackParams; + ciCallbackUserPartedParams * srcParams = (ciCallbackUserPartedParams *)callbackParams; + COPY(channel); + COPY(user); + COPY(reason); + COPY(kicker); + break; + } + + case CALLBACK_USER_CHANGED_NICK: + { + ciCallbackUserChangedNickParams * destParams = (ciCallbackUserChangedNickParams *)data.callbackParams; + ciCallbackUserChangedNickParams * srcParams = (ciCallbackUserChangedNickParams *)callbackParams; + COPY(channel); + COPY(oldNick); + COPY(newNick); + break; + } + + case CALLBACK_TOPIC_CHANGED: + { + ciCallbackTopicChangedParams * destParams = (ciCallbackTopicChangedParams *)data.callbackParams; + ciCallbackTopicChangedParams * srcParams = (ciCallbackTopicChangedParams *)callbackParams; + COPY(channel); + COPY(topic); + break; + } + + case CALLBACK_CHANNEL_MODE_CHANGED: + { + ciCallbackChannelModeChangedParams * destParams = (ciCallbackChannelModeChangedParams *)data.callbackParams; + ciCallbackChannelModeChangedParams * srcParams = (ciCallbackChannelModeChangedParams *)callbackParams; + COPY(channel); + COPY_MODE(); + break; + } + + case CALLBACK_USER_MODE_CHANGED: + { + ciCallbackUserModeChangedParams * destParams = (ciCallbackUserModeChangedParams *)data.callbackParams; + ciCallbackUserModeChangedParams * srcParams = (ciCallbackUserModeChangedParams *)callbackParams; + COPY(channel); + COPY(user); + break; + } + + case CALLBACK_USER_LIST_UPDATED: + { + ciCallbackUserListUpdatedParams * destParams = (ciCallbackUserListUpdatedParams *)data.callbackParams; + ciCallbackUserListUpdatedParams * srcParams = (ciCallbackUserListUpdatedParams *)callbackParams; + COPY(channel); + break; + } + + case CALLBACK_ENUM_CHANNELS_EACH: + { + ciCallbackEnumChannelsEachParams * destParams = (ciCallbackEnumChannelsEachParams *)data.callbackParams; + ciCallbackEnumChannelsEachParams * srcParams = (ciCallbackEnumChannelsEachParams *)callbackParams; + COPY(channel); + COPY(topic); + break; + } + + case CALLBACK_ENUM_CHANNELS_ALL: + { + ciCallbackEnumChannelsAllParams * destParams = (ciCallbackEnumChannelsAllParams *)data.callbackParams; + ciCallbackEnumChannelsAllParams * srcParams = (ciCallbackEnumChannelsAllParams *)callbackParams; + COPY_STR_ARRAY(channels, numChannels); + COPY_STR_ARRAY(topics, numChannels); + COPY_INT_ARRAY(numUsers, numChannels); + break; + } + + case CALLBACK_ENTER_CHANNEL: + { + ciCallbackEnterChannelParams * destParams = (ciCallbackEnterChannelParams *)data.callbackParams; + ciCallbackEnterChannelParams * srcParams = (ciCallbackEnterChannelParams *)callbackParams; + COPY(channel); + break; + } + + case CALLBACK_GET_CHANNEL_TOPIC: + { + ciCallbackGetChannelTopicParams * destParams = (ciCallbackGetChannelTopicParams *)data.callbackParams; + ciCallbackGetChannelTopicParams * srcParams = (ciCallbackGetChannelTopicParams *)callbackParams; + COPY(channel); + COPY(topic); + break; + } + + case CALLBACK_GET_CHANNEL_MODE: + { + ciCallbackGetChannelModeParams * destParams = (ciCallbackGetChannelModeParams *)data.callbackParams; + ciCallbackGetChannelModeParams * srcParams = (ciCallbackGetChannelModeParams *)callbackParams; + COPY(channel); + COPY_MODE(); + break; + } + + case CALLBACK_GET_UDPRELAY: + { + ciCallbackGetUdpRelayParams * destParams = (ciCallbackGetUdpRelayParams *)data.callbackParams; + ciCallbackGetUdpRelayParams * srcParams = (ciCallbackGetUdpRelayParams *)callbackParams; + COPY(channel); + COPY(udpIp); + break; + } + + case CALLBACK_GET_CHANNEL_PASSWORD: + { + ciCallbackGetChannelPasswordParams * destParams = (ciCallbackGetChannelPasswordParams *)data.callbackParams; + ciCallbackGetChannelPasswordParams * srcParams = (ciCallbackGetChannelPasswordParams *)callbackParams; + COPY(channel); + COPY(password); + break; + } + + case CALLBACK_ENUM_USERS: + { + ciCallbackEnumUsersParams * destParams = (ciCallbackEnumUsersParams *)data.callbackParams; + ciCallbackEnumUsersParams * srcParams = (ciCallbackEnumUsersParams *)callbackParams; + COPY(channel); + COPY_STR_ARRAY(users, numUsers); + COPY_INT_ARRAY(modes, numUsers); + break; + } + + case CALLBACK_GET_USER_INFO: + { + ciCallbackGetUserInfoParams * destParams = (ciCallbackGetUserInfoParams *)data.callbackParams; + ciCallbackGetUserInfoParams * srcParams = (ciCallbackGetUserInfoParams *)callbackParams; + COPY(nick); + COPY(user); + COPY(name); + COPY(address); + COPY_STR_ARRAY(channels, numChannels); + break; + } + + case CALLBACK_GET_BASIC_USER_INFO: + { + ciCallbackGetBasicUserInfoParams * destParams = (ciCallbackGetBasicUserInfoParams *)data.callbackParams; + ciCallbackGetBasicUserInfoParams * srcParams = (ciCallbackGetBasicUserInfoParams *)callbackParams; + COPY(nick); + COPY(user); + COPY(address); + break; + } + + case CALLBACK_GET_CHANNEL_BASIC_USER_INFO: + { + ciCallbackGetChannelBasicUserInfoParams * destParams = (ciCallbackGetChannelBasicUserInfoParams *)data.callbackParams; + ciCallbackGetChannelBasicUserInfoParams * srcParams = (ciCallbackGetChannelBasicUserInfoParams *)callbackParams; + COPY(channel); + COPY(nick); + COPY(user); + COPY(address); + break; + } + + case CALLBACK_GET_USER_MODE: + { + ciCallbackGetUserModeParams * destParams = (ciCallbackGetUserModeParams *)data.callbackParams; + ciCallbackGetUserModeParams * srcParams = (ciCallbackGetUserModeParams *)callbackParams; + COPY(channel); + COPY(user); + break; + } + + case CALLBACK_ENUM_CHANNEL_BANS: + { + ciCallbackEnumChannelBansParams * destParams = (ciCallbackEnumChannelBansParams *)data.callbackParams; + ciCallbackEnumChannelBansParams * srcParams = (ciCallbackEnumChannelBansParams *)callbackParams; + COPY(channel); + COPY_STR_ARRAY(bans, numBans); + break; + } + + case CALLBACK_NICK_ERROR: + { + ciCallbackNickErrorParams * destParams = (ciCallbackNickErrorParams *)data.callbackParams; + ciCallbackNickErrorParams * srcParams = (ciCallbackNickErrorParams *)callbackParams; + COPY(nick); + COPY_STR_ARRAY(suggestedNicks, numSuggestedNicks); + break; + } + + case CALLBACK_CHANGE_NICK: + { + ciCallbackChangeNickParams * destParams = (ciCallbackChangeNickParams *)data.callbackParams; + ciCallbackChangeNickParams * srcParams = (ciCallbackChangeNickParams *)callbackParams; + COPY(oldNick); + COPY(newNick); + break; + } + + case CALLBACK_NEW_USER_LIST: + { + ciCallbackNewUserListParams * destParams = (ciCallbackNewUserListParams *)data.callbackParams; + ciCallbackNewUserListParams * srcParams = (ciCallbackNewUserListParams *)callbackParams; + COPY(channel); + COPY_STR_ARRAY(users, numUsers); + COPY_INT_ARRAY(modes, numUsers); + break; + } + + case CALLBACK_BROADCAST_KEY_CHANGED: + { + ciCallbackBroadcastKeyChangedParams * destParams = (ciCallbackBroadcastKeyChangedParams *)data.callbackParams; + ciCallbackBroadcastKeyChangedParams * srcParams = (ciCallbackBroadcastKeyChangedParams *)callbackParams; + COPY(channel); + COPY(user); + COPY(key); + COPY(value); + break; + } + + case CALLBACK_GET_GLOBAL_KEYS: + { + ciCallbackGetGlobalKeysParams * destParams = (ciCallbackGetGlobalKeysParams *)data.callbackParams; + ciCallbackGetGlobalKeysParams * srcParams = (ciCallbackGetGlobalKeysParams *)callbackParams; + COPY(user); + COPY_STR_ARRAY(keys, num); + COPY_STR_ARRAY(values, num); + break; + } + + case CALLBACK_GET_CHANNEL_KEYS: + { + ciCallbackGetChannelKeysParams * destParams = (ciCallbackGetChannelKeysParams *)data.callbackParams; + ciCallbackGetChannelKeysParams * srcParams = (ciCallbackGetChannelKeysParams *)callbackParams; + COPY(channel); + COPY(user); + COPY_STR_ARRAY(keys, num); + COPY_STR_ARRAY(values, num); + break; + } + + case CALLBACK_AUTHENTICATE_CDKEY: + { + ciCallbackAuthenticateCDKeyParams * destParams = (ciCallbackAuthenticateCDKeyParams *)data.callbackParams; + ciCallbackAuthenticateCDKeyParams * srcParams = (ciCallbackAuthenticateCDKeyParams *)callbackParams; + COPY(message); + break; + } + + default: + // The type for this callback is messed up. + /////////////////////////////////////////// + assert(0); + } + + // Add it to the array. + /////////////////////// + ArrayAppend(connection->callbackList, &data); + + return CHATTrue; +} + +static void ciCallCallback(CHAT chat, ciCallbackData * data) +{ + void * param; + //CONNECTION; + + ASSERT_DATA(data); + + // Cache the param. + /////////////////// + param = data->param; + + // Find which type of callback it is. + ///////////////////////////////////// + switch(data->type) + { + case CALLBACK_RAW: + { + ciCallbackRawParams * callbackParams = (ciCallbackRawParams *)data->callbackParams; + chatRaw callback = (chatRaw)data->callback; +#ifndef GSI_UNICODE + callback(chat, RAW, param); + break; +#else + // UNICODE: Copy all the params, call the callback, free the params + unsigned short* raw_W = UTF8ToUCS2StringAlloc(RAW); + callback(chat, raw_W, param); + gsifree(raw_W); + break; +#endif + } + + case CALLBACK_DISCONNECTED: + { + ciCallbackDisconnectedParams * callbackParams = (ciCallbackDisconnectedParams *)data->callbackParams; + chatDisconnected callback = (chatDisconnected)data->callback; +#ifndef GSI_UNICODE + callback(chat, REASON, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* reason_W = UTF8ToUCS2StringAlloc(REASON); + callback(chat, reason_W, param); + gsifree(reason_W); + break; +#endif + } + + case CALLBACK_PRIVATE_MESSAGE: + { + ciCallbackPrivateMessageParams * callbackParams = (ciCallbackPrivateMessageParams *)data->callbackParams; + chatPrivateMessage callback = (chatPrivateMessage)data->callback; +#ifndef GSI_UNICODE + callback(chat, USER, MESSAGE, TYPE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* message_W = UTF8ToUCS2StringAlloc(MESSAGE); + callback(chat, user_W, message_W, TYPE, param); + gsifree(user_W); + gsifree(message_W); + break; +#endif + } + + case CALLBACK_INVITED: + { + ciCallbackInvitedParams * callbackParams = (ciCallbackInvitedParams *)data->callbackParams; + chatInvited callback = (chatInvited)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + callback(chat, channel_W, user_W, param); + gsifree(channel_W); + gsifree(user_W); + break; +#endif + } + + case CALLBACK_CHANNEL_MESSAGE: + { + ciCallbackChannelMessageParams * callbackParams = (ciCallbackChannelMessageParams *)data->callbackParams; + chatChannelMessage callback = (chatChannelMessage)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, MESSAGE, TYPE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* message_W = UTF8ToUCS2StringAlloc(MESSAGE); + callback(chat, channel_W, user_W, message_W, TYPE, param); + gsifree(channel_W); + gsifree(user_W); + gsifree(message_W); + break; +#endif + } + + case CALLBACK_KICKED: + { + ciCallbackKickedParams * callbackParams = (ciCallbackKickedParams *)data->callbackParams; + chatKicked callback = (chatKicked)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, REASON, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* reason_W = UTF8ToUCS2StringAlloc(REASON); + callback(chat, channel_W, user_W, reason_W, param); + gsifree(channel_W); + gsifree(user_W); + gsifree(reason_W); + break; +#endif + } + + case CALLBACK_USER_JOINED: + { + ciCallbackUserJoinedParams * callbackParams = (ciCallbackUserJoinedParams *)data->callbackParams; + chatUserJoined callback = (chatUserJoined)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, MODE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + callback(chat, channel_W, user_W, MODE, param); + gsifree(channel_W); + gsifree(user_W); + break; +#endif + + } + + case CALLBACK_USER_PARTED: + { + ciCallbackUserPartedParams * callbackParams = (ciCallbackUserPartedParams *)data->callbackParams; + chatUserParted callback = (chatUserParted)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, WHY, REASON, KICKER, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* reason_W = UTF8ToUCS2StringAlloc(REASON); + unsigned short* kicker_W = UTF8ToUCS2StringAlloc(KICKER); + callback(chat, channel_W, user_W, WHY, reason_W, kicker_W, param); + gsifree(channel_W); + gsifree(user_W); + gsifree(reason_W); + gsifree(kicker_W); + break; +#endif + } + + case CALLBACK_USER_CHANGED_NICK: + { + ciCallbackUserChangedNickParams * callbackParams = (ciCallbackUserChangedNickParams *)data->callbackParams; + chatUserChangedNick callback = (chatUserChangedNick)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, OLD_NICK, NEW_NICK, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* oldnick_W = UTF8ToUCS2StringAlloc(OLD_NICK); + unsigned short* newnick_W = UTF8ToUCS2StringAlloc(NEW_NICK); + callback(chat, channel_W, oldnick_W, newnick_W, param); + gsifree(channel_W); + gsifree(oldnick_W); + gsifree(newnick_W); + break; +#endif + } + + case CALLBACK_TOPIC_CHANGED: + { + ciCallbackTopicChangedParams * callbackParams = (ciCallbackTopicChangedParams *)data->callbackParams; + chatTopicChanged callback = (chatTopicChanged)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, TOPIC, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* topic_W = UTF8ToUCS2StringAlloc(TOPIC); + callback(chat, channel_W, topic_W, param); + gsifree(channel_W); + gsifree(topic_W); + break; +#endif + } + + case CALLBACK_CHANNEL_MODE_CHANGED: + { + ciCallbackChannelModeChangedParams * callbackParams = (ciCallbackChannelModeChangedParams *)data->callbackParams; + chatChannelModeChanged callback = (chatChannelModeChanged)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, MODE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + callback(chat, channel_W, MODE, param); + gsifree(channel_W); + break; +#endif + } + + case CALLBACK_USER_MODE_CHANGED: + { + ciCallbackUserModeChangedParams * callbackParams = (ciCallbackUserModeChangedParams *)data->callbackParams; + chatUserModeChanged callback = (chatUserModeChanged)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, MODE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + callback(chat, channel_W, user_W, MODE, param); + gsifree(channel_W); + gsifree(user_W); + break; +#endif + } + + case CALLBACK_USER_LIST_UPDATED: + { + ciCallbackUserListUpdatedParams * callbackParams = (ciCallbackUserListUpdatedParams *)data->callbackParams; + chatUserListUpdated callback = (chatUserListUpdated)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + callback(chat, channel_W, param); + gsifree(channel_W); + break; +#endif + } + + case CALLBACK_ENUM_CHANNELS_EACH: + { + ciCallbackEnumChannelsEachParams * callbackParams = (ciCallbackEnumChannelsEachParams *)data->callbackParams; + chatEnumChannelsCallbackEach callback = (chatEnumChannelsCallbackEach)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, INDEX, CHANNEL, TOPIC, NUM_USERS, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* topic_W = UTF8ToUCS2StringAlloc(TOPIC); + callback(chat, SUCCESS, INDEX, channel_W, topic_W, NUM_USERS, param); + gsifree(channel_W); + gsifree(topic_W); + break; +#endif + } + + case CALLBACK_ENUM_CHANNELS_ALL: + { + ciCallbackEnumChannelsAllParams * callbackParams = (ciCallbackEnumChannelsAllParams *)data->callbackParams; + chatEnumChannelsCallbackAll callback = (chatEnumChannelsCallbackAll)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, NUM_CHANNELS, (const char **)CHANNELS, (const char **)TOPICS, NUM_USERS, param); + break; +#else + unsigned short** channels_W = UTF8ToUCS2StringArrayAlloc((const char **)CHANNELS, NUM_CHANNELS); + unsigned short** topics_W = UTF8ToUCS2StringArrayAlloc((const char **)TOPICS, NUM_CHANNELS); + callback(chat, SUCCESS, NUM_CHANNELS, (const unsigned short**)channels_W, (const unsigned short**)topics_W, NUM_USERS, param); + FREE_STRING_ARRAY(channels_W, NUM_CHANNELS); + FREE_STRING_ARRAY(topics_W, NUM_CHANNELS); + break; +#endif + } + + case CALLBACK_ENTER_CHANNEL: + { + ciCallbackEnterChannelParams * callbackParams = (ciCallbackEnterChannelParams *)data->callbackParams; + chatEnterChannelCallback callback = (chatEnterChannelCallback)data->callback; + + // Call this before the callback so funcs called within the callback know. + ////////////////////////////////////////////////////////////////////////// + ciJoinCallbackCalled(chat, CHANNEL); + +#ifndef GSI_UNICODE + callback(chat, SUCCESS, RESULT, CHANNEL, param); + break; +#else + { + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + callback(chat, SUCCESS, RESULT, channel_W, param); + gsifree(channel_W); + break; + } +#endif + } + + case CALLBACK_GET_CHANNEL_TOPIC: + { + ciCallbackGetChannelTopicParams * callbackParams = (ciCallbackGetChannelTopicParams *)data->callbackParams; + chatGetChannelTopicCallback callback = (chatGetChannelTopicCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, TOPIC, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* topic_W = UTF8ToUCS2StringAlloc(TOPIC); + callback(chat, SUCCESS, channel_W, topic_W, param); + gsifree(channel_W); + gsifree(topic_W); + break; +#endif + } + + case CALLBACK_GET_CHANNEL_MODE: + { + ciCallbackGetChannelModeParams * callbackParams = (ciCallbackGetChannelModeParams *)data->callbackParams; + chatGetChannelModeCallback callback = (chatGetChannelModeCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, MODE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + callback(chat, SUCCESS, channel_W, MODE, param); + gsifree(channel_W); + break; +#endif + } + + case CALLBACK_GET_UDPRELAY: + { + ciCallbackGetUdpRelayParams * callbackParams = (ciCallbackGetUdpRelayParams *)data->callbackParams; + chatGetUdpRelayCallback callback = (chatGetUdpRelayCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, callbackParams->udpIp, callbackParams->udpPort, callbackParams->udpKey, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* udpIp_W = UTF8ToUCS2StringAlloc(callbackParams->udpIp); + callback(chat, channel_W, udpIp_W, callbackParams->udpPort, callbackParams->udpKey, param); + gsifree(channel_W); + gsifree(udpIp_W); + break; +#endif + } + + case CALLBACK_GET_CHANNEL_PASSWORD: + { + ciCallbackGetChannelPasswordParams * callbackParams = (ciCallbackGetChannelPasswordParams *)data->callbackParams; + chatGetChannelPasswordCallback callback = (chatGetChannelPasswordCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, ENABLED, PASSWORD, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* password_W = UTF8ToUCS2StringAlloc(PASSWORD); + callback(chat, SUCCESS, channel_W, ENABLED, password_W, param); + gsifree(channel_W); + gsifree(password_W); + break; +#endif + } + + case CALLBACK_ENUM_USERS: + { + ciCallbackEnumUsersParams * callbackParams = (ciCallbackEnumUsersParams *)data->callbackParams; + chatEnumUsersCallback callback = (chatEnumUsersCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, NUM_USERS, (const char **)USERS, MODES, param); + break; +#else + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short** users_W = UTF8ToUCS2StringArrayAlloc((const char **)USERS, NUM_USERS); + callback(chat, SUCCESS, channel_W, NUM_USERS, (const unsigned short**)users_W, MODES, param); + gsifree(channel_W); + FREE_STRING_ARRAY(users_W, NUM_USERS); + break; +#endif + } + + case CALLBACK_GET_USER_INFO: + { + ciCallbackGetUserInfoParams * callbackParams = (ciCallbackGetUserInfoParams *)data->callbackParams; + chatGetUserInfoCallback callback = (chatGetUserInfoCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, NICK, USER, NAME, ADDRESS, NUM_CHANNELS, (const char **)CHANNELS, param); + break; +#else + unsigned short* nick_W = UTF8ToUCS2StringAlloc(NICK); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* name_W = UTF8ToUCS2StringAlloc(NAME); + unsigned short* address_W = UTF8ToUCS2StringAlloc(ADDRESS); + unsigned short** channels_W = UTF8ToUCS2StringArrayAlloc((const char **)CHANNELS, NUM_CHANNELS); + callback(chat, SUCCESS, nick_W, user_W, name_W, address_W, NUM_CHANNELS, (const unsigned short**)channels_W, param); + gsifree(nick_W); + gsifree(user_W); + gsifree(name_W); + gsifree(address_W); + FREE_STRING_ARRAY(channels_W, NUM_CHANNELS); + break; +#endif + } + + case CALLBACK_GET_BASIC_USER_INFO: + { + ciCallbackGetBasicUserInfoParams * callbackParams = (ciCallbackGetBasicUserInfoParams *)data->callbackParams; + chatGetBasicUserInfoCallback callback = (chatGetBasicUserInfoCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, NICK, USER, ADDRESS, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* nick_W = UTF8ToUCS2StringAlloc(NICK); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* address_W = UTF8ToUCS2StringAlloc(ADDRESS); + callback(chat, SUCCESS, nick_W, user_W, address_W, param); + gsifree(nick_W); + gsifree(user_W); + gsifree(address_W); + break; +#endif + } + + case CALLBACK_GET_CHANNEL_BASIC_USER_INFO: + { + ciCallbackGetChannelBasicUserInfoParams * callbackParams = (ciCallbackGetChannelBasicUserInfoParams *)data->callbackParams; + chatGetChannelBasicUserInfoCallback callback = (chatGetChannelBasicUserInfoCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, NICK, USER, ADDRESS, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* nick_W = UTF8ToUCS2StringAlloc(NICK); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* address_W = UTF8ToUCS2StringAlloc(ADDRESS); + callback(chat, SUCCESS, channel_W, nick_W, user_W, address_W, param); + gsifree(channel_W); + gsifree(nick_W); + gsifree(user_W); + gsifree(address_W); + break; +#endif + } + + case CALLBACK_GET_USER_MODE: + { + ciCallbackGetUserModeParams * callbackParams = (ciCallbackGetUserModeParams *)data->callbackParams; + chatGetUserModeCallback callback = (chatGetUserModeCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, USER, MODE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + callback(chat, SUCCESS, channel_W, user_W, MODE, param); + gsifree(channel_W); + gsifree(user_W); + break; +#endif + } + + case CALLBACK_ENUM_CHANNEL_BANS: + { + ciCallbackEnumChannelBansParams * callbackParams = (ciCallbackEnumChannelBansParams *)data->callbackParams; + chatEnumChannelBansCallback callback = (chatEnumChannelBansCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, NUM_BANS, (const char **)BANS, param); + break; +#else + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short** bans_W = UTF8ToUCS2StringArrayAlloc((const char **)BANS, NUM_BANS); + callback(chat, SUCCESS, channel_W, NUM_BANS, (const unsigned short**)bans_W, param); + gsifree(channel_W); + FREE_STRING_ARRAY(bans_W, NUM_BANS); + break; +#endif + } + + case CALLBACK_NICK_ERROR: + { + ciCallbackNickErrorParams * callbackParams = (ciCallbackNickErrorParams *)data->callbackParams; + chatNickErrorCallback callback = (chatNickErrorCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, TYPE, NICK, NUM_SUGGESTED_NICKS, (const char**)SUGGESTED_NICKS, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* nick_W = UTF8ToUCS2StringAlloc(NICK); + unsigned short** suggestedNicks_W = UTF8ToUCS2StringArrayAlloc((const char **)SUGGESTED_NICKS, NUM_SUGGESTED_NICKS); + callback(chat, TYPE, nick_W, NUM_SUGGESTED_NICKS, (const unsigned short**)suggestedNicks_W, param); + gsifree(nick_W); + FREE_STRING_ARRAY(suggestedNicks_W, NUM_SUGGESTED_NICKS); + break; +#endif + } + + case CALLBACK_CHANGE_NICK: + { + ciCallbackChangeNickParams * callbackParams = (ciCallbackChangeNickParams *)data->callbackParams; + chatChangeNickCallback callback = (chatChangeNickCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, OLD_NICK, NEW_NICK, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* oldnick_W = UTF8ToUCS2StringAlloc(OLD_NICK); + unsigned short* newnick_W = UTF8ToUCS2StringAlloc(NEW_NICK); + callback(chat, SUCCESS, oldnick_W, newnick_W, param); + gsifree(oldnick_W); + gsifree(newnick_W); + break; +#endif + } + + case CALLBACK_NEW_USER_LIST: + { + ciCallbackNewUserListParams * callbackParams = (ciCallbackNewUserListParams *)data->callbackParams; + chatNewUserList callback = (chatNewUserList)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, NUM_USERS, (const char **)USERS, MODES, param); + break; +#else + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short** users_W = UTF8ToUCS2StringArrayAlloc((const char**)USERS, NUM_USERS); + callback(chat, channel_W, NUM_USERS, (const unsigned short**)users_W, MODES, param); + gsifree(channel_W); + FREE_STRING_ARRAY(users_W, NUM_USERS); + break; +#endif + } + + case CALLBACK_BROADCAST_KEY_CHANGED: + { + ciCallbackBroadcastKeyChangedParams * callbackParams = (ciCallbackBroadcastKeyChangedParams *)data->callbackParams; + chatBroadcastKeyChanged callback = (chatBroadcastKeyChanged)data->callback; +#ifndef GSI_UNICODE + callback(chat, CHANNEL, USER, KEY, VALUE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short* key_W = UTF8ToUCS2StringAlloc(KEY); + unsigned short* value_W = UTF8ToUCS2StringAlloc(VALUE); + callback(chat, channel_W, user_W, key_W, value_W, param); + gsifree(channel_W); + gsifree(user_W); + gsifree(key_W); + gsifree(value_W); + break; +#endif + } + + case CALLBACK_GET_GLOBAL_KEYS: + { + ciCallbackGetGlobalKeysParams * callbackParams = (ciCallbackGetGlobalKeysParams *)data->callbackParams; + chatGetGlobalKeysCallback callback = (chatGetGlobalKeysCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, USER, NUM, (const char **)KEYS, (const char **)VALUES, param); + break; +#else + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short** keys_W = UTF8ToUCS2StringArrayAlloc((const char**)KEYS, NUM); + unsigned short** values_W = UTF8ToUCS2StringArrayAlloc((const char**)VALUES, NUM); + callback(chat, SUCCESS, user_W, NUM, (const unsigned short**)keys_W, (const unsigned short**)values_W, param); + gsifree(user_W); + FREE_STRING_ARRAY(keys_W, NUM); + FREE_STRING_ARRAY(values_W, NUM); + break; +#endif + } + + case CALLBACK_GET_CHANNEL_KEYS: + { + ciCallbackGetChannelKeysParams * callbackParams = (ciCallbackGetChannelKeysParams *)data->callbackParams; + chatGetChannelKeysCallback callback = (chatGetChannelKeysCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, SUCCESS, CHANNEL, USER, NUM, (const char **)KEYS, (const char **)VALUES, param); + break; +#else + unsigned short* channel_W = UTF8ToUCS2StringAlloc(CHANNEL); + unsigned short* user_W = UTF8ToUCS2StringAlloc(USER); + unsigned short** keys_W = UTF8ToUCS2StringArrayAlloc((const char**)KEYS, NUM); + unsigned short** values_W = UTF8ToUCS2StringArrayAlloc((const char**)VALUES, NUM); + callback(chat, SUCCESS, channel_W, user_W, NUM, (const unsigned short**)keys_W, (const unsigned short**)values_W, param); + gsifree(channel_W); + gsifree(user_W); + FREE_STRING_ARRAY(keys_W, NUM); + FREE_STRING_ARRAY(values_W, NUM); + break; +#endif + } + + case CALLBACK_AUTHENTICATE_CDKEY: + { + ciCallbackAuthenticateCDKeyParams * callbackParams = (ciCallbackAuthenticateCDKeyParams *)data->callbackParams; + chatAuthenticateCDKeyCallback callback = (chatAuthenticateCDKeyCallback)data->callback; +#ifndef GSI_UNICODE + callback(chat, RESULT, MESSAGE, param); + break; +#else + // Copy all the params, call the callback, free the params + unsigned short* message_W = UTF8ToUCS2StringAlloc(MESSAGE); + callback(chat, RESULT, message_W, param); + gsifree(message_W); + break; +#endif + } + + default: + // The type for this callback is messed up. + /////////////////////////////////////////// + assert(0); + } + + // gsifree the data. + ///////////////// + ciFreeCallbackData(data); +} + +void ciCallCallbacks(CHAT chat, int ID) +{ + ciCallbackData * data; + ciCallbackData dataCopy; + int skip; + CONNECTION; + + // Call the callbacks. + ////////////////////// + for(skip = 0 ; ArrayLength(connection->callbackList) > skip ; ) + { + // Get the callback. + /////////////////// + data = (ciCallbackData *)ArrayNth(connection->callbackList, skip); + ASSERT_DATA(data); + + // Does this depend on a channel we're not in? + ////////////////////////////////////////////// + if((data->channel != NULL) && !ciInChannel(chat, data->channel)) + { + // gsifree the data. + ///////////////// + ciFreeCallbackData(data); + + // Kill it. + /////////// + ArrayDeleteAt(connection->callbackList, skip); + } + else + { + // Check if this callback depends on the join callback having been called. + // Also, if blocking, only call that callback. + ////////////////////////////////////////////////////////////////////////// + if(((data->channel == NULL) || ciWasJoinCallbackCalled(chat, data->channel)) && + ((ID == 0) || (data->ID == ID))) + { + // Copy the data so we can gsifree it before calling the callback. + /////////////////////////////////////////////////////////////// + dataCopy = *data; + + // gsifree it. + /////////// + ArrayDeleteAt(connection->callbackList, skip); + + // Call the callback. + ///////////////////// + ciCallCallback(chat, &dataCopy); + + // Was this the blocking callback? + ////////////////////////////////// + if(ID != 0) + return; + } + else + { + // Increment the skip, because it's still in the array. + /////////////////////////////////////////////////////// + skip++; + } + } + } +} + +static int ciGetCallbackIndexByID(CHAT chat, int ID) +{ + ciCallbackData * data; + int i; + int len; + CONNECTION; + + // Get the array length. + //////////////////////// + len = ArrayLength(connection->callbackList); + + // Loop through the callbacks. + ////////////////////////////// + for(i = 0 ; i < len ; i++) + { + // Get the callback. + //////////////////// + data = (ciCallbackData *)ArrayNth(connection->callbackList, i); + ASSERT_DATA(data); + + // Check for an ID match. + ///////////////////////// + if(data->ID == ID) + return i; + } + + // Didn't find one. + /////////////////// + return -1; +} + +CHATBool ciCheckCallbacksForID(CHAT chat, int ID) +{ + if(ciGetCallbackIndexByID(chat, ID) == -1) + return CHATFalse; + + return CHATTrue; +} diff --git a/xrGameSpy/gamespy/Chat/chatCallbacks.h b/xrGameSpy/gamespy/Chat/chatCallbacks.h new file mode 100644 index 00000000000..c84b2855909 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatCallbacks.h @@ -0,0 +1,329 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHATCALLBACKS_H_ +#define _CHATCALLBACKS_H_ + +/************* +** INCLUDES ** +*************/ +#include "chat.h" +#include "chatMain.h" + +/************ +** DEFINES ** +************/ +enum +{ + CALLBACK_RAW, + CALLBACK_DISCONNECTED, + CALLBACK_PRIVATE_MESSAGE, + CALLBACK_INVITED, + CALLBACK_CHANNEL_MESSAGE, + CALLBACK_KICKED, + CALLBACK_USER_JOINED, + CALLBACK_USER_PARTED, + CALLBACK_USER_CHANGED_NICK, + CALLBACK_TOPIC_CHANGED, + CALLBACK_CHANNEL_MODE_CHANGED, + CALLBACK_USER_MODE_CHANGED, + CALLBACK_USER_LIST_UPDATED, + CALLBACK_ENUM_CHANNELS_EACH, + CALLBACK_ENUM_CHANNELS_ALL, + CALLBACK_ENTER_CHANNEL, + CALLBACK_GET_CHANNEL_TOPIC, + CALLBACK_GET_CHANNEL_MODE, + CALLBACK_GET_CHANNEL_PASSWORD, + CALLBACK_ENUM_USERS, + CALLBACK_GET_USER_INFO, + CALLBACK_GET_BASIC_USER_INFO, + CALLBACK_GET_CHANNEL_BASIC_USER_INFO, + CALLBACK_GET_USER_MODE, + CALLBACK_ENUM_CHANNEL_BANS, + CALLBACK_NICK_ERROR, + CALLBACK_CHANGE_NICK, + CALLBACK_NEW_USER_LIST, + CALLBACK_BROADCAST_KEY_CHANGED, + CALLBACK_GET_GLOBAL_KEYS, + CALLBACK_GET_CHANNEL_KEYS, + CALLBACK_AUTHENTICATE_CDKEY, + CALLBACK_GET_UDPRELAY, + CALLBACK_NUM +}; + +/********** +** TYPES ** +**********/ +typedef struct ciCallbackRawParams +{ + char * raw; +} ciCallbackRawParams; + +typedef struct ciCallbackDisconnectedParams +{ + char * reason; +} ciCallbackDisconnectedParams; + +typedef struct ciCallbackPrivateMessageParams +{ + char * user; + char * message; + int type; +} ciCallbackPrivateMessageParams; + +typedef struct ciCallbackInvitedParams +{ + char * channel; + char * user; +} ciCallbackInvitedParams; + +typedef struct ciCallbackChannelMessageParams +{ + char * channel; + char * user; + char * message; + int type; +} ciCallbackChannelMessageParams; + +typedef struct ciCallbackKickedParams +{ + char * channel; + char * user; + char * reason; +} ciCallbackKickedParams; + +typedef struct ciCallbackUserJoinedParams +{ + char * channel; + char * user; + int mode; +} ciCallbackUserJoinedParams; + +typedef struct ciCallbackUserPartedParams +{ + char * channel; + char * user; + int why; + char * reason; + char * kicker; +} ciCallbackUserPartedParams; + +typedef struct ciCallbackUserChangedNickParams +{ + char * channel; + char * oldNick; + char * newNick; +} ciCallbackUserChangedNickParams; + +typedef struct ciCallbackTopicChangedParams +{ + char * channel; + char * topic; +} ciCallbackTopicChangedParams; + +typedef struct ciCallbackChannelModeChangedParams +{ + char * channel; + CHATChannelMode * mode; +} ciCallbackChannelModeChangedParams; + +typedef struct ciCallbackUserModeChangedParams +{ + char * channel; + char * user; + int mode; +} ciCallbackUserModeChangedParams; + +typedef struct ciCallbackUserListUpdatedParams +{ + char * channel; +} ciCallbackUserListUpdatedParams; + +typedef struct ciCallbackConnectParams +{ + CHATBool success; +} ciCallbackConnectParams; + +typedef struct ciCallbackEnumChannelsEachParams +{ + CHATBool success; + int index; + char * channel; + char * topic; + int numUsers; + void * param; +} ciCallbackEnumChannelsEachParams; + +typedef struct ciCallbackEnumChannelsAllParams +{ + CHATBool success; + int numChannels; + char ** channels; + char ** topics; + int * numUsers; +} ciCallbackEnumChannelsAllParams; + +typedef struct ciCallbackEnterChannelParams +{ + CHATBool success; + CHATEnterResult result; + char * channel; +} ciCallbackEnterChannelParams; + +typedef struct ciCallbackGetChannelTopicParams +{ + CHATBool success; + char * channel; + char * topic; +} ciCallbackGetChannelTopicParams; + +typedef struct ciCallbackGetChannelModeParams +{ + CHATBool success; + char * channel; + CHATChannelMode * mode; +} ciCallbackGetChannelModeParams; + +typedef struct ciCallbackGetChannelPasswordParams +{ + CHATBool success; + char * channel; + CHATBool enabled; + char * password; +} ciCallbackGetChannelPasswordParams; + +typedef struct ciCallbackEnumUsersParams +{ + CHATBool success; + char * channel; + int numUsers; + char ** users; + int * modes; +} ciCallbackEnumUsersParams; + +typedef struct ciCallbackGetUserInfoParams +{ + CHATBool success; + char * nick; + char * user; + char * name; + char * address; + int numChannels; + char ** channels; +} ciCallbackGetUserInfoParams; + +typedef struct ciCallbackGetBasicUserInfoParams +{ + CHATBool success; + char * nick; + char * user; + char * address; +} ciCallbackGetBasicUserInfoParams; + +typedef struct ciCallbackGetChannelBasicUserInfoParams +{ + CHATBool success; + char * channel; + char * nick; + char * user; + char * address; +} ciCallbackGetChannelBasicUserInfoParams; + +typedef struct ciCallbackGetUserModeParams +{ + CHATBool success; + char * channel; + char * user; + int mode; +} ciCallbackGetUserModeParams; + +typedef struct ciCallbackEnumChannelBansParams +{ + CHATBool success; + char * channel; + int numBans; + char ** bans; +} ciCallbackEnumChannelBansParams; + +typedef struct ciCallbackNickErrorParams +{ + int type; + char * nick; + int numSuggestedNicks; + char ** suggestedNicks; +} ciCallbackNickErrorParams; + +typedef struct ciCallbackChangeNickParams +{ + CHATBool success; + char * oldNick; + char * newNick; +} ciCallbackChangeNickParams; + +typedef struct ciCallbackNewUserListParams +{ + char * channel; + int numUsers; + char ** users; + int * modes; +} ciCallbackNewUserListParams; + +typedef struct ciCallbackBroadcastKeyChangedParams +{ + char * channel; + char * user; + char * key; + char * value; +} ciCallbackBroadcastKeyChangedParams; + +typedef struct ciCallbackGetGlobalKeysParams +{ + CHATBool success; + char * user; + int num; + char ** keys; + char ** values; +} ciCallbackGetGlobalKeysParams; + +typedef struct ciCallbackGetChannelKeysParams +{ + CHATBool success; + char * channel; + char * user; + int num; + char ** keys; + char ** values; +} ciCallbackGetChannelKeysParams; + +typedef struct ciCallbackAuthenticateCDKeyParams +{ + int result; + char * message; +} ciCallbackAuthenticateCDKeyParams; + +typedef struct ciCallbackGetUdpRelayParams +{ + char * channel; + char * udpIp; + unsigned short udpPort; + int udpKey; +} ciCallbackGetUdpRelayParams; + +/************** +** FUNCTIONS ** +**************/ +CHATBool ciInitCallbacks(ciConnection * connection); +void ciCleanupCallbacks(CHAT chat); +#define ciAddCallback(chat, type, callback, callbackParams, param, ID, channel) ciAddCallback_(chat, type, callback, callbackParams, param, ID, channel, sizeof(*callbackParams)) +CHATBool ciAddCallback_(CHAT chat, int type, void * callback, void * callbackParams, void * param, int ID, const char * channel, size_t callbackParamsSize); +void ciCallCallbacks(CHAT chat, int ID); +CHATBool ciCheckCallbacksForID(CHAT chat, int ID); + +#endif diff --git a/xrGameSpy/gamespy/Chat/chatChannel.c b/xrGameSpy/gamespy/Chat/chatChannel.c new file mode 100644 index 00000000000..bb5ef71557e --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatChannel.c @@ -0,0 +1,1265 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include "chatMain.h" +#include "chatChannel.h" +#include "chatCallbacks.h" + +#if defined(_WIN32) +// Compiler warns when explicitly casting from function* to void* +#pragma warning(disable:4054) +#endif + +/************ +** DEFINES ** +************/ +#define CHANNEL_HASH_BUCKETS 7 +#define USER_HASH_BUCKETS 61 +#define MAX_CHANNEL 257 +#define MAX_TOPIC 128 +#define MAX_NAME 128 +#define MAX_CACHED_USER 24 +#define MAX_CACHED_ADDRESS 64 + +#define ASSERT_CHANNEL() assert(channel != NULL); assert(channel[0] != '\0'); assert(strlen(channel) < MAX_CHANNEL); +#define ASSERT_USER(user) assert(user != NULL); assert(user[0] != '\0'); assert(strlen(user) < MAX_NAME); +#define ASSERT_STR(str) assert(str != NULL); assert(str[0] != '\0'); +#define ASSERT_MODE(mode) assert((mode >= 0) && (mode <= 3)); + +/********** +** TYPES ** +**********/ +typedef struct ciChatChannel +{ + char name[MAX_CHANNEL]; + chatChannelCallbacks callbacks; + + HashTable users; + + CHATChannelMode mode; + CHATBool gotMode; + + char * password; + + CHATBool joinCallbackCalled; + + char topic[MAX_TOPIC]; +} ciChatChannel; + +typedef struct ciChatUser +{ + char name[MAX_NAME]; + char user[MAX_CACHED_USER]; + char address[MAX_CACHED_ADDRESS]; +#ifdef GSI_UNICODE + // must store a unicode versions since a pointer to them is + // given to the developer application + unsigned short userW[MAX_CACHED_USER]; + unsigned short addressW[MAX_CACHED_ADDRESS]; +#endif + CHATBool gotUserAndAddress; + int mode; +} ciChatUser; + +typedef struct ciUserEnumChannelsData +{ + CHAT chat; + ciChatUser * user; + ciUserEnumChannelsCallback callback; + void * param; +} ciUserEnumChannelsData; + +typedef struct ciUserChangedNickData +{ + CHAT chat; + const char * oldNick; + const char * newNick; +} ciUserChangedNickData; + +typedef struct ciChannelListUsersData +{ + CHAT chat; + int numUsers; + char ** users; + int * modes; +} ciChannelListUsersData; + +typedef struct ciEnumJoinedChannelsData +{ + CHAT chat; + chatEnumJoinedChannelsCallback callback; + void * param; + int index; +} ciEnumJoinedChannelsData; + +typedef struct ciSetUserBasicInfoData +{ + ciChatUser * chatUser; + char * user; + char * address; +} ciSetUserBasicInfoData; + +typedef struct ciGetUserBasicInfoData +{ + CHATBool found; + ciChatUser * chatUser; + char * user; + char * address; +#ifdef GSI_UNICODE + // must store a unicode version since ptr to address is given to dev app + unsigned short * userW; + unsigned short * addressW; +#endif +} ciGetUserBasicInfoData; + +typedef struct ciClearAllUsersData +{ + CHAT chat; + ciChatChannel * channel; +} ciClearAllUsersData; + +/*************** +** PROTOTYPES ** +****************/ +// CodeWarrior will warn if this is not prototyped +int GS_STATIC_CALLBACK ciEnteringChannelComparator(const void *param1, const void *param2); + + +/************** +** FUNCTIONS ** +**************/ +static int ciHashString(const char * str, int numBuckets) +{ + unsigned int hash; + int c; + + ASSERT_STR(str); + + hash = 0; + while((c = *str++) != '\0') + hash += (unsigned int)tolower(c); + + return ((int)hash % numBuckets); +} + +static ciChatChannel * ciGetChannel(ciConnection * connection, const char * channel) +{ + ciChatChannel * chatChannel; + ciChatChannel channelTemp; + + strzcpy(channelTemp.name, channel, MAX_CHANNEL); + chatChannel = (ciChatChannel *)TableLookup(connection->channelTable, &channelTemp); + + return chatChannel; +} + +/********************** +** CHANNEL CALLBACKS ** +**********************/ +static int ciChannelTableHashFn(const void * elem, int numBuckets) +{ + int hash; + + assert(elem != NULL); + assert(numBuckets > 0); + + hash = ciHashString(((ciChatChannel *)elem)->name, numBuckets); + + return hash; +} + +static int GS_STATIC_CALLBACK ciChannelTableCompareFn(const void * elem1, const void * elem2) +{ + const char * str1; + const char * str2; + + assert(elem1 != NULL); + assert(elem2 != NULL); + + str1 = ((ciChatChannel *)elem1)->name; + str2 = ((ciChatChannel *)elem2)->name; + assert(str1 != NULL); + assert(str2 != NULL); + ASSERT_STR(str1); + ASSERT_STR(str2); + + return strcasecmp(str1, str2); +} + +static void ciChannelTableElementFreeFn(void * elem) +{ + ciChatChannel * channel; + + assert(elem != NULL); + + channel = (ciChatChannel *)elem; + gsifree(channel->password); + if(channel->users) + TableFree(channel->users); +} + +/******************* +** USER CALLBACKS ** +*******************/ +static int ciUserTableHashFn(const void * elem, int numBuckets) +{ + int hash; + + assert(elem != NULL); + assert(numBuckets > 0); + + hash = ciHashString(((ciChatUser *)elem)->name, numBuckets); + + return hash; +} + +static int GS_STATIC_CALLBACK ciUserTableCompareFn(const void * elem1, const void * elem2) +{ + const char * str1; + const char * str2; + + assert(elem1 != NULL); + assert(elem2 != NULL); + + // Sept 20, 2004 - Bill Dewey + // A NULL parameter has been causing Arcade to crash. (FogBugz 2825) + // This doesn't solve the real problem (elem is invalid), + // it just tries to keep Arcade going + if (elem1 == NULL || elem2 == NULL) + { + // A NULL user is automatically "less than" + if (elem1 == NULL && elem2 == NULL) + return 0; + else if (elem1 == NULL) + return -1; + else // if (elem2 == NULL) + return 1; + } + + str1 = ((ciChatUser *)elem1)->name; + str2 = ((ciChatUser *)elem2)->name; + ASSERT_STR(str1); + ASSERT_STR(str2); + + return strcasecmp(str1, str2); +} + +static void ciUserTableElementFreeFn(void * elem) +{ + assert(elem != NULL); + + GSI_UNUSED(elem); + + // if anything is done in here that changes the structure + // ciUserChangeNickMap() must be updated +} + +/********************** +** CHANNEL FUNCTIONS ** +**********************/ +CHATBool ciInitChannels(ciConnection * connection) +{ + connection->channelTable = TableNew2(sizeof(ciChatChannel), CHANNEL_HASH_BUCKETS, 2, ciChannelTableHashFn, ciChannelTableCompareFn, ciChannelTableElementFreeFn); + if(connection->channelTable == NULL) + return CHATFalse; + + connection->enteringChannelList = ArrayNew(sizeof(ciChatChannel), 0, NULL); + if(connection->enteringChannelList == NULL) + { + TableFree(connection->channelTable); + return CHATFalse; + } + + return CHATTrue; +} + +void ciCleanupChannels(CHAT chat) +{ + CONNECTION; + + if(connection->channelTable != NULL) + TableFree(connection->channelTable); + + if(connection->enteringChannelList != NULL) + ArrayFree(connection->enteringChannelList); +} + +void ciChannelEntering(CHAT chat, const char * channel) +{ + ciChatChannel chatChannel; + + CONNECTION; + + // Setup the channel. + ///////////////////// + memset(&chatChannel, 0, sizeof(ciChatChannel)); + strzcpy(chatChannel.name, channel, MAX_CHANNEL); + + // Add the channel to the list. + /////////////////////////////// + ArrayAppend(connection->enteringChannelList, &chatChannel); +} + +int GS_STATIC_CALLBACK ciEnteringChannelComparator(const void *param1, const void *param2) +{ + ciChatChannel * channel1 = (ciChatChannel *)param1; + ciChatChannel * channel2 = (ciChatChannel *)param2; + return strcasecmp(channel1->name, channel2->name); +} + +CHATBool ciIsEnteringChannel(CHAT chat, const char * channel) +{ + int i; + int count; + ciChatChannel * chatChannel; + + CONNECTION; + + count = ArrayLength(connection->enteringChannelList); + for(i = 0 ; i < count ; i++) + { + chatChannel = (ciChatChannel *)ArrayNth(connection->enteringChannelList, i); + assert(chatChannel); + if(strcasecmp(chatChannel->name, channel) == 0) + return CHATTrue; + } + + return CHATFalse; +} + +void ciChannelEntered(CHAT chat, const char * channel, chatChannelCallbacks * callbacks) +{ + ciChatChannel chatChannel; + char * password; + int index; + CONNECTION; + + ASSERT_CHANNEL(); + assert(callbacks != NULL); + + // Setup an empty password. + /////////////////////////// + password = (char *)gsimalloc(2); + if(password == NULL) + return; //ERRCON + strcpy(password, ""); + + // Setup the channel. + ///////////////////// + memset(&chatChannel, 0, sizeof(ciChatChannel)); + chatChannel.callbacks = *callbacks; + strzcpy(chatChannel.name, channel, MAX_CHANNEL); + chatChannel.users = TableNew2(sizeof(ciChatUser), USER_HASH_BUCKETS, 2, ciUserTableHashFn, ciUserTableCompareFn, ciUserTableElementFreeFn); + if(chatChannel.users == NULL) + return; //ERRCON + chatChannel.gotMode = CHATFalse; + chatChannel.password = password; + chatChannel.joinCallbackCalled = CHATFalse; + chatChannel.topic[0] = '\0'; + + // Check if this one is in the entering list. + ///////////////////////////////////////////// + index = ArraySearch(connection->enteringChannelList, &chatChannel, ciEnteringChannelComparator, 0, 0); + if(index != NOT_FOUND) + ArrayRemoveAt(connection->enteringChannelList, index); + + // Add the channel to the table. + //////////////////////////////// + TableEnter(connection->channelTable, &chatChannel); +} + +void ciChannelLeft(CHAT chat, const char * channel) +{ + ciChatChannel chatChannel; + int index; + //int rcode; + CONNECTION; + + ASSERT_CHANNEL(); + + // Setup a temp channel with the same name. + /////////////////////////////////////////// + strzcpy(chatChannel.name, channel, MAX_CHANNEL); + + // Check if this one is in the entering list. + ///////////////////////////////////////////// + index = ArraySearch(connection->enteringChannelList, &chatChannel, ciEnteringChannelComparator, 0, 0); + if(index != NOT_FOUND) + { + // Remove it from the entering list. + //////////////////////////////////// + ArrayRemoveAt(connection->enteringChannelList, index); + } + else + { + // Remove based on the name. + //////////////////////////// + //rcode = TableRemove(connection->channelTable, &chatChannel); + TableRemove(connection->channelTable, &chatChannel); + + // This will assert if we don't think we're in this channel. + //////////////////////////////////////////////////////////// + //assert(rcode != 0); + } +} + +chatChannelCallbacks * ciGetChannelCallbacks(CHAT chat, const char * channel) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return NULL; //ERRCON + + return &chatChannel->callbacks; +} + +static void ciChannelListUsersMap(void * elem, void * clientData) +{ + ciChatUser * user; + ciChannelListUsersData * data; + void * tempPtr; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the user. + //////////////// + user = (ciChatUser *)elem; + ASSERT_USER(user->name); + + // Get the data. + //////////////// + data = (ciChannelListUsersData *)clientData; + assert(data->numUsers >= 0); +#ifdef _DEBUG + { + int i; + for(i = 0 ; i < data->numUsers ; i++) + { + ASSERT_USER(data->users[i]); + ASSERT_MODE(data->modes[i]); + } + } +#endif + + // Resize the arrays. + // TODO: resize in increments. + ////////////////////////////// + tempPtr = gsirealloc(data->users, sizeof(char *) * (data->numUsers + 1)); + if(tempPtr == NULL) + { + assert(0); + return; //ERRCON + } + data->users = (char **)tempPtr; + tempPtr = gsirealloc(data->modes, sizeof(int) * (data->numUsers + 1)); + if(tempPtr == NULL) + { + assert(0); + return; //ERRCON + } + data->modes = (int *)tempPtr; + + // Fill in the data. + //////////////////// + data->users[data->numUsers] = user->name; + data->modes[data->numUsers] = user->mode; + data->numUsers++; +} + +void ciChannelListUsers(CHAT chat, const char * channel, ciChannelListUsersCallback callback, void * param) +{ + ciChatChannel * chatChannel; + ciChannelListUsersData data; + CONNECTION; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return; //ERRCON + + // Enum through the users. + ////////////////////////// + data.chat = chat; + data.numUsers = 0; + data.users = NULL; + data.modes = NULL; + TableMap(chatChannel->users, ciChannelListUsersMap, &data); + + // Call the callback. + ///////////////////// + callback(chat, channel, data.numUsers, (const char **)data.users, data.modes, param); + + // gsifree the memory. + /////////////////// + gsifree(data.users); + gsifree(data.modes); +} + +CHATBool ciInChannel(CHAT chat, const char * channel) +{ + CONNECTION; + + if(ciGetChannel(connection, channel) == NULL) + return CHATFalse; + + return CHATTrue; +} + +CHATBool ciGetChannelMode(CHAT chat, const char * channel, CHATChannelMode * mode) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return CHATFalse; //ERRCON + + // Did we get the mode yet? + /////////////////////////// + if(!chatChannel->gotMode) + return CHATFalse; //ERRCON + + // Copy the mode. + ///////////////// + memcpy(mode, &chatChannel->mode, sizeof(CHATChannelMode)); + + return CHATTrue; +} + +void ciSetChannelMode(CHAT chat, const char * channel, CHATChannelMode * mode) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return; //ERRCON + + // Set the gotMode flag. + //////////////////////// + chatChannel->gotMode = CHATTrue; + + // Copy the mode. + ///////////////// + memcpy(&chatChannel->mode, mode, sizeof(CHATChannelMode)); +} + +void ciSetChannelPassword(CHAT chat, const char * channel, const char * password) +{ + int len; + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return; //ERRCON + + // gsifree the old password. + ///////////////////////// + gsifree(chatChannel->password); + + // Set the password. + //////////////////// + if(password == NULL) + password = ""; + len = (int)(strlen(password) + 1); + chatChannel->password = (char *)gsimalloc((unsigned int)len); + if(chatChannel->password == NULL) + return; //ERRCON + memcpy(chatChannel->password, password, (unsigned int)len); +} + +const char * ciGetChannelPassword(CHAT chat, const char * channel) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return NULL; //ERRCON + + // Return the password. + /////////////////////// + return chatChannel->password; +} + +void ciJoinCallbackCalled(CHAT chat, const char * channel) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return; //ERRCON + + // Callback was called. + /////////////////////// + chatChannel->joinCallbackCalled = CHATTrue; +} + +CHATBool ciWasJoinCallbackCalled(CHAT chat, const char * channel) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return CHATFalse; //ERRCON + + return chatChannel->joinCallbackCalled; +} + +void ciSetChannelTopic(CHAT chat, const char * channel, const char * topic) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return; //ERRCON + + // Set the topic. + ///////////////// + strzcpy(chatChannel->topic, topic, MAX_TOPIC); +} + +const char * ciGetChannelTopic(CHAT chat, const char * channel) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return NULL; //ERRCON + + return chatChannel->topic; +} + +int ciGetChannelNumUsers(CHAT chat, const char * channel) +{ + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_CHANNEL(); + + // Find this channel. + ///////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return -1; + + return TableCount(chatChannel->users); +} + +/******************* +** USER FUNCTIONS ** +*******************/ +void ciUserEnteredChannel(CHAT chat, const char * name, const char * channel, int mode, const char * user, const char * address) +{ + ciChatUser chatUser; + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_USER(name); + ASSERT_STR(channel); + ASSERT_MODE(mode); + + // Get the channel. + /////////////////// + chatChannel = ciGetChannel(connection, channel); + if(!chatChannel) + return; + + // Setup the user. + ////////////////// + memset(&chatUser, 0, sizeof(ciChatUser)); + strzcpy(chatUser.name, name, MAX_NAME); + if(user && address) + { + strzcpy(chatUser.user, user, MAX_CACHED_USER); + strzcpy(chatUser.address, address, MAX_CACHED_ADDRESS); + chatUser.gotUserAndAddress = CHATTrue; + +#ifdef GSI_UNICODE // update the unicode versions + AsciiToUCS2String(chatUser.user, chatUser.userW); + AsciiToUCS2String(chatUser.address, chatUser.addressW); +#endif + } + else + { + chatUser.gotUserAndAddress = CHATFalse; + } + chatUser.mode = mode; + + // Add it to the channel. + ///////////////////////// + TableEnter(chatChannel->users, &chatUser); + + // Check that we're in. + /////////////////////// + assert(TableLookup(chatChannel->users, &chatUser) != NULL); +} + +void ciUserLeftChannel(CHAT chat, const char * user, const char * channel) +{ + ciChatUser chatUser; + ciChatChannel * chatChannel; + CONNECTION; + + ASSERT_USER(user); + ASSERT_STR(channel); + + // Get the channel. + /////////////////// + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return; //ERRCON + + // Setup a temp user with the same name. + //////////////////////////////////////// + strzcpy(chatUser.name, user, MAX_NAME); + + // Remove it. + ///////////// + TableRemove(chatChannel->users, &chatUser); +} + +static void ciUserEnumChannelsMap(void * elem, void * clientData) +{ + ciChatChannel * channel; + ciChatUser * user; + ciUserEnumChannelsData * data; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the channel. + /////////////////// + channel = (ciChatChannel *)elem; + assert(channel->users != NULL); + + // Get the user and callback. + ///////////////////////////// + data = (ciUserEnumChannelsData *)clientData; + assert(data->user != NULL); + assert(data->user->name[0] != '\0'); + assert(data->callback != NULL); + + // Check for the user. + ////////////////////// + user = (ciChatUser *)TableLookup(channel->users, data->user); + if(user != NULL) + { + // Call the callback. + ///////////////////// + data->callback(data->chat, data->user->name, channel->name, data->param); + } +} + +void ciUserEnumChannels(CHAT chat, const char * user, ciUserEnumChannelsCallback callback, void * param) +{ + ciChatUser chatUser; + ciUserEnumChannelsData data; + CONNECTION; + + ASSERT_USER(user); + assert(callback != NULL); + + strzcpy(chatUser.name, user, MAX_NAME); + data.chat = chat; + data.user = &chatUser; + data.callback = callback; + data.param = param; + + // Enum through channels looking for this user. + /////////////////////////////////////////////// + TableMap(connection->channelTable, ciUserEnumChannelsMap, &data); +} + +static void ciUserChangeNickMap(void * elem, void * clientData) +{ + ciChatChannel * channel; + ciChatUser tempUser; + ciChatUser * user; + ciUserChangedNickData * data; + ciCallbackUserChangedNickParams params; + int rcode; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the channel. + /////////////////// + channel = (ciChatChannel *)elem; + assert(channel->users != NULL); + + // Get the data. + //////////////// + data = (ciUserChangedNickData *)clientData; + ASSERT_USER(data->newNick); + ASSERT_USER(data->oldNick); + + // Check for the user. + ////////////////////// + user = (ciChatUser *)TableLookup(channel->users, data->oldNick); + if(user != NULL) + { + memcpy(&tempUser, user, sizeof(ciChatUser)); + + // Remove the old user. + /////////////////////// + rcode = TableRemove(channel->users, user); + assert(rcode != 0); + user = &tempUser; + + // Update the nick. + /////////////////// + strzcpy(user->name, data->newNick, MAX_NAME); + + // Add it back. + /////////////// + TableEnter(channel->users, user); + + // Was the join callback called? + //////////////////////////////// + if(ciWasJoinCallbackCalled(data->chat, channel->name)) //PANTS - 03.01.00 - check if the join callback was called + { + // Add the callback. + //////////////////// + if(channel->callbacks.userChangedNick != NULL) + { + params.channel = channel->name; + params.oldNick = (char *)data->oldNick; + params.newNick = (char *)data->newNick; + ciAddCallback(data->chat, CALLBACK_USER_CHANGED_NICK, (void*)channel->callbacks.userChangedNick, ¶ms, channel->callbacks.param, 0, channel->name); + } + } + } + GSI_UNUSED(rcode); +} + +void ciUserChangedNick(CHAT chat, const char * oldNick, const char * newNick) +{ + ciUserChangedNickData data; + CONNECTION; + + ASSERT_USER(oldNick); + ASSERT_USER(newNick); + + data.chat = chat; + data.oldNick = oldNick; + data.newNick = newNick; + + // Enum through channels looking for this user. + /////////////////////////////////////////////// + TableMap(connection->channelTable, ciUserChangeNickMap, &data); +} + +void ciUserChangedMode(CHAT chat, const char * user, const char * channel, int mode, CHATBool enabled) +{ + ciChatChannel channelTemp; + ciChatChannel * chatChannel; + ciChatUser userTemp; + ciChatUser * chatUser; + ciCallbackUserModeChangedParams params; + CONNECTION; + + ASSERT_USER(user); + ASSERT_STR(channel); + ASSERT_MODE(mode); + + // Find the channel. + //////////////////// + strzcpy(channelTemp.name, channel, MAX_CHANNEL); + chatChannel = (ciChatChannel *)TableLookup(connection->channelTable, &channelTemp); + if(chatChannel == NULL) + return; //ERRCON + + // Find the user. + ///////////////// + strzcpy(userTemp.name, user, MAX_NAME); + chatUser = (ciChatUser *)TableLookup(chatChannel->users, &userTemp); + if(chatUser == NULL) + return; //ERRCON + + // Change the mode. + /////////////////// + if(enabled) + chatUser->mode |= mode; + else + chatUser->mode &= ~mode; + + // Add the callback. + //////////////////// + if(chatChannel->callbacks.userModeChanged != NULL) + { + params.channel = (char *)channel; + params.user = (char *)user; + params.mode = chatUser->mode; + ciAddCallback(chat, CALLBACK_USER_MODE_CHANGED, (void*)chatChannel->callbacks.userModeChanged, ¶ms, chatChannel->callbacks.param, 0, channel); + } +} + +CHATBool ciUserInChannel(CHAT chat, const char * channel, const char * user) +{ + ciChatChannel * chatChannel; + ciChatUser chatUser; + CONNECTION; + + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return CHATFalse; + + strzcpy(chatUser.name, user, MAX_NAME); + if(TableLookup(chatChannel->users, &chatUser) == NULL) + return CHATFalse; + + return CHATTrue; +} + +int ciGetUserMode(CHAT chat, const char * channel, const char * user) +{ + ciChatChannel * chatChannel; + ciChatUser userTemp; + ciChatUser * chatUser; + CONNECTION; + + chatChannel = ciGetChannel(connection, channel); + if(chatChannel == NULL) + return -1; //ERRCON + + strzcpy(userTemp.name, user, MAX_NAME); + chatUser = (ciChatUser *)TableLookup(chatChannel->users, &userTemp); + if(chatUser == NULL) + return -1; //ERRCON + + return chatUser->mode; +} + + +static void ciEnumJoinedChannelsMap(void * elem, void * clientData) +{ + ciEnumJoinedChannelsData * data; + ciChatChannel * channel; + assert(elem != NULL); + assert(clientData != NULL); + + // Get the channel. + /////////////////// + channel = (ciChatChannel *)elem; + + // Get the callback & param + ///////////////////////////// + data = (ciEnumJoinedChannelsData *)clientData; + assert(data->callback != NULL); + + // Call the callback. + ///////////////////// +#ifdef GSI_UNICODE + { + unsigned short* name_W = UTF8ToUCS2StringAlloc(channel->name); + data->callback(data->chat, data->index++, name_W, data->param); + gsifree(name_W); + } +#else + data->callback(data->chat, data->index++, channel->name, data->param); +#endif +} + +// Enumerates the channels that we are joined to +////////////////////////////////////////////////////// +void ciEnumJoinedChannels(CHAT chat, + chatEnumJoinedChannelsCallback callback, + void * param) +{ + ciEnumJoinedChannelsData data; + CONNECTION; + CONNECTED; + data.callback = callback; + data.param = param; + data.index = 0; + data.chat = chat; + + TableMap(connection->channelTable,ciEnumJoinedChannelsMap,&data); +} + +static void ciSetUserBasicInfoMap(void * elem, void * clientData) +{ + ciChatChannel * channel; + ciChatUser * user; + ciSetUserBasicInfoData * data; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the data. + //////////////// + data = (ciSetUserBasicInfoData *)clientData; + + // Get the channel. + /////////////////// + channel = (ciChatChannel *)elem; + assert(channel->users != NULL); + + // Check for the user. + ////////////////////// + user = (ciChatUser *)TableLookup(channel->users, data->chatUser); + if(user != NULL) + { + // Found it. + //////////// + strzcpy(user->user, data->user, MAX_CACHED_USER); + strzcpy(user->address, data->address, MAX_CACHED_ADDRESS); + user->gotUserAndAddress = CHATTrue; + +#ifdef GSI_UNICODE + // Store a unicode version since we pass a raw pointer to the developer + AsciiToUCS2String(user->user, user->userW); + AsciiToUCS2String(user->address, user->addressW); +#endif + } +} + +void ciSetUserBasicInfo(CHAT chat, const char * nick, const char * user, const char * address) +{ + ciChatUser chatUser; + ciSetUserBasicInfoData data; + CONNECTION; + + ASSERT_USER(nick); + + strzcpy(chatUser.name, nick, MAX_NAME); + data.chatUser = &chatUser; + data.user = (char *)user; + data.address = (char *)address; + + // Enum through channels looking for this user. + /////////////////////////////////////////////// + TableMap(connection->channelTable, ciSetUserBasicInfoMap, &data); +} + +static void ciGetUserBasicInfoMap(void * elem, void * clientData) +{ + ciChatChannel * channel; + ciChatUser * user; + ciGetUserBasicInfoData * data; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the data. + //////////////// + data = (ciGetUserBasicInfoData *)clientData; + + // Did we already find the user? + // Keep looking if we don't have a real address yet. + //////////////////////////////////////////////////// + if(data->found && (strcmp(data->address, "*") != 0)) + return; + + // Get the channel. + /////////////////// + channel = (ciChatChannel *)elem; + assert(channel->users != NULL); + + // Check for the user. + ////////////////////// + user = (ciChatUser *)TableLookup(channel->users, data->chatUser); + if(user != NULL) + { + if(user->gotUserAndAddress) + { + // Found it. + //////////// + data->found = CHATTrue; + data->user = user->user; + data->address = user->address; +#ifdef GSI_UNICODE + data->userW = user->userW; + data->addressW = user->addressW; +#endif + } + } +} + +CHATBool ciGetUserBasicInfoA(CHAT chat, const char * nick, const char ** user, const char ** address) +{ + ciChatUser chatUser; + ciGetUserBasicInfoData data; + CONNECTION; + + ASSERT_USER(nick); + + strzcpy(chatUser.name, nick, MAX_NAME); + data.chatUser = &chatUser; + data.found = CHATFalse; + + // Enum through channels looking for this user. + /////////////////////////////////////////////// + TableMap(connection->channelTable, ciGetUserBasicInfoMap, &data); + + if(!data.found) + return CHATFalse; + + if(user) + *user = data.user; + if(address) + *address = data.address; + + return CHATTrue; +} + +#ifdef GSI_UNICODE +// Because we're returning a pointer to SDK memory, we have to +// duplicate the lookup to return the address of the unsigned short versions +CHATBool ciGetUserBasicInfoW(CHAT chat, const char * nick, const unsigned short ** user, const unsigned short ** address) +{ + ciChatUser chatUser; + ciGetUserBasicInfoData data; + CONNECTION; + + ASSERT_USER(nick); + + strzcpy(chatUser.name, nick, MAX_NAME); + data.chatUser = &chatUser; + data.found = CHATFalse; + + // Enum through channels looking for this user. + /////////////////////////////////////////////// + TableMap(connection->channelTable, ciGetUserBasicInfoMap, &data); + + if(!data.found) + return CHATFalse; + + if(user) + *user = data.userW; + if(address) + *address = data.addressW; + return CHATTrue; +} +#endif + +static void ciClearAllUsersUsersMap(void * elem, void * clientData) +{ + ciClearAllUsersData * data; + ciChatUser * user; + ciChatChannel * channel; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the user. + //////////////// + user = (ciChatUser *)elem; + + // Get the data. + //////////////// + data = (ciClearAllUsersData *)clientData; + channel = data->channel; + + // Remove the user from the channel. + //////////////////////////////////// + TableRemove(channel->users, user); +} + +static void ciClearAllUsersChannelMap(void * elem, void * clientData) +{ + ciChatChannel * channel; + ciClearAllUsersData data; + CHAT chat; + + assert(elem != NULL); + assert(clientData != NULL); + + // Get the channel. + /////////////////// + channel = (ciChatChannel *)elem; + assert(channel->users != NULL); + + // Get the chat object. + /////////////////////// + chat = (CHAT)clientData; + + // Setup the data. + ////////////////// + data.chat = chat; + data.channel = channel; + + // Remove all the users in this channel. + //////////////////////////////////////// + TableMapSafe(channel->users, ciClearAllUsersUsersMap, &data); + + // Call the user list updated callback. + /////////////////////////////////////// + if(channel->callbacks.userListUpdated != NULL) + { + ciCallbackUserListUpdatedParams params; + params.channel = channel->name; + ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)channel->callbacks.userListUpdated, ¶ms, channel->callbacks.param, 0, channel->name); + } +} + +void ciClearAllUsers(CHAT chat) +{ + CONNECTION; + + // Go through all the channels. + /////////////////////////////// + TableMap(connection->channelTable, ciClearAllUsersChannelMap, chat); +} diff --git a/xrGameSpy/gamespy/Chat/chatChannel.h b/xrGameSpy/gamespy/Chat/chatChannel.h new file mode 100644 index 00000000000..af38ef0258f --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatChannel.h @@ -0,0 +1,64 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHATCHANNEL_H_ +#define _CHATCHANNEL_H_ + +/************* +** INCLUDES ** +*************/ +#include "chat.h" + +/************ +** DEFINES ** +************/ + +/************** +** FUNCTIONS ** +**************/ +CHATBool ciInitChannels(ciConnection * connection); +void ciCleanupChannels(CHAT chat); +void ciChannelEntering(CHAT chat, const char * channel); +CHATBool ciIsEnteringChannel(CHAT chat, const char * channel); +void ciChannelEntered(CHAT chat, const char * channel, chatChannelCallbacks * callbacks); +void ciChannelLeft(CHAT chat, const char * channel); +chatChannelCallbacks * ciGetChannelCallbacks(CHAT chat, const char * channel); +typedef void (* ciChannelListUsersCallback)(CHAT chat, const char * channel, int numUsers, const char ** users, int * modes, void * param); +void ciChannelListUsers(CHAT chat, const char * channel, ciChannelListUsersCallback callback, void * param); +CHATBool ciInChannel(CHAT chat, const char * channel); +CHATBool ciGetChannelMode(CHAT chat, const char * channel, CHATChannelMode * mode); +void ciSetChannelMode(CHAT chat, const char * channel, CHATChannelMode * mode); +void ciSetChannelPassword(CHAT chat, const char * channel, const char * password); +const char * ciGetChannelPassword(CHAT chat, const char * channel); +void ciJoinCallbackCalled(CHAT chat, const char * channel); +CHATBool ciWasJoinCallbackCalled(CHAT chat, const char * channel); +void ciSetChannelTopic(CHAT chat, const char * channel, const char * topic); +const char * ciGetChannelTopic(CHAT chat, const char * channel); +int ciGetChannelNumUsers(CHAT chat, const char * channel); + +void ciUserEnteredChannel(CHAT chat, const char * nick, const char * channel, int mode, const char * user, const char * address); +void ciUserLeftChannel(CHAT chat, const char * user, const char * channel); +void ciUserChangedNick(CHAT chat, const char * oldNick, const char * newNick); +void ciUserChangedMode(CHAT chat, const char * user, const char * channel, int mode, CHATBool enabled); +typedef void (* ciUserEnumChannelsCallback)(CHAT chat, const char * user, const char * channel, void * param); +void ciUserEnumChannels(CHAT chat, const char * user, ciUserEnumChannelsCallback callback, void * param); +CHATBool ciUserInChannel(CHAT chat, const char * channel, const char * user); +int ciGetUserMode(CHAT chat, const char * channel, const char * user); +void ciEnumJoinedChannels(CHAT chat, chatEnumJoinedChannelsCallback callback, void * param); +void ciSetUserBasicInfo(CHAT chat, const char * nick, const char * user, const char * address); +void ciClearAllUsers(CHAT chat); + +// Because these return pointers to SDK memory, we must have a widestring version +// so we can return a pointer to widestring data +// DO NOT CHANGE nick to an unsigned short*, nicks are internally store as char* +CHATBool ciGetUserBasicInfoA(CHAT chat, const char * nick, const char ** user, const char ** address); +CHATBool ciGetUserBasicInfoW(CHAT chat, const char * nick, const unsigned short ** user, const unsigned short ** address); + +#endif diff --git a/xrGameSpy/gamespy/Chat/chatCrypt.c b/xrGameSpy/gamespy/Chat/chatCrypt.c new file mode 100644 index 00000000000..41a95ed6124 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatCrypt.c @@ -0,0 +1,65 @@ +#include "chatCrypt.h" + +#define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t + +void gs_prepare_key(const unsigned char *key_data_ptr, int key_data_len, gs_crypt_key *key) +{ + unsigned char t; + unsigned char index1; + unsigned char index2; + unsigned char* state; + int counter; + + state = &key->state[0]; + for(counter = 0; counter < 256; counter++) + state[255 - counter] = (unsigned char)counter; //crt - we fill reverse of normal + key->x = 0; + key->y = 0; + index1 = 0; + index2 = 0; + for(counter = 0; counter < 256; counter++) + { + index2 = (unsigned char)((key_data_ptr[index1] + state[counter] + index2) % 256); + swap_byte(&state[counter], &state[index2]); + index1 = (unsigned char)((index1 + 1) % key_data_len); + } +} + +void gs_crypt(unsigned char *buffer_ptr, int buffer_len, gs_crypt_key *key) +{ + unsigned char t; + unsigned char x; + unsigned char y; + unsigned char* state; + unsigned char xorIndex; + int counter; + + x = key->x; + y = key->y; + state = &key->state[0]; + for(counter = 0; counter < buffer_len; counter++) + { + x = (unsigned char)((x + 1) % 256); + y = (unsigned char)((state[x] + y) % 256); + swap_byte(&state[x], &state[y]); + xorIndex = (unsigned char)((state[x] + state[y]) % 256); + buffer_ptr[counter] ^= state[xorIndex]; + } + key->x = x; + key->y = y; +} + + +void gs_xcode_buf(char *buf, int len, char *enckey) +{ + int i; + char *pos = enckey; + + for (i = 0 ; i < len ; i++) + { + buf[i] ^= *pos++; + if (*pos == 0) + pos = enckey; + } + +} diff --git a/xrGameSpy/gamespy/Chat/chatCrypt.h b/xrGameSpy/gamespy/Chat/chatCrypt.h new file mode 100644 index 00000000000..c32d2c83663 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatCrypt.h @@ -0,0 +1,24 @@ +#ifndef _CHATCRYPT_H_ +#define _CHATCRYPT_H_ +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct _gs_crypt_key +{ + unsigned char state[256]; + unsigned char x; + unsigned char y; +} gs_crypt_key; + + +void gs_prepare_key(const unsigned char *key_data_ptr, int key_data_len, gs_crypt_key *key); +void gs_crypt(unsigned char *buffer_ptr, int buffer_len, gs_crypt_key *key); +void gs_xcode_buf(char *buf, int len, char *enckey); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Chat/chatHandlers.c b/xrGameSpy/gamespy/Chat/chatHandlers.c new file mode 100644 index 00000000000..60dc73d74ae --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatHandlers.c @@ -0,0 +1,4720 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include +#include "chatMain.h" +#include "chatSocket.h" +#include "chatHandlers.h" +#include "chatChannel.h" +#include "chatCallbacks.h" +#include "chatCrypt.h" + +#if defined(_WIN32) +// Silence the cast function* to void* warning. +// Since we are explicitly casting it, I'm not sure why the compiler warns +#pragma warning(disable:4054) + +// Silence the "conditional expression is constant" on our "while(1)" statements +#pragma warning(disable:4127) +#endif + +/************ +** DEFINES ** +************/ +#define FILTER_TIMEOUT 60000 +#define NAMES_ARRAY_INC 100 + +#define ASSERT_TYPE(type) assert((type >= 0) && (type < NUM_TYPES)); +#define ASSERT_STR(str) assert(str != NULL); assert(str[0] != '\0'); + +#define RPL_WELCOME "001" +#define RPL_USRIP "302" +#define RPL_WHOISUSER "311" +#define RPL_ENDOFWHO "315" +#define RPL_ENDOFWHOIS "318" +#define RPL_WHOISCHANNELS "319" +#define RPL_LISTSTART "321" +#define RPL_LIST "322" +#define RPL_LISTEND "323" +#define RPL_CHANNELMODEIS "324" +#define RPL_NOTOPIC "331" +#define RPL_TOPIC "332" +#define RPL_WHOREPLY "352" +#define RPL_NAMEREPLY "353" +#define RPL_ENDOFNAMES "366" +#define RPL_BANLIST "367" +#define RPL_ENDOFBANLIST "368" +#define RPL_GETKEY "700" +#define RPL_ENDGETKEY "701" +#define RPL_GETCKEY "702" +#define RPL_ENDGETCKEY "703" +#define RPL_GETCHANKEY "704" +#define RPL_SECUREKEY "705" +#define RPL_CDKEY "706" +#define RPL_LOGIN "707" +#define RPL_GETUDPRELAY "712" + +#define ERR_NOSUCHNICK "401" +#define ERR_NOSUCHCHANNEL "403" +#define ERR_TOOMANYCHANNELS "405" +#define ERR_ERRONEUSNICKNAME "432" +#define ERR_NICKNAMEINUSE "433" +#define ERR_CHANNELISFULL "471" +#define ERR_INVITEONLYCHAN "473" +#define ERR_BANNEDFROMCHAN "474" +#define ERR_BADCHANNELKEY "475" +#define ERR_BADCHANMASK "476" +#define ERR_LOGIN_FAILED "708" +#define ERR_NO_UNIQUE_NICK "709" +#define ERR_UNIQUE_NICK_EXPIRED "710" +#define ERR_REGISTER_NICK_FAILED "711" + +#define MODE_END 0 +#define MODE_BAN 1 +#define MODE_INVITE_ONLY 2 +#define MODE_LIMIT 3 +#define MODE_PRIVATE 4 +#define MODE_SECRET 5 +#define MODE_KEY 6 +#define MODE_MODERATED 7 +#define MODE_NO_EXTERNAL_MESSAGES 8 +#define MODE_ONLY_OPS_CHANGE_TOPIC 9 +#define MODE_OP 10 +#define MODE_VOICE 11 +#define MODE_USERS_HIDDEN 12 +#define MODE_RECEIVE_WALLOPS 13 +#define MODE_OPS_OBEY_CHANNEL_LIMIT 14 + + +#define FINISH_FILTER ciFinishFilter(chat, filter, ¶ms) +#define IS_ALPHA(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) + +enum +{ + TYPE_LIST, + TYPE_JOIN, + TYPE_TOPIC, + TYPE_NAMES, + TYPE_WHOIS, + TYPE_CMODE, + TYPE_UMODE, + TYPE_BAN, + TYPE_GETBAN, + TYPE_NICK, + TYPE_WHO, + TYPE_CWHO, + TYPE_GETKEY, + TYPE_GETCKEY, + TYPE_GETCHANKEY, + TYPE_UNQUIET, + TYPE_CDKEY, + TYPE_GETUDPRELAY, + NUM_TYPES +}; + +/********** +** TYPES ** +**********/ +typedef struct ciModeChange +{ + int mode; + CHATBool enable; + char * param; +} ciModeChange; + +typedef struct ciFilterMatch +{ + int type; + const char * name; + const char * name2; +} ciFilterMatch; + +typedef struct LISTData +{ + CHATBool gotStart; + int numChannels; + char ** channels; + int * numUsers; + char ** topics; +} LISTData; + +typedef struct JOINData +{ + chatChannelCallbacks callbacks; + CHATBool joined; + char password[MAX_PASSWORD]; +} JOINData; + +typedef struct NAMESData +{ + int len; + int numUsers; + char ** users; + int * modes; +} NAMESData; + +typedef struct WHOISData +{ + char * user; + char * name; + char * address; + int numChannels; + char ** channels; +} WHOISData; + +typedef struct BANData +{ + char * channel; +} BANData; + +typedef struct GETBANData +{ + int numBans; + char ** bans; +} GETBANData; + +typedef struct GETKEYData +{ + int num; + char ** keys; + char * channel; +} GETKEYData; + +typedef struct GETCKEYData +{ + int num; + char ** keys; + CHATBool channel; + CHATBool allBroadcastKeys; +} GETCKEYData; + +typedef struct GETCHANKEYData +{ + int num; + char ** keys; + CHATBool allBroadcastKeys; +} GETCHANKEYData; + +/***************** +** HANDLER DECS ** +*****************/ +void ciPrivmsgHandler(CHAT chat, const ciServerMessage * message); +void ciNoticeHandler(CHAT chat, const ciServerMessage * message); +void ciUTMHandler(CHAT chat, const ciServerMessage * message); +void ciATMHandler(CHAT chat, const ciServerMessage * message); +void ciPingHandler(CHAT chat, const ciServerMessage * message); +void ciNickHandler(CHAT chat, const ciServerMessage * message); +void ciJoinHandler(CHAT chat, const ciServerMessage * message); +void ciPartHandler(CHAT chat, const ciServerMessage * message); +void ciKickHandler(CHAT chat, const ciServerMessage * message); +void ciQuitHandler(CHAT chat, const ciServerMessage * message); +void ciKillHandler(CHAT chat, const ciServerMessage * message); +void ciTopicHandler(CHAT chat, const ciServerMessage * message); +void ciModeHandler(CHAT chat, const ciServerMessage * message); +void ciErrorHandler(CHAT chat, const ciServerMessage * message); +void ciNameReplyHandler(CHAT chat, const ciServerMessage * message); +void ciEndOfNamesHandler(CHAT chat, const ciServerMessage * message); +void ciInviteHandler(CHAT chat, const ciServerMessage * message); + +void ciRplTopicHandler(CHAT chat, const ciServerMessage * message); +void ciRplNoTopicHandler(CHAT chat, const ciServerMessage * message); +void ciErrNickInUseHandler(CHAT chat, const ciServerMessage * message); +void ciRplWhoReplyHandler(CHAT chat, const ciServerMessage * message); +void ciRplUserIPHandler(CHAT chat, const ciServerMessage * message); +void ciRplListStartHandler(CHAT chat, const ciServerMessage * message); +void ciRplListHandler(CHAT chat, const ciServerMessage * message); +void ciRplListEndHandler(CHAT chat, const ciServerMessage * message); +void ciRplChannelModeIsHandler(CHAT chat, const ciServerMessage * message); +void ciRplWhoisUserHandler(CHAT chat, const ciServerMessage * message); +void ciRplWhoisChannelsHandler(CHAT chat, const ciServerMessage * message); +void ciRplEndOfWhoisHandler(CHAT chat, const ciServerMessage * message); +void ciRplBanListHandler(CHAT chat, const ciServerMessage * message); +void ciRplEndOfBanListHandler(CHAT chat, const ciServerMessage * message); +void ciRplWelcomeHandler(CHAT chat, const ciServerMessage * message); +void ciRplEndOfWhoHandler(CHAT chat, const ciServerMessage * message); +void ciRplGetKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplEndGetKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplGetCKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplEndGetCKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplGetChanKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplSecureKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplCDKeyHandler(CHAT chat, const ciServerMessage * message); +void ciRplLoginHandler(CHAT chat, const ciServerMessage * message); +void ciRplGetUdpRelayHandler(CHAT chat, const ciServerMessage * message); + +void ciErrNoSuchChannelHandler(CHAT chat, const ciServerMessage * message); +void ciErrTooManyChannelsHandler(CHAT chat, const ciServerMessage * message); +void ciErrChannelIsFullHandler(CHAT chat, const ciServerMessage * message); +void ciErrInviteOnlyChanHandler(CHAT chat, const ciServerMessage * message); +void ciErrBannedFromChanHandler(CHAT chat, const ciServerMessage * message); +void ciErrBadChannelKeyHandler(CHAT chat, const ciServerMessage * message); +void ciErrBadChanMaskHandler(CHAT chat, const ciServerMessage * message); +void ciErrNoSuchNickHandler(CHAT chat, const ciServerMessage * message); +void ciErrErroneusNicknameHandler(CHAT chat, const ciServerMessage * message); +void ciErrLoginFailedHandler(CHAT chat, const ciServerMessage * message); +void ciErrNoUniqueNickHandler(CHAT chat, const ciServerMessage * message); +void ciErrUniqueNickExpiredHandler(CHAT chat, const ciServerMessage * message); +void ciErrRegisterNickFailedHandler(CHAT chat, const ciServerMessage * message); + +/************ +** GLOBALS ** +************/ +ciServerMessageType serverMessageTypes[] = +{ + { "PRIVMSG", ciPrivmsgHandler }, + { "NOTICE", ciNoticeHandler }, + { "UTM", ciUTMHandler }, + { "ATM", ciATMHandler }, + { "PING", ciPingHandler }, + { "NICK", ciNickHandler }, + { "JOIN", ciJoinHandler }, + { "PART", ciPartHandler }, + { "KICK", ciKickHandler }, + { "QUIT", ciQuitHandler }, + { "KILL", ciKillHandler }, + { "TOPIC", ciTopicHandler }, + { "MODE", ciModeHandler }, + { "ERROR", ciErrorHandler }, + { "INVITE", ciInviteHandler }, + + { RPL_NAMEREPLY, ciNameReplyHandler }, + { RPL_ENDOFNAMES, ciEndOfNamesHandler }, + { RPL_TOPIC, ciRplTopicHandler }, + { RPL_NOTOPIC, ciRplNoTopicHandler }, + { RPL_WHOREPLY, ciRplWhoReplyHandler }, + { RPL_USRIP, ciRplUserIPHandler }, + { RPL_LISTSTART, ciRplListStartHandler }, + { RPL_LIST, ciRplListHandler }, + { RPL_LISTEND, ciRplListEndHandler }, + { RPL_CHANNELMODEIS, ciRplChannelModeIsHandler }, + { RPL_WHOISUSER, ciRplWhoisUserHandler }, + { RPL_WHOISCHANNELS, ciRplWhoisChannelsHandler }, + { RPL_ENDOFWHOIS, ciRplEndOfWhoisHandler }, + { RPL_BANLIST, ciRplBanListHandler }, + { RPL_ENDOFBANLIST, ciRplEndOfBanListHandler }, + { RPL_WELCOME, ciRplWelcomeHandler }, + { RPL_ENDOFWHO, ciRplEndOfWhoHandler }, + { RPL_GETKEY, ciRplGetKeyHandler }, + { RPL_ENDGETKEY, ciRplEndGetKeyHandler }, + { RPL_GETCKEY, ciRplGetCKeyHandler }, + { RPL_ENDGETCKEY, ciRplEndGetCKeyHandler }, + { RPL_GETCHANKEY, ciRplGetChanKeyHandler }, + { RPL_SECUREKEY, ciRplSecureKeyHandler }, + { RPL_CDKEY, ciRplCDKeyHandler }, + { RPL_LOGIN, ciRplLoginHandler }, + { RPL_GETUDPRELAY, ciRplGetUdpRelayHandler }, + + { ERR_NICKNAMEINUSE, ciErrNickInUseHandler }, + { ERR_NOSUCHCHANNEL, ciErrNoSuchChannelHandler }, + { ERR_TOOMANYCHANNELS, ciErrTooManyChannelsHandler }, + { ERR_CHANNELISFULL, ciErrChannelIsFullHandler }, + { ERR_INVITEONLYCHAN, ciErrInviteOnlyChanHandler }, + { ERR_BANNEDFROMCHAN, ciErrBannedFromChanHandler }, + { ERR_BADCHANNELKEY, ciErrBadChannelKeyHandler }, + { ERR_BADCHANMASK, ciErrBadChanMaskHandler }, + { ERR_NOSUCHNICK, ciErrNoSuchNickHandler }, + { ERR_ERRONEUSNICKNAME, ciErrErroneusNicknameHandler }, + { ERR_LOGIN_FAILED, ciErrLoginFailedHandler }, + { ERR_NO_UNIQUE_NICK, ciErrNoUniqueNickHandler }, + { ERR_UNIQUE_NICK_EXPIRED, ciErrUniqueNickExpiredHandler }, + { ERR_REGISTER_NICK_FAILED, ciErrRegisterNickFailedHandler } +}; +int numServerMessageTypes = (sizeof(serverMessageTypes) / sizeof(ciServerMessageType)); + + +/************** +** FUNCTIONS ** +**************/ +static ciServerMessageFilter * ciFindFilter(CHAT chat, int numMatches, ciFilterMatch * matches) +{ + int i; + const char * name; + const char * name2; + ciServerMessageFilter * filter; + CONNECTION; + + assert(numMatches > 0); + assert(matches); + + for(filter = connection->filterList ; filter != NULL ; filter = filter->pnext) + { + for(i = 0 ; i < numMatches ; i++) + { + ASSERT_TYPE(matches[i].type); + if(filter->type == matches[i].type) + { + name = matches[i].name; + name2 = matches[i].name2; + if((!name && !filter->name) || (name && filter->name && (strcasecmp(name, filter->name) == 0))) + { + if((!name2 && !filter->name2) || (name2 && filter->name2 && (strcasecmp(name2, filter->name2) == 0))) + { + // Someone's interested in this filter, so extend the timeout. + ////////////////////////////////////////////////////////////// + filter->timeout = (current_time() + FILTER_TIMEOUT); + + return filter; + } + } + } + } + } + + return NULL; +} + +static ciServerMessageFilter * ciFindGetKeyFilter(CHAT chat, const char * channel) +{ + GETKEYData * data; + ciServerMessageFilter * filter; + CONNECTION; + + assert(channel); + assert(channel[0]); + + for(filter = connection->filterList ; filter != NULL ; filter = filter->pnext) + { + if(filter->type == TYPE_GETKEY) + { + data = (GETKEYData *)filter->data; + if(strcasecmp(data->channel, channel) == 0) + return filter; + } + } + + return NULL; +} + +static void ciDestroyFilter(ciServerMessageFilter * filter) +{ + assert(filter != NULL); + + gsifree(filter->data); + gsifree(filter->name); + gsifree(filter->name2); + gsifree(filter); +} + +static void ciRemoveFilter(CHAT chat, ciServerMessageFilter * filter) +{ + ciServerMessageFilter * pcurr; + ciServerMessageFilter * pprev = NULL; + CONNECTION; + + assert(filter != NULL); + + for(pcurr = connection->filterList ; pcurr != NULL ; pcurr = pcurr->pnext) + { + if(pcurr == filter) + { + if(connection->filterList == pcurr) + connection->filterList = pcurr->pnext; + + if(connection->lastFilter == pcurr) + connection->lastFilter = pprev; + + if(pprev != NULL) + pprev->pnext = pcurr->pnext; + + ciDestroyFilter(pcurr); + + return; + } + + pprev = pcurr; + } + + //ERRCON +} + +// Calls the callback, if not NULL, then removes the filter. +//////////////////////////////////////////////////////////// +static void ciFinishFilter(CHAT chat, ciServerMessageFilter * filter, void * params) +{ + int i; + + assert(filter); + ASSERT_TYPE(filter->type); + + // Check the type. + ////////////////// + if(filter->type == TYPE_LIST) + { + LISTData * data = (LISTData *)filter->data; + + if(filter->callback2) + ciAddCallback_(chat, CALLBACK_ENUM_CHANNELS_ALL, filter->callback2, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnumChannelsAllParams)); + + for(i = 0 ; i < data->numChannels ; i++) + { + gsifree(data->channels[i]); + gsifree(data->topics[i]); + } + gsifree(data->channels); + gsifree(data->topics); + gsifree(data->numUsers); + } + else if(filter->type == TYPE_JOIN) + { + if(filter->callback != NULL) + ciAddCallback_(chat, CALLBACK_ENTER_CHANNEL, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnterChannelParams)); + } + else if(filter->type == TYPE_TOPIC) + { + const char * channel = ((ciCallbackGetChannelTopicParams *)params)->channel; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_CHANNEL_TOPIC, filter->callback, params, filter->param, filter->ID, channel, sizeof(ciCallbackGetChannelTopicParams)); + } + else if(filter->type == TYPE_NAMES) + { + NAMESData * data = (NAMESData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_ENUM_USERS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnumUsersParams)); + + for(i = 0 ; i < data->numUsers ; i++) + gsifree(data->users[i]); + gsifree(data->users); + gsifree(data->modes); + } + else if(filter->type == TYPE_WHOIS) + { + WHOISData * data = (WHOISData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_USER_INFO, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetUserInfoParams)); + + for(i = 0 ; i < data->numChannels ; i++) + gsifree(data->channels[i]); + gsifree(data->channels); + gsifree(data->name); + gsifree(data->address); + gsifree(data->user); + } + else if(filter->type == TYPE_WHO) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_BASIC_USER_INFO, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetBasicUserInfoParams)); + } + else if(filter->type == TYPE_CWHO) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_CHANNEL_BASIC_USER_INFO, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetBasicUserInfoParams)); + } + else if(filter->type == TYPE_CMODE) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_CHANNEL_MODE, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetChannelModeParams)); + } + else if(filter->type == TYPE_UMODE) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_USER_MODE, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetUserModeParams)); + } + else if(filter->type == TYPE_GETUDPRELAY) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_UDPRELAY, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetUdpRelayParams)); + } + else if(filter->type == TYPE_BAN) + { + BANData * data = (BANData *)filter->data; + + gsifree(data->channel); + } + else if(filter->type == TYPE_GETBAN) + { + GETBANData * data = (GETBANData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_ENUM_CHANNEL_BANS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnumChannelBansParams)); + + // gsifree the filter. + /////////////////// + for(i = 0 ; i < data->numBans ; i++) + gsifree(data->bans[i]); + } + else if(filter->type == TYPE_NICK) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_CHANGE_NICK, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackChangeNickParams)); + } + else if(filter->type == TYPE_GETKEY) + { + GETKEYData * data = (GETKEYData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_GLOBAL_KEYS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetGlobalKeysParams)); + + gsifree(data->channel); + for(i = 0 ; i < data->num ; i++) + gsifree(data->keys[i]); + gsifree(data->keys); + } + else if(filter->type == TYPE_GETCKEY) + { + GETCKEYData * data = (GETCKEYData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_CHANNEL_KEYS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetChannelKeysParams)); + + for(i = 0 ; i < data->num ; i++) + gsifree(data->keys[i]); + gsifree(data->keys); + } + else if(filter->type == TYPE_GETCHANKEY) + { + GETCHANKEYData * data = (GETCHANKEYData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_GET_CHANNEL_KEYS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetChannelKeysParams)); + + for(i = 0 ; i < data->num ; i++) + gsifree(data->keys[i]); + gsifree(data->keys); + } + else if(filter->type == TYPE_UNQUIET) + { + NAMESData * data = (NAMESData *)filter->data; + + if(filter->callback) + ciAddCallback_(chat, CALLBACK_NEW_USER_LIST, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackNewUserListParams)); + + for(i = 0 ; i < data->numUsers ; i++) + gsifree(data->users[i]); + gsifree(data->users); + gsifree(data->modes); + } + else if(filter->type == TYPE_CDKEY) + { + if(filter->callback) + ciAddCallback_(chat, CALLBACK_AUTHENTICATE_CDKEY, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackAuthenticateCDKeyParams)); + } + else + { + assert(0); + } + + // Remove the filter. + ///////////////////// + ciRemoveFilter(chat, filter); +} + +// Called when a filter times out to deal with calling the failed callback. +/////////////////////////////////////////////////////////////////////////// +static void ciFilterTimedout(CHAT chat, ciServerMessageFilter * filter) +{ + assert(filter); + ASSERT_TYPE(filter->type); + + // Check the type. + ////////////////// + if(filter->type == TYPE_LIST) + { + ciCallbackEnumChannelsAllParams params; + params.success = CHATFalse; + params.numChannels = 0; + params.channels = NULL; + params.topics = NULL; + params.numUsers = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_JOIN) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATEnterTimedOut; + params.channel = filter->name; + + FINISH_FILTER; + } + else if(filter->type == TYPE_TOPIC) + { + ciCallbackGetChannelTopicParams params; + params.success = CHATFalse; + params.channel = filter->name; + params.topic = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_NAMES) + { + ciCallbackEnumUsersParams params; + params.success = CHATFalse; + params.channel = filter->name; + params.numUsers = 0; + params.users = NULL; + params.modes = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_WHOIS) + { + ciCallbackGetUserInfoParams params; + params.success = CHATFalse; + params.nick = filter->name; + params.user = NULL; + params.name = NULL; + params.address = NULL; + params.numChannels = 0; + params.channels = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_WHO) + { + ciCallbackGetBasicUserInfoParams params; + params.success = CHATFalse; + params.nick = filter->name; + params.user = NULL; + params.address = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_CWHO) + { + ciCallbackGetChannelBasicUserInfoParams params; + params.success = CHATFalse; + params.channel = filter->name; + params.nick = NULL; + params.user = NULL; + params.address = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_CMODE) + { + ciCallbackGetChannelModeParams params; + params.success = CHATFalse; + params.channel = filter->name; + params.mode = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_UMODE) + { + ciCallbackGetUserModeParams params; + params.success = CHATFalse; + params.channel = filter->name2; + params.user = filter->name; + params.mode = 0; + + FINISH_FILTER; + } + else if(filter->type == TYPE_BAN) + { + ciFinishFilter(chat, filter, NULL); + } + else if(filter->type == TYPE_GETBAN) + { + ciCallbackEnumChannelBansParams params; + params.channel = filter->name; + params.numBans = 0; + params.bans = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_NICK) + { + ciCallbackChangeNickParams params; + params.success = CHATFalse; + params.oldNick = filter->name; + params.newNick = filter->name2; + + FINISH_FILTER; + } + else if(filter->type == TYPE_GETKEY) + { + ciCallbackGetGlobalKeysParams params; + params.success = CHATFalse; + params.user = NULL; + params.num = 0; + params.keys = NULL; + params.values = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_GETCKEY) + { + ciCallbackGetChannelKeysParams params; + params.success = CHATFalse; + params.channel = NULL; + params.user = NULL; + params.num = 0; + params.keys = NULL; + params.values = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_GETCHANKEY) + { + ciCallbackGetChannelKeysParams params; + params.success = CHATFalse; + params.channel = NULL; + params.user = NULL; + params.num = 0; + params.keys = NULL; + params.values = NULL; + + FINISH_FILTER; + } + else if(filter->type == TYPE_UNQUIET) + { + ciRemoveFilter(chat, filter); + } + else if(filter->type == TYPE_CDKEY) + { + ciCallbackAuthenticateCDKeyParams params; + params.result = 0; + params.message = "Timed out"; + + FINISH_FILTER; + } + else if(filter->type == TYPE_GETUDPRELAY) + { + ciCallbackGetUdpRelayParams params; + params.channel = filter->name; + params.udpIp = NULL; + params.udpKey = 0; + params.udpPort = 0; + + FINISH_FILTER; + } + else + { + assert(0); + } +} + +void ciFilterThink(CHAT chat) +{ + ciServerMessageFilter * filter; + ciServerMessageFilter * pnext; + gsi_time now; + CONNECTION; + + now = 0; + now = 2; + now = current_time(); + + for(filter = connection->filterList ; filter != NULL ; filter = pnext) + { + pnext = filter->pnext; + if(now > filter->timeout) + { + ciFilterTimedout(chat, filter); + } + } +} + +int ciGetNextID(CHAT chat) +{ + int rcode; + CONNECTION; + + // Store the next. + ////////////////// + rcode = connection->nextID; + + // Increment the ID. + //////////////////// + if(connection->nextID == INT_MAX) + connection->nextID = 1; + else + connection->nextID++; + + return rcode; +} + +CHATBool ciCheckFiltersForID(CHAT chat, int ID) +{ + ciServerMessageFilter * filter; + CONNECTION; + + assert(ID > 0); + + for(filter = connection->filterList ; filter != NULL ; filter = filter->pnext) + { + // Check for a matching ID. + /////////////////////////// + if(filter->ID == ID) + return CHATTrue; + } + + // No matches. + ////////////// + return CHATFalse; +} + +void ciCleanupFilters(CHAT chat) +{ + CONNECTION; + + while(connection->filterList) + ciFilterTimedout(chat, connection->filterList); // PANTS|03.13.01 - changed from ciRemoveFilter +} + +static int ciAddFilter(CHAT chat, int type, const char * name, const char * name2, void * callback, void * callback2, void * param, void * data) +{ + ciServerMessageFilter * filter; + CONNECTION; + + // Create the filter. + ///////////////////// + filter = (ciServerMessageFilter *)gsimalloc(sizeof(ciServerMessageFilter)); + if(filter == NULL) + return 0; //ERRCON + + // Setup the filter. + //////////////////// + memset(filter, 0, sizeof(ciServerMessageFilter)); + filter->type = type; + filter->timeout = (current_time() + FILTER_TIMEOUT); + filter->callback = callback; + filter->callback2 = callback2; + filter->param = param; + filter->data = data; + if(name) + filter->name = goastrdup(name); + else + filter->name = NULL; + if(name2) + filter->name2 = goastrdup(name2); + else + filter->name2 = NULL; + filter->ID = ciGetNextID(chat); + + // Add the filter to the end of the list. + ///////////////////////////////////////// + if(connection->filterList == NULL) + connection->filterList = filter; + else + connection->lastFilter->pnext = filter; + connection->lastFilter = filter; + + return filter->ID; +} + +int ciAddLISTFilter(CHAT chat, chatEnumChannelsCallbackEach callbackEach, chatEnumChannelsCallbackAll callbackAll, void * param) +{ + LISTData * data = (LISTData *)gsimalloc(sizeof(LISTData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(LISTData)); + + return ciAddFilter(chat, TYPE_LIST, NULL, NULL, (void*)callbackEach, (void*)callbackAll, param, data); +} + +int ciAddJOINFilter(CHAT chat, const char * channel, chatEnterChannelCallback callback, void * param, chatChannelCallbacks * callbacks, const char * password) +{ + int rcode; + JOINData * data; + + assert(password != NULL); + assert(strlen(password) < MAX_PASSWORD); + + data = (JOINData *)gsimalloc(sizeof(JOINData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(JOINData)); + data->callbacks = *callbacks; + strzcpy(data->password, password, MAX_PASSWORD); + + rcode = ciAddFilter(chat, TYPE_JOIN, channel, NULL, (void*)callback, NULL, param, data); + if(rcode == 0) + gsifree(data); + + return rcode; +} + +int ciAddTOPICFilter(CHAT chat, const char * channel, chatGetChannelTopicCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_TOPIC, channel, NULL, (void*)callback, NULL, param, NULL); +} + +int ciAddNAMESFilter(CHAT chat, const char * channel, chatEnumUsersCallback callback, void * param) +{ + NAMESData * data = (NAMESData *)gsimalloc(sizeof(NAMESData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(NAMESData)); + + return ciAddFilter(chat, TYPE_NAMES, channel, NULL, (void*)callback, NULL, param, data); +} + +int ciAddWHOISFilter(CHAT chat, const char * user, chatGetUserInfoCallback callback, void * param) +{ + int rcode; + WHOISData * data = (WHOISData *)gsimalloc(sizeof(WHOISData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(WHOISData)); + + rcode = ciAddFilter(chat, TYPE_WHOIS, user, NULL, (void*)callback, NULL, param, data); + if(rcode == 0) + gsifree(data); + return rcode; +} + +int ciAddWHOFilter(CHAT chat, const char * user, chatGetBasicUserInfoCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_WHO, user, NULL, (void*)callback, NULL, param, NULL); +} + +int ciAddCWHOFilter(CHAT chat, const char * channel, chatGetChannelBasicUserInfoCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_CWHO, channel, NULL, (void*)callback, NULL, param, NULL); +} + +int ciAddCMODEFilter(CHAT chat, const char * channel, chatGetChannelModeCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_CMODE, channel, NULL, (void*)callback, NULL, param, NULL); +} + +int ciAddUMODEFilter(CHAT chat, const char * user, const char * channel, chatGetUserModeCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_UMODE, user, channel, (void*)callback, NULL, param, NULL); +} + +int ciAddGETUDPRELAYFilter(CHAT chat, const char * channel, chatGetUdpRelayCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_GETUDPRELAY, channel, NULL, (void*)callback, NULL, param, NULL); +} + + +int ciAddBANFilter(CHAT chat, const char * user, const char * channel) +{ + BANData * data = (BANData *)gsimalloc(sizeof(BANData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(BANData)); + data->channel = goastrdup(channel); + if(data->channel == NULL) + { + gsifree(data); + return 0; //ERRCON + } + + return ciAddFilter(chat, TYPE_BAN, user, NULL, NULL, NULL, NULL, data); +} + +int ciAddGETBANFilter(CHAT chat, const char * channel, chatEnumChannelBansCallback callback, void * param) +{ + GETBANData * data = (GETBANData *)gsimalloc(sizeof(GETBANData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(GETBANData)); + + return ciAddFilter(chat, TYPE_GETBAN, channel, NULL, (void*)callback, NULL, param, data); +} + +int ciAddNICKFilter(CHAT chat, const char * oldNick, const char * newNick, chatChangeNickCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_NICK, oldNick, newNick, (void*)callback, NULL, param, NULL); +} + +int ciAddGETKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, const char * channel, chatGetGlobalKeysCallback callback, void * param) +{ + int i; + GETKEYData * data = (GETKEYData *)gsimalloc(sizeof(GETKEYData)); + if(!data) + return 0; + memset(data, 0, sizeof(GETKEYData)); + + data->num = num; + if(channel) + { + data->channel = goastrdup(channel); + if(!data->channel) + { + gsifree(data); + return 0; + } + } + data->keys = (char **)gsimalloc(sizeof(char *) * num); + if(!data->keys) + { + gsifree(data->channel); + gsifree(data); + return 0; + } + for(i = 0 ; i < num ; i++) + { + data->keys[i] = goastrdup(keys[i]); + if(!data->keys[i]) + { + for( i-- ; i >= 0 ; i--) + gsifree(data->keys[i]); + gsifree(data->keys); + gsifree(data->channel); + gsifree(data); + return 0; + } + } + + return ciAddFilter(chat, TYPE_GETKEY, cookie, NULL, (void*)callback, NULL, param, data); +} + +int ciAddGETCKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, CHATBool channel, CHATBool getBroadcastKeys, chatGetChannelKeysCallback callback, void * param) +{ + int src; + int dest; + GETCKEYData * data = (GETCKEYData *)gsimalloc(sizeof(GETCKEYData)); + if(!data) + return 0; + memset(data, 0, sizeof(GETCKEYData)); + data->allBroadcastKeys = getBroadcastKeys; + + data->num = num; + data->channel = channel; + if(getBroadcastKeys) + data->num--; + data->keys = (char **)gsimalloc(sizeof(char *) * data->num); + if(!data->keys) + { + gsifree(data); + return 0; + } + for(src = 0, dest = 0 ; src < num ; src++) + { + if(strcmp(keys[src], "b_*") != 0) + { + data->keys[dest] = goastrdup(keys[src]); + if(!data->keys[dest]) + { + for( dest-- ; dest >= 0 ; dest--) + gsifree(data->keys[dest]); + gsifree(data->keys); + gsifree(data); + return 0; + } + dest++; + } + } + data->num = dest; + + return ciAddFilter(chat, TYPE_GETCKEY, cookie, NULL, (void*)callback, NULL, param, data); +} + +int ciAddGETCHANKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, CHATBool getBroadcastKeys, chatGetChannelKeysCallback callback, void * param) +{ + int src; + int dest; + GETCHANKEYData * data = (GETCHANKEYData *)gsimalloc(sizeof(GETCHANKEYData)); + if(!data) + return 0; + memset(data, 0, sizeof(GETCHANKEYData)); + data->allBroadcastKeys = getBroadcastKeys; + + data->num = num; + if(getBroadcastKeys) + data->num--; + if(data->num) + { + data->keys = (char **)gsimalloc(sizeof(char *) * data->num); + if(!data->keys) + { + gsifree(data); + return 0; + } + for(src = 0, dest = 0 ; src < num ; src++) + { + if(strcmp(keys[src], "b_*") != 0) + { + data->keys[dest] = goastrdup(keys[src]); + if(!data->keys[dest]) + { + for( dest-- ; dest >= 0 ; dest--) + gsifree(data->keys[dest]); + gsifree(data->keys); + gsifree(data); + return 0; + } + dest++; + } + } + data->num = dest; + } + + return ciAddFilter(chat, TYPE_GETCHANKEY, cookie, NULL, (void*)callback, NULL, param, data); +} + +int ciAddUNQUIETFilter(CHAT chat, const char * channel) +{ + chatChannelCallbacks * callbacks; + NAMESData * data; + + callbacks = ciGetChannelCallbacks(chat, channel); + if(!callbacks || !callbacks->newUserList) + return 0; + + data = (NAMESData *)gsimalloc(sizeof(NAMESData)); + if(data == NULL) + return 0; //ERRCON + memset(data, 0, sizeof(NAMESData)); + + return ciAddFilter(chat, TYPE_UNQUIET, channel, NULL, (void*)callbacks->newUserList, NULL, callbacks->param, data); +} + +int ciAddCDKEYFilter(CHAT chat, chatAuthenticateCDKeyCallback callback, void * param) +{ + return ciAddFilter(chat, TYPE_CDKEY, NULL, NULL, (void*)callback, NULL, param, NULL); +} + +/***************** +** MODE PARSING ** +*****************/ +static ciModeChange * ciParseMode(char * mode, char ** params, int numParams) +{ + CHATBool enable; + int c; + ciModeChange * changes = NULL; + int numChanges = 0; + ciModeChange * change; + int modeChange; + CHATBool addParam = CHATFalse; + void * tempPtr; + + assert(mode != NULL); + + // Check the initial enable mode. + ///////////////////////////////// + if(*mode == '+') + enable = CHATTrue; + else if(*mode == '-') + enable = CHATFalse; + else + return NULL; //ERRCON + mode++; + + // Go through the mode string. + ////////////////////////////// + do + { + // Get the next character. + ////////////////////////// + c = *mode++; + + // Interpret the char. + ////////////////////// + switch(c) + { + case '+': + enable = CHATTrue; + modeChange = -1; + break; + + case '-': + enable = CHATFalse; + modeChange = -1; + break; + + case '\0': + modeChange = MODE_END; + addParam = CHATFalse; + break; + + case 'i': + modeChange = MODE_INVITE_ONLY; + addParam = CHATFalse; + break; + + case 'l': + modeChange = MODE_LIMIT; + addParam = CHATTrue; + break; + + case 'p': + modeChange = MODE_PRIVATE; + addParam = CHATFalse; + break; + + case 's': + modeChange = MODE_SECRET; + addParam = CHATFalse; + break; + + case 'k': + modeChange = MODE_KEY; + addParam = CHATTrue; + break; + + case 'm': + modeChange = MODE_MODERATED; + addParam = CHATFalse; + break; + + case 'n': + modeChange = MODE_NO_EXTERNAL_MESSAGES; + addParam = CHATFalse; + break; + + case 't': + modeChange = MODE_ONLY_OPS_CHANGE_TOPIC; + addParam = CHATFalse; + break; + + case 'o': + modeChange = MODE_OP; + addParam = CHATTrue; + break; + + case 'v': + modeChange = MODE_VOICE; + addParam = CHATTrue; + break; + + case 'b': + modeChange = MODE_BAN; + addParam = CHATTrue; + break; + + case 'u': + modeChange = MODE_USERS_HIDDEN; + addParam = CHATFalse; + break; + + case 'w': + modeChange = MODE_RECEIVE_WALLOPS; + addParam = CHATFalse; + break; + + case 'e': + modeChange = MODE_OPS_OBEY_CHANNEL_LIMIT; + addParam = CHATFalse; + break; + + default: + // Unknown mode. + //////////////// + //assert(0); + modeChange = -1; + } + + // Make the change. + /////////////////// + if(modeChange != -1) + { + tempPtr = gsirealloc(changes, sizeof(ciModeChange) * (numChanges + 1)); + if(tempPtr == NULL) + { + gsifree(changes); + return NULL; //ERRCON + } + changes = (ciModeChange *)tempPtr; + change = &changes[numChanges++]; + memset(change, 0, sizeof(ciModeChange)); + change->enable = enable; + change->mode = modeChange; + + // Add a param if needed. + ///////////////////////// + if(addParam) + { + // PANTS - 09.27.00 - changed to work even if no param + if(numParams > 0) + { + change->param = *params++; + numParams--; + } + else + change->param = NULL; + } + } + } + while(c != '\0'); + + return changes; +} + +static void ciApplyChangesToMode(CHATChannelMode * mode, ciModeChange * changes) +{ + ciModeChange * change; + + // Go through all the changes. + ////////////////////////////// + for(change = changes ; change->mode != MODE_END ; change++) + { + switch(change->mode) + { + case MODE_BAN: + break; + + case MODE_INVITE_ONLY: + mode->InviteOnly = change->enable; + break; + + case MODE_LIMIT: + if(change->enable && change->param) + mode->Limit = atoi(change->param); + else + mode->Limit = 0; + break; + + case MODE_PRIVATE: + mode->Private = change->enable; + break; + + case MODE_SECRET: + mode->Secret = change->enable; + break; + + case MODE_KEY: + break; + + case MODE_MODERATED: + mode->Moderated = change->enable; + break; + + case MODE_NO_EXTERNAL_MESSAGES: + mode->NoExternalMessages = change->enable; + break; + + case MODE_ONLY_OPS_CHANGE_TOPIC: + mode->OnlyOpsChangeTopic = change->enable; + break; + + case MODE_OP: + break; + + case MODE_VOICE: + break; + + case MODE_USERS_HIDDEN: + break; + + case MODE_RECEIVE_WALLOPS: + break; + + case MODE_OPS_OBEY_CHANNEL_LIMIT: + mode->OpsObeyChannelLimit = change->enable; + break; + + default: + assert(0); + } + } +} + +/************* +** HANDLERS ** +*************/ +void ciPrivmsgHandler(CHAT chat, const ciServerMessage * message) +{ + char * ctcp; + char * target; + char * from; + CHATBool action = CHATFalse; + char * msg; + int len; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciPrivmsgHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + target = message->params[0]; + msg = message->params[1]; + from = message->nick; + + // Check for CTCP. + ////////////////// + len = (int)strlen(msg); + ctcp = ""; + if((msg[0] == '\001') && IS_ALPHA(msg[1]) && (msg[len - 1] == '\001')) + { + char * str; + + // Strip the ending \001. + // PANTS|08.14.00 + ///////////////////////// + msg[len - 1] = '\0'; + + // End the command. + /////////////////// + str = strchr(msg, ' '); + if(str != NULL) + { + // The start of the CTCP command. + ///////////////////////////////// + ctcp = &msg[1]; + + // End the ctcp. + //////////////// + *str = '\0'; + msg = (str + 1); + } + } + + // Is it an action? + /////////////////// + if(strcmp(ctcp, "ACTION") == 0) + { + // It's an action. + ////////////////// + action = CHATTrue; + } +#if 0 + // Is it a ping? + //////////////// + else if(strcmp(ctcp, "PING") == 0) + { + // Send back a ping. + //////////////////// + ciSocketSendf(&connection->chatSocket, "NOTICE %s :\001PING %s\001", from, msg); + + return; + } +#endif + else if(ctcp[0] != '\0') + { + // Unsupported action, ignore. + ////////////////////////////// + return; + } + + // Is it a private message? + /////////////////////////// + if(strcasecmp(target, connection->nick) == 0) + { + if(connection->globalCallbacks.privateMessage != NULL) + { + ciCallbackPrivateMessageParams params; + params.user = from; + params.message = msg; + if(action) + params.type = CHAT_ACTION; + else + params.type = CHAT_MESSAGE; + ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); + } + } + else + { + // Get the channel callbacks. + ///////////////////////////// + chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); + if((callbacks != NULL) && (callbacks->channelMessage != NULL)) + { + ciCallbackChannelMessageParams params; + params.channel = target; + params.user = from; + params.message = msg; + if(action) + params.type = CHAT_ACTION; + else + params.type = CHAT_MESSAGE; + ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); + } + } +} + +void ciNoticeHandler(CHAT chat, const ciServerMessage * message) +{ + char * target; + char * msg; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciNoticeHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + target = message->params[0]; + msg = message->params[1]; + + // Is it a private message? + /////////////////////////// + if(strcasecmp(target, connection->nick) == 0) + { + if(connection->globalCallbacks.privateMessage != NULL) + { + ciCallbackPrivateMessageParams params; + if(message->nick != NULL) + params.user = message->nick; + else + params.user = NULL; + params.message = msg; + params.type = CHAT_NOTICE; + ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); + } + } + else + { + // Get the channel callbacks. + ///////////////////////////// + chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); + if((callbacks != NULL) && (callbacks->channelMessage != NULL)) + { + ciCallbackChannelMessageParams params; + params.channel = target; + if(message->nick != NULL) + params.user = message->nick; + else + params.user = NULL; + params.message = msg; + params.type = CHAT_NOTICE; + ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); + } + } +} + +void ciUTMHandler(CHAT chat, const ciServerMessage * message) +{ + char * target; + char * msg; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciUTMHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + target = message->params[0]; + msg = message->params[1]; + + // Is it a private message? + /////////////////////////// + if(strcasecmp(target, connection->nick) == 0) + { + if(connection->globalCallbacks.privateMessage != NULL) + { + ciCallbackPrivateMessageParams params; + if(message->nick != NULL) + params.user = message->nick; + else + params.user = NULL; + params.message = msg; + params.type = CHAT_UTM; + ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); + } + } + else + { + // Get the channel callbacks. + ///////////////////////////// + chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); + if((callbacks != NULL) && (callbacks->channelMessage != NULL)) + { + ciCallbackChannelMessageParams params; + params.channel = target; + if(message->nick != NULL) + params.user = message->nick; + else + params.user = NULL; + params.message = msg; + params.type = CHAT_UTM; + ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); + } + } +} + +void ciATMHandler(CHAT chat, const ciServerMessage * message) +{ + char * target; + char * msg; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciATMHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + target = message->params[0]; + msg = message->params[1]; + + // Is it a private message? + /////////////////////////// + if(strcasecmp(target, connection->nick) == 0) + { + if(connection->globalCallbacks.privateMessage != NULL) + { + ciCallbackPrivateMessageParams params; + if(message->nick != NULL) + params.user = message->nick; + else + params.user = NULL; + params.message = msg; + params.type = CHAT_ATM; + ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); + } + } + else + { + // Get the channel callbacks. + ///////////////////////////// + chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); + if((callbacks != NULL) && (callbacks->channelMessage != NULL)) + { + ciCallbackChannelMessageParams params; + params.channel = target; + if(message->nick != NULL) + params.user = message->nick; + else + params.user = NULL; + params.message = msg; + params.type = CHAT_ATM; + ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); + } + } +} + +void ciPingHandler(CHAT chat, const ciServerMessage * message) +{ + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciPingHandler called\n"); +#endif + + ciSocketSendf(&connection->chatSocket, "PONG %s", message->param); +} + +void ciNickHandler(CHAT chat, const ciServerMessage * message) +{ + char * oldNick; + char * newNick; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciNickHandler called\n"); +#endif + + assert(message->numParams == 1); + if(message->numParams != 1) + return; //ERRCON + + oldNick = message->nick; + newNick = message->params[0]; + + // Is this me? + ////////////// + if(strcasecmp(oldNick, connection->nick) == 0) + { + ciServerMessageFilter * filter; + ciFilterMatch match; + + // Copy the new nick. + ///////////////////// + assert(strlen(newNick) < MAX_NICK); + strzcpy(connection->nick, newNick, MAX_NICK); + + // Copy to the unicode version +#ifdef GSI_UNICODE + AsciiToUCS2String(connection->nick, connection->nickW); +#endif + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_NICK; + match.name = oldNick; + match.name2 = newNick; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + // Add the callback. + //////////////////// + ciCallbackChangeNickParams params; + params.success = CHATTrue; + params.oldNick = oldNick; + params.newNick = newNick; + + FINISH_FILTER; + } + } + + // Change the nick. + /////////////////// + ciUserChangedNick(chat, oldNick, newNick); +} + +void ciJoinHandler(CHAT chat, const ciServerMessage * message) +{ + char * channel; + char * nick; + char * user; + char * address; + int mode; + chatChannelCallbacks * callbacks; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciJoinHandler called\n"); +#endif + + assert(message->numParams == 1); + if(message->numParams != 1) + return; //ERRCON + + channel = message->params[0]; + nick = message->nick; + user = message->user; + address = message->host; + + // Check for mode. + ////////////////// + if(*nick == '@') + { + mode = CHAT_OP; + nick++; + assert(*nick != '\0'); + } + else if(*nick == '+') + { + mode = CHAT_VOICE; + nick++; + assert(*nick != '\0'); + } + else + { + mode = CHAT_NORMAL; + } + + // Me? + ////// + if(strcmp(nick, connection->nick) == 0) + { + ciServerMessageFilter * filter; + ciFilterMatch match; + + // Make sure we're entering this channel. + ///////////////////////////////////////// + if(!ciIsEnteringChannel(chat, channel)) + return; + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + + // Look for a matching filter. + ////////////////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + JOINData * data; + + // Get the data. + //////////////// + data = (JOINData *)filter->data; + + // Add the channel. + /////////////////// + ciChannelEntered(chat, channel, &data->callbacks); + + // Set the password. + //////////////////// + ciSetChannelPassword(chat, channel, data->password); + + // Joined. + ////////// + data->joined = CHATTrue; + + // Get the channel's mode. + ////////////////////////// + ciSocketSendf(&connection->chatSocket, "MODE %s", channel); + } + + return; + } + + // Add the user to the channel. + /////////////////////////////// + if(ciInChannel(chat, channel)) + ciUserEnteredChannel(chat, nick, channel, mode, user, address); + + // Was the join callback called? + //////////////////////////////// + if(ciWasJoinCallbackCalled(chat, channel)) //PANTS - 03.01.00 - check if the join callback was called + { + // Call the join callback. + ////////////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks != NULL) + { + if(callbacks->userJoined != NULL) + { + ciCallbackUserJoinedParams params; + params.channel = channel; + params.user = nick; + params.mode = mode; + ciAddCallback(chat, CALLBACK_USER_JOINED, (void*)callbacks->userJoined, ¶ms, callbacks->param, 0, channel); + } + + // Call the user list updated callback. + /////////////////////////////////////// + if(callbacks->userListUpdated != NULL) + { + ciCallbackUserListUpdatedParams params; + params.channel = channel; + ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); + } + } + } +} + +void ciPartHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + char * channel; + char * reason; + chatChannelCallbacks * callbacks; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciPartHandler called\n"); +#endif + + nick = message->nick; + channel = message->params[0]; + if (message->numParams > 1) //get the reason + reason = message->params[1]; + else + reason = ""; + + // Did we leave the channel? + //////////////////////////// + if(strcmp(nick, connection->nick) == 0) + { + // Ignore it, we already left. + ////////////////////////////// + } + else + { + // Remove the user from the channel. + //////////////////////////////////// + ciUserLeftChannel(chat, nick, channel); + + // Was the join callback called? + //////////////////////////////// + if(ciWasJoinCallbackCalled(chat, channel)) + { + // Call the left callback. + ////////////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks != NULL) + { + if(callbacks->userParted != NULL) + { + ciCallbackUserPartedParams params; + params.channel = channel; + params.user = nick; + params.why = CHAT_LEFT; + params.reason = reason; + params.kicker = NULL; + ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); + } + + // Call the user list updated callback. + /////////////////////////////////////// + if(callbacks->userListUpdated != NULL) + { + ciCallbackUserListUpdatedParams params; + params.channel = channel; + ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); + } + } + } + } +} + +void ciKickHandler(CHAT chat, const ciServerMessage * message) +{ + char * channel; + char * kicker; + char * kickee; + char * reason; + chatChannelCallbacks * callbacks; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciKickHandler called\n"); +#endif + + assert((message->numParams == 2) || (message->numParams == 3)); + if((message->numParams != 2) && (message->numParams != 3)) + return; //ERRCON + + channel = message->params[0]; + kicker = message->nick; + kickee = message->params[1]; + if(message->numParams == 3) + reason = message->params[2]; + else + reason = ""; + + // Remove the user from the channel. + //////////////////////////////////// + ciUserLeftChannel(chat, kickee, channel); + + // Get the callbacks. + ///////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks != NULL) + { + // Check if we were kicked. + /////////////////////////// + if(strcasecmp(kickee, connection->nick) == 0) + { + // Add the callback. + //////////////////// + if(callbacks->kicked != NULL) + { + ciCallbackKickedParams params; + params.channel = channel; + params.user = kicker; + params.reason = reason; + ciAddCallback(chat, CALLBACK_KICKED, (void*)callbacks->kicked, ¶ms, callbacks->param, 0, NULL); + } + + // Left the channel. + //////////////////// + ciChannelLeft(chat, channel); + } + else + { + // Was the join callback called? + //////////////////////////////// + if(ciWasJoinCallbackCalled(chat, channel)) + { + // Add the callback. + //////////////////// + if(callbacks->userParted != NULL) + { + ciCallbackUserPartedParams params; + params.channel = channel; + params.user = kickee; + params.why = CHAT_KICKED; + params.reason = reason; + params.kicker = kicker; + ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); + } + + // Call the user list updated callback. + /////////////////////////////////////// + if(callbacks->userListUpdated != NULL) + { + ciCallbackUserListUpdatedParams params; + params.channel = channel; + ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); + } + } + } + } +} + +static void ciQuitEnumChannelsCallback(CHAT chat, const char * user, const char * channel, void * reason) +{ + chatChannelCallbacks * callbacks; + + ASSERT_STR(user); + ASSERT_STR(channel); + assert(reason != NULL); + + // Remove the user from the channel. + //////////////////////////////////// + ciUserLeftChannel(chat, user, channel); + + // Was the join callback called? + //////////////////////////////// + if(ciWasJoinCallbackCalled(chat, channel)) + { + // Get the channel callbacks. + ///////////////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks != NULL) + { + // Call the quit callback. + ////////////////////////// + if(callbacks->userParted != NULL) + { + ciCallbackUserPartedParams params; + params.channel = (char *)channel; + params.user = (char *)user; + params.why = CHAT_QUIT; + params.reason = (char *)reason; + params.kicker = NULL; + ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); + } + + // Call the user list updated callback. + /////////////////////////////////////// + if(callbacks->userListUpdated != NULL) + { + ciCallbackUserListUpdatedParams params; + params.channel = (char *)channel; + ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); + } + } + } +} + +void ciQuitHandler(CHAT chat, const ciServerMessage * message) +{ + char * reason; + //CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciQuitHandler called\n"); +#endif + + assert(message->numParams == 1); + if(message->numParams != 1) + return; //ERRCON + + reason = message->params[0]; + + // Enum the channels this user is in. + ///////////////////////////////////// + ciUserEnumChannels(chat, message->nick, ciQuitEnumChannelsCallback, reason); +} + +static void ciKillEnumChannelsCallback(CHAT chat, const char * user, const char * channel, void * param) +{ + chatChannelCallbacks * callbacks; + char *reason = (char *)param; + ASSERT_STR(user); + ASSERT_STR(channel); + assert(reason != NULL); + + // Remove the user from the channel. + //////////////////////////////////// + ciUserLeftChannel(chat, user, channel); + + // Was the join callback called? + //////////////////////////////// + if(ciWasJoinCallbackCalled(chat, channel)) + { + // Get the channel callbacks. + ///////////////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks != NULL) + { + if(callbacks->userParted != NULL) + { + ciCallbackUserPartedParams params; + params.channel = (char *)channel; + params.user = (char *)user; + params.why = CHAT_KILLED; + params.reason = (char *)reason; + params.kicker = NULL; + ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); + } + + // Call the user list updated callback. + /////////////////////////////////////// + if(callbacks->userListUpdated != NULL) + { + ciCallbackUserListUpdatedParams params; + params.channel = (char *)channel; + ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); + } + } + } +} + +void ciKillHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + char * reason; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciKillHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + nick = message->params[0]; + reason = message->params[1]; + + // Enum the channels this user is in. + ///////////////////////////////////// + ciUserEnumChannels(chat, nick, ciKillEnumChannelsCallback, reason); +} + +void ciTopicHandler(CHAT chat, const ciServerMessage * message) +{ + char * channel; + char * topic; + chatChannelCallbacks * callbacks; + //CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciTopicHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + channel = message->params[0]; + topic = message->params[1]; + + // Set the channel's topic. + /////////////////////////// + ciSetChannelTopic(chat, channel, topic); + + // Get the callbacks. + ///////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if((callbacks != NULL) && (callbacks->topicChanged != NULL)) + { + ciCallbackTopicChangedParams params; + params.channel = channel; + params.topic = topic; + ciAddCallback(chat, CALLBACK_TOPIC_CHANGED, (void*)callbacks->topicChanged, ¶ms, callbacks->param, 0, channel); + } +} + +void ciModeHandler(CHAT chat, const ciServerMessage * message) +{ + ciModeChange * changes; + ciModeChange * change; + CHATChannelMode channelMode; + char * channel; + char * mode; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciModeHandler called\n"); +#endif + + assert(message->numParams >= 2); + if(message->numParams < 2) + return; //ERRCON + + channel = message->params[0]; + mode = message->params[1]; + + // Check that we're in this channel. + //////////////////////////////////// + if(!ciInChannel(chat, channel)) + return; + + // Parse the changes. + ///////////////////// + changes = ciParseMode(mode, message->params + 2, message->numParams - 2); + if(changes == NULL) + return; //ERRCON + + // Go through all the changes. + ////////////////////////////// + for(change = changes ; change->mode != MODE_END ; change++) + { + switch(change->mode) + { + case MODE_BAN: + break; + + case MODE_INVITE_ONLY: + break; + + case MODE_LIMIT: + break; + + case MODE_PRIVATE: + break; + + case MODE_SECRET: + break; + + case MODE_KEY: + if(change->enable) + ciSetChannelPassword(chat, channel, change->param); + else + ciSetChannelPassword(chat, channel, NULL); + break; + + case MODE_MODERATED: + break; + + case MODE_NO_EXTERNAL_MESSAGES: + break; + + case MODE_ONLY_OPS_CHANGE_TOPIC: + break; + + case MODE_USERS_HIDDEN: + break; + + case MODE_RECEIVE_WALLOPS: + break; + + case MODE_OP: + if(change->param) + ciUserChangedMode(chat, change->param, channel, CHAT_OP, change->enable); + break; + + case MODE_VOICE: + if(change->param) + ciUserChangedMode(chat, change->param, channel, CHAT_VOICE, change->enable); + break; + case MODE_OPS_OBEY_CHANNEL_LIMIT: + break; + default: + assert(0); + } + } + + // Apply the changes to the mode. + ///////////////////////////////// + if(!ciGetChannelMode(chat, channel, &channelMode)) + { + gsifree(changes); + return; //ERRCON + } + ciApplyChangesToMode(&channelMode, changes); + ciSetChannelMode(chat, channel, &channelMode); + + // gsifree the changes. + //////////////////// + gsifree(changes); +} + +void ciErrorHandler(CHAT chat, const ciServerMessage * message) +{ + //CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrorHandler called\n"); +#endif + + assert(message->numParams == 1); + if(message->numParams != 1) + return; //ERRCON + + // Handle the disconnection. + //////////////////////////// + ciHandleDisconnect(chat, message->params[0]); +} + +void ciInviteHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + char * channel; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciInviteHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; //ERRCON + + // Get info. + //////////// + nick = message->nick; + channel = message->params[1]; + + // Call the invite callback. + //////////////////////////// + if(connection->globalCallbacks.invited != NULL) + { + ciCallbackInvitedParams params; + params.channel = channel; + params.user = nick; + ciAddCallback(chat, CALLBACK_INVITED, (void*)connection->globalCallbacks.invited, ¶ms, connection->globalCallbacks.param, 0, NULL); + } +} + +void ciNameReplyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch matches[4]; + ciServerMessageFilter * filter; + char * channel; + NAMESData * data = NULL; + char * names; + char * nick; + char * str; + void * tempPtr; + int mode; + int len; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciNameReplyHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + channel = message->params[2]; + names = message->params[3]; + + // Setup the filter matches. + //////////////////////////// + memset(matches, 0, sizeof(matches)); + matches[0].type = TYPE_JOIN; + matches[0].name = channel; + matches[1].type = TYPE_UNQUIET; + matches[1].name = channel; + matches[2].type = TYPE_NAMES; + matches[2].name = channel; + matches[3].type = TYPE_NAMES; + + // Check for a matching filter. + /////////////////////////////// + filter = ciFindFilter(chat, 4, matches); + if(!filter) + return; + + // Get the data. + //////////////// + if(filter->type != TYPE_JOIN) + data = (NAMESData *)filter->data; + + // Parse out the names. + /////////////////////// + nick = strtok(names, " "); + while(nick != NULL) + { + assert(nick[0] != '\0'); + + // Check the mode. + ////////////////// + if(nick[0] == '@') + { + assert(nick[1] != '\0'); + mode = CHAT_OP; + nick++; + } + else if(nick[0] == '+') + { + assert(nick[1] != '\0'); + mode = CHAT_VOICE; + nick++; + } + else + mode = CHAT_NORMAL; + + if(filter->type != TYPE_JOIN) + { + // Check for resize. + //////////////////// + if(data->numUsers == data->len) + { + tempPtr = (char **)gsirealloc(data->users, sizeof(char *) * (data->len + NAMES_ARRAY_INC)); + if(tempPtr == NULL) + { + assert(0); + return; //ERRCON + } + data->users = (char **)tempPtr; + tempPtr = (char **)gsirealloc(data->modes, sizeof(int) * (data->len + NAMES_ARRAY_INC)); + if(tempPtr == NULL) + { + assert(0); + return; //ERRCON + } + data->modes = (int *)tempPtr; + data->len += NAMES_ARRAY_INC; + } + + // Allocate mem for the nick. + ///////////////////////////// + len = (int)(strlen(nick) + 1); + str = (char *)gsimalloc((unsigned int)len); + if(str == NULL) + { + assert(0); + return; //ERRCON + } + memcpy(str, nick, (unsigned int)len); + + // Set the pointers. + //////////////////// + data->users[data->numUsers] = str; + data->modes[data->numUsers] = mode; + data->numUsers++; + } + + if((filter->type == TYPE_JOIN) || (filter->type == TYPE_UNQUIET)) + { + // Add the nick to the channel. + /////////////////////////////// + ciUserEnteredChannel(chat, nick, channel, mode, NULL, NULL); + } + + // Get the next nick. + ///////////////////// + nick = strtok(NULL, " "); + } +} + +void ciEndOfNamesHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch matches[4]; + ciServerMessageFilter * filter; + char * channel; + //CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciEndOfNamesHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Check for the special case "all channels". + ///////////////////////////////////////////// + if(strcmp(channel, "*") == 0) + channel = NULL; + + // Setup the filter matches. + //////////////////////////// + memset(matches, 0, sizeof(matches)); + matches[0].type = TYPE_JOIN; + matches[0].name = channel; + matches[1].type = TYPE_UNQUIET; + matches[1].name = channel; + matches[2].type = TYPE_NAMES; + matches[2].name = channel; + matches[3].type = TYPE_NAMES; + + // Look for a matching filter. + ////////////////////////////// + filter = ciFindFilter(chat, 4, matches); + if(!filter) + return; + + // Join filter? + /////////////// + if(filter->type == TYPE_JOIN) + { + ciCallbackEnterChannelParams params; + params.success = CHATTrue; + params.result = CHATEnterSuccess; + params.channel = channel; + + if(!filter->callback) + { + // There's no callback, so set the callback called flag now. + //////////////////////////////////////////////////////////// + ciJoinCallbackCalled(chat, channel); + } + + FINISH_FILTER; + + return; + } + + // Unquiet filter? + //////////////////// + if(filter->type == TYPE_UNQUIET) + { + NAMESData * data = (NAMESData *)filter->data; + ciCallbackNewUserListParams params; + params.channel = channel; + params.numUsers = data->numUsers; + params.users = data->users; + params.modes = data->modes; + + FINISH_FILTER; + + return; + } + + // Names filter? + //////////////// + if(filter->type == TYPE_NAMES) + { + NAMESData * data = (NAMESData *)filter->data; + ciCallbackEnumUsersParams params; + params.success = CHATTrue; + params.channel = channel; + params.numUsers = data->numUsers; + params.users = data->users; + params.modes = data->modes; + + FINISH_FILTER; + + return; + } +} + +void ciRplTopicHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * topic; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplTopicHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + channel = message->params[1]; + topic = message->params[2]; + + // Set the channel's topic. + /////////////////////////// + ciSetChannelTopic(chat, channel, topic); + + // Setup a filter match. + //////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_TOPIC; + match.name = channel; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackGetChannelTopicParams params; + params.success = CHATTrue; + params.channel = channel; + params.topic = topic; + + FINISH_FILTER; + } + else + { + // No filter, probably checking the topic on join. + ////////////////////////////////////////////////// + chatChannelCallbacks * callbacks; + callbacks = ciGetChannelCallbacks(chat, channel); + if((callbacks != NULL) && (callbacks->topicChanged != NULL)) + { + ciCallbackTopicChangedParams params; + params.channel = channel; + params.topic = topic; + ciAddCallback(chat, CALLBACK_TOPIC_CHANGED, (void*)callbacks->topicChanged, ¶ms, callbacks->param, 0, channel); + } + } +} + +void ciRplNoTopicHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplNoTopicHandler called\n"); +#endif + + assert(message->numParams >= 2); + if(message->numParams < 2) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_TOPIC; + match.name = channel; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackGetChannelTopicParams params; + params.success = CHATTrue; + params.channel = channel; + params.topic = ""; + + FINISH_FILTER; + } + else + { + // No filter, probably checking the topic on join. + ////////////////////////////////////////////////// + chatChannelCallbacks * callbacks; + callbacks = ciGetChannelCallbacks(chat, channel); + if((callbacks != NULL) && (callbacks->topicChanged != NULL)) + { + ciCallbackTopicChangedParams params; + params.channel = channel; + params.topic = ""; + ciAddCallback(chat, CALLBACK_TOPIC_CHANGED, (void*)callbacks->topicChanged, ¶ms, callbacks->param, 0, channel); + } + } +} + +void ciErrNickInUseHandler(CHAT chat, const ciServerMessage * message) +{ + char * oldNick; + char * newNick; + ciServerMessageFilter * filter; + ciFilterMatch match; + + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplNickErrorHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + oldNick = message->params[0]; + newNick = message->params[1]; + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_NICK; + match.name = oldNick; + match.name2 = newNick; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + // Add the callback. + //////////////////// + ciCallbackChangeNickParams params; + params.success = CHATFalse; + params.oldNick = oldNick; + params.newNick = newNick; + + FINISH_FILTER; + } + else + { + // We should be connecting. + ////////////////////////// + assert(connection->connecting); + if(connection->connecting) + ciNickError(chat, CHAT_IN_USE, connection->nick, 0, NULL); + } +} + +void ciRplWhoReplyHandler(CHAT chat, const ciServerMessage * message) +{ + char * channel; + char * nick; + char * user; + char * address; + ciServerMessageFilter * filter; + ciFilterMatch matches[3]; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplWhoReplyHandler called\n"); +#endif + + assert(message->numParams == 8); + if(message->numParams != 8) + return; //ERRCON + + channel = message->params[1]; + user = message->params[2]; + address = message->params[3]; + nick = message->params[5]; + + // Cache the user and address. + ////////////////////////////// + ciSetUserBasicInfo(chat, nick, user, address); + + // Setup the filter matches. + //////////////////////////// + memset(matches, 0, sizeof(matches)); + matches[0].type = TYPE_UMODE; + matches[0].name = nick; + matches[0].name2 = channel; + matches[1].type = TYPE_WHO; + matches[1].name = nick; + matches[2].type = TYPE_CWHO; + matches[2].name = channel; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 3, matches); + if(!filter) + return; + + // User mode filter? + //////////////////// + if(filter->type == TYPE_UMODE) + { + ciCallbackGetUserModeParams params; + int mode; + + // Check the mode. + ////////////////// + mode = 0; + if(strchr(message->params[6], '@')) + mode |= CHAT_OP; + if(strchr(message->params[6], '+')) + mode |= CHAT_VOICE; + + params.success = CHATTrue; + params.channel = channel; + params.user = nick; + params.mode = mode; + + FINISH_FILTER; + + return; + } + + // Who filter? + ////////////// + if(filter->type == TYPE_WHO) + { + ciCallbackGetBasicUserInfoParams params; + + params.success = CHATTrue; + params.nick = nick; + params.user = user; + params.address = address; + + ciAddCallback(chat, CALLBACK_GET_BASIC_USER_INFO, filter->callback, ¶ms, filter->param, filter->ID, NULL); + + // We want to wait until we get the end, but we've already called the callback. + /////////////////////////////////////////////////////////////////////////////// + filter->callback = NULL; + + return; + } + + // Who filter? + ////////////// + if((filter->type == TYPE_CWHO) && filter->callback) + { + ciCallbackGetChannelBasicUserInfoParams params; + + params.success = CHATTrue; + params.channel = filter->name; + params.nick = nick; + params.user = user; + params.address = address; + + ciAddCallback(chat, CALLBACK_GET_CHANNEL_BASIC_USER_INFO, filter->callback, ¶ms, filter->param, filter->ID, NULL); + + return; + } +} + +void ciRplEndOfWhoHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch matches[2]; + ciServerMessageFilter * filter; + char * name; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplEndOfWhoHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + name = message->params[1]; + + // Setup the filter matches. + //////////////////////////// + memset(matches, 0, sizeof(matches)); + matches[0].type = TYPE_WHO; + matches[0].name = name; + matches[1].type = TYPE_CWHO; + matches[1].name = name; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 2, matches); + if(!filter) + return; + + // Who filter? + ////////////// + if(filter->type == TYPE_WHO) + { + ciCallbackGetBasicUserInfoParams params; + + params.success = CHATFalse; + params.nick = name; + params.user = NULL; + params.address = NULL; + + FINISH_FILTER; + + return; + } + + // Channel who filter? + ////////////////////// + if(filter->type == TYPE_CWHO) + { + ciCallbackGetChannelBasicUserInfoParams params; + + params.success = CHATTrue; + params.channel = name; + params.nick = NULL; + params.user = NULL; + params.address = NULL; + + FINISH_FILTER; + + return; + } +} + +static char * ciParseValue(const char * flags, int * len) +{ + int i; + char * str; + + assert(flags); + assert(len); + + // First should be a '\'. + ///////////////////////// + if(!flags || (flags[0] != '\\')) + return NULL; + + // Skip it. + /////////// + flags++; + + // Find the end of the value. + ///////////////////////////// + for(i = 0 ; flags[i] && (flags[i] != '\\') ; i++) { }; + + // Allocate it. + /////////////// + str = (char *)gsimalloc((unsigned int)i + 1); + if(!str) + return NULL; + + // Copy it in. + ////////////// + memcpy(str, flags, (unsigned int)i); + str[i] = '\0'; + + // Return it. + ///////////// + *len = (i + 1); + return str; +} + +void ciRplGetKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + const char * nick; + const char * cookie; + const char * flags; + int num; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplGetKeyHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + nick = message->params[1]; + cookie = message->params[2]; + flags = message->params[3]; + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETKEY; + match.name = cookie; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + GETKEYData * data; + ciCallbackGetGlobalKeysParams params; + char ** values; + char * str; + int i; + int len; + + data = (GETKEYData *)filter->data; + num = data->num; + + // Allocate the values. + /////////////////////// + values = (char **)gsimalloc(sizeof(char *) * num); + if(!values) + return; + + // Parse them out. + ////////////////// + for(i = 0 ; i < num ; i++) + { + str = ciParseValue(flags, &len); + if(str) + { + values[i] = str; + flags += len; + } + else + { + values[i] = goastrdup(""); + } + } + + // Setup the callback parameters. + ///////////////////////////////// + params.success = CHATTrue; + params.user = (char *)nick; + params.num = num; + params.keys = data->keys; + params.values = values; + + // If this is a 1-user get, we're finished. + /////////////////////////////////////////// + if(!data->channel) + { + FINISH_FILTER; + } + else + { + ciAddCallback(chat, CALLBACK_GET_GLOBAL_KEYS, filter->callback, ¶ms, filter->param, filter->ID, NULL); + } + + for(i = 0 ; i < num ; i++) + gsifree(values[i]); + gsifree(values); + } +} + +void ciRplEndGetKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + const char * cookie; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplEndGetKeyHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + cookie = message->params[2]; + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETKEY; + match.name = cookie; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + ciCallbackGetGlobalKeysParams params; + GETKEYData * data; + + data = (GETKEYData *)filter->data; + + // Setup the callback parameters. + ///////////////////////////////// + params.success = CHATTrue; + params.user = NULL; + params.num = data->num; + params.keys = data->keys; + params.values = NULL; + + FINISH_FILTER; + } +} + +void ciRplGetCKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + const char * nick; + const char * cookie; + char * flags; + const char * channel; + int num; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplGetCKeyHandler called\n"); +#endif + + assert(message->numParams == 5); + if(message->numParams != 5) + return; //ERRCON + + channel = message->params[1]; + nick = message->params[2]; + cookie = message->params[3]; + flags = message->params[4]; + + // Check for a broadcast update. + //////////////////////////////// + if(strcmp(cookie, "BCAST") == 0) + { + chatChannelCallbacks * callbacks; + ciCallbackBroadcastKeyChangedParams params; + char * key; + char * value; + int temp; + + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks && callbacks->broadcastKeyChanged) + { + memset(¶ms, 0, sizeof(ciCallbackBroadcastKeyChangedParams)); + params.channel = (char *)channel; + params.user = (char *)nick; + + while(*flags) + { + key = strstr(flags, "b_"); + flags = key; + while(*flags && (*flags != '\\')) + flags++; + if(!*flags) + break; + *flags++ = '\0'; + value = flags; + while(*flags && (*flags != '\\')) + flags++; + temp = *flags; + *flags = '\0'; + + // Call the callback. + ///////////////////// + params.key = key; + params.value = value; + ciAddCallback(chat, CALLBACK_BROADCAST_KEY_CHANGED, (void*)callbacks->broadcastKeyChanged, ¶ms, callbacks->param, 0, channel); + + *flags = (char)temp; + } + } + + return; + } + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETCKEY; + match.name = cookie; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + GETCKEYData * data; + ciCallbackGetChannelKeysParams params; + char ** values; + char * key; + char * value; + int i; + int len; + char ** tempPtr; + + data = (GETCKEYData *)filter->data; + num = data->num; + + // Allocate the values. + /////////////////////// + values = (char **)gsimalloc(sizeof(char *) * num); + if(!values) + return; + + // Parse them out. + ////////////////// + for(i = 0 ; i < num ; i++) + { + value = ciParseValue(flags, &len); + values[i] = value; + if(value) + flags += len; + } + + // Do we need to do b_* stuff? + ////////////////////////////// + if(data->allBroadcastKeys) + { + while((key = ciParseValue(flags, &len)) != NULL) + { + flags += len; + value = ciParseValue(flags, &len); + if(value) + { + flags += len; + + // Add this key and value to our list. + ////////////////////////////////////// + tempPtr = (char **)gsirealloc(data->keys, sizeof(char *) * (num + 1)); + if(tempPtr) + { + data->keys = tempPtr; + tempPtr = (char **)gsirealloc(values, sizeof(char *) * (num + 1)); + if(tempPtr) + { + values = tempPtr; + data->keys[num] = key; + values[num] = value; + num++; + } + else + { + gsifree(key); + gsifree(value); + } + } + else + { + gsifree(key); + gsifree(value); + } + } + else + { + gsifree(key); + break; + } + } + + // The new number of keys. + ////////////////////////// + data->num = num; + } + + // Setup the callback parameters. + ///////////////////////////////// + params.success = CHATTrue; + params.channel = (char *)channel; + params.user = (char *)nick; + params.num = num; + params.keys = data->keys; + params.values = values; + + // If this is a 1-user get, we're finished. + /////////////////////////////////////////// + if(!data->channel) + { + FINISH_FILTER; + } + else + { + ciAddCallback(chat, CALLBACK_GET_CHANNEL_KEYS, filter->callback, ¶ms, filter->param, filter->ID, NULL); + } + + for(i = 0 ; i < num ; i++) + gsifree(values[i]); + gsifree(values); + } +} + +void ciRplEndGetCKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + const char * cookie; + const char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplEndGetCKeyHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + channel = message->params[1]; + cookie = message->params[2]; + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETCKEY; + match.name = cookie; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + GETCKEYData * data; + ciCallbackGetChannelKeysParams params; + + data = (GETCKEYData *)filter->data; + + // Setup the callback parameters. + ///////////////////////////////// + params.success = CHATTrue; + params.channel = (char *)channel; + params.user = NULL; + params.num = data->num; + params.keys = data->keys; + params.values = NULL; + + FINISH_FILTER; + } +} + +void ciRplGetChanKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + const char * cookie; + char * flags; + const char * channel; + int num; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplGetChanKeyHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + channel = message->params[1]; + cookie = message->params[2]; + flags = message->params[3]; + + // Check for a broadcast update. + //////////////////////////////// + if(strcmp(cookie, "BCAST") == 0) + { + chatChannelCallbacks * callbacks; + ciCallbackBroadcastKeyChangedParams params; + char * key; + char * value; + int temp; + + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks && callbacks->broadcastKeyChanged) + { + memset(¶ms, 0, sizeof(ciCallbackBroadcastKeyChangedParams)); + params.channel = (char *)channel; + params.user = NULL; + + while(*flags) + { + key = strstr(flags, "b_"); + flags = key; + while(*flags && (*flags != '\\')) + flags++; + if(!*flags) + break; + *flags++ = '\0'; + value = flags; + while(*flags && (*flags != '\\')) + flags++; + temp = *flags; + *flags = '\0'; + + // Call the callback. + ///////////////////// + params.key = key; + params.value = value; + ciAddCallback(chat, CALLBACK_BROADCAST_KEY_CHANGED, (void*)callbacks->broadcastKeyChanged, ¶ms, callbacks->param, 0, channel); + + *flags = (char)temp; + } + } + + return; + } + + // Setup the filter match. + ////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETCHANKEY; + match.name = cookie; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + GETCHANKEYData * data; + ciCallbackGetChannelKeysParams params; + char ** values; + char ** keys = NULL; + char * key; + char * value; + int i; + int len; + char ** tempPtr; + + data = (GETCHANKEYData *)filter->data; + num = data->num; + + // Allocate the values. + /////////////////////// + if(num) + { + values = (char **)gsimalloc(sizeof(char *) * num); + if(!values) + return; + + // Parse them out. + ////////////////// + for(i = 0 ; i < num ; i++) + { + value = ciParseValue(flags, &len); + values[i] = value; + if(value) + flags += len; + } + + // Do we need to do b_* stuff? + ////////////////////////////// + if(data->allBroadcastKeys) + { + while((key = ciParseValue(flags, &len)) != NULL) + { + flags += len; + value = ciParseValue(flags, &len); + if(value) + { + flags += len; + + // Add this key and value to our list. + ////////////////////////////////////// + tempPtr = (char **)gsirealloc(data->keys, sizeof(char *) * (num + 1)); + if(tempPtr) + { + data->keys = tempPtr; + tempPtr = (char **)gsirealloc(values, sizeof(char *) * (num + 1)); + if(tempPtr) + { + values = tempPtr; + data->keys[num] = key; + values[num] = value; + num++; + } + else + { + gsifree(key); + gsifree(value); + } + } + else + { + gsifree(key); + gsifree(value); + } + } + else + { + gsifree(key); + break; + } + } + + // The new number of keys. + ////////////////////////// + data->num = num; + } + } + else + { + char ** keysTemp; + char ** valuesTemp; + + keys = NULL; + values = NULL; + num = 0; + while(1) + { + key = ciParseValue(flags, &len); + if(!key) + break; + flags += len; + value = ciParseValue(flags, &len); + if(!value) + { + gsifree(key); + break; + } + flags += len; + + keysTemp = (char **)gsirealloc(keys, sizeof(char *) * (num + 1)); + valuesTemp = (char **)gsirealloc(values, sizeof(char *) * (num + 1)); + if(!keysTemp || !valuesTemp) + { + gsifree(key); + gsifree(value); + while(num--) + { + gsifree(keys[num]); + gsifree(values[num]); + } + if(keysTemp) + gsifree(keysTemp); + else + gsifree(keys); + if(valuesTemp) + gsifree(valuesTemp); + else + gsifree(values); + } + + keys = keysTemp; + keys[num] = key; + values = valuesTemp; + values[num] = value; + + num++; + } + + data->num = num; + data->keys = keys; + } + + // Setup the callback parameters. + ///////////////////////////////// + params.success = CHATTrue; + params.channel = (char *)channel; + params.user = NULL; + params.num = num; + params.keys = data->keys; + params.values = values; + + FINISH_FILTER; + + for(i = 0 ; i < num ; i++) + gsifree(values[i]); + gsifree(values); + } +} + +void ciRplUserIPHandler(CHAT chat, const ciServerMessage * message) +{ + char * IP; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplUserIPHandler called\n"); +#endif + + assert(message->numParams >= 1); + if(message->numParams < 1) + return; //ERRCON + + IP = strchr(message->params[message->numParams - 1], '@'); + if(IP) + { + IP++; + + if(connection->fillInUserCallback) + { +#ifndef GSI_UNICODE + char user[MAX_USER]; + connection->fillInUserCallback(chat, inet_addr(IP), user, connection->connectParam); + strzcpy(connection->user, user, MAX_USER); +#else + unsigned short user[MAX_USER]; + connection->fillInUserCallback(chat, inet_addr(IP), user, connection->connectParam); + wcszcpy(connection->userW, user, MAX_USER); // copy the unicode version + UCS2ToAsciiString(user, connection->user); // convert the unicode user to ascii (nicknames cannot currently be UTF-8!!) +#endif + } + } + + // Send the nick and user. + ////////////////////////// + ciSendNickAndUser(chat); +} + +void ciRplListStartHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplListStartHandler called\n"); +#endif + + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_LIST; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + LISTData * data = (LISTData *)filter->data; + assert(data != NULL); + //assert(!data->gotStart); + + data->gotStart = CHATTrue; + } + + GSI_UNUSED(message); +} + +void ciRplListHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplListHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_LIST; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + if(filter->callback != NULL) + { + ciCallbackEnumChannelsEachParams params; + int index; + char * channel; + int numUsers; + char * topic; + int len; + void * tempPtr; + LISTData * data = (LISTData *)filter->data; + + assert(data != NULL); + //assert(data->gotStart); + + // Get the channel. + /////////////////// + len = (int)(strlen(message->params[1]) + 1); + channel = (char *)gsimalloc((unsigned int)len); + if(channel == NULL) + return; //ERRCON + memcpy(channel, message->params[1], (unsigned int)len); + + // Get the num users. + ///////////////////// + numUsers = atoi(message->params[2]); + + // Get the topic. + ///////////////// + len = (int)(strlen(message->params[3]) + 1); + topic = (char *)gsimalloc((unsigned int)len); + if(topic == NULL) + { + gsifree(channel); + return; //ERRCON + } + memcpy(topic, message->params[3], (unsigned int)len); + + // Get the index. + ///////////////// + index = data->numChannels; + + // Add the callback. + //////////////////// + params.success = CHATTrue; + params.index = index; + params.channel = channel; + params.topic = topic; + params.numUsers = numUsers; + ciAddCallback(chat, CALLBACK_ENUM_CHANNELS_EACH, filter->callback, ¶ms, filter->param, filter->ID, NULL); + + //TODO:only store this stuff if there's an "all" callback + + // Add the channel. + /////////////////// + tempPtr = gsirealloc(data->channels, sizeof(char *) * (data->numChannels + 1)); + if(tempPtr == NULL) + { + gsifree(channel); + gsifree(topic); + return; //ERRCON + } + data->channels = (char **)tempPtr; + data->channels[index] = channel; + + // Add the numUsers. + //////////////////// + tempPtr = gsirealloc(data->numUsers, sizeof(int) * (data->numChannels + 1)); + if(tempPtr == NULL) + { + gsifree(channel); + gsifree(topic); + return; //ERRCON + } + data->numUsers = (int *)tempPtr; + data->numUsers[index] = numUsers; + + // Add the topic. + ///////////////// + tempPtr = gsirealloc(data->topics, sizeof(char *) * (data->numChannels + 1)); + if(tempPtr == NULL) + { + gsifree(channel); + gsifree(topic); + return; //ERRCON + } + data->topics = (char **)tempPtr; + data->topics[index] = topic; + + // One more channel. + //////////////////// + data->numChannels++; + } + } +} + +void ciRplListEndHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplListEndHandler called\n"); +#endif + + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_LIST; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + LISTData * data = (LISTData *)filter->data; + ciCallbackEnumChannelsAllParams params; + params.success = CHATTrue; + params.numChannels = data->numChannels; + params.channels = data->channels; + params.numUsers = data->numUsers; + params.topics = data->topics; + + FINISH_FILTER; + } + + GSI_UNUSED(message); +} + +void ciRplChannelModeIsHandler(CHAT chat, const ciServerMessage * message) +{ + char * channel; + char * modes; + ciModeChange * changes; + CHATChannelMode mode; + CHATChannelMode dummyMode; + ciServerMessageFilter * filter; + ciFilterMatch match; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplChannelModeIs called\n"); +#endif + + assert(message->numParams >=3); + if(message->numParams < 3) + return; //ERRCON + + channel = message->params[1]; + modes = message->params[2]; + + // Parse the mode. + ////////////////// + changes = ciParseMode(modes, message->params + 3, message->numParams - 3); + if(changes == NULL) + return; //ERRCON + + // Fill the mode struct. + //////////////////////// + memset(&mode, 0, sizeof(CHATChannelMode)); + ciApplyChangesToMode(&mode, changes); + + // Check if we have this channel's mode. + //////////////////////////////////////// + if(!ciGetChannelMode(chat, channel, &dummyMode)) + { + chatChannelCallbacks * callbacks; + + // Set the mode. + //////////////// + ciSetChannelMode(chat, channel, &mode); + + // Mode changed callback? + ///////////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if((callbacks != NULL) && (callbacks->channelModeChanged != NULL)) + { + ciCallbackChannelModeChangedParams params; + params.channel = channel; + params.mode = &mode; + ciAddCallback(chat, CALLBACK_CHANNEL_MODE_CHANGED, (void*)callbacks->channelModeChanged, ¶ms, callbacks->param, 0, channel); + } + } + + // Were we waiting for this? + //////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_CMODE; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackGetChannelModeParams params; + params.success = CHATTrue; + params.channel = channel; + params.mode = &mode; + + FINISH_FILTER; + } + + // gsifree the changes. + //////////////////// + gsifree(changes); +} + +void ciRplWhoisUserHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + ciFilterMatch matches[2]; + ciServerMessageFilter * filter; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplWhoisUserHandler called\n"); +#endif + + assert(message->numParams == 6); + if(message->numParams != 6) + return; //ERRCON + + // Get the nick. + //////////////// + nick = message->params[1]; + + // Setup the filter matches. + //////////////////////////// + memset(matches, 0, sizeof(matches)); + matches[0].type = TYPE_WHOIS; + matches[0].name = nick; + matches[1].type = TYPE_BAN; + matches[1].name = nick; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 2, matches); + if(!filter) + return; + + // Whois? + ///////// + if(filter->type == TYPE_WHOIS) + { + char * user; + char * name; + char * address; + + WHOISData * data = (WHOISData *)filter->data; + + // Cache the name and address pointers. + /////////////////////////////////////// + user = message->params[2]; + name = message->params[5]; + address = message->params[3]; + + // Copy the user. + ///////////////// + data->user = goastrdup(user); + if(data->user == NULL) + return; //ERRCON + + // Copy the name. + ///////////////// + data->name = goastrdup(name); + if(data->name == NULL) + return; //ERRCON + + // Copy the address. + //////////////////// + data->address = goastrdup(address); + if(data->address == NULL) + return; //ERRCON + + return; + } + + // Ban? + /////// + if(filter->type == TYPE_BAN) + { + char * host; + + BANData * data = (BANData *)filter->data; + assert(data != NULL); + ASSERT_STR(data->channel); + + host = message->params[3]; + + // Ban this guy. + //////////////// + ciSocketSendf(&connection->chatSocket, "MODE %s +b *!*@%s", data->channel, host); + + ciFinishFilter(chat, filter, NULL); + } +} + +void ciRplWhoisChannelsHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + ciServerMessageFilter * filter; + ciFilterMatch match; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplWhoisChannelsHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the nick. + //////////////// + nick = message->params[1]; + + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_WHOIS; + match.name = nick; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + char * channels; + char * str; + char * channel; + char ** tempPtr; + WHOISData * data = (WHOISData *)filter->data; + + channels = message->params[2]; + str = strtok(channels, " "); + while(str != NULL) + { + // Check for deaf mode. + /////////////////////// + if(str[0] == '-') + str++; + + // Check for op or voice. + ///////////////////////// + if((str[0] == '@') || (str[0] == '+')) + str++; + + // Add it to the list. + ////////////////////// + channel = goastrdup(str); + if(channel == NULL) + return; //ERRCON + tempPtr = (char **)gsirealloc(data->channels, sizeof(char *) * (data->numChannels + 1)); + if(tempPtr == NULL) + { + gsifree(channel); + return; //ERRCON + } + data->channels = tempPtr; + data->channels[data->numChannels] = channel; + data->numChannels++; + + // Get the next channel. + //////////////////////// + str = strtok(NULL, " "); + } + } +} + +void ciRplEndOfWhoisHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + ciServerMessageFilter * filter; + ciFilterMatch match; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplEndOfWhoisHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the nick. + //////////////// + nick = message->params[1]; + + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_WHOIS; + match.name = nick; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + WHOISData * data = (WHOISData *)filter->data; + ciCallbackGetUserInfoParams params; + params.success = (CHATBool)(data->user != NULL); //PANTS|08.21.00 - false if nothing found + params.nick = nick; + params.user = data->user; + params.name = data->name; + params.address = data->address; + params.numChannels = data->numChannels; + params.channels = data->channels; + + FINISH_FILTER; + } +} + +void ciRplBanListHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + char * ban; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplBanListHandler called\n"); +#endif + + assert(message->numParams >= 3); + if(message->numParams < 3) + return; //ERRCON + + channel = message->params[1]; + ban = message->params[2]; + + // Look for a filter. + ///////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETBAN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + int len; + void * tempPtr; + GETBANData * data = (GETBANData *)filter->data; + assert(data != NULL); + assert(data->numBans >= 0); + + // Increase the ban list. + ///////////////////////// + tempPtr = gsirealloc(data->bans, sizeof(char *) * (data->numBans + 1)); + if(tempPtr == NULL) + return; //ERRCON + data->bans = (char **)tempPtr; + + // Add the new ban. + /////////////////// + len = (int)(strlen(ban) + 1); + tempPtr = gsimalloc((unsigned int)len); + if(tempPtr == NULL) + return; //ERRCON + memcpy(tempPtr, ban, (unsigned int)len); + data->bans[data->numBans] = (char *)tempPtr; + data->numBans++; + } +} + +void ciRplEndOfBanListHandler(CHAT chat, const ciServerMessage * message) +{ + char * channel; + ciServerMessageFilter * filter; + ciFilterMatch match; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplEndOfBanListHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + channel = message->params[1]; + + // Look for a filter. + ///////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETBAN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + GETBANData * data = (GETBANData *)filter->data; + ciCallbackEnumChannelBansParams params; + params.success = CHATTrue; + params.channel = channel; + params.numBans = data->numBans; + params.bans = data->bans; + + FINISH_FILTER; + } +} + +void ciRplWelcomeHandler(CHAT chat, const ciServerMessage * message) +{ + char * nick; + + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplWelcomeHandler called\n"); +#endif + + assert(message->numParams == 2); + if(message->numParams != 2) + return; + + nick = message->params[0]; + + // Is the nick different? + ///////////////////////// + if(strcmp(connection->nick, nick) != 0) + { + strzcpy(connection->nick, nick, MAX_NICK); +#ifdef GSI_UNICODE + // store a unicode version + AsciiToUCS2String(connection->nick, connection->nickW); +#endif + } + + // Connected. + ///////////// + connection->connecting = CHATFalse; + connection->connected = CHATTrue; + + // Call the callback. + ///////////////////// + if(connection->connectCallback != NULL) + connection->connectCallback(chat, CHATTrue, 0, connection->connectParam); +} + +void ciRplSecureKeyHandler(CHAT chat, const ciServerMessage * message) +{ + char * outKeyRand; + char * inKeyRand; + int outKeyLen; + int inKeyLen; + + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplSecureKeyHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; + + outKeyRand = message->params[1]; + inKeyRand = message->params[2]; + + // Take the random keys and the secret key to create the encoding/decoding keys. + //////////////////////////////////////////////////////////////////////////////// + outKeyLen = (int)strlen(outKeyRand); + inKeyLen = (int)strlen(inKeyRand); + gs_xcode_buf(outKeyRand, outKeyLen, connection->secretKey); + gs_xcode_buf(inKeyRand, inKeyLen, connection->secretKey); + gs_prepare_key((unsigned char *)outKeyRand, outKeyLen, &connection->chatSocket.outKey); + gs_prepare_key((unsigned char *)inKeyRand, inKeyLen, &connection->chatSocket.inKey); + + // We now have a secure socket. + /////////////////////////////// + connection->chatSocket.secure = CHATTrue; + + // Login if we need to. + /////////////////////// + if(connection->loginType != CINoLogin) + { + ciSendLogin(chat); + } + // Get the IP if we need to. + //////////////////////////// + else if(connection->fillInUserCallback) + { + ciSocketSend(&connection->chatSocket, "USRIP"); + } + // Otherwise send the nick and user. + //////////////////////////////////// + else + { + ciSendNickAndUser(chat); + } +} + +void ciRplCDKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + int result; + char * msg; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplCDKeyHandler called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; + + result = atoi(message->params[1]); + msg = message->params[2]; + + // Setup a filter match. + //////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_CDKEY; + + // Find the filter. + /////////////////// + filter = ciFindFilter(chat, 1, &match); + if(filter) + { + ciCallbackAuthenticateCDKeyParams params; + params.result = result; + params.message = msg; + + FINISH_FILTER; + } +} + +void ciRplLoginHandler(CHAT chat, const ciServerMessage * message) +{ + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplLoginHandler called\n"); +#endif + + assert(message->numParams >= 3); + if(message->numParams < 3) + return; + + // Store the ids. + ///////////////// + connection->userID = atoi(message->params[1]); + connection->profileID = atoi(message->params[2]); + + // Get the IP if we need to. + //////////////////////////// + if(connection->fillInUserCallback) + { + ciSocketSend(&connection->chatSocket, "USRIP"); + } + // Otherwise send the nick and user. + //////////////////////////////////// + else + { + ciSendNickAndUser(chat); + } +} + +void ciRplGetUdpRelayHandler(CHAT chat, const ciServerMessage * message) +{ + char *channel; + int udpKey; + char *udpIp; + unsigned short udpPort; + ciServerMessageFilter * filter; + ciFilterMatch match; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciRplGetUdpRelayHandler called\n"); +#endif + assert(message->numParams >= 5); + if(message->numParams < 5) + return; + + channel = message->params[1]; + udpKey = atoi(message->params[2]); + udpIp = message->params[3]; + udpPort = (unsigned short)atoi(message->params[4]); + + // Were we waiting for this? + //////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_GETUDPRELAY; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackGetUdpRelayParams params; + params.channel = channel; + params.udpIp = udpIp; + params.udpPort = udpPort; + params.udpKey = udpKey; + FINISH_FILTER; + } + + +} + +void ciErrNoSuchChannelHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch matches[2]; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrNoSuchChannel called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Setup the filter matches. + //////////////////////////// + memset(&matches, 0, sizeof(ciFilterMatch)); + matches[0].type = TYPE_JOIN; + matches[0].name = channel; + matches[1].type = TYPE_CMODE; + matches[1].name = channel; + + // Look for a matching filter. + ////////////////////////////// + filter = ciFindFilter(chat, 2, matches); + if(filter) + { + // Join? + //////// + if(filter->type == TYPE_JOIN) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATBadChannelName; + params.channel = channel; + + FINISH_FILTER; + + return; + } + + // Channel mode? + //////////////// + if(filter->type == TYPE_CMODE) + { + ciCallbackGetChannelModeParams params; + params.success = CHATFalse; + params.channel = channel; + params.mode = NULL; + + FINISH_FILTER; + + return; + } + } + + // GetKey? + ////////// + filter = ciFindGetKeyFilter(chat, channel); + if(filter) + { + ciCallbackGetGlobalKeysParams params; + params.success = CHATFalse; + params.user = NULL; + params.num = 0; + params.keys = NULL; + params.values = NULL; + + FINISH_FILTER; + + return; + } +} + +void ciErrTooManyChannelsHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrTooManyChannels called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Look for a matching filter. + ////////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATTooManyChannels; + params.channel = channel; + + FINISH_FILTER; + } +} + +void ciErrChannelIsFullHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrChannelIsFull called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Look for a matching filter. + ////////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATChannelIsFull; + params.channel = channel; + + FINISH_FILTER; + } +} + +void ciErrInviteOnlyChanHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrInviteOnlyChan called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Look for a matching filter. + ////////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATInviteOnlyChannel; + params.channel = channel; + + FINISH_FILTER; + } +} + +void ciErrBannedFromChanHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrBannedFromChan called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Look for a matching filter. + ////////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATBannedFromChannel; + params.channel = channel; + + FINISH_FILTER; + } +} + +void ciErrBadChannelKeyHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrBadChannelKey called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Look for a matching filter. + ////////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATBadChannelPassword; + params.channel = channel; + + FINISH_FILTER; + } +} + +void ciErrBadChanMaskHandler(CHAT chat, const ciServerMessage * message) +{ + ciFilterMatch match; + ciServerMessageFilter * filter; + char * channel; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrBadChanMask called\n"); +#endif + + assert(message->numParams == 3); + if(message->numParams != 3) + return; //ERRCON + + // Get the channel. + /////////////////// + channel = message->params[1]; + + // Look for a matching filter. + ////////////////////////////// + memset(&match, 0, sizeof(ciFilterMatch)); + match.type = TYPE_JOIN; + match.name = channel; + filter = ciFindFilter(chat, 1, &match); + if(filter != NULL) + { + ciCallbackEnterChannelParams params; + params.success = CHATFalse; + params.result = CHATBadChannelMask; + params.channel = channel; + + FINISH_FILTER; + } +} + +void ciErrNoSuchNickHandler(CHAT chat, const ciServerMessage * message) +{ +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrNoSuchNickHandler called\n"); +#endif + + GSI_UNUSED(chat); + GSI_UNUSED(message); +} + +void ciErrErroneusNicknameHandler(CHAT chat, const ciServerMessage * message) +{ + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrErroneusNicknameHandler called\n"); +#endif + + // Are we connecting? + ///////////////////// + if(connection->connecting) + ciNickError(chat, CHAT_INVALID, connection->nick, 0, NULL); + + GSI_UNUSED(message); +} + +void ciErrLoginFailedHandler(CHAT chat, const ciServerMessage * message) +{ + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrLoginFailedHandler called\n"); +#endif + + // Are we connecting? + ///////////////////// + if(connection->connecting) + { + // No longer connecting. + //////////////////////// + connection->connecting = CHATFalse; + + // Call the connect failed callback. + //////////////////////////////////// + if(connection->connectCallback != NULL) + connection->connectCallback(chat, CHATFalse, CHAT_LOGIN_FAILED, connection->connectParam); + } + + GSI_UNUSED(message); +} + +void ciErrNoUniqueNickHandler(CHAT chat, const ciServerMessage * message) +{ + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrNoUniqueNickHandler called\n"); +#endif + + // Are we connecting? + ///////////////////// + if(connection->connecting) + ciNickError(chat, CHAT_NO_UNIQUENICK, "", 0, NULL); + + GSI_UNUSED(message); +} + +void ciErrUniqueNickExpiredHandler(CHAT chat, const ciServerMessage * message) +{ + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrUniqueNickExpiredHandler called\n"); +#endif + + // Are we connecting? + ///////////////////// + if(connection->connecting) + ciNickError(chat, CHAT_UNIQUENICK_EXPIRED, "", 0, NULL); + + GSI_UNUSED(message); +} + +void ciErrRegisterNickFailedHandler(CHAT chat, const ciServerMessage * message) +{ + int num; + char * nicks; + char * nick; + char ** nickArray; + int i; + CONNECTION; + +#ifdef FEEDBACK_HANDLERS + OutputDebugString("ciErrRegisterNickFailedHandler called\n"); +#endif + + assert(message->numParams == 4); + if(message->numParams != 4) + return; //ERRCON + + // Get the params we need. + ////////////////////////// + num = atoi(message->params[1]); + nicks = message->params[2]; + + // Are we connecting? + ///////////////////// + if(!connection->connecting) + return; + + // Allocate space for the nicks. + //////////////////////////////// + nickArray = (char **)gsimalloc(sizeof(char *) * num); + if(!nickArray) + return; + + // Parse out the suggested nicks. + ///////////////////////////////// + nick = strtok(nicks, "\\"); + for(i = 0 ; (i < num) && nick ; i++) + { + nickArray[i] = goastrdup(nick); + if(!nickArray[i]) + break; + + nick = strtok(NULL, "\\"); + } + + // Make sure our num is correct. + //////////////////////////////// + num = i; + + // Call the nick error callback. + //////////////////////////////// + ciNickError(chat, CHAT_INVALID_UNIQUENICK, connection->uniquenick, num, nickArray); + + // Free the memory. + /////////////////// + for(i = 0 ; i < num ; i++) + gsifree(nickArray[i]); + gsifree(nickArray); +} diff --git a/xrGameSpy/gamespy/Chat/chatHandlers.h b/xrGameSpy/gamespy/Chat/chatHandlers.h new file mode 100644 index 00000000000..af37c718cf0 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatHandlers.h @@ -0,0 +1,82 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHATHANDLERS_H_ +#define _CHATHANDLERS_H_ + +/************* +** INCLUDES ** +*************/ +#include "chat.h" +#include "chatSocket.h" + + +/********** +** TYPES ** +**********/ +typedef struct ciServerMessageType +{ + char * command; + void (* handler)(CHAT chat, const ciServerMessage * message); +} ciServerMessageType; + +typedef char ** ciCommands; +typedef struct ciServerMessageFilter +{ + int type; + gsi_time timeout; + + char * name; + char * name2; + + void * callback; + void * callback2; + void * param; + + void * data; + + int ID; + + struct ciServerMessageFilter * pnext; +} ciServerMessageFilter; + +/************ +** GLOBALS ** +************/ +extern ciServerMessageType serverMessageTypes[]; +extern int numServerMessageTypes; + +/************** +** FUNCTIONS ** +**************/ +void ciFilterThink(CHAT chat); +void ciCleanupFilters(CHAT chat); +int ciAddLISTFilter(CHAT chat, chatEnumChannelsCallbackEach callbackEach, chatEnumChannelsCallbackAll callbackAll, void * param); +int ciAddJOINFilter(CHAT chat, const char * channel, chatEnterChannelCallback callback, void * param, chatChannelCallbacks * callbacks, const char * password); +int ciAddTOPICFilter(CHAT chat, const char * channel, chatGetChannelTopicCallback callback, void * param); +int ciAddNAMESFilter(CHAT chat, const char * channel, chatEnumUsersCallback callback, void * param); +int ciAddWHOISFilter(CHAT chat, const char * user, chatGetUserInfoCallback callback, void * param); +int ciAddWHOFilter(CHAT chat, const char * user, chatGetBasicUserInfoCallback callback, void * param); +int ciAddCWHOFilter(CHAT chat, const char * channel, chatGetChannelBasicUserInfoCallback callback, void * param); +int ciAddCMODEFilter(CHAT chat, const char * channel, chatGetChannelModeCallback callback, void * param); +int ciAddUMODEFilter(CHAT chat, const char * user, const char * channel, chatGetUserModeCallback callback, void * param); +int ciAddBANFilter(CHAT chat, const char * user, const char * channel); +int ciAddGETBANFilter(CHAT chat, const char * channel, chatEnumChannelBansCallback callback, void * param); +int ciAddNICKFilter(CHAT chat, const char * oldNick, const char * newNick, chatChangeNickCallback callback, void * param); +int ciAddUNQUIETFilter(CHAT chat, const char * channel); +int ciAddGETKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, const char * channel, chatGetGlobalKeysCallback callback, void * param); +int ciAddGETCKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, CHATBool channel, CHATBool getBroadcastKeys, chatGetChannelKeysCallback callback, void * param); +int ciAddGETCHANKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, CHATBool getBroadcastKeys, chatGetChannelKeysCallback callback, void * param); +int ciAddCDKEYFilter(CHAT chat, chatAuthenticateCDKeyCallback callback, void * param); +int ciAddGETUDPRELAYFilter(CHAT chat, const char * channel, chatGetUdpRelayCallback callback, void * param); +int ciGetNextID(CHAT chat); +CHATBool ciCheckFiltersForID(CHAT chat, int ID); + +#endif diff --git a/xrGameSpy/gamespy/Chat/chatMain.c b/xrGameSpy/gamespy/Chat/chatMain.c new file mode 100644 index 00000000000..64c42a3265e --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatMain.c @@ -0,0 +1,3075 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include "chat.h" +#include "chatMain.h" +#include "chatASCII.h" +#include "chatSocket.h" +#include "chatHandlers.h" +#include "chatChannel.h" +#include "chatCallbacks.h" + + +#if defined(_WIN32) +// Silence the warning about explicitly casting a function* to a void* +#pragma warning(disable:4054) +#endif + +/************ +** GLOBALS ** +************/ +// This can be overridden using an extern to pass a different versionID number to the chat server as part of the crypt negotiation +int ciVersionID = 1; + +/************ +** DEFINES ** +************/ +#define CI_DO_BLOCKING if(blocking)\ + {\ + do{\ + ciThink(chat, ID);\ + msleep(10);\ + }while(ciCheckForID(chat, ID));\ + } + +#define ASSERT_CHANNEL() assert(channel != NULL); assert(channel[0] != '\0'); +#define ASSERT_NICK() assert(nick != NULL); assert(nick[0] != '\0'); assert(strlen(nick) < MAX_NICK); +#define ASSERT_USER(user) assert(user != NULL); assert(user[0] != '\0'); assert(strlen(user) < MAX_USER); +#define ASSERT_MESSAGE() assert(message != NULL); assert(message[0] != '\0'); +#define ASSERT_TYPE(type) assert((type == CHAT_MESSAGE) || (type == CHAT_ACTION) || (type == CHAT_NOTICE) || (type == CHAT_UTM) || (type == CHAT_ATM)); +#define ASSERT_PASSWORD() assert(password != NULL); assert(password[0] != '\0'); +#define ASSERT_BAN() assert(ban != NULL); assert(ban [0] != '\0'); + +#define CI_NUM_TRANSLATED_NICKS 2 + +/********** +** TYPES ** +**********/ + +typedef struct ciEnumUsersData +{ + chatEnumUsersCallback callback; + void * param; +} ciEnumUsersData; + +/************** +** FUNCTIONS ** +**************/ +static CHATBool ciProcessServerMessage(CHAT chat, const ciServerMessage * message) +{ + int i; + + assert(message != NULL); + + // Figure out what type of message this is. + /////////////////////////////////////////// + for(i = 0 ; i < numServerMessageTypes ; i++) + { + // Does the type match? + /////////////////////// + if(strcasecmp(message->command, serverMessageTypes[i].command) == 0) + { + // Is there a handler? + ////////////////////// + if(serverMessageTypes[i].handler != NULL) + { + // Call the handler. + //////////////////// + serverMessageTypes[i].handler(chat, message); + } + + return CHATTrue; + } + } + + // Didn't find a match. + /////////////////////// + return CHATFalse; //ERRCON +} + +static CHATBool ciCheckForID(CHAT chat, int ID) +{ + return (CHATBool)(ciCheckFiltersForID(chat, ID) || ciCheckCallbacksForID(chat, ID)); +} + +void ciHandleDisconnect(CHAT chat, const char * reason) +{ + CHATBool connecting; + CONNECTION; + + // Check if we've already handled this. + /////////////////////////////////////// + if(connection->disconnected) + return; + + // Keep track of if we are trying to connect. + ///////////////////////////////////////////// + connecting = connection->connecting; + + // Not connected anymore. + ///////////////////////// + connection->connected = CHATFalse; + connection->connecting = CHATFalse; + connection->disconnected = CHATTrue; + + // If we're still connecting, let the app know the attempt failed. + ////////////////////////////////////////////////////////////////// + if(connection->connecting) + { + // Call the callback. + ///////////////////// + if(connection->connectCallback != NULL) + connection->connectCallback(chat, CHATFalse, CHAT_DISCONNECTED, connection->connectParam); + } + // Otherwise call the global callback. + ////////////////////////////////////// + else if(connection->globalCallbacks.disconnected != NULL) + { + ciCallbackDisconnectedParams params; + params.reason = (char *)reason; + ciAddCallback(chat, CALLBACK_DISCONNECTED, (void*)connection->globalCallbacks.disconnected, ¶ms, connection->globalCallbacks.param, 0, NULL); + } + GSI_UNUSED(connecting); +} + +static void ciThink(CHAT chat, int ID) +{ + ciServerMessage * message; + CONNECTION; + + // Is the socket connected? + /////////////////////////// + if(connection->chatSocket.connectState == ciConnected) + { + // Do processing. + ///////////////// + ciSocketThink(&connection->chatSocket); + + // Check received messages. + /////////////////////////// + while((message = ciSocketRecv(&connection->chatSocket)) != NULL) + { + // Call the raw callback. + ///////////////////////// + if(connection->globalCallbacks.raw != NULL) + { + ciCallbackRawParams params; + params.raw = message->message; + ciAddCallback(chat, CALLBACK_RAW, (void*)connection->globalCallbacks.raw, ¶ms, connection->globalCallbacks.param, 0, NULL); + } + + // Process the message. + /////////////////////// + ciProcessServerMessage(chat, message); + } + + // Have we lost connection? + /////////////////////////// + if(connection->chatSocket.connectState == ciDisconnected) + { + ciHandleDisconnect(chat, "Disconnected"); + } + } + + // Let the filters think. + ///////////////////////// + ciFilterThink(chat); + + // Call callbacks. + ////////////////// + ciCallCallbacks(chat, ID); + +} + +/************ +** GENERAL ** +************/ +void ciSendNick(CHAT chat) +{ + const char * nick; + CONNECTION; + + // Handle based on login type. + ////////////////////////////// + if(connection->loginType == CINoLogin) + { + + // 10-13-2004: changed by Saad Nader + // check for nick length and for an invalid nick. + ///////////////////////////////////////////////// + + int validateNick = ciNickIsValid(connection->nick); + if (validateNick != CHAT_NICK_OK) + { + ciNickError(chat, validateNick, connection->nick, 0, NULL); + return; + } + + // Use the provided nick. + ///////////////////////// + nick = connection->nick; + } + else if((connection->loginType == CIProfileLogin) && (connection->namespaceID == 0)) + { + + // 10-13-2004: changed by Saad Nader + // check for nick length and for an invalid nick. + ///////////////////////////////////////////////// + + int validateNick = ciNickIsValid(connection->profilenick); + if (validateNick != CHAT_NICK_OK) + { + ciNickError(chat, validateNick, connection->profilenick, 0, NULL); + return; + } + + // Use the profile's nick. + ////////////////////////// + nick = connection->profilenick; + } + else + { + // The server will use the uniquenick. + ////////////////////////////////////// + nick = "*"; + } + + // Send the nick. + ///////////////// + ciSocketSendf(&connection->chatSocket, "NICK %s", nick); +} + +void ciSendUser(CHAT chat) +{ + CONNECTION; + + // Send the user. + ///////////////// + ciSocketSendf(&connection->chatSocket, "USER %s %s %s :%s", + connection->user, + "127.0.0.1", + connection->server, + connection->name); +} + +void ciSendNickAndUser(CHAT chat) +{ + ciSendUser(chat); + ciSendNick(chat); +} + +void ciSendLogin(CHAT chat) +{ + char passwordHash[33]; + CONNECTION; + + // If it's pre-auth, send it. + ///////////////////////////// + if(connection->loginType == CIPreAuthLogin) + { + ciSocketSendf(&connection->chatSocket, "LOGINPREAUTH %s %s", + connection->authtoken, + connection->partnerchallenge); + + return; + } + + // For uniquenick or profile logins, we need to MD5 the password. + ///////////////////////////////////////////////////////////////// + MD5Digest((unsigned char *)connection->password, strlen(connection->password), passwordHash); + + // Send the login message based on type. + //////////////////////////////////////// + if(connection->loginType == CIUniqueNickLogin) + { + ciSocketSendf(&connection->chatSocket, "LOGIN %d %s %s", + connection->namespaceID, + connection->uniquenick, + passwordHash); + } + else if(connection->loginType == CIProfileLogin) + { + ciSocketSendf(&connection->chatSocket, "LOGIN %d * %s :%s@%s", + connection->namespaceID, + passwordHash, + connection->profilenick, + connection->email); + } + else + { + // If we get here, the login type is invalid or isn't being handled properly. + ///////////////////////////////////////////////////////////////////////////// + assert(0); + } +} + +static CHAT chatConnectDoit(CILoginType loginType, + const char * serverAddress, + int port, + const char * nick, + const char * user, + const char * name, + int namespaceID, + const char * email, + const char * profilenick, + const char * uniquenick, + const char * password, + const char * authtoken, + const char * partnerchallenge, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + ciConnection * connection; + const char * socketNick = ""; + + //Added default server address and port + //assert(serverAddress != NULL); + assert(callbacks != NULL); + assert(connectCallback != NULL); + + // Check the arguments based on the login type. + /////////////////////////////////////////////// + if(loginType == CINoLogin) + { + ASSERT_NICK(); + if(!nick || !nick[0]) + return NULL; + socketNick = nick; + } + else if(loginType == CIUniqueNickLogin) + { + assert(namespaceID > 0); + if(namespaceID <= 0) + return NULL; + assert(uniquenick && uniquenick[0]); + if(!uniquenick || !uniquenick[0]) + return NULL; + assert(password && password[0]); + if(!password || !password[0]) + return NULL; + socketNick = uniquenick; + } + else if(loginType == CIProfileLogin) + { + assert(namespaceID >= 0); + if(namespaceID < 0) + return NULL; + assert(email && email[0]); + if(!email || !email[0]) + return NULL; + assert(profilenick && profilenick[0]); + if(!profilenick || !profilenick[0]) + return NULL; + assert(password && password[0]); + if(!password || !password[0]) + return NULL; + socketNick = profilenick; + } + else if(loginType == CIPreAuthLogin) + { + assert(authtoken && authtoken[0]); + if(!authtoken || !authtoken[0]) + return NULL; + assert(partnerchallenge && partnerchallenge[0]); + if(!partnerchallenge || !partnerchallenge[0]) + return NULL; + socketNick = "preauth"; + } + if(loginType != CINoLogin) + { + assert(gamename && gamename[0]); + if(!gamename || !gamename[0]) + return NULL; + assert(secretKey && secretKey[0]); + if(!secretKey || !secretKey[0]) + return NULL; + } + + // Init sockets. + //////////////// + SocketStartUp(); + + // Create a connection object. + ////////////////////////////// + connection = (ciConnection *)gsimalloc(sizeof(ciConnection)); + if(connection == NULL) + return NULL; //ERRCON + + // Initialize the connection. + ///////////////////////////// + memset(connection, 0, sizeof(ciConnection)); + connection->loginType = loginType; + if(nick) + strzcpy(connection->nick, nick, MAX_NICK); + if(user) + strzcpy(connection->user, user, MAX_USER); +#ifdef GSI_UNICODE // store a unicode version of the nick and user + UTF8ToUCS2String(connection->nick, connection->nickW); + UTF8ToUCS2String(connection->user, connection->userW); +#endif + if(name) + strzcpy(connection->name, name, MAX_NAME); + connection->namespaceID = namespaceID; + if(email) + strzcpy(connection->email, email, MAX_EMAIL); + if(profilenick) + strzcpy(connection->profilenick, profilenick, MAX_PROFILENICK); + if(uniquenick) + strzcpy(connection->uniquenick, uniquenick, MAX_UNIQUENICK); + if(password) + strzcpy(connection->password, password, MAX_PASSWORD); + if(authtoken) + strzcpy(connection->authtoken, authtoken, MAX_AUTHTOKEN); + if(partnerchallenge) + strzcpy(connection->partnerchallenge, partnerchallenge, MAX_PARTNERCHALLENGE); + strzcpy(connection->server, serverAddress?serverAddress:CI_DEFAULT_SERVER_ADDRESS, MAX_SERVER); + connection->port = port?port:CI_DEFUILT_SERVER_PORT; + connection->globalCallbacks = *callbacks; + connection->nextID = 1; + connection->connecting = CHATTrue; + connection->quiet = CHATFalse; + + // Initialize the channel table. + //////////////////////////////// + if(!ciInitChannels(connection)) + { + gsifree(connection); + SocketShutDown(); + return NULL; //ERRCON + } + + // Initialize the callbacks list. + ///////////////////////////////// + if(!ciInitCallbacks(connection)) + { + ciCleanupChannels((CHAT)connection); + gsifree(connection); + SocketShutDown(); + return NULL; //ERRCON + } + + // Initialize the socket. + ///////////////////////// + if(!ciSocketInit(&connection->chatSocket, socketNick)) + { + ciCleanupCallbacks((CHAT)connection); + ciCleanupChannels((CHAT)connection); + gsifree(connection); + SocketShutDown(); + return NULL; //ERRCON + } + + // Connect the socket. + ////////////////////// + if(!ciSocketConnect(&connection->chatSocket, connection->server, connection->port)) + { + ciSocketDisconnect(&connection->chatSocket); + ciCleanupCallbacks((CHAT)connection); + ciCleanupChannels((CHAT)connection); + gsifree(connection); + SocketShutDown(); + return NULL; //ERRCON + } + + // Special stuff for MS Chat server. + //////////////////////////////////// + //ciSocketSend(&connection->chatSocket, "MODE ISIRCX"); + //ciSocketSend(&connection->chatSocket, "IRCX"); + + // Set the callback info. + ///////////////////////// + connection->nickErrorCallback = nickErrorCallback; + connection->fillInUserCallback = fillInUserCallback; + connection->connectCallback = connectCallback; + connection->connectParam = param; + + // Check for a secure connection. + ///////////////////////////////// + if(gamename && gamename[0] && secretKey && secretKey[0]) + { + // Save the game secret key. + //////////////////////////// + strzcpy(connection->secretKey, secretKey, MAX_SECRETKEY); + + // Get the random keys. + /////////////////////// + ciSocketSendf(&connection->chatSocket, "CRYPT des %d %s", ciVersionID, gamename); + } + else if(connection->fillInUserCallback) + { + // Get the IP. + ////////////// + ciSocketSend(&connection->chatSocket, "USRIP"); + } + else + { + // Send the nick and user. + ////////////////////////// + ciSendNickAndUser((CHAT)connection); + } + + // Do blocking. + /////////////// + if(blocking) + { + // While we're connecting. + ////////////////////////// + do + { + ciThink((CHAT)connection, 0); + msleep(10); + } while(connection->connecting); + + // Check if the connect failed. + /////////////////////////////// + if(!connection->connected) + { + // Disconnect the connection. + ///////////////////////////// + chatDisconnect((CHAT)connection); + connection = NULL; + } + } + + return (CHAT)connection; +} + +CHAT chatConnectA(const char * serverAddress, + int port, + const char * nick, + const char * user, + const char * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + return chatConnectDoit(CINoLogin, + serverAddress, + port, + nick, + user, + name, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + callbacks, + nickErrorCallback, + NULL, + connectCallback, + param, + blocking); +} +#ifdef GSI_UNICODE +CHAT chatConnectW(const unsigned short * serverAddress, + int port, + const unsigned short * nick, + const unsigned short * user, + const unsigned short * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress); + char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + char* name_A = (char*)UCS2ToUTF8StringAlloc(name); + + CHAT aChat = chatConnectA(serverAddress_A, + port, + nick_A, + user_A, + name_A, + callbacks, + nickErrorCallback, + connectCallback, + param, + blocking); + + gsifree(serverAddress_A); + gsifree(nick_A); + gsifree(user_A); + gsifree(name_A); + + return aChat; +} +#endif + +CHAT chatConnectSpecialA(const char * serverAddress, + int port, + const char * nick, + const char * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + return chatConnectDoit(CINoLogin, + serverAddress, + port, + nick, + NULL, + name, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + callbacks, + nickErrorCallback, + fillInUserCallback, + connectCallback, + param, + blocking); +} +#ifdef GSI_UNICODE +CHAT chatConnectSpecialW(const unsigned short * serverAddress, + int port, + const unsigned short * nick, + const unsigned short * name, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress); + char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick); + char* name_A = (char*)UCS2ToUTF8StringAlloc(name); + CHAT aChat = chatConnectSpecialA(serverAddress_A, port, nick_A, name_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking); + gsifree(serverAddress_A); + gsifree(nick_A); + gsifree(name_A); + + return aChat; +} +#endif + +CHAT chatConnectSecureA(const char * serverAddress, + int port, + const char * nick, + const char * name, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + return chatConnectDoit(CINoLogin, + serverAddress, + port, + nick, + NULL, + name, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + gamename, + secretKey, + callbacks, + nickErrorCallback, + fillInUserCallback, + connectCallback, + param, + blocking); +} +#ifdef GSI_UNICODE +CHAT chatConnectSecureW(const unsigned short * serverAddress, + int port, + const unsigned short * nick, + const unsigned short * name, + const unsigned short * gamename, + const unsigned short * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress); + char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick); + char* name_A = (char*)UCS2ToUTF8StringAlloc(name); + char* gamename_A = (char*)UCS2ToUTF8StringAlloc(gamename); + char* secretKey_A = (char*)UCS2ToUTF8StringAlloc(secretKey); + CHAT aChat = chatConnectSecureA(serverAddress_A, port, nick_A, name_A, gamename_A, secretKey_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking); + gsifree(serverAddress_A); + gsifree(nick_A); + gsifree(name_A); + gsifree(gamename_A); + gsifree(secretKey_A); + + return aChat; +} +#endif + +CHAT chatConnectLoginA(const char * serverAddress, + int port, + int namespaceID, + const char * email, + const char * profilenick, + const char * uniquenick, + const char * password, + const char * name, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + return chatConnectDoit((uniquenick && uniquenick[0])?CIUniqueNickLogin:CIProfileLogin, + serverAddress, + port, + NULL, + NULL, + name, + namespaceID, + email, + profilenick, + uniquenick, + password, + NULL, + NULL, + gamename, + secretKey, + callbacks, + nickErrorCallback, + fillInUserCallback, + connectCallback, + param, + blocking); +} +#ifdef GSI_UNICODE +CHAT chatConnectLoginW(const unsigned short * serverAddress, + int port, + int namespaceID, + const unsigned short * email, + const unsigned short * profilenick, + const unsigned short * uniquenick, + const unsigned short * password, + const unsigned short * name, + const unsigned short * gamename, + const unsigned short * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress); + char* email_A = (char*)UCS2ToUTF8StringAlloc(email); + char* profilenick_A = (char*)UCS2ToUTF8StringAlloc(profilenick); + char* uniquenick_A = (char*)UCS2ToUTF8StringAlloc(uniquenick); + char* password_A = (char*)UCS2ToUTF8StringAlloc(password); + char* name_A = (char*)UCS2ToUTF8StringAlloc(name); + char* gamename_A = (char*)UCS2ToUTF8StringAlloc(gamename); + char* secretKey_A = (char*)UCS2ToUTF8StringAlloc(secretKey); + CHAT aChat= chatConnectLoginA(serverAddress_A, port, namespaceID, email_A, profilenick_A, uniquenick_A, password_A, name_A, gamename_A, secretKey_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking); + gsifree(serverAddress_A); + gsifree(email_A); + gsifree(profilenick_A); + gsifree(uniquenick_A); + gsifree(name_A); + gsifree(gamename_A); + gsifree(secretKey_A); + + return aChat; +} +#endif + +CHAT chatConnectPreAuthA(const char * serverAddress, + int port, + const char * authtoken, + const char * partnerchallenge, + const char * name, + const char * gamename, + const char * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + return chatConnectDoit(CIPreAuthLogin, + serverAddress, + port, + NULL, + NULL, + name, + 0, + NULL, + NULL, + NULL, + NULL, + authtoken, + partnerchallenge, + gamename, + secretKey, + callbacks, + nickErrorCallback, + fillInUserCallback, + connectCallback, + param, + blocking); +} +#ifdef GSI_UNICODE +CHAT chatConnectPreAuthW(const unsigned short * serverAddress, + int port, + const unsigned short * authtoken, + const unsigned short * partnerchallenge, + const unsigned short * name, + const unsigned short * gamename, + const unsigned short * secretKey, + chatGlobalCallbacks * callbacks, + chatNickErrorCallback nickErrorCallback, + chatFillInUserCallback fillInUserCallback, + chatConnectCallback connectCallback, + void * param, + CHATBool blocking) +{ + char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress); + char* authtoken_A = (char*)UCS2ToUTF8StringAlloc(authtoken); + char* partnerchallenge_A = (char*)UCS2ToUTF8StringAlloc(partnerchallenge); + char* name_A = (char*)UCS2ToUTF8StringAlloc(name); + char* gamename_A = (char*)UCS2ToUTF8StringAlloc(gamename); + char* secretKey_A = (char*)UCS2ToUTF8StringAlloc(secretKey); + CHAT aChat = chatConnectPreAuthA(serverAddress_A, port, authtoken_A, partnerchallenge_A, name_A, gamename_A, secretKey_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking); + gsifree(serverAddress_A); + gsifree(authtoken_A); + gsifree(partnerchallenge_A); + gsifree(name_A); + gsifree(gamename_A); + gsifree(secretKey_A); + + return aChat; +} +#endif + +void chatRetryWithNickA(CHAT chat, + const char * nick) +{ + int validateNick; + CONNECTION; + + // Are we already connected? + //////////////////////////// + if(connection->connected) + return; + + // A NULL nick means stop retrying and disconnect + if (nick == NULL) + { + connection->connecting = CHATFalse; + + // Call the callback. (Failed to connect) + ///////////////////// + if(connection->connectCallback != NULL) + connection->connectCallback(chat, CHATFalse, CHAT_NICK_ERROR, connection->connectParam); + + return; + } + + // Copy the new nick. + ///////////////////// + strzcpy(connection->nick, nick, MAX_NICK); +#ifdef GSI_UNICODE // store a unicode version of the nick + AsciiToUCS2String(connection->nick, connection->nickW); +#endif + + // Check for a bad nick. + //////////////////////// + validateNick = ciNickIsValid(nick); + if (validateNick != CHAT_NICK_OK) + { + ciNickError(chat, validateNick, nick, 0, NULL); + return; + } + + // Send the new nick. + ///////////////////// + ciSocketSendf(&connection->chatSocket, "NICK :%s", nick); + +} +#ifdef GSI_UNICODE +void chatRetryWithNickW(CHAT chat, + const unsigned short * nick) +{ + char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick); + chatRetryWithNickA(chat, nick_A); + gsifree(nick_A); +} +#endif + +void chatRegisterUniqueNickA(CHAT chat, + int namespaceID, + const char * uniquenick, + const char * cdkey) +{ + CONNECTION; + + // Are we already connected? + //////////////////////////// + if(connection->connected) + return; + + // A NULL nick means stop trying and disconnect. + //////////////////////////////////////////////// + if(uniquenick == NULL) + { + connection->connecting = CHATFalse; + + // Call the callback. + ///////////////////// + if(connection->connectCallback != NULL) + connection->connectCallback(chat, CHATFalse, CHAT_NICK_ERROR, connection->connectParam); + + return; + } + + // CDKey is optional. + ///////////////////// + if(!cdkey) + cdkey = ""; + + // Send the message. + //////////////////// + ciSocketSendf(&connection->chatSocket, "REGISTERNICK %d %s %s", namespaceID, uniquenick, cdkey); + + // Save the uniquenick we're trying to use. + /////////////////////////////////////////// + strzcpy(connection->uniquenick, uniquenick, MAX_UNIQUENICK); +} +#ifdef GSI_UNICODE +void chatRegisterUniqueNickW(CHAT chat, + int namespaceID, + const unsigned short * uniquenick, + const unsigned short * cdkey) +{ + char* uniquenick_A = (char*)UCS2ToUTF8StringAlloc(uniquenick); + char* cdkey_A = (char*)UCS2ToUTF8StringAlloc(cdkey); + chatRegisterUniqueNickA(chat, namespaceID, uniquenick_A, cdkey_A); + gsifree(uniquenick_A); + gsifree(cdkey_A); +} +#endif + +void chatDisconnect(CHAT chat) +{ + CONNECTION; + + // Cleanup all the filters first. + ///////////////////////////////// + ciCleanupFilters(chat); + + // Call the disconnected callback if we haven't already. + //////////////////////////////////////////////////////// + if(!connection->disconnected && connection->globalCallbacks.disconnected) +#ifdef GSI_UNICODE + connection->globalCallbacks.disconnected(chat, L"", connection->globalCallbacks.param); +#else + connection->globalCallbacks.disconnected(chat, "", connection->globalCallbacks.param); +#endif + + // Are we connected. + //////////////////// + if(connection->connected) + { + ciSocketSend(&connection->chatSocket, "QUIT :Later!"); + ciSocketThink(&connection->chatSocket); + } + + // gsifree the channel table. + ////////////////////////// + ciCleanupChannels(chat); + + // Cleanup the callbacks list. + ////////////////////////////// + ciCleanupCallbacks(chat); + + // Shutdown the chat socket. + //////////////////////////// + ciSocketDisconnect(&connection->chatSocket); + + // gsifree the memory. + /////////////////// + gsifree(chat); + + // Shutdown sockets. + //////////////////// + SocketShutDown(); +} + +void chatThink(CHAT chat) +{ + ciThink(chat, 0); +} + +void chatSendRawA(CHAT chat, + const char * command) +{ + CONNECTION; + if(!connection || (!connection->connected && !connection->connecting)) + return; + + ciSocketSend(&connection->chatSocket, command); +} +#ifdef GSI_UNICODE +void chatSendRawW(CHAT chat, + const unsigned short* command) +{ + char* command_A = (char*)UCS2ToUTF8StringAlloc(command); + chatSendRawA(chat, command_A); + gsifree(command_A); +} +#endif + +void chatChangeNickA(CHAT chat, + const char * newNick, + chatChangeNickCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CHATBool success = CHATTrue; + + CONNECTION; + CONNECTED; + + assert(newNick); + assert(newNick[0]); + assert(strlen(newNick) < MAX_NICK); + assert(callback); + assert(connection->connected); + + // chatRetryWithNick should be called while connecting. + /////////////////////////////////////////////////////// + if(!connection->connected) + return; + + // No nick. + /////////// + if(!newNick || !newNick[0]) + success = CHATFalse; + + // 10-13-2004: Added By Saad Nader + // check for long or invalid chars in new nick. + /////////////////////////////////////////////// + if (ciNickIsValid(newNick) != CHAT_NICK_OK) + { + success = CHATFalse; + } + + // Check for same nick. + /////////////////////// + if(success && (strcasecmp(newNick, connection->nick) == 0)) + success = CHATFalse; + + // Call the callback? + ///////////////////// + if(!success) + { + if(callback) + { + ciCallbackChangeNickParams params; + params.success = success; + params.oldNick = connection->nick; + params.newNick = (char *)newNick; + ID = ciGetNextID(chat); + ciAddCallback(chat, CALLBACK_CHANGE_NICK, (void*)callback, ¶ms, param, ID, NULL); + + CI_DO_BLOCKING; + } + + return; + } + + // Send the request. + //////////////////// + ciSocketSendf(&connection->chatSocket, "NICK :%s", newNick); + + ID = ciAddNICKFilter(chat, connection->nick, newNick, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatChangeNickW(CHAT chat, + const unsigned short * newNick, + chatChangeNickCallback callback, + void * param, + CHATBool blocking) +{ + char* newNick_A = (char*)UCS2ToUTF8StringAlloc(newNick); + chatChangeNickA(chat, newNick_A, callback, param, blocking); + gsifree(newNick_A); +} +#endif + +const char * chatGetNickA(CHAT chat) +{ + CONNECTION; + + if(!connection->connected) + return ""; + + return connection->nick; +} +#ifdef GSI_UNICODE +const unsigned short * chatGetNickW(CHAT chat) +{ + CONNECTION; + + if(!connection->connected) + return L""; + + return connection->nickW; +} +#endif + +void chatFixNickA(char * newNick, + const char * oldNick) +{ + int c; + char oldNickCopy[MAX_CHAT_NICK]; + char *pOldNick = oldNickCopy; + assert(oldNick); + assert(newNick); + strzcpy(oldNickCopy, oldNick, MAX_CHAT_NICK); + //if(isdigit(*oldNick) || (*oldNick == '-')) + // 10-14-2004 Changed by Saad Nader + // Using the nickname rules for unique nicks + // commented out the previous rules + //////////////////////////////////////////////// + if(*pOldNick == '@' || *pOldNick== '#' || *pOldNick== '+' || *pOldNick == ':') + *newNick++ = '_'; + + while((c = *pOldNick++) != '\0') + { + if(!strchr(VALID_NICK_CHARS, c)) + c = '_'; + + *newNick++ = (char)c; + } + *newNick = '\0'; + +} +#ifdef GSI_UNICODE +void chatFixNickW(unsigned short* newNick, + const unsigned short* oldNick) +{ + char* oldNick_A = (char*)UCS2ToUTF8StringAlloc(newNick); + char newNick_A[MAX_NICK]; + + chatFixNickA(newNick_A, oldNick_A); + + UTF8ToUCS2String(newNick_A, newNick); + + gsifree(oldNick_A); + + GSI_UNUSED(oldNick); +} +#endif + +const char * chatTranslateNickA(char * nick, + const char * extension) +{ + int nickLen; + int extensionLen; + + assert(nick); + assert(extension); + + nickLen = (int)strlen(nick); + extensionLen = (int)strlen(extension); + + if((extensionLen < nickLen) && (strcasecmp(nick + nickLen - extensionLen, extension) == 0)) + { + nick[nickLen - extensionLen] = '\0'; + return nick; + } + + return NULL; +} +#ifdef GSI_UNICODE +const unsigned short * chatTranslateNickW(unsigned short * nick, + const unsigned short * extension) +{ + char nick_A[MAX_NICK]; + char extension_A[MAX_NICK]; + const char * translatedNick_A; + + assert(nick); + assert(extension); + + UCS2ToAsciiString(nick, nick_A); + UCS2ToAsciiString(extension, extension_A); + + translatedNick_A = chatTranslateNickA(nick_A, extension_A); + + if(translatedNick_A) + { + AsciiToUCS2String(translatedNick_A, nick); + return nick; + } + + return NULL; +} +#endif + +int chatGetUserID(CHAT chat) +{ + CONNECTION; + + return connection->userID; +} + +int chatGetProfileID(CHAT chat) +{ + CONNECTION; + + return connection->profileID; +} + +static void ciSetQuietModeEnumJoinedChannelsA(CHAT chat, + int index, + const char * channel, + void * param) +{ + // Setup a filter. + ////////////////// + ciAddUNQUIETFilter(chat, channel); + + GSI_UNUSED(index); + GSI_UNUSED(param); +} +#ifdef GSI_UNICODE +static void ciSetQuietModeEnumJoinedChannelsW(CHAT chat, + int index, + const unsigned short * channel, + void * param) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + ciSetQuietModeEnumJoinedChannelsA(chat, index, channel_A, param); + gsifree(channel_A); +} +#endif + +void chatSetQuietMode(CHAT chat, + CHATBool quiet) +{ + CONNECTION; + CONNECTED; + + // Check if its the current mode. + ///////////////////////////////// + if(connection->quiet == quiet) + return; + + // Send the message. + //////////////////// + if(quiet) + ciSocketSendf(&connection->chatSocket, "MODE %s +q", connection->nick); + else + ciSocketSendf(&connection->chatSocket, "MODE %s -q", connection->nick); + + // Set the mode. + //////////////// + connection->quiet = quiet; + + // Are we disabling it? + /////////////////////// + if(!quiet) + { + // Clear all the player lists. + ////////////////////////////// + ciClearAllUsers(chat); + + // Setup a filter for each joined channel. + ////////////////////////////////////////// +#ifdef GSI_UNICODE + ciEnumJoinedChannels(chat, ciSetQuietModeEnumJoinedChannelsW, NULL); +#else + ciEnumJoinedChannels(chat, ciSetQuietModeEnumJoinedChannelsA, NULL); +#endif + } +} + +void chatAuthenticateCDKeyA(CHAT chat, + const char * cdkey, + chatAuthenticateCDKeyCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CHATBool success = CHATTrue; + + CONNECTION; + CONNECTED; + + assert(cdkey); + assert(cdkey[0]); + assert(callback); + assert(connection->connected); + + // Check we're connected. + ///////////////////////// + if(!connection->connected) + return; + + // No key. + ////////// + if(!cdkey || !cdkey[0]) + success = CHATFalse; + + // Call the callback? + ///////////////////// + if(!success) + { + if(callback) + { + ciCallbackAuthenticateCDKeyParams params; + params.result = 0; + params.message = ""; + ID = ciGetNextID(chat); + ciAddCallback(chat, CALLBACK_AUTHENTICATE_CDKEY, (void*)callback, ¶ms, param, ID, NULL); + + CI_DO_BLOCKING; + } + + return; + } + + // Send the request. + //////////////////// + ciSocketSendf(&connection->chatSocket, "CDKEY %s", cdkey); + + ID = ciAddCDKEYFilter(chat, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatAuthenticateCDKeyW(CHAT chat, + const unsigned short* cdkey, + chatAuthenticateCDKeyCallback callback, + void * param, + CHATBool blocking) +{ + char* cdkey_A = (char*)UCS2ToUTF8StringAlloc(cdkey); + chatAuthenticateCDKeyA(chat, cdkey_A, callback, param, blocking); + gsifree(cdkey_A); +} +#endif + +/************* +** CHANNELS ** +*************/ +void chatEnumChannelsA(CHAT chat, + const char * filter, + chatEnumChannelsCallbackEach callbackEach, + chatEnumChannelsCallbackAll callbackAll, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + assert((callbackAll != NULL) || (callbackEach != NULL)); + + if(!filter) + filter = ""; + + ciSocketSendf(&connection->chatSocket, "LIST %s", filter); + + ID = ciAddLISTFilter(chat, callbackEach, callbackAll, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatEnumChannelsW(CHAT chat, + const unsigned short * filter, + chatEnumChannelsCallbackEach callbackEach, + chatEnumChannelsCallbackAll callbackAll, + void * param, + CHATBool blocking) +{ + char* filter_A = (char*)UCS2ToUTF8StringAlloc(filter); + chatEnumChannelsA(chat, filter_A, callbackEach, callbackAll, param, blocking); + gsifree(filter_A); +} +#endif + +void chatEnterChannelA(CHAT chat, + const char * channel, + const char * password, + chatChannelCallbacks * callbacks, + chatEnterChannelCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callbacks != NULL); + + if(password == NULL) + password = ""; + + ciSocketSendf(&connection->chatSocket, "JOIN %s %s", channel, password); + + ID = ciAddJOINFilter(chat, channel, callback, param, callbacks, password); + + // Entering. + //////////// + ciChannelEntering(chat, channel); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatEnterChannelW(CHAT chat, + const unsigned short * channel, + const unsigned short * password, + chatChannelCallbacks * callbacks, + chatEnterChannelCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* password_A = (char*)UCS2ToUTF8StringAlloc(password); + chatEnterChannelA(chat, channel_A, password_A, callbacks, callback, param, blocking); + gsifree(channel_A); + gsifree(password_A); +} +#endif + +void chatLeaveChannelA(CHAT chat, + const char * channel, + const char * reason) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + + if(!reason) + reason = ""; + + ciSocketSendf(&connection->chatSocket, "PART %s :%s", channel, reason); + + // Left the channel. + //////////////////// + ciChannelLeft(chat, channel); +} +#ifdef GSI_UNICODE +void chatLeaveChannelW(CHAT chat, + const unsigned short * channel, + const unsigned short* reason) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* reason_A = (char*)UCS2ToUTF8StringAlloc(reason); + chatLeaveChannelA(chat, channel_A, reason_A); + gsifree(channel_A); + gsifree(reason_A); +} +#endif + +void chatSendChannelMessageA(CHAT chat, + const char * channel, + const char * message, + int type) +{ + chatChannelCallbacks * callbacks; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_TYPE(type); + + if (!message || !message[0]) + return; + if(type == CHAT_MESSAGE) + ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :%s", channel, message); + else if(type == CHAT_ACTION) + ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :\001ACTION %s\001", channel, message); + else if(type == CHAT_NOTICE) + ciSocketSendf(&connection->chatSocket, "NOTICE %s :%s", channel, message); + else if(type == CHAT_UTM) + ciSocketSendf(&connection->chatSocket, "UTM %s :%s", channel, message); + else if(type == CHAT_ATM) + ciSocketSendf(&connection->chatSocket, "ATM %s :%s", channel, message); + else + return; + + // We don't get these back, so call the callbacks. + ////////////////////////////////////////////////// + callbacks = ciGetChannelCallbacks(chat, channel); + if(callbacks != NULL) + { + ciCallbackChannelMessageParams params; + params.channel = (char *)channel; + params.user = connection->nick; + params.message = (char *)message; + params.type = type; + ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, channel); + } +} +#ifdef GSI_UNICODE +void chatSendChannelMessageW(CHAT chat, + const unsigned short * channel, + const unsigned short * message, + int type) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* message_A = (char*)UCS2ToUTF8StringAlloc(message); + chatSendChannelMessageA(chat, channel_A, message_A, type); + gsifree(channel_A); + gsifree(message_A); +} +#endif + +void chatSetChannelTopicA(CHAT chat, + const char * channel, + const char * topic) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + + if(topic == NULL) + topic = ""; + + ciSocketSendf(&connection->chatSocket, "TOPIC %s :%s", channel, topic); +} +#ifdef GSI_UNICODE +void chatSetChannelTopicW(CHAT chat, + const unsigned short * channel, + const unsigned short * topic) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* topic_A = (char*)UCS2ToUTF8StringAlloc(topic); + chatSetChannelTopicA(chat, channel_A, topic_A); + gsifree(channel_A); + gsifree(topic_A); +} +#endif + +void chatGetChannelTopicA(CHAT chat, + const char * channel, + chatGetChannelTopicCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + const char * topic; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + // Check if we already have the topic. + ////////////////////////////////////// + topic = ciGetChannelTopic(chat, channel); + if(topic) + { + ciCallbackGetChannelTopicParams params; + + ID = ciGetNextID(chat); + + params.success = CHATTrue; + params.channel = (char *)channel; + params.topic = (char *)topic; + ciAddCallback(chat, CALLBACK_GET_CHANNEL_TOPIC, (void*)callback, ¶ms, param, ID, channel); + } + else + { + ciSocketSendf(&connection->chatSocket, "TOPIC %s", channel); + + ID = ciAddTOPICFilter(chat, channel, callback, param); + } + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetChannelTopicW(CHAT chat, + const unsigned short * channel, + chatGetChannelTopicCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatGetChannelTopicA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + +void chatSetChannelModeA(CHAT chat, + const char * channel, + CHATChannelMode * mode) +{ + char buffer[64]; + + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(mode != NULL); + + // Build the mode string. + ///////////////////////// + strcpy(buffer, "XiXpXsXmXnXtXlXe"); + if(mode->InviteOnly) + buffer[0] = '+'; + else + buffer[0] = '-'; + if(mode->Private) + buffer[2] = '+'; + else + buffer[2] = '-'; + if(mode->Secret) + buffer[4] = '+'; + else + buffer[4] = '-'; + if(mode->Moderated) + buffer[6] = '+'; + else + buffer[6] = '-'; + if(mode->NoExternalMessages) + buffer[8] = '+'; + else + buffer[8] = '-'; + if(mode->OnlyOpsChangeTopic) + buffer[10] = '+'; + else + buffer[10] = '-'; + if(mode->Limit > 0) + buffer[12] = '+'; + else + buffer[12] = '-'; + if(mode->OpsObeyChannelLimit) + buffer[14] = '+'; + else + buffer[14] = '-'; + + // Add limit if needed. + /////////////////////// + if(mode->Limit > 0) + sprintf(&buffer[strlen(buffer)], " %d", mode->Limit); + + ciSocketSendf(&connection->chatSocket, "MODE %s %s", channel, buffer); +} +#ifdef GSI_UNICODE +void chatSetChannelModeW(CHAT chat, + const unsigned short * channel, + CHATChannelMode * mode) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatSetChannelModeA(chat, channel_A, mode); + gsifree(channel_A); +} +#endif + +void chatGetChannelModeA(CHAT chat, + const char * channel, + chatGetChannelModeCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + // Are we in this channel? + ////////////////////////// + if(ciInChannel(chat, channel)) + { + CHATChannelMode mode; + + // Get the mode locally. + //////////////////////// + if(ciGetChannelMode(chat, channel, &mode)) + { + ciCallbackGetChannelModeParams params; + + // Get an ID. + ///////////// + ID = ciGetNextID(chat); + + // Add the callback. + //////////////////// + params.success = CHATTrue; + params.channel = (char *)channel; + params.mode = &mode; + ciAddCallback(chat, CALLBACK_GET_CHANNEL_MODE, (void*)callback, ¶ms, param, ID, NULL); + + CI_DO_BLOCKING; + + return; + } + } + + ciSocketSendf(&connection->chatSocket, "MODE %s", channel); + + ID = ciAddCMODEFilter(chat, channel, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetChannelModeW(CHAT chat, + const unsigned short * channel, + chatGetChannelModeCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatGetChannelModeA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + +void chatSetChannelPasswordA(CHAT chat, + const char * channel, + CHATBool enable, + const char * password) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_PASSWORD(); + + if(enable) + ciSocketSendf(&connection->chatSocket, "MODE %s +k %s", channel, password); + else + ciSocketSendf(&connection->chatSocket, "MODE %s -k %s", channel, password); +} +#ifdef GSI_UNICODE +void chatSetChannelPasswordW(CHAT chat, + const unsigned short * channel, + CHATBool enable, + const unsigned short * password) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* password_A = (char*)UCS2ToUTF8StringAlloc(password); + chatSetChannelPasswordA(chat, channel_A, enable, password_A); + gsifree(channel_A); + gsifree(password_A); +} +#endif + +void chatGetChannelPasswordA(CHAT chat, + const char * channel, + chatGetChannelPasswordCallback callback, + void * param, + CHATBool blocking) +{ + ciCallbackGetChannelPasswordParams params; + const char * password; + int ID; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + // Check that we're in the channel. + /////////////////////////////////// + if(!ciInChannel(chat, channel)) + return; //ERRCON + + // Get the password. + //////////////////// + password = ciGetChannelPassword(chat, channel); + assert(password != NULL); + + // Get an ID. + ///////////// + ID = ciGetNextID(chat); + + // Add the callback. + //////////////////// + params.success = CHATTrue; + params.channel = (char *)channel; + params.enabled = CHATTrue; + params.password = (char *)password; + ciAddCallback(chat, CALLBACK_GET_CHANNEL_PASSWORD, (void*)callback, ¶ms, param, ID, NULL); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetChannelPasswordW(CHAT chat, + const unsigned short * channel, + chatGetChannelPasswordCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatGetChannelPasswordA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + +void chatSetChannelLimitA(CHAT chat, + const char * channel, + int limit) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(limit >= 0); + + if(limit) + ciSocketSendf(&connection->chatSocket, "MODE %s +l %d", channel, limit); + else + ciSocketSendf(&connection->chatSocket, "MODE %s -l", channel); +} +#ifdef GSI_UNICODE +void chatSetChannelLimitW(CHAT chat, + const unsigned short * channel, + int limit) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatSetChannelLimitA(chat, channel_A, limit); + gsifree(channel_A); +} +#endif + +void chatEnumChannelBansA(CHAT chat, + const char * channel, + chatEnumChannelBansCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + ciSocketSendf(&connection->chatSocket, "MODE %s +b", channel); + + ID = ciAddGETBANFilter(chat, channel, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatEnumChannelBansW(CHAT chat, + const unsigned short * channel, + chatEnumChannelBansCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatEnumChannelBansA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + +void chatAddChannelBanA(CHAT chat, + const char * channel, + const char * ban) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_BAN(); + + ciSocketSendf(&connection->chatSocket, "MODE %s +b %s", channel, ban); +} +#ifdef GSI_UNICODE +void chatAddChannelBanW(CHAT chat, + const unsigned short * channel, + const unsigned short * ban) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* ban_A = (char*)UCS2ToUTF8StringAlloc(ban); + chatAddChannelBanA(chat, channel_A, ban_A); + gsifree(channel_A); + gsifree(ban_A); +} +#endif + +void chatRemoveChannelBanA(CHAT chat, + const char * channel, + const char * ban) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_BAN(); + + ciSocketSendf(&connection->chatSocket, "MODE %s -b %s", channel, ban); +} +#ifdef GSI_UNICODE +void chatRemoveChannelBanW(CHAT chat, + const unsigned short * channel, + const unsigned short * ban) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* ban_A = (char*)UCS2ToUTF8StringAlloc(ban); + chatRemoveChannelBanA(chat, channel_A, ban_A); + gsifree(channel_A); + gsifree(ban_A); +} +#endif + +void chatSetChannelGroupA(CHAT chat, + const char * channel, + const char * group) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + + // No way to clear the group. + ///////////////////////////// + if(!group || !group[0]) + return; + + ciSocketSendf(&connection->chatSocket, "SETGROUP %s %s", channel, group); +} +#ifdef GSI_UNICODE +void chatSetChannelGroupW(CHAT chat, + const unsigned short * channel, + const unsigned short* group) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* group_A = (char*)UCS2ToUTF8StringAlloc(group); + chatSetChannelGroupA(chat, channel_A, group_A); + gsifree(channel_A); + gsifree(group_A); +} +#endif + +int chatGetChannelNumUsersA(CHAT chat, + const char * channel) +{ + CONNECTION; + if(!connection->connected) + return -1; + + ASSERT_CHANNEL(); + + if(!channel || !channel[0]) + return -1; + + if(!ciInChannel(chat, channel)) + return -1; + + return ciGetChannelNumUsers(chat, channel); +} +#ifdef GSI_UNICODE +int chatGetChannelNumUsersW(CHAT chat, + const unsigned short * channel) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + int result = chatGetChannelNumUsersA(chat, channel_A); + gsifree(channel_A); + + return result; +} +#endif + +CHATBool chatInChannelA(CHAT chat, + const char * channel) + +{ + CONNECTION; + if(!connection->connected) + return CHATFalse; + + ASSERT_CHANNEL(); + + if(!channel || !channel[0]) + return CHATFalse; + + return ciInChannel(chat, channel); +} +#ifdef GSI_UNICODE +CHATBool chatInChannelW(CHAT chat, + const unsigned short * channel) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + CHATBool result = chatInChannelA(chat, channel_A); + gsifree(channel_A); + + return result; +} +#endif + + +/********** +** USERS ** +**********/ +static void ciEnumUsersCallback(CHAT chat, const char * channel, int numUsers, const char ** users, int * modes, void * param) +{ + ciEnumUsersData * data; + CONNECTION; + + // Check the args. + ////////////////// + ASSERT_CHANNEL(); + assert(numUsers >= 0); +#ifdef _DEBUG + { + int i; + if(numUsers > 0) + { + assert(users != NULL); + assert(modes != NULL); + } + for(i = 0 ; i < numUsers ; i++) + { + ASSERT_USER(users[i]); + ASSERT_TYPE(modes[i]); + } + } +#endif + assert(param != NULL); + + // Get the data. + //////////////// + data = (ciEnumUsersData *)param; + assert(data->callback != NULL); + + // Call the callback directly. + ////////////////////////////// +#ifdef GSI_UNICODE + { + unsigned short* channel_W = UTF8ToUCS2StringAlloc(channel); + unsigned short** users_W = UTF8ToUCS2StringArrayAlloc(users, numUsers); + data->callback(chat, CHATTrue, channel_W, numUsers, (const unsigned short**)users_W, modes, data->param); + gsifree(channel_W); + while(numUsers-- > 0) + gsifree(users_W[numUsers]); + gsifree(users_W); + } +#else + data->callback(chat, CHATTrue, channel, numUsers, users, modes, data->param); +#endif +} + +void chatEnumUsersA(CHAT chat, + const char * channel, + chatEnumUsersCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + ciEnumUsersData data; + CONNECTION; + CONNECTED; + + //ASSERT_CHANNEL(); + assert(callback != NULL); + + if(channel == NULL) + channel = ""; + + // Is there a channel specified? + //////////////////////////////// + if(channel[0] != '\0') + { + // Check if we have this one locally. + ///////////////////////////////////// + if(ciInChannel(chat, channel)) + { + // Get the users in the channel. + //////////////////////////////// + data.callback = callback; + data.param = param; + ciChannelListUsers(chat, channel, ciEnumUsersCallback, &data); + + return; + } + } + + ciSocketSendf(&connection->chatSocket, "NAMES %s", channel); + + // Channel needs to be empty, not NULL, for the filter. + /////////////////////////////////////////////////////// + if(!channel[0]) + channel = NULL; + + ID = ciAddNAMESFilter(chat, channel, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatEnumUsersW(CHAT chat, + const unsigned short * channel, + chatEnumUsersCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatEnumUsersA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + + +// Enumerates the channels that we are joined to +////////////////////////////////////////////////////// +void chatEnumJoinedChannels(CHAT chat, + chatEnumJoinedChannelsCallback callback, + void * param) +{ + ciEnumJoinedChannels(chat, callback, param); +} + +void chatSendUserMessageA(CHAT chat, + const char * user, + const char * message, + int type) +{ + CONNECTION; + CONNECTED; + + ASSERT_USER(user); + ASSERT_TYPE(type); + + if (!message || message[0] == 0) + return; + + if(type == CHAT_MESSAGE) + ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :%s", user, message); + else if(type == CHAT_ACTION) + ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :\001ACTION %s\001", user, message); + else if(type == CHAT_NOTICE) + ciSocketSendf(&connection->chatSocket, "NOTICE %s :%s", user, message); + else if(type == CHAT_UTM) + ciSocketSendf(&connection->chatSocket, "UTM %s :%s", user, message); + else if(type == CHAT_ATM) + ciSocketSendf(&connection->chatSocket, "ATM %s :%s", user, message); +} +#ifdef GSI_UNICODE +void chatSendUserMessageW(CHAT chat, + const unsigned short * user, + const unsigned short * message, + int type) +{ + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + char* message_A = (char*)UCS2ToUTF8StringAlloc(message); + chatSendUserMessageA(chat, user_A, message_A, type); + gsifree(user_A); + gsifree(message_A); +} +#endif + +void chatGetUserInfoA(CHAT chat, + const char * user, + chatGetUserInfoCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + ASSERT_USER(user); + assert(callback != NULL); + + ciSocketSendf(&connection->chatSocket, "WHOIS %s", user); + + ID = ciAddWHOISFilter(chat, user, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetUserInfoW(CHAT chat, + const unsigned short * user, + chatGetUserInfoCallback callback, + void * param, + CHATBool blocking) +{ + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + chatGetUserInfoA(chat, user_A, callback, param, blocking); + gsifree(user_A); +} +#endif + +void chatGetBasicUserInfoA(CHAT chat, + const char * nick, + chatGetBasicUserInfoCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + const char * user; + const char * address; + CONNECTION; + CONNECTED; + + ASSERT_USER(nick); + assert(callback != NULL); + + // Check if we already have it. + /////////////////////////////// + if(ciGetUserBasicInfoA(chat, nick, &user, &address)) + { + ciCallbackGetBasicUserInfoParams params; + + params.success = CHATTrue; + params.nick = (char *)nick; + params.user = (char *)user; + params.address = (char *)address; + + ID = ciGetNextID(chat); + + ciAddCallback(chat, CALLBACK_GET_BASIC_USER_INFO, (void*)callback, ¶ms, param, ID, NULL); + } + else + { + ciSocketSendf(&connection->chatSocket, "WHO %s", nick); + + ID = ciAddWHOFilter(chat, nick, callback, param); + } + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetBasicUserInfoW(CHAT chat, + const unsigned short * nick, + chatGetBasicUserInfoCallback callback, + void * param, + CHATBool blocking) +{ + char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick); + chatGetBasicUserInfoA(chat, nick_A, callback, param, blocking); + gsifree(nick_A); +} +#endif + +CHATBool chatGetBasicUserInfoNoWaitA(CHAT chat, + const char * nick, + const char ** user, + const char ** address) +{ + CONNECTION; + // 2002.Feb.28.JED - added additional check, was blowing up in GSA + if(!connection) + return CHATFalse; + if(!connection->connected) + return CHATFalse; + + ASSERT_USER(nick); + + return ciGetUserBasicInfoA(chat, nick, user, address); +} +#ifdef GSI_UNICODE +CHATBool chatGetBasicUserInfoNoWaitW(CHAT chat, + const unsigned short * nick, + const unsigned short ** user, + const unsigned short ** address) +{ + char nick_A[MAX_NICK]; + + CONNECTION; + // 2002.Feb.28.JED - added additional check, was blowing up in GSA + if(!connection) + return CHATFalse; + if(!connection->connected) + return CHATFalse; + + assert(nick); + + UCS2ToAsciiString(nick, nick_A); + return ciGetUserBasicInfoW(chat, nick_A, user, address); +} +#endif + +void chatGetChannelBasicUserInfoA(CHAT chat, + const char * channel, + chatGetChannelBasicUserInfoCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + ciSocketSendf(&connection->chatSocket, "WHO %s", channel); + + ID = ciAddCWHOFilter(chat, channel, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetChannelBasicUserInfoW(CHAT chat, + const unsigned short * channel, + chatGetChannelBasicUserInfoCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatGetChannelBasicUserInfoA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + +void chatInviteUserA(CHAT chat, + const char * channel, + const char * user) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_USER(user); + + ciSocketSendf(&connection->chatSocket, "INVITE %s %s", user, channel); +} +#ifdef GSI_UNICODE +void chatInviteUserW(CHAT chat, + const unsigned short * channel, + const unsigned short * user) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + chatInviteUserA(chat, channel_A, user_A); + gsifree(channel_A); + gsifree(user_A); +} +#endif + +void chatKickUserA(CHAT chat, + const char * channel, + const char * user, + const char * reason) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_USER(user); + + if(reason == NULL) + reason = ""; + + ciSocketSendf(&connection->chatSocket, "KICK %s %s :%s", channel, user, reason); +} +#ifdef GSI_UNICODE +void chatKickUserW(CHAT chat, + const unsigned short * channel, + const unsigned short * user, + const unsigned short * reason) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + char* reason_A = (char*)UCS2ToUTF8StringAlloc(reason); + chatKickUserA(chat, channel_A, user_A, reason_A); + gsifree(channel_A); + gsifree(user_A); + gsifree(reason_A); +} +#endif + +void chatBanUserA(CHAT chat, + const char * channel, + const char * user) +{ + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_USER(user); + + ciSocketSendf(&connection->chatSocket, "WHOIS %s", user); + + ciAddBANFilter(chat, user, channel); +} +#ifdef GSI_UNICODE +void chatBanUserW(CHAT chat, + const unsigned short * channel, + const unsigned short * user) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + chatBanUserA(chat, channel_A, user_A); + gsifree(channel_A); + gsifree(user_A); +} +#endif + +void chatSetUserModeA(CHAT chat, + const char * channel, + const char * user, + int mode) +{ + int sign; + + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_USER(user); + ASSERT_TYPE(mode); + + sign = (mode & CHAT_OP)?'+':'-'; + ciSocketSendf(&connection->chatSocket, "MODE %s %co %s", channel, sign, user); + + sign = (mode & CHAT_VOICE)?'+':'-'; + ciSocketSendf(&connection->chatSocket, "MODE %s %cv %s", channel, sign, user); +} +#ifdef GSI_UNICODE +void chatSetUserModeW(CHAT chat, + const unsigned short * channel, + const unsigned short * user, + int mode) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + chatSetUserModeA(chat, channel_A, user_A, mode); + gsifree(channel_A); + gsifree(user_A); +} +#endif + +void chatGetUserModeA(CHAT chat, + const char * channel, + const char * user, + chatGetUserModeCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + int mode; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + ASSERT_USER(user); + assert(callback != NULL); + + // Get the mode. + //////////////// + mode = ciGetUserMode(chat, channel, user); + if(mode != -1) + { + ciCallbackGetUserModeParams params; + params.success = CHATTrue; + params.channel = (char *)channel; + params.user = (char *)user; + params.mode = mode; + + ID = ciGetNextID(chat); + ciAddCallback(chat, CALLBACK_GET_USER_MODE, (void*)callback, ¶ms, param, ID, NULL); + + CI_DO_BLOCKING; + } + + ciSocketSendf(&connection->chatSocket, "WHO %s", user); + + ID = ciAddUMODEFilter(chat, user, channel, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetUserModeW(CHAT chat, + const unsigned short * channel, + const unsigned short * user, + chatGetUserModeCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + chatGetUserModeA(chat, channel_A, user_A, callback, param, blocking); + gsifree(channel_A); + gsifree(user_A); +} +#endif + +CHATBool chatGetUserModeNoWaitA(CHAT chat, + const char * channel, + const char * user, + int * mode) +{ + CONNECTION; + if(!connection->connected) + return CHATFalse; + + ASSERT_CHANNEL(); + ASSERT_USER(user); + assert(mode); + + // Get the mode. + //////////////// + *mode = ciGetUserMode(chat, channel, user); + + return (CHATBool)(*mode != -1); +} +#ifdef GSI_UNICODE +CHATBool chatGetUserModeNoWaitW(CHAT chat, + const unsigned short * channel, + const unsigned short * user, + int * mode) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + char* user_A = (char*)UCS2ToUTF8StringAlloc(user); + CHATBool result = chatGetUserModeNoWaitA(chat, channel_A, user_A, mode); + gsifree(channel_A); + gsifree(user_A); + return result; +} +#endif + + +void chatGetUdpRelayA(CHAT chat, + const char * channel, + chatGetUdpRelayCallback callback, + void * param, + CHATBool blocking) +{ + int ID; + CONNECTION; + CONNECTED; + + ASSERT_CHANNEL(); + assert(callback != NULL); + + ciSocketSendf(&connection->chatSocket, "GETUDPRELAY %s", channel); + + ID = ciAddGETUDPRELAYFilter(chat, channel, callback, param); + + CI_DO_BLOCKING; +} + +#ifdef GSI_UNICODE +void chatGetUdpRelayW(CHAT chat, + const unsigned short * channel, + chatGetUdpRelayCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + chatGetUdpRelayA(chat, channel_A, callback, param, blocking); + gsifree(channel_A); +} +#endif + +/********* +** KEYS ** +*********/ +void chatSetGlobalKeysA(CHAT chat, + int num, + const char ** keys, + const char ** values) +{ + char buffer[512]; + const char * key; + const char * value; + int i; + CONNECTION; + CONNECTED; + + if(!keys || !values) + return; + + strcpy(buffer, "SETKEY :"); + for(i = 0 ; i < num ; i++) + { + key = keys[i]; + if(!key || !key[0]) + return; + value = values[i]; + if(!value) + value = ""; + sprintf(buffer + strlen(buffer), "\\%s\\%s", key, value); + } + + ciSocketSend(&connection->chatSocket, buffer); +} +#ifdef GSI_UNICODE +void chatSetGlobalKeysW(CHAT chat, + int num, + const unsigned short ** keys, + const unsigned short ** values) +{ + char** keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = (char**)UCS2ToUTF8StringArrayAlloc(values, num); + int i = 0; + chatSetGlobalKeysA(chat, num, (const char**)keys_A, (const char**)values_A); + for (; i < num; i++) + { + gsifree(keys_A[i]); + gsifree(values_A[i]); + } + gsifree(keys_A); + gsifree(values_A); +} +#endif + +static char * ciRandomCookie() +{ + static char cookie[4]; + static int nextCookie = 0; + + sprintf(cookie, "%03d", nextCookie++); + nextCookie %= 1000; + + return cookie; +} + +static void ciSendGetKey(CHAT chat, + const char * target, + const char * cookie, + int num, + const char ** keys) +{ + char buffer[512]; + int len; + int i; + int j; + int keyLen; + + CONNECTION; + + assert(target && target[0]); + assert(cookie && cookie[0]); + assert(num >= 1); + assert(keys); + + // Start off the buffer. + //////////////////////// + sprintf(buffer, "GETKEY %s %s 0 :", target, cookie); + len = (int)strlen(buffer); + + // Add the keys. + //////////////// + for(i = 0 ; i < num ; i++) + { + // Check for a blank. + ///////////////////// + if(!keys[i] || !keys[i][0]) + continue; + + // Check lengths. + ///////////////// + keyLen = (int)strlen(keys[i]); + if((len + keyLen + 1) >= (int)sizeof(buffer)) + return; + + // Add the key. + /////////////// + buffer[len++] = '\\'; + memcpy(buffer + len, keys[i], (unsigned int)keyLen); + for(j = len ; j < (len + keyLen) ; j++) + if(buffer[j] == '\\') + buffer[j] = '/'; + len += keyLen; + buffer[len] = '\0'; + } + + // Send it. + /////////// + ciSocketSend(&connection->chatSocket, buffer); +} + +void chatGetGlobalKeysA(CHAT chat, + const char * target, + int num, + const char ** keys, + chatGetGlobalKeysCallback callback, + void * param, + CHATBool blocking) +{ + char * cookie; + const char * channel; + int ID; + CONNECTION; + CONNECTED; + + assert(num >= 0); + assert(keys); + + if(!target || !target[0]) + target = connection->nick; + + // Get a cookie. + //////////////// + cookie = ciRandomCookie(); + + // Send the request. + //////////////////// + ciSendGetKey(chat, target, cookie, num, keys); + + // Check if this is a channel or a user. + //////////////////////////////////////// + if(target[0] == '#') + channel = target; + else + channel = NULL; + + ID = ciAddGETKEYFilter(chat, cookie, num, keys, channel, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetGlobalKeysW(CHAT chat, + const unsigned short * target, + int num, + const unsigned short ** keys, + chatGetGlobalKeysCallback callback, + void * param, + CHATBool blocking) +{ + char* target_A; + char** keys_A; + int i = 0; + + assert(target); + assert(keys); + + target_A = (char*)UCS2ToUTF8StringAlloc(target); + keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num); + + chatGetGlobalKeysA(chat, target_A, num, (const char**)keys_A, callback, param, blocking); + gsifree(target_A); + + for (; i < num; i++) + gsifree(keys_A[i]); + gsifree(keys_A); +} +#endif + +void chatSetChannelKeysA(CHAT chat, + const char * channel, + const char * user, + int num, + const char ** keys, + const char ** values) +{ + char buffer[512]; + const char * value; + int i; + CONNECTION; + CONNECTED; + + if(!user || !user[0]) + sprintf(buffer, "SETCHANKEY %s :", channel); + else + sprintf(buffer, "SETCKEY %s %s :", channel, user); + for(i = 0 ; i < num ; i++) + { + value = values[i]; + if(!value) + value = ""; + sprintf(buffer + strlen(buffer), "\\%s\\%s", keys[i], value); + } + + ciSocketSend(&connection->chatSocket, buffer); +} +#ifdef GSI_UNICODE +void chatSetChannelKeysW(CHAT chat, + const unsigned short * channel, + const unsigned short * user, + int num, + const unsigned short ** keys, + const unsigned short ** values) +{ + char* channel_A; + char* user_A; + char** keys_A; + char** values_A; + int i = 0; + + channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + user_A = (char*)UCS2ToUTF8StringAlloc(user); + keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num); + values_A = (char**)UCS2ToUTF8StringArrayAlloc(values, num); + + chatSetChannelKeysA(chat, channel_A, user_A, num, (const char**)keys_A, (const char**)values_A); + + gsifree(channel_A); + gsifree(user_A); + + for (; i < num; i++) + { + gsifree(keys_A[i]); + gsifree(values_A[i]); + } + + gsifree(keys_A); + gsifree(values_A); +} +#endif + +static CHATBool ciSendGetChannelKey(CHAT chat, + const char * channel, + const char * nick, + const char * cookie, + int num, + const char ** keys) +{ + char buffer[512]; + int len; + int i; + int j; + int keyLen; + CHATBool getBrocastKeys = CHATFalse; + + CONNECTION; + + assert(channel && channel[0]); + assert(cookie && cookie[0]); + assert(!num || keys); + + // Start off the buffer. + //////////////////////// + if(!nick || !nick[0]) + sprintf(buffer, "GETCHANKEY %s %s 0 :", channel, cookie); + else + sprintf(buffer, "GETCKEY %s %s %s 0 :", channel, nick, cookie); + len = (int)strlen(buffer); + + // Add the keys. + //////////////// + for(i = 0 ; i < num ; i++) + { + // Check for a blank. + ///////////////////// + if(!keys[i] || !keys[i][0]) + continue; + + // Check for b_*. + ///////////////// + if(strcmp(keys[i], "b_*") == 0) + { + getBrocastKeys = CHATTrue; + continue; + } + + // Check lengths. + ///////////////// + keyLen = (int)strlen(keys[i]); + if((len + keyLen + 1) >= (int)sizeof(buffer)) + continue; + + // Add the key. + /////////////// + buffer[len++] = '\\'; + memcpy(buffer + len, keys[i], (unsigned int)keyLen); + for(j = len ; j < (len + keyLen) ; j++) + if(buffer[j] == '\\') + buffer[j] = '/'; + len += keyLen; + buffer[len] = '\0'; + } + + // Check for broadcast keys. + //////////////////////////// + if(getBrocastKeys) + { + if((len + 4) < (int)sizeof(buffer)) + { + strcpy(buffer + len, "\\b_*"); + len += 4; + } + } + + // Check for requesting all keys on a room. + /////////////////////////////////////////// + if(!num && (!nick || !nick[0])) + { + strcpy(buffer + len, "*"); + len++; + } + + // Send it. + /////////// + ciSocketSend(&connection->chatSocket, buffer); + + return getBrocastKeys; +} + +void chatGetChannelKeysA(CHAT chat, + const char * channel, + const char * user, + int num, + const char ** keys, + chatGetChannelKeysCallback callback, + void * param, + CHATBool blocking) +{ + char * cookie; + int ID; + CHATBool getBroadcastKeys; + CONNECTION; + CONNECTED; + + assert(num >= 0); + assert(!num || keys); + + // Get a cookie. + //////////////// + cookie = ciRandomCookie(); + + // Send the request. + //////////////////// + getBroadcastKeys = ciSendGetChannelKey(chat, channel, user, cookie, num, keys); + + if(!user || !user[0]) + ID = ciAddGETCHANKEYFilter(chat, cookie, num, keys, getBroadcastKeys, callback, param); + else + ID = ciAddGETCKEYFilter(chat, cookie, num, keys, (CHATBool)(strcmp(user, "*") == 0), getBroadcastKeys, callback, param); + + CI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void chatGetChannelKeysW(CHAT chat, + const unsigned short * channel, + const unsigned short * user, + int num, + const unsigned short ** keys, + chatGetChannelKeysCallback callback, + void * param, + CHATBool blocking) +{ + char* channel_A; + char* user_A; + char** keys_A; + int i = 0; + + channel_A = (char*)UCS2ToUTF8StringAlloc(channel); + user_A = (char*)UCS2ToUTF8StringAlloc(user); + keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num); + + chatGetChannelKeysA(chat, channel_A, user_A, num, (const char**)keys_A, callback, param, blocking); + + gsifree(channel_A); + gsifree(user_A); + + for (; i < num; i++) + gsifree(keys_A[i]); + + gsifree(keys_A); +} +#endif + +// Check if a given nickname is valid. Looks for illegal IRC characters. +// [in] nick - The nickname to validate +int ciNickIsValid(const char* nick) +{ + if (strlen(nick) >= MAX_CHAT_NICK) + return CHAT_NICK_TOO_LONG; + + // Empty nick is invalid + if ((NULL == nick) || ('\0' == *nick)) + return CHAT_INVALID; + + + // 10-14-2004 Changed by Saad Nader + // Using the nickname rules for unique nicks + // commented out the previous rules + //////////////////////////////////////////////// + // Nick can't start with a number or a '+', '@', '#' + //if(isdigit(*oldNick) || (*oldNick == '-')) + + if(*nick == '@' || *nick == '#' || *nick == '+' || *nick == ':') + return CHAT_INVALID; + + // Make sure each character is valid + while(*nick != '\0') + { + // If the character isn't in the valid set, the nick is not valid + if (NULL == strchr(VALID_NICK_CHARS,*nick++)) + return CHAT_INVALID; + } + + return CHAT_NICK_OK; +} + +/**************** +** NICK ERRORS ** +****************/ +void ciNickError(CHAT chat, int type, const char * nick, int numSuggestedNicks, char ** suggestedNicks) +{ + CONNECTION; + + // Check if there's a nick-in-use callback. + /////////////////////////////////////////// + if(connection->nickErrorCallback) + { + ciCallbackNickErrorParams params; + + // Add the callback. + //////////////////// + memset(¶ms, 0, sizeof(ciCallbackNickErrorParams)); + params.type = type; + params.nick = (char *)nick; + params.numSuggestedNicks = numSuggestedNicks; + params.suggestedNicks = suggestedNicks; + ciAddCallback(chat, CALLBACK_NICK_ERROR, (void*)connection->nickErrorCallback, ¶ms, connection->connectParam, 0, NULL); + } + else + { + // There's no callback, disconnect. + /////////////////////////////////// + connection->connecting = CHATFalse; + + // Call the callback. + ///////////////////// + if(connection->connectCallback != NULL) + connection->connectCallback(chat, CHATFalse, CHAT_NICK_ERROR, connection->connectParam); + } +} + diff --git a/xrGameSpy/gamespy/Chat/chatMain.h b/xrGameSpy/gamespy/Chat/chatMain.h new file mode 100644 index 00000000000..417e6a87484 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatMain.h @@ -0,0 +1,133 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHATMAIN_H_ +#define _CHATMAIN_H_ + +/************* +** INCLUDES ** +*************/ +#include "chat.h" +#include "chatSocket.h" +#include "chatHandlers.h" +#include "../hashtable.h" +#include "../darray.h" +#include "../md5.h" + +/************ +** DEFINES ** +************/ +#define MAX_NICK 64 +#define MAX_CHAT_NICK 21 +#define MAX_NAME 128 +#define MAX_USER 128 +#define MAX_SERVER 128 +#define MAX_PARAM 512 +#define MAX_SECRETKEY 128 +#define MAX_EMAIL 64 +#define MAX_PROFILENICK 32 +#define MAX_UNIQUENICK 64 +#define MAX_PASSWORD 32 +#define MAX_AUTHTOKEN 256 +#define MAX_PARTNERCHALLENGE 256 + +#define CONNECTION ciConnection * connection;\ + assert(chat != NULL);\ + connection = (ciConnection *)chat;\ + GSI_UNUSED(connection); +#define CONNECTED if(!connection || !connection->connected) return; //ERRCON +#if 0 +ciConnection * connection; // for visual assist +#endif + +#define VALID_NICK_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"#$%&'()*+,-./:;<=>?@[]^_`{|}~" + +#define CI_DEFAULT_SERVER_ADDRESS "peerchat." GSI_DOMAIN_NAME +#define CI_DEFUILT_SERVER_PORT 6667 +/********** +** TYPES ** +**********/ +typedef enum +{ + CINoLogin, + CIUniqueNickLogin, + CIProfileLogin, + CIPreAuthLogin +} CILoginType; + +typedef struct ciConnection +{ + CHATBool connected; + CHATBool connecting; + CHATBool disconnected; + chatNickErrorCallback nickErrorCallback; + chatFillInUserCallback fillInUserCallback; + chatConnectCallback connectCallback; + void * connectParam; + + ciSocket chatSocket; + + char nick[MAX_NICK]; + char name[MAX_NAME]; + char user[MAX_USER]; + + int namespaceID; + char email[MAX_EMAIL]; + char profilenick[MAX_PROFILENICK]; + char uniquenick[MAX_UNIQUENICK]; + char password[MAX_PASSWORD]; + + char authtoken[MAX_AUTHTOKEN]; + char partnerchallenge[MAX_PARTNERCHALLENGE]; + +#ifdef GSI_UNICODE + unsigned short nickW[MAX_NICK]; + unsigned short userW[MAX_NAME]; +#endif + + unsigned int IP; + + char server[MAX_SERVER]; + int port; + + chatGlobalCallbacks globalCallbacks; + + HashTable channelTable; + DArray enteringChannelList; + + ciServerMessageFilter * filterList; + ciServerMessageFilter * lastFilter; + + int nextID; + + DArray callbackList; + + CHATBool quiet; + + char secretKey[MAX_SECRETKEY]; + + CILoginType loginType; + + int userID; + int profileID; +} ciConnection; + +void ciSendNickAndUser(CHAT chat); +void ciSendNick(CHAT chat); +void ciSendUser(CHAT chat); +void ciSendLogin(CHAT chat); +void ciHandleDisconnect(CHAT chat, const char * reason); +int ciNickIsValid(const char* nick); +void ciNickError(CHAT chat, int type, const char * nick, int numSuggestedNicks, char ** suggestedNicks); + +#define strzcpy(dest, src, len) { strncpy(dest, src, (len)); (dest)[(len) - 1] = '\0'; } +#define wcszcpy(dest, src, len) { wcsncpy(dest, src, (len)); (dest)[(len) - 1] = 0; } + +#endif diff --git a/xrGameSpy/gamespy/Chat/chatSocket.c b/xrGameSpy/gamespy/Chat/chatSocket.c new file mode 100644 index 00000000000..9bb7227d59b --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatSocket.c @@ -0,0 +1,1032 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include +#include +#include "chatMain.h" +#include "chatSocket.h" + + +#if defined(_WIN32) +// Silence the "conditional expression is constant" on the FD_SET macros +#pragma warning(disable:4127) +#endif + +/************ +** DEFINES ** +************/ +#define BUFFER_INC 8192 +#define RECV_LEN 4096 + +/*********** +** MACROS ** +***********/ +#define ASSERT_SOCK(sock) {\ + assert((sock) != NULL);\ + assert(((sock)->connectState == ciNotConnected) ||\ + ((sock)->connectState == ciConnected) ||\ + ((sock)->connectState == ciDisconnected));\ + ASSERT_BUFFER(&(sock)->inputQueue);\ + ASSERT_BUFFER(&(sock)->outputQueue);\ + } + +#define ASSERT_CONNECTED(sock) assert((sock)->connectState == ciConnected) + +#define ASSERT_BUFFER(buffer) {\ + assert((buffer) != NULL);\ + assert((buffer)->size >= 0);\ + assert(((buffer)->size % BUFFER_INC) == 0);\ + assert((buffer)->length >= 0);\ + assert((buffer)->length <= (buffer)->size);\ + } +#define RESET(ptr) {if (ptr) {gsifree(ptr); ptr = NULL;} } + +/********* +** TIME ** +*********/ +#ifdef IRC_LOG +static const char * ciGetTime(void) +{ +#if defined(UNDER_CE) || defined(_PS2) || defined(_NITRO) + return ""; +#else + static char buffer[256]; + time_t timer; + struct tm * now; + + timer = time(NULL); + now = localtime(&timer); + if(now) // fixes the date > 2060 crash (23apr03/bgw) + { + if(now->tm_year > 99) + now->tm_year -= 100; + sprintf(buffer, "%02d.%02d.%02d %02d:%02d.%02d", now->tm_mon + 1, now->tm_mday, now->tm_year, now->tm_hour, now->tm_min, now->tm_sec); + } + else + strcpy(buffer, "00.00.00 00:00.00"); + + return buffer; +#endif +} +#endif + +/*********** +** BUFFER ** +***********/ +static CHATBool ciBufferInit(ciBuffer * buffer) +{ + assert(buffer != NULL); + + buffer->length = 0; + buffer->size = BUFFER_INC; + buffer->buffer = (char *)gsimalloc((unsigned int)buffer->size + 1); + if(buffer->buffer == NULL) + return CHATFalse; + + // Just for fun. + //////////////// + buffer->buffer[0] = '\0'; + + return CHATTrue; +} + +static void ciBufferFree(ciBuffer * buffer) +{ + gsifree(buffer->buffer); +} + +static CHATBool ciBufferPreAppend(ciBuffer * buffer, int len) +{ + int total; + char * tempPtr; + + ASSERT_BUFFER(buffer); + assert(len >= 0); + assert(len <= SHRT_MAX); // sanity check + + // Check if the buffer is big enough. + ///////////////////////////////////// + total = (buffer->length + len); + if(total <= buffer->size) + return CHATTrue; + + // Figure out the new size. + /////////////////////////// + total += BUFFER_INC; + total -= (total % BUFFER_INC); + + // Allocate the memory. + /////////////////////// + tempPtr = (char *)gsirealloc(buffer->buffer, (unsigned int)total + 1); + if(tempPtr == NULL) + return CHATFalse; + + // Update the buffer. + ///////////////////// + buffer->buffer = tempPtr; + buffer->size = total; + + return CHATTrue; +} + +static void ciBufferClipFront(ciBuffer * buffer, int len) +{ + ASSERT_BUFFER(buffer); + assert(len >= 0); + assert(len <= buffer->length); + + buffer->length -= len; + memmove(buffer->buffer, &buffer->buffer[len], (unsigned int)buffer->length); + buffer->buffer[buffer->length] = '\0'; +} + + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped +/*************** +** PROTOTYPES ** +****************/ +CHATBool ciParseParam(const char *pText, ciServerMessage * message); +#endif + +/************** +** FUNCTIONS ** +**************/ +CHATBool ciSocketInit(ciSocket * sock, const char * nick) +{ +#ifdef IRC_LOG + FILE * log; +#endif + + assert(sock != NULL); + + memset(sock, 0, sizeof(ciSocket)); + + sock->sock = INVALID_SOCKET; + if(!ciBufferInit(&sock->inputQueue)) + return CHATFalse; + if(!ciBufferInit(&sock->outputQueue)) + { + ciBufferFree(&sock->inputQueue); + return CHATFalse; + } +#ifdef IRC_LOG + sprintf(sock->filename, "%s_irc.log", nick); + log = fopen(sock->filename, "at"); + if(log != NULL) + { + fprintf(log, "\n\n\n\n\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n"); + fclose(log); + } +#endif + + GSI_UNUSED(nick); + return CHATTrue; +} + +CHATBool ciSocketConnect(ciSocket * sock, + const char * serverAddress, + int port) +{ + unsigned int ip; + HOSTENT * host; + SOCKADDR_IN address; + int rcode; + +#if !defined(INSOCK) && !defined(_NITRO) && !defined(_REVOLUTION) + int keepalive; +#endif + + ASSERT_SOCK(sock); + assert(serverAddress != NULL); + assert(port >= 0); + assert(port <= USHRT_MAX); + assert(sock->connectState == ciNotConnected); + + // Copy off the address. + //////////////////////// + strzcpy(sock->serverAddress, serverAddress, 255); + + // Try resolving the string as an IP a.b.c.d number. + //////////////////////////////////////////////////// + ip = inet_addr(serverAddress); + if(ip == INADDR_NONE) + { + // Try resolving with DNS. + ////////////////////////// + host = gethostbyname((char *)serverAddress); + if(host == NULL) + return CHATFalse; + + // Get the ip. + ////////////// + ip = *(unsigned int *)host->h_addr_list[0]; + } + + // Setup the address. + ///////////////////// + memset(&address, 0, sizeof(SOCKADDR_IN)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = ip; + address.sin_port = htons((unsigned short)port); + + // Create the socket. + ///////////////////// + sock->sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock->sock == INVALID_SOCKET) + return CHATFalse; + + // Enable keep-alive. + ///////////////////// +#if !defined(INSOCK) && !defined(_NITRO) && !defined(_REVOLUTION) + keepalive = 1; + rcode = setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(int)); + //assert(gsiSocketIsNotError(rcode)); +#endif + + // Try and connect. + /////////////////// + rcode = connect(sock->sock, (SOCKADDR *)&address, sizeof(SOCKADDR_IN)); + if(gsiSocketIsError(rcode)) + { + closesocket(sock->sock); + return CHATFalse; + } + + // We're connected. + /////////////////// + sock->connectState = ciConnected; + + return CHATTrue; +} + +void ciSocketDisconnect(ciSocket * sock) +{ + int i; + + ASSERT_SOCK(sock); + + // Shutdown the socket. + /////////////////////// + if(sock->sock != INVALID_SOCKET) + { + shutdown(sock->sock, 2); + closesocket(sock->sock); + } + + // We're disconnected. + ////////////////////// + sock->connectState = ciDisconnected; + + // gsifree the buffers. + //////////////////// + ciBufferFree(&sock->inputQueue); + ciBufferFree(&sock->outputQueue); + + // gsifree the last-message pointers. + ////////////////////////////////// + gsifree(sock->lastMessage.message); + gsifree(sock->lastMessage.server); + gsifree(sock->lastMessage.nick); + gsifree(sock->lastMessage.user); + gsifree(sock->lastMessage.host); + gsifree(sock->lastMessage.command); + gsifree(sock->lastMessage.middle); + gsifree(sock->lastMessage.param); + for(i = 0 ; i < sock->lastMessage.numParams ; i++) + gsifree(sock->lastMessage.params[i]); + gsifree(sock->lastMessage.params); +} + +static void ciSocketSelect(SOCKET sock, CHATBool * readFlag, CHATBool * writeFlag, CHATBool * exceptFlag) +{ + int aReadFlag = 0; + int aWriteFlag = 0; + int aExceptFlag = 0; + + // Call generic select GSISocketSelect + GSISocketSelect(sock, &aReadFlag, &aWriteFlag, &aExceptFlag); + + // Translate the int flags to ChatBool flags + if (readFlag) + *readFlag = (CHATBool)aReadFlag; + if (writeFlag) + *writeFlag = (CHATBool)aWriteFlag; + if (exceptFlag) + *exceptFlag = (CHATBool)aExceptFlag; +} + +static void ciSocketThinkSend(ciSocket * sock) +{ + int rcode; + int len; + + ASSERT_SOCK(sock); + ASSERT_CONNECTED(sock); + + // While there's data to send... + //////////////////////////////// + while(sock->outputQueue.length > 0) + { + CHATBool writeFlag; + + // Can we send? + /////////////// + ciSocketSelect(sock->sock, NULL, &writeFlag, NULL); + if(!writeFlag) + return; + + // Try and send some. + ///////////////////// + len = min(sock->outputQueue.length, 1024); + rcode = send(sock->sock, sock->outputQueue.buffer, len, 0); + + if(rcode == 0) + return; + if(gsiSocketIsError(rcode)) + return; //ERRCON + + // Update the output queue. + /////////////////////////// + ciBufferClipFront(&sock->outputQueue, rcode); + } +} + +static void ciSocketThinkRecv(ciSocket * sock) +{ + CHATBool readFlag; + int len; + int rcode; + char * pos; + + ASSERT_SOCK(sock); + ASSERT_CONNECTED(sock); + + while(CHATTrue) + { + // Check the read flag. + /////////////////////// + ciSocketSelect(sock->sock, &readFlag, NULL, NULL); + + // Nothing to read? + /////////////////// + if(!readFlag) + return; + + // Make sure the buffer is ready. + ///////////////////////////////// + if(!ciBufferPreAppend(&sock->inputQueue, RECV_LEN)) + return; //ERRCON + + // Recv into the buffer. + //////////////////////// + pos = &sock->inputQueue.buffer[sock->inputQueue.length]; + rcode = recv(sock->sock, pos, RECV_LEN, 0); + + // Connection closed? + ///////////////////// + if(rcode <= 0) //crt -- handle remote disconnections + { + sock->connectState = ciDisconnected; + return; + } + + // Set the number of bytes read. + //////////////////////////////// + len = rcode; + +#if 0 +{ + char * buffer; + int i; + buffer = (char *)gsimalloc(len + 2); + assert(buffer != NULL); + memcpy(buffer, &sock->inputQueue.buffer[sock->inputQueue.length], len); + buffer[len] = '\0'; + OutputDebugString("--->>>XXXRECV\n"); + for(i = 0 ; i < len ; i += 1023) + OutputDebugString(&buffer[i]); + OutputDebugString("<<<---XXXRECV\n"); +} +#endif + + // Decrypt data if the socket is secure. + //////////////////////////////////////// + if(sock->secure) + gs_crypt((unsigned char *)pos, len, &sock->inKey); + + // Update the buffer length. + //////////////////////////// + sock->inputQueue.length += len; + + // NUL terminate the buffer. + //////////////////////////// + sock->inputQueue.buffer[sock->inputQueue.length] = '\0'; + } +} + +void ciSocketThink(ciSocket * sock) +{ + ASSERT_SOCK(sock); + ASSERT_CONNECTED(sock); + + // Disconnected? + //////////////// + if(sock->connectState == ciDisconnected) + return; + + // Send any waiting data. + ///////////////////////// + ciSocketThinkSend(sock); + + // Recv any waiting data. + ///////////////////////// + ciSocketThinkRecv(sock); +} + +CHATBool ciSocketSend(ciSocket * sock, + const char * buffer) +{ +#ifdef IRC_LOG + FILE * log; +#endif + int len; + char * pos; + + ASSERT_SOCK(sock); + ASSERT_CONNECTED(sock); + assert(buffer != NULL); + + // Disconnected? + //////////////// + if(sock->connectState == ciDisconnected) + return CHATTrue; + + // Get the buffer length. + ///////////////////////// + len = (int)strlen(buffer); + + // Make sure the buffer is big enough. + ////////////////////////////////////// + if(!ciBufferPreAppend(&sock->outputQueue, len + 2)) + return CHATFalse; + + // Append to the output buffer. + /////////////////////////////// + pos = &sock->outputQueue.buffer[sock->outputQueue.length]; + memcpy(pos, buffer, (unsigned int)len); + + // Update the buffer length. + //////////////////////////// + sock->outputQueue.length += len; + + // Add the CRLF. + //////////////// + sock->outputQueue.buffer[sock->outputQueue.length++] = 0x0D; + sock->outputQueue.buffer[sock->outputQueue.length++] = 0x0A; + + // Encrypt data if the socket is secure. + //////////////////////////////////////// + if(sock->secure) + gs_crypt((unsigned char *)pos, len + 2, &sock->outKey); + +#ifdef IRC_LOG + // Write it to the log. + /////////////////////// + log = fopen(sock->filename, "at"); + if(log != NULL) + { + fprintf(log, "%s | OUT | %s\n", ciGetTime(), buffer); + fclose(log); + } +#endif + + return CHATTrue; +} + +CHATBool ciSocketSendf(ciSocket * sock, + const char * format, + ...) +{ + static char buffer[4096]; + int num; + va_list args; + + ASSERT_SOCK(sock); + ASSERT_CONNECTED(sock); + assert(buffer != NULL); + + // Disconnected? + //////////////// + if(sock->connectState == ciDisconnected) + return CHATTrue; + + // Do the formatting. + ///////////////////// + va_start(args, format); + num = vsprintf(buffer, format, args); + if(num != -1) + buffer[num] = '\0'; + else + buffer[sizeof(buffer) - 1] = '\0'; //ERRCON + + // Send. + //////// + return ciSocketSend(sock, buffer); +} + +static CHATBool ciParseUser(const char *pText, ciServerMessage * message) +{ + char *pTmpNick = NULL, *pTmpUsername = NULL, *pTmpHost = NULL; + int nNick = 0, nUsername = 0, nHost = 0; + char *p; + + if(pText == NULL || pText[0] == '\0') + { + assert(0); + return CHATFalse; //ERRCON + } + + p = pTmpNick = (char *)pText; + + while(*p != '\0') + { + if(*p != '!') + { + ++p; + ++nNick; + } + else + { + pTmpUsername = ++p; + + while(*p != '\0') + { + if(*p != '@') + { + ++p; + ++nUsername; + } + else + { + pTmpHost = ++p; + + while(*p != '\0') + { + ++p; + ++nHost; + } + } + } + } + } + + if(nNick) + { + message->nick = (char *)gsimalloc((unsigned int)nNick + 1); + + if(message->nick) + { + memcpy(message->nick, pTmpNick, (unsigned int)nNick); + message->nick[nNick] = '\0'; + } + } + else + message->nick = NULL; + + if(nUsername) + { + message->user = (char *)gsimalloc((unsigned int)nUsername + 1); + + if(message->user) + { + memcpy(message->user, pTmpUsername, (unsigned int)nUsername); + message->user[nUsername] = '\0'; + } + } + else + message->user = NULL; + + if(nHost) + { + message->host = (char *)gsimalloc((unsigned int)nHost + 1); + + if(message->host) + { + memcpy(message->host, pTmpHost, (unsigned int)nHost); + message->host[nHost] = '\0'; + } + } + else + message->host = NULL; + + return CHATTrue; +} + +static CHATBool ciAddParam(const char *param, ciServerMessage * message) +{ + void * tempPtr; + + // Reallocate the parameter array. + ////////////////////////////////// + tempPtr = gsirealloc(message->params, sizeof(char *) * (message->numParams + 1)); + if(tempPtr == NULL) + return CHATFalse; //ERRCON + message->params = (char **)tempPtr; + + // Allocate mem for the param. + ////////////////////////////// + tempPtr = gsimalloc(strlen(param) + 1); + if(tempPtr == NULL) + return CHATFalse; //ERRCON + + // Copy the param. + ////////////////// + strcpy((char *)tempPtr, param); + message->params[message->numParams++] = (char *)tempPtr; + + return CHATTrue; +} + +CHATBool ciParseParam(const char *pText, ciServerMessage * message) +{ + char * colon; + char * str; + char * p; + + assert(pText != NULL); + assert(message != NULL); + + // Copy off the text. + ///////////////////// + p = (char *)gsimalloc(strlen(pText) + 1); + if(p == NULL) + return CHATFalse; //ERRCON + strcpy(p, pText); + + // Find the colon. + ////////////////// + if(p[0] == ':') + { + p[0] = '\0'; + colon = &p[1]; + } + else + { + colon = strstr(p, " :"); + if(colon != NULL) + { + *colon = '\0'; + colon += 2; + } + } + + str = strtok(p, " "); + while(str != NULL) + { + // Add the param. + ///////////////// + if(!ciAddParam(str, message)) + { + gsifree(p); + return CHATFalse; //ERRCON + } + + // Get the next one. + //////////////////// + str = strtok(NULL, " "); + } + + if(colon != NULL) + { + // Add the last param. + ////////////////////// + if(!ciAddParam(colon, message)) + { + gsifree(p); + return CHATFalse; //ERRCON + } + } + + gsifree(p); + return CHATTrue; +} + +static CHATBool ciParseMessage(ciSocket * sock, const char *sText) +{ + // TRACE("ServM: Parse Data=%s\n", sText); + int nMessage = 0, nServer = 0, nCommand = 0, nMiddle = 0, nParam = 0; + char *p, *temp; + ciServerMessage * message = &sock->lastMessage; + + if(sText == NULL || sText[0] == '\0') + { + assert(0); + return CHATFalse; //ERRCON + } + + nMessage = (int)strlen(sText); + message->message = (char *)gsimalloc((unsigned int)nMessage + 1); + if(message->message == NULL) + return CHATFalse; //ERRCON + memcpy(message->message, sText, (unsigned int)nMessage); + message->message[nMessage] = '\0'; + + p = (char *)sText; + + while(*p == '\n' || *p == '\r') + ++p; + + if(*p == ':') + { // server + message->server = ++p; // ?? BUGBUG + + if(*p != '\0') + { + while(*p != ' ' && *p != '\0') + { + ++nServer; + ++p; + } + } + } + + while(*p == ' ') + // skip spaces + ++p; + + if(*p != '\0') + { // command + message->command = p; + + while(*p != ' ' && *p != '\0') + { + ++nCommand; + ++p; + } + } + + while(*p == ' ') + // skip spaces + ++p; + + if(*p != ':' && *p != '\0') + { // middle + message->middle = p; + + while(*p != ' ' && *p != '\0') + { + ++nMiddle; + ++p; + } + } + + while(*p == ' ') + // skip spaces + ++p; + + //if(*p == ':') + // params delimiter + // ++p; + + if(*p != '\0') + { // params + message->param = p; + + while(*p != '\0') + { + ++nParam; + ++p; + } + } + + if(nServer) + { + temp = message->server; + message->server = (char *)gsimalloc((unsigned int)nServer + 1); + + if(message->server) + { + memcpy(message->server, temp, (unsigned int)nServer); + message->server[nServer] = '\0'; + } + + if(!ciParseUser(message->server, message)) + { + RESET(message->message); + RESET(message->server); + return CHATFalse; //ERRCON + } + } + else + { + message->server = NULL; + message->nick = NULL; + message->user = NULL; + message->host = NULL; + } + + if(nMiddle) + { + if(!ciParseParam(message->middle, message)) + { + RESET(message->message); + RESET(message->server); + RESET(message->nick); + RESET(message->user); + RESET(message->host); + return CHATFalse; //ERRCON + } + } + else if(nParam) + { + if(!ciParseParam(message->param, message)) + { + RESET(message->message); + RESET(message->server); + RESET(message->nick); + RESET(message->user); + RESET(message->host); + return CHATFalse; //ERRCON + } + } + else + { + message->params = NULL; + message->numParams = 0; + } + + if(nParam) + { + temp = message->param; + message->param = (char *)gsimalloc((unsigned int)nParam + 1); + + if(message->param) + { + memcpy(message->param, temp, (unsigned int)nParam); + message->param[nParam] = '\0'; + } + } + else + { + message->param = NULL; + } + + if(nCommand) + { + temp = message->command; + message->command = (char *)gsimalloc((unsigned int)nCommand + 1); + + if(message->command) + { + memcpy(message->command, temp, (unsigned int)nCommand); + message->command[nCommand] = '\0'; + } + } + else + message->command = NULL; + + if(nMiddle) + { + temp = message->middle; + message->middle = (char *)gsimalloc((unsigned int)nMiddle + 1); + + if(message->middle) + { + memcpy(message->middle, temp, (unsigned int)nMiddle); + message->middle[nMiddle] = '\0'; + } + } + else + message->middle = NULL; + + return CHATTrue; +} + + +static CHATBool ciParseInput(ciSocket * sock) +{ + char *p, *q, *r; + char temp; + int i; + + p = sock->inputQueue.buffer; // start + + if(*p != '\0') + { + // eat all CRs & LFs + while(*p == 13 || *p == 10) + ++p; + + // end of string ? + if(*p != '\0') + { + r = q = p; + + // everything between last-nonspace char and CRLF should be discarded + while(*q != 10 && *q != 13 && *q != '\0') + { + if(*q != ' ') + r = q; + ++q; + } + + if(*q != '\0') + { + ++r; + temp = *r; + *r = '\0'; + + // gsifree the old message stuff. + ////////////////////////////// + RESET(sock->lastMessage.message); + RESET(sock->lastMessage.server); + RESET(sock->lastMessage.nick); + RESET(sock->lastMessage.user); + RESET(sock->lastMessage.host); + RESET(sock->lastMessage.command); + RESET(sock->lastMessage.middle); + RESET(sock->lastMessage.param); + for(i = 0 ; i < sock->lastMessage.numParams ; i++) + RESET(sock->lastMessage.params[i]); + RESET(sock->lastMessage.params); + sock->lastMessage.numParams = 0; + + // Parse the message. + ///////////////////// + memset(&sock->lastMessage,0,sizeof(sock->lastMessage)); + if(!ciParseMessage(sock, p)) + { + memset(&sock->lastMessage,0,sizeof(sock->lastMessage)); + return CHATFalse; //ERRCON + } + + // Restore the temp character. + ////////////////////////////// + *r = temp; + + // Take the message out of the buffer. + ////////////////////////////////////// + ciBufferClipFront(&sock->inputQueue, (q - sock->inputQueue.buffer)); + + return CHATTrue; + } + } + } + + return CHATFalse; +} + +ciServerMessage * ciSocketRecv(ciSocket * sock) +{ +#ifdef IRC_LOG + FILE * log; +#endif + ASSERT_SOCK(sock); + + // Bill: 08-10-04 + // There may be unprocessed messages in the queue + //if(sock->connectState == ciDisconnected) + // return NULL; + + // Check for an empty buffer. + ///////////////////////////// + if(sock->inputQueue.length == 0) + return NULL; + + // Check for a message. + /////////////////////// + if(!ciParseInput(sock)) + { + // No message. + ////////////// + return NULL; + } + +#ifdef IRC_LOG + // Write it to the log. + /////////////////////// + log = fopen(sock->filename, "at"); + if(log != NULL) + { + fprintf(log, "%s | IN | %s\n", ciGetTime(), sock->lastMessage.message); + fclose(log); + } +#endif + + // Got a message. + ///////////////// + return &sock->lastMessage; +} diff --git a/xrGameSpy/gamespy/Chat/chatSocket.h b/xrGameSpy/gamespy/Chat/chatSocket.h new file mode 100644 index 00000000000..fa955753090 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatSocket.h @@ -0,0 +1,96 @@ +/* +GameSpy Chat SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _CHATSOCKET_H_ +#define _CHATSOCKET_H_ + +/************* +** INCLUDES ** +*************/ +#include "chat.h" +#include "chatCrypt.h" + +/********** +** ENUMS ** +**********/ +typedef enum ciConnectState +{ + ciNotConnected, + ciConnected, + ciDisconnected +} ciConnectState; + +/********** +** TYPES ** +**********/ +typedef struct ciBuffer +{ + char * buffer; + int length; + int size; +} ciBuffer; + +typedef struct ciServerMessage +{ + char * message; + char * server; + char * nick; + char * user; + char * host; + char * command; + char * middle; + char * param; + char ** params; + int numParams; +} ciServerMessage; + +typedef struct ciSocket +{ + SOCKET sock; + ciConnectState connectState; + char serverAddress[256]; + + ciBuffer inputQueue; + ciBuffer outputQueue; + + CHATBool secure; + gs_crypt_key inKey; + gs_crypt_key outKey; + + ciServerMessage lastMessage; + +#ifdef IRC_LOG + char filename[FILENAME_MAX]; +#endif +} ciSocket; + +/************** +** FUNCTIONS ** +**************/ +CHATBool ciSocketInit(ciSocket * sock, const char * nick); + +CHATBool ciSocketConnect(ciSocket * sock, + const char * serverAddress, + int port); + +void ciSocketDisconnect(ciSocket * sock); + +void ciSocketThink(ciSocket * sock); + +CHATBool ciSocketSend(ciSocket * sock, + const char * buffer); + +CHATBool ciSocketSendf(ciSocket * sock, + const char * format, + ...); + +ciServerMessage * ciSocketRecv(ciSocket * sock); + +#endif diff --git a/xrGameSpy/gamespy/Chat/chat_vs2005.sln b/xrGameSpy/gamespy/Chat/chat_vs2005.sln new file mode 100644 index 00000000000..0d4b6a95554 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chat_vs2005.sln @@ -0,0 +1,47 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chatc_vs2005", "chatc\chatc_vs2005.vcproj", "{29EC5401-56BF-46BE-AC9B-E3AE68523798}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chatty_vs2005", "chatty\chatty_vs2005.vcproj", "{E6E425F1-DBD7-41B1-810A-1101C686BD2A}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 3 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = chatc\\chatc_vs2005.vcproj + SccProjectName1 = chatc + SccLocalPath1 = chatc + SccProjectUniqueName2 = chatty\\chatty_vs2005.vcproj + SccProjectName2 = chatty + SccLocalPath2 = chatty + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Debug|Win32.ActiveCfg = Debug|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Debug|Win32.Build.0 = Debug|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Release|Win32.ActiveCfg = Release|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Release|Win32.Build.0 = Release|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {29EC5401-56BF-46BE-AC9B-E3AE68523798}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Debug|Win32.ActiveCfg = Debug|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Debug|Win32.Build.0 = Debug|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Release|Win32.ActiveCfg = Release|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Release|Win32.Build.0 = Release|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {E6E425F1-DBD7-41B1-810A-1101C686BD2A}.Unicode Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Chat/chat_vs2005.vssscc b/xrGameSpy/gamespy/Chat/chat_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chat_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Chat/chatc/chatc.c b/xrGameSpy/gamespy/Chat/chatc/chatc.c new file mode 100644 index 00000000000..d95a6d60c32 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatc.c @@ -0,0 +1,552 @@ +// GameSpy Chat SDK C Test App +// Dan "Mr. Pants" Schoenblum +// dan@gamespy.com + +/************* +** INCLUDES ** +*************/ +#include "../chat.h" +#include "../../common/gsStringUtil.h" + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define MAX_MESSAGE_SIZE 200 +#define CHAT_NICK_SIZE 128 + +/************ +** GLOBALS ** +************/ +// mj Nov 7th, zero out to known state globals. +int port = 0; +CHAT chat = {0}; +gsi_char serverAddress[128] = {0}; +gsi_char chatNick[128] = {0}; +gsi_char chatUser[128] = {0}; +gsi_char chatName[128] = {0}; +gsi_char chatChannel[128] = {0}; +gsi_char gamename[128] = {0}; +gsi_char secretKey[128] = {0}; +CHATBool quit = CHATFalse; + +#ifdef __MWERKS__ // CodeWarrior will warn if functions not prototyped +/*************** +** PROTOTYPES ** +***************/ +int test_main(int argc, char **argv); +#endif + +/************** +** FUNCTIONS ** +**************/ +#ifdef GSI_UNICODE + #define _tstrcasecmp WideCaseCompare + #define _tstrncasecmp WideCaseNCompare +#else + #define _tstrcasecmp strcasecmp + #define _tstrncasecmp strncasecmp +#endif + +// Simulate case insensitive compare functions +#if defined(GSI_UNICODE) +int WideCaseCompare(const unsigned short* s1, const unsigned short* s2); +int WideCaseNCompare(const unsigned short* s1, const unsigned short* s2, size_t count); + +int WideCaseCompare(const unsigned short* s1, const unsigned short* s2) +{ + char s1_A[512]; + char s2_A[512]; + UCS2ToAsciiString(s1, s1_A); + UCS2ToAsciiString(s2, s2_A); + return strcasecmp(s1_A, s2_A); +} + +int WideCaseNCompare(const unsigned short* s1, const unsigned short* s2, size_t count) +{ + char s1_A[512]; + char s2_A[512]; + unsigned short temp[512]; + + // null terminate + temp[count+1] = 0; + + // Copy to temp buffer, then convert to ascii + memcpy(temp, s1, count * sizeof(unsigned short)); + UCS2ToAsciiString(temp, s1_A); + + memcpy(temp, s2, count * sizeof(unsigned short)); + UCS2ToAsciiString(temp, s2_A); + + return strncasecmp(s1_A, s2_A, count); +} + +#endif + + +static void Raw(CHAT chat, const gsi_char * raw, void * param) +{ + _tprintf(_T("RAW: %s\n"), raw); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void Disconnected(CHAT chat, const gsi_char * reason, void * param) +{ + _tprintf(_T("Disconnected: %s\n"), reason); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void ChangedNickCallback(CHAT chat, CHATBool success, const gsi_char * oldNick, const gsi_char * newNick, void * param) +{ + if(success) + { + _tprintf(_T("Successfully changed")); + _tcscpy(chatNick, newNick); + } + else + _tprintf(_T("Failed to change")); + _tprintf(_T(" nick from %s to %s\n"), oldNick, newNick); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void PrivateMessage(CHAT chat, const gsi_char * user, const gsi_char * message, int type, void * param) +{ + _tprintf(_T("Private message from %s: %s\n"), user, message); + + // Nick change? + /////////////// + if(_tstrncasecmp(_T("nick"), message, 4) == 0) + { + chatChangeNick(chat, &message[5], ChangedNickCallback, NULL, CHATFalse); + } + + GSI_UNUSED(type); + GSI_UNUSED(param); +} + +static void Invited(CHAT chat, const gsi_char * channel, const gsi_char * user, void * param) +{ + _tprintf(_T("Invited by %s to %s\n"), user, channel); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void ChannelMessage(CHAT chat, const gsi_char * channel, const gsi_char * user, const gsi_char * message, int type, void * param) +{ + gsi_char buffer[MAX_MESSAGE_SIZE]; + + _tprintf(_T("%s, in %s, said \"%s\"\n"), user, channel, message); + + // Is this from us? + /////////////////// + if(_tstrcasecmp(user, chatNick) == 0) + return; + + // Is it a command? + /////////////////// + if(message[0] == '!') + { + message++; + if(!_tstrcasecmp(message, _T("quit")) || !_tstrcasecmp(message, _T("exit"))) + quit = CHATTrue; + return; + } + _tsnprintf(buffer, MAX_MESSAGE_SIZE, _T("%s: I agree"), user); + buffer[MAX_MESSAGE_SIZE - 1] = '\0'; + chatSendChannelMessage(chat, channel, buffer, CHAT_MESSAGE); + + GSI_UNUSED(type); + GSI_UNUSED(param); +} + +static void Kicked(CHAT chat, const gsi_char * channel, const gsi_char * user, const gsi_char * reason, void * param) +{ + _tprintf(_T("Kicked from %s by %s: %s\n"), channel, user, reason); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void UserJoined(CHAT chat, const gsi_char * channel, const gsi_char * user, int mode, void * param) +{ + _tprintf(_T("%s joined %s"), user, channel); + + GSI_UNUSED(chat); + GSI_UNUSED(param); + GSI_UNUSED(mode); +} + +static void UserParted(CHAT chat, const gsi_char * channel, const gsi_char * user, int why, const gsi_char * reason, const gsi_char * kicker, void * param) +{ + if(why == CHAT_LEFT) + _tprintf(_T("%s left %s\n"), user, channel); + else if(why == CHAT_QUIT) + _tprintf(_T("%s quit: %s\n"), user, reason); + else if(why == CHAT_KICKED) + _tprintf(_T("%s was kicked from %s by %s: %s"), user, channel, kicker, reason); + else if(why == CHAT_KILLED) + _tprintf(_T("%s was killed: %s\n"), user, reason); + else + _tprintf(_T("UserParted() called with unknown part-type\n")); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void UserChangedNick(CHAT chat, const gsi_char * channel, const gsi_char * oldNick, const gsi_char * newNick, void * param) +{ + _tprintf(_T("%s changed nicks to %s\n"), oldNick, newNick); + + GSI_UNUSED(chat); + GSI_UNUSED(channel); + GSI_UNUSED(param); +} + +static void UserModeChanged(CHAT chat, const gsi_char * channel, const gsi_char * user, int mode, void * param) +{ + _tprintf(_T("%s's new mode in %s is "), user, channel);; + if(mode == CHAT_VOICE) + _tprintf(_T("voice\n")); + else if(mode == CHAT_OP) + _tprintf(_T("ops\n")); + else if(mode == (CHAT_VOICE | CHAT_OP)) + _tprintf(_T("voice+ops\n")); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void TopicChanged(CHAT chat, const gsi_char * channel, const gsi_char * topic, void * param) +{ + _tprintf(_T("The topic in %s changed to %s\n"), channel, topic); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void ChannelModeChanged(CHAT chat, const gsi_char * channel, CHATChannelMode * mode, void * param) +{ + _tprintf(_T("The mode in %s has changed:\n"), channel); + _tprintf(_T(" InviteOnly: %d\n"), mode->InviteOnly); + _tprintf(_T(" Private: %d\n"), mode->Private); + _tprintf(_T(" Secret: %d\n"), mode->Secret); + _tprintf(_T(" Moderated: %d\n"), mode->Moderated); + _tprintf(_T(" NoExternalMessages: %d\n"), mode->NoExternalMessages); + _tprintf(_T(" OnlyOpsChangeTopic: %d\n"), mode->OnlyOpsChangeTopic); + _tprintf(_T(" Limit: ")); + if(mode->Limit == 0) + _tprintf(_T("N/A\n")); + else + _tprintf(_T("%d\n"), mode->Limit); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +static void UserListUpdated(CHAT chat, const gsi_char * channel, void * param) +{ + _tprintf(_T("User list updated\n")); + + GSI_UNUSED(chat); + GSI_UNUSED(channel); + GSI_UNUSED(param); +} + +static void ConnectCallback(CHAT chat, CHATBool success, int failureReason, void * param) +{ + if (success == CHATFalse) + _tprintf(_T("Failed to connect (%d)\n"), failureReason); + else + _tprintf(_T("Connected\n")); + GSI_UNUSED(chat); + GSI_UNUSED(success); + GSI_UNUSED(param); +} + + +static void FillInUserCallback(CHAT chat, unsigned int IP, gsi_char user[128], void * param) +{ + _tcscpy(user, chatUser); + + GSI_UNUSED(chat); + GSI_UNUSED(IP); + GSI_UNUSED(param); +} + +static void NickErrorCallback(CHAT chat, int type, const gsi_char * nick, int numSuggestedNicks, const gsi_char ** suggestedNicks, void * param) +{ + if(type == CHAT_IN_USE) + { + _tprintf(_T("The nick %s is already being used.\n"), nick); + _tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time()); + chatNick[CHAT_NICK_SIZE - 1] = '\0'; + chatRetryWithNick(chat, chatNick); + } + else if(type == CHAT_INVALID) + { + _tprintf(_T("The nick %s is invalid!\n"), nick); + // chatDisconnect(chat); THIS CRASHES + + // 10-14-2004: Added By Saad Nader + // this is necessary as the function will fail if a new nick is not retries. + //////////////////////////////////////////////////////////////////////////// + _tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time()); + chatNick[CHAT_NICK_SIZE - 1] = '\0'; + chatRetryWithNick(chat, chatNick); + } + else if((type == CHAT_UNIQUENICK_EXPIRED) || (type == CHAT_NO_UNIQUENICK)) + { + _tprintf(_T("This account has no uniquenick or an expired uniquenick!\n")); + + chatRegisterUniqueNick(chat, 2, _T("MrPants"), _T("")); + } + else if(type == CHAT_INVALID_UNIQUENICK) + { + int i; + + _tprintf(_T("The uniquenick %s is invalid or in use\n"), nick); + _tprintf(_T("There are %d suggested nicks:\n"), numSuggestedNicks); + + for(i = 0 ; i < numSuggestedNicks ; i++) + _tprintf(_T(" %s\n"), suggestedNicks[i]); + } + + // 10-14-2004: Added By Saad Nader + // added for the addition of a new error code. + //////////////////////////////////////////////////////////////////////////// + else if(type == CHAT_NICK_TOO_LONG) + { + _tprintf(_T("The nick %s is too long.\n"), nick); + _tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time()); + chatNick[CHAT_NICK_SIZE - 1] = '\0'; + chatRetryWithNick(chat, chatNick); + } + GSI_UNUSED(param); +} + +CHATBool enterChannelSuccess; +static void EnterChannelCallback(CHAT chat, CHATBool success, CHATEnterResult result, const gsi_char * channel, void * param) +{ + enterChannelSuccess = success; + + GSI_UNUSED(chat); + GSI_UNUSED(result); + GSI_UNUSED(channel); + GSI_UNUSED(param); +} + +static void GetUserInfoCallback(CHAT chat, CHATBool success, const gsi_char * nick, const gsi_char * user, const gsi_char * name, const gsi_char * address, int numChannels, const gsi_char ** channels, void * param) +{ + int i; + + if(!success) + { + _tprintf(_T("GetUserInfo failed\n")); + return; + } + + _tprintf(_T("%s's Info:\n"), nick); + _tprintf(_T(" User: %s\n"), user); + _tprintf(_T(" Name: %s\n"), name); + _tprintf(_T(" Address: %s\n"), address); + _tprintf(_T(" Channels (%d):\n"), numChannels); + for(i = 0 ; i < numChannels ; i++) + _tprintf(_T(" %s\n"), channels[i]); + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} +/* +static void EnumChannelsAllCallback(CHAT chat, CHATBool success, int numChannels, const gsi_char ** channel, const gsi_char ** topic, int* numUsers, void * param) +{ + GSI_UNUSED(chat); + GSI_UNUSED(success); + GSI_UNUSED(numChannels); + GSI_UNUSED(channel); + GSI_UNUSED(topic); + GSI_UNUSED(numUsers); + GSI_UNUSED(param); +} +*/ +static void EnumUsersCallback(CHAT chat, CHATBool success, const gsi_char * channel, int numUsers, const gsi_char ** users, int * modes, void * param) +{ + int i; + + if(!success) + { + _tprintf(_T("EnumUsers failed\n")); + return; + } + + for(i = 0 ; i < numUsers ; i++) + chatGetUserInfo(chat, users[i], GetUserInfoCallback, NULL, CHATFalse); + + GSI_UNUSED(channel); + GSI_UNUSED(modes); + GSI_UNUSED(param); +} + +int test_main(int argc, char **argv) +{ + int i; + chatGlobalCallbacks globalCallbacks; + chatChannelCallbacks channelCallbacks; + unsigned long stopTime; + + + // Set default options. + /////////////////////// + // SDK takes care of default server address and port now + //_tcscpy(serverAddress, _T("peerchat." GSI_DOMAIN_NAME)); + //port = 6667; + _tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time() % 1000); + chatNick[CHAT_NICK_SIZE - 1] = '\0'; + _tcscpy(chatUser, _T("ChatCUser")); + _tcscpy(chatName, _T("ChatCName")); + _tcscpy(chatChannel, _T("#GSP!gmtest")); + _tcscpy(gamename, _T("gmtest")); + secretKey[0] = 'H'; + secretKey[1] = 'A'; + secretKey[2] = '6'; + secretKey[3] = 'z'; + secretKey[4] = 'k'; + secretKey[5] = 'S'; + secretKey[6] = '\0'; + + // Go through command-line options. + /////////////////////////////////// + for(i = 1 ; i < argc ; i++) + { + if((argv[i][0] == '-') && ((i + 1) < argc)) + { + switch(argv[i][1]) + { + case 's': +#ifndef GSI_UNICODE + strcpy(serverAddress, argv[++i]); +#else + AsciiToUCS2String(argv[++i], serverAddress); +#endif + break; + case 'p': + port = atoi(argv[++i]); + break; + case 'n': +#ifndef GSI_UNICODE + strcpy(chatNick, argv[++i]); +#else + AsciiToUCS2String(argv[++i], chatNick); +#endif + break; + case 'u': +#ifndef GSI_UNICODE + strcpy(chatUser, argv[++i]); +#else + AsciiToUCS2String(argv[++i], chatUser); +#endif + break; + case 'c': +#ifndef GSI_UNICODE + strcpy(chatChannel, argv[++i]); +#else + AsciiToUCS2String(argv[++i], chatChannel); +#endif + break; + default: + _tprintf(_T("Error parsing command-line: %s\n"), argv[i]); + return 1; + } + } + else + { + _tprintf(_T("Error parsing command-line: %s\n"), argv[i]); + return 1; + } + } + + // Set global callbacks. + //////////////////////// + memset(&globalCallbacks, 0, sizeof(chatGlobalCallbacks)); + globalCallbacks.raw = Raw; + globalCallbacks.disconnected = Disconnected; + globalCallbacks.privateMessage = PrivateMessage; + globalCallbacks.invited = Invited; + globalCallbacks.param = NULL; + + // Connect. + /////////// + chat = chatConnectSecure(serverAddress[0]?serverAddress:NULL, port, chatNick, chatName, gamename, secretKey, &globalCallbacks, NickErrorCallback, FillInUserCallback, ConnectCallback, NULL, CHATTrue); + if(!chat) + { + _tprintf(_T("Connect failed\n")); + return 1; + } + + // Set channel callbacks. + ///////////////////////// + memset(&channelCallbacks, 0, sizeof(chatChannelCallbacks)); + channelCallbacks.channelMessage = ChannelMessage; + channelCallbacks.channelModeChanged = ChannelModeChanged; + channelCallbacks.kicked = Kicked; + channelCallbacks.topicChanged = TopicChanged; + channelCallbacks.userParted = UserParted; + channelCallbacks.userJoined = UserJoined; + channelCallbacks.userListUpdated = UserListUpdated; + channelCallbacks.userModeChanged = UserModeChanged; + channelCallbacks.userChangedNick = UserChangedNick; + channelCallbacks.param = NULL; + + // Join. + //////// + chatEnterChannel(chat, chatChannel, NULL, &channelCallbacks, EnterChannelCallback, NULL, CHATTrue); + if(!enterChannelSuccess) + { + _tprintf(_T("Enter Channel failed\n")); + return 1; + } + + // Say hi. + ////////// + chatSendChannelMessage(chat, chatChannel, _T("Hi"), CHAT_MESSAGE); + + + // Enum through the players. + //////////////////////////// + chatEnumUsers(chat, chatChannel, EnumUsersCallback, NULL, CHATFalse); + + // Stay for a while. + //////////////////// + stopTime = (current_time() + 60000); + do + { + chatThink(chat); + msleep(50); + } + while(!quit && (current_time() < stopTime)); + + // Say bye. + /////////// + chatSendChannelMessage(chat, chatChannel, _T("Bye"), CHAT_MESSAGE); + + // Leave. + ///////// + chatLeaveChannel(chat, chatChannel, NULL); + + // Disconnect. + ////////////// + chatDisconnect(chat); + _tprintf(_T("All Done!\n")); + return 0; +} diff --git a/xrGameSpy/gamespy/Chat/chatc/chatc.dsp b/xrGameSpy/gamespy/Chat/chatc/chatc.dsp new file mode 100644 index 00000000000..3eb8937c5c8 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatc.dsp @@ -0,0 +1,319 @@ +# Microsoft Developer Studio Project File - Name="chatc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=chatc - Win32 Unicode 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 "chatc.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 "chatc.mak" CFG="chatc - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "chatc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "chatc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "chatc - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "chatc - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Chat/chatc", RRUAAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "chatc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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 wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "chatc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fr /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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 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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "chatc - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "chatc___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "chatc___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "GSI_UNICODE" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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 wsock32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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 wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "chatc - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "chatc___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "chatc___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "GSI_UNICODE" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 wsock32.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 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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "chatc - Win32 Release" +# Name "chatc - Win32 Debug" +# Name "chatc - Win32 Unicode Release" +# Name "chatc - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\chatc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Chat" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\chat.h +# End Source File +# Begin Source File + +SOURCE=..\chatCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\chatChannel.c +# End Source File +# Begin Source File + +SOURCE=..\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\chatCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\chatHandlers.c +# End Source File +# Begin Source File + +SOURCE=..\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\chatMain.c +# End Source File +# Begin Source File + +SOURCE=..\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\chatSocket.c +# End Source File +# Begin Source File + +SOURCE=..\chatSocket.h +# End Source File +# End Group +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Chat/chatc/chatc.vcproj b/xrGameSpy/gamespy/Chat/chatc/chatc.vcproj new file mode 100644 index 00000000000..713528f4e52 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatc.vcproj @@ -0,0 +1,508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatc.vcproj.vspscc b/xrGameSpy/gamespy/Chat/chatc/chatc.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatc.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Chat/chatc/chatc_vs2005.vcproj b/xrGameSpy/gamespy/Chat/chatc/chatc_vs2005.vcproj new file mode 100644 index 00000000000..707c6e0efdb --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatc_vs2005.vcproj @@ -0,0 +1,698 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatc_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Chat/chatc/chatc_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatc_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Chat/chatc/chatcrevolutioncw/chatcrevolution.mcp b/xrGameSpy/gamespy/Chat/chatc/chatcrevolutioncw/chatcrevolution.mcp new file mode 100644 index 00000000000..c045887126c Binary files /dev/null and b/xrGameSpy/gamespy/Chat/chatc/chatcrevolutioncw/chatcrevolution.mcp differ diff --git a/xrGameSpy/gamespy/Chat/chatc/chatlinux/Makefile b/xrGameSpy/gamespy/Chat/chatc/chatlinux/Makefile new file mode 100644 index 00000000000..88989ff7700 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatlinux/Makefile @@ -0,0 +1,53 @@ +# Chat SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=chatsdk + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../md5c.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../chatCrypt.o\ + ../../chatCallbacks.o\ + ../../chatChannel.o\ + ../../chatHandlers.o\ + ../../chatMain.o\ + ../../chatSocket.o\ + ../chatc.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatmacosx/Makefile b/xrGameSpy/gamespy/Chat/chatc/chatmacosx/Makefile new file mode 100644 index 00000000000..46a84f8bc38 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatmacosx/Makefile @@ -0,0 +1,27 @@ +# Chat SDK Makefile - Mac OS X +# Copyright 2006 GameSpy Industries + +PROJECT=chatc + +PROG_OBJS = \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../md5c.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../chatCallbacks.o\ + ../../chatCrypt.o\ + ../../chatChannel.o\ + ../../chatHandlers.o\ + ../../chatMain.o\ + ../../chatSocket.o\ + ../chatc.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/Nitro.lcf b/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/chatnitrocw.mcp b/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/chatnitrocw.mcp new file mode 100644 index 00000000000..372a6bac3df Binary files /dev/null and b/xrGameSpy/gamespy/Chat/chatc/chatnitrocw/chatnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps2/Makefile b/xrGameSpy/gamespy/Chat/chatc/chatps2/Makefile new file mode 100644 index 00000000000..88b81a84455 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps2/Makefile @@ -0,0 +1,30 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = chatc + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o \ + ../../../hashtable.o \ + ../../../md5c.o \ + ../../chatCrypt.o \ + ../../chatCallbacks.o \ + ../../chatMain.o \ + ../../chatHandlers.o \ + ../../chatSocket.o \ + ../../chatChannel.o \ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps2cw/chatps2cw.mcp b/xrGameSpy/gamespy/Chat/chatc/chatps2cw/chatps2cw.mcp new file mode 100644 index 00000000000..b002c91535f Binary files /dev/null and b/xrGameSpy/gamespy/Chat/chatc/chatps2cw/chatps2cw.mcp differ diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.dsp b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.dsp new file mode 100644 index 00000000000..45caf5bf94b --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.dsp @@ -0,0 +1,384 @@ +# Microsoft Developer Studio Project File - Name="chatps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=chatps2prodg - Win32 PS2 EE Release Insock +!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 "chatps2prodg.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 "chatps2prodg.mak" CFG="chatps2prodg - Win32 PS2 EE Release Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "chatps2prodg - Win32 PS2 EE Debug EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "chatps2prodg - Win32 PS2 EE Debug SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "chatps2prodg - Win32 PS2 EE Debug Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "chatps2prodg - Win32 PS2 EE Release EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "chatps2prodg - Win32 PS2 EE Release SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "chatps2prodg - Win32 PS2 EE Release Insock" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Chat/chatc/chatps2prodg", DSEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "chatps2prodg - Win32 PS2 EE Debug EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Debug EENet" +# PROP BASE Intermediate_Dir "PS2 EE Debug EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /I "C:\usr\local\sce\ee\include\libeenet" /D "SN_TARGET_PS2" /D "_DEBUG" /D "EENET" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\chatps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 ent_smap.a ent_eth.a ent_ppp.a eenetctl.a libeenet.a libcdvd.a libscf.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\chatps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "chatps2prodg - Win32 PS2 EE Debug SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Debug SNSystems" +# PROP BASE Intermediate_Dir "PS2 EE Debug SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "SN_SYSTEMS" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\chatps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\chatps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "chatps2prodg - Win32 PS2 EE Debug Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "chatps2prodg___Win32_PS2_EE_Debug_Insock" +# PROP BASE Intermediate_Dir "chatps2prodg___Win32_PS2_EE_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /I "C:\usr\local\sce\ee\include\libeenet" /D "SN_TARGET_PS2" /D "_DEBUG" /D "EENET" /FD /debug /c +# ADD CPP /nologo /W3 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "INSOCK" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 ent_smap.a ent_eth.a ent_ppp.a eenetctl.a libeenet.a libcdvd.a libscf.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\chatps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\chatps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "chatps2prodg - Win32 PS2 EE Release EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Release EENet" +# PROP BASE Intermediate_Dir "PS2 EE Release EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /I "C:\usr\local\sce\ee\include\libeenet" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\chatps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 ent_smap.a ent_eth.a ent_ppp.a eenetctl.a libeenet.a libcdvd.a libscf.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\chatps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "chatps2prodg - Win32 PS2 EE Release SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Release SNSystems" +# PROP BASE Intermediate_Dir "PS2 EE Release SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\chatps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\chatps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "chatps2prodg - Win32 PS2 EE Release Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "chatps2prodg___Win32_PS2_EE_Release_Insock" +# PROP BASE Intermediate_Dir "chatps2prodg___Win32_PS2_EE_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "chatps2prodg___Win32_PS2_EE_Release_Insock" +# PROP Intermediate_Dir "chatps2prodg___Win32_PS2_EE_Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "INSOCK" /Fo"Debug_Insock/" /Fd"Debug_Insock/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /Fo"Release_Insock/" /Fd"Release_Insock/" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\chatps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Release_Insock\chatps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "chatps2prodg - Win32 PS2 EE Debug EENet" +# Name "chatps2prodg - Win32 PS2 EE Debug SNSystems" +# Name "chatps2prodg - Win32 PS2 EE Debug Insock" +# Name "chatps2prodg - Win32 PS2 EE Release EENet" +# Name "chatps2prodg - Win32 PS2 EE Release SNSystems" +# Name "chatps2prodg - Win32 PS2 EE Release Insock" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\chatc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "ChatSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\chat.h +# End Source File +# Begin Source File + +SOURCE=..\..\chatCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\chatChannel.c +# End Source File +# Begin Source File + +SOURCE=..\..\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\..\chatCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\chatHandlers.c +# End Source File +# Begin Source File + +SOURCE=..\..\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\..\chatMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\chatSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\chatSocket.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.dsw b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.dsw new file mode 100644 index 00000000000..ec4a5ce56ca --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "chatps2prodg"=.\chatps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat/chatc/chatps2prodg", DSEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat/chatc/chatps2prodg", DSEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.sln b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.sln new file mode 100644 index 00000000000..e2f4e64038c --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.sln @@ -0,0 +1,41 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chatps2prodg", "chatps2prodg.vcproj", "{56504723-1052-4576-82A4-F29799ECA609}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 1 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = chatps2prodg.vcproj + SccProjectName0 = . + SccAuxPath0 = http://tfsapp1:8080 + SccLocalPath0 = . + SccProvider0 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {56504723-1052-4576-82A4-F29799ECA609}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {56504723-1052-4576-82A4-F29799ECA609}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.vcproj b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.vcproj new file mode 100644 index 00000000000..1fd0bd159c4 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps2prodg/chatps2prodg.vcproj @@ -0,0 +1,681 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps3/Makefile b/xrGameSpy/gamespy/Chat/chatc/chatps3/Makefile new file mode 100644 index 00000000000..b2c388eac92 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps3/Makefile @@ -0,0 +1,36 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = chatc + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../../hashtable.o \ + ../../../darray.o \ + ../../../md5c.o \ + ../../chatCrypt.o \ + ../../chatCallbacks.o \ + ../../chatMain.o \ + ../../chatHandlers.o \ + ../../chatSocket.o \ + ../../chatChannel.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps3prodg/chatps3prodg.sln b/xrGameSpy/gamespy/Chat/chatc/chatps3prodg/chatps3prodg.sln new file mode 100644 index 00000000000..bee2d586680 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps3prodg/chatps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chatps3prodg", "chatps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccProjectUniqueName0 = chatps3prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Chat/chatc/chatps3prodg/chatps3prodg.vcproj b/xrGameSpy/gamespy/Chat/chatc/chatps3prodg/chatps3prodg.vcproj new file mode 100644 index 00000000000..b3c6587e599 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatps3prodg/chatps3prodg.vcproj @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatpsp/Makefile b/xrGameSpy/gamespy/Chat/chatc/chatpsp/Makefile new file mode 100644 index 00000000000..bcab62ce990 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatpsp/Makefile @@ -0,0 +1,33 @@ +#GameSpy.net PSP Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +#SDK_LIBS = + +#Name of the SDK sample +TARGET = chatc + +#All the object files needed for this SDK +OBJS = ../../../common/psp/pspcommon.o\ + ../../../common/psp/gsUtilPSP.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../chatCallbacks.o\ + ../../chatChannel.o\ + ../../chatCrypt.o\ + ../../chatHandlers.o\ + ../../chatMain.o\ + ../../chatSocket.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/psp/Makefile.common + diff --git a/xrGameSpy/gamespy/Chat/chatc/chatpspprodg/chatpspprodg.sln b/xrGameSpy/gamespy/Chat/chatc/chatpspprodg/chatpspprodg.sln new file mode 100644 index 00000000000..bc746aa0f75 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatpspprodg/chatpspprodg.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chatpspprodg", "chatpspprodg.vcproj", "{68B8E20D-AA73-48B7-8E3A-7568A80A556E}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = chatpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {68B8E20D-AA73-48B7-8E3A-7568A80A556E}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {68B8E20D-AA73-48B7-8E3A-7568A80A556E}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {68B8E20D-AA73-48B7-8E3A-7568A80A556E}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {68B8E20D-AA73-48B7-8E3A-7568A80A556E}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {68B8E20D-AA73-48B7-8E3A-7568A80A556E}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {68B8E20D-AA73-48B7-8E3A-7568A80A556E}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Chat/chatc/chatpspprodg/chatpspprodg.vcproj b/xrGameSpy/gamespy/Chat/chatc/chatpspprodg/chatpspprodg.vcproj new file mode 100644 index 00000000000..820c73858c0 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatc/chatpspprodg/chatpspprodg.vcproj @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Chat/chatty/ChannelListDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/ChannelListDlg.cpp new file mode 100644 index 00000000000..4cb385d6713 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ChannelListDlg.cpp @@ -0,0 +1,164 @@ +// ChannelListDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "ChannelListDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChannelListDlg dialog + + +CChannelListDlg::CChannelListDlg(CWnd* pParent /*=NULL*/) + : CDialog(CChannelListDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CChannelListDlg) + m_filter = _T(""); + //}}AFX_DATA_INIT +} + + +void CChannelListDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CChannelListDlg) + DDX_Control(pDX, IDC_NUM, m_num); + DDX_Control(pDX, IDC_LIST, m_list); + DDX_Text(pDX, IDC_FILTER, m_filter); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CChannelListDlg, CDialog) + //{{AFX_MSG_MAP(CChannelListDlg) + ON_BN_CLICKED(ID_CHANNELS, OnChannels) + ON_BN_CLICKED(ID_USERS, OnUsers) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChannelListDlg message handlers + +void EnumChannelsCallbackEach(CHAT chat, CHATBool success, int index, const char * channel, const char * topic, int numUsers, void * param) +{ + if(success) + { + CChannelListDlg * dlg = (CChannelListDlg *)param; + + CListBox * list = &dlg->m_list; + + CString str; + str = channel; + str += " ("; + char buffer[16]; + itoa(numUsers, buffer, 10); + str += buffer; + str += "): "; + str += topic; + + list->AddString(str); + + char buf[16]; + itoa(index + 1, buf, 10); + dlg->m_num.SetWindowText(buf); + } + + GSI_UNUSED(chat); +} + +void EnumJoinedChannelsCallback(CHAT chat, + int index, + const char * channel, + void * param) +{ + CChannelListDlg * dlg = (CChannelListDlg *)param; + + CListBox * list = &dlg->m_list; + + CString str; + str = "IN: "; + str += channel; + str += " ("; + char buffer[16]; + itoa(index, buffer, 10); + str += buffer; + str += "): "; + list->AddString(str); + + GSI_UNUSED(chat); +} + +void EnumChannelsCallbackAll(CHAT chat, CHATBool success, int numChannels, const char ** channels, const char ** topics, int * numUsers, void * param) +{ + if(success) + { + CChannelListDlg * dlg = (CChannelListDlg *)param; + dlg->MessageBox("Search Complete"); + } + + GSI_UNUSED(numUsers); + GSI_UNUSED(topics); + GSI_UNUSED(channels); + GSI_UNUSED(numChannels); + GSI_UNUSED(chat); +} + +void ListUsers(CHAT chat, CHATBool success, const char * channel, int numUsers, const char ** users, int * modes, void * param) +{ + if(success) + { + CChannelListDlg * dlg = (CChannelListDlg *)param; + + CListBox * list = &dlg->m_list; + + CString str; + for(int i = 0 ; i < numUsers ; i++) + { + str = users[i]; + if(modes[i] & CHAT_OP) + str.Insert(0, '@'); + else if(modes[i] & CHAT_VOICE) + str.Insert(0, '?'); + + list->AddString(str); + } + + char buf[16]; + itoa(numUsers, buf, 10); + dlg->m_num.SetWindowText(buf); + } + + GSI_UNUSED(channel); + GSI_UNUSED(chat); +} + +void CChannelListDlg::OnChannels() +{ + // Clear the list. + ////////////////// + m_list.ResetContent(); + + // Get the list. + //////////////// + UpdateData(); + chatEnumJoinedChannels(theApp.m_chat, EnumJoinedChannelsCallback, this); + chatEnumChannels(theApp.m_chat, m_filter, EnumChannelsCallbackEach, EnumChannelsCallbackAll, this, CHATFalse); +} + +void CChannelListDlg::OnUsers() +{ + // Clear the list. + ////////////////// + m_list.ResetContent(); + + // Get the list. + //////////////// + UpdateData(); + chatEnumUsers(theApp.m_chat, m_filter, ListUsers, this, CHATFalse); +} diff --git a/xrGameSpy/gamespy/Chat/chatty/ChannelListDlg.h b/xrGameSpy/gamespy/Chat/chatty/ChannelListDlg.h new file mode 100644 index 00000000000..1322ca8f2b5 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ChannelListDlg.h @@ -0,0 +1,49 @@ +#if !defined(AFX_CHANNELLISTDLG_H__2D417F5B_EB62_4913_BB7A_6B20477ED21D__INCLUDED_) +#define AFX_CHANNELLISTDLG_H__2D417F5B_EB62_4913_BB7A_6B20477ED21D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ChannelListDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CChannelListDlg dialog + +class CChannelListDlg : public CDialog +{ +// Construction +public: + CChannelListDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CChannelListDlg) + enum { IDD = IDD_CHANNEL_LIST }; + CEdit m_num; + CListBox m_list; + CString m_filter; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChannelListDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CChannelListDlg) + afx_msg void OnChannels(); + afx_msg void OnUsers(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHANNELLISTDLG_H__2D417F5B_EB62_4913_BB7A_6B20477ED21D__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/ChannelModeDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/ChannelModeDlg.cpp new file mode 100644 index 00000000000..66d32f01756 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ChannelModeDlg.cpp @@ -0,0 +1,56 @@ +// ChannelModeDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "ChannelModeDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChannelModeDlg dialog + + +CChannelModeDlg::CChannelModeDlg(CWnd* pParent /*=NULL*/) + : CDialog(CChannelModeDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CChannelModeDlg) + m_inviteOnly = FALSE; + m_limit = 0; + m_moderated = FALSE; + m_noExternalMessages = FALSE; + m_onlyOpsChangeTopic = FALSE; + m_private = FALSE; + m_secret = FALSE; + //}}AFX_DATA_INIT +} + + +void CChannelModeDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CChannelModeDlg) + DDX_Check(pDX, IDC_INVITE_ONLY, m_inviteOnly); + DDX_Text(pDX, IDC_LIMIT, m_limit); + DDV_MinMaxInt(pDX, m_limit, 0, 9999); + DDX_Check(pDX, IDC_MODERATED, m_moderated); + DDX_Check(pDX, IDC_NO_EXTERNAL_MESSAGES, m_noExternalMessages); + DDX_Check(pDX, IDC_ONLY_OPS_CHANGE_TOPIC, m_onlyOpsChangeTopic); + DDX_Check(pDX, IDC_PRIVATE, m_private); + DDX_Check(pDX, IDC_SECRET, m_secret); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CChannelModeDlg, CDialog) + //{{AFX_MSG_MAP(CChannelModeDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChannelModeDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/ChannelModeDlg.h b/xrGameSpy/gamespy/Chat/chatty/ChannelModeDlg.h new file mode 100644 index 00000000000..16d001b1253 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ChannelModeDlg.h @@ -0,0 +1,52 @@ +#if !defined(AFX_CHANNELMODEDLG_H__87449420_C42C_11D3_BD38_00C0F056BC39__INCLUDED_) +#define AFX_CHANNELMODEDLG_H__87449420_C42C_11D3_BD38_00C0F056BC39__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ChannelModeDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CChannelModeDlg dialog + +class CChannelModeDlg : public CDialog +{ +// Construction +public: + CChannelModeDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CChannelModeDlg) + enum { IDD = IDD_CHANNEL_MODE }; + BOOL m_inviteOnly; + int m_limit; + BOOL m_moderated; + BOOL m_noExternalMessages; + BOOL m_onlyOpsChangeTopic; + BOOL m_private; + BOOL m_secret; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChannelModeDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CChannelModeDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHANNELMODEDLG_H__87449420_C42C_11D3_BD38_00C0F056BC39__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/ChildFrm.cpp b/xrGameSpy/gamespy/Chat/chatty/ChildFrm.cpp new file mode 100644 index 00000000000..4db2c1fbdb2 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ChildFrm.cpp @@ -0,0 +1,69 @@ +// ChildFrm.cpp : implementation of the CChildFrame class +// + +#include "stdafx.h" +#include "chatty.h" + +#include "ChildFrm.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame + +IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd) + +BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd) + //{{AFX_MSG_MAP(CChildFrame) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame construction/destruction + +CChildFrame::CChildFrame() +{ + // TODO: add member initialization code here + +} + +CChildFrame::~CChildFrame() +{ +} + +BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs + + if( !CMDIChildWnd::PreCreateWindow(cs) ) + return FALSE; + + return TRUE; +} + + + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame diagnostics + +#ifdef _DEBUG +void CChildFrame::AssertValid() const +{ + CMDIChildWnd::AssertValid(); +} + +void CChildFrame::Dump(CDumpContext& dc) const +{ + CMDIChildWnd::Dump(dc); +} + +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CChildFrame message handlers + diff --git a/xrGameSpy/gamespy/Chat/chatty/ChildFrm.h b/xrGameSpy/gamespy/Chat/chatty/ChildFrm.h new file mode 100644 index 00000000000..0ef4e246ec6 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ChildFrm.h @@ -0,0 +1,51 @@ +// ChildFrm.h : interface of the CChildFrame class +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CHILDFRM_H__CECBEADE_E41E_4FB6_93DD_C3735CFC4679__INCLUDED_) +#define AFX_CHILDFRM_H__CECBEADE_E41E_4FB6_93DD_C3735CFC4679__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +class CChildFrame : public CMDIChildWnd +{ + DECLARE_DYNCREATE(CChildFrame) +public: + CChildFrame(); + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChildFrame) + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CChildFrame(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +// Generated message map functions +protected: + //{{AFX_MSG(CChildFrame) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHILDFRM_H__CECBEADE_E41E_4FB6_93DD_C3735CFC4679__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/ConnectDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/ConnectDlg.cpp new file mode 100644 index 00000000000..e4ec8944be3 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ConnectDlg.cpp @@ -0,0 +1,47 @@ +// ConnectDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "ConnectDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CConnectDlg dialog + + +CConnectDlg::CConnectDlg(CWnd* pParent /*=NULL*/) + : CDialog(CConnectDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CConnectDlg) + m_address = _T(""); + m_nick = _T(""); + m_port = 0; + //}}AFX_DATA_INIT +} + + +void CConnectDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CConnectDlg) + DDX_Text(pDX, IDC_ADDRESS, m_address); + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_PORT, m_port); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CConnectDlg, CDialog) + //{{AFX_MSG_MAP(CConnectDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CConnectDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/ConnectDlg.h b/xrGameSpy/gamespy/Chat/chatty/ConnectDlg.h new file mode 100644 index 00000000000..427675b5261 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ConnectDlg.h @@ -0,0 +1,48 @@ +#if !defined(AFX_CONNECTDLG_H__999D9DD8_12B0_4F46_BF46_F607FB3341A0__INCLUDED_) +#define AFX_CONNECTDLG_H__999D9DD8_12B0_4F46_BF46_F607FB3341A0__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ConnectDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CConnectDlg dialog + +class CConnectDlg : public CDialog +{ +// Construction +public: + CConnectDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CConnectDlg) + enum { IDD = IDD_CONNECT }; + CString m_address; + CString m_nick; + int m_port; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CConnectDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CConnectDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CONNECTDLG_H__999D9DD8_12B0_4F46_BF46_F607FB3341A0__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/EnterDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/EnterDlg.cpp new file mode 100644 index 00000000000..24e1f215ecb --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/EnterDlg.cpp @@ -0,0 +1,74 @@ +// EnterDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "EnterDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CEnterDlg dialog + + +CEnterDlg::CEnterDlg(CWnd* pParent /*=NULL*/) + : CDialog(CEnterDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CEnterDlg) + m_channel = _T(""); + m_password = _T(""); + //}}AFX_DATA_INIT + + m_quickChannel = ""; +} + + +void CEnterDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CEnterDlg) + DDX_Text(pDX, IDC_CHANNEL, m_channel); + DDX_Text(pDX, IDC_PASSWORD, m_password); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CEnterDlg, CDialog) + //{{AFX_MSG_MAP(CEnterDlg) + ON_BN_CLICKED(IDC_QUICK1, OnQuick1) + ON_BN_CLICKED(IDC_QUICK2, OnQuick2) + ON_BN_CLICKED(IDC_QUICK3, OnQuick3) + ON_BN_CLICKED(IDC_QUICK4, OnQuick4) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CEnterDlg message handlers + +void CEnterDlg::OnQuick1() +{ + m_quickChannel = "#istanbul"; + OnOK(); +} + +void CEnterDlg::OnQuick2() +{ + m_quickChannel = "#montreal"; + OnOK(); +} + +void CEnterDlg::OnQuick3() +{ + m_quickChannel = "#pants-test"; + OnOK(); +} + +void CEnterDlg::OnQuick4() +{ + m_quickChannel = "#zurna"; + OnOK(); +} diff --git a/xrGameSpy/gamespy/Chat/chatty/EnterDlg.h b/xrGameSpy/gamespy/Chat/chatty/EnterDlg.h new file mode 100644 index 00000000000..0dd126a8f06 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/EnterDlg.h @@ -0,0 +1,52 @@ +#if !defined(AFX_ENTERDLG_H__56D121BA_9750_4FF9_AEA2_0CDAC1CB1DC2__INCLUDED_) +#define AFX_ENTERDLG_H__56D121BA_9750_4FF9_AEA2_0CDAC1CB1DC2__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// EnterDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CEnterDlg dialog + +class CEnterDlg : public CDialog +{ +// Construction +public: + CEnterDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CEnterDlg) + enum { IDD = IDD_ENTER }; + CString m_channel; + CString m_password; + //}}AFX_DATA + + CString m_quickChannel; + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CEnterDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CEnterDlg) + afx_msg void OnQuick1(); + afx_msg void OnQuick2(); + afx_msg void OnQuick3(); + afx_msg void OnQuick4(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ENTERDLG_H__56D121BA_9750_4FF9_AEA2_0CDAC1CB1DC2__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/GetUserInfoDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/GetUserInfoDlg.cpp new file mode 100644 index 00000000000..be0276b18ce --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/GetUserInfoDlg.cpp @@ -0,0 +1,80 @@ +// GetUserInfoDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "GetUserInfoDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CGetUserInfoDlg dialog + + +CGetUserInfoDlg::CGetUserInfoDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGetUserInfoDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CGetUserInfoDlg) + m_address = _T(""); + m_name = _T(""); + m_user = _T(""); + m_nick = _T(""); + //}}AFX_DATA_INIT +} + + +void CGetUserInfoDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGetUserInfoDlg) + DDX_Control(pDX, IDC_CHANNELS, m_channels); + DDX_Text(pDX, IDC_ADDRESS, m_address); + DDX_Text(pDX, IDC_NAME, m_name); + DDX_Text(pDX, IDC_USER, m_user); + DDX_Text(pDX, IDC_NICK, m_nick); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CGetUserInfoDlg, CDialog) + //{{AFX_MSG_MAP(CGetUserInfoDlg) + ON_BN_CLICKED(ID_GET_INFO, OnGetInfo) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGetUserInfoDlg message handlers + +void GetUserInfoCallback(CHAT chat, CHATBool success, const char * nick, const char * user, const char * name, const char * address, int numChannels, const char ** channels, void * param) +{ + CGetUserInfoDlg * dlg = (CGetUserInfoDlg *)param; + + if(success) + { + dlg->m_user = user; + dlg->m_name = name; + dlg->m_address = address; + dlg->UpdateData(FALSE); + dlg->m_channels.ResetContent(); + for(int i = 0 ; i < numChannels ; i++) + dlg->m_channels.AddString(channels[i]); + } + + dlg->MessageBox("done"); + + GSI_UNUSED(nick); + GSI_UNUSED(chat); +} + +void CGetUserInfoDlg::OnGetInfo() +{ + if(theApp.m_chat != NULL) + { + UpdateData(); + chatGetUserInfo(theApp.m_chat, m_nick, GetUserInfoCallback, this, CHATTrue); + } +} diff --git a/xrGameSpy/gamespy/Chat/chatty/GetUserInfoDlg.h b/xrGameSpy/gamespy/Chat/chatty/GetUserInfoDlg.h new file mode 100644 index 00000000000..1452927c8ea --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/GetUserInfoDlg.h @@ -0,0 +1,50 @@ +#if !defined(AFX_GETUSERINFODLG_H__600E8857_A5B5_41DF_973E_0A3DCCF0DCEB__INCLUDED_) +#define AFX_GETUSERINFODLG_H__600E8857_A5B5_41DF_973E_0A3DCCF0DCEB__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// GetUserInfoDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CGetUserInfoDlg dialog + +class CGetUserInfoDlg : public CDialog +{ +// Construction +public: + CGetUserInfoDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CGetUserInfoDlg) + enum { IDD = IDD_GET_USER_INFO }; + CListBox m_channels; + CString m_address; + CString m_name; + CString m_user; + CString m_nick; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGetUserInfoDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CGetUserInfoDlg) + afx_msg void OnGetInfo(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GETUSERINFODLG_H__600E8857_A5B5_41DF_973E_0A3DCCF0DCEB__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/KickReasonDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/KickReasonDlg.cpp new file mode 100644 index 00000000000..7d9f6cc9c03 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/KickReasonDlg.cpp @@ -0,0 +1,43 @@ +// KickReasonDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "KickReasonDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CKickReasonDlg dialog + + +CKickReasonDlg::CKickReasonDlg(CWnd* pParent /*=NULL*/) + : CDialog(CKickReasonDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CKickReasonDlg) + m_reason = _T(""); + //}}AFX_DATA_INIT +} + + +void CKickReasonDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CKickReasonDlg) + DDX_Text(pDX, IDC_REASON, m_reason); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CKickReasonDlg, CDialog) + //{{AFX_MSG_MAP(CKickReasonDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CKickReasonDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/KickReasonDlg.h b/xrGameSpy/gamespy/Chat/chatty/KickReasonDlg.h new file mode 100644 index 00000000000..07739d72d59 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/KickReasonDlg.h @@ -0,0 +1,46 @@ +#if !defined(AFX_KICKREASONDLG_H__25C49432_E9A9_4BEF_8C47_31F8DF889DF0__INCLUDED_) +#define AFX_KICKREASONDLG_H__25C49432_E9A9_4BEF_8C47_31F8DF889DF0__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// KickReasonDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CKickReasonDlg dialog + +class CKickReasonDlg : public CDialog +{ +// Construction +public: + CKickReasonDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CKickReasonDlg) + enum { IDD = IDD_KICK_REASON }; + CString m_reason; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CKickReasonDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CKickReasonDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_KICKREASONDLG_H__25C49432_E9A9_4BEF_8C47_31F8DF889DF0__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/MainFrm.cpp b/xrGameSpy/gamespy/Chat/chatty/MainFrm.cpp new file mode 100644 index 00000000000..3365da4e6ca --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/MainFrm.cpp @@ -0,0 +1,133 @@ +// MainFrm.cpp : implementation of the CMainFrame class +// + +#include "stdafx.h" +#include "chatty.h" + +#include "MainFrm.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame + +IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd) + +BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) + //{{AFX_MSG_MAP(CMainFrame) + ON_WM_CREATE() + ON_WM_TIMER() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +static UINT indicators[] = +{ + ID_SEPARATOR, // status line indicator + ID_INDICATOR_CAPS, + ID_INDICATOR_NUM, + ID_INDICATOR_SCRL, +}; + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame construction/destruction + +CMainFrame::CMainFrame() +{ + // TODO: add member initialization code here + +} + +CMainFrame::~CMainFrame() +{ +} + +int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) + return -1; + + if (!m_wndToolBar.CreateEx(this) || + !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) + { + TRACE0("Failed to create toolbar\n"); + return -1; // fail to create + } + if (!m_wndDlgBar.Create(this, IDR_MAINFRAME, + CBRS_ALIGN_TOP, AFX_IDW_DIALOGBAR)) + { + TRACE0("Failed to create dialogbar\n"); + return -1; // fail to create + } + + if (!m_wndReBar.Create(this) || + !m_wndReBar.AddBar(&m_wndToolBar) || + !m_wndReBar.AddBar(&m_wndDlgBar)) + { + TRACE0("Failed to create rebar\n"); + return -1; // fail to create + } + + if (!m_wndStatusBar.Create(this) || + !m_wndStatusBar.SetIndicators(indicators, + sizeof(indicators)/sizeof(UINT))) + { + TRACE0("Failed to create status bar\n"); + return -1; // fail to create + } + + // TODO: Remove this if you don't want tool tips + m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | + CBRS_TOOLTIPS | CBRS_FLYBY); + +/**************** +** TIMER SETUP ** +****************/ + SetTimer(50, 50, NULL); + + return 0; +} + +BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + if( !CMDIFrameWnd::PreCreateWindow(cs) ) + return FALSE; + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame diagnostics + +#ifdef _DEBUG +void CMainFrame::AssertValid() const +{ + CMDIFrameWnd::AssertValid(); +} + +void CMainFrame::Dump(CDumpContext& dc) const +{ + CMDIFrameWnd::Dump(dc); +} + +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame message handlers + + +void CMainFrame::OnTimer(UINT nIDEvent) +{ + if(nIDEvent == 50) + { + if(theApp.m_chat != NULL) + chatThink(theApp.m_chat); + } + + CMDIFrameWnd::OnTimer(nIDEvent); +} diff --git a/xrGameSpy/gamespy/Chat/chatty/MainFrm.h b/xrGameSpy/gamespy/Chat/chatty/MainFrm.h new file mode 100644 index 00000000000..2b869f7d887 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/MainFrm.h @@ -0,0 +1,58 @@ +// MainFrm.h : interface of the CMainFrame class +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_MAINFRM_H__501D21BC_112E_496A_A17B_FB30CD931AF1__INCLUDED_) +#define AFX_MAINFRM_H__501D21BC_112E_496A_A17B_FB30CD931AF1__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class CMainFrame : public CMDIFrameWnd +{ + DECLARE_DYNAMIC(CMainFrame) +public: + CMainFrame(); + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CMainFrame) + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CMainFrame(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: // control bar embedded members + CStatusBar m_wndStatusBar; + CToolBar m_wndToolBar; + CReBar m_wndReBar; + CDialogBar m_wndDlgBar; + +// Generated message map functions +protected: + //{{AFX_MSG(CMainFrame) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnTimer(UINT nIDEvent); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_MAINFRM_H__501D21BC_112E_496A_A17B_FB30CD931AF1__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/ReadMe.txt b/xrGameSpy/gamespy/Chat/chatty/ReadMe.txt new file mode 100644 index 00000000000..beade7a9bd8 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/ReadMe.txt @@ -0,0 +1,117 @@ +======================================================================== + MICROSOFT FOUNDATION CLASS LIBRARY : chatty +======================================================================== + + +AppWizard has created this chatty application for you. This application +not only demonstrates the basics of using the Microsoft Foundation classes +but is also a starting point for writing your application. + +This file contains a summary of what you will find in each of the files that +make up your chatty application. + +chatty.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +chatty.h + This is the main header file for the application. It includes other + project specific headers (including Resource.h) and declares the + CChattyApp application class. + +chatty.cpp + This is the main application source file that contains the application + class CChattyApp. + +chatty.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +chatty.clw + This file contains information used by ClassWizard to edit existing + classes or add new classes. ClassWizard also uses this file to store + information needed to create and edit message maps and dialog data + maps and to create prototype member functions. + +res\chatty.ico + This is an icon file, which is used as the application's icon. This + icon is included by the main resource file chatty.rc. + +res\chatty.rc2 + This file contains resources that are not edited by Microsoft + Visual C++. You should place all resources not editable by + the resource editor in this file. + + + +///////////////////////////////////////////////////////////////////////////// + +For the main frame window: + +MainFrm.h, MainFrm.cpp + These files contain the frame class CMainFrame, which is derived from + CMDIFrameWnd and controls all MDI frame features. + +res\Toolbar.bmp + This bitmap file is used to create tiled images for the toolbar. + The initial toolbar and status bar are constructed in the CMainFrame + class. Edit this toolbar bitmap using the resource editor, and + update the IDR_MAINFRAME TOOLBAR array in chatty.rc to add + toolbar buttons. +///////////////////////////////////////////////////////////////////////////// + +For the child frame window: + +ChildFrm.h, ChildFrm.cpp + These files define and implement the CChildFrame class, which + supports the child windows in an MDI application. + +///////////////////////////////////////////////////////////////////////////// + +AppWizard creates one document type and one view: + +chattyDoc.h, chattyDoc.cpp - the document + These files contain your CChattyDoc class. Edit these files to + add your special document data and to implement file saving and loading + (via CChattyDoc::Serialize). + +chattyView.h, chattyView.cpp - the view of the document + These files contain your CChattyView class. + CChattyView objects are used to view CChattyDoc objects. + +res\chattyDoc.ico + This is an icon file, which is used as the icon for MDI child windows + for the CChattyDoc class. This icon is included by the main + resource file chatty.rc. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named chatty.pch and a precompiled types file named StdAfx.obj. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +If your application uses MFC in a shared DLL, and your application is +in a language other than the operating system's current language, you +will need to copy the corresponding localized resources MFC42XXX.DLL +from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, +and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. +For example, MFC42DEU.DLL contains resources translated to German.) If you +don't do this, some of the UI elements of your application will remain in the +language of the operating system. + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Chat/chatty/SendRawDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/SendRawDlg.cpp new file mode 100644 index 00000000000..7646f14e418 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/SendRawDlg.cpp @@ -0,0 +1,43 @@ +// SendRawDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "SendRawDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSendRawDlg dialog + + +CSendRawDlg::CSendRawDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSendRawDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSendRawDlg) + m_raw = _T(""); + //}}AFX_DATA_INIT +} + + +void CSendRawDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSendRawDlg) + DDX_Text(pDX, IDC_RAW, m_raw); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSendRawDlg, CDialog) + //{{AFX_MSG_MAP(CSendRawDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSendRawDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/SendRawDlg.h b/xrGameSpy/gamespy/Chat/chatty/SendRawDlg.h new file mode 100644 index 00000000000..7723f3cf526 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/SendRawDlg.h @@ -0,0 +1,46 @@ +#if !defined(AFX_SENDRAWDLG_H__543BE7A8_4BE8_4ED0_972D_2339364077F6__INCLUDED_) +#define AFX_SENDRAWDLG_H__543BE7A8_4BE8_4ED0_972D_2339364077F6__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SendRawDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSendRawDlg dialog + +class CSendRawDlg : public CDialog +{ +// Construction +public: + CSendRawDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSendRawDlg) + enum { IDD = IDD_SEND_RAW }; + CString m_raw; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSendRawDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CSendRawDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SENDRAWDLG_H__543BE7A8_4BE8_4ED0_972D_2339364077F6__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/SetPasswordDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/SetPasswordDlg.cpp new file mode 100644 index 00000000000..32630d1b784 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/SetPasswordDlg.cpp @@ -0,0 +1,45 @@ +// SetPasswordDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "SetPasswordDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSetPasswordDlg dialog + + +CSetPasswordDlg::CSetPasswordDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSetPasswordDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSetPasswordDlg) + m_password = _T(""); + m_enable = FALSE; + //}}AFX_DATA_INIT +} + + +void CSetPasswordDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSetPasswordDlg) + DDX_Text(pDX, IDC_PASSWORD, m_password); + DDX_Check(pDX, IDC_ENABLE, m_enable); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSetPasswordDlg, CDialog) + //{{AFX_MSG_MAP(CSetPasswordDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSetPasswordDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/SetPasswordDlg.h b/xrGameSpy/gamespy/Chat/chatty/SetPasswordDlg.h new file mode 100644 index 00000000000..95736f82a8b --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/SetPasswordDlg.h @@ -0,0 +1,47 @@ +#if !defined(AFX_SETPASSWORDDLG_H__666C66DA_E10E_420D_954E_FB2BCE01D798__INCLUDED_) +#define AFX_SETPASSWORDDLG_H__666C66DA_E10E_420D_954E_FB2BCE01D798__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SetPasswordDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSetPasswordDlg dialog + +class CSetPasswordDlg : public CDialog +{ +// Construction +public: + CSetPasswordDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSetPasswordDlg) + enum { IDD = IDD_SET_PASSWORD }; + CString m_password; + BOOL m_enable; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSetPasswordDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CSetPasswordDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SETPASSWORDDLG_H__666C66DA_E10E_420D_954E_FB2BCE01D798__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/SetTopicDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/SetTopicDlg.cpp new file mode 100644 index 00000000000..496c2ef49e7 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/SetTopicDlg.cpp @@ -0,0 +1,43 @@ +// SetTopicDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "SetTopicDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSetTopicDlg dialog + + +CSetTopicDlg::CSetTopicDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSetTopicDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSetTopicDlg) + m_topic = _T(""); + //}}AFX_DATA_INIT +} + + +void CSetTopicDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSetTopicDlg) + DDX_Text(pDX, IDC_TOPIC, m_topic); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSetTopicDlg, CDialog) + //{{AFX_MSG_MAP(CSetTopicDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSetTopicDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/SetTopicDlg.h b/xrGameSpy/gamespy/Chat/chatty/SetTopicDlg.h new file mode 100644 index 00000000000..26a91465295 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/SetTopicDlg.h @@ -0,0 +1,46 @@ +#if !defined(AFX_SETTOPICDLG_H__15C72001_C3D8_11D3_BD38_00C0F056BC39__INCLUDED_) +#define AFX_SETTOPICDLG_H__15C72001_C3D8_11D3_BD38_00C0F056BC39__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SetTopicDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSetTopicDlg dialog + +class CSetTopicDlg : public CDialog +{ +// Construction +public: + CSetTopicDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSetTopicDlg) + enum { IDD = IDD_SET_TOPIC }; + CString m_topic; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSetTopicDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CSetTopicDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SETTOPICDLG_H__15C72001_C3D8_11D3_BD38_00C0F056BC39__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/StdAfx.cpp b/xrGameSpy/gamespy/Chat/chatty/StdAfx.cpp new file mode 100644 index 00000000000..b92833be553 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// chatty.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/Chat/chatty/StdAfx.h b/xrGameSpy/gamespy/Chat/chatty/StdAfx.h new file mode 100644 index 00000000000..11ae4416a24 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/StdAfx.h @@ -0,0 +1,31 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__4CAB521F_F4DE_4629_A857_08E96E0C89E8__INCLUDED_) +#define AFX_STDAFX_H__4CAB521F_F4DE_4629_A857_08E96E0C89E8__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC socket extensions +#include + +#include "../chat.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__4CAB521F_F4DE_4629_A857_08E96E0C89E8__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/TalkDlg.cpp b/xrGameSpy/gamespy/Chat/chatty/TalkDlg.cpp new file mode 100644 index 00000000000..954629745d7 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/TalkDlg.cpp @@ -0,0 +1,45 @@ +// TalkDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "chatty.h" +#include "TalkDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTalkDlg dialog + + +CTalkDlg::CTalkDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTalkDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTalkDlg) + m_message = _T(""); + m_type = -1; + //}}AFX_DATA_INIT +} + + +void CTalkDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTalkDlg) + DDX_Text(pDX, IDC_MESSAGE, m_message); + DDX_Radio(pDX, IDC_NORMAL, m_type); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTalkDlg, CDialog) + //{{AFX_MSG_MAP(CTalkDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTalkDlg message handlers diff --git a/xrGameSpy/gamespy/Chat/chatty/TalkDlg.h b/xrGameSpy/gamespy/Chat/chatty/TalkDlg.h new file mode 100644 index 00000000000..e7af85f270e --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/TalkDlg.h @@ -0,0 +1,47 @@ +#if !defined(AFX_TALKDLG_H__87449421_C42C_11D3_BD38_00C0F056BC39__INCLUDED_) +#define AFX_TALKDLG_H__87449421_C42C_11D3_BD38_00C0F056BC39__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TalkDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CTalkDlg dialog + +class CTalkDlg : public CDialog +{ +// Construction +public: + CTalkDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CTalkDlg) + enum { IDD = IDD_TALK }; + CString m_message; + int m_type; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTalkDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CTalkDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TALKDLG_H__87449421_C42C_11D3_BD38_00C0F056BC39__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/chatty.cpp b/xrGameSpy/gamespy/Chat/chatty/chatty.cpp new file mode 100644 index 00000000000..a76f8823f41 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chatty.cpp @@ -0,0 +1,377 @@ +// chatty.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "chatty.h" + +#include "MainFrm.h" +#include "ChildFrm.h" +#include "chattyDoc.h" +#include "chattyView.h" +#include "ConnectDlg.h" +#include "ChannelListDlg.h" +#include "SendRawDlg.h" +#include "GetUserInfoDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChattyApp + +BEGIN_MESSAGE_MAP(CChattyApp, CWinApp) + //{{AFX_MSG_MAP(CChattyApp) + ON_COMMAND(ID_APP_ABOUT, OnAppAbout) + ON_COMMAND(ID_FILE_CONNECT, OnFileConnect) + ON_COMMAND(ID_FILE_DISCONNECT, OnFileDisconnect) + ON_COMMAND(ID_FILE_LISTCHANNELS, OnFileListchannels) + ON_COMMAND(ID_FILE_SENDRAW, OnFileSendraw) + ON_COMMAND(ID_FILE_GETUSERINFO, OnFileGetuserinfo) + ON_COMMAND(ID_FILE_SILENCE, OnFileSilence) + ON_COMMAND(ID_FILE_UNSILENCE, OnFileUnsilence) + //}}AFX_MSG_MAP + // Standard file based document commands + ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) + ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChattyApp construction + +CChattyApp::CChattyApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance + m_chat = NULL; + m_connected = false; +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CChattyApp object + +CChattyApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CChattyApp initialization + +BOOL CChattyApp::InitInstance() +{ + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + // Change the registry key under which our settings are stored. + // TODO: You should modify this string to be something appropriate + // such as the name of your company or organization. + SetRegistryKey(_T("GameSpy")); + + LoadStdProfileSettings(0); // Load standard INI file options (including MRU) + + // Register the application's document templates. Document templates + // serve as the connection between documents, frame windows and views. + + CMultiDocTemplate* pDocTemplate; + pDocTemplate = new CMultiDocTemplate( + IDR_CHATTYTYPE, + RUNTIME_CLASS(CChattyDoc), + RUNTIME_CLASS(CChildFrame), // custom MDI child frame + RUNTIME_CLASS(CChattyView)); + AddDocTemplate(pDocTemplate); + + // create main MDI Frame window + CMainFrame* pMainFrame = new CMainFrame; + if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) + return FALSE; + m_pMainWnd = pMainFrame; + + // Parse command line for standard shell commands, DDE, file open + // Removed for VS .NET + /* + CCommandLineInfo cmdInfo; + cmdInfo.m_nShellCommand = CCommandLineInfo.FileNothing; + ParseCommandLine(cmdInfo); + + // Dispatch commands specified on the command line + if (!ProcessShellCommand(cmdInfo)) + return FALSE; + */ + // The main window has been initialized, so show and update it. + pMainFrame->ShowWindow(m_nCmdShow); + pMainFrame->UpdateWindow(); + + return TRUE; +} + + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// Dialog Data + //{{AFX_DATA(CAboutDlg) + enum { IDD = IDD_ABOUTBOX }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CAboutDlg) + // No message handlers + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +// App command to run the dialog +void CChattyApp::OnAppAbout() +{ + CAboutDlg aboutDlg; + aboutDlg.DoModal(); +} + +///////////////////////////////////////////////////////////////////////////// +// CChattyApp message handlers + +/********************* +** GLOBAL CALLBACKS ** +*********************/ +void Raw(CHAT chat, const char * raw, void * param) +{ + GSI_UNUSED(chat); + GSI_UNUSED(raw); + GSI_UNUSED(param); +} + +void Disconnected(CHAT chat, const char * reason, void * param) +{ + OutputDebugString("Disconnected called\n"); + char buffer[256]; + + sprintf(buffer, "You have been disconnected: %s", reason); + theApp.m_pActiveWnd->MessageBox(buffer); + + //chatDisconnect(theApp.m_chat); + theApp.m_chat = NULL; + + GSI_UNUSED(chat); + GSI_UNUSED(param); +} + +void PrivateMessage(CHAT chat, const char * user, const char * message, int type, void * param) +{ + OutputDebugString("PrivateMessage called\n"); +#ifdef FEEDBACK + CString str = user; + str.MakeLower(); + + // Ignore of this is from a server. + /////////////////////////////////// + if(strstr(str, ".org") || strstr(str, ".net") || strstr(str, ".com")) + return; + + char buffer[256]; + + sprintf(buffer, "%s: %s", user, message); + if(type == CHAT_ACTION) + strcat(buffer, ""); + else if(type == CHAT_NOTICE) + strcat(buffer, ""); + theApp.m_pActiveWnd->MessageBox(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(type); + GSI_UNUSED(message); + GSI_UNUSED(user); + GSI_UNUSED(chat); +} + +void Invited(CHAT chat, const char * channel, const char * user, void * param) +{ + OutputDebugString("Invited called\n"); +#ifdef FEEDBACK + char buffer[256]; + + sprintf(buffer, "%s has invited you to join %s", user, channel); + theApp.m_pActiveWnd->MessageBox(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(user); + GSI_UNUSED(channel); + GSI_UNUSED(chat); +} + +void NickErrorCallback(CHAT chat, int type, const char * nick, int numSuggestedNicks, const char ** suggestedNicks, void * param) +{ + OutputDebugString("NickErrorCallback called\n"); + + // Try a new nick. + ////////////////// + chatRetryWithNick(chat, "testnick"); + + GSI_UNUSED(param); + GSI_UNUSED(suggestedNicks); + GSI_UNUSED(numSuggestedNicks); + GSI_UNUSED(nick); + GSI_UNUSED(type); +} + +void ConnectCallback(CHAT chat, CHATBool success, int failureReason, void * param) +{ + OutputDebugString("ConnectCallback called\n"); + if(success) + { + theApp.m_pMainWnd->MessageBox("Connected!"); + theApp.m_connected = true; + } + else + { + theApp.m_pMainWnd->MessageBox("Connect Failed!"); + theApp.m_connected = false; + } + + GSI_UNUSED(param); + GSI_UNUSED(failureReason); + GSI_UNUSED(chat); +} + +void CChattyApp::OnFileConnect() +{ + if(m_chat == NULL) + { + CConnectDlg dlg; + dlg.m_nick = "Pants"; + dlg.m_address = "peerchat." GSI_DOMAIN_NAME; + //dlg.m_address = "baltimore.md.us.undernet.org"; + //dlg.m_address = "saltlake.ut.us.undernet.org"; + dlg.m_port = 6667; + + if(dlg.DoModal() == IDOK) + { + chatGlobalCallbacks callbacks; + memset(&callbacks, 0, sizeof(chatGlobalCallbacks)); + callbacks.raw = Raw; + callbacks.disconnected = Disconnected; + callbacks.privateMessage = PrivateMessage; + callbacks.invited = Invited; + + m_chat = chatConnect(dlg.m_address, dlg.m_port, dlg.m_nick, "pants", "pants", &callbacks, NickErrorCallback, ConnectCallback, this, CHATTrue); + + // Check for a NULL chat object. + // PANTS|05.15.2000 + //////////////////////////////// + if(!m_chat) + MessageBox(NULL, "chatConnect() failed", NULL, MB_OK); + } + } +} + +void CChattyApp::OnFileDisconnect() +{ + if(m_chat != NULL) + { + chatDisconnect(m_chat); + + m_chat = NULL; + } +} + +int CChattyApp::ExitInstance() +{ + if(m_chat != NULL) + { + chatDisconnect(m_chat); + + m_chat = NULL; + } + + return CWinApp::ExitInstance(); +} + +void CChattyApp::OnFileListchannels() +{ + if(theApp.m_chat != NULL) + { + CChannelListDlg dlg; + dlg.DoModal(); + } +} + +void CChattyApp::OnFileSendraw() +{ + if(theApp.m_chat != NULL) + { + CSendRawDlg dlg; + if(dlg.DoModal() == IDOK) + { + chatSendRaw(theApp.m_chat, dlg.m_raw); + } + } +} + +void CChattyApp::OnFileGetuserinfo() +{ + if(theApp.m_chat != NULL) + { + CGetUserInfoDlg dlg; + dlg.DoModal(); + } +} + +void CChattyApp::OnFileSilence() +{ + if(theApp.m_chat != NULL) + chatSetQuietMode(theApp.m_chat, CHATTrue); +} + +void CChattyApp::OnFileUnsilence() +{ + if(theApp.m_chat != NULL) + chatSetQuietMode(theApp.m_chat, CHATFalse); +} diff --git a/xrGameSpy/gamespy/Chat/chatty/chatty.dsp b/xrGameSpy/gamespy/Chat/chatty/chatty.dsp new file mode 100644 index 00000000000..c6546ea74dd --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chatty.dsp @@ -0,0 +1,439 @@ +# Microsoft Developer Studio Project File - Name="chatty" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=chatty - 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 "chatty.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 "chatty.mak" CFG="chatty - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "chatty - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "chatty - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Chat/chatty", ELLAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "chatty - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "chatty - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"LIBCD" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "chatty - Win32 Release" +# Name "chatty - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ChannelListDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChannelModeDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\chatty.cpp +# End Source File +# Begin Source File + +SOURCE=.\chatty.rc +# End Source File +# Begin Source File + +SOURCE=.\chattyDoc.cpp +# End Source File +# Begin Source File + +SOURCE=.\chattyView.cpp +# End Source File +# Begin Source File + +SOURCE=.\ChildFrm.cpp +# End Source File +# Begin Source File + +SOURCE=.\ConnectDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnterDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\GetUserInfoDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\KickReasonDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\MainFrm.cpp +# End Source File +# Begin Source File + +SOURCE=.\SendRawDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\SetPasswordDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\SetTopicDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\TalkDlg.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ChannelListDlg.h +# End Source File +# Begin Source File + +SOURCE=.\ChannelModeDlg.h +# End Source File +# Begin Source File + +SOURCE=.\chatty.h +# End Source File +# Begin Source File + +SOURCE=.\chattyDoc.h +# End Source File +# Begin Source File + +SOURCE=.\chattyView.h +# End Source File +# Begin Source File + +SOURCE=.\ChildFrm.h +# End Source File +# Begin Source File + +SOURCE=.\ConnectDlg.h +# End Source File +# Begin Source File + +SOURCE=.\EnterDlg.h +# End Source File +# Begin Source File + +SOURCE=.\GetUserInfoDlg.h +# End Source File +# Begin Source File + +SOURCE=.\KickReasonDlg.h +# End Source File +# Begin Source File + +SOURCE=.\MainFrm.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\SendRawDlg.h +# End Source File +# Begin Source File + +SOURCE=.\SetPasswordDlg.h +# End Source File +# Begin Source File + +SOURCE=.\SetTopicDlg.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\TalkDlg.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\chatty.ico +# End Source File +# Begin Source File + +SOURCE=.\res\chatty.rc2 +# End Source File +# Begin Source File + +SOURCE=.\res\chattyDoc.ico +# End Source File +# Begin Source File + +SOURCE=.\res\Toolbar.bmp +# End Source File +# End Group +# Begin Group "Chat" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\chat.h +# End Source File +# Begin Source File + +SOURCE=..\chatCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\chatChannel.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\chatCrypt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\chatHandlers.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\chatMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\chatSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\chatSocket.h +# End Source File +# End Group +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Chat/chatty/chatty.h b/xrGameSpy/gamespy/Chat/chatty/chatty.h new file mode 100644 index 00000000000..3d74cd6c275 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chatty.h @@ -0,0 +1,59 @@ +// chatty.h : main header file for the CHATTY application +// + +#if !defined(AFX_CHATTY_H__D2C88C24_CA2E_4ED3_B08E_BF48F6C0A36B__INCLUDED_) +#define AFX_CHATTY_H__D2C88C24_CA2E_4ED3_B08E_BF48F6C0A36B__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CChattyApp: +// See chatty.cpp for the implementation of this class +// + +class CChattyApp : public CWinApp +{ +public: + CChattyApp(); + + CHAT m_chat; + bool m_connected; + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChattyApp) + public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + //}}AFX_VIRTUAL + +// Implementation + //{{AFX_MSG(CChattyApp) + afx_msg void OnAppAbout(); + afx_msg void OnFileConnect(); + afx_msg void OnFileDisconnect(); + afx_msg void OnFileListchannels(); + afx_msg void OnFileSendraw(); + afx_msg void OnFileGetuserinfo(); + afx_msg void OnFileSilence(); + afx_msg void OnFileUnsilence(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +extern CChattyApp theApp; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHATTY_H__D2C88C24_CA2E_4ED3_B08E_BF48F6C0A36B__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/chatty.rc b/xrGameSpy/gamespy/Chat/chatty/chatty.rc new file mode 100644 index 00000000000..a71806faf7b --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chatty.rc @@ -0,0 +1,737 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\chatty.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\chatty.ico" +IDR_CHATTYTYPE ICON DISCARDABLE "res\\chattyDoc.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDR_MAINFRAME BITMAP MOVEABLE PURE "res\\Toolbar.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_FILE_CONNECT + BUTTON ID_FILE_DISCONNECT + SEPARATOR + BUTTON ID_FILE_LISTCHANNELS + BUTTON ID_FILE_SENDRAW + SEPARATOR + BUTTON ID_FILE_NEW + BUTTON ID_FILE_CLOSE + SEPARATOR + BUTTON ID_CHANNEL_SET_TOPIC + BUTTON ID_CHANNEL_MODE + BUTTON ID_CHANNEL_TALK + BUTTON ID_CHANNEL_PASSWORD + SEPARATOR + BUTTON ID_FILE_GETUSERINFO + SEPARATOR + BUTTON ID_FILE_SILENCE + BUTTON ID_FILE_UNSILENCE + SEPARATOR + BUTTON ID_BUTTON32802 + BUTTON ID_BUTTON32803 + SEPARATOR + BUTTON ID_FILE_OPEN + BUTTON ID_FILE_SAVE + SEPARATOR + BUTTON ID_EDIT_CUT + BUTTON ID_EDIT_COPY + BUTTON ID_EDIT_PASTE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAINFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Connect...", ID_FILE_CONNECT + MENUITEM "&Disconnect", ID_FILE_DISCONNECT + MENUITEM SEPARATOR + MENUITEM "&Enter...\tCtrl+N", ID_FILE_NEW + MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN + MENUITEM SEPARATOR + MENUITEM "&List Channels...", ID_FILE_LISTCHANNELS + MENUITEM "&Send Raw...", ID_FILE_SENDRAW + MENUITEM "&Get User Info...", ID_FILE_GETUSERINFO + MENUITEM "&Silence", ID_FILE_SILENCE + MENUITEM "&Unsilence", ID_FILE_UNSILENCE + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_APP_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Toolbar", ID_VIEW_TOOLBAR + MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR + END + POPUP "&Help" + BEGIN + MENUITEM "&About chatty...", ID_APP_ABOUT + END +END + +IDR_CHATTYTYPE MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Enter\tCtrl+N", ID_FILE_NEW + MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN + MENUITEM "&Leave", ID_FILE_CLOSE + MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE + MENUITEM "Save &As...", ID_FILE_SAVE_AS + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_APP_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\tCtrl+X", ID_EDIT_CUT + MENUITEM "&Copy\tCtrl+C", ID_EDIT_COPY + MENUITEM "&Paste\tCtrl+V", ID_EDIT_PASTE + END + POPUP "&View" + BEGIN + MENUITEM "&Toolbar", ID_VIEW_TOOLBAR + MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR + END + POPUP "&Window" + BEGIN + MENUITEM "&New Window", ID_WINDOW_NEW + MENUITEM "&Cascade", ID_WINDOW_CASCADE + MENUITEM "&Tile", ID_WINDOW_TILE_HORZ + MENUITEM "&Arrange Icons", ID_WINDOW_ARRANGE + END + POPUP "&Help" + BEGIN + MENUITEM "&About chatty...", ID_APP_ABOUT + END + POPUP "&Channel" + BEGIN + MENUITEM "Set &Topic", ID_CHANNEL_SET_TOPIC + MENUITEM "&Mode", ID_CHANNEL_MODE + MENUITEM "&Talk", ID_CHANNEL_TALK + MENUITEM "&Password", ID_CHANNEL_PASSWORD + MENUITEM "&Get Ban List", ID_CHANNEL_GETBANLIST + END + POPUP "User" + BEGIN + MENUITEM "Get Info", ID_USER_GETINFO + MENUITEM "Kick", ID_USER_KICK + MENUITEM "Ban", ID_USER_BAN + POPUP "Mode" + BEGIN + MENUITEM "Op", ID_USER_MODE_OP + MENUITEM "Voice", ID_USER_MODE_VOICE + MENUITEM "Normal", ID_USER_MODE_NORMAL + END + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE +BEGIN + "N", ID_FILE_NEW, VIRTKEY, CONTROL + "O", ID_FILE_OPEN, VIRTKEY, CONTROL + "S", ID_FILE_SAVE, VIRTKEY, CONTROL + "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL + "X", ID_EDIT_CUT, VIRTKEY, CONTROL + "C", ID_EDIT_COPY, VIRTKEY, CONTROL + "V", ID_EDIT_PASTE, VIRTKEY, CONTROL + VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT + VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT + VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL + VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT + VK_F6, ID_NEXT_PANE, VIRTKEY + VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About chatty" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "chatty Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2000",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP +END + +IDD_CHATTY_FORM DIALOG DISCARDABLE 0, 0, 427, 304 +STYLE WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + LISTBOX IDC_LIST,7,7,343,173,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT,7,185,343,13,ES_AUTOHSCROLL | ES_WANTRETURN + LISTBOX IDC_USERS,352,20,68,146,LBS_SORT | LBS_NOINTEGRALHEIGHT | + LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_CALLBACKS,7,202,415,95,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | + WS_HSCROLL | WS_TABSTOP + LTEXT "Num Users:",IDC_STATIC,353,7,38,8 + EDITTEXT IDC_NUM_USERS,394,7,26,12,ES_AUTOHSCROLL | ES_READONLY | + ES_NUMBER | NOT WS_BORDER + CONTROL "Hide Stuff",IDC_HIDE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,353,170,47,10 + DEFPUSHBUTTON "Send",IDC_SENDBUTT,353,184,50,14 +END + +IDR_MAINFRAME DIALOG DISCARDABLE 0, 0, 330, 16 +STYLE WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "TODO: layout dialog bar ",IDC_STATIC,20,8,300,8 +END + +IDD_CONNECT DIALOG DISCARDABLE 0, 0, 187, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Connect" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,130,25,50,14 + LTEXT "Nick:",IDC_STATIC,5,9,18,8 + LTEXT "Address:",IDC_STATIC,5,24,28,8 + LTEXT "Port:",IDC_STATIC,5,39,16,8 + EDITTEXT IDC_NICK,45,5,80,12,ES_AUTOHSCROLL + EDITTEXT IDC_ADDRESS,45,20,80,12,ES_AUTOHSCROLL + EDITTEXT IDC_PORT,45,35,80,12,ES_AUTOHSCROLL +END + +IDD_ENTER DIALOG DISCARDABLE 0, 0, 186, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Channel:",IDC_STATIC,5,9,29,8 + EDITTEXT IDC_CHANNEL,45,5,80,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,5,30,34,8 + EDITTEXT IDC_PASSWORD,45,26,80,12,ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "istanbul",IDC_QUICK1,7,45,35,14 + PUSHBUTTON "montreal",IDC_QUICK2,52,45,35,14 + PUSHBUTTON "pants-test",IDC_QUICK3,97,45,35,14 + PUSHBUTTON "zurna",IDC_QUICK4,142,45,35,14 +END + +IDD_SET_TOPIC DIALOG DISCARDABLE 0, 0, 186, 46 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Topic" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Topic:",IDC_STATIC,5,19,21,8 + EDITTEXT IDC_TOPIC,30,16,90,12,ES_AUTOHSCROLL +END + +IDD_CHANNEL_MODE DIALOG DISCARDABLE 0, 0, 128, 114 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Channel Mode" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,71,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,71,24,50,14 + LTEXT "Limit:",IDC_STATIC,7,97,17,8 + CONTROL "Invite Only",IDC_INVITE_ONLY,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,7,49,10 + CONTROL "Private",IDC_PRIVATE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,22,38,10 + CONTROL "Secret",IDC_SECRET,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,37,37,10 + CONTROL "Moderated",IDC_MODERATED,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,52,50,10 + CONTROL "No External Messages",IDC_NO_EXTERNAL_MESSAGES,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,67,87,10 + CONTROL "Only Ops Change Topic",IDC_ONLY_OPS_CHANGE_TOPIC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,82,91,10 + EDITTEXT IDC_LIMIT,30,96,26,12,ES_AUTOHSCROLL +END + +IDD_TALK DIALOG DISCARDABLE 0, 0, 186, 47 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Talk" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Talk:",IDC_STATIC,7,10,17,8 + EDITTEXT IDC_MESSAGE,32,7,90,12,ES_AUTOHSCROLL + CONTROL "Normal",IDC_NORMAL,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,7,30,38,10 + CONTROL "Action",IDC_ACTION,"Button",BS_AUTORADIOBUTTON,47,30,36, + 10 + CONTROL "Notice",IDC_NOTICE,"Button",BS_AUTORADIOBUTTON,85,30,37, + 10 +END + +IDD_CHANNEL_LIST DIALOG DISCARDABLE 0, 0, 288, 257 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Channel List" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,231,7,50,14 + LISTBOX IDC_LIST,7,24,274,226,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "Channels",ID_CHANNELS,7,7,41,14 + EDITTEXT IDC_FILTER,107,7,96,12,ES_AUTOHSCROLL + EDITTEXT IDC_NUM,209,7,17,12,ES_AUTOHSCROLL | ES_READONLY | NOT + WS_BORDER + DEFPUSHBUTTON "Users",ID_USERS,57,7,44,14 +END + +IDD_SEND_RAW DIALOG DISCARDABLE 0, 0, 186, 46 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Send Raw" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Raw:",IDC_STATIC,7,19,18,8 + EDITTEXT IDC_RAW,30,16,90,12,ES_AUTOHSCROLL +END + +IDD_SET_PASSWORD DIALOG DISCARDABLE 0, 0, 220, 47 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Password" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,163,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,163,24,50,14 + LTEXT "Password:",IDC_STATIC,7,20,34,8 + EDITTEXT IDC_PASSWORD,46,17,76,12,ES_AUTOHSCROLL + CONTROL "Enable",IDC_ENABLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,18,38,10 +END + +IDD_GET_USER_INFO DIALOG DISCARDABLE 0, 0, 186, 202 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Get User Info" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,23,50,14 + LTEXT "Nick:",IDC_STATIC,7,7,18,8 + EDITTEXT IDC_NICK,42,7,80,12,ES_AUTOHSCROLL + LTEXT "Address:",IDC_STATIC,7,41,28,8 + EDITTEXT IDC_ADDRESS,42,39,80,12,ES_AUTOHSCROLL | ES_READONLY + LISTBOX IDC_CHANNELS,7,85,172,110,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Channels:",IDC_STATIC,7,73,32,8 + DEFPUSHBUTTON "Get Info",ID_GET_INFO,129,7,50,14 + LTEXT "Name:",IDC_STATIC,7,23,22,8 + EDITTEXT IDC_NAME,42,23,80,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "User:",IDC_STATIC,7,57,18,8 + EDITTEXT IDC_USER,42,54,80,12,ES_AUTOHSCROLL | ES_READONLY +END + +IDD_KICK_REASON DIALOG DISCARDABLE 0, 0, 186, 46 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Kick Reason" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + LTEXT "Reason:",IDC_STATIC,7,18,28,8 + EDITTEXT IDC_REASON,37,16,83,12,ES_AUTOHSCROLL +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "chatty MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "chatty\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "chatty.EXE\0" + VALUE "ProductName", "chatty Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_CHATTY_FORM, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 420 + TOPMARGIN, 7 + BOTTOMMARGIN, 297 + END + + IDD_CONNECT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_ENTER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 59 + END + + IDD_SET_TOPIC, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 39 + END + + IDD_CHANNEL_MODE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 121 + TOPMARGIN, 7 + BOTTOMMARGIN, 107 + END + + IDD_TALK, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 40 + END + + IDD_CHANNEL_LIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 281 + TOPMARGIN, 7 + BOTTOMMARGIN, 250 + END + + IDD_SEND_RAW, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 39 + END + + IDD_SET_PASSWORD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 40 + END + + IDD_GET_USER_INFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 195 + END + + IDD_KICK_REASON, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 39 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed." +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + IDR_MAINFRAME "chatty" + IDR_CHATTYTYPE "\nChatty\nChatty\n\n\nChatty.Document\nChatty Document" +END + +STRINGTABLE PRELOAD DISCARDABLE +BEGIN + AFX_IDS_APP_TITLE "chatty" + AFX_IDS_IDLEMESSAGE "Ready" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_INDICATOR_EXT "EXT" + ID_INDICATOR_CAPS "CAP" + ID_INDICATOR_NUM "NUM" + ID_INDICATOR_SCRL "SCRL" + ID_INDICATOR_OVR "OVR" + ID_INDICATOR_REC "REC" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_FILE_NEW "Create a new document\nNew" + ID_FILE_OPEN "Open an existing document\nOpen" + ID_FILE_CLOSE "Close the active document\nClose" + ID_FILE_SAVE "Save the active document\nSave" + ID_FILE_SAVE_AS "Save the active document with a new name\nSave As" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_APP_EXIT "Quit the application; prompts to save documents\nExit" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_FILE_MRU_FILE1 "Open this document" + ID_FILE_MRU_FILE2 "Open this document" + ID_FILE_MRU_FILE3 "Open this document" + ID_FILE_MRU_FILE4 "Open this document" + ID_FILE_MRU_FILE5 "Open this document" + ID_FILE_MRU_FILE6 "Open this document" + ID_FILE_MRU_FILE7 "Open this document" + ID_FILE_MRU_FILE8 "Open this document" + ID_FILE_MRU_FILE9 "Open this document" + ID_FILE_MRU_FILE10 "Open this document" + ID_FILE_MRU_FILE11 "Open this document" + ID_FILE_MRU_FILE12 "Open this document" + ID_FILE_MRU_FILE13 "Open this document" + ID_FILE_MRU_FILE14 "Open this document" + ID_FILE_MRU_FILE15 "Open this document" + ID_FILE_MRU_FILE16 "Open this document" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_NEXT_PANE "Switch to the next window pane\nNext Pane" + ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_WINDOW_NEW "Open another window for the active document\nNew Window" + ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons" + ID_WINDOW_CASCADE "Arrange windows so they overlap\nCascade Windows" + ID_WINDOW_TILE_HORZ "Arrange windows as non-overlapping tiles\nTile Windows" + ID_WINDOW_TILE_VERT "Arrange windows as non-overlapping tiles\nTile Windows" + ID_WINDOW_SPLIT "Split the active window into panes\nSplit" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_EDIT_CLEAR "Erase the selection\nErase" + ID_EDIT_CLEAR_ALL "Erase everything\nErase All" + ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy" + ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut" + ID_EDIT_FIND "Find the specified text\nFind" + ID_EDIT_PASTE "Insert Clipboard contents\nPaste" + ID_EDIT_REPEAT "Repeat the last action\nRepeat" + ID_EDIT_REPLACE "Replace specific text with different text\nReplace" + ID_EDIT_SELECT_ALL "Select the entire document\nSelect All" + ID_EDIT_UNDO "Undo the last action\nUndo" + ID_EDIT_REDO "Redo the previously undone action\nRedo" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar" + ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar" +END + +STRINGTABLE DISCARDABLE +BEGIN + AFX_IDS_SCSIZE "Change the window size" + AFX_IDS_SCMOVE "Change the window position" + AFX_IDS_SCMINIMIZE "Reduce the window to an icon" + AFX_IDS_SCMAXIMIZE "Enlarge the window to full size" + AFX_IDS_SCNEXTWINDOW "Switch to the next document window" + AFX_IDS_SCPREVWINDOW "Switch to the previous document window" + AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents" +END + +STRINGTABLE DISCARDABLE +BEGIN + AFX_IDS_SCRESTORE "Restore the window to normal size" + AFX_IDS_SCTASKLIST "Activate Task List" + AFX_IDS_MDICHILD "Activate this window" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_FILE_CONNECT "Connect to the chat server\nConnect" + ID_FILE_DISCONNECT "Disconnect from the chat server\nDisconnect" + ID_CHANNEL_SET_TOPIC "Set the channel topic\nTopic" + ID_CHANNEL_MODE "View/Set the channel mode\nMode" + ID_CHANNEL_TALK "Send a message\nTalk" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\chatty.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/Chat/chatty/chattyDoc.cpp b/xrGameSpy/gamespy/Chat/chatty/chattyDoc.cpp new file mode 100644 index 00000000000..e72dfdaa965 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chattyDoc.cpp @@ -0,0 +1,586 @@ +// chattyDoc.cpp : implementation of the CChattyDoc class +// + +#include "stdafx.h" +#include "chatty.h" + +#include "chattyDoc.h" +#include "EnterDlg.h" +#include "SetTopicDlg.h" +#include "ChannelModeDlg.h" +#include "TalkDlg.h" +#include "SetPasswordDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChattyDoc + +IMPLEMENT_DYNCREATE(CChattyDoc, CDocument) + +BEGIN_MESSAGE_MAP(CChattyDoc, CDocument) + //{{AFX_MSG_MAP(CChattyDoc) + ON_COMMAND(ID_CHANNEL_SET_TOPIC, OnChannelSetTopic) + ON_COMMAND(ID_CHANNEL_MODE, OnChannelMode) + ON_COMMAND(ID_CHANNEL_TALK, OnChannelTalk) + ON_COMMAND(ID_CHANNEL_PASSWORD, OnChannelPassword) + ON_COMMAND(ID_CHANNEL_GETBANLIST, OnChannelGetbanlist) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChattyDoc construction/destruction + +CChattyDoc::CChattyDoc() +{ + m_inChannel = FALSE; + m_hide = FALSE; +} + +CChattyDoc::~CChattyDoc() +{ +} + +/********************** +** CHANNEL CALLBACKS ** +**********************/ +#if 0 +CChattyDoc * pDoc; // Get rid of VA complaints. +#endif +#define DOC CChattyDoc * pDoc;\ + pDoc = (CChattyDoc *)param;\ + ASSERT(pDoc != NULL);\ + if(!pDoc->m_inChannel) { OutputDebugString("Not in channel anymore!\n"); return; } +#define ADD(s) *str += " | ";\ + *str += #s;\ + *str += "--";\ + *str += s; +char __i__[32]; +#define ADD_INT(i) *str += " | ";\ + *str += #i;\ + *str += "--";\ + itoa(i, __i__, 10);\ + *str += __i__; +void ChannelMessage(CHAT chat, const char * channel, const char * user, const char * message, int type, void * param) +{ + OutputDebugString("ChannelMessage called\n"); + DOC; + CString * str; + + str = new CString("ChannelMessage"); + ADD(channel); + ADD(user); + ADD(message); + ADD_INT(type); + pDoc->m_addCallbacks.AddTail(str); // MORE DESCRIPTIVE (SHOW PARAMS) + + str = new CString; + + if(type == CHAT_MESSAGE) + { + *str = user; + *str += ": "; + *str += message; + } + else if(type == CHAT_ACTION) + { + *str += user; + *str += " "; + *str += message; + } + else + { + *str += user; + *str += "* "; + *str += message; + } + + pDoc->m_newStuff.AddTail(str); + + GSI_UNUSED(chat); +} + +void Kicked(CHAT chat, const char * channel, const char * user, const char * reason, void * param) +{ + OutputDebugString("Kicked called\n"); + DOC; + + // Not in the channel anymore. + ////////////////////////////// + pDoc->m_inChannel = FALSE; + + POSITION pos = pDoc->GetFirstViewPosition(); + pDoc->GetNextView(pos)->GetParentFrame()->DestroyWindow(); + + GSI_UNUSED(reason); + GSI_UNUSED(user); + GSI_UNUSED(channel); + GSI_UNUSED(chat); +} + +void UserJoined(CHAT chat, const char * channel, const char * user, int mode, void * param) +{ + OutputDebugString("UserJoined called\n"); + DOC; + CString * str; + + if(!pDoc->m_hide) + { + str = new CString("UserJoined"); + ADD(channel); + ADD(user); + ADD_INT(mode); + pDoc->m_addCallbacks.AddTail(str); + } + + CModUsers * mod = new CModUsers; + mod->type = NEW; + mod->nick = user; + mod->mode = mode; + pDoc->m_modUsers.AddTail(mod); + + GSI_UNUSED(chat); +} + +void UserParted(CHAT chat, const char * channel, const char * user, int why, const char * reason, const char * kicker, void * param) +{ + OutputDebugString("UserParted called\n"); + DOC; + CString * str; + + if(!pDoc->m_hide) + { + str = new CString("UserParted"); + ADD(channel); + ADD(user); + ADD_INT(why); + ADD(reason); + ADD(kicker); + pDoc->m_addCallbacks.AddTail(str); + } + + CModUsers * mod = new CModUsers; + mod->type = DEL; + mod->nick = user; + pDoc->m_modUsers.AddTail(mod); + + GSI_UNUSED(chat); +} + +void UserChangedNick(CHAT chat, const char * channel, const char * oldNick, const char * newNick, void * param) +{ + OutputDebugString("UserChangedNick called\n"); + DOC; + CString * str; + + if(!pDoc->m_hide) + { + str = new CString("UserChangedNick"); + ADD(channel); + ADD(oldNick); + ADD(newNick); + pDoc->m_addCallbacks.AddTail(str); + } + + CModUsers * mod = new CModUsers; + mod->type = RENAME; + mod->nick = oldNick; + mod->newNick = newNick; + pDoc->m_modUsers.AddTail(mod); + + GSI_UNUSED(chat); +} + +void UserModeChanged(CHAT chat, const char * channel, const char * user, int mode, void * param) +{ + OutputDebugString("UserModeChanged called\n"); + DOC; + CString *str; + + str = new CString("UserModeChanged"); + ADD(channel); + ADD(user); + ADD_INT(mode); + pDoc->m_addCallbacks.AddTail(str); + + CModUsers * mod = new CModUsers; + mod->type = MODE; + mod->nick = user; + mod->mode = mode; + pDoc->m_modUsers.AddTail(mod); + + GSI_UNUSED(chat); +} + +void TopicChanged(CHAT chat, const char * channel, const char * topic, void * param) +{ + OutputDebugString("TopicChanged called\n"); + DOC; + CString * str; + + str = new CString("TopicChanged"); + ADD(channel); + ADD(topic); + pDoc->m_addCallbacks.AddTail(str); + + CString title = channel; + title += " - "; + title += topic; + pDoc->SetTitle(title); + + pDoc->m_topic = topic; + + GSI_UNUSED(chat); +} + +void ChannelModeChanged(CHAT chat, const char * channel, CHATChannelMode * mode, void * param) +{ + OutputDebugString("ChannelModeChanged called\n"); + DOC; + CString * str; + + str = new CString("ChannelModeChanged"); + ADD(channel); + ADD_INT(mode->InviteOnly); + ADD_INT(mode->Limit); + ADD_INT(mode->Moderated); + ADD_INT(mode->NoExternalMessages); + ADD_INT(mode->OnlyOpsChangeTopic); + ADD_INT(mode->Private); + ADD_INT(mode->Secret); + pDoc->m_addCallbacks.AddTail(str); + + str = new CString("Channel Mode Changed"); + pDoc->m_newStuff.AddTail(str); + + GSI_UNUSED(chat); +} + +void UserListUpdated(CHAT chat, const char * channel, void * param) +{ + OutputDebugString("UserListUpdated called\n"); + DOC; + CString * str; + + if(!pDoc->m_hide) + { + str = new CString("UserListUpdated"); + ADD(channel); + pDoc->m_addCallbacks.AddTail(str); + } + + GSI_UNUSED(chat); +} + +void EnumUsersCallback(CHAT chat, CHATBool success, const char * channel, int numUsers, const char ** users, int * modes, void * param) +{ + OutputDebugString("EnumUsersCallback called\n"); + CChattyDoc * pDoc = (CChattyDoc *)param; + + if(success) + { + pDoc->m_numUsers = numUsers; + + int i; + for(i = 0 ; i < numUsers ; i++) + { + CModUsers * mod = new CModUsers; + ASSERT(mod != NULL); + mod->type = NEW; + mod->nick = users[i]; + mod->mode = modes[i]; + pDoc->m_modUsers.AddTail(mod); + } + } + + GSI_UNUSED(chat); + GSI_UNUSED(channel); +} + +void EnterChannelCallback(CHAT chat, CHATBool success, CHATEnterResult result, const char * channel, void * param) +{ + OutputDebugString("EnterChannelCallback called\n"); + CChattyDoc * pDoc = (CChattyDoc *)param; + + // Check for success or failure. + //////////////////////////////// + if(success) + { + pDoc->m_inChannel = TRUE; + + // Get the inital list of users. + //////////////////////////////// + DWORD before = GetTickCount(); + chatEnumUsers(theApp.m_chat, channel, EnumUsersCallback, pDoc, CHATTrue); + DWORD after = GetTickCount(); + char buffer[128]; + sprintf(buffer, "%dms to enum %d users in %s\n", after - before, pDoc->m_numUsers, pDoc->m_channelName); + OutputDebugString(buffer); + } + + GSI_UNUSED(chat); + GSI_UNUSED(result); +} + +BOOL CChattyDoc::OnNewDocument() +{ + if (!CDocument::OnNewDocument()) + return FALSE; + + // Check for no connection. + /////////////////////////// + if(theApp.m_chat == NULL) + return FALSE; + + // Set the dialog defaults. + /////////////////////////// + CEnterDlg dlg; + //dlg.m_channel = "#test"; + //dlg.m_channel = "#montreal"; + dlg.m_channel = "#istanbul"; + dlg.m_password = ""; + + // Go modal. + //////////// + int rcode = dlg.DoModal(); + + // Check for a cancel. + ////////////////////// + if(rcode != IDOK) + return FALSE; + + // Setup the callbacks. + /////////////////////// + chatChannelCallbacks callbacks; + memset(&callbacks, 0, sizeof(chatChannelCallbacks)); + callbacks.channelMessage = ChannelMessage; + callbacks.channelModeChanged = ChannelModeChanged; + callbacks.kicked = Kicked; + callbacks.topicChanged = TopicChanged; + callbacks.userParted = UserParted; + callbacks.userJoined = UserJoined; + callbacks.userListUpdated = UserListUpdated; + callbacks.userModeChanged = UserModeChanged; + callbacks.userChangedNick = UserChangedNick; + callbacks.param = this; + + // Join the group. + ////////////////// + if(dlg.m_quickChannel != "") + m_channelName = dlg.m_quickChannel; + else + m_channelName = dlg.m_channel; + chatEnterChannel(theApp.m_chat, m_channelName, dlg.m_password, &callbacks, EnterChannelCallback, this, CHATTrue); + + // Check for failure. + ///////////////////// + if(!m_inChannel) + return FALSE; + + // Set the name. + //////////////// + SetTitle(m_channelName); + + return TRUE; +} + + + +///////////////////////////////////////////////////////////////////////////// +// CChattyDoc serialization + +void CChattyDoc::Serialize(CArchive& ar) +{ + if (ar.IsStoring()) + { + // TODO: add storing code here + } + else + { + // TODO: add loading code here + } +} + +///////////////////////////////////////////////////////////////////////////// +// CChattyDoc diagnostics + +#ifdef _DEBUG +void CChattyDoc::AssertValid() const +{ + CDocument::AssertValid(); +} + +void CChattyDoc::Dump(CDumpContext& dc) const +{ + CDocument::Dump(dc); +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CChattyDoc commands + +void CChattyDoc::OnCloseDocument() +{ + // Did we ever get in the channel? + ////////////////////////////////// + if(m_inChannel) + { + if(theApp.m_chat != NULL) + { + // Leave the channel. + ///////////////////// + chatLeaveChannel(theApp.m_chat, m_channelName, NULL); + + OutputDebugString("LEFT channel\n"); + } + + m_inChannel = FALSE; + } + + CDocument::OnCloseDocument(); +} + +void CChattyDoc::OnChannelSetTopic() +{ + if(theApp.m_chat != NULL) + { + CSetTopicDlg dlg; + dlg.m_topic = m_topic; + + if(dlg.DoModal() == IDOK) + { + chatSetChannelTopic(theApp.m_chat, m_channelName, dlg.m_topic); + } + } +} + +void GetChannelModeCallback(CHAT chat, CHATBool success, const char * channel, CHATChannelMode * mode, void * param) +{ + CHATChannelMode * modeParam = (CHATChannelMode *)param; + *modeParam = *mode; + + GSI_UNUSED(chat); + GSI_UNUSED(channel); + GSI_UNUSED(success); +} + +void CChattyDoc::OnChannelMode() +{ + if(theApp.m_chat != NULL) + { + CHATChannelMode mode; + + // Get the channel mode. + //////////////////////// + chatGetChannelMode(theApp.m_chat, m_channelName, GetChannelModeCallback, &mode, CHATTrue); + + // Setup the dlg. + ///////////////// + CChannelModeDlg dlg; + dlg.m_inviteOnly = mode.InviteOnly; + dlg.m_private = mode.Private; + dlg.m_secret = mode.Secret; + dlg.m_moderated = mode.Moderated; + dlg.m_noExternalMessages = mode.NoExternalMessages; + dlg.m_onlyOpsChangeTopic = mode.OnlyOpsChangeTopic; + dlg.m_limit = mode.Limit; + + // Show the dlg. + //////////////// + if(dlg.DoModal() == IDOK) + { + // Copy back the new mode. + ////////////////////////// + mode.InviteOnly = (CHATBool)dlg.m_inviteOnly; + mode.Private = (CHATBool)dlg.m_private; + mode.Secret = (CHATBool)dlg.m_secret; + mode.Moderated = (CHATBool)dlg.m_moderated; + mode.NoExternalMessages = (CHATBool)dlg.m_noExternalMessages; + mode.OnlyOpsChangeTopic = (CHATBool)dlg.m_onlyOpsChangeTopic; + mode.Limit = (CHATBool)dlg.m_limit; + + // Set the mode. + //////////////// + chatSetChannelMode(theApp.m_chat, m_channelName, &mode); + } + } +} + +void CChattyDoc::OnChannelTalk() +{ + if(theApp.m_chat != NULL) + { + CTalkDlg dlg; + dlg.m_type = 0; + if(dlg.DoModal() == IDOK) + { + int type; + if(dlg.m_type == 0) + type = CHAT_NORMAL; + else if(dlg.m_type == 1) + type = CHAT_ACTION; + else + type = CHAT_NOTICE; + chatSendChannelMessage(theApp.m_chat, m_channelName, dlg.m_message, type); + } + } +} + +void GetChannelPasswordCallback(CHAT chat, CHATBool success, const char * channel, CHATBool enabled, const char * password, void * param) +{ + CSetPasswordDlg * dlg = (CSetPasswordDlg *)param; + if(success) + { + dlg->m_password = password; + dlg->m_enable = enabled; + } + else + { + dlg->m_password = ""; + dlg->m_enable = FALSE; + } + + GSI_UNUSED(channel); + GSI_UNUSED(chat); +} + +void CChattyDoc::OnChannelPassword() +{ + if(theApp.m_chat != NULL) + { + CSetPasswordDlg dlg; + chatGetChannelPassword(theApp.m_chat, m_channelName, GetChannelPasswordCallback, &dlg, CHATTrue); + if(dlg.DoModal() == IDOK) + { + chatSetChannelPassword(theApp.m_chat, m_channelName, (CHATBool)dlg.m_enable, dlg.m_password); + } + } +} + +void EnumChannelBansCallback(CHAT chat, CHATBool success, const char * channel, int numBans, const char ** bans, void * param) +{ + DOC; + int i; + + pDoc->m_newStuff.AddTail(new CString("Bans:")); + for(i = 0 ; i < numBans ; i++) + { + pDoc->m_newStuff.AddTail(new CString(bans[i])); + } + + GSI_UNUSED(channel); + GSI_UNUSED(success); + GSI_UNUSED(chat); +} + +void CChattyDoc::OnChannelGetbanlist() +{ + if(theApp.m_chat != NULL) + { + chatEnumChannelBans(theApp.m_chat, m_channelName, EnumChannelBansCallback, this, CHATFalse); + } +} diff --git a/xrGameSpy/gamespy/Chat/chatty/chattyDoc.h b/xrGameSpy/gamespy/Chat/chatty/chattyDoc.h new file mode 100644 index 00000000000..e2812702090 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chattyDoc.h @@ -0,0 +1,80 @@ +// chattyDoc.h : interface of the CChattyDoc class +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CHATTYDOC_H__A9A7E462_6E3D_4AE0_9DF8_355AE2D28FBC__INCLUDED_) +#define AFX_CHATTYDOC_H__A9A7E462_6E3D_4AE0_9DF8_355AE2D28FBC__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define NEW 1 +#define DEL 2 +#define RENAME 3 +#define MODE 4 +struct CModUsers +{ + int type; + CString nick; + CString newNick; + int mode; +}; + +class CChattyDoc : public CDocument +{ +protected: // create from serialization only + CChattyDoc(); + DECLARE_DYNCREATE(CChattyDoc) + +// Attributes +public: + BOOL m_inChannel; + CString m_channelName; + CList m_newStuff; + CString m_topic; + CList m_addCallbacks; + CList m_modUsers; + BOOL m_hide; + int m_numUsers; + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChattyDoc) + public: + virtual BOOL OnNewDocument(); + virtual void Serialize(CArchive& ar); + virtual void OnCloseDocument(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CChattyDoc(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: + +// Generated message map functions +protected: + //{{AFX_MSG(CChattyDoc) + afx_msg void OnChannelSetTopic(); + afx_msg void OnChannelMode(); + afx_msg void OnChannelTalk(); + afx_msg void OnChannelPassword(); + afx_msg void OnChannelGetbanlist(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHATTYDOC_H__A9A7E462_6E3D_4AE0_9DF8_355AE2D28FBC__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/chattyView.cpp b/xrGameSpy/gamespy/Chat/chatty/chattyView.cpp new file mode 100644 index 00000000000..b8499899201 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chattyView.cpp @@ -0,0 +1,391 @@ +// chattyView.cpp : implementation of the CChattyView class +// + +#include "stdafx.h" +#include "chatty.h" + +#include "chattyDoc.h" +#include "chattyView.h" +#include "TalkDlg.h" +#include "KickReasonDlg.h" +#include "GetUserInfoDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CChattyView + +IMPLEMENT_DYNCREATE(CChattyView, CFormView) + +BEGIN_MESSAGE_MAP(CChattyView, CFormView) + //{{AFX_MSG_MAP(CChattyView) + ON_WM_CREATE() + ON_WM_TIMER() + ON_BN_CLICKED(IDC_HIDE, OnHide) + ON_LBN_SELCHANGE(IDC_CALLBACKS, OnSelchangeCallbacks) + ON_LBN_DBLCLK(IDC_USERS, OnDblclkUsers) + ON_COMMAND(ID_USER_BAN, OnUserBan) + ON_COMMAND(ID_USER_GETINFO, OnUserGetinfo) + ON_COMMAND(ID_USER_KICK, OnUserKick) + ON_COMMAND(ID_USER_MODE_OP, OnUserModeOp) + ON_COMMAND(ID_USER_MODE_VOICE, OnUserModeVoice) + ON_COMMAND(ID_USER_MODE_NORMAL, OnUserModeNormal) + ON_BN_CLICKED(IDC_SENDBUTT, OnSendbutt) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CChattyView construction/destruction + +CChattyView::CChattyView() + : CFormView(CChattyView::IDD) +{ + //{{AFX_DATA_INIT(CChattyView) + m_edit = _T(""); + m_hide = FALSE; + //}}AFX_DATA_INIT + // TODO: add construction code here +} + +CChattyView::~CChattyView() +{ +} + +void CChattyView::DoDataExchange(CDataExchange* pDX) +{ + CFormView::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CChattyView) + DDX_Control(pDX, IDC_NUM_USERS, m_numUsers); + DDX_Control(pDX, IDC_CALLBACKS, m_callbacks); + DDX_Control(pDX, IDC_USERS, m_users); + DDX_Control(pDX, IDC_LIST, m_list); + DDX_Text(pDX, IDC_EDIT, m_edit); + DDX_Check(pDX, IDC_HIDE, m_hide); + //}}AFX_DATA_MAP +} + +BOOL CChattyView::PreCreateWindow(CREATESTRUCT& cs) +{ + // TODO: Modify the Window class or styles here by modifying + // the CREATESTRUCT cs + + return CFormView::PreCreateWindow(cs); +} + +void CChattyView::OnInitialUpdate() +{ + CFormView::OnInitialUpdate(); + ResizeParentToFit(); + + SetTimer(100, 50, NULL); +} + +///////////////////////////////////////////////////////////////////////////// +// CChattyView diagnostics + +#ifdef _DEBUG +void CChattyView::AssertValid() const +{ + CFormView::AssertValid(); +} + +void CChattyView::Dump(CDumpContext& dc) const +{ + CFormView::Dump(dc); +} + +CChattyDoc* CChattyView::GetDocument() // non-debug version is inline +{ + ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CChattyDoc))); + return (CChattyDoc*)m_pDocument; +} +#endif //_DEBUG + +///////////////////////////////////////////////////////////////////////////// +// CChattyView message handlers + +int CChattyView::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CFormView::OnCreate(lpCreateStruct) == -1) + return -1; + + return 0; +} + +void CChattyView::OnTimer(UINT nIDEvent) +{ + if(nIDEvent == 100) + { + CChattyDoc * pDoc = GetDocument(); + if(pDoc != NULL) + { + CString * str; + while(!pDoc->m_newStuff.IsEmpty()) + { + str = pDoc->m_newStuff.GetHead(); + pDoc->m_newStuff.RemoveHead(); + + m_list.InsertString(0, *str); + + delete str; + } + + while(!pDoc->m_addCallbacks.IsEmpty()) + { + str = pDoc->m_addCallbacks.GetHead(); + pDoc->m_addCallbacks.RemoveHead(); + + m_callbacks.InsertString(0, *str); + + delete str; + } + + CModUsers * mod; + CString name; + CString newName; + UINT index; + while(!pDoc->m_modUsers.IsEmpty()) + { + mod = pDoc->m_modUsers.GetHead(); + pDoc->m_modUsers.RemoveHead(); + + if(mod->type == NEW) + { + name = mod->nick; + if(mod->mode & CHAT_OP) + name.Insert(0, '@'); + else if(mod->mode & CHAT_VOICE) + name.Insert(0, '?'); + + m_users.AddString(name); + } + else if(mod->type == DEL) + { + name = mod->nick; + index = m_users.FindStringExact(-1, name); + if(index == LB_ERR) + index = m_users.FindStringExact(-1, '@' + name); + if(index == LB_ERR) + index = m_users.FindStringExact(-1, '?' + name); + if(index == LB_ERR) + ASSERT(0); + + m_users.DeleteString(index); + } + else if(mod->type == RENAME) + { + name = mod->nick; + newName = ""; + index = m_users.FindStringExact(-1, name); + if(index == LB_ERR) + { + newName = '@'; + index = m_users.FindStringExact(-1, '@' + name); + } + if(index == LB_ERR) + { + newName = '?'; + index = m_users.FindStringExact(-1, '?' + name); + } + if(index == LB_ERR) + ASSERT(0); + + m_users.DeleteString(index); + + newName += mod->newNick; + m_users.AddString(newName); + } + else if(mod->type == MODE) + { + name = mod->nick; + index = m_users.FindStringExact(-1, name); + if(index == LB_ERR) + index = m_users.FindStringExact(-1, '@' + name); + if(index == LB_ERR) + index = m_users.FindStringExact(-1, '?' + name); + if(index == LB_ERR) + ASSERT(0); + + m_users.DeleteString(index); + + if(mod->mode & CHAT_OP) + name.Insert(0, '@'); + else if(mod->mode & CHAT_VOICE) + name.Insert(0, '?'); + + m_users.AddString(name); + } + else + ASSERT(0); + + delete mod; + } + + char buf[16]; + itoa(m_users.GetCount(), buf, 10); + m_numUsers.SetWindowText(buf); + } + + SetTimer(100, 50, NULL); + } + + CFormView::OnTimer(nIDEvent); +} + +void CChattyView::OnHide() +{ + UpdateData(); + GetDocument()->m_hide = m_hide; +} + +void CChattyView::OnSelchangeCallbacks() +{ + UpdateData(); + m_callbacks.GetText(m_callbacks.GetCurSel(), m_edit); + UpdateData(FALSE); +} + +void CChattyView::OnDblclkUsers() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + CTalkDlg dlg; + dlg.m_type = 0; + if(dlg.DoModal() == IDOK) + chatSendUserMessage(theApp.m_chat, user, dlg.m_message, dlg.m_type); + } + } +} + +void CChattyView::OnUserBan() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + + chatBanUser(theApp.m_chat, GetDocument()->m_channelName, user); + } + } +} + +void CChattyView::OnUserGetinfo() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + + CGetUserInfoDlg dlg; + dlg.m_user = user; + dlg.DoModal(); + } + } +} + +void CChattyView::OnUserKick() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + + CKickReasonDlg dlg; + if(dlg.DoModal() == IDOK) + { + chatKickUser(theApp.m_chat, GetDocument()->m_channelName, user, dlg.m_reason); + } + } + } +} + +void CChattyView::OnUserModeOp() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + + chatSetUserMode(theApp.m_chat, GetDocument()->m_channelName, user, CHAT_OP); + } + } +} + +void CChattyView::OnUserModeVoice() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + + chatSetUserMode(theApp.m_chat, GetDocument()->m_channelName, user, CHAT_VOICE); + } + } +} + +void CChattyView::OnUserModeNormal() +{ + if(theApp.m_chat != NULL) + { + int index = m_users.GetCurSel(); + if(index != LB_ERR) + { + CString user; + m_users.GetText(index, user); + if((user.Left(1) == "@") || (user.Left(1) == "?")) + user = user.Mid(1); + + chatSetUserMode(theApp.m_chat, GetDocument()->m_channelName, user, CHAT_NORMAL); + } + } +} + + +void CChattyView::OnSendbutt() +{ + // TODO: Add your control notification handler code here + if(theApp.m_chat != NULL) + { + UpdateData(); + chatSendChannelMessage(theApp.m_chat, GetDocument()->m_channelName, (LPCSTR)m_edit,CHAT_MESSAGE); + m_edit.Empty(); + UpdateData(FALSE); + } + +} diff --git a/xrGameSpy/gamespy/Chat/chatty/chattyView.h b/xrGameSpy/gamespy/Chat/chatty/chattyView.h new file mode 100644 index 00000000000..c7e53468461 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chattyView.h @@ -0,0 +1,86 @@ +// chattyView.h : interface of the CChattyView class +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CHATTYVIEW_H__E1B25967_4DA7_4ABD_A404_9C60D59E1C60__INCLUDED_) +#define AFX_CHATTYVIEW_H__E1B25967_4DA7_4ABD_A404_9C60D59E1C60__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +class CChattyView : public CFormView +{ +protected: // create from serialization only + CChattyView(); + DECLARE_DYNCREATE(CChattyView) + +public: + //{{AFX_DATA(CChattyView) + enum { IDD = IDD_CHATTY_FORM }; + CEdit m_numUsers; + CListBox m_callbacks; + CListBox m_users; + CListBox m_list; + CString m_edit; + BOOL m_hide; + //}}AFX_DATA + +// Attributes +public: + CChattyDoc* GetDocument(); + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CChattyView) + public: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual void OnInitialUpdate(); // called first time after construct + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CChattyView(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: + +// Generated message map functions +protected: + //{{AFX_MSG(CChattyView) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnHide(); + afx_msg void OnSelchangeCallbacks(); + afx_msg void OnDblclkUsers(); + afx_msg void OnUserBan(); + afx_msg void OnUserGetinfo(); + afx_msg void OnUserKick(); + afx_msg void OnUserModeOp(); + afx_msg void OnUserModeVoice(); + afx_msg void OnUserModeNormal(); + afx_msg void OnSendbutt(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#ifndef _DEBUG // debug version in chattyView.cpp +inline CChattyDoc* CChattyView::GetDocument() + { return (CChattyDoc*)m_pDocument; } +#endif + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CHATTYVIEW_H__E1B25967_4DA7_4ABD_A404_9C60D59E1C60__INCLUDED_) diff --git a/xrGameSpy/gamespy/Chat/chatty/chatty_vs2005.vcproj b/xrGameSpy/gamespy/Chat/chatty/chatty_vs2005.vcproj new file mode 100644 index 00000000000..8302ba77897 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chatty_vs2005.vcproj @@ -0,0 +1,875 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Chat/chatty/chatty_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Chat/chatty/chatty_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/chatty_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Chat/chatty/res/Toolbar.bmp b/xrGameSpy/gamespy/Chat/chatty/res/Toolbar.bmp new file mode 100644 index 00000000000..2d40a91fcd5 Binary files /dev/null and b/xrGameSpy/gamespy/Chat/chatty/res/Toolbar.bmp differ diff --git a/xrGameSpy/gamespy/Chat/chatty/res/chatty.ico b/xrGameSpy/gamespy/Chat/chatty/res/chatty.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/Chat/chatty/res/chatty.ico differ diff --git a/xrGameSpy/gamespy/Chat/chatty/res/chatty.rc2 b/xrGameSpy/gamespy/Chat/chatty/res/chatty.rc2 new file mode 100644 index 00000000000..399a219fc17 --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/res/chatty.rc2 @@ -0,0 +1,13 @@ +// +// CHATTY.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Chat/chatty/res/chattyDoc.ico b/xrGameSpy/gamespy/Chat/chatty/res/chattyDoc.ico new file mode 100644 index 00000000000..2a1f1ae6ef1 Binary files /dev/null and b/xrGameSpy/gamespy/Chat/chatty/res/chattyDoc.ico differ diff --git a/xrGameSpy/gamespy/Chat/chatty/resource.h b/xrGameSpy/gamespy/Chat/chatty/resource.h new file mode 100644 index 00000000000..3b28d34121b --- /dev/null +++ b/xrGameSpy/gamespy/Chat/chatty/resource.h @@ -0,0 +1,91 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by chatty.rc +// +#define ID_CHANNELS 2 +#define ID_GET_INFO 2 +#define ID_USERS 3 +#define IDD_ABOUTBOX 100 +#define IDD_CHATTY_FORM 101 +#define IDP_SOCKETS_INIT_FAILED 104 +#define IDR_MAINFRAME 128 +#define IDR_CHATTYTYPE 129 +#define IDD_SET_TOPIC 130 +#define IDD_CHANNEL_MODE 131 +#define IDD_CONNECT 132 +#define IDD_ENTER 133 +#define IDD_TALK 134 +#define IDD_CHANNEL_LIST 136 +#define IDD_SEND_RAW 137 +#define IDD_SET_PASSWORD 138 +#define IDD_GET_USER_INFO 139 +#define IDD_KICK_REASON 140 +#define IDC_LIST 1000 +#define IDC_EDIT 1001 +#define IDC_TOPIC 1002 +#define IDC_USERS 1002 +#define IDC_NICK 1003 +#define IDC_INVITE_ONLY 1003 +#define IDC_CALLBACKS 1003 +#define IDC_ADDRESS 1004 +#define IDC_PASSWORD 1004 +#define IDC_PRIVATE 1004 +#define IDC_PORT 1005 +#define IDC_CHANNEL 1005 +#define IDC_SECRET 1005 +#define IDC_USER 1005 +#define IDC_MODERATED 1006 +#define IDC_NO_EXTERNAL_MESSAGES 1007 +#define IDC_ONLY_OPS_CHANGE_TOPIC 1008 +#define IDC_LIMIT 1009 +#define IDC_MESSAGE 1010 +#define IDC_NORMAL 1012 +#define IDC_ACTION 1013 +#define IDC_NOTICE 1014 +#define IDC_NUM_USERS 1015 +#define IDC_HIDE 1016 +#define IDC_FILTER 1018 +#define IDC_RAW 1019 +#define IDC_ENABLE 1020 +#define IDC_NUM 1021 +#define IDC_NAME 1023 +#define IDC_CHANNELS 1025 +#define IDC_QUICK1 1026 +#define IDC_QUICK2 1027 +#define IDC_REASON 1027 +#define IDC_QUICK3 1028 +#define IDC_SENDBUTT 1028 +#define IDC_QUICK4 1029 +#define ID_FILE_CONNECT 32771 +#define ID_FILE_DISCONNECT 32772 +#define ID_CHANNEL_SET_TOPIC 32776 +#define ID_CHANNEL_MODE 32778 +#define ID_CHANNEL_TALK 32781 +#define ID_BUTTON32782 32782 +#define ID_FILE_LISTCHANNELS 32783 +#define ID_FILE_SENDRAW 32784 +#define ID_CHANNEL_PASSWORD 32786 +#define ID_FILE_GETUSERINFO 32789 +#define ID_USER_GETINFO 32790 +#define ID_USER_KICK 32792 +#define ID_USER_BAN 32793 +#define ID_USER_MODE_OP 32796 +#define ID_USER_MODE_VOICE 32798 +#define ID_USER_MODE_NORMAL 32800 +#define ID_CHANNEL_GETBANLIST 32801 +#define ID_BUTTON32802 32802 +#define ID_BUTTON32803 32803 +#define ID_FILE_SILENCE 32804 +#define ID_FILE_UNSILENCE 32805 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 141 +#define _APS_NEXT_COMMAND_VALUE 32806 +#define _APS_NEXT_CONTROL_VALUE 1029 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/GP/GP.dsw b/xrGameSpy/gamespy/GP/GP.dsw new file mode 100644 index 00000000000..c69db83e67c --- /dev/null +++ b/xrGameSpy/gamespy/GP/GP.dsw @@ -0,0 +1,53 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gpstress"=.\gpstress\gpstress.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gptest"=.\gptest\gptest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gptestc"=.\gptestc\gptestc.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/GP/changelog.txt b/xrGameSpy/gamespy/GP/changelog.txt new file mode 100644 index 00000000000..d9553492a2c --- /dev/null +++ b/xrGameSpy/gamespy/GP/changelog.txt @@ -0,0 +1,182 @@ +Changelog for: GameSpy Presence & Messaging SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.13.00 RMV RELEASE Released to Developer Site +12-12-2007 1.12.15 RMV OTHER Updated gptest app to include block list functions and cleaned up buddy messaging +12-05-2007 1.12.14 SN OTHER Added test for searching unique nickes across namespaces +11-27-2007 1.12.13 SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +11-19-2007 1.12.12 SAH OTHER Marked gpFindPlayers and gpSetInvitableGames as DEPRECATED + SAH CLEANUP Removed gpFindPlayers and gpSetInvitableGames from MFC app +11-13-2007 1.12.11 SAH OTHER Modified GP MFC App to support Blocked Lists + SAH FIX Fixed bug where blocked list was deleted from disabling info cache +11-12-2007 1.12.10 MWJ FEATURE Added/updated Add/Remove Block List error messages +11-09-2007 1.12.09 SAH CLEANUP Switched to using a darray for NP Id lookup transactions + SAH FIX Fixed NP Block List Add to keep trying if NP returns busy +11-08-2007 1.12.08 SAH CLEANUP Removed gpGetBlockedList to replace with more consistent functions + SAH FEATURE Added gpGetNumBlocked, gpGetBlockedProfile, gpIsBlocked +11-05-2007 1.12.07 SAH FEATURE Added NP Block List mirroring for gpAddtoBlockedList + SAH FEATURE Added initial support for PS3 NP Block List Syncing +10-30-2007 1.12.06 SAH FEATURE Added BlockedList support and buddy/block list retrieval upon login + SAH FIX Fixed bug causing infoCache to not save when disconnect called before destroy + SAH FIX Fixed memory leak from infoCacheBuddyOnly not freeing up status data +10-23-2007 1.12.05 SAH FIX Fixed NP Sync so it only destroys NP if GP was the one that initialized it +10-11-2007 1.12.04 SAH FIX Fixed gpiPS3.c to use gpSendBuddyRequest to remove errors using GSI_UNICODE +09-14-2007 1.12.03 SAH FEATURE Added initial support for PS3 NP Buddy Syncing + SAH FIX Fixed two bugs in gpSearch.c - searches causing assert and missing unicode support +09-11-2007 1.12.02 DES FEATURE Added support for a search by uniquenick across multiple namespaces +08-23-2007 1.12.01 SAH OTHER Added gpRegisterCdKey to gptest MFC sample +08-06-2007 1.12.00 RMV RELEASE Released to Developer Site +07-27-2007 1.11.03 BED FEATURE Added gpRegisterCdKey +07-19-2007 1.11.02 SAH FIX Added explicit typecasts to remove compiler warnings, Fixed DS project +07-10-2007 1.11.01 RMV FIX Fixed gptest/gptestc Project files to get rid of Unicode warnings + RMV FIX Fixed memory allocation to prevent possible use of uninitialized pointer in gp.c +06-07-2007 1.11.00 SN RELEASE Releasing to developer site +06-07-2007 1.11.00 SN FEATURE Added newer style buddy status info + SN FEATURE Replaced old TCP peer to peer code with UDP Layer + SN FEATURE Added keys/values pair feature +05-22-2007 1.10.05 DES FEATURE Added gpGetInfoNoWait +05-17-2007 1.10.04 DES FIX Added a few explicit casts to avoid warnings +02-21-2007 1.10.03 SN FEATURE Added a version of get reverse buddies that allows a specified list of profiles to be passed in. +01-16-2007 1.10.02 DES FEATURE Added X360 support +12-21-2006 1.10.01 DES FEATURE Added initial support for quiet mode +12-15-2006 1.10.00 MJW RELEASE Released to Developer Site +12-13-2006 1.09.69 SN FIX Removed connection state change to allow the internal disconnect function to change the state +10-05-2006 1.09.68 SAH FIX Updated MacOSX Makefile +09-28-2006 1.09.67 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-07-2006 1.09.66 SAH FIX fixed gpGetBuddyStatus to set 'status' output to '\0' if it encounters NULL data +08-04-2006 1.09.65 SAH OTHER Changed ctime/gmtime calls to gsi time wrapper calls +08-03-2006 1.09.64 DDW FEATURE Added support for automatic login ticket renewal +08-02-2006 1.09.63 DDW OTHER Added productID to GUI for gptest sample +08-02-2006 1.09.62 SAH RELEASE Releasing to developer site +07-31-2006 1.09.62 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 1.09.61 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-24-2006 1.09.60 SAH FIX Removed #ifdef _PS3 for socket calls (changed platformSocket.h to typecast calls) +07-06-2006 1.09.59 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +06-30-2006 1.09.58 SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) + SAH FIX Fixed Linux makefile +06-27-2006 1.09.57 SAH FIX Removed unused variables in gpiInfo.c and gpiSearch.c +06-26-2006 1.09.56 BMS FEATURE Passwords no longer go over the wire in cleartext +05-31-2006 1.09.55 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-30-2006 1.09.54 SAH FIX Fixed PS3 project to work with newest PS3(084_001 SDK) release +05-25-2006 1.09.53 SAH FIX Added PS3 required typecasts + SAH FIX Changed PSP project warning levels + SAH FIX Fixed PS3 project to compile with 084_001 SDK +05-22-2006 1.09.52 SAH FIX Added GSI_UNUSED calls to get rid of codewarrior warnings +05-19-2006 1.09.51 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-15-2006 1.09.50 SAH FIX Added "PS3 Release" configuration to project +05-08-2006 1.09.49 SAH FIX Changed some sprintf calls on empty string to strcpy +04-27-2006 1.09.48 BMS FEATURE Updates to Fedreg implementation: login and profile update also needed partner ID. +04-25-2006 1.09.47 SAH RELEASE Releasing to developer site +04-24-2006 1.09.47 SAH FIX Fixed Nitro project files to work on build machine +04-13-2006 1.09.46 SAH FIX Replaced all (rcode == SOCKET_ERROR) w/ (gsiSocketIsError(rcode)) +04-12-2006 1.09.45 BMS FEATURE Updates for Fedreg. Includes new partner ID parameter on gpInitialize. +02-27-2006 1.09.44 SN FIX Added check to determine if hard coded IP was used for connection manager +02-03-2006 1.09.43 SN FIX Added checks for character string limits within gpConnectNewUser +01-26-2006 1.09.42 SN FIX Added psp prodg solution and project to sgv +01-19-2006 1.09.42 RH FIX Changed gpSendBuddyUTM message type from char * to gsi_char *. +12-16-2005 1.09.41 SN OTHER Cleaned up projects to missing common code if any +12-12-2005 1.09.40 SN FIX Removed connection closed check, eliminating false timeouts +11-18-2005 1.09.40 SN FEATURE Added timeout errors to searches which are non-fatal. +11-17-2005 1.09.39 DES FIX Updated Nitro Makefile. + DES FIX Fixed Unicode incompatibility in gptestc. +11-14-2005 1.09.38 DES FIX Updated the OSX Makefile. + DES FEATURE Added support for GSI_DOMAIN_NAME +11-03-2005 1.09.37 BED FEATURE Added ps3 makefile. +09-21-2005 1.09.36 DES FEATURE Updated DS support + DES FEATURE Updated to use the common debug code + DES FIX All connection operation errors are now fatal errors + DES CLEANUP Cleaned up gptestc and added a firewall option +09-16-2005 1.09.35 BED FEATURE Added a callback for buddy revoke notifications. +08-19-2005 1.09.34 BED FIX Update linux makefile +08-11-2005 1.09.33 BED FEATURE Added support for Buddy UTMs (part one, text messages on separate channel) +07-28-2005 1.09.32 SN RELEASE Releasing to developer site. +07-27-2005 1.09.32 SN FEATURE Added support for new style responses for both gpdeleteprofile and buddy authorizations. +06-03-2005 1.09.31 SN RELEASE Releasing to developer site. +05-26-2005 1.09.31 SN FIX Fixed the setinfo function that sent passwords in clear text. Now passwords are encrypted for security purposes. +05-05-2005 1.09.30 BED FIX Updated projects to use new common folder +04-29-2005 1.09.29 SN OTHER Created a Visual Studio .NET project +04-28-2005 1.09.29 SN RELEASE Releasing to developer site. +04-27-2005 1.09.29 DES RELEASE Limited release to Nintendo DS developers. +04-27-2005 1.09.29 DES CLEANUP Extra printfs in gptestc. + DES FEATURE Always assume a firewall on the DS. +04-25-2005 1.09.28 DES FIX Cleaned up a Nitro warning. + DES CLEANUP General cleanup of gptestc. + DES CLEANUP Disable Win32 linker warning. +04-04-2005 1.09.27 SN RELEASE Releasing to developer site. +04-01-2005 1.09.27 DDW FIX Use gsi_time in transfer file structure to match nonport definition +03-30-2005 1.09.26 SN FIX Changed size of unique nick to match DB size plus null character +03-30-2005 1.09.25 SN FIX Fixed case where time was of type long instead of 32 bit int +03-28-2005 1.09.24 SN FIX Fixed bug with all transfers being deleted when deleting only those associated with a single peer +03-18-2005 1.09.24 DES FIX Fixed typo in parameter explanation. +03-14-2005 1.09.23 DES FEATURE Nintendo DS support +12-28-2004 1.09.22 SN FIX Added const qualifiers to function parameters not modified +09-24-2004 1.09.21 BED FIX SDK now allows you to delete buddies that it doesn't have a status for. +09-16-2004 1.09.20 SN RELEASE Releasing to developer site. +08-31-2004 1.09.20 SN FIX Added call to reset the GP internal connection structure fixing memory leaks +08-27-2004 1.09.19 DES CLEANUP Removed MacOS style includes + DES CLEANUP Removed headers already included in nonport.h + XGD bug in caching profile marketing info + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Fixed warnings under OSX + DES CLEANUP Updated OSX Makefile +08-05-2004 1.09.18 SN RELEASE Releasing to developer site. +07-19-2004 1.09.18 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +06-25-2004 1.09.18 BED FEATURE Added location string to gpInvitePlayer +06-24-2004 1.09.17 BED FEATURE Now encrypting password and cdkey for gpNewUser +06-18-2004 1.09.16 BED RELEASE Releasing to developer site. +06-17-2004 1.09.16 DDW FEATURE Added login ticket support +06-16-2004 1.09.15 BED FEATURE Added PS2 Insock support +05-20-2004 1.09.14 BED RELEASE Releasing to developer site. +05-20-2004 1.09.14 BED FEATURE Added state GP_INFO_CACHING_BUDDY_ONLY. +04-05-2004 1.09.13 BED FIX Fixed small allocation bug in Unicode interface. +03-30-2004 1.09.12 BED FIX Removed misc compiler warnings for VC7 strict compiling. +01-10-2004 1.09.11 BED FIX Fixed typo'd length for email addresses in gpNewUser. +01-08-2004 1.09.10 BED FIX ProfileID was not initialized when receiving a buddy message in UNICODE mode. +01-03-2004 1.09.09 DES FIX Receive and send buffer sizes are now set on incoming Peer sockets. +11-10-2003 1.09.08 DES RELEASE Releasing to developer site. +11-07-2003 1.09.08 BED FIX Removed CodeWarrior strictest warnings. +11-07-2003 1.09.07 DES FIX Updated the linux and PS2 makefiles. +11-04-2003 1.09.06 DES FEATURE Added availability check code. +11-03-2003 1.09.05 BED FIX Converting email and passwords to Ascii instead of UTF8 now. + FIX Removed misc. strict warnings in sample. +10-29-2003 1.09.04 DES FEATURE Pass the gamename to the backend when connecting or searching. +10-21-2003 1.09.03 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-21-2003 1.09.03 DES FEATURE Updated gptest to handle new connect methods. +10-17-2003 1.09.02 DES FIX Changed gptest to use the default GameSpy namespace. +10-16-2003 1.09.01 DES FIX The desirednick pased to gpSuggestUniqueNick now has a + length of GP_UNIQUENICK_LEN instead of GP_NICK_LEN. +09-22-2003 1.09.00 DES FEATURE Added support for unique nicks. + FEATURE Added support for associating a cdkey with a unique nick. + FEATURE Added a namespaceID parameter to gpInitialize for setting the current namespace. + FEATURE Added gpConnectPreAuthenticated for logging in from a partner system. + FIX Minor internal cleanup and fixes. +09-14-2003 1.08.17 DES FIX Removed Unicode defines for gptest debug project. +09-08-2003 1.08.16 BED FEATURE Added wrapper for UNICODE support. +07-24-2003 1.08.15 DES RELEASE Releasing to developer site. +07-24-2003 1.08.15 DES CLEANUP Removed unused gpiSendInfo(). + CLEANUP Fixed up NOFILE usage to prevent warnings. +07-18-2003 1.08.14 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 1.08.13 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 1.08.12 BED FEATURE Added ProDG sample project files. +07-14-2003 1.08.11 DES FIX Changed check for __mips64 to check for _PS2. +07-10-2003 1.08.10 BED CLEANUP Changed GP to use GSI_UNUSED for silencing unused variable warnings. + CLEANUP Added newline to end of gpiUtility.c to silence compiler warning. +05-09-2003 1.08.09 DES CLEANUP Removed Dreamcast support. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +04-08-2003 1.08.08 JED FIX Cleanup up code to remove multiple DevStudio level4 compiler warnings +03-26-2003 1.08.07 DES FIX gpiDisconnect now checks if sockets are valid before attempting to close them. +03-20-2003 1.08.06 DES FEATURE The productID is now reported to the backend on connect. +03-03-2003 1.08.05 DES CLEANUP General cleanup to remove warnings. +12-19-2002 1.08.04 DES RELEASE Releasing to developer site. +12-19-2002 1.08.04 DES CLEANUP Removed assert.h includes. +12-16-2002 1.08.03 DES FIX Set listen call to use SOMAXCONN for the backlog paramter. + CLEANUP Removed call to GOAClearSocketError. +12-13-2002 1.08.02 DES FEATURE Added PS2 eenet stack support. + CLEANUP Cleaned up code to remove PS2 compiler warnings. +12-11-2002 1.08.01 DES OTHER Moved SetSendBufferSize(), GetSendBufferSize(), and GetReceiveBufferSize() to nonport. +09-25-2002 1.08.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/GP/gp.c b/xrGameSpy/gamespy/GP/gp.c new file mode 100644 index 00000000000..90e0dafd706 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gp.c @@ -0,0 +1,4318 @@ +/* +gp.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include +#include +#include "gpi.h" + +//FUNCTIONS +/////////// +GPResult gpInitialize( + GPConnection * connection, + int productID, + int namespaceID, + int partnerID +) +{ + // Check if the backend is available. + ///////////////////////////////////// + if(__GSIACResult != GSIACAvailable) + return GP_PARAMETER_ERROR; + + // Error check. + /////////////// + if(connection == NULL) + return GP_PARAMETER_ERROR; + + return gpiInitialize(connection, productID, namespaceID, partnerID); +} + +void gpDestroy( + GPConnection * connection +) +{ + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return; + + gpiDestroy(connection); +} + +GPResult gpEnable( + GPConnection * connection, + GPEnum state +) +{ + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + return gpiEnable(connection, state); +} + +GPResult gpDisable( + GPConnection * connection, + GPEnum state +) +{ + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + return gpiDisable(connection, state); +} + +GPResult gpProcess( + GPConnection * connection +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + return gpiProcess(connection, 0); +} + +GPResult gpSetCallback( + GPConnection * connection, + GPEnum func, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + int index; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Find which callback. + /////////////////////// + index = func; + if((index < 0) || (index >= GPI_NUM_CALLBACKS)) + Error(connection, GP_PARAMETER_ERROR, "Invalid func."); + + // Set the info. + //////////////// + iconnection->callbacks[index].callback = callback; + iconnection->callbacks[index].param = param; + + return GP_NO_ERROR; +} + +GPResult gpConnectA( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((nick == NULL) || (nick[0] == '\0')) + return GP_PARAMETER_ERROR; + if((email == NULL) || (email[0] == '\0')) + return GP_PARAMETER_ERROR; + if((password == NULL) || (password[0] == '\0')) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + GPConnectResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do it. + ///////// + return gpiConnect(connection, nick, "", email, password, "", "", NULL, firewall, GPIFalse, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpConnectW( + GPConnection * connection, + const unsigned short nick[GP_NICK_LEN], + const unsigned short email[GP_EMAIL_LEN], + const unsigned short password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char nick_A[GP_NICK_LEN]; + char email_A[GP_EMAIL_LEN]; + char password_A[GP_PASSWORD_LEN]; + + UCS2ToAsciiString(nick, nick_A); + UCS2ToAsciiString(email, email_A); + UCS2ToAsciiString(password, password_A); + + return gpConnectA(connection, nick_A, email_A, password_A, firewall, blocking, callback, param); +} +#endif + +GPResult gpConnectNewUserA( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((nick == NULL) || (nick[0] == '\0')) + return GP_PARAMETER_ERROR; + if(uniquenick == NULL) + uniquenick = ""; + if((email == NULL) || (email[0] == '\0')) + return GP_PARAMETER_ERROR; + if((password == NULL) || (password[0] == '\0')) + return GP_PARAMETER_ERROR; + if(cdkey && (cdkey[0] == '\0')) + cdkey = NULL; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check the length of the nick. + //////////////////////////////// + if(strlen(nick) >= GP_NICK_LEN) + Error(connection, GP_PARAMETER_ERROR, "Nick too long."); + + // Check the length of the uniquenick. + ////////////////////////////////////// + if(strlen(uniquenick) >= GP_UNIQUENICK_LEN) + Error(connection, GP_PARAMETER_ERROR, "Uniquenick too long."); + + // Check the length of the email. + ///////////////////////////////// + if(strlen(email) >= GP_EMAIL_LEN) + Error(connection, GP_PARAMETER_ERROR, "Email too long."); + + // Check the length of the password. + //////////////////////////////////// + if(strlen(password) >= GP_PASSWORD_LEN) + Error(connection, GP_PARAMETER_ERROR, "Password too long."); + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + GPConnectResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do it. + ///////// + return gpiConnect(connection, nick, uniquenick, email, password, "", "", cdkey, firewall, GPITrue, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpConnectNewUserW( + GPConnection * connection, + const unsigned short nick[GP_NICK_LEN], + const unsigned short uniquenick[GP_UNIQUENICK_LEN], + const unsigned short email[GP_EMAIL_LEN], + const unsigned short password[GP_PASSWORD_LEN], + const unsigned short cdkey[GP_CDKEY_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char nick_A[GP_NICK_LEN]; + char uniquenick_A[GP_UNIQUENICK_LEN]; + char email_A[GP_NICK_LEN]; + char password_A[GP_NICK_LEN]; + char cdkey_A[GP_CDKEY_LEN]; + + UCS2ToAsciiString(nick, nick_A); + UCS2ToAsciiString(uniquenick, uniquenick_A); + UCS2ToAsciiString(email, email_A); + UCS2ToAsciiString(password, password_A); + UCS2ToAsciiString(cdkey, cdkey_A); + + return gpConnectNewUserA(connection, nick_A, uniquenick_A, email_A, password_A, cdkey_A, firewall, blocking, callback, param); +} +#endif + +GPResult gpConnectUniqueNickA( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((uniquenick == NULL) || (uniquenick[0] == '\0')) + return GP_PARAMETER_ERROR; + if((password == NULL) || (password[0] == '\0')) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + GPConnectResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do it. + ///////// + return gpiConnect(connection, "", uniquenick, "", password, "", "", NULL, firewall, GPIFalse, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpConnectUniqueNickW( + GPConnection * connection, + const unsigned short uniquenick[GP_UNIQUENICK_LEN], + const unsigned short password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char uniquenick_A[GP_UNIQUENICK_LEN]; + char password_A[GP_NICK_LEN]; + + UCS2ToAsciiString(uniquenick, uniquenick_A); + UCS2ToAsciiString(password, password_A); + + return gpConnectUniqueNickA(connection, uniquenick_A, password_A, firewall, blocking, callback, param); +} +#endif + +GPResult gpConnectPreAuthenticatedA +( + GPConnection * connection, + const char authtoken[GP_AUTHTOKEN_LEN], + const char partnerchallenge[GP_PARTNERCHALLENGE_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((authtoken == NULL) || (authtoken[0] == '\0')) + return GP_PARAMETER_ERROR; + if((partnerchallenge == NULL) || (partnerchallenge[0] == '\0')) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + GPConnectResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do it. + ///////// + return gpiConnect(connection, "", "", "", "", authtoken, partnerchallenge, NULL, firewall, GPIFalse, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpConnectPreAuthenticatedW +( + GPConnection * connection, + const unsigned short authtoken[GP_AUTHTOKEN_LEN], + const unsigned short partnerchallenge[GP_PARTNERCHALLENGE_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char authtoken_A[GP_AUTHTOKEN_LEN]; + char partnerchallenge_A[GP_PARTNERCHALLENGE_LEN]; + + UCS2ToAsciiString(authtoken, authtoken_A); + UCS2ToAsciiString(partnerchallenge, partnerchallenge_A); + + return gpConnectPreAuthenticatedA(connection, authtoken_A, partnerchallenge_A, firewall, blocking, callback, param); +} +#endif + +void gpDisconnect( + GPConnection * connection +) +{ + GPIConnection * iconnection; + int oldState; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return; + + // Make a note of connection state prior to reset + ///////////////////////////////////////////////// + oldState = iconnection->connectState; + + gpiDisconnect(connection, GPITrue); + //Added by Saad Nader + //08-28-2004; fix for memory leaks after being disconnected abruptly + //////////////////////////////////////////////// + gpiReset(connection); + + // If we were connected prior, set to disconnected to save off info cache + ////////////////////////////////////////////////////////////////////////// + if (oldState == GPI_CONNECTED) + iconnection->connectState = GPI_DISCONNECTED; + +} + +GPResult gpIsConnected +( + GPConnection * connection, + GPEnum * connected +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Set the flag. + //////////////// + if(iconnection->connectState == GPI_CONNECTED) + *connected = GP_CONNECTED; + else + *connected = GP_NOT_CONNECTED; + + return GP_NO_ERROR; +} + +GPResult gpCheckUserA( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check the length of the nick. + //////////////////////////////// + if(strlen(nick) >= GP_NICK_LEN) + Error(connection, GP_PARAMETER_ERROR, "Nick too long."); + + // Check the length of the email. + ///////////////////////////////// + if(strlen(email) >= GP_EMAIL_LEN) + Error(connection, GP_PARAMETER_ERROR, "Email too long."); + + // Check the length of the password. + //////////////////////////////////// + if(password && (strlen(password) >= GP_PASSWORD_LEN)) + Error(connection, GP_PARAMETER_ERROR, "Password too long."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPCheckResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do the check. + //////////////// + return gpiCheckUser(connection, nick, email, password, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpCheckUserW( + GPConnection * connection, + const unsigned short nick[GP_NICK_LEN], + const unsigned short email[GP_EMAIL_LEN], + const unsigned short password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char nick_A[GP_NICK_LEN]; + char email_A[GP_NICK_LEN]; + char password_A[GP_NICK_LEN]; + + UCS2ToAsciiString(nick, nick_A); + UCS2ToAsciiString(email, email_A); + UCS2ToAsciiString(password, password_A); + + return gpCheckUserA(connection, nick_A, email_A, password_A, blocking, callback, param); +} +#endif + +GPResult gpNewUserA( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((nick == NULL) || (nick[0] == '\0')) + return GP_PARAMETER_ERROR; + if(uniquenick == NULL) + uniquenick = ""; + if((email == NULL) || (email[0] == '\0')) + return GP_PARAMETER_ERROR; + if((password == NULL) || (password[0] == '\0')) + return GP_PARAMETER_ERROR; + if(cdkey && (cdkey[0] == '\0')) + cdkey = NULL; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check the length of the nick. + //////////////////////////////// + if(strlen(nick) >= GP_NICK_LEN) + Error(connection, GP_PARAMETER_ERROR, "Nick too long."); + + // Check the length of the uniquenick. + ////////////////////////////////////// + if(strlen(uniquenick) >= GP_UNIQUENICK_LEN) + Error(connection, GP_PARAMETER_ERROR, "Uniquenick too long."); + + // Check the length of the email. + ///////////////////////////////// + if(strlen(email) >= GP_EMAIL_LEN) + Error(connection, GP_PARAMETER_ERROR, "Email too long."); + + // Check the length of the password. + //////////////////////////////////// + if(strlen(password) >= GP_PASSWORD_LEN) + Error(connection, GP_PARAMETER_ERROR, "Password too long."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPNewUserResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Creat the new user. + ////////////////////// + return gpiNewUser(connection, nick, uniquenick, email, password, cdkey, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpNewUserW( + GPConnection * connection, + const unsigned short nick[GP_NICK_LEN], + const unsigned short uniquenick[GP_UNIQUENICK_LEN], + const unsigned short email[GP_EMAIL_LEN], + const unsigned short password[GP_PASSWORD_LEN], + const unsigned short cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char nick_A[GP_NICK_LEN]; + char uniquenick_A[GP_UNIQUENICK_LEN]; + char email_A[GP_EMAIL_LEN]; + char password_A[GP_PASSWORD_LEN]; + char cdkey_A[GP_CDKEY_LEN]; + + UCS2ToAsciiString(nick, nick_A); + UCS2ToAsciiString(uniquenick, uniquenick_A); + UCS2ToAsciiString(email, email_A); + UCS2ToAsciiString(password, password_A); + UCS2ToAsciiString(cdkey, cdkey_A); + + return gpNewUserA(connection, nick_A, uniquenick_A, email_A, password_A, cdkey_A, blocking, callback, param); +} +#endif + +GPResult gpSuggestUniqueNickA( + GPConnection * connection, + const char desirednick[GP_NICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check the length of the desirednick. + /////////////////////////////////////// + if(strlen(desirednick) >= GP_UNIQUENICK_LEN) + Error(connection, GP_PARAMETER_ERROR, "Desirednick too long."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPSuggestUniqueNickResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Creat the new user. + ////////////////////// + return gpiSuggestUniqueNick(connection, desirednick, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpSuggestUniqueNickW( + GPConnection * connection, + const unsigned short desirednick[GP_NICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char desirednick_A[GP_UNIQUENICK_LEN]; + + UCS2ToAsciiString(desirednick, desirednick_A); + + return gpSuggestUniqueNickA(connection, desirednick_A, blocking, callback, param); +} +#endif + +GPResult gpRegisterUniqueNickA( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((uniquenick == NULL) || (uniquenick[0] == '\0')) + return GP_PARAMETER_ERROR; + if(cdkey && (cdkey[0] == '\0')) + cdkey = NULL; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPRegisterUniqueNickResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiRegisterUniqueNick(connection, uniquenick, cdkey, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpRegisterUniqueNickW( + GPConnection * connection, + const unsigned short uniquenick[GP_UNIQUENICK_LEN], + const unsigned short cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char uniquenick_A[GP_UNIQUENICK_LEN]; + char cdkey_A[GP_CDKEY_LEN]; + + UCS2ToAsciiString(uniquenick, uniquenick_A); + UCS2ToAsciiString(cdkey, cdkey_A); + + return gpRegisterUniqueNickA(connection, uniquenick_A, cdkey_A, blocking, callback, param); +} +#endif + + +GPResult gpRegisterCdKeyA( + GPConnection * connection, + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + if((cdkey == NULL) || (cdkey[0] == '\0')) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPRegisterCdKeyResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiRegisterCdKey(connection, cdkey, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpRegisterCdKeyW( + GPConnection * connection, + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char cdkey_A[GP_CDKEY_LEN]; + UCS2ToAsciiString(cdkey, cdkey_A); + return gpRegisterCdKeyA(connection, cdkey_A, blocking, callback, param); +} +#endif + +GPResult gpGetErrorCode( + GPConnection * connection, + GPErrorCode * errorCode +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Error check. + /////////////// + if(errorCode == NULL) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + *errorCode = (GPErrorCode)0; + return GP_NO_ERROR; + } + + // Set the code. + //////////////// + *errorCode = iconnection->errorCode; + + return GP_NO_ERROR; +} + +GPResult gpGetErrorStringA( + GPConnection * connection, + char errorString[GP_ERROR_STRING_LEN] +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Error check. + /////////////// + if(errorString == NULL) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + errorString[0] = '\0'; + return GP_NO_ERROR; + } + + // Copy the error string. + ///////////////////////// + strzcpy(errorString, iconnection->errorString, GP_ERROR_STRING_LEN); + return GP_NO_ERROR; +} +#ifdef GSI_UNICODE +GPResult gpGetErrorStringW( + GPConnection * connection, + unsigned short errorString[GP_ERROR_STRING_LEN] +) +{ + char errorString_A[GP_ERROR_STRING_LEN]; + GPResult result; + + result = gpGetErrorStringA(connection, errorString_A); + AsciiToUCS2String(errorString_A, errorString); + return result; +} +#endif + +GPResult gpNewProfileA( + GPConnection * connection, + const char nick[GP_NICK_LEN], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check for no nick. + // PANTS|05.18.00 + ///////////////////// + if((nick == NULL) || (nick[0] == '\0')) + Error(connection, GP_PARAMETER_ERROR, "Invalid nick."); + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + GPNewProfileResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiNewProfile(connection, nick, replace, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpNewProfileW( + GPConnection * connection, + const unsigned short nick[GP_NICK_LEN], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char nick_A[GP_NICK_LEN]; + + // Since we don't currently allow UNICODE nicknames, make sure the first byte is empty + // (We make this check as an early alert to devlopers that the parameter is invalid) + // (Even if it's bypassed, the server will still reject the name.) + int i = 0; + for (; (i < GP_NICK_LEN) && (nick[i] != 0); i++) + { + if ((nick[i] & 0xFF00) != 0) + return GP_PARAMETER_ERROR; + } + + // Convert to ascii and call "A" version + UCS2ToAsciiString(nick, nick_A); + return gpNewProfileA(connection, nick_A, replace, blocking, callback, param); +} +#endif + +GPResult gpDeleteProfile( + GPConnection * connection, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + GPDeleteProfileResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiDeleteProfile(connection, callback, param); +} + +GPResult gpProfileFromID( + GPConnection * connection, + GPProfile * profile, + int id +) +{ + GSI_UNUSED(connection); + + // Set the profile. + // This function is depreciated & may be removed from future versions. + ////////////////////////////////////////////////////////////////////// + *profile = id; + + return GP_NO_ERROR; +} + +// gpIDFromProfile +////////////////// +GPResult gpIDFromProfile( + GPConnection * connection, + GPProfile profile, + int * id +) +{ + GSI_UNUSED(connection); + + // ID is the same as GPProfile + // This function is depreciated & may be removed from future versions. + ////////////////////////////////////////////////////////////////////// + *id = profile; + + return GP_NO_ERROR; +} + +// gpUserIDFromProfile +////////////////// +GPResult gpUserIDFromProfile( + GPConnection * connection, + GPProfile profile, + int * userid +) +{ + GPIConnection * iconnection; + GPIProfile * pProfile; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + *userid = 0; + return GP_NO_ERROR; + } + + // Get the profile object. + ////////////////////////// + if(!gpiGetProfile(connection, profile, &pProfile)) + Error(connection, GP_PARAMETER_ERROR, "Invalid profile."); + + // Set the id. + ////////////// + *userid = pProfile->userId; + + return GP_NO_ERROR; +} + + +GPResult gpProfileSearchA( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char firstname[GP_FIRSTNAME_LEN], + const char lastname[GP_LASTNAME_LEN], + int icquin, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPProfileSearchResponseArg arg; + memset(&arg, 0, sizeof(arg)); + arg.more = GP_DONE; + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do the search. + ///////////////// + return gpiProfileSearch(connection, nick, uniquenick, email, firstname, lastname, icquin, 0, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpProfileSearchW( + GPConnection * connection, + const unsigned short nick[GP_NICK_LEN], + const unsigned short uniquenick[GP_UNIQUENICK_LEN], + const unsigned short email[GP_EMAIL_LEN], + const unsigned short firstname[GP_FIRSTNAME_LEN], + const unsigned short lastname[GP_LASTNAME_LEN], + int icquin, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char nick_A[GP_NICK_LEN]; + char uniquenick_A[GP_UNIQUENICK_LEN]; + char email_A[GP_NICK_LEN]; + char firstname_A[GP_NICK_LEN]; + char lastname_A[GP_NICK_LEN]; + + UCS2ToAsciiString(nick, nick_A); // nicknames are ascii + UCS2ToAsciiString(uniquenick, uniquenick_A); + UCS2ToAsciiString(email, email_A); + UCS2ToAsciiString(firstname, firstname_A); + UCS2ToAsciiString(lastname, lastname_A); + + return gpProfileSearchA(connection, nick_A, uniquenick_A, email_A, firstname_A, lastname_A, icquin, blocking, callback, param); +} +#endif + +GPResult gpProfileSearchUniquenickA( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const int namespaceIDs[GP_MAX_NAMESPACEIDS], + int numNamespaces, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL) || (namespaceIDs == NULL) || (numNamespaces < 1)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPProfileSearchResponseArg arg; + memset(&arg, 0, sizeof(arg)); + arg.more = GP_DONE; + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do the search. + ///////////////// + return gpiProfileSearchUniquenick(connection, uniquenick, namespaceIDs, numNamespaces, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpProfileSearchUniquenickW( + GPConnection * connection, + const unsigned short uniquenick[GP_UNIQUENICK_LEN], + const int namespaceIDs[GP_MAX_NAMESPACEIDS], + int numNamespaces, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char uniquenick_A[GP_UNIQUENICK_LEN]; + + UCS2ToAsciiString(uniquenick, uniquenick_A); + + return gpProfileSearchUniquenickA(connection, uniquenick_A, namespaceIDs, numNamespaces, blocking, callback, param); +} +#endif + +GPResult gpGetInfo( + GPConnection * connection, + GPProfile profile, + GPEnum checkCache, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL) || (profile == 0)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPGetInfoResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiGetInfo(connection, profile, checkCache, blocking, callback, param); +} + +GPResult gpGetInfoNoWait( + GPConnection * connection, + GPProfile profile, + GPGetInfoResponseArg * arg +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL) || (profile == 0) || (arg == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + { + memset(arg, 0, sizeof(arg)); + return GP_NO_ERROR; + } + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiGetInfoNoWait(connection, profile, arg); +} + +GPResult gpSetInfoi( + GPConnection * connection, + GPEnum info, + int value +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiSetInfoi(connection, info, value); +} + +GPResult gpSetInfosA( + GPConnection * connection, + GPEnum info, + const char * value +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiSetInfos(connection, info, value); +} +#ifdef GSI_UNICODE +GPResult gpSetInfosW( + GPConnection * connection, + GPEnum info, + const unsigned short* value +) +{ + char* value_A = UCS2ToUTF8StringAlloc(value); + GPResult result = gpSetInfosA(connection, info, value_A); + gsifree(value_A); + return result; +} +#endif + +GPResult gpSetInfod( + GPConnection * connection, + GPEnum info, + int day, + int month, + int year +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiSetInfod(connection, info, day, month, year); +} + +GPResult gpSetInfoMask( + GPConnection * connection, + GPEnum mask +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiSetInfoMask(connection, mask); +} + +GPResult gpSendBuddyRequestA( + GPConnection * connection, + GPProfile profile, + const char reason[GP_REASON_LEN] +) +{ + GPIConnection * iconnection; + char reasonFixed[GP_REASON_LEN]; + int i; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Error check. + /////////////// + if(reason == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid reason."); + + // Replace backslashes in reason. + ///////////////////////////////// + strzcpy(reasonFixed, reason, GP_REASON_LEN); + for(i = 0 ; reasonFixed[i] ; i++) + if(reasonFixed[i] == '\\') + reasonFixed[i] = '/'; + + // Send the request. + //////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\addbuddy\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\newprofileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profile); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\reason\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, reasonFixed); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} +#ifdef GSI_UNICODE +GPResult gpSendBuddyRequestW( + GPConnection * connection, + GPProfile profile, + const unsigned short reason[GP_REASON_LEN] +) +{ + char reason_A[GP_REASON_LEN]; + UCS2ToUTF8String(reason, reason_A); + return gpSendBuddyRequestA(connection, profile, reason_A); +} +#endif + +GPResult gpAuthBuddyRequest( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiAuthBuddyRequest(connection, profile); +} + +GPResult gpDenyBuddyRequest( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + GPIProfile * pProfile; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for simulation mode. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Get the profile. + /////////////////// + if(!gpiGetProfile(connection, profile, &pProfile)) + return GP_NO_ERROR; + + // freeclear the sig if no more requests. + //////////////////////////////////// + pProfile->requestCount--; + if(!iconnection->infoCaching && (pProfile->requestCount <= 0)) + { + freeclear(pProfile->authSig); + if(gpiCanFreeProfile(pProfile)) + gpiRemoveProfile(connection, pProfile); + } + + return GP_NO_ERROR; +} + +GPResult gpGetNumBuddies( + GPConnection * connection, + int * numBuddies +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + *numBuddies = 0; + return GP_NO_ERROR; + } + + // Set the number of buddies. + ///////////////////////////// + *numBuddies = iconnection->profileList.numBuddies; + + return GP_NO_ERROR; +} + +#ifndef GP_NEW_STATUS_INFO +GPResult gpGetBuddyStatus( + GPConnection * connection, + int index, + GPBuddyStatus * status +) +{ + GPIConnection * iconnection; + int num; + GPIProfile * profile; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + memset(status, 0, sizeof(GPBuddyStatus)); + return GP_NO_ERROR; + } + + // Check for a NULL status. + /////////////////////////// + if(status == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid status."); + + // Check the buddy index. + ///////////////////////// + num = iconnection->profileList.numBuddies; + if((index < 0) || (index >= num)) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + // Find the buddy with this index. + ////////////////////////////////// + profile = gpiFindBuddy(connection, index); + if(!profile) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + + assert(profile->buddyStatus); + status->profile = (GPProfile)profile->profileId; + status->status = profile->buddyStatus->status; +#ifndef GSI_UNICODE + if(profile->buddyStatus->statusString) + strzcpy(status->statusString, profile->buddyStatus->statusString, GP_STATUS_STRING_LEN); + else + status->statusString[0] = '\0'; + + + if(profile->buddyStatus->locationString) + strzcpy(status->locationString, profile->buddyStatus->locationString, GP_LOCATION_STRING_LEN); + else + status->locationString[0] = '\0'; + +#else + if(profile->buddyStatus->statusString) + UTF8ToUCS2String(profile->buddyStatus->statusString, status->statusString); + else + status->statusString[0] = '\0'; + + if(profile->buddyStatus->locationString) + UTF8ToUCS2String(profile->buddyStatus->locationString, status->locationString); + else + status->locationString[0] = '\0'; + +#endif + status->ip = profile->buddyStatus->ip; + status->port = profile->buddyStatus->port; + status->quietModeFlags = profile->buddyStatus->quietModeFlags; + + return GP_NO_ERROR; +} +#endif + +#ifdef GP_NEW_STATUS_INFO +GPResult gpGetBuddyStatusInfo( + GPConnection * connection, + int index, + GPBuddyStatusInfo * statusInfo +) +{ + GPIConnection * iconnection; + int num; + GPIProfile * profile; + GPIBuddyStatus *buddyStatus; + GPIBuddyStatusInfo * buddyStatusInfo; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + memset(statusInfo, 0, sizeof(GPBuddyStatusInfo)); + return GP_NO_ERROR; + } + + // Check for a NULL status. + /////////////////////////// + if(statusInfo == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid status."); + + // Check the buddy index. + ///////////////////////// + num = iconnection->profileList.numBuddies; + if((index < 0) || (index >= num)) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + // Find the buddy with this index. + ////////////////////////////////// + profile = gpiFindBuddy(connection, index); + if(!profile) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + + buddyStatus = profile->buddyStatus; + buddyStatusInfo = profile->buddyStatusInfo; + assert(buddyStatus || buddyStatusInfo); + + statusInfo->profile = (GPProfile)profile->profileId; + if (buddyStatus) + { + statusInfo->statusState = buddyStatus->status; +#ifndef GSI_UNICODE + if(buddyStatus->statusString) + strzcpy(statusInfo->richStatus, buddyStatus->statusString, GP_RICH_STATUS_LEN); + else + statusInfo->richStatus[0] = '\0'; + statusInfo->gameType[0] = '\0'; + statusInfo->gameVariant[0] = '\0'; + statusInfo->gameMapName[0] = '\0'; +#else + if(buddyStatus->statusString) + UTF8ToUCS2String(buddyStatus->statusString, statusInfo->richStatus); + else + statusInfo->richStatus[0] = '\0'; + statusInfo->gameType[0] = '\0'; + statusInfo->gameVariant[0] = '\0'; + statusInfo->gameMapName[0] = '\0'; +#endif + statusInfo->buddyIp = buddyStatus->ip; + statusInfo->buddyPort = buddyStatus->port; + statusInfo->quietModeFlags = buddyStatus->quietModeFlags; + statusInfo->newStatusInfoFlag = GP_NEW_STATUS_INFO_NOT_SUPPORTED; + } + else if (buddyStatusInfo) + { + statusInfo->statusState = buddyStatusInfo->statusState; + statusInfo->buddyIp = buddyStatusInfo->buddyIp; + statusInfo->buddyPort = buddyStatusInfo->buddyPort; + statusInfo->hostIp = buddyStatusInfo->hostIp; + statusInfo->hostPrivateIp = buddyStatusInfo->hostPrivateIp; + statusInfo->queryPort = buddyStatusInfo->queryPort; + statusInfo->hostPort = buddyStatusInfo->hostPort; + statusInfo->sessionFlags = buddyStatusInfo->sessionFlags; + statusInfo->quietModeFlags = buddyStatusInfo->quietModeFlags; + statusInfo->newStatusInfoFlag = GP_NEW_STATUS_INFO_SUPPORTED; +#ifndef GSI_UNICODE + strzcpy(statusInfo->richStatus, buddyStatusInfo->richStatus, GP_RICH_STATUS_LEN); + strzcpy(statusInfo->gameType, buddyStatusInfo->gameType, GP_STATUS_BASIC_STR_LEN); + strzcpy(statusInfo->gameVariant, buddyStatusInfo->gameVariant, GP_STATUS_BASIC_STR_LEN); + strzcpy(statusInfo->gameMapName, buddyStatusInfo->gameMapName, GP_STATUS_BASIC_STR_LEN); +#else + UTF8ToUCS2String(buddyStatusInfo->richStatus, statusInfo->richStatus); + UTF8ToUCS2String(buddyStatusInfo->gameType, statusInfo->gameType); + UTF8ToUCS2String(buddyStatusInfo->gameVariant, statusInfo->gameVariant); + UTF8ToUCS2String(buddyStatusInfo->gameMapName, statusInfo->gameMapName); +#endif + } + + return GP_NO_ERROR; +} + +GPResult gpSetBuddyAddr( + GPConnection *connection, + int index, + unsigned int buddyIp, + unsigned short buddyPort +) +{ + GPIConnection * iconnection; + int num; + GPIProfile * profile; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check the buddy index. + ///////////////////////// + num = iconnection->profileList.numBuddies; + if((index < 0) || (index >= num)) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + // Find the buddy with this index. + ////////////////////////////////// + profile = gpiFindBuddy(connection, index); + if(!profile) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + if (buddyIp == 0 || buddyPort == 0) + Error(connection, GP_PARAMETER_ERROR, "Invalid IP and port"); + if (profile->buddyStatusInfo) + { + profile->buddyStatusInfo->buddyIp = buddyIp; + profile->buddyStatusInfo->buddyPort = buddyPort; + } + return GP_NO_ERROR; +} +#endif + +GPResult gpGetBuddyIndex( + GPConnection * connection, + GPProfile profile, + int * index +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + *index = 0; + return GP_NO_ERROR; + } + + // Get the index. + ///////////////// + if(gpiGetProfile(connection, profile, &pProfile) && pProfile->buddyStatus) + *index = pProfile->buddyStatus->buddyIndex; + else if (gpiGetProfile(connection, profile, &pProfile) && pProfile->buddyStatusInfo) + *index = pProfile->buddyStatusInfo->buddyIndex; + else + *index = -1; + + return GP_NO_ERROR; +} + +int gpIsBuddy( + GPConnection * connection, + GPProfile profile +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return 0; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return 0; + + // Get the index. + ///////////////// + if(gpiGetProfile(connection, profile, &pProfile) && pProfile->buddyStatus) + return 1; + else if (gpiGetProfile(connection, profile, &pProfile) &&pProfile->buddyStatusInfo) + return 1; + + return 0; +} + +int gpIsBuddyConnectionOpen( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + GPIPeer *aPeer; + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return 0; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return 0; + + aPeer = gpiGetPeerByProfile(connection, profile); + + if (aPeer == NULL || !gpiIsPeerConnected(aPeer)) + return 0; // not connected + else + return 1; // connected +} + +GPResult gpDeleteBuddy( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Delete the buddy. + //////////////////// + CHECK_RESULT(gpiDeleteBuddy(connection, profile, GPITrue)); + + return GP_NO_ERROR; +} + +GPResult gpAddToBlockedList( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Add em to the internal list - remove buddy status if already a buddy + /////////////////////////////////////////////////////////////////////// + return gpiAddToBlockedList(connection, profile); +} + +GPResult gpRemoveFromBlockedList( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Remove blocked association from internal list if it's there + ////////////////////////////////////////////////////////////// + return gpiRemoveFromBlockedList(connection, profile); +} + +GPResult gpGetNumBlocked( + GPConnection * connection, + int * numBlocked +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + *numBlocked = 0; + return GP_NO_ERROR; + } + + // Set the number of blocked profiles + ///////////////////////////////////// + *numBlocked = iconnection->profileList.numBlocked; + + return GP_NO_ERROR; +} + +GPResult gpGetBlockedProfile( + GPConnection * connection, + int index, + GPProfile * profile +) +{ + GPIConnection * iconnection; + int num; + GPIProfile * pProfile; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for a NULL profile. + //////////////////////////// + if(profile == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid profile container"); + + // Check the block index. + ///////////////////////// + num = iconnection->profileList.numBlocked; + if((index < 0) || (index >= num)) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + // Find the blocked profile with this index. + //////////////////////////////////////////// + pProfile = gpiFindBlockedProfile(connection, index); + if(!pProfile) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + *profile = (GPProfile)pProfile->profileId; + + return GP_NO_ERROR; +} + +gsi_bool gpIsBlocked( + GPConnection * connection, + GPProfile profile +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return gsi_false; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return gsi_false; + + // Get the index. + ///////////////// + if(gpiGetProfile(connection, profile, &pProfile) && pProfile->blocked) + return gsi_true; + + return gsi_false; +} + +#ifndef GP_NEW_STATUS_INFO +GPResult gpSetStatusA( + GPConnection * connection, + GPEnum status, + const char statusString[GP_STATUS_STRING_LEN], + const char locationString[GP_LOCATION_STRING_LEN] +) +{ + char statusStringFixed[GP_STATUS_STRING_LEN]; + char locationStringFixed[GP_LOCATION_STRING_LEN]; + GPIConnection * iconnection; + int i; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Error check. + /////////////// + if(statusString == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid statusString."); + if(locationString == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid locationString."); + + // Replace backslashes with slashes. + //////////////////////////////////// + strzcpy(statusStringFixed, statusString, GP_STATUS_STRING_LEN); + for(i = 0 ; statusStringFixed[i] ; i++) + if(statusStringFixed[i] == '\\') + statusStringFixed[i] = '/'; + strzcpy(locationStringFixed, locationString, GP_LOCATION_STRING_LEN); + for(i = 0 ; locationStringFixed[i] ; i++) + if(locationStringFixed[i] == '\\') + locationStringFixed[i] = '/'; + + // Don't send it if its the same as the previous. + ///////////////////////////////////////////////// + if((status == iconnection->lastStatusState) && + (strcmp(statusStringFixed, iconnection->lastStatusString) == 0) && + (strcmp(locationStringFixed, iconnection->lastLocationString) == 0)) + { + return GP_NO_ERROR; + } + + // Copy off the new status. + /////////////////////////// + iconnection->lastStatusState = status; +#ifndef GSI_UNICODE + strzcpy(iconnection->lastStatusString, statusStringFixed, GP_STATUS_STRING_LEN); + strzcpy(iconnection->lastLocationString, locationStringFixed, GP_LOCATION_STRING_LEN); +#else + UTF8ToUCS2StringLen(iconnection->lastStatusString, iconnection->lastStatusString_W, GP_STATUS_STRING_LEN); + UTF8ToUCS2StringLen(iconnection->lastStatusString, iconnection->lastLocationString_W, GP_LOCATION_STRING_LEN); +#endif + + // Send the new status. + /////////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\status\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, status); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\statstring\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, statusStringFixed); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\locstring\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, locationStringFixed); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} +#ifdef GSI_UNICODE +GPResult gpSetStatusW( + GPConnection * connection, + GPEnum status, + const unsigned short statusString[GP_STATUS_STRING_LEN], + const unsigned short locationString[GP_LOCATION_STRING_LEN] +) +{ + char statusString_A[GP_STATUS_STRING_LEN]; + char locationString_A[GP_LOCATION_STRING_LEN]; + UCS2ToUTF8String(statusString, statusString_A); + UCS2ToUTF8String(locationString, locationString_A); + return gpSetStatusA(connection, status, statusString_A, locationString_A); +} +#endif +#endif + +#ifdef GP_NEW_STATUS_INFO +GPResult gpSetStatusInfoA( + GPConnection *connection, + GPEnum statusState, + unsigned int hostIp, + unsigned int hostPrivateIp, + unsigned short queryPort, + unsigned short hostPort, + unsigned int sessionFlags, + const char *richStatus, + int richStatusLen, + const char *gameType, + int gameTypeLen, + const char *gameVariant, + int gameVariantLen, + const char *gameMapName, + int gameMapNameLen +) +{ + GPIConnection * iconnection; + +#ifndef GSI_UNICODE + char gameTypeFixed[GP_STATUS_BASIC_STR_LEN]; + char gameVariantFixed[GP_STATUS_BASIC_STR_LEN]; + char gameMapNameFixed[GP_STATUS_BASIC_STR_LEN]; +#else + char *gameTypeFixed; + char *gameVariantFixed; + char *gameMapNameFixed; +#endif + + GS_ASSERT(connection != NULL); + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Error check. + /////////////// + GS_ASSERT(richStatus != NULL); + if (richStatus == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid richStatus."); + +#ifndef GSI_UNICODE + GS_ASSERT(richStatusLen <= GP_RICH_STATUS_LEN); + GS_ASSERT(gameTypeLen <= GP_STATUS_BASIC_STR_LEN); + GS_ASSERT(gameVariantLen <= GP_STATUS_BASIC_STR_LEN); + GS_ASSERT(gameMapNameLen <= GP_STATUS_BASIC_STR_LEN); + + if (gameType == NULL) + strncpy(gameTypeFixed, "", GP_STATUS_BASIC_STR_LEN); + else + strncpy(gameTypeFixed, gameType, GP_STATUS_BASIC_STR_LEN); + if (gameVariant == NULL) + strncpy(gameVariantFixed, "", GP_STATUS_BASIC_STR_LEN); + else + strncpy(gameVariantFixed, gameVariant, GP_STATUS_BASIC_STR_LEN); + if (gameMapName == NULL) + strncpy(gameMapNameFixed, "", GP_STATUS_BASIC_STR_LEN); + else + strncpy(gameMapNameFixed, gameMapName, GP_STATUS_BASIC_STR_LEN); + + // Don't send it if its the same as the previous. + ///////////////////////////////////////////////// + if((statusState == iconnection->lastStatusState) && + (strcmp(richStatus, iconnection->richStatus) == 0) && + (strcmp(gameTypeFixed, iconnection->gameType) == 0) && + (strcmp(gameVariantFixed, iconnection->gameVariant) == 0) && + (strcmp(gameMapNameFixed, iconnection->gameMapName) == 0) && + (sessionFlags == iconnection->sessionFlags) && + (hostIp == iconnection->hostIp) && + (hostPrivateIp == iconnection->hostPrivateIp) && + (queryPort == iconnection->queryPort) && + (hostPort == iconnection->hostPort)) + { + return GP_NO_ERROR; + } +#else + gameTypeFixed = goastrdup(gameType); + gameVariantFixed = goastrdup(gameVariant); + gameMapNameFixed = goastrdup(gameMapName); +#endif + + iconnection->lastStatusState = statusState; + iconnection->hostIp = hostIp; + iconnection->hostPrivateIp = hostPrivateIp; + iconnection->queryPort = queryPort; + iconnection->hostPort = hostPort; + iconnection->sessionFlags = sessionFlags; + +#ifndef GSI_UNICODE + strzcpy(iconnection->gameType, gameTypeFixed, GP_STATUS_BASIC_STR_LEN); + strzcpy(iconnection->gameVariant, gameVariantFixed, GP_STATUS_BASIC_STR_LEN); + strzcpy(iconnection->gameMapName, gameMapNameFixed, GP_STATUS_BASIC_STR_LEN); + strzcpy(iconnection->richStatus, richStatus, GP_RICH_STATUS_LEN); +#endif + + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\statusinfo\\\\state\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, statusState); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\hostIp\\"); + gpiAppendUIntToBuffer(connection, &iconnection->outputBuffer, ntohl(hostIp)); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\hprivIp\\"); + gpiAppendUIntToBuffer(connection, &iconnection->outputBuffer, ntohl(hostPrivateIp)); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\qport\\"); + gpiAppendUShortToBuffer(connection, &iconnection->outputBuffer, queryPort); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\hport\\"); + gpiAppendUShortToBuffer(connection, &iconnection->outputBuffer, hostPort); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sessflags\\"); + gpiAppendUIntToBuffer(connection, &iconnection->outputBuffer, sessionFlags); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\richStatus\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, richStatus); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\gameType\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, gameTypeFixed); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\gameVariant\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, gameVariantFixed); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\gameMapName\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, gameMapNameFixed); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + GSI_UNUSED(richStatusLen); + GSI_UNUSED(gameTypeLen); + GSI_UNUSED(gameVariantLen); + GSI_UNUSED(gameMapNameLen); + return GP_NO_ERROR; +} + +#ifdef GSI_UNICODE +GPResult gpSetStatusInfoW( + GPConnection *connection, + GPEnum statusState, + unsigned int hostIp, + unsigned int hostPrivateIp, + unsigned short queryPort, + unsigned short hostPort, + unsigned int sessionFlags, + const unsigned short *richStatus, + int richStatusLen, + const unsigned short *gameType, + int gameTypeLen, + const unsigned short *gameVariant, + int gameVariantLen, + const unsigned short *gameMapName, + int gameMapNameLen + ) +{ + char *richStatus_A, *gameType_A, *gameVariant_A, *gameMapName_A; + GPResult aResult; + GPIConnection * iconnection; + GS_ASSERT(connection != NULL); + GS_ASSERT(richStatusLen <= GP_RICH_STATUS_LEN); + GS_ASSERT(gameTypeLen <= GP_STATUS_BASIC_STR_LEN); + GS_ASSERT(gameVariantLen <= GP_STATUS_BASIC_STR_LEN); + GS_ASSERT(gameMapNameLen <= GP_STATUS_BASIC_STR_LEN); + GS_ASSERT(richStatus != NULL); + + if (connection != NULL && (*connection != NULL)) + iconnection = (GPIConnection *)*connection; + else return GP_PARAMETER_ERROR; + + if (richStatus == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid richStatus."); + + if (richStatusLen <= GP_RICH_STATUS_LEN) + richStatus_A = UCS2ToUTF8StringAlloc(richStatus); + else + richStatus_A = UCS2ToUTF8StringAlloc((UCS2String)_T("")); + if (gameType && (gameTypeLen <= GP_STATUS_BASIC_STR_LEN)) + gameType_A = UCS2ToUTF8StringAlloc(gameType); + else + gameType_A = UCS2ToUTF8StringAlloc((UCS2String)_T("")); + if (gameVariant && (gameVariantLen <= GP_STATUS_BASIC_STR_LEN)) + gameVariant_A = UCS2ToUTF8StringAlloc(gameVariant); + else + gameVariant_A = UCS2ToUTF8StringAlloc((UCS2String)_T("")); + if (gameMapName && (gameMapNameLen <= GP_STATUS_BASIC_STR_LEN)) + gameMapName_A = UCS2ToUTF8StringAlloc(gameMapName); + else + gameMapName_A = UCS2ToUTF8StringAlloc((UCS2String)_T("")); + + if ((statusState == iconnection->lastStatusState) && + (sessionFlags == iconnection->sessionFlags) && + (hostIp == iconnection->hostIp) && + (hostPrivateIp == iconnection->hostPrivateIp) && + (queryPort == iconnection->queryPort) && + (hostPort == iconnection->hostPort) && + (_tcscmp(richStatus, iconnection->richStatus_W) == 0) && + (_tcscmp(gameType, iconnection->gameType_W) == 0) && + (_tcscmp(gameVariant, iconnection->gameVariant_W) == 0) && + (_tcscmp(gameMapName, iconnection->gameMapName_W) == 0)) + { + return GP_NO_ERROR; + } + _tcsncpy(iconnection->richStatus_W, richStatus, GP_RICH_STATUS_LEN); + _tcsncpy(iconnection->gameType_W, gameType, GP_STATUS_BASIC_STR_LEN); + _tcsncpy(iconnection->gameVariant_W, gameVariant, GP_STATUS_BASIC_STR_LEN); + _tcsncpy(iconnection->gameMapName_W, gameMapName, GP_STATUS_BASIC_STR_LEN); + + aResult = gpSetStatusInfoA(connection, statusState, hostIp, hostPrivateIp, queryPort, hostPort, + sessionFlags, richStatus_A, (int)strlen(richStatus_A), gameType_A, (int)strlen(gameType_A), + gameVariant_A, (int)strlen(gameVariant_A), gameMapName_A, (int)strlen(gameMapName_A)); + gsifree(richStatus_A); + gsifree(gameType_A); + gsifree(gameVariant_A); + gsifree(gameMapName_A); + return aResult; +} +#endif + +GPResult gpAddStatusInfoKeyA(GPConnection *connection, const char *keyName, const char *keyValue) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if ((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if ( iconnection->simulation ) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if (iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiStatusInfoAddKey(connection, iconnection->extendedInfoKeys, keyName, keyValue); +} + +#ifdef GSI_UNICODE +GPResult gpAddStatusInfoKeyW(GPConnection *connection, const unsigned short *keyName, const unsigned short *keyValue) +{ + GPResult aResult; + char *keyName_A = UCS2ToUTF8StringAlloc(keyName); + char *keyValue_A = UCS2ToUTF8StringAlloc(keyValue); + aResult = gpAddStatusInfoKeyA(connection, keyName_A, keyValue_A); + gsifree(keyName_A); + gsifree(keyValue_A); + return aResult; +} +#endif + +GPResult gpSetStatusInfoKeyA(GPConnection *connection, const char *keyName, const char *keyValue) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if ((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if ( iconnection->simulation ) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if (iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiStatusInfoSetKey(connection, iconnection->extendedInfoKeys, keyName, keyValue); +} + +#ifdef GSI_UNICODE +GPResult gpSetStatusInfoKeyW(GPConnection *connection, const unsigned short *keyName, const unsigned short *keyValue) +{ + GPResult aResult; + char *keyName_A = UCS2ToUTF8StringAlloc(keyName); + char *keyValue_A = UCS2ToUTF8StringAlloc(keyValue); + aResult = gpSetStatusInfoKeyA(connection, keyName_A, keyValue_A); + gsifree(keyName_A); + gsifree(keyValue_A); + return aResult; +} +#endif + +GPResult gpDelStatusInfoKeyA(GPConnection *connection, const char *keyName) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if ((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if ( iconnection->simulation ) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if (iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiStatusInfoDelKey(connection, iconnection->extendedInfoKeys, keyName); +} + +#ifdef GSI_UNICODE +GPResult gpDelStatusInfoKeyW(GPConnection *connection, const unsigned short *keyName) +{ + GPResult aResult; + char *keyName_A = UCS2ToUTF8StringAlloc(keyName); + aResult = gpDelStatusInfoKeyA(connection, keyName_A); + gsifree(keyName_A); + return aResult; +} +#endif + +GPResult gpGetStatusInfoKeyValA(GPConnection *connection, const char *keyName, char **keyValue) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if ((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if ( iconnection->simulation ) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if (iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + return gpiStatusInfoGetKey(connection, iconnection->extendedInfoKeys, keyName, keyValue); +} +#ifdef GSI_UNICODE +GPResult gpGetStatusInfoKeyValW(GPConnection *connection, const unsigned short *keyName, unsigned short **keyValue) +{ + GPResult aResult; + char *keyValue_A; + + char *keyName_A = UCS2ToUTF8StringAlloc(keyName); + + aResult = gpGetStatusInfoKeyValA(connection, keyName_A, &keyValue_A); + *keyValue = UTF8ToUCS2StringAlloc(keyValue_A); + + gsifree(keyName_A); + gsifree(keyValue_A); + return aResult; +} +#endif + + + +GPResult gpGetBuddyStatusInfoKeys(GPConnection *connection, int index, GPCallback callback, void *userData) +{ + GPIConnection *iconnection; + GPIProfile * pProfile; + GPResult aResult; + GPIPeerOp *aPeerOp; + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + pProfile = gpiFindBuddy(connection, index); + if (!pProfile) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + + if (pProfile->buddyStatus) + CallbackError(connection, GP_PARAMETER_ERROR, GP_BM_EXT_INFO_NOT_SUPPORTED, "The profile does not support extended info keys.") + + if (!pProfile->buddyStatusInfo && !pProfile->buddyStatus) + CallbackError(connection, GP_PARAMETER_ERROR, GP_BM_NOT_BUDDY, "The profile used to get extended info keys is not a buddy.") + + if (pProfile->buddyStatusInfo && pProfile->buddyStatusInfo->statusState == GP_OFFLINE) + CallbackError(connection, GP_NETWORK_ERROR, GP_BM_BUDDY_OFFLINE, "The profile used to get extended info keys is offline."); + + aPeerOp = (GPIPeerOp *)gsimalloc(sizeof(GPIPeerOp)); + aPeerOp->callback = callback; + aPeerOp->next = NULL; + aPeerOp->state = GPI_PEER_OP_STATE_REQUESTED; + aPeerOp->type = GPI_BM_KEYS_REQUEST; + aPeerOp->userData = userData; + aPeerOp->timeout = current_time() + GPI_PEER_OP_TIMEOUT; + aResult = gpiSendBuddyMessage(connection, pProfile->profileId, GPI_BM_KEYS_REQUEST, "Keys?", GP_DONT_ROUTE, aPeerOp); + return aResult; +} +#endif + +GPResult gpSendBuddyMessageA( + GPConnection * connection, + GPProfile profile, + const char * message +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Error check. + /////////////// + if(message == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid message."); + + return gpiSendBuddyMessage(connection, profile, GPI_BM_MESSAGE, message, 0, NULL); +} +#ifdef GSI_UNICODE +GPResult gpSendBuddyMessageW( + GPConnection * connection, + GPProfile profile, + const unsigned short* message +) +{ + char* message_A; + GPResult result; + + assert(message != NULL); + message_A = UCS2ToUTF8StringAlloc(message); // convert to UTF8 + result = gpSendBuddyMessageA(connection, profile, message_A); // send + gsifree(message_A); // free the converted string + return result; +} +#endif + +GPResult gpSendBuddyUTMA( + GPConnection * connection, + GPProfile profile, + const char * message, + int sendOption +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Error check. + /////////////// + if(message == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid message."); + + return gpiSendBuddyMessage(connection, profile, GPI_BM_UTM, message, sendOption, NULL); +} + +#ifdef GSI_UNICODE +GPResult gpSendBuddyUTMW( + GPConnection * connection, + GPProfile profile, + const unsigned short* message, + int sendOption +) +{ + char* message_A; + GPResult result; + + assert(message != NULL); + message_A = UCS2ToUTF8StringAlloc(message); // convert to UTF8 + result = gpSendBuddyUTMA(connection, profile, message_A, sendOption); // send + gsifree(message_A); // free the converted string + return result; +} +#endif + +GPResult gpIsValidEmailA( + GPConnection * connection, + const char email[GP_EMAIL_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check the length of the email. + ///////////////////////////////// + if(strlen(email) >= GP_EMAIL_LEN) + Error(connection, GP_PARAMETER_ERROR, "Email too long."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPIsValidEmailResponseArg arg; + memset(&arg, 0, sizeof(arg)); +#ifndef GSI_UNICODE + strzcpy(arg.email, email, GP_EMAIL_LEN); +#else + UTF8ToUCS2String(email, arg.email); +#endif + arg.isValid = GP_INVALID; + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do the validation. + ///////////////////// + return gpiIsValidEmail(connection, email, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpIsValidEmailW( + GPConnection * connection, + const unsigned short email[GP_EMAIL_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char email_A[GP_EMAIL_LEN]; + UCS2ToAsciiString(email, email_A); + return gpIsValidEmailA(connection, email_A, blocking,callback, param); +} +#endif + +GPResult gpGetUserNicksA( + GPConnection * connection, + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Check the length of the email. + ///////////////////////////////// + if(strlen(email) >= GP_EMAIL_LEN) + Error(connection, GP_PARAMETER_ERROR, "Email too long."); + + // Check the length of the password. + //////////////////////////////////// + if(strlen(password) >= GP_PASSWORD_LEN) + Error(connection, GP_PARAMETER_ERROR, "Password too long."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPGetUserNicksResponseArg arg; + memset(&arg, 0, sizeof(arg)); +#ifndef GSI_UNICODE + strzcpy(arg.email, email, GP_EMAIL_LEN); +#else + AsciiToUCS2String(email, arg.email); +#endif + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Do the validation. + ///////////////////// + return gpiGetUserNicks(connection, email, password, blocking, callback, param); +} +#ifdef GSI_UNICODE +GPResult gpGetUserNicksW( + GPConnection * connection, + const unsigned short email[GP_EMAIL_LEN], + const unsigned short password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + char email_A[GP_EMAIL_LEN]; + char password_A[GP_PASSWORD_LEN]; + UCS2ToAsciiString(email, email_A); + UCS2ToAsciiString(password, password_A); + return gpGetUserNicksA(connection, email_A, password_A, blocking, callback, param); +} +#endif + +GPResult gpSetInvitableGames( + GPConnection * connection, + int numProductIDs, + const int * productIDs +) +{ + GPIConnection * iconnection; + int i; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Error check. + /////////////// + if(numProductIDs < 0) + Error(connection, GP_PARAMETER_ERROR, "Invalid numProductIDs."); + if((numProductIDs > 0) && (productIDs == NULL)) + Error(connection, GP_PARAMETER_ERROR, "Invalid productIDs."); + + // Send the list. + ///////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\inviteto\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\products\\"); + for(i = 0 ; i < numProductIDs ; i++) + { + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, productIDs[i]); + if(i < (numProductIDs - 1)) + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, ","); + } + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult gpFindPlayers( + GPConnection * connection, + int productID, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPFindPlayersResponseArg arg; + memset(&arg, 0, sizeof(arg)); + arg.productID = productID; + arg.numMatches = 0; + arg.matches = NULL; + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Start the find. + ////////////////// + return gpiFindPlayers(connection, productID, blocking, callback, param); +} + +GPResult gpInvitePlayerA( + GPConnection * connection, + GPProfile profile, + int productID, + const char location[GP_LOCATION_STRING_LEN] +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Send the invite. + /////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\pinvite\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profile); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\productid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, productID); + + if (location && location[0]) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\location\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, location); + } + + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} +#ifdef GSI_UNICODE +GPResult gpInvitePlayerW( + GPConnection * connection, + GPProfile profile, + int productID, + const gsi_char location[GP_LOCATION_STRING_LEN] +) +{ + char location_A[GP_LOCATION_STRING_LEN]; + UCS2ToAsciiString(location, location_A); + return gpInvitePlayerA(connection, profile, productID, location_A); +} +#endif + +GPResult gpGetReverseBuddies( + GPConnection * connection, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPGetReverseBuddiesResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Start the search. + //////////////////// + return gpiOthersBuddy(connection, blocking, callback, param); +} + +GPResult gpGetReversBuddiesList( GPConnection * connection, + GPProfile *targets, int numOfTargets, + GPEnum blocking, + GPCallback callback, + void * param) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for no callback. + ///////////////////////// + if(callback == NULL) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + { + GPGetReverseBuddiesListResponseArg arg; + memset(&arg, 0, sizeof(arg)); + callback(connection, &arg, param); + return GP_NO_ERROR; + } + + // Start the search. + //////////////////// + return gpiOthersBuddyList(connection, targets, numOfTargets, blocking, callback, param); + +} + + +GPResult gpRevokeBuddyAuthorization( + GPConnection * connection, + GPProfile profile +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + return GP_NO_ERROR; + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Send the invite. + /////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\revoke\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profile); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + + +GPResult gpGetLoginTicket( + GPConnection * connection, + char loginTicket[GP_LOGIN_TICKET_LEN] +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + memcpy(loginTicket, iconnection->loginTicket, GP_LOGIN_TICKET_LEN); + return GP_NO_ERROR; +} + +GPResult gpSetQuietMode( + GPConnection * connection, + GPEnum flags +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Store the flags locally. + /////////////////////////// + iconnection->quietModeFlags = flags; + + // Check for a connection. + ////////////////////////// + if(iconnection->connectState == GPI_CONNECTED) + { + // Send the flags. + ////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\quiet\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->quietModeFlags); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + } + + return GP_NO_ERROR; +} + +#ifndef NOFILE +void gpSetInfoCacheFilenameA( + const char * filename +) +{ + gpiSetInfoCacheFilename(filename); +} +void gpSetInfoCacheFilenameW( + const unsigned short * filename +) +{ + char* filename_A = UCS2ToUTF8StringAlloc(filename); + gpiSetInfoCacheFilename(filename_A); + gsifree(filename_A); +} + +static GPResult gpiAddSendingFileA( + GPConnection * connection, + GPITransfer * transfer, + const char * path, + const char * name +) +{ + GPIFile * file = NULL; + int size = 0; + gsi_time modTime = 0; + + // Check for a bad path or name. + //////////////////////////////// + if(!path && !name) + Error(connection, GP_PARAMETER_ERROR, "File missing path and name."); + if(path && !path[0]) + Error(connection, GP_PARAMETER_ERROR, "Empty path."); + if(name && !name[0]) + Error(connection, GP_PARAMETER_ERROR, "Empty name."); + + // Check that the file exists and is readable. + ////////////////////////////////////////////// + if(path) + { + FILE * fileVerify; + + fileVerify = fopen(path, "r"); + if(!fileVerify) + Error(connection, GP_PARAMETER_ERROR, "Can't find file."); + + if(!gpiGetTransferFileInfo(fileVerify, &size, &modTime)) + { + fclose(fileVerify); + Error(connection, GP_PARAMETER_ERROR, "Can't get info on file."); + } + + fclose(fileVerify); + } + + // Validate the name. + ///////////////////// + if(name) + { + size_t len; + + len = strlen(name); + + if(strstr(name, "//") || strstr(name, "\\\\")) + Error(connection, GP_PARAMETER_ERROR, "Empty directory in filename."); + if(strstr(name, "./") || strstr(name, ".\\") || (name[len - 1] == '.')) + Error(connection, GP_PARAMETER_ERROR, "Directory level in filename."); + if((name[0] == '/') || (name[0] == '\\')) + Error(connection, GP_PARAMETER_ERROR, "Filename can't start with a slash."); + if(strcspn(name, ":*?\"<>|\n") != len) + Error(connection, GP_PARAMETER_ERROR, "Invalid character in filename."); + } + // The name is the path's title. + //////////////////////////////// + else + { + const char * str; + + // Find the end of the path. + //////////////////////////// + name = strrchr(path, '/'); + str = strrchr(path, '\\'); + if(str > name) + name = str; + + // Point the name at the title. + /////////////////////////////// + if(name) + name++; + else + name = path; + } + + // Add this to the list. + //////////////////////// + file = gpiAddFileToTransfer(transfer, path, name); + if(!file) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Set the size and time. + ///////////////////////// + file->size = size; + file->modTime = modTime; + + // Update the total size. + ///////////////////////// + transfer->totalSize += size; + + return GP_NO_ERROR; +} +#ifdef GSI_UNICODE +static GPResult gpiAddSendingFileW( + GPConnection * connection, + GPITransfer * transfer, + const unsigned short * path, + const unsigned short * name +) +{ + char* path_A = UCS2ToUTF8StringAlloc(path); + char* name_A = UCS2ToUTF8StringAlloc(name); + GPResult result = gpiAddSendingFileA(connection, transfer, path_A, name_A); + gsifree(path_A); + gsifree(name_A); + return result; +} +#endif + + +GPResult gpSendFilesA( + GPConnection * connection, + GPTransfer * transfer, + GPProfile profile, + const char * message, + gpSendFilesCallback callback, + void * param +) +{ + GPIConnection * iconnection; + GPITransfer * pTransfer; + GPResult result; + const gsi_char * path; + const gsi_char * name; + int numFiles; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Check for simulation mode. + ///////////////////////////// + if(iconnection->simulation) + Error(connection, GP_PARAMETER_ERROR, "Cannot send files in simulation mode."); + + // Check for disconnected. + ////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + Error(connection, GP_PARAMETER_ERROR, "The connection has already been disconnected."); + + // Check other stuff. + ///////////////////// + if(!callback) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + if(!iconnection->callbacks[GPI_TRANSFER_CALLBACK].callback) + Error(connection, GP_PARAMETER_ERROR, "No callback."); + + // No message is an empty message. + ////////////////////////////////// + if(!message) + message = ""; + + // Create the transfer object. + ////////////////////////////// + CHECK_RESULT(gpiNewSenderTransfer(connection, &pTransfer, profile)); + + // Fill in the message. + /////////////////////// + pTransfer->message = goastrdup(message); + if(!pTransfer->message) + { + gpiFreeTransfer(connection, pTransfer); + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + + // Add all the files. + ///////////////////// + numFiles = 0; + do + { + path = NULL; + name = NULL; + callback(connection, numFiles++, &path, &name, param); + if(path && !path[0]) + path = NULL; + if(name && !name[0]) + name = NULL; + + if(name || path) + { +#ifndef GSI_UNICODE + result = gpiAddSendingFileA(connection, pTransfer, path, name); +#else + result = gpiAddSendingFileW(connection, pTransfer, path, name); +#endif + if(result != GP_NO_ERROR) + { + gpiFreeTransfer(connection, pTransfer); + return result; + } + } + } + while(name || path); + + // Check that we got at least 1 file. + ///////////////////////////////////// + if(!ArrayLength(pTransfer->files)) + { + gpiFreeTransfer(connection, pTransfer); + Error(connection, GP_PARAMETER_ERROR, "No files to send."); + } + + // Ping the receiver. + ///////////////////// + result = gpiSendBuddyMessage(connection, profile, GPI_BM_PING, "1", 0, NULL); + if(result != GP_NO_ERROR) + { + gpiFreeTransfer(connection, pTransfer); + return result; + } + + // Successful so far. + ///////////////////// + if(transfer) + *transfer = pTransfer->localID; + + return GP_NO_ERROR; +} +GPResult gpSendFilesW( + GPConnection * connection, + GPTransfer * transfer, + GPProfile profile, + const unsigned short* message, + gpSendFilesCallback callback, + void * param +) +{ + char* message_A = NULL; + GPResult result; + + if (message == NULL) + return gpSendFilesA(connection, transfer, profile, NULL, callback, param); + + message_A = UCS2ToUTF8StringAlloc(message); + result = gpSendFilesA(connection, transfer, profile, message_A, callback, param); + gsifree(message_A); + return result; +} + +GPResult gpAcceptTransferA( + GPConnection * connection, + GPTransfer transfer, + const char * message +) +{ + GPITransfer * pTransfer; + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Check that we have a directory set. + ////////////////////////////////////// + if(!pTransfer->baseDirectory) + Error(connection, GP_PARAMETER_ERROR, "No transfer directory set."); + + // Check if this transfer has been cancelled. + ///////////////////////////////////////////// + if(pTransfer->state & GPITransferCancelled) + Error(connection, GP_PARAMETER_ERROR, "Transfer already cancelled."); + + // Send a reply. + //////////////// + CHECK_RESULT(gpiSendTransferReply(connection, &pTransfer->transferID, pTransfer->peer, GPI_ACCEPTED, message)); + + // We're now transferring. + ////////////////////////// + pTransfer->state = GPITransferTransferring; + + // Set the current file index to the first file. + //////////////////////////////////////////////// + pTransfer->currentFile = 0; + + return GP_NO_ERROR; +} +GPResult gpAcceptTransferW( + GPConnection * connection, + GPTransfer transfer, + const unsigned short * message +) +{ + char* message_A = NULL; + GPResult result; + + if (message == NULL) + return gpAcceptTransferA(connection, transfer, NULL); + + message_A = UCS2ToUTF8StringAlloc(message); + result = gpAcceptTransferA(connection, transfer, message_A); + gsifree(message_A); + return result; +} + + +GPResult gpRejectTransferA( + GPConnection * connection, + GPTransfer transfer, + const char * message +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + return GP_NO_ERROR; + + // Check if this transfer has been cancelled. + ///////////////////////////////////////////// + if(pTransfer->state & GPITransferCancelled) + return GP_NO_ERROR; + + // Send the reply. + ////////////////// + gpiSendTransferReply(connection, &pTransfer->transferID, pTransfer->peer, GPI_REJECTED, message); + + // Free the transfer. + ///////////////////// + gpiFreeTransfer(connection, pTransfer); + + return GP_NO_ERROR; +} +GPResult gpRejectTransferW( + GPConnection * connection, + GPTransfer transfer, + const unsigned short* message +) +{ + char* message_A = NULL; + GPResult result; + + if (message == NULL) + return gpRejectTransferA(connection, transfer, NULL); + + message_A = UCS2ToUTF8StringAlloc(message); + result = gpRejectTransferA(connection, transfer, message_A); + gsifree(message_A); + return result; +} + +GPResult gpFreeTransfer( + GPConnection * connection, + GPTransfer transfer +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + return GP_NO_ERROR; + + // Check if this should be a reject. + //////////////////////////////////// + if(!pTransfer->sender && (pTransfer->state == GPITransferWaiting)) + return gpRejectTransfer(connection, transfer, NULL); + + // Check for cancelling. + //////////////////////// + if(pTransfer->state < GPITransferComplete) + gpiCancelTransfer(connection, pTransfer); + + // Free the transfer. + ///////////////////// + gpiFreeTransfer(connection, pTransfer); + + return GP_NO_ERROR; +} + +GPResult gpSetTransferData( + GPConnection * connection, + GPTransfer transfer, + void * userData +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Set the data. + //////////////// + pTransfer->userData = userData; + + return GP_NO_ERROR; +} + +void * gpGetTransferData( + GPConnection * connection, + GPTransfer transfer +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + return NULL; + + // Return the data. + /////////////////// + return pTransfer->userData; +} + +GPResult gpSetTransferDirectoryA( + GPConnection * connection, + GPTransfer transfer, + const char * directory +) +{ + GPITransfer * pTransfer; + char lastChar; + + if(!directory || !directory[0]) + Error(connection, GP_PARAMETER_ERROR, "Invalid directory."); + lastChar = directory[strlen(directory) - 1]; + if((lastChar != '\\') && (lastChar != '/')) + Error(connection, GP_PARAMETER_ERROR, "Invalid directory."); + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // This has to be set before transferring. + ////////////////////////////////////////// + if(pTransfer->sender) + Error(connection, GP_PARAMETER_ERROR, "Sender has no transfer directory."); + if(pTransfer->state != GPITransferWaiting) + Error(connection, GP_PARAMETER_ERROR, "Can only set transfer directory before transferring."); + + // Free any existing directory. + /////////////////////////////// + if(pTransfer->baseDirectory) + gsifree(pTransfer->baseDirectory); + pTransfer->baseDirectory = NULL; + + // Set the directory. + ///////////////////// + pTransfer->baseDirectory = goastrdup(directory); + if(!pTransfer->baseDirectory) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + return GP_NO_ERROR; +} +GPResult gpSetTransferDirectoryW( + GPConnection * connection, + GPTransfer transfer, + const unsigned short * directory +) +{ + char* directory_A = UCS2ToUTF8StringAlloc(directory); + GPResult result = gpSetTransferDirectoryA(connection, transfer, directory_A); + gsifree(directory_A); + return result; +} + +GPResult gpSetTransferThrottle( + GPConnection * connection, + GPTransfer transfer, + int throttle +) +{ + GPITransfer * pTransfer; + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + + // Negative means no throttle. + ////////////////////////////// + if(throttle < 0) + throttle = -1; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Store the throttle setting. + ////////////////////////////// + pTransfer->throttle = throttle; + + // Send the rate. + ///////////////// + CHECK_RESULT(gpiPeerStartTransferMessage(connection, pTransfer->peer, GPI_BM_FILE_TRANSFER_THROTTLE, (GPITransferID_st)&pTransfer->transferID)); + gpiSendOrBufferString(connection, pTransfer->peer, "\\rate\\"); + gpiSendOrBufferInt(connection, pTransfer->peer, throttle); + gpiPeerFinishTransferMessage(connection, pTransfer->peer, NULL, 0); + + // If we're the sender, call the callback. + ////////////////////////////////////////// + if(pTransfer->sender) + { + GPTransferCallbackArg * arg; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = pTransfer->localID; + arg->type = GP_TRANSFER_THROTTLE; + arg->num = throttle; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + } + + return GP_NO_ERROR; +} + +GPResult gpGetTransferThrottle( + GPConnection * connection, + GPTransfer transfer, + int * throttle +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the throttle. + //////////////////// + *throttle = pTransfer->throttle; + + return GP_NO_ERROR; +} + +GPResult gpGetTransferProfile( + GPConnection * connection, + GPTransfer transfer, + GPProfile * profile +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the profile. + /////////////////// + *profile = pTransfer->profile; + + return GP_NO_ERROR; +} + +GPResult gpGetTransferSide( + GPConnection * connection, + GPTransfer transfer, + GPEnum * side +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the side. + //////////////// + if(pTransfer->sender) + *side = GP_TRANSFER_SENDER; + else + *side = GP_TRANSFER_RECEIVER; + + return GP_NO_ERROR; +} + +GPResult gpGetTransferSize( + GPConnection * connection, + GPTransfer transfer, + int * size +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the size. + //////////////// + *size = pTransfer->totalSize; + + return GP_NO_ERROR; +} + +GPResult gpGetTransferProgress( + GPConnection * connection, + GPTransfer transfer, + int * progress +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the progress. + //////////////////// + *progress = pTransfer->progress; + + return GP_NO_ERROR; +} + +GPResult gpGetNumFiles( + GPConnection * connection, + GPTransfer transfer, + int * num +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the progress. + //////////////////// + *num = ArrayLength(pTransfer->files); + + return GP_NO_ERROR; +} + +GPResult gpGetCurrentFile( + GPConnection * connection, + GPTransfer transfer, + int * index +) +{ + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the current file. + //////////////////////// + *index = pTransfer->currentFile; + + return GP_NO_ERROR; +} + +GPResult gpSkipFile( + GPConnection * connection, + GPTransfer transfer, + int index +) +{ + GPIFile * file; + GPITransfer * pTransfer; + GPTransferCallbackArg * arg; + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection*)*connection; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the file. + //////////////// + if((index < 0) || (index >= ArrayLength(pTransfer->files))) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + file = (GPIFile *)ArrayNth(pTransfer->files, index); + + // Are we already past this file? + ///////////////////////////////// + if(index < pTransfer->currentFile) + return GP_NO_ERROR; + + // Did we not get to this file yet? + /////////////////////////////////// + if(pTransfer->currentFile != index) + { + // Mark it. + /////////// + file->flags |= GPI_FILE_SKIP; + + // If we're receiving, let the sender know we want to skip it. + ////////////////////////////////////////////////////////////// + if(!pTransfer->sender) + gpiSkipFile(connection, pTransfer, index, GPI_SKIP_USER_SKIP); + + return GP_NO_ERROR; + } + + // If we're receiving, delete our temp file. + //////////////////////////////////////////// + if(!pTransfer->sender && (index == pTransfer->currentFile) && file->file) + { + fclose(file->file); + file->file = NULL; + remove(file->path); + } + + // Skip the current file. + ///////////////////////// + gpiSkipCurrentFile(connection, pTransfer, GPI_SKIP_USER_SKIP); + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = pTransfer->localID; + arg->index = index; + arg->type = GP_FILE_SKIP; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + return GP_NO_ERROR; +} + +GPResult gpGetFileName( + GPConnection * connection, + GPTransfer transfer, + int index, + gsi_char ** name +) +{ + GPIFile * file; + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the file. + //////////////// + if((index < 0) || (index >= ArrayLength(pTransfer->files))) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + file = (GPIFile *)ArrayNth(pTransfer->files, index); + + // Get the name. + //////////////// +#ifndef GSI_UNICODE + *name = file->name; +#else + *name = file->name_W; +#endif + + return GP_NO_ERROR; +} + + +GPResult gpGetFilePath( + GPConnection * connection, + GPTransfer transfer, + int index, + gsi_char ** path +) +{ + GPIFile * file; + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the file. + //////////////// + if((index < 0) || (index >= ArrayLength(pTransfer->files))) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + file = (GPIFile *)ArrayNth(pTransfer->files, index); + + // Get the path. + //////////////// +#ifndef GSI_UNICODE + *path = file->path; +#else + *path = file->path_W; +#endif + + return GP_NO_ERROR; +} + +GPResult gpGetFileSize( + GPConnection * connection, + GPTransfer transfer, + int index, + int * size +) +{ + GPIFile * file; + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the file. + //////////////// + if((index < 0) || (index >= ArrayLength(pTransfer->files))) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + file = (GPIFile *)ArrayNth(pTransfer->files, index); + + // Get the size. + //////////////// + *size = file->size; + + return GP_NO_ERROR; +} + +GPResult gpGetFileProgress( + GPConnection * connection, + GPTransfer transfer, + int index, + int * progress +) +{ + GPIFile * file; + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the file. + //////////////// + if((index < 0) || (index >= ArrayLength(pTransfer->files))) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + file = (GPIFile *)ArrayNth(pTransfer->files, index); + + // Get the progress. + //////////////////// + *progress = file->progress; + + return GP_NO_ERROR; +} + +GPResult gpGetFileModificationTime( + GPConnection * connection, + GPTransfer transfer, + int index, + gsi_time * modTime +) +{ + GPIFile * file; + GPITransfer * pTransfer; + + // Get the transfer. + //////////////////// + pTransfer = gpiFindTransferByLocalID(connection, transfer); + if(!pTransfer) + Error(connection, GP_PARAMETER_ERROR, "Invalid transfer."); + + // Get the file. + //////////////// + if((index < 0) || (index >= ArrayLength(pTransfer->files))) + Error(connection, GP_PARAMETER_ERROR, "Invalid index."); + file = (GPIFile *)ArrayNth(pTransfer->files, index); + + // Get the modTime. + /////////////////// + *modTime = file->modTime; + + return GP_NO_ERROR; +} + +GPResult gpGetNumTransfers( + GPConnection * connection, + int * num +) +{ + GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for NULL. + ////////////////// + if(num == NULL) + Error(connection, GP_PARAMETER_ERROR, "NULL pointer."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Set num. + /////////// + *num = ArrayLength(iconnection->transfers); + + return GP_NO_ERROR; +} + +GPResult gpGetTransfer( + GPConnection * connection, + int index, + GPTransfer * transfer +) +{ + GPIConnection * iconnection; + int localID; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return GP_PARAMETER_ERROR; + + // Check for NULL. + ////////////////// + if(transfer == NULL) + Error(connection, GP_PARAMETER_ERROR, "NULL pointer."); + + // Get the connection object. + ///////////////////////////// + iconnection = (GPIConnection *)*connection; + + // Get the local ID. + //////////////////// + localID = gpiGetTransferLocalIDByIndex(connection, index); + + // Check if it was a bad index. + /////////////////////////////// + if(localID == -1) + Error(connection, GP_PARAMETER_ERROR, "Index out of range."); + + // Set the transfer they want. + ////////////////////////////// + *transfer = localID; + + return GP_NO_ERROR; +} +#endif + +#ifdef _DEBUG +void gpProfilesReport( + GPConnection * connection, + void (* report)(const char * output) +) +{ + //GPIConnection * iconnection; + + // Error check. + /////////////// + if((connection == NULL) || (*connection == NULL)) + return; + + // Get the connection object. + ///////////////////////////// + //iconnection = (GPIConnection *)*connection; + + gpiReport(connection, report); +} +#endif diff --git a/xrGameSpy/gamespy/GP/gp.h b/xrGameSpy/gamespy/GP/gp.h new file mode 100644 index 00000000000..b0ea430af23 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gp.h @@ -0,0 +1,1631 @@ +/* +gp.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ +#ifndef _GP_H_ +#define _GP_H_ + +// necessary for gsi_char and UNICODE support +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//ENUMS +//////// +typedef enum _GPEnum +{ + // Callbacks + //////////// + GP_ERROR = 0, + GP_RECV_BUDDY_REQUEST, + GP_RECV_BUDDY_STATUS, + GP_RECV_BUDDY_MESSAGE, + GP_RECV_BUDDY_UTM, + GP_RECV_GAME_INVITE, + GP_TRANSFER_CALLBACK, + GP_RECV_BUDDY_AUTH, + GP_RECV_BUDDY_REVOKE, + + // Global States. + ///////////////// + GP_INFO_CACHING = 0x0100, + GP_SIMULATION, + GP_INFO_CACHING_BUDDY_AND_BLOCK_ONLY, + + // Blocking + /////////// + GP_BLOCKING = 1, + GP_NON_BLOCKING = 0, + + // Firewall + /////////// + GP_FIREWALL = 1, + GP_NO_FIREWALL = 0, + + // Check Cache + ////////////// + GP_CHECK_CACHE = 1, + GP_DONT_CHECK_CACHE = 0, + + // Is Valid Email. + // PANTS|02.15.00 + ////////////////// + GP_VALID = 1, + GP_INVALID = 0, + + // Fatal Error. + /////////////// + GP_FATAL = 1, + GP_NON_FATAL = 0, + + // Sex + ////// + GP_MALE = 0x0500, + GP_FEMALE, + GP_PAT, + + // Profile Search. + ////////////////// + GP_MORE = 0x0600, + GP_DONE, + + // Set Info + /////////// + GP_NICK = 0x0700, + GP_UNIQUENICK, + GP_EMAIL, + GP_PASSWORD, + GP_FIRSTNAME, + GP_LASTNAME, + GP_ICQUIN, + GP_HOMEPAGE, + GP_ZIPCODE, + GP_COUNTRYCODE, + GP_BIRTHDAY, + GP_SEX, + GP_CPUBRANDID, + GP_CPUSPEED, + GP_MEMORY, + GP_VIDEOCARD1STRING, + GP_VIDEOCARD1RAM, + GP_VIDEOCARD2STRING, + GP_VIDEOCARD2RAM, + GP_CONNECTIONID, + GP_CONNECTIONSPEED, + GP_HASNETWORK, + GP_OSSTRING, + GP_AIMNAME, // PANTS|03.20.01 + GP_PIC, + GP_OCCUPATIONID, + GP_INDUSTRYID, + GP_INCOMEID, + GP_MARRIEDID, + GP_CHILDCOUNT, + GP_INTERESTS1, + + // New Profile. + /////////////// + GP_REPLACE = 1, + GP_DONT_REPLACE = 0, + + // Is Connected. + //////////////// + GP_CONNECTED = 1, + GP_NOT_CONNECTED = 0, + + // Public mask. + /////////////// + GP_MASK_NONE = 0x00000000, + GP_MASK_HOMEPAGE = 0x00000001, + GP_MASK_ZIPCODE = 0x00000002, + GP_MASK_COUNTRYCODE = 0x00000004, + GP_MASK_BIRTHDAY = 0x00000008, + GP_MASK_SEX = 0x00000010, + GP_MASK_EMAIL = 0x00000020, + GP_MASK_ALL = 0xFFFFFFFF, + + // Status + ///////// + GP_OFFLINE = 0, + GP_ONLINE = 1, + GP_PLAYING = 2, + GP_STAGING = 3, + GP_CHATTING = 4, + GP_AWAY = 5, + + // Session flags + ///////////////// + GP_SESS_IS_CLOSED = 0x00000001, + GP_SESS_IS_OPEN = 0x00000002, + GP_SESS_HAS_PASSWORD = 0x00000004, + GP_SESS_IS_BEHIND_NAT = 0x00000008, + GP_SESS_IS_RANKED = 0x000000010, + + + // CPU Brand ID + /////////////// + GP_INTEL = 1, + GP_AMD, + GP_CYRIX, + GP_MOTOROLA, + GP_ALPHA, + + // Connection ID. + ///////////////// + GP_MODEM = 1, + GP_ISDN, + GP_CABLEMODEM, + GP_DSL, + GP_SATELLITE, + GP_ETHERNET, + GP_WIRELESS, + + // Transfer callback type. + // *** the transfer is ended when these types are received + ////////////////////////// + GP_TRANSFER_SEND_REQUEST = 0x800, // arg->num == numFiles + GP_TRANSFER_ACCEPTED, + GP_TRANSFER_REJECTED, // *** + GP_TRANSFER_NOT_ACCEPTING, // *** + GP_TRANSFER_NO_CONNECTION, // *** + GP_TRANSFER_DONE, // *** + GP_TRANSFER_CANCELLED, // *** + GP_TRANSFER_LOST_CONNECTION, // *** + GP_TRANSFER_ERROR, // *** + GP_TRANSFER_THROTTLE, // arg->num == Bps + GP_FILE_BEGIN, + GP_FILE_PROGRESS, // arg->num == numBytes + GP_FILE_END, + GP_FILE_DIRECTORY, + GP_FILE_SKIP, + GP_FILE_FAILED, // arg->num == error + + // GP_FILE_FAILED error + /////////////////////// + GP_FILE_READ_ERROR = 0x900, + GP_FILE_WRITE_ERROR, + GP_FILE_DATA_ERROR, + + // Transfer Side. + ///////////////// + GP_TRANSFER_SENDER = 0xA00, + GP_TRANSFER_RECEIVER, + + // UTM send options. + //////////////////// + GP_DONT_ROUTE = 0xB00, // only send direct + + // Quiet mode flags. + //////////////////// + GP_SILENCE_NONE = 0x00000000, + GP_SILENCE_MESSAGES = 0x00000001, + GP_SILENCE_UTMS = 0x00000002, + GP_SILENCE_LIST = 0x00000004, // includes requests, auths, and revokes + GP_SILENCE_ALL = 0xFFFFFFFF, + + // Flags for checking if newer version of status info is supported + GP_NEW_STATUS_INFO_SUPPORTED = 0xC00, + GP_NEW_STATUS_INFO_NOT_SUPPORTED = 0xC01 +} GPEnum; + +//RESULTS +////////// +typedef enum _GPResult +{ + GP_NO_ERROR, + GP_MEMORY_ERROR, + GP_PARAMETER_ERROR, + GP_NETWORK_ERROR, + GP_SERVER_ERROR, + GP_MISC_ERROR, + GP_COUNT +} GPResult; + +//ERROR CODES +///////////// +//#define GP_ERROR_TYPE(errorCode) ((errorCode) >> 8) +typedef enum _GPErrorCode +{ + // General. + /////////// + GP_GENERAL = 0x0000, + GP_PARSE, + GP_NOT_LOGGED_IN, + GP_BAD_SESSKEY, + GP_DATABASE, + GP_NETWORK, + GP_FORCED_DISCONNECT, + GP_CONNECTION_CLOSED, + GP_UDP_LAYER, + + // Login. + ///////// + GP_LOGIN = 0x0100, + GP_LOGIN_TIMEOUT, + + GP_LOGIN_BAD_NICK, + GP_LOGIN_BAD_EMAIL, + GP_LOGIN_BAD_PASSWORD, + GP_LOGIN_BAD_PROFILE, + GP_LOGIN_PROFILE_DELETED, + GP_LOGIN_CONNECTION_FAILED, + GP_LOGIN_SERVER_AUTH_FAILED, + GP_LOGIN_BAD_UNIQUENICK, + GP_LOGIN_BAD_PREAUTH, + + // Newuser. + /////////// + GP_NEWUSER = 0x0200, + GP_NEWUSER_BAD_NICK, + GP_NEWUSER_BAD_PASSWORD, + GP_NEWUSER_UNIQUENICK_INVALID, + GP_NEWUSER_UNIQUENICK_INUSE, + + // Updateui. + //////////// + GP_UPDATEUI = 0x0300, + GP_UPDATEUI_BAD_EMAIL, + + // Newprofile. + ////////////// + GP_NEWPROFILE = 0x0400, + GP_NEWPROFILE_BAD_NICK, + GP_NEWPROFILE_BAD_OLD_NICK, + + // Updatepro. + ///////////// + GP_UPDATEPRO = 0x0500, + GP_UPDATEPRO_BAD_NICK, + + // Addbuddy. + //////////// + GP_ADDBUDDY = 0x0600, + GP_ADDBUDDY_BAD_FROM, + GP_ADDBUDDY_BAD_NEW, + GP_ADDBUDDY_ALREADY_BUDDY, + + // Authadd. + /////////// + GP_AUTHADD = 0x0700, + GP_AUTHADD_BAD_FROM, + GP_AUTHADD_BAD_SIG, + + // Status. + ////////// + GP_STATUS = 0x0800, + + // Bm. + ////// + GP_BM = 0x0900, + GP_BM_NOT_BUDDY, + GP_BM_EXT_INFO_NOT_SUPPORTED, + GP_BM_BUDDY_OFFLINE, + + // Getprofile. + ////////////// + GP_GETPROFILE = 0x0A00, + GP_GETPROFILE_BAD_PROFILE, + + // Delbuddy. + //////////// + GP_DELBUDDY = 0x0B00, + GP_DELBUDDY_NOT_BUDDY, + + // Delprofile. + ///////////// + GP_DELPROFILE = 0x0C00, + GP_DELPROFILE_LAST_PROFILE, + + // Search. + ////////// + GP_SEARCH = 0x0D00, + GP_SEARCH_CONNECTION_FAILED, + GP_SEARCH_TIMED_OUT, + + // Check. + ///////// + GP_CHECK = 0x0E00, + GP_CHECK_BAD_EMAIL, + GP_CHECK_BAD_NICK, + GP_CHECK_BAD_PASSWORD, + + // Revoke. + ////////// + GP_REVOKE = 0x0F00, + GP_REVOKE_NOT_BUDDY, + + // Registeruniquenick. + ////////////////////// + GP_REGISTERUNIQUENICK = 0x1000, + GP_REGISTERUNIQUENICK_TAKEN, + GP_REGISTERUNIQUENICK_RESERVED, + GP_REGISTERUNIQUENICK_BAD_NAMESPACE, + + // Register cdkey. + ////////////////// + GP_REGISTERCDKEY = 0x1100, + GP_REGISTERCDKEY_BAD_KEY, + GP_REGISTERCDKEY_ALREADY_SET, + GP_REGISTERCDKEY_ALREADY_TAKEN, + + // AddBlock. + //////////// + GP_ADDBLOCK = 0x1200, + GP_ADDBLOCK_ALREADY_BLOCKED, + + // RemoveBlock. + /////////////// + GP_REMOVEBLOCK = 0x1300, + GP_REMOVEBLOCK_NOT_BLOCKED + +} GPErrorCode; + +//STRING LENGTHS +//////////////// +#define GP_NICK_LEN 31 +#define GP_UNIQUENICK_LEN 21 +#define GP_FIRSTNAME_LEN 31 +#define GP_LASTNAME_LEN 31 +#define GP_EMAIL_LEN 51 +#define GP_PASSWORD_LEN 31 +#define GP_PASSWORDENC_LEN ((((GP_PASSWORD_LEN+2)*4)/3)+1) +#define GP_HOMEPAGE_LEN 76 +#define GP_ZIPCODE_LEN 11 +#define GP_COUNTRYCODE_LEN 3 +#define GP_PLACE_LEN 128 +#define GP_AIMNAME_LEN 51 +#define GP_REASON_LEN 1025 +#define GP_STATUS_STRING_LEN 256 +#define GP_LOCATION_STRING_LEN 256 +#define GP_ERROR_STRING_LEN 256 +#define GP_AUTHTOKEN_LEN 256 +#define GP_PARTNERCHALLENGE_LEN 256 +#define GP_CDKEY_LEN 65 +#define GP_CDKEYENC_LEN ((((GP_CDKEY_LEN+2)*4)/3)+1) +#define GP_LOGIN_TICKET_LEN 25 + +#define GP_RICH_STATUS_LEN 256 +#define GP_STATUS_BASIC_STR_LEN 33 + +// Random number seed for PASSWORDENC and CDKEYENC +// MUST MATCH SERVER - If you change this, you'll have to +// release an updated server +#define GP_XOR_SEED 0x79707367 // "gspy" + +// Well known values for partner ID. +#define GP_PARTNERID_GAMESPY 0 +#define GP_PARTNERID_IGN 10 + +// Maximum number of namespaces that can be searched for a uniquenick +#define GP_MAX_NAMESPACEIDS 16 + +//TYPES +//////// +// GPConnection +/////////////// +typedef void * GPConnection; + +// GPProfile +//////////// +typedef int GPProfile; + +// GPTransfer +///////////// +typedef int GPTransfer; + +// GPCallback +///////////// +typedef void (* GPCallback)( + GPConnection * connection, + void * arg, + void * param +); + +//STRUCTURES +///////////// +// GPErrorArg +///////////// +typedef struct +{ + GPResult result; + GPErrorCode errorCode; + gsi_char * errorString; + GPEnum fatal; +} GPErrorArg; + +// GPConnectResponseArg +//////////////////////// +typedef struct +{ + GPResult result; + GPProfile profile; + gsi_char uniquenick[GP_UNIQUENICK_LEN]; +} GPConnectResponseArg; + +// GPNewUserResponseArg +/////////////////////// +typedef struct +{ + GPResult result; + GPProfile profile; +} GPNewUserResponseArg; + +// GPCheckResponseArg +///////////////////// +typedef struct +{ + GPResult result; + GPProfile profile; +} GPCheckResponseArg; + +// GPSuggestUniqueNickResponseArg +///////////////////////////////// +typedef struct +{ + GPResult result; + int numSuggestedNicks; + gsi_char ** suggestedNicks; +} GPSuggestUniqueNickResponseArg; + +// GPRegisterUniqueNickResponseArg +////////////////////////////////// +typedef struct +{ + GPResult result; +} GPRegisterUniqueNickResponseArg; + +// GPRegisterCdKeyResponseArg +////////////////////////////////// +typedef struct +{ + GPResult result; +} GPRegisterCdKeyResponseArg; + +// GPNewProfileResponseArg +////////////////////////// +typedef struct +{ + GPResult result; + GPProfile profile; +} GPNewProfileResponseArg; + +// GPDeleteProfileResponseArg +///////////////////////////// + +typedef struct +{ + GPResult result; + GPProfile profile; +} GPDeleteProfileResponseArg; + +// GPProfileSearchMatch +/////////////////////// +typedef struct +{ + GPProfile profile; + gsi_char nick[GP_NICK_LEN]; + gsi_char uniquenick[GP_UNIQUENICK_LEN]; + int namespaceID; + gsi_char firstname[GP_FIRSTNAME_LEN]; + gsi_char lastname[GP_LASTNAME_LEN]; + gsi_char email[GP_EMAIL_LEN]; +} GPProfileSearchMatch; + +// GPProfileSearchResponseArg +///////////////////////////// +typedef struct +{ + GPResult result; + int numMatches; + GPEnum more; + GPProfileSearchMatch * matches; +} GPProfileSearchResponseArg; + +// GPGetInfoResponseArg +/////////////////////// +typedef struct +{ + GPResult result; + GPProfile profile; + gsi_char nick[GP_NICK_LEN]; + gsi_char uniquenick[GP_UNIQUENICK_LEN]; + gsi_char email[GP_EMAIL_LEN]; + gsi_char firstname[GP_FIRSTNAME_LEN]; + gsi_char lastname[GP_LASTNAME_LEN]; + gsi_char homepage[GP_HOMEPAGE_LEN]; + int icquin; + gsi_char zipcode[GP_ZIPCODE_LEN]; + gsi_char countrycode[GP_COUNTRYCODE_LEN]; + float longitude; // negative is west, positive is east. (0, 0) means unknown. + float latitude; // negative is south, positive is north. (0, 0) means unknown. + gsi_char place[GP_PLACE_LEN]; // e.g., "USA|California|Irvine", "South Korea|Seoul", "Turkey" + int birthday; + int birthmonth; + int birthyear; + GPEnum sex; + GPEnum publicmask; + gsi_char aimname[GP_AIMNAME_LEN]; + int pic; + int occupationid; + int industryid; + int incomeid; + int marriedid; + int childcount; + int interests1; + int ownership1; + int conntypeid; +} GPGetInfoResponseArg; + +// GPRecvBuddyRequestArg +//////////////////////// +typedef struct +{ + GPProfile profile; + unsigned int date; + gsi_char reason[GP_REASON_LEN]; +} GPRecvBuddyRequestArg; + +// GPBuddyStatus +//////////////// +typedef struct +{ + GPProfile profile; + GPEnum status; + gsi_char statusString[GP_STATUS_STRING_LEN]; + gsi_char locationString[GP_LOCATION_STRING_LEN]; + unsigned int ip; + int port; + GPEnum quietModeFlags; +} GPBuddyStatus; + + +// BETA +//GPBuddyStatusInfo +/////////////////// +typedef struct +{ + GPProfile profile; + GPEnum statusState; + unsigned int buddyIp; + unsigned short buddyPort; + unsigned int hostIp; + unsigned int hostPrivateIp; + unsigned short queryPort; + unsigned short hostPort; + unsigned int sessionFlags; + gsi_char richStatus[GP_RICH_STATUS_LEN]; + gsi_char gameType[GP_STATUS_BASIC_STR_LEN]; + gsi_char gameVariant[GP_STATUS_BASIC_STR_LEN]; + gsi_char gameMapName[GP_STATUS_BASIC_STR_LEN]; + GPEnum quietModeFlags; + GPEnum newStatusInfoFlag; +} GPBuddyStatusInfo; + +//GPGetBuddyStatusInfoKeysArg +///////////////////////////// +typedef struct +{ + GPProfile profile; + gsi_char **keys; + gsi_char **values; + int numKeys; + +} GPGetBuddyStatusInfoKeysArg; + + +// GPRecvBuddyStatusArg +/////////////////////// +typedef struct +{ + GPProfile profile; + unsigned int date; + int index; +} GPRecvBuddyStatusArg; + +// GPRecvBuddyMessageArg +//////////////////////// +typedef struct +{ + GPProfile profile; + unsigned int date; + gsi_char * message; +} GPRecvBuddyMessageArg; + +typedef struct +{ + GPProfile profile; + unsigned int date; + gsi_char * message; +} GPRecvBuddyUTMArg; + +typedef struct +{ + GPProfile profile; + unsigned int date; +} GPRecvBuddyAuthArg; + +typedef struct +{ + GPProfile profile; + unsigned int date; +} GPRecvBuddyRevokeArg; + +// GPTransferCallbackArg; +///////////////////////// +typedef struct +{ + GPTransfer transfer; + GPEnum type; + int index; + int num; + gsi_char * message; +} GPTransferCallbackArg; + +// GPIsValidEmailResponseArg +//////////////////////////// +typedef struct +{ + GPResult result; + gsi_char email[GP_EMAIL_LEN]; + GPEnum isValid; +} GPIsValidEmailResponseArg; + +// GPGetUserNicksResponseArg +//////////////////////////// +typedef struct +{ + GPResult result; + gsi_char email[GP_EMAIL_LEN]; + int numNicks; // If 0, then the email/password did not match. + gsi_char ** nicks; + gsi_char ** uniquenicks; +} GPGetUserNicksResponseArg; + +// GPRecvGameInviteArg +////////////////////// +typedef struct +{ + GPProfile profile; + int productID; + gsi_char location[GP_LOCATION_STRING_LEN]; +} GPRecvGameInviteArg; + +// GPFindPlayerMatch +//////////////////// +typedef struct +{ + GPProfile profile; + gsi_char nick[GP_NICK_LEN]; + GPEnum status; + gsi_char statusString[GP_STATUS_STRING_LEN]; +} GPFindPlayerMatch; + +// GPFindPlayersResponseArg +/////////////////////////// +typedef struct +{ + GPResult result; + int productID; //PANTS|06.06.00 - added by request for JED + int numMatches; + GPFindPlayerMatch * matches; +} GPFindPlayersResponseArg; + +// GPGetReverseBuddiesResponseArg +///////////////////////////////// +typedef struct +{ + GPResult result; + int numProfiles; + GPProfileSearchMatch * profiles; +} GPGetReverseBuddiesResponseArg; + +typedef struct +{ + GPProfile profile; + gsi_char uniqueNick[GP_UNIQUENICK_LEN]; +} GPUniqueMatch; + +typedef struct +{ + GPResult result; + int numOfUniqueMatchs; + GPUniqueMatch *matches; +} GPGetReverseBuddiesListResponseArg; + + +//GLOBALS +///////// +/* The hostnames of the connection manager +server and the search manager server. +If the app resolves either or both hostnames, +the IP(s) can be stored in the string(s) before +calling gpInitialize */ +extern char GPConnectionManagerHostname[64]; +extern char GPSearchManagerHostname[64]; + + +//FUNCTIONS +//////////// +#ifndef GSI_UNICODE +#define gpConnect gpConnectA +#define gpConnectNewUser gpConnectNewUserA +#define gpConnectUniqueNick gpConnectUniqueNickA +#define gpConnectPreAuthenticated gpConnectPreAuthenticatedA +#define gpCheckUser gpCheckUserA +#define gpNewUser gpNewUserA +#define gpSuggestUniqueNick gpSuggestUniqueNickA +#define gpRegisterUniqueNick gpRegisterUniqueNickA +#define gpRegisterCdKey gpRegisterCdKeyA +#define gpGetErrorString gpGetErrorStringA +#define gpNewProfile gpNewProfileA +#define gpProfileSearch gpProfileSearchA +#define gpProfileSearchUniquenick gpProfileSearchUniquenickA +#define gpSetInfos gpSetInfosA +#define gpSendBuddyRequest gpSendBuddyRequestA +#ifndef GP_NEW_STATUS_INFO +#define gpSetStatus gpSetStatusA +#endif +#ifdef GP_NEW_STATUS_INFO +// BETA +#define gpSetStatusInfo gpSetStatusInfoA +#endif +#define gpSendBuddyMessage gpSendBuddyMessageA +#define gpSendBuddyUTM gpSendBuddyUTMA +#define gpIsValidEmail gpIsValidEmailA +#define gpGetUserNicks gpGetUserNicksA +#define gpSetInfoCacheFilename gpSetInfoCacheFilenameA +#define gpSendFiles gpSendFilesA +#define gpAcceptTransfer gpAcceptTransferA +#define gpRejectTransfer gpRejectTransferA +#define gpSetTransferDirectory gpSetTransferDirectoryA +#define gpGetFileName gpGetFileNameA +#define gpGetFilePath gpGetFilePathA +#define gpInvitePlayer gpInvitePlayerA +#ifdef GP_NEW_STATUS_INFO +// BETA +#define gpAddStatusInfoKey gpAddStatusInfoKeyA +#define gpSetStatusInfoKey gpSetStatusInfoKeyA +#define gpGetStatusInfoKeyVal gpGetStatusInfoKeyValA +#define gpDelStatusInfoKey gpDelStatusInfoKeyA +#endif +#else +#define gpConnect gpConnectW +#define gpConnectNewUser gpConnectNewUserW +#define gpConnectUniqueNick gpConnectUniqueNickW +#define gpConnectPreAuthenticated gpConnectPreAuthenticatedW +#define gpCheckUser gpCheckUserW +#define gpNewUser gpNewUserW +#define gpSuggestUniqueNick gpSuggestUniqueNickW +#define gpRegisterUniqueNick gpRegisterUniqueNickW +#define gpRegisterCdKey gpRegisterCdKeyW +#define gpGetErrorString gpGetErrorStringW +#define gpNewProfile gpNewProfileW +#define gpProfileSearch gpProfileSearchW +#define gpProfileSearchUniquenick gpProfileSearchUniquenickW +#define gpSetInfos gpSetInfosW +#define gpSendBuddyRequest gpSendBuddyRequestW +#ifndef GP_NEW_STATUS_INFO +#define gpSetStatus gpSetStatusW +#endif +#ifdef GP_NEW_STATUS_INFO +// BETA +#define gpSetStatusInfo gpSetStatusInfoW +#endif +#define gpSendBuddyMessage gpSendBuddyMessageW +#define gpSendBuddyUTM gpSendBuddyUTMW +#define gpIsValidEmail gpIsValidEmailW +#define gpGetUserNicks gpGetUserNicksW +#define gpSetInfoCacheFilename gpSetInfoCacheFilenameW +#define gpSendFiles gpSendFilesW +#define gpAcceptTransfer gpAcceptTransferW +#define gpRejectTransfer gpRejectTransferW +#define gpSetTransferDirectory gpSetTransferDirectoryW +#define gpGetFileName gpGetFileNameW +#define gpGetFilePath gpGetFilePathW +#define gpInvitePlayer gpInvitePlayerW +// #ifdef GP_NEW_STATUS_INFO +// BETA +// #define gpAddStatusInfoKey gpAddStatusInfoKeyW +// #define gpSetStatusInfoKey gpSetStatusInfoKeyW +// #define gpGetStatusInfoKeyVal gpGetStatusInfoKeyValW +// #define gpDelStatusInfoKey gpDelStatusInfoKeyW +// #endif +#endif + +// gpInitialize +/////////////// +GPResult gpInitialize +( + GPConnection * connection, + int productID, // The productID is a unique ID that identifies your product + int namespaceID, // The namespaceID identified which namespace to login under. A namespaceID of 0 indicates that no + // namespace should be used. A namespaceID of 1 represents the default GameSpy namespace + int partnerID // The partnerID identifies the account system being used. + // Use GP_PARTNERID_GAMESPY for GSID accounts. + // Use GP_PARTNERID_IGN for IGN accounts. +); + +// gpDestroy +//////////// +void gpDestroy( + GPConnection * connection +); + +// gpEnable +/////////// +GPResult gpEnable +( + GPConnection * connection, + GPEnum state +); + +// gpDisable +//////////// +GPResult gpDisable +( + GPConnection * connection, + GPEnum state +); + +// gpProcess +//////////// +GPResult gpProcess +( + GPConnection * connection +); + +// gpSetCallback +//////////////// +GPResult gpSetCallback +( + GPConnection * connection, + GPEnum func, + GPCallback callback, + void * param +); + +// gpConnect +//////////// +GPResult gpConnect +( + GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpConnectNewUser +/////////////////// +GPResult gpConnectNewUser +( + GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpConnectUniqueNick +////////////////////// +GPResult gpConnectUniqueNick +( + GPConnection * connection, + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpConnectPreAuthenticated +//////////////////////////// +GPResult gpConnectPreAuthenticated +( + GPConnection * connection, + const gsi_char authtoken[GP_AUTHTOKEN_LEN], + const gsi_char partnerchallenge[GP_PARTNERCHALLENGE_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpDisconnect +/////////////// +void gpDisconnect +( + GPConnection * connection +); + +// gpIsConnected +//////////////// +GPResult gpIsConnected +( + GPConnection * connection, + GPEnum * connected +); + +// gpCheckUser +////////////// +GPResult gpCheckUser +( + GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpNewUser +//////////// +GPResult gpNewUser +( + GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpSuggestUniqueNick +////////////////////// +GPResult gpSuggestUniqueNick +( + GPConnection * connection, + const gsi_char desirednick[GP_UNIQUENICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpRegisterUniqueNick +/////////////////////// +GPResult gpRegisterUniqueNick +( + GPConnection * connection, + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpRegisterCdKey +/////////////////////// +GPResult gpRegisterCdKey +( + GPConnection * connection, + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpGetErrorCode +///////////////// +GPResult gpGetErrorCode( + GPConnection * connection, + GPErrorCode * errorCode +); + +// gpGetErrorString +/////////////////// +GPResult gpGetErrorString( + GPConnection * connection, + gsi_char errorString[GP_ERROR_STRING_LEN] +); + +// gpNewProfile +/////////////// +GPResult gpNewProfile( + GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpDeleteProfile +////////////////// +GPResult gpDeleteProfile( + GPConnection * connection, + GPCallback callback, + void * param +); + +// gpProfileFromID +// PANTS|09.11.00 - A GPProfile is now the same +// as a profileid. This function is no longer needed +// and will be removed in a future version of GP. +///////////////////////////////////////////////////// +GPResult gpProfileFromID( + GPConnection * connection, + GPProfile * profile, + int id +); + +// gpIDFromProfile +// PANTS|09.11.00 - A GPProfile is now the same +// as a profileid. This function is no longer needed +// and will be removed in a future version of GP. +///////////////////////////////////////////////////// +GPResult gpIDFromProfile( + GPConnection * connection, + GPProfile profile, + int * id +); + +// gpUserIDFromProfile +////////////////// +GPResult gpUserIDFromProfile( + GPConnection * connection, + GPProfile profile, + int * userid +); + +// gpProfileSearch +////////////////// +GPResult gpProfileSearch( + GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char firstname[GP_FIRSTNAME_LEN], + const gsi_char lastname[GP_LASTNAME_LEN], + int icquin, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpProfileSearchUniquenick +//////////////////////////// +GPResult gpProfileSearchUniquenick( + GPConnection * connection, + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const int namespaceIDs[GP_MAX_NAMESPACEIDS], + int numNamespaces, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpGetInfo +//////////// +GPResult gpGetInfo( + GPConnection * connection, + GPProfile profile, + GPEnum checkCache, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpGetInfoNoWait +////////////////// +GPResult gpGetInfoNoWait( + GPConnection * connection, + GPProfile profile, + GPGetInfoResponseArg * arg +); + +// gpSetInfoi +///////////// +GPResult gpSetInfoi( + GPConnection * connection, + GPEnum info, + int value +); + +// gpSetInfos +///////////// +GPResult gpSetInfos( + GPConnection * connection, + GPEnum info, + const gsi_char * value +); + +// gpSetInfod +///////////// +GPResult gpSetInfod( + GPConnection * connection, + GPEnum info, + int day, + int month, + int year +); + +// gpSetInfoMask +//////////////// +GPResult gpSetInfoMask( + GPConnection * connection, + GPEnum mask +); + +// gpSendBuddyRequest +///////////////////// +GPResult gpSendBuddyRequest( + GPConnection * connection, + GPProfile profile, + const gsi_char reason[GP_REASON_LEN] +); + +// gpAuthBuddyRequest +///////////////////// +GPResult gpAuthBuddyRequest( + GPConnection * connection, + GPProfile profile +); + +// gpDenyBuddyRequest +// PANTS|09.11.00 +///////////////////// +GPResult gpDenyBuddyRequest( + GPConnection * connection, + GPProfile profile +); + +// gpDeleteBuddy +//////////////// +GPResult gpDeleteBuddy( + GPConnection * connection, + GPProfile profile +); + +// gpAddToBlockedList +///////////////////// +GPResult gpAddToBlockedList( + GPConnection * connection, + GPProfile profile +); + +// gpRemoveFromBlockedList +///////////////////// +GPResult gpRemoveFromBlockedList( + GPConnection * connection, + GPProfile profile +); + +// gpGetNumBlocked +////////////////// +GPResult gpGetNumBlocked( + GPConnection * connection, + int * numBlocked +); + +// gpGetBlockedProfile +///////////////////// +GPResult gpGetBlockedProfile( + GPConnection * connection, + int index, + GPProfile * profile +); + +// gpIsBlocked +// returns gsi_true if blocked, gsi_false if not blocked +//////////////////////////////////////////////////////// +gsi_bool gpIsBlocked( + GPConnection * connection, + GPProfile profile +); + +// gpGetNumBuddies +////////////////// +GPResult gpGetNumBuddies( + GPConnection * connection, + int * numBuddies +); + +// gpGetBuddyStatus +/////////////////// +#ifndef GP_NEW_STATUS_INFO +GPResult gpGetBuddyStatus( + GPConnection * connection, + int index, + GPBuddyStatus * status +); +#endif + +#ifdef GP_NEW_STATUS_INFO +// +////////////////////////////// +GPResult gpGetBuddyStatusInfo( + GPConnection * connection, + int index, + GPBuddyStatusInfo * statusInfo +); + +GPResult gpSetBuddyAddr( + GPConnection *connection, + int index, + unsigned int buddyIp, + unsigned short buddyPort +); +#endif +// gpGetBuddyIndex +////////////////// +GPResult gpGetBuddyIndex( + GPConnection * connection, + GPProfile profile, + int * index +); + +// gpIsBuddy +// returns 1 if a buddy, 0 if not a buddy +//////////// +int gpIsBuddy( + GPConnection * connection, + GPProfile profile +); + +int gpIsBuddyConnectionOpen( + GPConnection * connection, + GPProfile profile +); + +// gpSetStatus +////////////// +#ifndef GP_NEW_STATUS_INFO +GPResult gpSetStatus( + GPConnection * connection, + GPEnum status, + const gsi_char statusString[GP_STATUS_STRING_LEN], + const gsi_char locationString[GP_LOCATION_STRING_LEN] +); +#endif + +#ifdef GP_NEW_STATUS_INFO +GPResult gpSetStatusInfo( + GPConnection *connection, + GPEnum statusState, + unsigned int hostIp, + unsigned int hostPrivateIp, + unsigned short queryPort, + unsigned short hostPort, + unsigned int sessionFlags, + const gsi_char *richStatus, + int richStatusLen, + const gsi_char *gameType, + int gameTypeLen, + const gsi_char *gameVariant, + int gameVariantLen, + const gsi_char *gameMapName, + int gameMapNameLen +); + +GPResult gpAddStatusInfoKey(GPConnection *connection, const gsi_char *keyName, const gsi_char *keyValue); +GPResult gpSetStatusInfoKey(GPConnection *connection, const gsi_char *keyName, const gsi_char *keyValue); +GPResult gpGetStatusInfoKeyVal(GPConnection *connection, const gsi_char *keyName, gsi_char **keyValue); +GPResult gpDelStatusInfoKey(GPConnection *connection, const gsi_char *keyName); + +GPResult gpGetBuddyStatusInfoKeys(GPConnection *connection, int index, GPCallback callback, void *userData); +#endif +// gpSendBuddyMessage +///////////////////// +GPResult gpSendBuddyMessage( + GPConnection * connection, + GPProfile profile, + const gsi_char * message +); + +// gpSendBuddyUTM +///////////////////// +GPResult gpSendBuddyUTM( + GPConnection * connection, + GPProfile profile, + const gsi_char * message, + int sendOption // GP_DONT_ROUTE +); + + +// PANTS|02.15.00 +// Added gpIsValidEmail and gpGetUserNicks for login wizard. +//////////////////////////////////////////////////////////// + +// gpIsValidEmail +///////////////// +GPResult gpIsValidEmail( + GPConnection * connection, + const gsi_char email[GP_EMAIL_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpGetUserNicks +///////////////// +GPResult gpGetUserNicks( + GPConnection * connection, + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +// *DEPRECATED* +// gpSetInvitableGames +////////////////////// +GPResult gpSetInvitableGames( + GPConnection * connection, + int numProductIDs, + const int * productIDs +); + +// *DEPRECATED* +// gpFindPlayers +//////////////// +GPResult gpFindPlayers( + GPConnection * connection, + int productID, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpInvitePlayer +///////////////// +GPResult gpInvitePlayer( + GPConnection * connection, + GPProfile profile, + int productID, + const gsi_char location[GP_LOCATION_STRING_LEN] +); + +// gpGetReverseBuddies +// Get profiles that have you on their buddy list. +////////////////////////////////////////////////// +GPResult gpGetReverseBuddies( + GPConnection * connection, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpGetReverseBuddiesList +// Get profile ids and unique nicks for profiles +// that have you on their buddy list. +////////////////////////////////////////////////// +GPResult gpGetReversBuddiesList( GPConnection * connection, + GPProfile *targets, int numOfTargets, + GPEnum blocking, + GPCallback callback, + void * param +); + +// gpRevokeBuddyAuthorization +///////////////////////////// +GPResult gpRevokeBuddyAuthorization( + GPConnection * connection, + GPProfile profile +); + +// gpSetCdKey +GPResult gpSetCdKey( + GPConnection * connection, + const gsi_char cdkeyhash, + GPCallback callback +); + +// gpGetLoginTicket +///////////////////////////// +GPResult gpGetLoginTicket( + GPConnection * connection, + char loginTicket[GP_LOGIN_TICKET_LEN] +); + +// gpSetQuietMode +///////////////// +GPResult gpSetQuietMode( + GPConnection * connection, + GPEnum flags +); + +#ifndef NOFILE + +// gpiSetInfoCacheFilename +// Should be called before gpIntialize. +/////////////////////////////////////// +void gpSetInfoCacheFilename( + const gsi_char * filename +); + +/////////////////// +// FILE TRANSFER // +/////////////////// +typedef void (* gpSendFilesCallback)( + GPConnection * connection, + int index, + const gsi_char ** path, + const gsi_char ** name, + void * param +); + +GPResult gpSendFiles( + GPConnection * connection, + GPTransfer * transfer, + GPProfile profile, + const gsi_char * message, + gpSendFilesCallback callback, + void * param +); + +GPResult gpAcceptTransfer( + GPConnection * connection, + GPTransfer transfer, + const gsi_char * message +); + +GPResult gpRejectTransfer( + GPConnection * connection, + GPTransfer transfer, + const gsi_char * message +); + +GPResult gpFreeTransfer( + GPConnection * connection, + GPTransfer transfer +); + +GPResult gpSetTransferData( + GPConnection * connection, + GPTransfer transfer, + void * userData +); + +void * gpGetTransferData( + GPConnection * connection, + GPTransfer transfer +); + +GPResult gpSetTransferDirectory( + GPConnection * connection, + GPTransfer transfer, + const gsi_char * directory +); + +// NOTE: THROTTLING IS NOT CURRENTLY IMPLEMENTED +GPResult gpSetTransferThrottle( + GPConnection * connection, + GPTransfer transfer, + int throttle +); + +// NOTE: THROTTLING IS NOT CURRENTLY IMPLEMENTED +GPResult gpGetTransferThrottle( + GPConnection * connection, + GPTransfer transfer, + int * throttle +); + +GPResult gpGetTransferProfile( + GPConnection * connection, + GPTransfer transfer, + GPProfile * profile +); + +GPResult gpGetTransferSide( + GPConnection * connection, + GPTransfer transfer, + GPEnum * side +); + +GPResult gpGetTransferSize( + GPConnection * connection, + GPTransfer transfer, + int * size +); + +GPResult gpGetTransferProgress( + GPConnection * connection, + GPTransfer transfer, + int * progress +); + +GPResult gpGetNumFiles( + GPConnection * connection, + GPTransfer transfer, + int * num +); + +GPResult gpGetCurrentFile( + GPConnection * connection, + GPTransfer transfer, + int * index +); + +GPResult gpSkipFile( + GPConnection * connection, + GPTransfer transfer, + int index +); + +GPResult gpGetFileName( + GPConnection * connection, + GPTransfer transfer, + int index, + gsi_char ** name +); + +GPResult gpGetFilePath( + GPConnection * connection, + GPTransfer transfer, + int index, + gsi_char ** path +); + +GPResult gpGetFileSize( + GPConnection * connection, + GPTransfer transfer, + int index, + int * size +); + +GPResult gpGetFileProgress( + GPConnection * connection, + GPTransfer transfer, + int index, + int * progress +); + +GPResult gpGetFileModificationTime( + GPConnection * connection, + GPTransfer transfer, + int index, + gsi_time * modTime +); + +GPResult gpGetNumTransfers( + GPConnection * connection, + int * num +); + +GPResult gpGetTransfer( + GPConnection * connection, + int index, + GPTransfer * transfer +); +#endif + +#ifdef _DEBUG +// gpProfilesReport +// PANTS|09.11.00 +/////////////////// +void gpProfilesReport( + GPConnection * connection, + void (* report)(const char * output) +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/GP/gp_vs2005.ncb b/xrGameSpy/gamespy/GP/gp_vs2005.ncb new file mode 100644 index 00000000000..aad7ed76860 Binary files /dev/null and b/xrGameSpy/gamespy/GP/gp_vs2005.ncb differ diff --git a/xrGameSpy/gamespy/GP/gp_vs2005.sln b/xrGameSpy/gamespy/GP/gp_vs2005.sln new file mode 100644 index 00000000000..baafcf0638e --- /dev/null +++ b/xrGameSpy/gamespy/GP/gp_vs2005.sln @@ -0,0 +1,65 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpstress_vs2005", "gpstress\gpstress_vs2005.vcproj", "{ADC08350-16C5-4822-A04A-1AD5133CF64D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gptest_vs2005", "gptest\gptest_vs2005.vcproj", "{E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gptestc_vs2005", "gptestc\gptestc_vs2005.vcproj", "{36F25843-777E-492D-B420-3D43953AB26B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BBA094FA-6655-401E-8B11-135A0BE83F9D}" + ProjectSection(SolutionItems) = preProject + changelog.txt = changelog.txt + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gptest\\gptest_vs2005.vcproj + SccProjectName1 = gptest + SccLocalPath1 = gptest + SccProjectUniqueName2 = gptestc\\gptestc_vs2005.vcproj + SccProjectName2 = gptestc + SccLocalPath2 = gptestc + SccProjectUniqueName3 = gpstress\\gpstress_vs2005.vcproj + SccProjectName3 = gpstress + SccLocalPath3 = gpstress + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Debug|Win32.Build.0 = Debug|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Release|Win32.ActiveCfg = Release|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Release|Win32.Build.0 = Release|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {ADC08350-16C5-4822-A04A-1AD5133CF64D}.Unicode Release|Win32.Build.0 = Release|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Debug|Win32.ActiveCfg = Debug|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Debug|Win32.Build.0 = Debug|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Release|Win32.ActiveCfg = Release|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Release|Win32.Build.0 = Release|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {E6B3FC4E-7F99-47F1-A57E-55ED2F3863A8}.Unicode Release|Win32.Build.0 = Release|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Debug|Win32.ActiveCfg = Debug|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Debug|Win32.Build.0 = Debug|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Release|Win32.ActiveCfg = Release|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Release|Win32.Build.0 = Release|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {36F25843-777E-492D-B420-3D43953AB26B}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/GP/gp_vs2005.suo b/xrGameSpy/gamespy/GP/gp_vs2005.suo new file mode 100644 index 00000000000..ae82709cbc4 Binary files /dev/null and b/xrGameSpy/gamespy/GP/gp_vs2005.suo differ diff --git a/xrGameSpy/gamespy/GP/gp_vs2005.vssscc b/xrGameSpy/gamespy/GP/gp_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gp_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/GP/gpi.c b/xrGameSpy/gamespy/GP/gpi.c new file mode 100644 index 00000000000..acd1fc701e3 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpi.c @@ -0,0 +1,821 @@ +/* +gpi.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 345, 362 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + +#include +#include +#include "gpi.h" + +// DEFINES +////////// +#define KEEPALIVE_TIMEOUT (60 * 2000) + +// This is so VisualAssist will know about these functions. +/////////////////////////////////////////////////////////// +#if 0 +void MD5Init(MD5_CTX *); +void MD5Update(MD5_CTX *, unsigned char *, unsigned int); +void MD5Final(unsigned char [16], MD5_CTX *); +void MD5Print(unsigned char [16], char[33]); +void MD5Digest(unsigned char *, unsigned int, char[33]); +#endif + +//FUNCTIONS +/////////// +GPResult +gpiInitialize( + GPConnection * connection, + int productID, + int namespaceID, + int partnerID +) +{ + GPIConnection * iconnection; + int i; + GPResult result; + + // Set the connection to NULL in case of error. + /////////////////////////////////////////////// + *connection = NULL; + + // Allocate the connection. + /////////////////////////// + iconnection = (GPIConnection *)gsimalloc(sizeof(GPIConnection)); + if(iconnection == NULL) + return GP_MEMORY_ERROR; + + // Initialize connection-specific variables. + //////////////////////////////////////////// + memset(iconnection, 0, sizeof(GPIConnection)); + iconnection->errorString[0] = '\0'; + iconnection->errorCode = (GPErrorCode)0; + iconnection->infoCaching = GPITrue; + iconnection->infoCachingBuddyAndBlockOnly = GPIFalse; + iconnection->simulation = GPIFalse; + iconnection->firewall = GPIFalse; + iconnection->productID = productID; + iconnection->namespaceID = namespaceID; + iconnection->partnerID = partnerID; + +#ifdef GSI_UNICODE + iconnection->errorString_W[0] = '\0'; +#endif + + if(!gpiInitProfiles((GPConnection *)&iconnection)) + { + freeclear(iconnection); + return GP_MEMORY_ERROR; + } + iconnection->diskCache = NULL; + for(i = 0 ; i < GPI_NUM_CALLBACKS ; i++) + { + iconnection->callbacks[i].callback = NULL; + iconnection->callbacks[i].param = NULL; + } + + // Reset connection-specific stuff. + /////////////////////////////////// + result = gpiReset((GPConnection *)&iconnection); + if(result != GP_NO_ERROR) + { + gpiDestroy((GPConnection *)&iconnection); + return result; + } + + // Initialize the sockets library. + ////////////////////////////////// + SocketStartUp(); + + // Seed the random number generator. + //////////////////////////////////// + srand((unsigned int)current_time()); + +#ifndef NOFILE + // Load profiles cached on disk. + //////////////////////////////// + result = gpiLoadDiskProfiles((GPConnection *)&iconnection); + if(result != GP_NO_ERROR) + { + gpiDestroy((GPConnection *)&iconnection); + return result; + } +#endif + +#ifndef NOFILE + result = gpiInitTransfers((GPConnection *)&iconnection); + if(result != GP_NO_ERROR) + { + gpiDestroy((GPConnection *)&iconnection); + return result; + } +#endif + + // Set the connection. + ////////////////////// + *connection = (GPConnection)iconnection; + + return GP_NO_ERROR; +} + +void +gpiDestroy( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Cleanup connection-specific stuff. + ///////////////////////////////////// + gpiDisconnect(connection, GPITrue); + gpiStatusInfoKeysDestroy(connection); + +#ifdef _PS3 + // Destroy NP + ///////////// + if (iconnection->npInitialized) + gpiDestroyNpBasic(connection); +#endif + +#ifndef NOFILE + // Write the profile info to disk. + // BD - Don't update if we never connected. + ////////////////////////////////// + if(iconnection->infoCaching && iconnection->connectState != GPI_NOT_CONNECTED) + { + if(gpiSaveDiskProfiles(connection) != GP_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_HotError, + "Error saving profiles to disk."); + } + } +#endif + + // Free the profile list. + ///////////////////////// + TableFree(iconnection->profileList.profileTable); + +#ifndef NOFILE + // Free the transfers. + ////////////////////// + gpiCleanupTransfers(connection); +#endif + + // Free the memory. + /////////////////// + freeclear(iconnection); + + // Set the connection pointer to NULL. + ////////////////////////////////////// + *connection = NULL; +} + +static GPIBool +gpiResetProfile( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ + GSI_UNUSED(connection); + GSI_UNUSED(data); + + profile->buddyStatus = NULL; + profile->buddyStatusInfo = NULL; + profile->authSig = NULL; + profile->requestCount = 0; + profile->peerSig = NULL; + profile->blocked = gsi_false; + profile->buddyOrBlockCache = gsi_false; + + return GPITrue; +} + +GPResult +gpiReset( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPResult result; + iconnection->nick[0] = '\0'; + iconnection->uniquenick[0] = '\0'; + iconnection->email[0] = '\0'; + iconnection->cmSocket = INVALID_SOCKET; + iconnection->connectState = GPI_NOT_CONNECTED; + + iconnection->socketBuffer.len = 0; + iconnection->socketBuffer.pos = 0; + iconnection->socketBuffer.size = 0; + freeclear(iconnection->socketBuffer.buffer); + iconnection->socketBuffer.buffer = NULL; + + iconnection->inputBufferSize = 0; + freeclear(iconnection->inputBuffer); + iconnection->inputBuffer = NULL; + + iconnection->outputBuffer.len = 0; + iconnection->outputBuffer.pos = 0; + iconnection->outputBuffer.size = 0; + freeclear(iconnection->outputBuffer.buffer); + iconnection->outputBuffer.buffer = NULL; + + iconnection->updateproBuffer.len = 0; + iconnection->updateproBuffer.pos = 0; + iconnection->updateproBuffer.size = 0; + freeclear(iconnection->updateproBuffer.buffer); + iconnection->updateproBuffer.buffer = NULL; + + iconnection->updateuiBuffer.len = 0; + iconnection->updateuiBuffer.pos = 0; + iconnection->updateuiBuffer.size = 0; + freeclear(iconnection->updateuiBuffer.buffer); + iconnection->updateuiBuffer.buffer = NULL; + gpiStatusInfoKeysDestroy(connection); + result = gpiStatusInfoKeysInit((GPConnection *)&iconnection); + if (result != GP_NO_ERROR) + { + gpiDestroy((GPConnection *)&iconnection); + return result; + } + //iconnection->peerSocket = INVALID_SOCKET; + iconnection->nextOperationID = 2; + while(iconnection->operationList != NULL) + gpiRemoveOperation(connection, iconnection->operationList); + iconnection->operationList = NULL; + iconnection->profileList.numBuddies = 0; + iconnection->profileList.numBlocked = 0; + gpiProfileMap(connection, gpiResetProfile, NULL); + iconnection->userid = 0; + iconnection->profileid = 0; + iconnection->sessKey = 0; + iconnection->numSearches = 0; + iconnection->fatalError = GPIFalse; + iconnection->peerList = NULL; + iconnection->lastStatusState = (GPEnum)-1; + iconnection->lastStatusString[0] = '\0'; + iconnection->lastLocationString[0] = '\0'; + iconnection->kaTransmit = 0; + +#ifdef GSI_UNICODE + iconnection->nick_W[0] = '\0'; + iconnection->uniquenick_W[0] = '\0'; + iconnection->email_W[0] = '\0'; + iconnection->lastStatusString_W[0] = '\0'; + iconnection->lastLocationString_W[0] = '\0'; +#endif + + return GP_NO_ERROR; +} + +GPResult +gpiProcessConnectionManager( + GPConnection * connection +) +{ + char * next; + char * str; + int id; + GPIOperation * operation; + char * tempPtr; + int len; + GPIBool connClosed = GPIFalse; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPResult result; + GPIBool loop; + gsi_time now = current_time(); + + // Loop through the rest while waiting for any blocking operations. + /////////////////////////////////////////////////////////////////// + do + { + // Add any waiting info to the output buffer. + ///////////////////////////////////////////// + gpiAddLocalInfo(connection, &iconnection->outputBuffer); + + // Send anything that needs to be sent. + /////////////////////////////////////// + if ( iconnection->outputBuffer.len > 0 ) + iconnection->kaTransmit = now; // data already being transmitted. We don't need to send keep alives + CHECK_RESULT(gpiSendFromBuffer(connection, iconnection->cmSocket, &iconnection->outputBuffer, &connClosed, GPITrue, "CM")); + + // Read everything the connection manager sent. + /////////////////////////////////////////////// + result = gpiRecvToBuffer(connection, iconnection->cmSocket, &iconnection->socketBuffer, &len, &connClosed, "CM"); + if(result != GP_NO_ERROR) + { + if(result == GP_NETWORK_ERROR) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error reading from the server."); + + return result; + } + + // Check if we have a completed command. + //////////////////////////////////////// + while((next = strstr(iconnection->socketBuffer.buffer, "\\final\\")) != NULL) + { + // Received command. Connection is still valid + ////////////////////////////////////////////// + iconnection->kaTransmit = now; + + // NUL terminate the command. + ///////////////////////////// + next[0] = '\0'; + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "CMD: %s\n", iconnection->socketBuffer.buffer); + + // Copy the command to the input buffer. + //////////////////////////////////////// + len = (next - iconnection->socketBuffer.buffer); + if(len > iconnection->inputBufferSize) + { + iconnection->inputBufferSize += max(GPI_READ_SIZE, len); + tempPtr = (char*)gsirealloc(iconnection->inputBuffer, (unsigned int)iconnection->inputBufferSize + 1); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + iconnection->inputBuffer = tempPtr; + } + memcpy(iconnection->inputBuffer, iconnection->socketBuffer.buffer, (unsigned int)len + 1); + + // Point to the start of the next one. + ////////////////////////////////////// + next += 7; + + // Move the rest of the connect buffer up to the front. + /////////////////////////////////////////////////////// + iconnection->socketBuffer.len -= (next - iconnection->socketBuffer.buffer); + memmove(iconnection->socketBuffer.buffer, next, (unsigned int)iconnection->socketBuffer.len + 1); + + // Check for an id. + /////////////////// + str = strstr(iconnection->inputBuffer, "\\id\\"); + if(str != NULL) + { + // Get the id. + ////////////// + id = atoi(str + 4); + + // Try and match the id with an operation. + ////////////////////////////////////////// + if(!gpiFindOperationByID(connection, &operation, id)) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, + "No matching operation found for id %d\n", id); + } + else + { + // Process the operation. + ///////////////////////// + CHECK_RESULT(gpiProcessOperation(connection, operation, iconnection->inputBuffer)); + } + } + // This is an unsolicited message. + ////////////////////////////////// + else + { + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, iconnection->inputBuffer, GPITrue)) + { + return GP_SERVER_ERROR; + } + else if(strncmp(iconnection->inputBuffer, "\\bm\\", 4) == 0) + { + CHECK_RESULT(gpiProcessRecvBuddyMessage(connection, iconnection->inputBuffer)); + } + else if(strncmp(iconnection->inputBuffer, "\\ka\\", 4) == 0) + { + // Ignore the keep-alive. + ///////////////////////// + } + else if(strncmp(iconnection->inputBuffer, "\\lt\\", 4) == 0) + { + // Process the login ticket + ///////////////////////// + gpiValueForKey(iconnection->inputBuffer, "\\lt\\", iconnection->loginTicket, sizeof(iconnection->loginTicket)); + } + else if(strncmp(iconnection->inputBuffer, "\\bsi\\", 5) == 0) + { + CHECK_RESULT(gpiProcessRecvBuddyStatusInfo(connection, iconnection->inputBuffer)); + } + else if(strncmp(iconnection->inputBuffer, "\\bdy\\", 5) == 0) + { + // Process the buddy list - retrieved upon login before final login response + // * Note: this only gets the list of your buddies so at least you'll know who + // is a buddy while the status of each is asynchronously updated. + ////////////////////////////////////////////////////////////////////////////// + CHECK_RESULT(gpiProcessRecvBuddyList(connection, iconnection->inputBuffer)); + } + else if(strncmp(iconnection->inputBuffer, "\\blk\\", 5) == 0) + { + // Process the block list - retrieved upon login before final login response + ////////////////////////////////////////////////////////////////////////////// + CHECK_RESULT(gpiProcessRecvBlockedList(connection, iconnection->inputBuffer)); + } + else + { + // This is an unrecognized message. + /////////////////////////////////// + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, + "Received an unrecognized message.\n"); + } + } + } + + + // Check for a closed connection. + ///////////////////////////////// + if(connClosed && iconnection->connectState != GPI_PROFILE_DELETING) + { + // We've been disconnected. + /////////////////////////// + // Let gpiDisconnect change the state to GPI_DISCONNECTED + //iconnection->connectState = GPI_DISCONNECTED; + gpiSetError(connection, GP_CONNECTION_CLOSED, "The server has closed the connection."); + gpiCallErrorCallback(connection, GP_NETWORK_ERROR, GP_FATAL); + return GP_NO_ERROR; + } + + //PANTS|05.23.00 - removed sleep + //crt - added it back 6/13/00 + //PANTS|07.10.00 - only sleep if looping + loop = gpiOperationsAreBlocking(connection); + if(loop) + msleep(10); + } + while(loop); + + // Send Keep-Alive. Just need TCP to ack the data + ///////////////////////////////////////////////// + if ( now - iconnection->kaTransmit > KEEPALIVE_TIMEOUT ) + { + // keep alive packet will be sent next think + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\ka\\\\final\\"); + iconnection->kaTransmit = now; + } + + return GP_NO_ERROR; +} + +GPResult +gpiProcess( + GPConnection * connection, + int blockingOperationID +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIOperation * operation; + GPIOperation * delOperation; + GPResult result = GP_NO_ERROR; + GPIBool loop; + + assert((iconnection->connectState == GPI_NOT_CONNECTED) || + (iconnection->connectState == GPI_CONNECTING) || + (iconnection->connectState == GPI_NEGOTIATING) || + (iconnection->connectState == GPI_CONNECTED) || + (iconnection->connectState == GPI_DISCONNECTED) || + (iconnection->connectState == GPI_PROFILE_DELETING)); + + // Check if no connection was attempted. + //////////////////////////////////////// +/* if(iconnection->connectState == GPI_NOT_CONNECTED) + return GP_NO_ERROR; + + // Check for a disconnection. + ///////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + return GP_NO_ERROR; +*/ + // Check if we're connecting. + ///////////////////////////// + if(iconnection->connectState == GPI_CONNECTING) + { + do + { + result = gpiCheckConnect(connection); + //PANTS|07.10.00 - only sleep if looping + loop = (((result == GP_NO_ERROR) && (blockingOperationID != 0) && (iconnection->connectState == GPI_CONNECTING))) ? GPITrue:GPIFalse; + if(loop) + msleep(10); + } + while(loop); + + if(result != GP_NO_ERROR) + { + // Find the connect operation. + ////////////////////////////// + if(gpiFindOperationByID(connection, &operation, 1)) + { + operation->result = GP_SERVER_ERROR; + } + else + { + // Couldn't find the connect operation. + /////////////////////////////////////// + assert(0); + } + } + } + + // Only do this stuff if we're connected. + ///////////////////////////////////////// + if((iconnection->connectState == GPI_CONNECTED) || (iconnection->connectState == GPI_NEGOTIATING) || + (iconnection->connectState == GPI_PROFILE_DELETING)) + { +#ifdef _PS3 + // initialize NP during the sync delay, if initialized wait for status == online + //////////////////////////////////////////////////////////////////////////////// + if (iconnection->npInitialized && !iconnection->npStatusRetrieved) + gpiCheckNpStatus(connection); + + // TODO: handle non-fatal errors (consider all errors from sync non-fatal?) + if (iconnection->npInitialized && iconnection->npStatusRetrieved) + { + // Delay sync after initialization to ensure block list has been received + ///////////////////////////////////////////////////////////////////////// + if ((current_time() - iconnection->loginTime) > GPI_NP_SYNC_DELAY) + { + if (iconnection->npPerformBuddySync) + gpiSyncNpBuddies(connection); + if (iconnection->npPerformBlockSync) + gpiSyncNpBlockList(connection); + } + + // Need to check callback for lookups + gpiProcessNp(connection); + } +#endif + + // Process the connection. + ////////////////////////// + if(result == GP_NO_ERROR) + result = gpiProcessConnectionManager(connection); + + // Process peer messaging stuff. + //////////////////////////////// + if(result == GP_NO_ERROR) + result = gpiProcessPeers(connection); + +#ifndef NOFILE + // Process transfers. + ///////////////////// + if(result == GP_NO_ERROR) + result = gpiProcessTransfers(connection); +#endif + } + + // Process searches. + //////////////////// + if(result == GP_NO_ERROR) + result = gpiProcessSearches(connection); + + // Look for failed operations. + ////////////////////////////// + for(operation = iconnection->operationList ; operation != NULL ; ) + { + if(operation->result != GP_NO_ERROR) + { + gpiFailedOpCallback(connection, operation); + delOperation = operation; + operation = operation->pnext; + gpiRemoveOperation(connection, delOperation); + } + else + { + operation = operation->pnext; + } + } + + // Call callbacks. + ////////////////// + CHECK_RESULT(gpiProcessCallbacks(connection, blockingOperationID)); + + if(iconnection->fatalError) + { + gpiDisconnect(connection, GPIFalse); + gpiReset(connection); + } + else + { + //assert(!((result != GP_NO_ERROR) && (iconnection->connectState != GPI_CONNECTED))); + } + + return result; +} + +GPResult +gpiEnable( + GPConnection * connection, + GPEnum state +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Enable the state. + //////////////////// + switch(state) + { + case GP_INFO_CACHING: + iconnection->infoCaching = GPITrue; + break; + + case GP_SIMULATION: + iconnection->simulation = GPITrue; + break; + + case GP_INFO_CACHING_BUDDY_AND_BLOCK_ONLY: + iconnection->infoCachingBuddyAndBlockOnly = GPITrue; + break; + + default: + Error(connection, GP_PARAMETER_ERROR, "Invalid state."); + } + + return GP_NO_ERROR; +} + +static GPIBool gpiFreeProfileInfo( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ + GSI_UNUSED(data); + + gpiFreeInfoCache(profile); + freeclear(profile->peerSig); + + if(gpiCanFreeProfile(profile)) + { + gpiRemoveProfile(connection, profile); + return GPIFalse; + } + + return GPITrue; +} + +GPResult +gpiDisable( + GPConnection * connection, + GPEnum state +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + if(state == GP_INFO_CACHING) + { + iconnection->infoCaching = GPIFalse; + + // freeclear everyone's info. + //////////////////////// + while(!gpiProfileMap(connection, gpiFreeProfileInfo, NULL)) { }; + } + else if(state == GP_SIMULATION) + { + iconnection->simulation = GPIFalse; + } + else if(state == GP_INFO_CACHING_BUDDY_AND_BLOCK_ONLY) + { + iconnection->infoCachingBuddyAndBlockOnly = GPIFalse; + } + else + { + Error(connection, GP_PARAMETER_ERROR, "Invalid state."); + } + + return GP_NO_ERROR; +} + +#ifdef _DEBUG +static int nProfiles; +static int nUserID; +static int nBuddyStatus; +static int nBuddyMemory; +static int nInfoCache; +static int nInfoMemory; +static int nAuthSig; +static int nPeerSig; +static int nTotalMemory; +static int nBlocked; + +static GPIBool +gpiReportProfile( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ + int temp; + + GSI_UNUSED(connection); + GSI_UNUSED(data); + + nProfiles++; + nTotalMemory += sizeof(GPIProfile); + if(profile->userId) nUserID++; + if(profile->buddyStatus) + { + nBuddyStatus++; + temp = sizeof(GPIBuddyStatus); + if(profile->buddyStatus->statusString) + temp += (int)(strlen(profile->buddyStatus->statusString) + 1); + if(profile->buddyStatus->locationString) + temp += (int)(strlen(profile->buddyStatus->locationString) + 1); +#ifdef GSI_UNICODE +// if(profile->buddyStatus->statusString_W) +// temp += (wcslen(profile->buddyStatus->statusString_W) + 2); +// if(profile->buddyStatus->locationString_W) +// temp += (wcslen(profile->buddyStatus->locationString_W) + 2); +#endif + nBuddyMemory += temp; + nTotalMemory += temp; + } + if(profile->cache) + { + nInfoCache++; + temp = sizeof(GPIInfoCache); + if(profile->cache->nick) + temp += (int)(strlen(profile->cache->nick) + 1); + if(profile->cache->uniquenick) + temp += (int)(strlen(profile->cache->uniquenick) + 1); + if(profile->cache->email) + temp += (int)(strlen(profile->cache->email) + 1); + if(profile->cache->firstname) + temp += (int)(strlen(profile->cache->firstname) + 1); + if(profile->cache->lastname) + temp += (int)(strlen(profile->cache->lastname) + 1); + if(profile->cache->homepage) + temp += (int)(strlen(profile->cache->homepage) + 1); + nInfoMemory += temp; + nTotalMemory += temp; + } + if(profile->authSig) nAuthSig++; + if(profile->peerSig) nPeerSig++; + if(profile->blocked) nBlocked++; + + return GPITrue; +} + +void +gpiReport( + GPConnection * connection, + void (* report)(const char * output) +) +{ + char buf[128]; + + nProfiles = 0; + nUserID = 0; + nBuddyStatus = 0; + nBuddyMemory = 0; + nInfoCache = 0; + nInfoMemory = 0; + nAuthSig = 0; + nPeerSig = 0; + nTotalMemory = 0; + nBlocked = 0; + + report("START PROFILE MAP"); + report("-----------------"); + gpiProfileMap(connection, gpiReportProfile, NULL); + + sprintf(buf, "%d profiles %d bytes (%d avg)", nProfiles, nTotalMemory, nTotalMemory / max(nProfiles, 1)); + report(buf); + if(nProfiles) + { + sprintf(buf, "UserID: %d (%d%%)", nUserID, nUserID * 100 / nProfiles); + report(buf); + sprintf(buf, "BuddyStatus: %d (%d%%) %d bytes (%d avg)", nBuddyStatus, nBuddyStatus * 100 / nProfiles, nBuddyMemory, nBuddyMemory / max(nBuddyStatus, 1)); + report(buf); + sprintf(buf, "InfoCache: %d (%d%%) %d bytes (%d avg)", nInfoCache, nInfoCache * 100 / nProfiles, nInfoMemory, nInfoMemory / max(nInfoCache, 1)); + report(buf); + sprintf(buf, "AuthSig: %d (%d%%)", nAuthSig, nAuthSig * 100 / nProfiles); + report(buf); + sprintf(buf, "PeerSig: %d (%d%%)", nPeerSig, nPeerSig * 100 / nProfiles); + report(buf); + sprintf(buf, "Blocked: %d (%d%%)", nBlocked, nBlocked * 100 / nProfiles); + report(buf); + } + + report("---------------"); + report("END PROFILE MAP"); + + +} +#endif diff --git a/xrGameSpy/gamespy/GP/gpi.h b/xrGameSpy/gamespy/GP/gpi.h new file mode 100644 index 00000000000..0c23ad39a0b --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpi.h @@ -0,0 +1,231 @@ +/* +gpi.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPI_H_ +#define _GPI_H_ + +//INCLUDES +////////// +#include "../common/gsCommon.h" +#include "../common/gsAvailable.h" +#include "../common/gsUdpEngine.h" +#include "../hashtable.h" +#include "../darray.h" +#include "../md5.h" +#include "gp.h" + +// Extended message support +#define GPI_NEW_AUTH_NOTIFICATION (1<<0) +#define GPI_NEW_REVOKE_NOTIFICATION (1<<1) + +// New Status Info support +#define GPI_NEW_STATUS_NOTIFICATION (1<<2) + +// Buddy List + Block List retrieval on login +#define GPI_NEW_LIST_RETRIEVAL_ON_LOGIN (1<<3) + +// Extended SDK features +#ifndef GPI_SDKREV +#ifdef GP_NEW_STATUS_INFO +#define GPI_SDKREV (GPI_NEW_AUTH_NOTIFICATION | GPI_NEW_REVOKE_NOTIFICATION | GPI_NEW_STATUS_NOTIFICATION | GPI_NEW_LIST_RETRIEVAL_ON_LOGIN) +#else +#define GPI_SDKREV (GPI_NEW_AUTH_NOTIFICATION | GPI_NEW_REVOKE_NOTIFICATION | GPI_NEW_LIST_RETRIEVAL_ON_LOGIN) +#endif +#endif + +// New UDP Layer port +#define GPI_PEER_PORT 6500 + +//TYPES +/////// +// Boolean. +/////////// +typedef enum _GPIBool +{ + GPIFalse, + GPITrue +} GPIBool; + +#include "gpiUtility.h" +#include "gpiCallback.h" +#include "gpiOperation.h" +#include "gpiConnect.h" +#include "gpiBuffer.h" +#include "gpiInfo.h" +#include "gpiProfile.h" +#include "gpiPeer.h" +#include "gpiSearch.h" +#include "gpiBuddy.h" +#include "gpiTransfer.h" +#include "gpiUnique.h" +#include "gpiKeys.h" + +// For PS3 NP Sync functionality +#ifdef _PS3 +#include "gpiPS3.h" +#endif + +// Connection data. +/////////////////// +typedef struct +{ + char errorString[GP_ERROR_STRING_LEN]; + GPIBool infoCaching; + GPIBool infoCachingBuddyAndBlockOnly; + GPIBool simulation; + GPIBool firewall; + char nick[GP_NICK_LEN]; + char uniquenick[GP_UNIQUENICK_LEN]; + char email[GP_EMAIL_LEN]; + char password[GP_PASSWORD_LEN]; + int sessKey; + int userid; + int profileid; + int partnerID; + GPICallback callbacks[GPI_NUM_CALLBACKS]; + SOCKET cmSocket; + int connectState; + GPIBuffer socketBuffer; + char * inputBuffer; + int inputBufferSize; + GPIBuffer outputBuffer; + // Replaced by UDP Layer + //SOCKET peerSocket; + char mHeader[GS_UDP_MSG_HEADER_LEN]; + unsigned short peerPort; + int nextOperationID; + int numSearches; + + // new style status info + GPEnum lastStatusState; + unsigned int hostIp; + unsigned int hostPrivateIp; + unsigned short queryPort; + unsigned short hostPort; + unsigned int sessionFlags; + + char richStatus[GP_RICH_STATUS_LEN]; + char gameType[GP_STATUS_BASIC_STR_LEN]; + char gameVariant[GP_STATUS_BASIC_STR_LEN]; + char gameMapName[GP_STATUS_BASIC_STR_LEN]; + + // New Status Info extended info Keys + DArray extendedInfoKeys; + + // Deprecated + char lastStatusString[GP_STATUS_STRING_LEN]; + char lastLocationString[GP_LOCATION_STRING_LEN]; + + GPErrorCode errorCode; + GPIBool fatalError; + FILE * diskCache; + GPIOperation * operationList; + GPIProfileList profileList; + GPIPeer * peerList; + GPICallbackData * callbackList; + GPICallbackData * lastCallback; + GPIBuffer updateproBuffer; + GPIBuffer updateuiBuffer; + DArray transfers; + unsigned int nextTransferID; + int productID; + int namespaceID; + char loginTicket[GP_LOGIN_TICKET_LEN]; + GPEnum quietModeFlags; + gsi_time kaTransmit; + +#ifdef GSI_UNICODE + unsigned short errorString_W[GP_ERROR_STRING_LEN]; + unsigned short nick_W[GP_NICK_LEN]; + unsigned short uniquenick_W[GP_UNIQUENICK_LEN]; + unsigned short email_W[GP_EMAIL_LEN]; + unsigned short password_W[GP_PASSWORD_LEN]; + + // Deprecated + unsigned short lastStatusString_W[GP_STATUS_STRING_LEN]; + unsigned short lastLocationString_W[GP_LOCATION_STRING_LEN]; + + unsigned short richStatus_W[GP_RICH_STATUS_LEN]; + unsigned short gameType_W[GP_STATUS_BASIC_STR_LEN]; + unsigned short gameVariant_W[GP_STATUS_BASIC_STR_LEN]; + unsigned short gameMapName_W[GP_STATUS_BASIC_STR_LEN]; +#endif + +#ifdef _PS3 + // NP sync info + gsi_bool npInitialized; + gsi_bool npStatusRetrieved; + gsi_bool npBasicGameInitialized; + gsi_bool npLookupGameInitialized; + gsi_bool npPerformBuddySync; + gsi_bool npPerformBlockSync; + gsi_bool npSyncLock; + int npLookupTitleCtxId; + DArray npTransactionList; + gsi_time loginTime; +#endif + +} GPIConnection; + +//FUNCTIONS +/////////// +GPResult +gpiInitialize( + GPConnection * connection, + int productID, + int namespaceID, + int partnerID +); + +void +gpiDestroy( + GPConnection * connection +); + +GPResult +gpiReset( + GPConnection * connection +); + +GPResult +gpiProcessConnectionManager( + GPConnection * connection +); + +GPResult +gpiProcess( + GPConnection * connection, + int blockingOperationID +); + +GPResult +gpiEnable( + GPConnection * connection, + GPEnum state +); + +GPResult +gpiDisable( + GPConnection * connection, + GPEnum state +); + +#ifdef _DEBUG +void +gpiReport( + GPConnection * connection, + void (* report)(const char * output) +); +#endif + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiBuddy.c b/xrGameSpy/gamespy/GP/gpiBuddy.c new file mode 100644 index 00000000000..4a42e73e9a3 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiBuddy.c @@ -0,0 +1,1070 @@ +/* +gpiBuddy.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4311) //lines: 977 +#pragma warning(disable: 4312) //lines: 1039, 1064 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +//INCLUDES +////////// +#include +#include +#include "gpi.h" + +//FUNCTIONS +/////////// +static GPResult +gpiSendAuthBuddyRequest( + GPConnection * connection, + GPIProfile * profile +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Send the auth. + ///////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\authadd\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\fromprofileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profile->profileId); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sig\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, profile->authSig); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult +gpiProcessRecvBuddyMessage( + GPConnection * connection, + const char * input +) +{ + char buffer[4096]; + int type; + int profileid; + time_t date; + GPICallback callback; + GPIProfile * profile; + GPIBuddyStatus * buddyStatus; + char intValue[16]; + char * str; + unsigned short port; + int productID; + GPIConnection * iconnection = (GPIConnection*)*connection; + char strTemp[max(GP_STATUS_STRING_LEN, GP_LOCATION_STRING_LEN)]; + + // Check the type of bm. + //////////////////////// + if(!gpiValueForKey(input, "\\bm\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + type = atoi(buffer); + + // Get the profile this is from. + //////////////////////////////// + if(!gpiValueForKey(input, "\\f\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + profileid = atoi(buffer); + + // Get the time. + //////////////// + if(!gpiValueForKey(input, "\\date\\", buffer, sizeof(buffer))) + date = time(NULL); + else + date = atoi(buffer); + + // What type of message is this? + //////////////////////////////// + switch(type) + { + case GPI_BM_MESSAGE: + // Call the callback. + ///////////////////// + callback = iconnection->callbacks[GPI_RECV_BUDDY_MESSAGE]; + if(callback.callback != NULL) + { + GPRecvBuddyMessageArg * arg; + arg = (GPRecvBuddyMessageArg *)gsimalloc(sizeof(GPRecvBuddyMessageArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); +#ifndef GSI_UNICODE + arg->message = (char *)gsimalloc(strlen(buffer) + 1); + if(arg->message == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + strcpy(arg->message, buffer); + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; +#else + arg->message = (unsigned short*)gsimalloc(strlen(buffer)*2+2); + if(arg->message == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + UTF8ToUCS2String(buffer, arg->message); + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; +#endif + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_MESSAGE)); + } + break; + case GPI_BM_UTM: + // Call the callback. + ///////////////////// + callback = iconnection->callbacks[GPI_RECV_BUDDY_UTM]; + if(callback.callback != NULL) + { + GPRecvBuddyUTMArg * arg; + arg = (GPRecvBuddyUTMArg *)gsimalloc(sizeof(GPRecvBuddyUTMArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); +#ifndef GSI_UNICODE + arg->message = (char *)gsimalloc(strlen(buffer) + 1); + if(arg->message == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + strcpy(arg->message, buffer); + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; +#else + arg->message = (unsigned short*)gsimalloc(strlen(buffer)*2+2); + if(arg->message == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + UTF8ToUCS2String(buffer, arg->message); + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; +#endif + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYUTM)); + } + break; + + case GPI_BM_REQUEST: + // Get the profile, adding if needed. + ///////////////////////////////////// + profile = gpiProfileListAdd(connection, profileid); + if(!profile) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Get the reason. + ////////////////// + if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Find where the sig starts. + ///////////////////////////// + str = strstr(buffer, "|signed|"); + if(str == NULL) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the sig out of the message. + ////////////////////////////////// + *str = '\0'; + str += 8; + if(strlen(str) != 32) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + freeclear(profile->authSig); + profile->authSig = goastrdup(str); + profile->requestCount++; + + // Call the callback. + ///////////////////// + callback = iconnection->callbacks[GPI_RECV_BUDDY_REQUEST]; + if(callback.callback != NULL) + { + GPRecvBuddyRequestArg * arg; + arg = (GPRecvBuddyRequestArg *)gsimalloc(sizeof(GPRecvBuddyRequestArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); +#ifndef GSI_UNICODE + strzcpy(arg->reason, buffer, GP_REASON_LEN); +#else + UTF8ToUCS2String(buffer, arg->reason); +#endif + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDDYREQUEST)); + } + break; + + case GPI_BM_AUTH: + // call the callback + callback = iconnection->callbacks[GPI_RECV_BUDDY_AUTH]; + if(callback.callback != NULL) + { + GPRecvBuddyAuthArg * arg; + arg = (GPRecvBuddyAuthArg *)gsimalloc(sizeof(GPRecvBuddyAuthArg)); + + if (arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYAUTH)); + } + break; + + case GPI_BM_REVOKE: + // call the callback + callback = iconnection->callbacks[GPI_RECV_BUDDY_REVOKE]; + if(callback.callback != NULL) + { + GPRecvBuddyRevokeArg * arg; + arg = (GPRecvBuddyRevokeArg *)gsimalloc(sizeof(GPRecvBuddyRevokeArg)); + + if (arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->profile = (GPProfile)profileid; + arg->date = (unsigned int)date; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYREVOKE)); + } + break; + + + case GPI_BM_STATUS: + // Get the profile, adding if needed. + ///////////////////////////////////// + profile = gpiProfileListAdd(connection, profileid); + if(!profile) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Make sure profile wasn't blocked prior to getting the status update + ////////////////////////////////////////////////////////////////////// + if (!profile->blocked) + { + // This is a buddy. + /////////////////// + if(!profile->buddyStatus) + { + profile->buddyStatus = (GPIBuddyStatus *)gsimalloc(sizeof(GPIBuddyStatus)); + if(!profile->buddyStatus) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(profile->buddyStatus, 0, sizeof(GPIBuddyStatus)); + if (profile->buddyStatusInfo) + { + profile->buddyStatus->buddyIndex = profile->buddyStatusInfo->buddyIndex; + gpiRemoveBuddyStatusInfo(profile->buddyStatusInfo); + profile->buddyStatusInfo = NULL; + } + else + profile->buddyStatus->buddyIndex = iconnection->profileList.numBuddies++; + } + + // Get the buddy status. + //////////////////////// + buddyStatus = profile->buddyStatus; + + // Get the msg. + /////////////// + if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the status. + ////////////////// + if(!gpiValueForKey(buffer, "|s|", intValue, sizeof(intValue))) + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + } + else + { + buddyStatus->status = (GPEnum)atoi(intValue); + } + // Get the status string. + ///////////////////////// + freeclear(buddyStatus->statusString); + if(!gpiValueForKey(buffer, "|ss|", strTemp, GP_STATUS_STRING_LEN)) + strTemp[0] = '\0'; + buddyStatus->statusString = goastrdup(strTemp); + if(!buddyStatus->statusString) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Get the location string. + /////////////////////////// + freeclear(buddyStatus->locationString); + if(!gpiValueForKey(buffer, "|ls|", strTemp, GP_LOCATION_STRING_LEN)) + strTemp[0] = '\0'; + buddyStatus->locationString = goastrdup(strTemp); + if(!buddyStatus->locationString) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Get the ip. + ////////////// + if(!gpiValueForKey(buffer, "|ip|", intValue, sizeof(intValue))) + buddyStatus->ip = 0; + else + buddyStatus->ip = htonl((unsigned int)atoi(intValue)); + + // Get the port. + //////////////// + if(!gpiValueForKey(buffer, "|p|", intValue, sizeof(intValue))) + buddyStatus->port = 0; + else + { + port = (unsigned short)atoi(intValue); + buddyStatus->port = htons(port); + } + + // Get the quiet mode flags. + //////////////////////////// + if(!gpiValueForKey(buffer, "|qm|", intValue, sizeof(intValue))) + buddyStatus->quietModeFlags = GP_SILENCE_NONE; + else + buddyStatus->quietModeFlags = (GPEnum)atoi(intValue); + + // Call the callback. + ///////////////////// + callback = iconnection->callbacks[GPI_RECV_BUDDY_STATUS]; + if(callback.callback != NULL) + { + GPRecvBuddyStatusArg * arg; + arg = (GPRecvBuddyStatusArg *)gsimalloc(sizeof(GPRecvBuddyStatusArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + arg->profile = (GPProfile)profileid; + arg->index = buddyStatus->buddyIndex; + arg->date = (unsigned int)date; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_STATUS)); + } + } + break; + + case GPI_BM_INVITE: + // Get the msg. + /////////////// + if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Find the productid. + ////////////////////// + str = strstr(buffer, "|p|"); + if(str == NULL) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Skip the |p|. + //////////////// + str += 3; + if(str[0] == '\0') + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the productid. + ///////////////////// + productID = atoi(str); + + // Find the location string (optional - older versions won't have) + str = strstr(buffer, "|l|"); + if(str != NULL) + strzcpy(strTemp, (str+3), sizeof(strTemp)); + else + strTemp[0] = '\0'; // no location, set to empty string + + // Call the callback. + ///////////////////// + callback = iconnection->callbacks[GPI_RECV_GAME_INVITE]; + if(callback.callback != NULL) + { + GPRecvGameInviteArg * arg; + arg = (GPRecvGameInviteArg *)gsimalloc(sizeof(GPRecvGameInviteArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + arg->profile = (GPProfile)profileid; + arg->productID = productID; +#ifdef GSI_UNICODE + AsciiToUCS2String(strTemp, arg->location); +#else + strcpy(arg->location, strTemp); +#endif + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, 0)); + } + break; + + case GPI_BM_PING: + // Get the msg. + /////////////// + if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Send back a pong. + //////////////////// + gpiSendBuddyMessage(connection, profileid, GPI_BM_PONG, "1", 0, NULL); + + break; + +#ifndef NOFILE + case GPI_BM_PONG: + // Lets the transfers handle this. + ////////////////////////////////// + gpiTransfersHandlePong(connection, profileid, NULL); + + break; +#endif + } + + return GP_NO_ERROR; +} + +GPResult gpiProcessRecvBuddyStatusInfo(GPConnection *connection, const char *input) +{ + char buffer[1024]; + int profileid; + time_t date; + GPICallback callback; + GPIProfile * profile; + GPIBuddyStatusInfo * buddyStatusInfo; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // This is what the message should look like. Its broken up for easy viewing. + // + // "\bsi\\state\\profile\\bip\\bport\\hostip\\hprivip\" + // "\qport\\hport\\sessflags\\rstatus\\gameType\" + // "\gameVnt\\gameMn\\product\\qmodeflags\" + //////////////////////////////// + date = time(NULL); + // Get the buddy's profile + //////////////////////////////// + if(!gpiValueForKey(input, "\\profile\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + profileid = atoi(buffer); + + // Get the profile from the SDK's list, adding it if needed. + ///////////////////////////////////// + profile = gpiProfileListAdd(connection, profileid); + if(!profile) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Make sure profile wasn't blocked prior to getting the status update + ////////////////////////////////////////////////////////////////////// + if (!profile->blocked) + { + // This is a buddy. + /////////////////// + if(!profile->buddyStatusInfo) + { + profile->buddyStatusInfo = (GPIBuddyStatusInfo *)gsimalloc(sizeof(GPIBuddyStatusInfo)); + if(!profile->buddyStatusInfo) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(profile->buddyStatusInfo, 0, sizeof(GPIBuddyStatusInfo)); + if (profile->buddyStatus) + { + profile->buddyStatusInfo->buddyIndex = profile->buddyStatus->buddyIndex; + gpiRemoveBuddyStatus(profile->buddyStatus); + profile->buddyStatus = NULL; + } + else + profile->buddyStatusInfo->buddyIndex = iconnection->profileList.numBuddies++; + profile->buddyStatusInfo->extendedInfoKeys = ArrayNew(sizeof(GPIKey), GPI_INITIAL_NUM_KEYS, gpiStatusInfoKeyFree); + if (!profile->buddyStatusInfo->extendedInfoKeys) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + + // extract the buddy status information and + // fill in appropriate information. + ///////////////////////////////////////////// + buddyStatusInfo = profile->buddyStatusInfo; + + if (!gpiValueForKey(input, "\\state\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->statusState = (GPEnum)atoi(buffer); + + if (!gpiValueForKey(input, "\\bip\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->buddyIp = htonl((unsigned int)atoi(buffer)); + + if (!gpiValueForKey(input, "\\bport\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->buddyPort = (unsigned short)atoi(buffer); + + if (!gpiValueForKey(input, "\\hostip\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->hostIp = htonl((unsigned int)atoi(buffer)); + + if (!gpiValueForKey(input, "\\hprivip\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->hostPrivateIp = htonl((unsigned int)atoi(buffer)); + + if (!gpiValueForKey(input, "\\qport\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->queryPort = (unsigned short)atoi(buffer); + + if (!gpiValueForKey(input, "\\hport\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->hostPort = (unsigned short)atoi(buffer); + + if (!gpiValueForKey(input, "\\sessflags\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->sessionFlags = (unsigned int)atoi(buffer); + + freeclear(buddyStatusInfo->richStatus); + if (!gpiValueForKey(input, "\\rstatus\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->richStatus = goastrdup(buffer); + + freeclear(buddyStatusInfo->gameType); + if (!gpiValueForKey(input, "\\gameType\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->gameType = goastrdup(buffer); + + freeclear(buddyStatusInfo->gameVariant); + if (!gpiValueForKey(input, "\\gameVnt\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->gameVariant = goastrdup(buffer); + + freeclear(buddyStatusInfo->gameMapName); + if (!gpiValueForKey(input, "\\gameMn\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->gameMapName = goastrdup(buffer); + + if (!gpiValueForKey(input, "\\product\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->productId = (int)atoi(buffer); + + if (!gpiValueForKey(input, "\\qmodeflags\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + buddyStatusInfo->quietModeFlags = (GPEnum)atoi(buffer); + + callback = iconnection->callbacks[GPI_RECV_BUDDY_STATUS]; + if (callback.callback != NULL) + { + GPRecvBuddyStatusArg *anArg; + anArg = (GPRecvBuddyStatusArg *)gsimalloc(sizeof(GPRecvBuddyStatusArg)); + if (anArg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + anArg->date = (unsigned int)date; + anArg->index = buddyStatusInfo->buddyIndex; + anArg->profile = profileid; + + CHECK_RESULT(gpiAddCallback(connection, callback, anArg, NULL, 0)); + } + } + return GP_NO_ERROR; + +} + +GPResult +gpiProcessRecvBuddyList( + GPConnection * connection, + const char * input +) +{ + int i=0, j=0; + int num = 0; + int index = 0; + char c; + char *str = NULL; + char buffer[512]; + GPIProfile * profile; + GPProfile profileid; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // Process Buddy List Retrieval msg - Format like: + /* =============================================== + \bdy\\list\\final\ + =============================================== */ + + if(!gpiValueForKeyWithIndex(input, "\\bdy\\", &index, buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + num = atoi(buffer); + + // Check to make sure list is there + /////////////////////////////////// + str = strstr(input, "\\list\\"); + if (str == NULL) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Then increment index to get ready for parsing + //////////////////////////////////////////////// + str += 6; + index += 6; + + for (i=0; i < num; i++) + { + if (i==0) + { + // Manually grab first profile in list - comma delimiter + //////////////////////////////////////////////////////// + for(j=0 ; (j < sizeof(buffer)) && ((c = str[j]) != '\0') && (c != ',') ; j++) + { + buffer[j] = c; + } + buffer[j] = '\0'; + index += j; + } + else + { + if(!gpiValueForKeyWithIndex(input, ",", &index, buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + } + + profileid = atoi(buffer); + + // Get the profile, adding if needed. + ///////////////////////////////////// + profile = gpiProfileListAdd(connection, profileid); + if(!profile) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Mark as offline buddy for now until we get the real status + ///////////////////////////////////////////////////////////// +#ifdef GP_NEW_STATUS_INFO + // Use new status info as placeholder + profile->buddyStatusInfo = (GPIBuddyStatusInfo *)gsimalloc(sizeof(GPIBuddyStatusInfo)); + if(!profile->buddyStatusInfo) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(profile->buddyStatusInfo, 0, sizeof(GPIBuddyStatusInfo)); + + profile->buddyStatusInfo->extendedInfoKeys = ArrayNew(sizeof(GPIKey), GPI_INITIAL_NUM_KEYS, gpiStatusInfoKeyFree); + if (!profile->buddyStatusInfo->extendedInfoKeys) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + profile->buddyStatusInfo->buddyIndex = iconnection->profileList.numBuddies++; + profile->buddyStatusInfo->statusState = GP_OFFLINE; +#else + // Use buddy status as placeholder + profile->buddyStatus = (GPIBuddyStatus *)gsimalloc(sizeof(GPIBuddyStatus)); + if(!profile->buddyStatus) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(profile->buddyStatus, 0, sizeof(GPIBuddyStatus)); + profile->buddyStatus->buddyIndex = iconnection->profileList.numBuddies++; + profile->buddyStatus->status = GP_OFFLINE; +#endif + } + + return GP_NO_ERROR; +} + +GPResult +gpiSendServerBuddyMessage( + GPConnection * connection, + int profileid, + int type, + const char * message +) +{ + char buffer[3501]; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Copy the message into an internal buffer. + //////////////////////////////////////////// + strzcpy(buffer, message, sizeof(buffer)); + + // Setup the message. + ///////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\bm\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, type); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\t\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profileid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\msg\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, buffer); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult +gpiSendBuddyMessage( + GPConnection * connection, + int profileid, + int type, + const char * message, + int sendOption, + GPIPeerOp *peerOp +) +{ + GPIPeer * peer; + GPIProfile * profile; + //GPIConnection *iconnection = (GPIConnection *)*connection; + peer = gpiGetPeerByProfile(connection, profileid); + if(!peer) + { + // Check if we should send this through the server. + //////////////////////////////////////////////////// + if(!gpiGetProfile(connection, profileid, &profile) || + (!profile->buddyStatusInfo || !profile->buddyStatusInfo->buddyPort)) + { + if (sendOption == GP_DONT_ROUTE) + return GP_NETWORK_ERROR; + return gpiSendServerBuddyMessage(connection, profileid, type, message); + } + + // Create a new peer connection for this message. + ///////////////////////////////////////////////// + peer = gpiAddPeer(connection, profileid, GPITrue); + if(!peer) + return GP_MEMORY_ERROR; + + // Check if we need a sig. + ////////////////////////// + if(!profile->peerSig) + { + // Get the sig. + /////////////// + CHECK_RESULT(gpiPeerGetSig(connection, peer)); + } + else + { + // Try to connect to the peer. + ////////////////////////////// + CHECK_RESULT(gpiPeerStartConnect(connection, peer)); + } + } + else if (peer->state == GPI_PEER_DISCONNECTED) + { + if (gpiGetProfile(connection, profileid, &profile)) + { + // clear the buddy port to prevent future messages from + // being sent via UDP layer + if (profile->buddyStatusInfo) + profile->buddyStatusInfo->buddyPort = 0; + + // send the message through the server + if (sendOption == GP_DONT_ROUTE) + return GP_NETWORK_ERROR; + if (type < 100) + return gpiSendServerBuddyMessage(connection, profileid, type, message); + } + } + + if (peerOp) + { + gpiPeerAddOp(peer, peerOp); + } + // Copy the message. + //////////////////// + CHECK_RESULT(gpiPeerAddMessage(connection, peer, type, message)); + + return GP_NO_ERROR; +} + +GPResult gpiBuddyHandleKeyRequest(GPConnection *connection, GPIPeer *peer) +{ + char *message; + + // get all the keys and put them in the message part of bm + ////////////////////////////////////////////////////////// + CHECK_RESULT(gpiSaveKeysToBuffer(connection, &message)); + + // Done in case we haven't set any keys + if (message == NULL) + message = ""; + + CHECK_RESULT(gpiSendBuddyMessage(connection, peer->profile, GPI_BM_KEYS_REPLY, message, GP_DONT_ROUTE, NULL)); + + if (strcmp(message, "")!= 0) + freeclear(message); + return GP_NO_ERROR; +} + +GPResult gpiBuddyHandleKeyReply(GPConnection *connection, GPIPeer *peer, char *buffer) +{ + GPIProfile *pProfile; + + // Get the profile object to store the keys internally + ////////////////////////////////////////////////////// + + if(!gpiGetProfile(connection, peer->profile, &pProfile)) + Error(connection, GP_PARAMETER_ERROR, "Invalid profile."); + + // calculate the B64Decoded string len + if (strcmp(buffer, "") == 0) + { + GPIPeerOp *anIterator; + + for (anIterator = peer->peerOpQueue.first; anIterator != NULL; anIterator = anIterator->next) + if (anIterator->type == GPI_BM_KEYS_REQUEST) + break; + + if (!anIterator) + { + return GP_NO_ERROR; + } + else if (anIterator->type == GPI_BM_KEYS_REQUEST && anIterator->callback) + { + GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg)); + GPICallback callback; + callback.callback = anIterator->callback; + callback.param = anIterator->userData; + + arg->keys = NULL; + arg->numKeys = 0; + arg->values = NULL; + arg->profile = peer->profile; + gpiAddCallback(connection, callback, arg, NULL, 0); + gpiPeerRemoveOp(peer, anIterator); + } + } + else + { + int decodedLen = 0, + index = 0, numKeys, i; + char keyName[512]; + char keyVal[512]; + char decodeKey[512]; + char decodeVal[512]; + gsi_char **keys; + gsi_char **values; + GPIPeerOp *anIterator; + char *checkKey = NULL; + + // start by getting the number of keys + gpiReadKeyAndValue(connection, buffer, &index, keyName, keyVal); + + // do not continue further if the header is missing + if (strcmp(keyName, "keys") != 0) + CallbackError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading keys reply message"); + + numKeys = atoi(keyVal); + + if (numKeys == 0) + { + GPIPeerOp *anIterator; + + for (anIterator = peer->peerOpQueue.first; anIterator != NULL; anIterator = anIterator->next) + if (anIterator->type == GPI_BM_KEYS_REQUEST) + break; + + if (!anIterator) + { + return GP_NO_ERROR; + } + else if (anIterator->type == GPI_BM_KEYS_REQUEST && anIterator->callback) + { + GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg)); + GPICallback callback; + callback.callback = anIterator->callback; + callback.param = anIterator->userData; + + arg->keys = NULL; + arg->numKeys = 0; + arg->values = NULL; + arg->profile = peer->profile; + gpiAddCallback(connection, callback, arg, NULL, 0); + gpiPeerRemoveOp(peer, anIterator); + } + } + else + { + keys = (gsi_char **)gsimalloc(sizeof(gsi_char *) * numKeys); + values = (gsi_char **)gsimalloc(sizeof(gsi_char *) * numKeys); + + for (i = 0; i < numKeys; i++) + { + gpiReadKeyAndValue(connection, buffer, &index, keyName, keyVal); + B64Decode(keyName, decodeKey, (int)strlen(keyName), &decodedLen, 2); + decodeKey[decodedLen] = '\0'; + B64Decode(keyVal, decodeVal, (int)strlen(keyVal), &decodedLen, 2); + decodeVal[decodedLen] = '\0'; + #ifdef GSI_UNICODE + keys[i] = UTF8ToUCS2StringAlloc(decodeKey); + values[i]= UTF8ToUCS2StringAlloc(decodeVal); + #else + keys[i] = goastrdup(decodeKey); + values[i] = goastrdup(decodeVal); + #endif + + if (gpiStatusInfoCheckKey(connection, pProfile->buddyStatusInfo->extendedInfoKeys, decodeKey, &checkKey) == GP_NO_ERROR + && checkKey == NULL) + { + gpiStatusInfoAddKey(connection, pProfile->buddyStatusInfo->extendedInfoKeys, decodeKey, decodeVal); + } + else + { + gpiStatusInfoSetKey(connection, pProfile->buddyStatusInfo->extendedInfoKeys, decodeKey, decodeVal); + } + } + + for (anIterator = peer->peerOpQueue.first; anIterator != NULL; anIterator = anIterator->next) + if (anIterator->type == GPI_BM_KEYS_REQUEST) + break; + + if (!anIterator) + { + return GP_NO_ERROR; + } + else if (anIterator->type == GPI_BM_KEYS_REQUEST && anIterator->callback) + { + GPICallback callback; + GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg)); + + callback.callback = anIterator->callback; + callback.param = anIterator->userData; + + // allocate a key array that points to each extended info key for that player + arg->numKeys = numKeys; + + arg->keys = keys; + arg->values = values; + arg->profile = peer->profile; + + gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYKEYS); + gpiPeerRemoveOp(peer, anIterator); + } + } + } + + return GP_NO_ERROR; +} + +GPResult gpiAuthBuddyRequest +( + GPConnection * connection, + GPProfile profile +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Get the profile object. + ////////////////////////// + if(!gpiGetProfile(connection, profile, &pProfile)) + Error(connection, GP_PARAMETER_ERROR, "Invalid profile."); + + // Check for a valid sig. + ///////////////////////// + if(!pProfile->authSig) + Error(connection, GP_PARAMETER_ERROR, "Invalid profile."); + + // Send the request. + //////////////////// + CHECK_RESULT(gpiSendAuthBuddyRequest(connection, pProfile)); + + // freeclear the sig if no more requests. + //////////////////////////////////// + pProfile->requestCount--; + if(!iconnection->infoCaching && (pProfile->requestCount <= 0)) + { + freeclear(pProfile->authSig); + if(gpiCanFreeProfile(pProfile)) + gpiRemoveProfile(connection, pProfile); + } + + return GP_NO_ERROR; +} + +GPIBool +gpiFixBuddyIndices( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ +#ifndef _PS2 + int baseIndex = (int)(unsigned long)data; +#else + int baseIndex = (int)data; +#endif + + GSI_UNUSED(connection); + + if(profile->buddyStatus && (profile->buddyStatus->buddyIndex > baseIndex)) + profile->buddyStatus->buddyIndex--; + else if (profile->buddyStatusInfo && profile->buddyStatusInfo->buddyIndex > baseIndex) + profile->buddyStatusInfo->buddyIndex--; + return GPITrue; +} + +GPResult +gpiDeleteBuddy( + GPConnection * connection, + GPProfile profile, + GPIBool sendServerRequest +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection = (GPIConnection*)*connection; + int index; + + // Get the profile object. + ////////////////////////// + if(!gpiGetProfile(connection, profile, &pProfile)) + Error(connection, GP_PARAMETER_ERROR, "Invalid profile."); + + // Check that this is a buddy. + ////////////////////////////// + // Removed - 092404 BED - User could be a buddy even though we don't have the status + //if(!pProfile->buddyStatus) + // Error(connection, GP_PARAMETER_ERROR, "Profile not a buddy."); + + // Send the request. + //////////////////// + if (GPITrue == sendServerRequest) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\delbuddy\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\delprofileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, pProfile->profileId); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + } + + // Need to fix up the buddy indexes. + //////////////////////////////////// + if (pProfile->buddyStatus) + { + index = pProfile->buddyStatus->buddyIndex; + assert(index >= 0); + freeclear(pProfile->buddyStatus->statusString); + freeclear(pProfile->buddyStatus->locationString); + freeclear(pProfile->buddyStatus); + if(gpiCanFreeProfile(pProfile)) + gpiRemoveProfile(connection, pProfile); + iconnection->profileList.numBuddies--; + assert(iconnection->profileList.numBuddies >= 0); +#ifndef _PS2 + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)(unsigned long)index); +#else + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)index); +#endif + } + if (pProfile->buddyStatusInfo) + { + index = pProfile->buddyStatusInfo->buddyIndex; + assert(index >= 0); + freeclear(pProfile->buddyStatusInfo->richStatus); + freeclear(pProfile->buddyStatusInfo->gameType); + freeclear(pProfile->buddyStatusInfo->gameVariant); + freeclear(pProfile->buddyStatusInfo->gameMapName); + freeclear(pProfile->buddyStatusInfo); + if (pProfile->buddyStatusInfo->extendedInfoKeys) + { + ArrayFree(pProfile->buddyStatusInfo->extendedInfoKeys); + pProfile->buddyStatusInfo->extendedInfoKeys = NULL; + } + + if(gpiCanFreeProfile(pProfile)) + gpiRemoveProfile(connection, pProfile); + iconnection->profileList.numBuddies--; + assert(iconnection->profileList.numBuddies >= 0); +#ifndef _PS2 + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)(unsigned long)index); +#else + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)index); +#endif + } + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiBuddy.h b/xrGameSpy/gamespy/GP/gpiBuddy.h new file mode 100644 index 00000000000..3b62d6d0e26 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiBuddy.h @@ -0,0 +1,104 @@ +/* +gpiBuddy.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIBUDDY_H_ +#define _GPIBUDDY_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +// Types of bm's. +///////////////// +#define GPI_BM_MESSAGE 1 +#define GPI_BM_REQUEST 2 +#define GPI_BM_REPLY 3 // only used on the backend +#define GPI_BM_AUTH 4 +#define GPI_BM_UTM 5 +#define GPI_BM_REVOKE 6 // remote buddy removed from local list +#define GPI_BM_STATUS 100 +#define GPI_BM_INVITE 101 +#define GPI_BM_PING 102 +#define GPI_BM_PONG 103 +#define GPI_BM_KEYS_REQUEST 104 +#define GPI_BM_KEYS_REPLY 105 +#define GPI_BM_FILE_SEND_REQUEST 200 +#define GPI_BM_FILE_SEND_REPLY 201 +#define GPI_BM_FILE_BEGIN 202 +#define GPI_BM_FILE_END 203 +#define GPI_BM_FILE_DATA 204 +#define GPI_BM_FILE_SKIP 205 +#define GPI_BM_FILE_TRANSFER_THROTTLE 206 +#define GPI_BM_FILE_TRANSFER_CANCEL 207 +#define GPI_BM_FILE_TRANSFER_KEEPALIVE 208 + +//FUNCTIONS +/////////// +GPResult +gpiProcessRecvBuddyMessage( + GPConnection * connection, + const char * input +); + +GPResult gpiProcessRecvBuddyStatusInfo(GPConnection *connection, const char *input); + +GPResult +gpiProcessRecvBuddyList( + GPConnection * connection, + const char * input +); + +GPResult +gpiSendServerBuddyMessage( + GPConnection * connection, + int profileid, + int type, + const char * message +); + +GPResult +gpiSendBuddyMessage( + GPConnection * connection, + int profileid, + int type, + const char * message, + int sendOptions, + GPIPeerOp *peerOp +); + +GPResult gpiBuddyHandleKeyRequest(GPConnection *connection, GPIPeer *peer); +GPResult gpiBuddyHandleKeyReply(GPConnection *connection, GPIPeer *peer, char *buffer); + +GPResult +gpiAuthBuddyRequest( + GPConnection * connection, + GPProfile profile +); + +GPIBool +gpiFixBuddyIndices( + GPConnection * connection, + GPIProfile * profile, + void * data +); + +GPResult +gpiDeleteBuddy( + GPConnection * connection, + GPProfile profile, + GPIBool sendServerRequest +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiBuffer.c b/xrGameSpy/gamespy/GP/gpiBuffer.c new file mode 100644 index 00000000000..40d1db7417a --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiBuffer.c @@ -0,0 +1,771 @@ +/* +gpiBuffer.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 720 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +//INCLUDES +////////// +#include +#include +#include "gpi.h" + +//DEFINES +///////// +#define GPI_DUMP_NET_TRAFFIC + +//FUNCTIONS +/////////// +GPResult +gpiAppendCharToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + char c +) +{ + int len; + int size; + char * output; + + assert(outputBuffer != NULL); + + // Init locals. + /////////////// + len = outputBuffer->len; + size = outputBuffer->size; + output = outputBuffer->buffer; + + // Check if it needs to be resized. + /////////////////////////////////// + if(size == len) + { + size += GPI_READ_SIZE; + output = (char*)gsirealloc(output, (unsigned int)size + 1); + if(output == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + + // Do the copy. + /////////////// + output[len] = c; + output[len + 1] = '\0'; + + // Update the buffer info. + ////////////////////////// + outputBuffer->len++; + outputBuffer->size = size; + outputBuffer->buffer = output; + + return GP_NO_ERROR; +} + +GPResult +gpiAppendStringToBufferLen( + GPConnection * connection, + GPIBuffer * outputBuffer, + const char * string, + int stringLen +) +{ + int len; + int size; + char * output; + + assert(string != NULL); + assert(stringLen >= 0); + assert(outputBuffer != NULL); + + if(!string) + return GP_NO_ERROR; + + // Init locals. + /////////////// + len = outputBuffer->len; + size = outputBuffer->size; + output = outputBuffer->buffer; + + // Check if it needs to be resized. + /////////////////////////////////// + if((size - len) < stringLen) + { + size += max(GPI_READ_SIZE, stringLen); + output = (char*)gsirealloc(output, (unsigned int)size + 1); + if(output == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + + // Do the copy. + /////////////// + memcpy(&output[len], string, (unsigned int)stringLen); + output[len + stringLen] = '\0'; + + // Update the buffer info. + ////////////////////////// + outputBuffer->len += stringLen; + outputBuffer->size = size; + outputBuffer->buffer = output; + + return GP_NO_ERROR; +} + +GPResult +gpiAppendStringToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + const char * buffer +) +{ + return gpiAppendStringToBufferLen(connection, outputBuffer, buffer, (int)strlen(buffer)); +} + +GPResult gpiAppendShortToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + short num) +{ + char shortVal[8]; + sprintf(shortVal, "%d", num); + return gpiAppendStringToBuffer(connection, outputBuffer, shortVal); +} + +GPResult gpiAppendUShortToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + unsigned short num) +{ + char shortVal[8]; + sprintf(shortVal, "%u", num); + return gpiAppendStringToBuffer(connection, outputBuffer, shortVal); +} + +GPResult +gpiAppendIntToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + int num +) +{ + char intValue[16]; + sprintf(intValue,"%d",num); + return gpiAppendStringToBuffer(connection, outputBuffer, intValue); +} + +GPResult +gpiAppendUIntToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + unsigned int num +) +{ + char intValue[16]; + sprintf(intValue,"%u",num); + return gpiAppendStringToBuffer(connection, outputBuffer, intValue); +} + +static GPResult +gpiSendData( + GPConnection * connection, + SOCKET sock, + const char * buffer, + int bufferLen, + GPIBool * closed, + int * sent, + char id[3] +) +{ + int rcode; + + rcode = send(sock, buffer, bufferLen, 0); + if(gsiSocketIsError(rcode)) + { + rcode = GOAGetLastError(sock); + if((rcode != WSAEWOULDBLOCK) && (rcode != WSAEINPROGRESS) && (rcode != WSAETIMEDOUT) ) + { + // handle peer connections specially + if((id[0] == 'P') && (id[1] == 'R')) + return GP_NETWORK_ERROR; + CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error sending on a socket."); + } + + *sent = 0; + *closed = GPIFalse; + } + else if(rcode == 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Comment, + "SENDXXXX(%s): Connection closed\n", id); + + *sent = 0; + *closed = GPITrue; + } + else + { + #if defined(GPI_DUMP_NET_TRAFFIC) && defined(GSI_COMMON_DEBUG) + { + static int sendCount; + char *buf = (char *)gsimalloc((size_t)(rcode + 1)); + memcpy(buf, buffer, (size_t)rcode); + buf[rcode] = '\0'; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_RawDump, "SENT%04d(%s): %s\n", sendCount++, id, buf); + freeclear(buf); + } + #elif defined(GSI_COMMON_DEBUG) + { + static int sendCount; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "SENT%04d(%s): %d\n", sendCount++, id, rcode); + } + #endif + + *sent = rcode; + *closed = GPIFalse; + } + + return GP_NO_ERROR; +} + +GPResult +gpiSendOrBufferChar( + GPConnection * connection, + GPIPeer_st peer, + char c +) +{ + //GPIBool closed; + //int sent; +/* + assert(peer->outputBuffer.buffer != NULL); + + // Only try to send if the buffer is empty and there are no messages. + ///////////////////////////////////////////////////////////////////// + if(!(peer->outputBuffer.len - peer->outputBuffer.pos) && !ArrayLength(peer->messages)) + { + CHECK_RESULT(gpiSendData(connection, peer->sock, &c, 1, &closed, &sent, "PT")); + if(sent) + return GP_NO_ERROR; + } + + // Buffer if not sent. + ////////////////////// + return gpiAppendCharToBuffer(connection, &peer->outputBuffer, c); + */ + GSI_UNUSED(c); + GSI_UNUSED(peer); + GSI_UNUSED(connection); + return GP_NO_ERROR; +} + +GPResult +gpiSendOrBufferStringLenToPeer( + GPConnection * connection, + GPIPeer_st peer, + const char * string, + int stringLen +) +{ + GPIConnection *iconnection; + + unsigned int sent; + unsigned int total; + unsigned int remaining; + + assert(peer->outputBuffer.buffer != NULL); + + sent = 0; + iconnection = (GPIConnection *)*connection; + remaining = (unsigned int)stringLen; + total = 0; + + // Check for nothing to send. + ///////////////////////////// + if(stringLen == 0) + return GP_NO_ERROR; + + // Only try to send if the buffer is empty and there are no messages. + ///////////////////////////////////////////////////////////////////// + if(!(peer->outputBuffer.len - peer->outputBuffer.pos) && !ArrayLength(peer->messages)) + { + if ((int)remaining <= (gsUdpEngineGetPeerOutBufferFreeSpace(peer->ip, peer->port) - GS_UDP_RELIABLE_MSG_HEADER - GS_UDP_MSG_HEADER_LEN)) + { + gsUdpEngineSendMessage(peer->ip, peer->port, iconnection->mHeader, (unsigned char *)string, remaining, gsi_true); + total = remaining; + remaining = 0; + } + else + { + unsigned int freeSpace = (unsigned int)gsUdpEngineGetPeerOutBufferFreeSpace(peer->ip, peer->port); + if (freeSpace > (GS_UDP_MSG_HEADER_LEN + GS_UDP_RELIABLE_MSG_HEADER)) + { + sent = freeSpace - (GS_UDP_MSG_HEADER_LEN + GS_UDP_RELIABLE_MSG_HEADER); + gsUdpEngineSendMessage(peer->ip, peer->port, iconnection->mHeader, (unsigned char *)string, + sent, gsi_true); + total = sent; + remaining -= sent; + } + } + + } + + // Buffer what wasn't sent. + /////////////////////////// + if(remaining) + CHECK_RESULT(gpiAppendStringToBufferLen(connection, &peer->outputBuffer, &string[total], (int)remaining)); + + return GP_NO_ERROR; +} + +/* +GPResult +gpiSendOrBufferStringLen( + GPConnection * connection, + GPIPeer_st peer, + const char * string, + int stringLen + ) +{ + + GPIBool closed; + int sent; + int total; + int remaining; + + + assert(peer->outputBuffer.buffer != NULL); + + remaining = stringLen; + total = 0; + + // Check for nothing to send. + ///////////////////////////// + if(stringLen == 0) + return GP_NO_ERROR; + + // Only try to send if the buffer is empty and there are no messages. + ///////////////////////////////////////////////////////////////////// + if(!(peer->outputBuffer.len - peer->outputBuffer.pos) && !ArrayLength(peer->messages)) + { + do + { + CHECK_RESULT(gpiSendData(connection, peer->sock, &string[total], remaining, &closed, &sent, "PT")); + if(sent) + { + total += sent; + remaining -= sent; + } + } + while(sent && remaining); + } + + // Buffer what wasn't sent. + /////////////////////////// + if(remaining) + CHECK_RESULT(gpiAppendStringToBufferLen(connection, &peer->outputBuffer, &string[total], remaining)); + + + GSI_UNUSED(stringLen); + GSI_UNUSED(string); + GSI_UNUSED(peer); + GSI_UNUSED(connection); + return GP_NO_ERROR; +} +*/ + +GPResult +gpiSendOrBufferString( + GPConnection * connection, + GPIPeer_st peer, + char * string +) +{ + return gpiSendOrBufferStringLenToPeer(connection, peer, string, (int)strlen(string)); +} + +GPResult +gpiSendOrBufferInt( + GPConnection * connection, + GPIPeer_st peer, + int num +) +{ + char intValue[16]; + sprintf(intValue,"%d",num); + return gpiSendOrBufferString(connection, peer, intValue); +} + +GPResult +gpiSendOrBufferUInt( + GPConnection * connection, + GPIPeer_st peer, + unsigned int num +) +{ + char intValue[16]; + sprintf(intValue,"%u",num); + return gpiSendOrBufferString(connection, peer, intValue); +} + +GPResult +gpiRecvToBuffer( + GPConnection * connection, + SOCKET sock, + GPIBuffer * inputBuffer, + int * bytesRead, + GPIBool * connClosed, + char id[3] +) +{ + char * buffer; + int len; + int size; + int rcode; + int total; + GPIBool closed; + + assert(sock != INVALID_SOCKET); + assert(inputBuffer != NULL); + assert(bytesRead != NULL); + assert(connClosed != NULL); + + // Init locals. + /////////////// + buffer = inputBuffer->buffer; + len = inputBuffer->len; + size = inputBuffer->size; + total = 0; + closed = GPIFalse; + + do + { + // Check if the buffer needs to be resized. + /////////////////////////////////////////// + if((len + GPI_READ_SIZE) > size) + { + size = (len + GPI_READ_SIZE); + buffer = (char *)gsirealloc(buffer, (unsigned int)size + 1); + if(buffer == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + + // Read from the network. + rcode = recv(sock, &buffer[len], size - len, 0); + + + if(gsiSocketIsError(rcode)) + { + int error = GOAGetLastError(sock); + if((error != WSAEWOULDBLOCK) && (error != WSAEINPROGRESS) && (error != WSAETIMEDOUT) ) + { + Error(connection, GP_NETWORK_ERROR, "There was an error reading from a socket."); + } + } + else if(rcode == 0) + { + // Check for a closed connection. + ///////////////////////////////// + closed = GPITrue; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Comment, + "RECVXXXX(%s): Connection closed\n", id); + } + else + { + #if defined(GPI_DUMP_NET_TRAFFIC) && defined(GSI_COMMON_DEBUG) + { + static int recvCount; + char *buf = (char *)gsimalloc((size_t)(rcode + 1)); + memcpy(buf, &buffer[len], (size_t)rcode); + buf[rcode] = '\0'; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "RECV%04d(%s): %s\n", recvCount++, id, buf); + freeclear(buf); + } + #elif defined(GSI_COMMON_DEBUG) + { + static int recvCount; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "RECV%04d(%s): %d\n", recvCount++, id, rcode); + } + #endif + // Update the buffer len. + ///////////////////////// + len += rcode; + + // Update the total. + //////////////////// + total += rcode; + } + + buffer[len] = '\0'; + } + while((rcode >= 0) && !closed && (total < (128 * 1024))); + + if(total) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "RECVTOTL(%s): %d\n", id, total); + } + + // Set output stuff. + //////////////////// + inputBuffer->buffer = buffer; + inputBuffer->len = len; + inputBuffer->size = size; + *bytesRead = total; + *connClosed = closed; + + GSI_UNUSED(id); //to get rid of codewarrior warnings + + return GP_NO_ERROR; +} + +GPResult +gpiSendFromBuffer( + GPConnection * connection, + SOCKET sock, + GPIBuffer * outputBuffer, + GPIBool * connClosed, + GPIBool clipSentData, + char id[3] +) +{ + GPIBool closed; + int sent; + int total; + int remaining; + char * buffer; + int pos; + int len; + + assert(outputBuffer != NULL); + + buffer = outputBuffer->buffer; + len = outputBuffer->len; + pos = outputBuffer->pos; + remaining = (len - pos); + total = 0; + + // Check for nothing to send. + ///////////////////////////// + if(remaining == 0) + return GP_NO_ERROR; + + do + { + CHECK_RESULT(gpiSendData(connection, sock, &buffer[pos + total], remaining, &closed, &sent, id)); + if(sent) + { + total += sent; + remaining -= sent; + } + } + while(sent && remaining); + + if(clipSentData) + { + if(total > 0) + { + memmove(buffer, &buffer[total], (unsigned int)remaining + 1); + len -= total; + } + } + else + { + pos += total; + } + + assert(len >= 0); + assert(pos >= 0); + assert(pos <= len); + + // Set outputs. + /////////////// + outputBuffer->len = len; + outputBuffer->pos = pos; + if(connClosed) + *connClosed = closed; + + return GP_NO_ERROR; +} + +GPResult gpiSendBufferToPeer(GPConnection * connection, unsigned int ip, unsigned short port, + GPIBuffer * outputBuffer, GPIBool *closed, GPIBool clipSentData) +{ + GPIConnection *iconnection = (GPIConnection *)*connection; + //GPIBool closed; + unsigned int remaining; + unsigned char * buffer; + unsigned int pos; + unsigned int len; + unsigned int total = 0; + GSUdpPeerState aPeerState; + assert(outputBuffer != NULL); + + buffer = (unsigned char *)outputBuffer->buffer; + len = (unsigned int)outputBuffer->len; + pos = (unsigned int)outputBuffer->pos; + remaining = (len - pos); + + // Check for nothing to send. + ///////////////////////////// + if(remaining == 0) + return GP_NO_ERROR; + + // length of message remaining must be smaller than total buffer size minus gt2 reliable msg header size minus + // in order to send the message in one shot. + if ((int)remaining <= (gsUdpEngineGetPeerOutBufferFreeSpace(ip, port) - GS_UDP_RELIABLE_MSG_HEADER - GS_UDP_MSG_HEADER_LEN)) + { + gsUdpEngineSendMessage(ip, port, iconnection->mHeader, &buffer[pos], remaining, gsi_true); + total = remaining; + remaining = 0; + } + else + { + unsigned int freeSpace =0; + unsigned int sendAmount = 0; + do + { + freeSpace = (unsigned int)gsUdpEngineGetPeerOutBufferFreeSpace(ip, port); + sendAmount = freeSpace - (GS_UDP_MSG_HEADER_LEN + GS_UDP_RELIABLE_MSG_HEADER); + if (sendAmount <= (GS_UDP_MSG_HEADER_LEN + GS_UDP_RELIABLE_MSG_HEADER)) + break; + if (gsUdpEngineSendMessage(ip, port, iconnection->mHeader, &buffer[pos+total], sendAmount, gsi_true) == GS_UDP_SEND_FAILED) + break; + total += sendAmount; + remaining -= sendAmount; + }while (remaining); + } + + if(clipSentData) + { + if (total > 0) + { + memmove(buffer, &buffer[total], remaining + 1); + len -= total; + } + } + else + { + pos += total; + } + // Set outputs. + /////////////// + outputBuffer->len = (int)len; + outputBuffer->pos = (int)pos; + + gsUdpEngineGetPeerState(ip, port, &aPeerState); + if (aPeerState == GS_UDP_PEER_CLOSED) + *closed = GPITrue; + else + *closed = GPIFalse; + + return GP_NO_ERROR; +} + +GPResult +gpiReadMessageFromBuffer( + GPConnection * connection, + GPIBuffer * inputBuffer, + char ** message, + int * type, + int * plen +) +{ + char * str; + int len; + char intValue[16]; + + // Default. + /////////// + *message = NULL; + + // Check for not enough data. + ///////////////////////////// + if(inputBuffer->len < 5) + return GP_NO_ERROR; + + // Find the end of the header. + ////////////////////////////// + str = strchr(inputBuffer->buffer, '\n'); + if(str != NULL) + { + // Check that this is the msg. + ////////////////////////////// + if(strncmp(str - 5, "\\msg\\", 5) != 0) + return GP_NETWORK_ERROR; + + // Cap the header. + ////////////////// + *str = '\0'; + + // Read the header. + /////////////////// + if(!gpiValueForKey(inputBuffer->buffer, "\\m\\", intValue, sizeof(intValue))) + return GP_NETWORK_ERROR; + *type = atoi(intValue); + + // Get the length. + ////////////////// + if(!gpiValueForKey(inputBuffer->buffer, "\\len\\", intValue, sizeof(intValue))) + return GP_NETWORK_ERROR; + len = atoi(intValue); + len++; + + // Is the whole message available? + ////////////////////////////////// + if(inputBuffer->len > ((str - inputBuffer->buffer) + len)) + { + // Does it not end with a NUL? + ////////////////////////////// + if(str[len] != '\0') + return GP_NETWORK_ERROR; + + // Set the message stuff. + ///////////////////////// + *message = &str[1]; + *plen = (len - 1); + + // Set the position to the end of the message. + ////////////////////////////////////////////// + inputBuffer->pos = ((str - inputBuffer->buffer) + len + 1); + } + else + { + // Put the LF back. + /////////////////// + *str = '\n'; + } + } + + GSI_UNUSED(connection); + return GP_NO_ERROR; +} + +GPResult +gpiClipBufferToPosition( + GPConnection * connection, + GPIBuffer * buffer +) +{ + if(!buffer || !buffer->buffer || !buffer->pos) + return GP_NO_ERROR; + + buffer->len -= buffer->pos; + if(buffer->len) + memmove(buffer->buffer, buffer->buffer + buffer->pos, (unsigned int)buffer->len); + buffer->buffer[buffer->len] = '\0'; + buffer->pos = 0; + + GSI_UNUSED(connection); + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiBuffer.h b/xrGameSpy/gamespy/GP/gpiBuffer.h new file mode 100644 index 00000000000..2a2b7a7113e --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiBuffer.h @@ -0,0 +1,167 @@ +/* +gpiBuffer.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIBUFFER_H_ +#define _GPIBUFFER_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//TYPES +/////// +// A buffer. +//////////// +typedef struct +{ + char * buffer; + int size; + int len; + int pos; +} GPIBuffer; + +typedef struct GPIPeer_s * GPIPeer_st; + +//FUNCTIONS +/////////// +GPResult +gpiAppendCharToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + char c +); + +GPResult +gpiAppendStringToBufferLen( + GPConnection * connection, + GPIBuffer * outputBuffer, + const char * string, + int stringLen +); + +GPResult +gpiAppendStringToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + const char * buffer +); + +GPResult gpiAppendShortToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + short num +); + +GPResult gpiAppendUShortToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + unsigned short num +); + +GPResult +gpiAppendIntToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + int num +); + +GPResult +gpiAppendUIntToBuffer( + GPConnection * connection, + GPIBuffer * outputBuffer, + unsigned int num +); + +GPResult +gpiSendOrBufferChar( + GPConnection * connection, + GPIPeer_st peer, + char c +); + +/* +GPResult +gpiSendOrBufferStringLen( + GPConnection * connection, + GPIPeer_st peer, + const char * string, + int stringLen +); +*/ +GPResult +gpiSendOrBufferStringLenToPeer( + GPConnection * connection, + GPIPeer_st peer, + const char * string, + int stringLen +); + +GPResult +gpiSendOrBufferString( + GPConnection * connection, + GPIPeer_st peer, + char * string +); + +GPResult +gpiSendOrBufferInt( + GPConnection * connection, + GPIPeer_st peer, + int num +); + +GPResult +gpiSendOrBufferUInt( + GPConnection * connection, + GPIPeer_st peer, + unsigned int num +); + +GPResult +gpiSendFromBuffer( + GPConnection * connection, + SOCKET sock, + GPIBuffer * outputBuffer, + GPIBool * connClosed, + GPIBool clipSentData, + char id[3] +); + +GPResult +gpiRecvToBuffer( + GPConnection * connection, + SOCKET sock, + GPIBuffer * inputBuffer, + int * bytesRead, + GPIBool * connClosed, + char id[3] +); + +GPResult +gpiReadMessageFromBuffer( + GPConnection * connection, + GPIBuffer * inputBuffer, + char ** message, + int * type, + int * len +); + +GPResult +gpiClipBufferToPosition( + GPConnection * connection, + GPIBuffer * buffer +); + +GPResult gpiSendBufferToPeer(GPConnection * connection, unsigned int ip, unsigned short port, + GPIBuffer * outputBuffer, GPIBool *closed, GPIBool clipSentData); +#endif diff --git a/xrGameSpy/gamespy/GP/gpiCallback.c b/xrGameSpy/gamespy/GP/gpiCallback.c new file mode 100644 index 00000000000..4de1049cc28 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiCallback.c @@ -0,0 +1,277 @@ +/* +gpiCallback.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include +#include "gpi.h" + +//FUNCTIONS +/////////// +void +gpiCallErrorCallback( + GPConnection * connection, + GPResult result, + GPEnum fatal +) +{ + GPICallback callback; + GPIConnection * iconnection = (GPIConnection*)*connection; + + assert(iconnection != NULL); + assert(result != GP_NO_ERROR); + assert((fatal == GP_FATAL) || (fatal == GP_NON_FATAL)); + + if(fatal == GP_FATAL) + iconnection->fatalError = GPITrue; + + callback = iconnection->callbacks[GPI_ERROR]; + if(callback.callback != NULL) + { + GPErrorArg * arg; + arg = (GPErrorArg *)gsimalloc(sizeof(GPErrorArg)); + + if(arg != NULL) + { + arg->result = result; + arg->fatal = fatal; + arg->errorCode = iconnection->errorCode; +#ifndef GSI_UNICODE + arg->errorString = iconnection->errorString; +#else + arg->errorString = iconnection->errorString_W; +#endif + + } + + gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_ERROR); + } +} + +GPResult +gpiAddCallback( + GPConnection * connection, + GPICallback callback, + void * arg, + const struct GPIOperation_s * operation, + int type +) +{ + GPICallbackData * data; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Allocate the callback data. + ////////////////////////////// + data = (GPICallbackData *)gsimalloc(sizeof(GPICallbackData)); + if(data == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + data->callback = callback; + data->arg = arg; + if(operation != NULL) + data->operationID = operation->id; + else + data->operationID = 0; + data->type = type; + data->pnext = NULL; + + // Update the list. + /////////////////// + if(iconnection->callbackList == NULL) + iconnection->callbackList = data; + if(iconnection->lastCallback != NULL) + iconnection->lastCallback->pnext = data; + iconnection->lastCallback = data; + + return GP_NO_ERROR; +} + +static void +gpiCallCallback( + GPConnection * connection, + GPICallbackData * data +) +{ + // Call the callback. + ///////////////////// + assert(data->callback.callback != NULL); + assert(data->arg != NULL); + data->callback.callback(connection, data->arg, data->callback.param); + if(data->type == GPI_ADD_MESSAGE) + { + freeclear(((GPRecvBuddyMessageArg *)data->arg)->message); + } + else if (data->type == GPI_ADD_BUDDYUTM) + { + freeclear(((GPRecvBuddyUTMArg *)data->arg)->message); + } + else if(data->type == GPI_ADD_NICKS) + { + int i; + GPGetUserNicksResponseArg * arg = (GPGetUserNicksResponseArg *)data->arg; + + for(i = 0 ; i < arg->numNicks ; i++) + { + freeclear(arg->nicks[i]); + freeclear(arg->uniquenicks[i]); + } + freeclear(arg->nicks); + freeclear(arg->uniquenicks) + } + else if(data->type == GPI_ADD_PMATCH) + { + GPFindPlayersResponseArg * arg = (GPFindPlayersResponseArg *)data->arg; + + freeclear(arg->matches); + } + else if(data->type == GPI_ADD_TRANSFER_CALLBACK) + { + GPTransferCallbackArg * arg = (GPTransferCallbackArg *)data->arg; + + if(arg->message) + freeclear(arg->message); + } + else if(data->type == GPI_ADD_REVERSE_BUDDIES) + { + GPGetReverseBuddiesResponseArg * arg = (GPGetReverseBuddiesResponseArg *)data->arg; + + if(arg->profiles) + freeclear(arg->profiles); + } + else if(data->type == GPI_ADD_SUGGESTED_UNIQUE) + { + int i; + GPSuggestUniqueNickResponseArg * arg = (GPSuggestUniqueNickResponseArg *)data->arg; + + for(i = 0 ; i < arg->numSuggestedNicks ; i++) + { + freeclear(arg->suggestedNicks[i]); + } + freeclear(arg->suggestedNicks); + } + else if (data->type == GPI_ADD_BUDDYREVOKE) + { + GPRecvBuddyRevokeArg * arg = (GPRecvBuddyRevokeArg *)data->arg; + + // Remove the profile from our local lists AFTER the callback has been called + gpiDeleteBuddy(connection, arg->profile, GPIFalse); + } + else if (data->type == GPI_ADD_REVERSE_BUDDIES_LIST) + { + GPGetReverseBuddiesListResponseArg * arg = (GPGetReverseBuddiesListResponseArg *)data->arg; + + if(arg->matches) + freeclear(arg->matches); + } + else if (data->type == GPI_ADD_BUDDYKEYS) + { + GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)data->arg; + if (arg->numKeys != 0) + { + int i; + for (i=0; i < arg->numKeys; i++) + { + freeclear(arg->keys[i]); + freeclear(arg->values[i]); + } + freeclear(arg->keys); + freeclear(arg->values); + } + } + freeclear(data->arg); + freeclear(data); +} + +GPResult +gpiProcessCallbacks( + GPConnection * connection, + int blockingOperationID +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPICallbackData * list; + GPICallbackData * last; + GPICallbackData * pcurr; + GPICallbackData * pnext; + GPICallbackData * pprev; + + if(blockingOperationID != 0) + { + list = iconnection->callbackList; + last = iconnection->lastCallback; + iconnection->callbackList = NULL; + iconnection->lastCallback = NULL; + + pprev = NULL; + for(pcurr = list ; pcurr != NULL ; ) + { + pnext = pcurr->pnext; + + if((pcurr->operationID == blockingOperationID) || (pcurr->type == GPI_ADD_ERROR)) + { + // Take this one out of the list. + ///////////////////////////////// + if(pprev != NULL) + pprev->pnext = pcurr->pnext; + else + list = pcurr->pnext; + if(last == pcurr) + last = pprev; + + // Call the callback. + ///////////////////// + gpiCallCallback(connection, pcurr); + } + else + { + pprev = pcurr; + } + + pcurr = pnext; + } + + // Were callbacks added within the callback? + //////////////////////////////////////////// + if(iconnection->callbackList != NULL) + { + iconnection->lastCallback->pnext = list; + iconnection->lastCallback = last; + } + else + { + // Reset the list. + ////////////////// + iconnection->callbackList = list; + iconnection->lastCallback = last; + } + + return GP_NO_ERROR; + } + + while(iconnection->callbackList != NULL) + { + list = iconnection->callbackList; + iconnection->callbackList = NULL; + iconnection->lastCallback = NULL; + + for(pcurr = list ; pcurr != NULL ; pcurr = pnext) + { + pnext = pcurr->pnext; + + // Call the callback. + ///////////////////// + gpiCallCallback(connection, pcurr); + } + } + + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiCallback.h b/xrGameSpy/gamespy/GP/gpiCallback.h new file mode 100644 index 00000000000..599d090911a --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiCallback.h @@ -0,0 +1,109 @@ +/* +gpiCallback.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPICALLBACK_H_ +#define _GPICALLBACK_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +// Unsolicited Callbacks. +///////////////////////// +enum GPICallbackId +{ + GPI_ERROR = GP_ERROR, + GPI_RECV_BUDDY_REQUEST = GP_RECV_BUDDY_REQUEST, + GPI_RECV_BUDDY_STATUS = GP_RECV_BUDDY_STATUS, + GPI_RECV_BUDDY_MESSAGE = GP_RECV_BUDDY_MESSAGE, + GPI_RECV_BUDDY_UTM = GP_RECV_BUDDY_UTM, + GPI_RECV_GAME_INVITE = GP_RECV_GAME_INVITE, + GPI_TRANSFER_CALLBACK = GP_TRANSFER_CALLBACK, + GPI_RECV_BUDDY_AUTH = GP_RECV_BUDDY_AUTH, + GPI_RECV_BUDDY_REVOKE = GP_RECV_BUDDY_REVOKE, + GPI_NUM_CALLBACKS +}; + +// Add type - not 0 only for a few. +/////////////////////////////////// +enum GPIAddCallbackType +{ + GPI_ADD_NORMAL, + GPI_ADD_ERROR, + GPI_ADD_MESSAGE, + GPI_ADD_NICKS, + GPI_ADD_PMATCH, + GPI_ADD_STATUS, + GPI_ADD_BUDDDYREQUEST, + GPI_ADD_TRANSFER_CALLBACK, + GPI_ADD_REVERSE_BUDDIES, + GPI_ADD_SUGGESTED_UNIQUE, + GPI_ADD_BUDDYAUTH, + GPI_ADD_BUDDYUTM, + GPI_ADD_BUDDYREVOKE, + GPI_ADD_REVERSE_BUDDIES_LIST, + GPI_ADD_BUDDYKEYS, + GPI_NUM_ADD_CALLBACK_TYPES +}; + + +//TYPES +/////// +// A Callback. +////////////// +typedef struct +{ + GPCallback callback; + void * param; +} GPICallback; + +// Data for a pending callback. +/////////////////////////////// +typedef struct GPICallbackData +{ + GPICallback callback; + void * arg; + int type; + int operationID; + struct GPICallbackData * pnext; +} GPICallbackData; + +//FUNCTIONS +/////////// +void +gpiCallErrorCallback( + GPConnection * connection, + GPResult result, + GPEnum fatal +); + +typedef struct GPIOperation_s *GPIOperation_st; + +GPResult +gpiAddCallback( + GPConnection * connection, + GPICallback callback, + void * arg, + const struct GPIOperation_s * operation, + int type +); + +GPResult +gpiProcessCallbacks( + GPConnection * connection, + int blockingOperationID +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiConnect.c b/xrGameSpy/gamespy/GP/gpiConnect.c new file mode 100644 index 00000000000..5c4ecc89329 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiConnect.c @@ -0,0 +1,993 @@ +/* +gpiConnect.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 379, 415, 739 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +//INCLUDES +////////// +#include +#include +#include "gpi.h" +#include + + +//DEFINES +///////// +// Connection Manager Address. +////////////////////////////// +#define GPI_CONNECTION_MANAGER_NAME "gpcm." GSI_DOMAIN_NAME +#define GPI_CONNECTION_MANAGER_PORT 29900 + +#define GPI_UDP_HEADER "gamespygp" +// Random String stuff. +/////////////////////// +#define RANDSTRING "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +//this is off by one +//#define RANDOMCHAR() (RANDSTRING[(rand() * sizeof(RANDSTRING)) / (RAND_MAX + 1)]) +#define RANDOMCHAR() (RANDSTRING[rand() % (sizeof(RANDSTRING) - 1)]) + +//GLOBALS +///////// +char GPConnectionManagerHostname[64] = GPI_CONNECTION_MANAGER_NAME; + +//FUNCTIONS +/////////// +static void randomString( + char * buffer, + int numChars +) +{ + int i; + + for(i = 0 ; i < numChars ; i++) + buffer[i] = RANDOMCHAR(); + buffer[i] = '\0'; +} + +static GPResult +gpiStartConnect( + GPConnection * connection, + GPIOperation * operation +) +{ + struct sockaddr_in address; + int rcode; + //int len; + GPIConnection * iconnection = (GPIConnection*)*connection; + struct hostent * host; + + GSUdpErrorCode anError; + strncpy(iconnection->mHeader, GPI_UDP_HEADER, GS_UDP_MSG_HEADER_LEN); + + if (!gsUdpEngineIsInitialized()) + { + unsigned short peerPort = GPI_PEER_PORT; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, + "Initializing UDP Layer\n"); + anError = gsUdpEngineInitialize(peerPort, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (anError != GS_UDP_NO_ERROR) + { + while (anError != GS_UDP_NO_ERROR && peerPort < GPI_PEER_PORT + 100) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Comment, + "Port %d failed, trying next port\n", peerPort); + anError = gsUdpEngineInitialize(++peerPort, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + } + if (anError != GS_UDP_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, + "Tryed all 100 ports after default port, giving up.\n"); + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_UDP_LAYER, + "There was error starting the UDP layer."); + } + } + if (!iconnection->firewall) + { + iconnection->peerPort = peerPort; + } + } + else + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, + "UDP Layer already initialized, using existing port.\n"); + iconnection->peerPort = gsUdpEngineGetLocalPort(); + } + anError = gsUdpEngineAddMsgHandler(iconnection->mHeader, iconnection->mHeader, NULL, gpiPeerAcceptedCallback, gpiPeerLeftCallback, + gpiPeerPingReplyCallback, gpiPeerMessageCallback, connection); + if (anError != GS_UDP_NO_ERROR) + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_UDP_LAYER, "There was an error starting the UDP Layer."); + } + if(iconnection->firewall) + { + + /* + // Create the peer listening socket. + //////////////////////////////////// + iconnection->peerSocket = socket(AF_INET, SOCK_STREAM, 0); + if(iconnection->peerSocket == INVALID_SOCKET) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error creating a socket."); + + // Make it non-blocking. + //////////////////////// + rcode = SetSockBlocking(iconnection->peerSocket,0); + if (rcode == 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error making a socket non-blocking."); + // Bind the socket. + /////////////////// + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + rcode = bind(iconnection->peerSocket, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if(gsiSocketIsError(rcode)) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error binding a socket."); + + // Start listening on the socket. + ///////////////////////////////// + rcode = listen(iconnection->peerSocket, SOMAXCONN); + if(gsiSocketIsError(rcode)) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error listening on a socket."); + + // Get the socket's port. + ///////////////////////// + len = sizeof(struct sockaddr_in); + rcode = getsockname(iconnection->peerSocket, (struct sockaddr *)&address, &len); + + if (gsiSocketIsError(rcode)) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error getting a socket's addres."); + iconnection->peerPort = address.sin_port; + */ + + + iconnection->peerPort = 0; + } + /* + else + { + // Deprecated TCP code; Replaced by UDP Layer + // No local port. + ///////////////// + //iconnection->peerSocket = INVALID_SOCKET; + + // Set to nothing because NN will determine this + ////////////////////////// + //iconnection->peerPort = 0; + } + */ + + + + // Create the cm socket. + //////////////////////// + iconnection->cmSocket = socket(AF_INET, SOCK_STREAM, 0); + if(iconnection->cmSocket == INVALID_SOCKET) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error creating a socket."); + + // Make it non-blocking. + //////////////////////// + rcode = SetSockBlocking(iconnection->cmSocket,0); + if(rcode == 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error making a socket non-blocking."); +/* + // Bind the socket. + /////////////////// + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + rcode = bind(iconnection->cmSocket, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if (gsiSocketIsError(rcode)) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error binding a socket."); +*/ + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + // Get the server host. + /////////////////////// + if (inet_addr(GPConnectionManagerHostname) == INADDR_NONE) + { + host = gethostbyname(GPConnectionManagerHostname); + if(host == NULL) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "Could not resolve connection mananger host name."); + address.sin_addr.s_addr = *(unsigned int *)host->h_addr_list[0]; + //printf("Resolved Hostname and copied address: %s\n", inet_ntoa(address.sin_addr)); + } + else + { + address.sin_addr.s_addr = inet_addr(GPConnectionManagerHostname); + //printf("Using hardcoded address: %s", GPConnectionManagerHostname); + } + + // Connect the socket. + ////////////////////// + assert(address.sin_addr.s_addr != 0); + address.sin_port = htons(GPI_CONNECTION_MANAGER_PORT); + rcode = connect(iconnection->cmSocket, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if (gsiSocketIsError(rcode)) + { + int error = GOAGetLastError(iconnection->cmSocket); + if((error != WSAEWOULDBLOCK) && (error != WSAEINPROGRESS) && (error != WSAETIMEDOUT)) + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error connecting a socket."); + } + } + + // We're waiting for the connect to complete. + ///////////////////////////////////////////// + operation->state = GPI_CONNECTING; + iconnection->connectState = GPI_CONNECTING; + + return GP_NO_ERROR; +} + +GPResult +gpiConnect( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + const char authtoken[GP_AUTHTOKEN_LEN], + const char partnerchallenge[GP_PARTNERCHALLENGE_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum firewall, + GPIBool newuser, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnectData * data; + GPIOperation * operation; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPResult result; + + // Reset if this connection was already used. + ///////////////////////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + CHECK_RESULT(gpiReset(connection)); + + // Error check. + /////////////// + if(iconnection->connectState != GPI_NOT_CONNECTED) + Error(connection, GP_PARAMETER_ERROR, "Invalid connection."); + + // Get the firewall setting. + //////////////////////////// +#if defined(GS_WIRELESS_DEVICE) + GSI_UNUSED(firewall); + iconnection->firewall = GPITrue; +#else + switch(firewall) + { + case GP_FIREWALL: + iconnection->firewall = GPITrue; + break; + case GP_NO_FIREWALL: + iconnection->firewall = GPIFalse; + break; + default: + Error(connection, GP_PARAMETER_ERROR, "Invalid firewall."); + } +#endif + + // Get the nick, uniquenick, email, and password. + ///////////////////////////////////////////////// + strzcpy(iconnection->nick, nick, GP_NICK_LEN); + strzcpy(iconnection->uniquenick, uniquenick, GP_UNIQUENICK_LEN); + strzcpy(iconnection->email, email, GP_EMAIL_LEN); + strzcpy(iconnection->password, password, GP_PASSWORD_LEN); + +#ifdef GSI_UNICODE + // Create the _W version in addition + UTF8ToUCS2StringLen(iconnection->nick, iconnection->nick_W, GP_NICK_LEN); + UTF8ToUCS2StringLen(iconnection->uniquenick, iconnection->uniquenick_W, GP_UNIQUENICK_LEN); + UTF8ToUCS2StringLen(iconnection->email, iconnection->email_W, GP_EMAIL_LEN); + UTF8ToUCS2StringLen(iconnection->password, iconnection->password_W, GP_PASSWORD_LEN); +#endif + + // Lowercase the email. + /////////////////////// + _strlwr(iconnection->email); + +#ifdef GSI_UNICODE + // Update the UCS2 version (emails are ASCII anyhow so lowercasing didn't data) + AsciiToUCS2String(iconnection->email, iconnection->email_W); +#endif + + // Create a connect operation data struct. + ////////////////////////////////////////// + data = (GPIConnectData *)gsimalloc(sizeof(GPIConnectData)); + if(data == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(data, 0, sizeof(GPIConnectData)); + + // Check for new user. + ////////////////////// + data->newuser = newuser; + + // Store pre-auth data. + /////////////////////// + if(authtoken[0] && partnerchallenge[0]) + { + strzcpy(data->authtoken, authtoken, GP_AUTHTOKEN_LEN); + strzcpy(data->partnerchallenge, partnerchallenge, GP_PARTNERCHALLENGE_LEN); + } + + // Store cdkey if we have one. + ////////////////////////////// + if(cdkey) + strzcpy(data->cdkey, cdkey, GP_CDKEY_LEN); + + // Add the operation to the list. + ///////////////////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_CONNECT, data, &operation, blocking, callback, param)); + + // Start it. + //////////// + result = gpiStartConnect(connection, operation); + if(result != GP_NO_ERROR) + { + operation->result = result; + gpiFailedOpCallback(connection, operation); + gpiDisconnect(connection, GPIFalse); + return result; + } + + // Process it if blocking. + ////////////////////////// + if(operation->blocking) + CHECK_RESULT(gpiProcess(connection, operation->id)); + + return GP_NO_ERROR; +} + +static GPResult +gpiSendLogin( + GPConnection * connection, + GPIConnectData * data +) +{ + char buffer[512]; + char response[33]; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfile * profile; + char * passphrase; + char userBuffer[GP_NICK_LEN + GP_EMAIL_LEN]; + char partnerBuffer[11]; + char * user; + + // Construct the user challenge. + //////////////////////////////// + randomString(data->userChallenge, sizeof(data->userChallenge) - 1); + + // Hash the password. + ///////////////////// + if(data->partnerchallenge[0]) + passphrase = data->partnerchallenge; + else + passphrase = iconnection->password; + MD5Digest((unsigned char*)passphrase, strlen(passphrase), data->passwordHash); + + // Construct the user. + ////////////////////// + if(iconnection->partnerID != GP_PARTNERID_GAMESPY) + { + sprintf(partnerBuffer, "%d@", iconnection->partnerID); + } + else + { + // GS ID's do not stash the partner ID in the auth challenge to support legacy clients. + strcpy(partnerBuffer, ""); + } + + if(data->authtoken[0]) + user = data->authtoken; + else if(iconnection->uniquenick[0]) + { + sprintf(userBuffer, "%s%s", partnerBuffer, iconnection->uniquenick); + user = userBuffer; + } + else + { + sprintf(userBuffer, "%s%s@%s", partnerBuffer, iconnection->nick, iconnection->email); + user = userBuffer; + } + + // Construct the response. + ////////////////////////// + sprintf(buffer, "%s%s%s%s%s%s", + data->passwordHash, + " ", + user, + data->userChallenge, + data->serverChallenge, + data->passwordHash); + MD5Digest((unsigned char *)buffer, strlen(buffer), response); + + // Check for an existing profile. + ///////////////////////////////// + if(iconnection->infoCaching) + { + gpiFindProfileByUser(connection, iconnection->nick, iconnection->email, &profile); + if(profile != NULL) + { + // Get the userid and profileid. + //////////////////////////////// + iconnection->userid = profile->userId; + iconnection->profileid = profile->profileId; + } + } + + // Construct the outgoing message. + ////////////////////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\login\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\challenge\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, data->userChallenge); + if(data->authtoken[0]) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\authtoken\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, data->authtoken); + } + else if(iconnection->uniquenick[0]) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\uniquenick\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->uniquenick); + } + else + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\user\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->nick); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "@"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->email); + } + if(iconnection->userid != 0) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\userid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->userid); + } + if(iconnection->profileid != 0) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->profileid); + } + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->partnerID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\response\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, response); + if(iconnection->firewall == GP_FIREWALL) + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\firewall\\1"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\port\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->peerPort); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\productid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->productID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\gamename\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, __GSIACGamename); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->namespaceID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sdkrevision\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, GPI_SDKREV); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\quiet\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->quietModeFlags); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\1"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +static GPResult +gpiSendNewuser( + GPConnection * connection, + GPIConnectData * data +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + size_t i; + const int useAlternateEncoding = 1; + + // Encrypt the password (xor with random values) + char passwordenc[GP_PASSWORDENC_LEN]; + gpiEncodeString(iconnection->password, passwordenc); + + // Construct the outgoing message. + ////////////////////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\newuser\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\email\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->email); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\nick\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->nick); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\passwordenc\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, passwordenc); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\productid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->productID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\gamename\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, __GSIACGamename); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->namespaceID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\uniquenick\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->uniquenick); + if(data->cdkey[0]) + { + // Encrypt the cdkey (xor with random values) + char cdkeyxor[GP_CDKEY_LEN]; + char cdkeyenc[GP_CDKEYENC_LEN]; + size_t cdkeylen = strlen(data->cdkey); + + Util_RandSeed((unsigned long)GP_XOR_SEED); + for (i=0; i < cdkeylen; i++) + { + // XOR each character with the next rand + char aRand = (char)Util_RandInt(0, 0xFF); + cdkeyxor[i] = (char)(data->cdkey[i] ^ aRand); + } + cdkeyxor[i] = '\0'; + + // Base 64 it (printable chars only) + B64Encode(cdkeyxor, cdkeyenc, (int)cdkeylen, useAlternateEncoding); + + //gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\cdkey\\"); + //gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, data->cdkey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\cdkeyenc\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, cdkeyenc); + } + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->partnerID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\1"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult +gpiProcessConnect( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + char buffer[512]; + char check[33]; + char uniquenick[GP_UNIQUENICK_LEN]; + GPIConnectData * data; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPICallback callback; + GPIProfile * profile; + char userBuffer[GP_NICK_LEN + GP_EMAIL_LEN]; + char partnerBuffer[11]; + char * user; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPIFalse)) + { + // Is this a deleted profile? + ///////////////////////////// + if((iconnection->errorCode == GP_LOGIN_PROFILE_DELETED) && iconnection->profileid) + { + // Remove this profile object. + ////////////////////////////// + gpiRemoveProfileByID(connection, iconnection->profileid); + + // If we have the profileid/userid cached, lose them. + ///////////////////////////////////////////////////// + iconnection->userid = 0; + iconnection->profileid = 0; + } + // Check for creating an existing profile. + ////////////////////////////////////////// + else if(iconnection->errorCode == GP_NEWUSER_BAD_NICK) + { + // Store the pid. + ///////////////// + if(gpiValueForKey(input, "\\pid\\", buffer, sizeof(buffer))) + iconnection->profileid = atoi(buffer); + } + + // Call the callbacks. + ////////////////////// + CallbackFatalError(connection, GP_SERVER_ERROR, iconnection->errorCode, iconnection->errorString); + } + + // Get a pointer to the data. + ///////////////////////////// + data = (GPIConnectData*)operation->data; + + switch(operation->state) + { + case GPI_CONNECTING: + // This should be \lc\1. + //////////////////////// + if(strncmp(input, "\\lc\\1", 5) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the server challenge. + //////////////////////////// + if(!gpiValueForKey(input, "\\challenge\\", data->serverChallenge, sizeof(data->serverChallenge))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Check if this is a new user. + /////////////////////////////// + if(data->newuser) + { + // Send a new user message. + /////////////////////////// + CHECK_RESULT(gpiSendNewuser(connection, data)); + + // Update the operation's state. + //////////////////////////////// + operation->state = GPI_REQUESTING; + } + else + { + // Send a login message. + //////////////////////// + CHECK_RESULT(gpiSendLogin(connection, data)); + + // Update the operation's state. + //////////////////////////////// + operation->state = GPI_LOGIN; + } + + break; + + case GPI_REQUESTING: + // This should be \nur\. + //////////////////////// + if(strncmp(input, "\\nur\\", 5) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the userid. + ////////////////// + if(!gpiValueForKey(input, "\\userid\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexepected data was received from the server."); + iconnection->userid = atoi(buffer); + + // Get the profileid. + ///////////////////// + if(!gpiValueForKey(input, "\\profileid\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexepected data was received from the server."); + iconnection->profileid = atoi(buffer); + + // Send a login request. + //////////////////////// + CHECK_RESULT(gpiSendLogin(connection, data)); + + // Update the operation's state. + //////////////////////////////// + operation->state = GPI_LOGIN; + + break; + + case GPI_LOGIN: + // This should be \lc\2. + //////////////////////// + if(strncmp(input, "\\lc\\2", 5) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the sesskey. + /////////////////// + if(!gpiValueForKey(input, "\\sesskey\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexepected data was received from the server."); + iconnection->sessKey = atoi(buffer); + + // Get the userid. + ////////////////// + if(!gpiValueForKey(input, "\\userid\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexepected data was received from the server."); + iconnection->userid = atoi(buffer); + + // Get the profileid. + ///////////////////// + if(!gpiValueForKey(input, "\\profileid\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexepected data was received from the server."); + iconnection->profileid = atoi(buffer); + + // Get the uniquenick. + ////////////////////// + if(!gpiValueForKey(input, "\\uniquenick\\", uniquenick, sizeof(uniquenick))) + uniquenick[0] = '\0'; + + // Get the loginticket. + ////////////////////// + if(!gpiValueForKey(input, "\\lt\\", iconnection->loginTicket, sizeof(iconnection->loginTicket))) + iconnection->loginTicket[0] = '\0'; + + + // Construct the user. + ////////////////////// + if(iconnection->partnerID != GP_PARTNERID_GAMESPY) + { + sprintf(partnerBuffer, "%d@", iconnection->partnerID); + } + else + { + // GS ID's do not stash the partner ID in the auth challenge to support legacy clients. + strcpy(partnerBuffer, ""); + } + + if(data->authtoken[0]) + user = data->authtoken; + else if(iconnection->uniquenick[0]) + { + sprintf(userBuffer, "%s%s", partnerBuffer, iconnection->uniquenick); + user = userBuffer; + } + else + { + sprintf(userBuffer, "%s%s@%s", partnerBuffer, iconnection->nick, iconnection->email); + user = userBuffer; + } + + // Construct the check. + /////////////////////// + sprintf(buffer, "%s%s%s%s%s%s", + data->passwordHash, + " ", + user, + data->serverChallenge, + data->userChallenge, + data->passwordHash); + MD5Digest((unsigned char *)buffer, strlen(buffer), check); + + // Get the proof. + ///////////////// + if(!gpiValueForKey(input, "\\proof\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexepected data was received from the server."); + + // Check the server authentication. + /////////////////////////////////// + if(memcmp(check, buffer, 32) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_LOGIN_SERVER_AUTH_FAILED, "Could not authenticate server."); + + // Add the local profile to the list. + ///////////////////////////////////// + if(iconnection->infoCaching) + { + profile = gpiProfileListAdd(connection, iconnection->profileid); + profile->profileId = iconnection->profileid; + profile->userId = iconnection->userid; + } + + // Set the connect state. + ///////////////////////// + iconnection->connectState = GPI_CONNECTED; + + // Call the connect-response callback. + ////////////////////////////////////// + callback = operation->callback; + if(callback.callback != NULL) + { + GPConnectResponseArg * arg; + arg = (GPConnectResponseArg *)gsimalloc(sizeof(GPConnectResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPConnectResponseArg)); + + arg->profile = (GPProfile)iconnection->profileid; + arg->result = GP_NO_ERROR; +#ifndef GSI_UNICODE + strzcpy(arg->uniquenick, uniquenick, GP_UNIQUENICK_LEN); +#else + UTF8ToUCS2StringLen(uniquenick, arg->uniquenick, GP_UNIQUENICK_LEN); +#endif + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + + // This operation is complete. + ////////////////////////////// + gpiRemoveOperation(connection, operation); + + // Get the local profile's info. + //////////////////////////////// +#if 0 + gpiAddOperation(connection, GPI_GET_INFO, NULL, &operation, GP_NON_BLOCKING, NULL, NULL); + gpiSendGetInfo(connection, iconnection->profileid, operation->id); +#endif + + +#ifdef _PS3 + // We just connected, so setup buddy sync && start NP init + // For future, we can limit syncs by setting flags to turn on/off here + ////////////////////////////////////////////////////////////////////// + iconnection->npPerformBuddySync = gsi_true; + iconnection->npPerformBlockSync = gsi_true; + iconnection->loginTime = current_time(); + + if (!iconnection->npInitialized) + gpiInitializeNpBasic(connection); +#endif + + break; + + default: + break; + } + + return GP_NO_ERROR; +} + +GPResult +gpiCheckConnect( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int state; + + // Check if the connection is completed. + //////////////////////////////////////// + CHECK_RESULT(gpiCheckSocketConnect(connection, iconnection->cmSocket, &state)); + + // Check for a failed attempt. + ////////////////////////////// + if(state == GPI_DISCONNECTED) + CallbackFatalError(connection, GP_SERVER_ERROR, GP_LOGIN_CONNECTION_FAILED, "The server has refused the connection."); + + // Check if not finished connecting. + //////////////////////////////////// + if(state == GPI_NOT_CONNECTED) + return GP_NO_ERROR; + + // We're now negotiating the connection. + //////////////////////////////////////// + assert(state == GPI_CONNECTED); + iconnection->connectState = GPI_NEGOTIATING; + + return GP_NO_ERROR; +} + +static GPIBool +gpiDisconnectCleanupProfile( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GSI_UNUSED(data); + + // Even if we cache buddy/block info, free it up to get rid of mem + // leaks, just don't remove the profile until we save the cache. + ////////////////////////////////////////////////////////////////// + if(profile->buddyStatus) + { + profile->buddyOrBlockCache = gsi_true; + freeclear(profile->buddyStatus->statusString); + freeclear(profile->buddyStatus->locationString); + freeclear(profile->buddyStatus); + } + if (profile->buddyStatusInfo) + { + profile->buddyOrBlockCache = gsi_true; + freeclear(profile->buddyStatusInfo->richStatus); + freeclear(profile->buddyStatusInfo->gameType); + freeclear(profile->buddyStatusInfo->gameVariant); + freeclear(profile->buddyStatusInfo->gameMapName); + if (profile->buddyStatusInfo->extendedInfoKeys) + { + ArrayFree(profile->buddyStatusInfo->extendedInfoKeys); + profile->buddyStatusInfo->extendedInfoKeys = NULL; + } + freeclear(profile->buddyStatusInfo); + } + if (profile->blocked) + profile->buddyOrBlockCache = gsi_true; + + freeclear(profile->authSig); + freeclear(profile->peerSig); + profile->requestCount = 0; + + // Remove Profile if: + // (there is no info to cache) or + // (we only cache buddies/blocked and the user is not a buddy or a block) + if ((!profile->cache) || + (iconnection->infoCachingBuddyAndBlockOnly==GPITrue && !profile->buddyOrBlockCache)) + { + gpiRemoveProfile(connection, profile); + return GPIFalse; + } + + return GPITrue; +} + +void +gpiDisconnect( + GPConnection * connection, + GPIBool tellServer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIPeer * peer; + GPIPeer * delPeer; + GPIBool connClosed; + + // Check if we're already disconnected. + // PANTS|05.15.00 + /////////////////////////////////////// + if(iconnection->connectState == GPI_DISCONNECTED) + return; + + // Skip most of this stuff if we never actually connected. + // PANTS|05.16.00 + ////////////////////////////////////////////////////////// + if(iconnection->connectState != GPI_NOT_CONNECTED) + { + // Are we connected? + //////////////////// + if(tellServer && (iconnection->connectState == GPI_CONNECTED)) + { + // Send the disconnect. + /////////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\logout\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + } + + // Always flush remaining messages. + // PANTS|05.16.00 + /////////////////////////////////// + gpiSendFromBuffer(connection, iconnection->cmSocket, &iconnection->outputBuffer, &connClosed, GPITrue, "CM"); + + // Cleanup the connection. + ////////////////////////// + if(iconnection->cmSocket != INVALID_SOCKET) + { + shutdown(iconnection->cmSocket, 2); + closesocket(iconnection->cmSocket); + iconnection->cmSocket = INVALID_SOCKET; + } + + if(/*iconnection->peerSocket != INVALID_SOCKET*/ gsUdpEngineIsInitialized()) + { + //shutdown(iconnection->peerSocket, 2); + //closesocket(iconnection->peerSocket); + //iconnection->peerSocket = INVALID_SOCKET; + gsUdpEngineRemoveMsgHandler(iconnection->mHeader); + if (gsUdpEngineNoMoreMsgHandlers() && gsUdpEngineNoApp()) + gsUdpEngineShutdown(); + } + + // We're disconnected. + ////////////////////// + iconnection->connectState = GPI_DISCONNECTED; + + // Don't keep the userid/profileid. + /////////////////////////////////// + iconnection->userid = 0; + iconnection->profileid = 0; + } + + // freeclear all the memory. + /////////////////////// + freeclear(iconnection->socketBuffer.buffer); + freeclear(iconnection->inputBuffer); + freeclear(iconnection->outputBuffer.buffer); + freeclear(iconnection->updateproBuffer.buffer); + freeclear(iconnection->updateuiBuffer.buffer); + while(iconnection->operationList != NULL) + gpiRemoveOperation(connection, iconnection->operationList); + iconnection->operationList = NULL; + for(peer = iconnection->peerList ; peer != NULL ; ) + { + delPeer = peer; + peer = peer->pnext; + gpiDestroyPeer(connection, delPeer); + } + iconnection->peerList = NULL; + + // Cleanup buddies. + // This is not optimal - because we can't continue the mapping + // after freeing a profile, we need to start it all over again. + /////////////////////////////////////////////////////////////// + while(!gpiProfileMap(connection, gpiDisconnectCleanupProfile, NULL)) { }; +} diff --git a/xrGameSpy/gamespy/GP/gpiConnect.h b/xrGameSpy/gamespy/GP/gpiConnect.h new file mode 100644 index 00000000000..b9910bf062f --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiConnect.h @@ -0,0 +1,69 @@ +/* +gpiConnect.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPICONNECT_H_ +#define _GPICONNECT_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +// Connect States. +////////////////// +#define GPI_NOT_CONNECTED 0 +#define GPI_CONNECTING 1 +#define GPI_NEGOTIATING 2 +#define GPI_CONNECTED 3 +#define GPI_DISCONNECTED 4 +#define GPI_PROFILE_DELETING 5 + +//FUNCTIONS +/////////// +GPResult +gpiConnect( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + const char authtoken[GP_AUTHTOKEN_LEN], + const char partnerchallenge[GP_PARTNERCHALLENGE_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum firewall, + GPIBool newuser, + GPEnum blocking, + GPCallback callback, + void * param +); + +void +gpiDisconnect( + GPConnection * connection, + GPIBool tellServer +); + +GPResult +gpiProcessConnect( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +GPResult +gpiCheckConnect( + GPConnection * connection +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiInfo.c b/xrGameSpy/gamespy/GP/gpiInfo.c new file mode 100644 index 00000000000..60ae65f00a8 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiInfo.c @@ -0,0 +1,1286 @@ +/* +gpiInfo.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include "gpi.h" + +//FUNCTIONS +/////////// +static GPIBool +gpiIsValidDate( + int day, + int month, + int year +) +{ + // Check for a blank. + ///////////////////// + if((day == 0) && (month == 0) && (year == 0)) + return GPITrue; + + // Check for negatives. + /////////////////////// + if((day < 0) || (month < 0) || (year < 0)) + return GPIFalse; + + // Validate the day of the month. + ///////////////////////////////// + switch(month) + { + // No month. + //////////// + case 0: + // Can't specify a day without a month. + /////////////////////////////////////// + if(day != 0) + return GPIFalse; + break; + + // 31-day month. + //////////////// + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + if(day > 31) + return GPIFalse; + break; + + // 30-day month. + //////////////// + case 4: + case 6: + case 9: + case 11: + if(day > 30) + return GPIFalse; + break; + + // 28/29-day month. + /////////////////// + case 2: + // Leap year? + ///////////// + if((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)) + { + if(day > 29) + return GPIFalse; + } + else + { + if(day > 28) + return GPIFalse; + } + break; + + // Invalid month. + ///////////////// + default: + return GPIFalse; + } + + // Check that the date is in the valid range. + // 01.01.1900 - 06.06.2079 + // PANTS|02.14.2000 + ///////////////////////////////////////////// + if(year < 1900) + return GPIFalse; + if(year > 2079) + return GPIFalse; + if(year == 2079) + { + if(month > 6) + return GPIFalse; + if((month == 6) && (day > 6)) + return GPIFalse; + } + + return GPITrue; +} + +static GPResult +gpiDateToInt( + GPConnection * connection, + int * date, + int day, + int month, + int year +) +{ + int temp; + + // Pack the day/month/year into an int. + // 31-22: day + // 23-16: month + // 15-00: year + /////////////////////////////////////// + + // Error check. + /////////////// + assert(gpiIsValidDate(day, month, year)); + if(!gpiIsValidDate(day, month, year)) + Error(connection, GP_PARAMETER_ERROR, "Invalid date."); + + // Pack! + //////// + temp = 0; + temp |= (day << 24); + temp |= (month << 16); + temp |= year; + + // Set it. + ////////// + *date = temp; + + return GP_NO_ERROR; +} + +static GPResult +gpiIntToDate( + GPConnection * connection, + int date, + int * day, + int * month, + int * year +) +{ + int d; + int m; + int y; + + // Unpack the int into a day/month/year. + // 31-22: day + // 23-16: month + // 15-00: year + //////////////////////////////////////// + + // Split up the date. + ///////////////////// + d = ((date >> 24) & 0xFF); + m = ((date >> 16) & 0xFF); + y = (date & 0xFFFF); + + // Error check. + /////////////// + assert(gpiIsValidDate(d, m, y)); + if(!gpiIsValidDate(d, m, y)) + Error(connection, GP_PARAMETER_ERROR, "Invalid date."); + + // It's all good. + ///////////////// + *day = d; + *month = m; + *year = y; + + return GP_NO_ERROR; +} + +void +gpiInfoCacheToArg( + const GPIInfoCache * cache, + GPGetInfoResponseArg * arg +) +{ +#ifndef GSI_UNICODE + // Copy.... + /////////// + if(cache->nick) + strzcpy(arg->nick, cache->nick, GP_NICK_LEN); + else + arg->nick[0] = '\0'; + if(cache->uniquenick) + strzcpy(arg->uniquenick, cache->uniquenick, GP_UNIQUENICK_LEN); + else + arg->uniquenick[0] = '\0'; + if(cache->email) + strzcpy(arg->email, cache->email, GP_EMAIL_LEN); + else + arg->email[0] = '\0'; + if(cache->firstname) + strzcpy(arg->firstname, cache->firstname, GP_FIRSTNAME_LEN); + else + arg->firstname[0] = '\0'; + if(cache->lastname) + strzcpy(arg->lastname, cache->lastname, GP_LASTNAME_LEN); + else + arg->lastname[0] = '\0'; + if(cache->homepage) + strzcpy(arg->homepage, cache->homepage, GP_HOMEPAGE_LEN); + else + arg->homepage[0] = '\0'; + arg->icquin = cache->icquin; + strzcpy(arg->zipcode, cache->zipcode, GP_ZIPCODE_LEN); + strzcpy(arg->countrycode, cache->countrycode, GP_COUNTRYCODE_LEN); + arg->longitude = cache->longitude; + arg->latitude = cache->latitude; + if(cache->place) + strzcpy(arg->place, cache->place, GP_PLACE_LEN); + else + arg->place[0] = '\0'; + arg->birthday = cache->birthday; + arg->birthmonth = cache->birthmonth; + arg->birthyear = cache->birthyear; + arg->sex = (GPEnum)cache->sex; + arg->publicmask = (GPEnum)cache->publicmask; + if(cache->aimname) + strzcpy(arg->aimname, cache->aimname, GP_AIMNAME_LEN); + else + arg->aimname[0] = '\0'; +#else + // Copy.... + /////////// + if(cache->nick) + UTF8ToUCS2StringLen(cache->nick, arg->nick, GP_NICK_LEN); + else + arg->nick[0] = '\0'; + if(cache->uniquenick) + UTF8ToUCS2StringLen(cache->uniquenick, arg->uniquenick, GP_UNIQUENICK_LEN); + else + arg->uniquenick[0] = '\0'; + if(cache->email) + UTF8ToUCS2StringLen(cache->email, arg->email, GP_EMAIL_LEN); + else + arg->email[0] = '\0'; + if(cache->firstname) + UTF8ToUCS2StringLen(cache->firstname, arg->firstname, GP_FIRSTNAME_LEN); + else + arg->firstname[0] = '\0'; + if(cache->lastname) + UTF8ToUCS2StringLen(cache->lastname, arg->lastname, GP_LASTNAME_LEN); + else + arg->lastname[0] = '\0'; + if(cache->homepage) + UTF8ToUCS2StringLen(cache->homepage, arg->homepage, GP_HOMEPAGE_LEN); + else + arg->homepage[0] = '\0'; + UTF8ToUCS2StringLen(cache->zipcode, arg->zipcode, GP_ZIPCODE_LEN); + UTF8ToUCS2StringLen(cache->countrycode, arg->countrycode, GP_COUNTRYCODE_LEN); + if(cache->place) + UTF8ToUCS2StringLen(cache->place, arg->place, GP_PLACE_LEN); + else + arg->place[0] = '\0'; + if(cache->aimname) + UTF8ToUCS2StringLen(cache->aimname, arg->aimname, GP_AIMNAME_LEN); + else + arg->aimname[0] = '\0'; +#endif + + // Non string members + arg->icquin = cache->icquin; + arg->longitude = cache->longitude; + arg->latitude = cache->latitude; + + arg->birthday = cache->birthday; + arg->birthmonth = cache->birthmonth; + arg->birthyear = cache->birthyear; + arg->sex = (GPEnum)cache->sex; + arg->publicmask = (GPEnum)cache->publicmask; + + arg->pic = cache->pic; + arg->occupationid = cache->occupationid; + arg->industryid = cache->industryid; + arg->incomeid = cache->incomeid; + arg->marriedid = cache->marriedid; + arg->childcount = cache->childcount; + arg->interests1 = cache->interests1; + arg->ownership1 = cache->ownership1; + arg->conntypeid = cache->conntypeid; +} + +GPResult +gpiProcessGetInfo( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + GPIInfoCache infoCache; + char buffer[64]; + int profileid; + GPIProfile * profile; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPICallback callback; + GPIPeer * peer; + char nick[GP_NICK_LEN]; + char uniquenick[GP_UNIQUENICK_LEN]; + char email[GP_EMAIL_LEN]; + char firstname[GP_FIRSTNAME_LEN]; + char lastname[GP_LASTNAME_LEN]; + char homepage[GP_HOMEPAGE_LEN]; + char aimname[GP_AIMNAME_LEN]; + GPIBool saveSig; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // This should be \pi\. + /////////////////////// + if(strncmp(input, "\\pi\\", 4) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the profile id. + ////////////////////// + if(!gpiValueForKey(input, "\\profileid\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + profileid = atoi(buffer); + assert(profileid > 0); + + // Get the profile - we might not have a profile object. + //////////////////////////////////////////////////////// + gpiGetProfile(connection, (GPProfile)profileid, &profile); + + // Setup the info cache. + //////////////////////// + memset(&infoCache, 0, sizeof(GPIInfoCache)); + infoCache.nick = nick; + infoCache.uniquenick = uniquenick; + infoCache.email = email; + infoCache.firstname = firstname; + infoCache.lastname = lastname; + infoCache.homepage = homepage; + infoCache.aimname = aimname; + + // Parse the info. + ////////////////// + if(!gpiValueForKey(input, "\\nick\\", infoCache.nick, GP_NICK_LEN)) + infoCache.nick[0] = '\0'; + if(!gpiValueForKey(input, "\\uniquenick\\", infoCache.uniquenick, GP_UNIQUENICK_LEN)) + infoCache.uniquenick[0] = '\0'; + if(!gpiValueForKey(input, "\\email\\", infoCache.email, GP_EMAIL_LEN)) + infoCache.email[0] = '\0'; + if(!gpiValueForKey(input, "\\firstname\\", infoCache.firstname, GP_FIRSTNAME_LEN)) + infoCache.firstname[0] = '\0'; + if(!gpiValueForKey(input, "\\lastname\\", infoCache.lastname, GP_LASTNAME_LEN)) + infoCache.lastname[0] = '\0'; + if(!gpiValueForKey(input, "\\icquin\\", buffer, sizeof(buffer))) + infoCache.icquin = -1; + else + infoCache.icquin = atoi(buffer); + if(!gpiValueForKey(input, "\\homepage\\", infoCache.homepage, GP_HOMEPAGE_LEN)) + infoCache.homepage[0] = '\0'; + if(!gpiValueForKey(input, "\\zipcode\\", infoCache.zipcode, sizeof(infoCache.zipcode))) + infoCache.zipcode[0] = '\0'; + if(!gpiValueForKey(input, "\\countrycode\\", infoCache.countrycode, sizeof(infoCache.countrycode))) + infoCache.countrycode[0] = '\0'; + if(!gpiValueForKey(input, "\\lon\\", buffer, sizeof(buffer))) + infoCache.longitude = 0; + else + infoCache.longitude = (float)atof(buffer); + if(!gpiValueForKey(input, "\\lat\\", buffer, sizeof(buffer))) + infoCache.latitude = 0; + else + infoCache.latitude = (float)atof(buffer); + if(!gpiValueForKey(input, "\\loc\\", infoCache.place, GP_PLACE_LEN)) + infoCache.place[0] = '\0'; + if(!gpiValueForKey(input, "\\birthday\\", buffer, sizeof(buffer))) + { + infoCache.birthday = 0; + infoCache.birthmonth = 0; + infoCache.birthyear = 0; + } + else + { + CHECK_RESULT(gpiIntToDate(connection, atoi(buffer), &infoCache.birthday, &infoCache.birthmonth, &infoCache.birthyear)); + } + if(!gpiValueForKey(input, "\\sex\\", buffer, sizeof(buffer))) + infoCache.sex = GP_PAT; + else if(buffer[0] == '0') + infoCache.sex = GP_MALE; + else if(buffer[0] == '1') + infoCache.sex = GP_FEMALE; + else + infoCache.sex = GP_PAT; + if(!gpiValueForKey(input, "\\pmask\\", buffer, sizeof(buffer))) + infoCache.publicmask = 0xFFFFFFFF; + else + infoCache.publicmask = atoi(buffer); + if(!gpiValueForKey(input, "\\aim\\", infoCache.aimname, GP_AIMNAME_LEN)) + infoCache.aimname[0] = '\0'; + if(!gpiValueForKey(input, "\\pic\\", buffer, sizeof(buffer))) + infoCache.pic = 0; + else + infoCache.pic = atoi(buffer); + if(!gpiValueForKey(input, "\\occ\\", buffer, sizeof(buffer))) + infoCache.occupationid = 0; + else + infoCache.occupationid = atoi(buffer); + if(!gpiValueForKey(input, "\\ind\\", buffer, sizeof(buffer))) + infoCache.industryid = 0; + else + infoCache.industryid = atoi(buffer); + if(!gpiValueForKey(input, "\\inc\\", buffer, sizeof(buffer))) + infoCache.incomeid = 0; + else + infoCache.incomeid = atoi(buffer); + if(!gpiValueForKey(input, "\\mar\\", buffer, sizeof(buffer))) + infoCache.marriedid = 0; + else + infoCache.marriedid = atoi(buffer); + if(!gpiValueForKey(input, "\\chc\\", buffer, sizeof(buffer))) + infoCache.childcount = 0; + else + infoCache.childcount = atoi(buffer); + if(!gpiValueForKey(input, "\\i1\\", buffer, sizeof(buffer))) + infoCache.interests1 = 0; + else + infoCache.interests1 = atoi(buffer); + if(!gpiValueForKey(input, "\\o1\\", buffer, sizeof(buffer))) + infoCache.ownership1 = 0; + else + infoCache.ownership1 = atoi(buffer); + if(!gpiValueForKey(input, "\\conn\\", buffer, sizeof(buffer))) + infoCache.conntypeid = 0; + else + infoCache.conntypeid = atoi(buffer); + + // Get the peer sig. + //////////////////// + if(!gpiValueForKey(input, "\\sig\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + saveSig = iconnection->infoCaching; + + // Is there a pending peer connection looking for a sig? + //////////////////////////////////////////////////////// + for(peer = iconnection->peerList ; peer != NULL ; peer = peer->pnext) + { + // Is it the same profile? + ////////////////////////// + if(peer->profile == profileid) + { + // Is it getting the sig? + ///////////////////////// + if(peer->state == GPI_PEER_GETTING_SIG) + { + // We need to make sure there's an actual profile object. + ///////////////////////////////////////////////////////// + if(!profile) + profile = gpiProfileListAdd(connection, profileid); + + // It got it. + ///////////// + peer->state = GPI_PEER_GOT_SIG; + + saveSig = GPITrue; + } + } + } + + // Cache info? + ////////////// + if(!profile && iconnection->infoCaching) + profile = gpiProfileListAdd(connection, profileid); + + // Set the peer sig. + //////////////////// + if(saveSig) + { + freeclear(profile->peerSig); + profile->peerSig = goastrdup(buffer); + } + + // Caching info? + //////////////// + if(iconnection->infoCaching) + gpiSetInfoCache(connection, profile, &infoCache); + + // Call the callback. + ///////////////////// + callback = operation->callback; + if(callback.callback != NULL) + { + GPGetInfoResponseArg * arg; + arg = (GPGetInfoResponseArg *)gsimalloc(sizeof(GPGetInfoResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + gpiInfoCacheToArg(&infoCache, arg); + arg->result = GP_NO_ERROR; + arg->profile = (GPProfile)profileid; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + + // This operation is complete. + ////////////////////////////// + gpiRemoveOperation(connection, operation); + + return GP_NO_ERROR; +} + +GPResult +gpiAddLocalInfo( + GPConnection * connection, + GPIBuffer * buffer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Add updatepro info. + ////////////////////// + if(iconnection->updateproBuffer.len > 0) + { + gpiAppendStringToBuffer(connection, buffer, "\\updatepro\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, buffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, buffer, iconnection->updateproBuffer.buffer); + gpiAppendStringToBuffer(connection, buffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, buffer, iconnection->partnerID); + gpiAppendStringToBuffer(connection, buffer, "\\final\\"); + + iconnection->updateproBuffer.len = 0; + } + + // Add updateui info. + ////////////////////// + if(iconnection->updateuiBuffer.len > 0) + { + gpiAppendStringToBuffer(connection, buffer, "\\updateui\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, buffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, buffer, iconnection->updateuiBuffer.buffer); + gpiAppendStringToBuffer(connection, buffer, "\\final\\"); + + iconnection->updateuiBuffer.len = 0; + } + + return GP_NO_ERROR; +} + +static GPResult +gpiSendLocalInfo( + GPConnection * connection, + const char * info, + const char * value +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + CHECK_RESULT(gpiAppendStringToBuffer(connection, &iconnection->updateproBuffer, info)); + CHECK_RESULT(gpiAppendStringToBuffer(connection, &iconnection->updateproBuffer, value)); + + return GP_NO_ERROR; +} + +static GPResult +gpiSendUserInfo( + GPConnection * connection, + const char * info, + const char * value +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + CHECK_RESULT(gpiAppendStringToBuffer(connection, &iconnection->updateuiBuffer, info)); + CHECK_RESULT(gpiAppendStringToBuffer(connection, &iconnection->updateuiBuffer, value)); + + return GP_NO_ERROR; +} + +GPResult +gpiSetInfoi( + GPConnection * connection, + GPEnum info, + int value +) +{ + char intValue[16]; + + // Check the info param. + //////////////////////// + switch(info) + { + case GP_ZIPCODE: + // Error check. + /////////////// + if(value < 0) + Error(connection, GP_PARAMETER_ERROR, "Invalid zipcode."); + + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\zipcode\\", intValue)); + + break; + + case GP_SEX: + // Check the sex type. + ////////////////////// + switch(value) + { + case GP_MALE: + CHECK_RESULT(gpiSendLocalInfo(connection, "\\sex\\", "0")); + break; + + case GP_FEMALE: + CHECK_RESULT(gpiSendLocalInfo(connection, "\\sex\\", "1")); + break; + + case GP_PAT: + CHECK_RESULT(gpiSendLocalInfo(connection, "\\sex\\", "2")); + break; + + default: + Error(connection, GP_PARAMETER_ERROR, "Invalid sex."); + } + + break; + + case GP_ICQUIN: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\icquin\\", intValue)); + + break; + + case GP_CPUBRANDID: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\cpubrandid\\", intValue)); + + break; + + case GP_CPUSPEED: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\cpuspeed\\", intValue)); + + break; + + case GP_MEMORY: + // Divide by 16. + //////////////// + value /= 16; + + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\memory\\", intValue)); + + break; + + case GP_VIDEOCARD1RAM: + // Divide by 4. + /////////////// + value /= 4; + + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\videocard1ram\\", intValue)); + + break; + + case GP_VIDEOCARD2RAM: + // Divide by 4. + /////////////// + value /= 4; + + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\videocard2ram\\", intValue)); + + break; + + case GP_CONNECTIONID: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\connectionid\\", intValue)); + + break; + + case GP_CONNECTIONSPEED: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\connectionspeed\\", intValue)); + + break; + + case GP_HASNETWORK: + // A boolean. + ///////////// + if(value) + value = 1; + + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendUserInfo(connection, "\\hasnetwork\\", intValue)); + + break; + + case GP_PIC: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\pic\\", intValue)); + + break; + + case GP_OCCUPATIONID: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\occ\\", intValue)); + + break; + + case GP_INDUSTRYID: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\ind\\", intValue)); + + break; + + case GP_INCOMEID: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\inc\\", intValue)); + + break; + + case GP_MARRIEDID: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\mar\\", intValue)); + + break; + + case GP_CHILDCOUNT: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\chc\\", intValue)); + + break; + + case GP_INTERESTS1: + // Convert it to a string. + ////////////////////////// + sprintf(intValue,"%d",value); + + // Send it to the server. + ///////////////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\i1\\", intValue)); + + break; + + default: + Error(connection, GP_PARAMETER_ERROR, "Invalid info."); + } + + return GP_NO_ERROR; +} + +GPResult +gpiSetInfos( + GPConnection * connection, + GPEnum info, + const char * value +) +{ + + GPIConnection * iconnection = (GPIConnection*)*connection; + char buffer[256]; + char sex; + + //password encryption stuff + char passwordenc[GP_PASSWORDENC_LEN]; + + // Error check. + /////////////// + if(value == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid value."); + + // Check the info param. + //////////////////////// + switch(info) + { + case GP_NICK: + if(!value[0]) + Error(connection, GP_PARAMETER_ERROR, "Invalid value."); + strzcpy(buffer, value, GP_NICK_LEN); + strzcpy(iconnection->nick, buffer, GP_NICK_LEN); +#ifdef GSI_UNICODE + UTF8ToUCS2StringLen(iconnection->nick, iconnection->nick_W, GP_NICK_LEN); // update the UCS2 version +#endif + CHECK_RESULT(gpiSendLocalInfo(connection, "\\nick\\", buffer)); + break; + + case GP_UNIQUENICK: + if(!value[0]) + Error(connection, GP_PARAMETER_ERROR, "Invalid value."); + strzcpy(buffer, value, GP_UNIQUENICK_LEN); + strzcpy(iconnection->uniquenick, buffer, GP_UNIQUENICK_LEN); +#ifdef GSI_UNICODE + UTF8ToUCS2StringLen(iconnection->uniquenick, iconnection->uniquenick_W, GP_UNIQUENICK_LEN); +#endif + CHECK_RESULT(gpiSendLocalInfo(connection, "\\uniquenick\\", buffer)); + break; + + case GP_EMAIL: + if(!value[0]) + Error(connection, GP_PARAMETER_ERROR, "Invalid value."); + strzcpy(buffer, value, GP_EMAIL_LEN); + _strlwr(buffer); + strzcpy(iconnection->email, buffer, GP_EMAIL_LEN); +#ifdef GSI_UNICODE + UTF8ToUCS2StringLen(iconnection->email, iconnection->email_W, GP_EMAIL_LEN); +#endif + CHECK_RESULT(gpiSendUserInfo(connection, "\\email\\", buffer)); + break; + + case GP_PASSWORD: + if(!value[0]) + Error(connection, GP_PARAMETER_ERROR, "Invalid value."); + strzcpy(buffer, value, GP_PASSWORD_LEN); + strzcpy(iconnection->password, buffer, GP_PASSWORD_LEN); +#ifdef GSI_UNICODE + UTF8ToUCS2StringLen(iconnection->password, iconnection->password_W, GP_PASSWORD_LEN); +#endif + gpiEncodeString(iconnection->password, passwordenc); + CHECK_RESULT(gpiSendUserInfo(connection, "\\passwordenc\\", passwordenc)); + break; + + case GP_FIRSTNAME: + strzcpy(buffer, value, GP_FIRSTNAME_LEN); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\firstname\\", buffer)); + break; + + case GP_LASTNAME: + strzcpy(buffer, value, GP_LASTNAME_LEN); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\lastname\\", buffer)); + break; + + case GP_HOMEPAGE: + strzcpy(buffer, value, GP_HOMEPAGE_LEN); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\homepage\\", buffer)); + break; + + case GP_ZIPCODE: + strzcpy(buffer, value, GP_ZIPCODE_LEN); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\zipcode\\", buffer)); + break; + + case GP_COUNTRYCODE: + // Error check. + /////////////// + if(strlen(value) != 2) + Error(connection, GP_PARAMETER_ERROR, "Invalid countrycode."); + + strzcpy(buffer, value, GP_COUNTRYCODE_LEN); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\countrycode\\", buffer)); + break; + + case GP_SEX: + sex = (char)toupper(value[0]); + if(sex == 'M') + strcpy(buffer, "0"); + else if(sex == 'F') + strcpy(buffer, "1"); + else + strcpy(buffer, "2"); + + CHECK_RESULT(gpiSendLocalInfo(connection, "\\sex\\", buffer)); + break; + + case GP_ICQUIN: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\icquin\\", buffer)); + break; + + case GP_CPUSPEED: + CHECK_RESULT(gpiSetInfoi(connection, GP_CPUSPEED, atoi(value))); + break; + + case GP_MEMORY: + CHECK_RESULT(gpiSetInfoi(connection, GP_MEMORY, atoi(value))); + break; + + case GP_VIDEOCARD1STRING: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\videocard1string\\", buffer)); + break; + + case GP_VIDEOCARD1RAM: + CHECK_RESULT(gpiSetInfoi(connection, GP_VIDEOCARD1RAM, atoi(value))); + break; + + case GP_VIDEOCARD2STRING: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\videocard2string\\", buffer)); + break; + + case GP_VIDEOCARD2RAM: + CHECK_RESULT(gpiSetInfoi(connection, GP_VIDEOCARD2RAM, atoi(value))); + break; + + case GP_CONNECTIONSPEED: + CHECK_RESULT(gpiSetInfoi(connection, GP_CONNECTIONSPEED, atoi(value))); + break; + + case GP_HASNETWORK: + CHECK_RESULT(gpiSetInfoi(connection, GP_HASNETWORK, atoi(value))); + break; + + case GP_OSSTRING: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\osstring\\", buffer)); + break; + + case GP_AIMNAME: + strzcpy(buffer, value, GP_AIMNAME_LEN); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\aim\\", buffer)); + break; + + case GP_PIC: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\pic\\", buffer)); + break; + + case GP_OCCUPATIONID: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\occ\\", buffer)); + break; + + case GP_INDUSTRYID: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\ind\\", buffer)); + break; + + case GP_INCOMEID: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\inc\\", buffer)); + break; + + case GP_MARRIEDID: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\mar\\", buffer)); + break; + + case GP_CHILDCOUNT: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\chc\\", buffer)); + break; + + case GP_INTERESTS1: + strzcpy(buffer, value, sizeof(buffer)); + CHECK_RESULT(gpiSendLocalInfo(connection, "\\i1\\", buffer)); + break; + + default: + Error(connection, GP_PARAMETER_ERROR, "Invalid info."); + } + + return GP_NO_ERROR; +} + +GPResult +gpiSetInfod( + GPConnection * connection, + GPEnum info, + int day, + int month, + int year +) +{ + int date; + char intValue[16]; + + // Birthday is the only date supported. + /////////////////////////////////////// + if(info != GP_BIRTHDAY) + Error(connection, GP_PARAMETER_ERROR, "Invalid info."); + + // Convert the date into our internal format. + ///////////////////////////////////////////// + CHECK_RESULT(gpiDateToInt(connection, &date, day, month, year)); + + // Convert the int to a string. + /////////////////////////////// + sprintf(intValue,"%d",date); + + // Send the date. + ///////////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\birthday\\", intValue)); + + return GP_NO_ERROR; +} + +GPResult +gpiSetInfoMask( + GPConnection * connection, + GPEnum mask +) +{ + char buffer[16]; + + // Convert the mask to a string. + //////////////////////////////// + sprintf(buffer,"%d",mask); + + // Send it. + /////////// + CHECK_RESULT(gpiSendLocalInfo(connection, "\\publicmask\\", buffer)); + + return GP_NO_ERROR; + +} + +GPResult +gpiSendGetInfo( + GPConnection * connection, + int profileid, + int operationid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\getprofile\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profileid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, operationid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult +gpiGetInfo( + GPConnection * connection, + GPProfile profile, + GPEnum checkCache, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIOperation * operation = NULL; + GPIBool useCache; + GPResult result; + int id; + + // Check checkCache. + //////////////////// + useCache = (checkCache == GP_CHECK_CACHE) ? GPITrue:GPIFalse; + + // Check the info cache state. + ////////////////////////////// + if(!iconnection->infoCaching) + useCache = GPIFalse; + + // Check for using cached info. + /////////////////////////////// + if(callback && useCache && gpiGetProfile(connection, profile, &pProfile) && pProfile->cache) + { + GPICallback gpiCallback; + GPGetInfoResponseArg * arg; + + arg = (GPGetInfoResponseArg *)gsimalloc(sizeof(GPGetInfoResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + gpiInfoCacheToArg(pProfile->cache, arg); + arg->result = GP_NO_ERROR; + arg->profile = profile; + + gpiCallback.callback = callback; + gpiCallback.param = param; + + // Add a dummy operation. + ///////////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_GET_INFO, NULL, &operation, GP_BLOCKING, callback, param)); + id = operation->id; + + // Add the callback. + //////////////////// + CHECK_RESULT(gpiAddCallback(connection, gpiCallback, arg, operation, 0)); + + // Remove the dummy operation. + ////////////////////////////// + gpiRemoveOperation(connection, operation); + } + else + { + // Add the operation. + ///////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_GET_INFO, NULL, &operation, blocking, callback, param)); + id = operation->id; + + // Send a request for info. + /////////////////////////// + result = gpiSendGetInfo(connection, profile, operation->id); + CHECK_RESULT(result); + } + + // Process it if blocking. + ////////////////////////// + if(blocking) + { + result = gpiProcess(connection, id); + CHECK_RESULT(result); + } + + return GP_NO_ERROR; +} + +GPResult +gpiGetInfoNoWait( + GPConnection * connection, + GPProfile profile, + GPGetInfoResponseArg * arg +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Check the info cache state. + ////////////////////////////// + if(!iconnection->infoCaching) + return GP_NETWORK_ERROR; + + // Check to see if we have the info cached. + /////////////////////////////////////////// + if(!gpiGetProfile(connection, profile, &pProfile) || !pProfile->cache) + return GP_NETWORK_ERROR; + + // Fill in the arg. + /////////////////// + gpiInfoCacheToArg(pProfile->cache, arg); + arg->result = GP_NO_ERROR; + arg->profile = profile; + + return GP_NO_ERROR; +} + +GPIBool +gpiSetInfoCache( + GPConnection * connection, + pGPIProfile profile, + const GPIInfoCache * cache +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Check if we're caching info. + /////////////////////////////// + if(!iconnection->infoCaching) + return GPITrue; + + // Free any old cached info. + //////////////////////////// + gpiFreeInfoCache(profile); + + // Allocate the new info. + ///////////////////////// + profile->cache = (GPIInfoCache *)gsimalloc(sizeof(GPIInfoCache)); + + // Copy in the new info. + //////////////////////// + if(profile->cache) + { + *profile->cache = *cache; + profile->cache->nick = goastrdup(cache->nick); + profile->cache->uniquenick = goastrdup(cache->uniquenick); + profile->cache->email = goastrdup(cache->email); + profile->cache->firstname = goastrdup(cache->firstname); + profile->cache->lastname = goastrdup(cache->lastname); + profile->cache->homepage = goastrdup(cache->homepage); + profile->cache->aimname = goastrdup(cache->aimname); + } + + return (profile->cache != NULL) ? GPITrue:GPIFalse; +} + +void +gpiFreeInfoCache( + pGPIProfile profile +) +{ + if(!profile->cache) + return; + + freeclear(profile->cache->nick); + freeclear(profile->cache->uniquenick); + freeclear(profile->cache->email); + freeclear(profile->cache->firstname); + freeclear(profile->cache->lastname); + freeclear(profile->cache->homepage); + freeclear(profile->cache->aimname); + freeclear(profile->cache); +} diff --git a/xrGameSpy/gamespy/GP/gpiInfo.h b/xrGameSpy/gamespy/GP/gpiInfo.h new file mode 100644 index 00000000000..79fe4bbcf52 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiInfo.h @@ -0,0 +1,144 @@ +/* +gpiInfo.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIINFO_H_ +#define _GPIINFO_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//TYPES +/////// +// Profile info cache. +////////////////////// +typedef struct +{ + char * nick; + char * uniquenick; + char * email; + char * firstname; + char * lastname; + char * homepage; + int icquin; + char zipcode[GP_ZIPCODE_LEN]; + char countrycode[GP_COUNTRYCODE_LEN]; + float longitude; // negative is west, positive is east. (0, 0) means unknown. + float latitude; // negative is south, positive is north. (0, 0) means unknown. + char place[GP_PLACE_LEN]; // e.g., "USA|California|Irvine", "South Korea|Seoul", "Turkey" + int birthday; + int birthmonth; + int birthyear; + GPEnum sex; + int publicmask; + char * aimname; + int pic; + int occupationid; + int industryid; + int incomeid; + int marriedid; + int childcount; + int interests1; + int ownership1; + int conntypeid; +} GPIInfoCache; + +//FUNCTIONS +/////////// +GPResult +gpiSetInfoi( + GPConnection * connection, + GPEnum info, + int value +); + +GPResult +gpiSetInfos( + GPConnection * connection, + GPEnum info, + const char * value +); + +GPResult +gpiSetInfod( + GPConnection * connection, + GPEnum info, + int day, + int month, + int year +); + +GPResult +gpiSetInfoMask( + GPConnection * connection, + GPEnum mask +); + +void +gpiInfoCacheToArg( + const GPIInfoCache * cache, + GPGetInfoResponseArg * arg +); + +GPResult +gpiGetInfo( + GPConnection * connection, + GPProfile profile, + GPEnum checkCache, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult +gpiGetInfoNoWait( + GPConnection * connection, + GPProfile profile, + GPGetInfoResponseArg * arg +); + +GPResult +gpiProcessGetInfo( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +GPResult +gpiSendGetInfo( + GPConnection * connection, + int profileid, + int operationid +); + +GPResult +gpiAddLocalInfo( + GPConnection * connection, + GPIBuffer * buffer +); + +typedef struct GPIProfile *pGPIProfile; + +GPIBool +gpiSetInfoCache( + GPConnection * connection, + pGPIProfile profile, + const GPIInfoCache * cache +); + +void +gpiFreeInfoCache( + pGPIProfile profile +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiKeys.c b/xrGameSpy/gamespy/GP/gpiKeys.c new file mode 100644 index 00000000000..009259a2a0e --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiKeys.c @@ -0,0 +1,196 @@ +#include "gpi.h" + +void gpiStatusInfoKeyFree(void *element) +{ + GPIKey *aKey = (GPIKey *)element; + freeclear(aKey->keyName); + freeclear(aKey->keyValue); +} + +GPResult gpiStatusInfoKeysInit(GPConnection * connection) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + iconnection->extendedInfoKeys = ArrayNew(sizeof(GPIKey), GPI_INITIAL_NUM_KEYS, gpiStatusInfoKeyFree); + if(!iconnection->extendedInfoKeys) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + return GP_NO_ERROR; +} + +void gpiStatusInfoKeysDestroy(GPConnection * connection) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + if (iconnection->extendedInfoKeys) + { + ArrayFree(iconnection->extendedInfoKeys); + iconnection->extendedInfoKeys = NULL; + } +} + +int gpiStatusInfoKeyCompFunc(const void *elem1, const void *elem2) +{ + GPIKey *key1 = (GPIKey *)elem1, + *key2 = (GPIKey *)elem2; + return strcmp(key1->keyName, key2->keyName); +} + +GPResult gpiStatusInfoAddKey(GPConnection *connection, DArray keys, const char *theKeyName, const char *theKeyValue) +{ + GPIKey aKey; + GS_ASSERT(keys); + GS_ASSERT(theKeyName); + GS_ASSERT(theKeyValue); + + if (!theKeyName) + Error(connection, GP_PARAMETER_ERROR, "Invalid key name"); + if (!theKeyValue) + Error(connection, GP_PARAMETER_ERROR, "Invalid key value"); + + aKey.keyName = goastrdup(theKeyName); + aKey.keyValue = goastrdup(theKeyValue); + + ArrayInsertSorted(keys, &aKey, gpiStatusInfoKeyCompFunc); + + return GP_NO_ERROR; +} + +GPResult gpiStatusInfoDelKey(GPConnection *connection, DArray keys, const char *keyName) +{ + GPIKey aKey; + int anIndex; + GS_ASSERT(keys); + GS_ASSERT(keyName); + + if (!keyName) + Error(connection, GP_PARAMETER_ERROR, "Invalid key name"); + + aKey.keyName = goastrdup(keyName); + anIndex = ArraySearch(keys, &aKey, gpiStatusInfoKeyCompFunc, 0, 1); + if (anIndex != NOT_FOUND) + { + ArrayDeleteAt(keys, anIndex); + } + + freeclear(aKey.keyName); + return GP_NO_ERROR; +} + +GPResult gpiStatusInfoSetKey(GPConnection *connection, DArray keys, const char *keyName, const char *newKeyValue) +{ + GPIKey aKey; + int anIndex; + GS_ASSERT(keys); + GS_ASSERT(keyName); + + if (!keyName) + Error(connection, GP_PARAMETER_ERROR, "Invalid key name"); + + aKey.keyName = goastrdup(keyName); + anIndex = ArraySearch(keys, &aKey, gpiStatusInfoKeyCompFunc, 0, 1); + if (anIndex != NOT_FOUND) + { + GPIKey *aKeyFound = (GPIKey *)ArrayNth(keys, anIndex); + gsifree(aKeyFound->keyValue); + aKeyFound->keyValue = goastrdup(newKeyValue); + } + freeclear(aKey.keyName); + return GP_NO_ERROR; +} + +GPResult gpiStatusInfoGetKey(GPConnection *connection, DArray keys, const char *keyName, char **keyValue) +{ + GPIKey aKey; + int anIndex; + GS_ASSERT(keys); + GS_ASSERT(keyName); + + if (!keyName) + Error(connection, GP_PARAMETER_ERROR, "Invalid key name"); + + aKey.keyName = goastrdup(keyName); + anIndex = ArraySearch(keys, &aKey, gpiStatusInfoKeyCompFunc, 0, 1); + if (anIndex != NOT_FOUND) + { + GPIKey *aKeyFound = (GPIKey *)ArrayNth(keys, anIndex); + *keyValue = goastrdup(aKeyFound->keyValue); + } + freeclear(aKey.keyName); + return GP_NO_ERROR; +} + +GPResult gpiStatusInfoCheckKey(GPConnection *connection, DArray keys, const char *keyName, char **keyValue) +{ + GPIKey aKey; + int anIndex; + GS_ASSERT(keys); + GS_ASSERT(keyName); + + if (!keyName) + Error(connection, GP_PARAMETER_ERROR, "Invalid key name"); + + aKey.keyName = goastrdup(keyName); + anIndex = ArraySearch(keys, &aKey, gpiStatusInfoKeyCompFunc, 0, 1); + if (anIndex != NOT_FOUND) + { + GPIKey *aKeyFound = (GPIKey *)ArrayNth(keys, anIndex); + *keyValue = aKeyFound->keyValue; + } + freeclear(aKey.keyName); + return GP_NO_ERROR; +} + +GPResult gpiSaveKeysToBuffer(GPConnection *connection, char **buffer) +{ + GPIConnection *iconnection = (GPIConnection *)*connection; + char *tempPoint; + int sizeKeys = 0, i, bytesWritten; + int base64KeyNameLen, base64KeyValLen; + int aLength = ArrayLength(iconnection->extendedInfoKeys); + + char keysHeader[64]; + sprintf(keysHeader, "\\keys\\%d", aLength); + + // figure out the size of the buffer to allocate + // by adding up the key value pairs with backslashes + for (i = 0; i < aLength; i++) + { + GPIKey *aKey = (GPIKey *)ArrayNth(iconnection->extendedInfoKeys, i); + if (strlen(aKey->keyName) % 3 != 0) + base64KeyNameLen = (int)(strlen(aKey->keyName) * 4 / 3) + (int)(4 - (strlen(aKey->keyName) % 3)); + else + base64KeyNameLen = (int)(strlen(aKey->keyName) * 4 / 3); + if (strlen(aKey->keyValue) % 3 != 0) + base64KeyValLen= (int)(strlen(aKey->keyValue) * 4 / 3) + (int)(4 - (strlen(aKey->keyValue) % 3)); + else + base64KeyValLen = (int)(strlen(aKey->keyValue) * 4 / 3); + sizeKeys += 1 + base64KeyNameLen + 1 + base64KeyValLen; + } + *buffer = (char *)gsimalloc(strlen(keysHeader) + (size_t)sizeKeys + 1); + if (*buffer == NULL) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_HotError, "gpiSaveKeysToBuffer: buffer Out of memory."); + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + bytesWritten = sprintf(*buffer, keysHeader); + tempPoint = *buffer + bytesWritten; + for (i = 0; i < aLength; i++) + { + GPIKey *aKey = (GPIKey *)ArrayNth(iconnection->extendedInfoKeys, i); + strcat(tempPoint, "\\"); + tempPoint++; + B64Encode(aKey->keyName, tempPoint, (int)strlen(aKey->keyName), 2); + if (strlen(aKey->keyName) % 3 != 0) + tempPoint+= (int)(strlen(aKey->keyName) * 4 / 3) + (4 - (strlen(aKey->keyName) % 3)); + else + tempPoint+= (int)(strlen(aKey->keyName) * 4 / 3); + strcat(tempPoint, "\\"); + tempPoint++; + B64Encode(aKey->keyValue, tempPoint, (int)strlen(aKey->keyValue), 2); + if (strlen(aKey->keyValue) % 3 != 0) + tempPoint+= (int)(strlen(aKey->keyValue) * 4 / 3) + (4 - (strlen(aKey->keyValue) % 3)); + else + tempPoint+= (int)(strlen(aKey->keyValue) * 4 / 3); + } + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiKeys.h b/xrGameSpy/gamespy/GP/gpiKeys.h new file mode 100644 index 00000000000..10a13effbe8 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiKeys.h @@ -0,0 +1,23 @@ +#ifndef _GPIKEYS_H_ +#define _GPIKEYS_H_ + +#include "gpi.h" +#define GPI_INITIAL_NUM_KEYS 1 + +typedef struct +{ + char *keyName; + char *keyValue; +} GPIKey; + +void gpiStatusInfoKeyFree(void *element); +GPResult gpiStatusInfoKeysInit(GPConnection * connection); +void gpiStatusInfoKeysDestroy(GPConnection * connection); +int gpiStatusInfoKeyCompFunc(const void *elem1, const void *elem2); +GPResult gpiStatusInfoAddKey(GPConnection *connection, DArray keys, const char *theKeyName, const char *theKeyValue); +GPResult gpiStatusInfoDelKey(GPConnection *connection, DArray keys, const char *keyName); +GPResult gpiStatusInfoSetKey(GPConnection *connection, DArray keys, const char *keyName, const char *newKeyValue); +GPResult gpiStatusInfoGetKey(GPConnection *connection, DArray keys, const char *keyName, char **keyValue); +GPResult gpiSaveKeysToBuffer(GPConnection *connection, char **buffer); +GPResult gpiStatusInfoCheckKey(GPConnection *connection, DArray keys, const char *keyName, char **keyValue); +#endif diff --git a/xrGameSpy/gamespy/GP/gpiOperation.c b/xrGameSpy/gamespy/GP/gpiOperation.c new file mode 100644 index 00000000000..bcb14803459 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiOperation.c @@ -0,0 +1,363 @@ +/* +gpiOperation.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include +#include "gpi.h" + +//FUNCTIONS +/////////// +GPResult +gpiFailedOpCallback( + GPConnection * connection, + const GPIOperation * operation +) +{ + GPICallback callback; + GPIConnection * iconnection = (GPIConnection*)*connection; + + assert(connection != NULL); + assert(*connection != NULL); + assert(operation != NULL); + + callback = operation->callback; + if(callback.callback != NULL) + { + // Handle based on operation type. + ////////////////////////////////// + switch(operation->type) + { + case GPI_CONNECT: + { + GPConnectResponseArg * arg; + arg = (GPConnectResponseArg *)gsimalloc(sizeof(GPConnectResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPConnectResponseArg)); + arg->result = operation->result; + if(iconnection->errorCode == GP_NEWUSER_BAD_NICK) + { + arg->profile = (GPProfile)iconnection->profileid; + iconnection->profileid = 0; + } + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + } + case GPI_NEW_PROFILE: + { + GPNewProfileResponseArg * arg; + arg = (GPNewProfileResponseArg *)gsimalloc(sizeof(GPNewProfileResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPNewProfileResponseArg)); + arg->result = operation->result; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + } + case GPI_DELETE_PROFILE: + { + GPDeleteProfileResponseArg * arg; + arg = (GPDeleteProfileResponseArg *)gsimalloc(sizeof(GPDeleteProfileResponseArg)); + if (arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPDeleteProfileResponseArg)); + arg->result = operation->result; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + + } + case GPI_GET_INFO: + { + GPGetInfoResponseArg * arg; + arg = (GPGetInfoResponseArg *)gsimalloc(sizeof(GPGetInfoResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPGetInfoResponseArg)); + arg->result = operation->result; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + } + case GPI_PROFILE_SEARCH: + { + GPProfileSearchResponseArg * arg; + arg = (GPProfileSearchResponseArg *)gsimalloc(sizeof(GPProfileSearchResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPProfileSearchResponseArg)); + arg->result = operation->result; + ((GPProfileSearchResponseArg *)arg)->matches = NULL; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + } + case GPI_REGISTER_UNIQUENICK: + { + GPRegisterUniqueNickResponseArg * arg; + arg = (GPRegisterUniqueNickResponseArg *)gsimalloc(sizeof(GPRegisterUniqueNickResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPRegisterUniqueNickResponseArg)); + arg->result = operation->result; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + } + case GPI_REGISTER_CDKEY: + { + GPRegisterCdKeyResponseArg * arg; + arg = (GPRegisterCdKeyResponseArg *)gsimalloc(sizeof(GPRegisterCdKeyResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(arg, 0, sizeof(GPRegisterCdKeyResponseArg)); + arg->result = operation->result; + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + break; + } + default: + assert(0); + } + } + + return GP_NO_ERROR; +} + +GPResult +gpiAddOperation( + GPConnection * connection, + int type, + void * data, + GPIOperation ** op, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIOperation * operation; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Create a new operation struct. + ///////////////////////////////// + operation = (GPIOperation *)gsimalloc(sizeof(GPIOperation)); + if(operation == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Set the data. + //////////////// + operation->type = type; + operation->data = data; + operation->blocking = (GPIBool)blocking; + operation->state = GPI_START; + if(type == GPI_CONNECT) + { + // Connect is always ID 1. + ////////////////////////// + operation->id = 1; + } + else + { + operation->id = iconnection->nextOperationID++; + if(iconnection->nextOperationID < 2) + iconnection->nextOperationID = 2; + } + operation->result = GP_NO_ERROR; + operation->callback.callback = callback; + operation->callback.param = param; + + // Add it to the list. + ////////////////////// + operation->pnext = iconnection->operationList; + iconnection->operationList = operation; + + *op = operation; + return GP_NO_ERROR; +} + +void +gpiDestroyOperation( + GPConnection * connection, + GPIOperation * operation +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Search? + ////////// + if(operation->type == GPI_PROFILE_SEARCH) + { + GPISearchData * data = (GPISearchData *)operation->data; + + // One less. + //////////// + iconnection->numSearches--; + assert(iconnection->numSearches >= 0); + + // Close the socket. + //////////////////// + shutdown(data->sock, 2); + closesocket(data->sock); + + // freeclear the buffers. + //////////////////// + freeclear(data->outputBuffer.buffer); + freeclear(data->inputBuffer.buffer); + } + + // freeclear the data. + ///////////////// + freeclear(operation->data); + + // freeclear the operation struct. + ///////////////////////////// + freeclear(operation); +} + +void +gpiRemoveOperation( + GPConnection * connection, + GPIOperation * operation +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIOperation * pcurr = iconnection->operationList; + GPIOperation * pprev = NULL; + + // Go through the list of operations. + ///////////////////////////////////// + while(pcurr != NULL) + { + // Check for a match. + ///////////////////// + if(pcurr == operation) + { + // Update the list. + /////////////////// + if(pprev == NULL) + iconnection->operationList = pcurr->pnext; + else + pprev->pnext = operation->pnext; + + gpiDestroyOperation(connection, operation); + + return; + } + + pprev = pcurr; + pcurr = pcurr->pnext; + } +} + +GPIBool +gpiFindOperationByID( + const GPConnection * connection, + GPIOperation ** operation, + int id +) +{ + GPIOperation * op; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Go through the list of operations. + ///////////////////////////////////// + for(op = iconnection->operationList ; op != NULL ; op = op->pnext) + { + // Check the id. + //////////////// + if(op->id == id) + { + // Found it. + //////////// + if(operation != NULL) + *operation = op; + return GPITrue; + } + } + + // Didn't find it. + ////////////////// + if(operation != NULL) + *operation = NULL; + return GPIFalse; +} + +GPIBool +gpiOperationsAreBlocking( + const GPConnection * connection +) +{ + GPIOperation * operation; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Loop through the operations. + /////////////////////////////// + for(operation = iconnection->operationList ; operation != NULL ; operation = operation->pnext) + { + // Check if it's blocking. + ////////////////////////// + if((operation->blocking) && (operation->type != GPI_PROFILE_SEARCH)) + return GPITrue; + } + + // Nothing was blocking. + //////////////////////// + return GPIFalse; +} + +GPResult +gpiProcessOperation( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + GPResult result = GP_NO_ERROR; + + // Check the operation type. + //////////////////////////// + switch(operation->type) + { + case GPI_CONNECT: + result = gpiProcessConnect(connection, operation, input); + break; + + case GPI_NEW_PROFILE: + result = gpiProcessNewProfile(connection, operation, input); + break; + + case GPI_DELETE_PROFILE: + result = gpiProcessDeleteProfle(connection, operation, input); + break; + + case GPI_GET_INFO: + result = gpiProcessGetInfo(connection, operation, input); + break; + + case GPI_REGISTER_UNIQUENICK: + result = gpiProcessRegisterUniqueNick(connection, operation, input); + break; + + case GPI_REGISTER_CDKEY: + result = gpiProcessRegisterCdKey(connection, operation, input); + break; + + default: + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiProcessOperation was passed an operation with an invalid type (%d)\n", operation->type); + assert(0); + break; + } + + if(result != GP_NO_ERROR) + operation->result = result; + + return result; +} + diff --git a/xrGameSpy/gamespy/GP/gpiOperation.h b/xrGameSpy/gamespy/GP/gpiOperation.h new file mode 100644 index 00000000000..06204cac1a0 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiOperation.h @@ -0,0 +1,120 @@ +/* +gpiOperation.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIOPERATION_H_ +#define _GPIOPERATION_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +// Operation Types. +/////////////////// +#define GPI_CONNECT 0 +#define GPI_NEW_PROFILE 1 +#define GPI_GET_INFO 2 +#define GPI_PROFILE_SEARCH 3 +#define GPI_REGISTER_UNIQUENICK 4 +#define GPI_DELETE_PROFILE 5 +#define GPI_REGISTER_CDKEY 6 +// Operation States. +//////////////////// +#define GPI_START 0 +//#define GPI_CONNECTING 1 +#define GPI_LOGIN 2 +#define GPI_REQUESTING 3 +#define GPI_WAITING 4 +#define GPI_FINISHING 5 + +//TYPES +/////// +// Operation data. +////////////////// +typedef struct GPIOperation_s +{ + int type; + void * data; + GPIBool blocking; + GPICallback callback; + int state; + int id; + GPResult result; + struct GPIOperation_s * pnext; +} GPIOperation; + +// Connect operation data. +////////////////////////// +typedef struct +{ + char serverChallenge[128]; + char userChallenge[33]; + char passwordHash[33]; + char authtoken[GP_AUTHTOKEN_LEN]; + char partnerchallenge[GP_PARTNERCHALLENGE_LEN]; + char cdkey[GP_CDKEY_LEN]; + GPIBool newuser; +} GPIConnectData; + +//FUNCTIONS +/////////// +GPResult +gpiAddOperation( + GPConnection * connection, + int type, + void * data, + GPIOperation ** op, + GPEnum blocking, + GPCallback callback, + void * param +); + +void +gpiRemoveOperation( + GPConnection * connection, + GPIOperation * operation +); + +void +gpiDestroyOperation( + GPConnection * connection, + GPIOperation * operation +); + +GPIBool +gpiFindOperationByID( + const GPConnection * connection, + GPIOperation ** operation, + int id +); + +GPIBool +gpiOperationsAreBlocking( + const GPConnection * connection +); + +GPResult +gpiProcessOperation( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +GPResult +gpiFailedOpCallback( + GPConnection * connection, + const GPIOperation * operation +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiPS3.c b/xrGameSpy/gamespy/GP/gpiPS3.c new file mode 100644 index 00000000000..cb11fbdc020 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiPS3.c @@ -0,0 +1,592 @@ +/* +gpiPS3.c +GameSpy Presence SDK + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include +#include +#include "gpi.h" + +#ifdef _PS3 +//GLOBALS +////////// +uint8_t gpi_np_pool[SCE_NP_MIN_POOL_SIZE]; +SceNpCommunicationId gpi_communication_id = { + {'N','P','X','S','0','0','0','0','5'}, + '\0', + 0, + 0 +}; + +//FUNCTIONS +/////////// +int gpiNpBasicCallback( + int event, + int retCode, + uint32_t reqId, + void *arg +) +{ + // No-op - can ignore any events + //////////////////////////////// + return 0; +} + +GPResult gpiInitializeNpBasic( + GPConnection * connection +) +{ + int ret = 0; + GPIConnection * iconnection = (GPIConnection*)*connection; + + iconnection->npInitialized = gsi_true; + + // Initial NP init - after this we wait for status to get to online + //////////////////////////////////////////////////////////////////// + ret = sceNpInit(SCE_NP_MIN_POOL_SIZE, gpi_np_pool); + + if (ret == SCE_NP_ERROR_ALREADY_INITIALIZED) + { + // If already initialized - DO NOT terminate after sync (game might need it) + //////////////////////////////////////////////////////////////////////////// + iconnection->npBasicGameInitialized = gsi_true; + } + else if (ret < 0) + { + iconnection->npBasicGameInitialized = gsi_true; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiInitializeNpBasic: sceNpInit() failed, NP-functionality disabled. ret = 0x%x\n", ret); + return GP_MISC_ERROR; + } + else + iconnection->npBasicGameInitialized = gsi_false; //GP initialized, so destroy after complete + + return GP_NO_ERROR; +} + +// Freeing up transaction list darray +void gpiNpTransactionListFree(void *element) +{ + npIdLookupTrans *aTrans = (npIdLookupTrans *)element; + freeclear(aTrans->npIdForAdd); +} + + +GPResult gpiCheckNpStatus( + GPConnection * connection +) +{ + int ret = 0; + int status = SCE_NP_MANAGER_STATUS_OFFLINE; + SceNpId npId; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Get NP status + //////////////// + ret = sceNpManagerGetStatus(&status); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: sceNpGetStatus() failed. ret = 0x%x\n", ret); + } + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "gpiCheckNpStatus: sceNpGetStatus - status = %d\n", status); + + + // If NP status != online after the timeout period, stop syncing + //////////////////////////////////////////////////////////////// + if (status != SCE_NP_MANAGER_STATUS_ONLINE && (current_time() - iconnection->loginTime > GPI_NP_STATUS_TIMEOUT)) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: NP Status not online - timed out\n"); + + // Flag to stop the sync process + //////////////////////////////// + iconnection->npPerformBuddySync = gsi_false; + iconnection->npPerformBlockSync = gsi_false; + + return GP_MISC_ERROR; + } + + // Once status is online, finish NP init + //////////////////////////////////////// + if (status == SCE_NP_MANAGER_STATUS_ONLINE) + { + iconnection->loginTime = current_time(); + + // Note - we ignore error messages here - if something fails we really don't care + ///////////////////////////////////////////////////////////////////////////////// + if (!iconnection->npBasicGameInitialized) + { + ret = sceNpBasicInit(); //obsolete? + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: sceNpBasicInit() failed. ret = 0x%x\n", ret); + } + + ret = sceNpBasicRegisterHandler(&gpi_communication_id, gpiNpBasicCallback, NULL); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: sceNpBasicRegisterHandler() failed. ret = 0x%x\n", ret); + } + } + + ret = sceNpLookupInit(); + if (ret == SCE_NP_COMMUNITY_ERROR_ALREADY_INITIALIZED) + { + // If already initialized - DO NOT terminate after GP destroy (game might need it) + ////////////////////////////////////////////////////////////////////////////////// + iconnection->npLookupGameInitialized = gsi_true; + } + else if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: sceNpLookupInit() failed. ret = 0x%x\n", ret); + iconnection->npLookupGameInitialized = gsi_true; + } + else + iconnection->npLookupGameInitialized = gsi_false; + + // Regardless of game, create a title context id for GP to use for lookups + /////////////////////////////////////////////////////////////////////////// + ret = sceNpManagerGetNpId(&npId); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: sceNpManagerGetNpId() failed. ret = 0x%x\n", ret); + } + + ret = sceNpLookupCreateTitleCtx(&gpi_communication_id, &npId); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "gpiCheckNpStatus: sceNpLookupCreateTitleCtx() failed. ret = 0x%x\n", ret); + } + + iconnection->npLookupTitleCtxId = ret; + + // Mark status retrieval completed + ////////////////////////////////// + iconnection->npStatusRetrieved = gsi_true; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "gpiCheckNpStatus: NP is now initialized with status.\n"); + + iconnection->npTransactionList = ArrayNew(sizeof(npIdLookupTrans), 1, gpiNpTransactionListFree); + if (!iconnection->npTransactionList) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + + return GP_NO_ERROR; +} + +GPResult gpiDestroyNpBasic( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Explicitly destroy title context we used for lookup + ////////////////////////////////////////////////////// + if (iconnection->npLookupTitleCtxId >= 0) + sceNpLookupDestroyTitleCtx(iconnection->npLookupTitleCtxId); + + // Do not destroy NpLookup or NpBasic if Game is using it + ///////////////////////////////////////////////////////// + if (!iconnection->npLookupGameInitialized) + sceNpLookupTerm(); + + if (!iconnection->npBasicGameInitialized) + { + sceNpBasicUnregisterHandler(); + + // Obsolete? + sceNpBasicTerm(); + + sceNpTerm(); + } + + // Free up transaction list used for NP lookups + /////////////////////////////////////////////// + if (iconnection->npTransactionList) + ArrayFree(iconnection->npTransactionList); + + iconnection->npInitialized = gsi_false; + iconnection->npStatusRetrieved = gsi_false; + + return GP_NO_ERROR; +} + +GPResult gpiSyncNpBuddies( + GPConnection * connection +) +{ + int ret; + SceNpId npId; //Buffer to store friend list entry's NP ID + gsi_u32 i, count = 0; + GPIConnection * iconnection = (GPIConnection*)*connection; + + + // Flag sync as complete so we don't do it more than once per login + //////////////////////////////////////////////////////////////////// + iconnection->npPerformBuddySync = gsi_false; + + // Get buddy count + /////////////////// + ret = sceNpBasicGetFriendListEntryCount(&count); + if ( ret < 0 ) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3BuddySync: Failed to get NP friend list count\n"); + } + + // Loop through each buddy, check for existence of GSID account + /////////////////////////////////////////////////////////////// + for (i = 0; i < count; i++) + { + memset(&npId, 0x00, sizeof(npId)); + ret = sceNpBasicGetFriendListEntry(i, &npId); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3BuddySync: Failed to get NP friend entry #%d\n", i); + return GP_MISC_ERROR; + } + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BuddySync: NP friend entry #%d, npid = %s. Queueing Search.\n", i, npId.handle.data); + + gpiProfileSearchUniquenick(connection, npId.handle.data, &iconnection->namespaceID, + 1, GP_NON_BLOCKING, (GPCallback)gpiSyncNpBuddiesCallback, NULL); + } + + return GP_NO_ERROR; +} + +void gpiSyncNpBuddiesCallback( + GPConnection * pconnection, + GPProfileSearchResponseArg * arg, + void * param +) +{ + if(arg->result == GP_NO_ERROR) + { + if(arg->numMatches == 1) + { + // Check if already a buddy + //////////////////////////// + if (!gpIsBuddy(pconnection, arg->matches[0].profile)) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BuddySync: NP Buddy \"%s\" found in namespace %d. Sending Request.\n", + arg->matches[0].uniquenick, arg->matches[0].namespaceID); + + // Send the add request + //////////////////////// + gpSendBuddyRequest(pconnection, arg->matches[0].profile, _T("PS3 Buddy Sync")); + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BuddySync: \"%s\" is already a buddy\n", arg->matches[0].uniquenick); + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BuddySync: No suitable match found\n"); + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3BuddySync: Buddy Search FAILED!\n"); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +GPResult gpiSyncNpBlockList( + GPConnection * connection +) +{ + int ret; + SceNpId npId; //Buffer to store block list entry's NP ID + gsi_u32 i, count = 0; + GPIConnection * iconnection = (GPIConnection*)*connection; + + + // Flag sync as complete so we don't do it more than once per login + //////////////////////////////////////////////////////////////////// + iconnection->npPerformBlockSync = gsi_false; + + // Get block list count + /////////////////////// + ret = sceNpBasicGetBlockListEntryCount(&count); + if ( ret < 0 ) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3BlockSync: Failed to get NP block list count\n"); + } + + // Loop through each entry, check for existence of GSID account + /////////////////////////////////////////////////////////////// + for (i = 0; i < count; i++) + { + memset(&npId, 0x00, sizeof(npId)); + ret = sceNpBasicGetBlockListEntry(i, &npId); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3BlockSync: Failed to get NP block entry #%d\n", i); + return GP_MISC_ERROR; + } + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BlockSync: NP block entry #%d, npid = %s. Queueing Search.\n", i, npId.handle.data); + + gpiProfileSearchUniquenick(connection, npId.handle.data, &iconnection->namespaceID, + 1, GP_NON_BLOCKING, (GPCallback)gpiSyncNpBlockListCallback, NULL); + } + + return GP_NO_ERROR; +} + +void gpiSyncNpBlockListCallback( + GPConnection * pconnection, + GPProfileSearchResponseArg * arg, + void * param +) +{ + GPIProfile * pProfile; + GPIConnection * iconnection = (GPIConnection*)*pconnection; + + if(arg->result == GP_NO_ERROR) + { + if(arg->numMatches == 1) + { + // Check if already blocked + //////////////////////////// + if(!gpiGetProfile(pconnection, arg->matches[0].profile, &pProfile) || !pProfile->blocked) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BlockSync: NP Block Entry \"%s\" found in namespace %d. Adding to BlockedList.\n", + arg->matches[0].uniquenick, arg->matches[0].namespaceID); + + // Add to GP Blocked List - set lock to make sure we dont try to add to NP list + /////////////////////////////////////////////////////////////////////////////// + iconnection->npSyncLock = gsi_true; + gpiAddToBlockedList(pconnection, arg->matches[0].profile); + iconnection->npSyncLock = gsi_false; + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BlockSync: \"%s\" is already blocked\n", arg->matches[0].uniquenick); + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3BlockSync: No suitable match found\n"); + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3BlockSync: Block Entry Search FAILED!\n"); + + GSI_UNUSED(param); +} + +GPResult gpiAddToNpBlockList( + GPConnection * connection, + int profileid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + // TODO: consider developer method for cache input in order to check HDD cache? + + // If NP status not resolved, don't bother with lookup + /////////////////////////////////////////////////////// + if (!iconnection->npTransactionList || iconnection->npLookupTitleCtxId < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: Cancelling add - NP status not yet resolved.\n"); + return GP_NO_ERROR; + } + + // Do an info lookup to find out if this player has an NP account. + ///////////////////////////////////////////////////////////////// + gpiGetInfo(connection, profileid, GP_CHECK_CACHE, GP_NON_BLOCKING, + (GPCallback)gpiAddToNpBlockListInfoCallback, NULL); + + return GP_NO_ERROR; +} + +void gpiAddToNpBlockListInfoCallback( + GPConnection * pconnection, + GPGetInfoResponseArg * arg, + void * param +) +{ + SceNpOnlineId onlineId; + int ret; + npIdLookupTrans transaction; + GPIConnection * iconnection = (GPIConnection*)*pconnection; +#ifdef GSI_UNICODE + char asciiUniquenick[GP_UNIQUENICK_LEN]; +#endif + + if(arg->result == GP_NO_ERROR) + { + // Make sure its a PS3 uniquenick (e.g. we have the uniquenick) + /////////////////////////////////////////////////////////////// + if (_tcslen(arg->uniquenick) != 0) + { + memset(&onlineId, 0, sizeof(onlineId)); + +#ifdef GSI_UNICODE + UCS2ToAsciiString(arg->uniquenick, (char*)asciiUniquenick); + strncpy(onlineId.data, asciiUniquenick, SCE_NET_NP_ONLINEID_MAX_LENGTH); +#else + strncpy(onlineId.data, arg->uniquenick, SCE_NET_NP_ONLINEID_MAX_LENGTH); +#endif + + if (ArrayLength(iconnection->npTransactionList) < GPI_NP_NUM_TRANSACTIONS) + { + ret = sceNpLookupCreateTransactionCtx(iconnection->npLookupTitleCtxId); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: sceNpLookupCreateTransactionCtx() failed. ret = 0x%x\n", ret); + } + else + { + transaction.npIdForAdd = (SceNpId*)gsimalloc(sizeof(SceNpId)); + if(transaction.npIdForAdd == NULL) + { + sceNpLookupDestroyTransactionCtx(ret); + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: Out of memory.\n"); + return; + } + transaction.npTransId = ret; + transaction.npLookupDone = gsi_false; + ArrayAppend(iconnection->npTransactionList, &transaction); + + // Perform NP lookup to get the NpId + ///////////////////////////////////// + ret = sceNpLookupNpIdAsync(transaction.npTransId, &onlineId, + transaction.npIdForAdd, 0, NULL); + if (ret < 0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: sceNpLookupNpIdAsync() failed. ret = 0x%x\n", ret); + } + } + } + else + { + // Can only have a max of 32 simultaneous transactions (based on PS3 lib) + ///////////////////////////////////////////////////////////////////////// + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "PS3AddToNpBlockList: Transactions limit reached for np lookups\n"); + } + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: Profile [%d] does not have a uniquenick in namespace %d!\n", + arg->profile, iconnection->namespaceID); + } + else + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: Player Info lookup FAILED!\n"); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +GPResult gpiProcessNp(GPConnection * connection) +{ + int i, ret=0; + GPIConnection * iconnection = (GPIConnection*)*connection; + npIdLookupTrans * transaction; + + // Check for uninitialized transaction darray + ////////////////////////////////////////////// + if (!iconnection->npTransactionList) + return GP_NO_ERROR; + + // Need to process Sysutil for the Async lookups + ///////////////////////////////////////////////// + if (ArrayLength(iconnection->npTransactionList) > 0) + cellSysutilCheckCallback(); + + // Loop through all current transactions, check if complete + /////////////////////////////////////////////////////////// + for (i=0; i < ArrayLength(iconnection->npTransactionList); i++) + { + // Grab next transaction in the list + ///////////////////////////////////// + transaction = (npIdLookupTrans *)ArrayNth(iconnection->npTransactionList, i); + + if (!transaction->npLookupDone) + { + if (sceNpLookupPollAsync(transaction->npTransId, &ret)==0) + transaction->npLookupDone = gsi_true; + } + else + { + if (ret<0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: sceNpLookupWaitAsync. ret = 0x%x\n", ret); + if (ret == (int)SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_USER_NPID) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: Player '%s' is not an NP user.\n", + transaction->npIdForAdd->handle.data); + } + } + else + { + // Found an NpId, try to add + ///////////////////////////// + ret = sceNpBasicAddBlockListEntry(transaction->npIdForAdd); + if (ret == (int)SCE_NP_BASIC_ERROR_BUSY) + { + // Oh nice, NP is too busy to help us.... keep on trying + ///////////////////////////////////////////////////////// + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3AddToNpBlockList: SCE_NP_BASIC_ERROR_BUSY. continue trying to add to NP\n"); + return GP_NO_ERROR; + } + else if ( ret < 0 ) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: sceNpBasicAddBlockListEntry() failed. ret = 0x%x\n", ret); + } + else + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Comment, + "PS3AddToNpBlockList: Player '%s' added to NP Block list.\n", + transaction->npIdForAdd->handle.data); + } + } + + ret = sceNpLookupDestroyTransactionCtx(transaction->npTransId); + if (ret<0) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "PS3AddToNpBlockList: sceNpLookupDestroyTransactionCtx() failed. ret = 0x%x\n", ret); + } + + // Delete Transaction when its complete + //////////////////////////////////////// + ArrayDeleteAt(iconnection->npTransactionList, i); + } + } + + return GP_NO_ERROR; +} + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiPS3.h b/xrGameSpy/gamespy/GP/gpiPS3.h new file mode 100644 index 00000000000..fc09b15d9e2 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiPS3.h @@ -0,0 +1,54 @@ +/* +gpiPS3.h +GameSpy Presence SDK + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIPS3_H_ +#define _GPIPS3_H_ + +//INCLUDES +////////// +#include "gpi.h" +#include +#include +#include + + +//DEFINES +///////// +#define GPI_NP_SYNC_DELAY 5000 //wait 5 seconds after login before doing any syncs +#define GPI_NP_STATUS_TIMEOUT 5000 //timeout after 5 second max if NP status is not online +#define GPI_NP_NUM_TRANSACTIONS 32 //Max num of simultaneous NP lookup transactions + +//STRUCTURES +//////////// +typedef struct +{ + int npTransId; + SceNpId *npIdForAdd; + gsi_bool npLookupDone; +} npIdLookupTrans; + +//FUNCTIONS +/////////// +GPResult gpiInitializeNpBasic(); +GPResult gpiCheckNpStatus(GPConnection * connection); +GPResult gpiDestroyNpBasic(GPConnection * connection); +GPResult gpiProcessNp(GPConnection * connection); +int gpiNpBasicCallback(int event, int retCode, uint32_t reqId, void *arg); + +GPResult gpiSyncNpBuddies(GPConnection * connection); +void gpiSyncNpBuddiesCallback(GPConnection * pconnection, GPProfileSearchResponseArg * arg, void * param); + +GPResult gpiSyncNpBlockList(GPConnection * connection); +void gpiSyncNpBlockListCallback(GPConnection * pconnection, GPProfileSearchResponseArg * arg, void * param); + +GPResult gpiAddToNpBlockList(GPConnection * connection, int profileid); +void gpiAddToNpBlockListInfoCallback(GPConnection * pconnection, GPGetInfoResponseArg * arg, void * param); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiPeer.c b/xrGameSpy/gamespy/GP/gpiPeer.c new file mode 100644 index 00000000000..b9b04fc0d71 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiPeer.c @@ -0,0 +1,1311 @@ +/* +gpiPeer.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 275 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + +//INCLUDES +////////// +#include +#include +#include +#include "gpi.h" + +//FUNCTIONS +/////////// +static GPResult +gpiProcessPeerInitiatingConnection( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + //int state; + char * str = NULL; + //int len; + GPIBool connClosed; + GPIProfile * pProfile; + GPResult result; + GSUdpPeerState aPeerState; + + GS_ASSERT(peer); + if (!peer) + return GP_NETWORK_ERROR; + + GS_ASSERT(peer->state != GPI_PEER_DISCONNECTED && peer->state != GPI_PEER_NOT_CONNECTED); + if (peer->state == GPI_PEER_DISCONNECTED || peer->state == GPI_PEER_NOT_CONNECTED) + return GP_NETWORK_ERROR; + // Check the state. + /////////////////// + switch(peer->state) + { + case GPI_PEER_GETTING_SIG: + // Do nothing - we're waiting for getinfo to get the sig. + ///////////////////////////////////////////////////////// + break; + + case GPI_PEER_GOT_SIG: + { + // Start the connect. + ///////////////////// + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_State, GSIDebugLevel_Verbose, "Got the peer signature for profileid: %d\n", peer->profile); + CHECK_RESULT(gpiPeerStartConnect(connection, peer)); + + break; + } + case GPI_PEER_CONNECTING: + { + // Check if the connect finished. + ///////////////////////////////// + /* + CHECK_RESULT(gpiCheckSocketConnect(connection, peer->sock, &state)); + if(state == GPI_DISCONNECTED) + { + Error(connection, GP_NETWORK_ERROR, "Error connecting to a peer."); + } + */ + + gsUdpEngineGetPeerState(peer->ip, peer->port, &aPeerState); + + if(aPeerState == GS_UDP_PEER_CONNECTED) + { + GPIPeer * pcurr; + GPIBool freePeerSig = GPITrue; + + // Get the profile object. + ////////////////////////// + if(!gpiGetProfile(connection, peer->profile, &pProfile)) + Error(connection, GP_NETWORK_ERROR, "Error connecting to a peer."); + + // Send the auth. + ///////////////// + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\auth\\"); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\pid\\"); + gpiAppendIntToBuffer(connection, &peer->outputBuffer, iconnection->profileid); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\nick\\"); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, iconnection->nick); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\sig\\"); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, pProfile->peerSig); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\final\\"); + + // Are there any other peers still connecting? + ////////////////////////////////////////////// + for(pcurr = iconnection->peerList ; pcurr != NULL ; pcurr = pcurr->pnext) + if((pcurr->profile == peer->profile) && (pcurr != peer)) + if(pcurr->state <= GPI_PEER_CONNECTING) + freePeerSig = GPIFalse; + + // freeclear it? + /////////// + if(freePeerSig) + { + freeclear(pProfile->peerSig); + if(gpiCanFreeProfile(pProfile)) + gpiRemoveProfile(connection, pProfile); + } + + // Update the state. + //////////////////// + peer->state = GPI_PEER_WAITING; + } + + break; + } + case GPI_PEER_WAITING: + { + // Check for a response. + //////////////////////// + //CHECK_RESULT(gpiRecvToBuffer(connection, peer->sock, &peer->inputBuffer, &len, &connClosed, "PR")); + + // Check for a final. + ///////////////////// + if (peer->inputBuffer.buffer) + str = strstr(peer->inputBuffer.buffer, "\\final\\"); + if(str != NULL) + { + str[0] = '\0'; + str += 7; + + // Was it rejected? + /////////////////// + if(strncmp(peer->inputBuffer.buffer, "\\anack\\", 7) == 0) + { + // Rejected. + //////////// + peer->nackCount++; + + // Is this more than once? + ////////////////////////// + if(peer->nackCount > 1) + { + // we shouldn't reach this case unless there is a problem with + // the server when getting a buddy's signature + + // Give up already. + /////////////////// + Error(connection, GP_NETWORK_ERROR, "Error getting buddy authorization."); + } + + // Try getting the latest sig. + ////////////////////////////// + CHECK_RESULT(gpiPeerGetSig(connection, peer)); + } + else if(strncmp(peer->inputBuffer.buffer, "\\aack\\", 6) != 0) + { + // Unknown message. + /////////////////// + Error(connection, GP_NETWORK_ERROR, "Error parsing buddy message."); + } + + // The connection has been established. + /////////////////////////////////////// + peer->state = GPI_PEER_CONNECTED; + peer->inputBuffer.len = 0; + } + + break; + } + // code should not reach here. + default: break; + } + + // Send stuff that needs to be sent. + //////////////////////////////////// + if(peer->outputBuffer.len > 0) + { + //result = gpiSendFromBuffer(connection, peer->sock, &peer->outputBuffer, &connClosed, GPITrue, "PR"); + result = gpiSendBufferToPeer(connection, peer->ip, peer->port, &peer->outputBuffer, &connClosed, GPITrue); + if(connClosed || (result != GP_NO_ERROR)) + peer->state = GPI_PEER_DISCONNECTED; + } + + return GP_NO_ERROR; +} + +static GPResult +gpiProcessPeerAcceptingConnection( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GSUdpPeerState aPeerState; + char * str; + //int len; + GPIBool connClosed; + char intValue[16]; + int pid; + char nick[GP_NICK_LEN]; + char sig[33]; + char sigCheck[33]; + char buffer[256]; + + // Check the state. + /////////////////// + GS_ASSERT(peer->state == GPI_PEER_WAITING); + if (peer->state != GPI_PEER_WAITING) + return GP_NETWORK_ERROR; + + // Read any pending info. + ///////////////////////// + //CHECK_RESULT(gpiRecvToBuffer(connection, peer->sock, &peer->inputBuffer, &len, &connClosed, "PR")); + gsUdpEngineGetPeerState(peer->ip, peer->port, &aPeerState); + + // Check for a closed connection. + ///////////////////////////////// + if(aPeerState == GS_UDP_PEER_CLOSED) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + + // Check for a final. + ///////////////////// + str = strstr(peer->inputBuffer.buffer, "\\final\\"); + if(str != NULL) + { + str[0] = '\0'; + str += 7; + + // Is it an auth? + ///////////////// + if(strncmp(peer->inputBuffer.buffer, "\\auth\\", 6) == 0) + { + // Get the pid. + /////////////// + if(!gpiValueForKey(peer->inputBuffer.buffer, "\\pid\\", intValue, sizeof(intValue))) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + pid = atoi(intValue); + + // Get the nick. + //////////////// + if(!gpiValueForKey(peer->inputBuffer.buffer, "\\nick\\", nick, sizeof(nick))) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + + // Get the sig. + /////////////// + if(!gpiValueForKey(peer->inputBuffer.buffer, "\\sig\\", sig, sizeof(sig))) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + + // Compute what the sig should be. + ////////////////////////////////// + sprintf(buffer, "%s%d%d", + iconnection->password, + iconnection->profileid, + pid); + MD5Digest((unsigned char *)buffer, strlen(buffer), sigCheck); + + // Check the sig. + ///////////////// + if(strcmp(sig, sigCheck) != 0) + { + // Bad sig. + /////////// + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\anack\\"); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\final\\"); + + gpiSendBufferToPeer(connection, peer->ip, peer->port, &peer->outputBuffer, &connClosed, GPITrue); + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + + // Send an ack. + /////////////// + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\aack\\"); + gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\final\\"); + + peer->state = GPI_PEER_CONNECTED; + peer->profile = (GPProfile)pid; + } + else + { + // Unrecognized command. + //////////////////////// + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + + // Update the buffer length. + //////////////////////////// + peer->inputBuffer.len = 0; + } + + return GP_NO_ERROR; +} + +GPResult +gpiPeerSendMessages( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIBool connClosed; + GPIMessage * message; + GPResult result; + + GS_ASSERT(peer); + if (!peer) + return GP_NETWORK_ERROR; + // Only send messages if there's nothing waiting in the output buffer. + ////////////////////////////////////////////////////////////////////// + if(peer->outputBuffer.len) + return GP_NO_ERROR; + + // Send outgoing messages. + ////////////////////////// + while(ArrayLength(peer->messages)) + { + // Get the first message. + ///////////////////////// + message = (GPIMessage *)ArrayNth(peer->messages, 0); + + // Send as much as possible. + //////////////////////////// + //result = gpiSendFromBuffer(connection, peer->sock, &message->buffer, &connClosed, GPIFalse, "PR"); + result = gpiSendBufferToPeer(connection, peer->ip, peer->port, &message->buffer, &connClosed, GPIFalse); + if(connClosed || (result != GP_NO_ERROR)) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + + // Did we not send it all? + ////////////////////////// + if(message->buffer.pos != message->buffer.len) + break; + + // Remove the message. + ////////////////////// + ArrayDeleteAt(peer->messages, 0); + } + + return GP_NO_ERROR; +} + +static GPResult +gpiProcessPeerConnected( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + //int len; + GSUdpPeerState aPeerState; + GPIBool connClosed; + GPICallback callback; + char * buffer; + int type; + int messageLen; + GPResult result; + + GS_ASSERT(peer); + if (!peer) + return GP_NETWORK_ERROR; + // Send stuff. + ////////////// + if(peer->outputBuffer.len) + { + //result = gpiSendFromBuffer(connection, peer->sock, &peer->outputBuffer, &connClosed, GPITrue, "PR"); + result = gpiSendBufferToPeer(connection, peer->ip, peer->port, &peer->outputBuffer, &connClosed, GPITrue); + if(connClosed || (result != GP_NO_ERROR)) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + } + + // Send outgoing messages. + ////////////////////////// + if(!peer->outputBuffer.len) + { + CHECK_RESULT(gpiPeerSendMessages(connection, peer)); + if(peer->state == GPI_PEER_DISCONNECTED) + return GP_NO_ERROR; + } + + // Read messages. + ///////////////// + /* + result = gpiRecvToBuffer(connection, peer->sock, &peer->inputBuffer, &len, &connClosed, "PR"); + if(result != GP_NO_ERROR) + { + peer->state = GPI_PEER_DISCONNECTED; + return GP_NO_ERROR; + } + */ + if(peer->inputBuffer.len > 0) + { + peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT); + } + + // Grab the message header. + /////////////////////////// + do + { + // Read a message. + ////////////////// + CHECK_RESULT(gpiReadMessageFromBuffer(connection, &peer->inputBuffer, &buffer, &type, &messageLen)); + if(buffer != NULL) + { + // Got a message! + ///////////////// + switch(type) + { + case GPI_BM_MESSAGE: + callback = iconnection->callbacks[GPI_RECV_BUDDY_MESSAGE]; + if(callback.callback != NULL) + { + GPRecvBuddyMessageArg * arg; + + arg = (GPRecvBuddyMessageArg *)gsimalloc(sizeof(GPRecvBuddyMessageArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->profile = peer->profile; +#ifndef GSI_UNICODE + arg->message = goastrdup(buffer); +#else + arg->message = UTF8ToUCS2StringAlloc(buffer); +#endif + arg->date = (unsigned int)time(NULL); + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_MESSAGE)); + } + break; + + case GPI_BM_UTM: + callback = iconnection->callbacks[GPI_RECV_BUDDY_UTM]; + if (callback.callback != NULL) + { + GPRecvBuddyUTMArg * arg; + + arg = (GPRecvBuddyUTMArg *)gsimalloc(sizeof(GPRecvBuddyUTMArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->profile = peer->profile; +#ifndef GSI_UNICODE + arg->message = goastrdup(buffer); +#else + arg->message = UTF8ToUCS2StringAlloc(buffer); +#endif + arg->date = (unsigned int)time(NULL); + CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_MESSAGE)); + } + break; + + case GPI_BM_PING: + // Send back a pong. + //////////////////// + gpiSendBuddyMessage(connection, peer->profile, GPI_BM_PONG, "1", 0, NULL); + + break; + +#ifndef NOFILE + case GPI_BM_PONG: + // Lets the transfers handle this. + ////////////////////////////////// + gpiTransfersHandlePong(connection, peer->profile, peer); + break; +#endif + case GPI_BM_KEYS_REQUEST: + CHECK_RESULT(gpiBuddyHandleKeyRequest(connection, peer)); + break; + case GPI_BM_KEYS_REPLY: + CHECK_RESULT(gpiBuddyHandleKeyReply(connection, peer, buffer)); + // Let the keys request reply handler take care of this. + //////////////////////////////////////////////////////// + break; + case GPI_BM_FILE_SEND_REQUEST: + case GPI_BM_FILE_SEND_REPLY: + case GPI_BM_FILE_BEGIN: + case GPI_BM_FILE_END: + case GPI_BM_FILE_DATA: + case GPI_BM_FILE_SKIP: + case GPI_BM_FILE_TRANSFER_THROTTLE: + case GPI_BM_FILE_TRANSFER_CANCEL: + case GPI_BM_FILE_TRANSFER_KEEPALIVE: + // Handle a transfer protocol message. + ////////////////////////////////////// + gpiHandleTransferMessage(connection, peer, type, peer->inputBuffer.buffer, buffer, messageLen); + + + break; + + default: + break; + } + + // Remove it from the buffer. + ///////////////////////////// + gpiClipBufferToPosition(connection, &peer->inputBuffer); + } + } + while(buffer); + + gsUdpEngineGetPeerState(peer->ip, peer->port, &aPeerState); + //if(connClosed) + if (aPeerState == GS_UDP_PEER_CLOSED) + peer->state = GPI_PEER_DISCONNECTED; + + return GP_NO_ERROR; +} + + +// Used to check for any timed out peer operations +// assumes peer is not NULL +// makes no assumption of the operation queue +void gpiCheckTimedOutPeerOperations(GPConnection * connection, GPIPeer *peer) +{ + GPIPeerOp *anIterator = peer->peerOpQueue.first; + GS_ASSERT(peer); + if (!peer) + return; + + while (anIterator && anIterator != peer->peerOpQueue.last) + { + if (anIterator->state != GPI_PEER_OP_STATE_FINISHED && current_time() > anIterator->timeout && anIterator->callback) + { + // currently only one type of peer operation exists + // when it's found, we need to provide the application with + // a result of no data + if (anIterator->type == GPI_BM_KEYS_REQUEST) + { + GPICallback callback; + GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg)); + callback.callback = anIterator->callback; + callback.param = anIterator->userData; + arg->keys = NULL; + arg->numKeys = 0; + arg->values = NULL; + arg->profile = peer->profile; + gpiAddCallback(connection, callback, arg, NULL, 0); + + } + // The peer operation is removed regardless of type + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer operation timed out"); + gpiPeerRemoveOp(peer, anIterator); + } + anIterator = anIterator->next; + } +} + + +static GPResult +gpiProcessPeer( + GPConnection * connection, + GPIPeer * peer +) +{ + GPResult result = GP_NO_ERROR; + + // This state should never get out of initialization. + ///////////////////////////////////////////////////// + GS_ASSERT(peer->state != GPI_PEER_NOT_CONNECTED); + if (peer->state == GPI_PEER_NOT_CONNECTED) + return GP_NETWORK_ERROR; + + // If we're not connected yet. + ////////////////////////////// + if(peer->state != GPI_PEER_CONNECTED) + { + if(peer->initiated) + result = gpiProcessPeerInitiatingConnection(connection, peer); + else + result = gpiProcessPeerAcceptingConnection(connection, peer); + } + + // If we're connected. + ////////////////////// + if((result == GP_NO_ERROR) && (peer->state == GPI_PEER_CONNECTED)) + { + result = gpiProcessPeerConnected(connection, peer); + gpiCheckTimedOutPeerOperations(connection, peer); + } + + return result; +} + +void +gpiDestroyPeer( + GPConnection * connection, + GPIPeer * peer +) +{ +#ifndef NOFILE + // Cleanup any transfers that use this peer. + //////////////////////////////////////////// + gpiTransferPeerDestroyed(connection, peer); +#endif + + //shutdown(peer->sock, 2); + //closesocket(peer->sock); + freeclear(peer->inputBuffer.buffer); + freeclear(peer->outputBuffer.buffer); + if(peer->messages) + { + ArrayFree(peer->messages); + peer->messages = NULL; + } + freeclear(peer); + + GSI_UNUSED(connection); +} + +void +gpiRemovePeer( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIPeer * pprev; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIMessage * message; + + GS_ASSERT(peer != NULL); + if (peer == NULL) + return; + + GS_ASSERT(iconnection->peerList); + if (iconnection->peerList == NULL) + return; + // Check if this is the first peer. + /////////////////////////////////// + if(iconnection->peerList == peer) + { + iconnection->peerList = peer->pnext; + } + else + { + // Find the previous peer. + ////////////////////////// + for(pprev = iconnection->peerList ; pprev->pnext != peer ; pprev = pprev->pnext) + { + if(pprev->pnext == NULL) + { + // Can't find this peer in the list! + //////////////////////////////////// + assert(0); + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Tried to remove peer not in list."); + return; + } + } + pprev->pnext = peer->pnext; + } + + // Check for pending messages. + ////////////////////////////// + while(ArrayLength(peer->messages)) + { + // Get the next message. + //////////////////////// + message = (GPIMessage *)ArrayNth(peer->messages, 0); + + // Don't forward protocol messages. + /////////////////////////////////// + if(message->type < 100) + gpiSendServerBuddyMessage(connection, peer->profile, message->type, message->buffer.buffer + message->start); + + // Remove the message. + ////////////////////// + ArrayDeleteAt(peer->messages, 0); + } + + gpiDestroyPeer(connection, peer); +} + +GPResult gpiProcessPeers(GPConnection *connection) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIPeer * nextPeer; + GPIPeer * peer; + //SOCKET incoming; + GPResult result; + + /* + // Check for incoming peer connections. + /////////////////////////////////////// + if(iconnection->peerSocket != INVALID_SOCKET) + { + // Have to manually check if accept is possible since + // PS2 Insock only supports blocking sockets. + if (CanReceiveOnSocket(iconnection->peerSocket)) + { + incoming = accept(iconnection->peerSocket, NULL, NULL); + if(incoming != INVALID_SOCKET) + { + // This is a new peer. + ////////////////////// + peer = gpiAddPeer(connection, -1, GPIFalse); + if(peer) + { + peer->state = GPI_PEER_WAITING; + peer->sock = incoming; + SetSockBlocking(incoming, 0); + gpiSetPeerSocketSizes(peer->sock); + } + else + { + closesocket(incoming); + } + } + } + } + */ + gsUdpEngineThink(); + // Got through the list of peers. + ///////////////////////////////// + for(peer = iconnection->peerList ; peer != NULL ; peer = nextPeer) + { + // Store the next peer. + /////////////////////// + nextPeer = peer->pnext; + if(peer->state == GPI_PEER_DISCONNECTED) + { + // Remove it. + ///////////// + //gsDebug + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer disconnected, pid: %d", peer->profile); + gpiRemovePeer(connection, peer); + } + else + { + // Process the peer. + //////////////////// + result = gpiProcessPeer(connection, peer); + + // Check for a disconnection or a timeout. + ////////////////////////////////////////// + if((peer->state == GPI_PEER_DISCONNECTED) || (result != GP_NO_ERROR) || (time(NULL) > peer->timeout)) + { + // Remove it. + ///////////// + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer disconnected, pid: %d", peer->profile); + gpiRemovePeer(connection, peer); + } + } + } + + return GP_NO_ERROR; +} + +// NOTE: use this function when in a gp function +GPIPeer * gpiGetPeerByProfile(const GPConnection * connection, + int profileid) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIPeer * pcurr; + + // Go through the list of peers. + //////////////////////////////// + for(pcurr = iconnection->peerList ; pcurr != NULL ; pcurr = pcurr->pnext) + { + // Check for a match. + ///////////////////// + if(pcurr->profile == profileid) + { + // Got it. + ////////// + return pcurr; + } + } + + return NULL; +} + +// NOTE: use this function only when in a UDP layer callback +GPIPeer * gpiGetPeerByAddr(const GPConnection *connection, + unsigned int ip, + unsigned short port) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIPeer * pcurr; + + GS_ASSERT(ip); + GS_ASSERT(port); + if (!ip && !port) + return NULL; + // Go through the list of peers. + //////////////////////////////// + for(pcurr = iconnection->peerList ; pcurr != NULL ; pcurr = pcurr->pnext) + { + // Check for a match. + ///////////////////// + if(pcurr->ip == ip && pcurr->port == port) + { + // Got it. + ////////// + return pcurr; + } + } + + return NULL; +} + +gsi_bool gpiIsPeerConnected(GPIPeer *peer) +{ + GS_ASSERT(peer); + if (!peer) + return gsi_false; + + if (peer && peer->state != GPI_PEER_CONNECTED) + return gsi_false; + + return gsi_true; +} + +static void gpiFreeMessage(void * elem) +{ + GPIMessage * message = (GPIMessage *)elem; + + freeclear(message->buffer.buffer); +} + +GPIPeer * +gpiAddPeer( + GPConnection * connection, + int profileid, + GPIBool initiate +) +{ + GPIPeer * peer; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Create a new peer. + ///////////////////// + peer = (GPIPeer *)gsimalloc(sizeof(GPIPeer)); + if(peer == NULL) + return NULL; + memset(peer, 0, sizeof(GPIPeer)); + peer->state = GPI_PEER_NOT_CONNECTED; + peer->initiated = initiate; + //peer->sock = INVALID_SOCKET; + peer->profile = profileid; + peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT); + peer->pnext = iconnection->peerList; + peer->messages = ArrayNew(sizeof(GPIMessage), 0, gpiFreeMessage); + iconnection->peerList = peer; + peer->peerOpQueue.first = NULL; + peer->peerOpQueue.last = NULL; + peer->peerOpQueue.opList = NULL; + return peer; +} + +GPResult +gpiPeerGetSig( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIOperation * operation; + + // Start a get info operation to get the sig. + ///////////////////////////////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_GET_INFO, NULL, &operation, GP_NON_BLOCKING, NULL, NULL)); + + // Send the get info. + ///////////////////// + CHECK_RESULT(gpiSendGetInfo(connection, peer->profile, operation->id)); + + // Set the state. + ///////////////// + peer->state = GPI_PEER_GETTING_SIG; + + return GP_NO_ERROR; +} + +GPResult +gpiPeerStartConnect( + GPConnection * connection, + GPIPeer * peer +) +{ + //int rcode; + //struct sockaddr_in address; + GPIProfile * profile; + GPIConnection * iconnection = (GPIConnection*)*connection; + GSUdpErrorCode anError; + + // Get the profile object. + ////////////////////////// + if(!gpiGetProfile(connection, peer->profile, &profile)) + Error(connection, GP_NETWORK_ERROR, "Error connecting to a peer."); + + /* + // Create the socket. + ///////////////////// + peer->sock = socket(AF_INET, SOCK_STREAM, 0); + if(peer->sock == INVALID_SOCKET) + CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error creating a socket."); + + // Make it non-blocking. + //////////////////////// + rcode = SetSockBlocking(peer->sock, 0); + if(rcode == 0) + CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error making a socket non-blocking."); + + // Bind the socket. + /////////////////// + +// BD: PS2 Insock has bug with binding to port 0 +// No sockets after the first will be able to bind + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + rcode = bind(peer->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if (gsiSocketIsError(rcode)) + CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error binding a socket."); + + // Set the socket sizes. + //////////////////////// + gpiSetPeerSocketSizes(peer->sock); + + // Connect the socket. + ////////////////////// + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = profile->buddyStatus->ip; + address.sin_port = (gsi_u16)profile->buddyStatus->port; + rcode = connect(peer->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if (gsiSocketIsError(rcode)) + { + int error = GOAGetLastError(peer->sock); + if((error != WSAEWOULDBLOCK) && (error != WSAEINPROGRESS) && (error != WSAETIMEDOUT) ) + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error connecting a socket."); + } + } + */ + + if (profile->buddyStatusInfo) + { + GSUdpPeerState aPeerState; + gsUdpEngineGetPeerState(profile->buddyStatusInfo->buddyIp , profile->buddyStatusInfo->buddyPort, &aPeerState); + if (aPeerState != GS_UDP_PEER_CONNECTED || aPeerState != GS_UDP_PEER_CONNECTING) + { + anError = gsUdpEngineStartTalkingToPeer(profile->buddyStatusInfo->buddyIp , profile->buddyStatusInfo->buddyPort, + iconnection->mHeader, GPI_PEER_TIMEOUT); + if (anError != GS_UDP_ADDRESS_ALREADY_IN_USE) + CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error starting communication with a peer."); + } + peer->ip = profile->buddyStatusInfo->buddyIp; + peer->port = profile->buddyStatusInfo->buddyPort; + } + // We're waiting for the connect to complete. + ///////////////////////////////////////////// + peer->state = GPI_PEER_CONNECTING; + + return GP_NO_ERROR; +} + +GPResult +gpiPeerAddMessage( + GPConnection * connection, + GPIPeer * peer, + int type, + const char * message +) +{ + GPIMessage gpiMessage; + int len; + + GS_ASSERT(peer != NULL); + GS_ASSERT(message != NULL); + + if (peer == NULL) + return GP_NETWORK_ERROR; + if (message == NULL) + return GP_NETWORK_ERROR; + + // Get the length. + ////////////////// + len = (int)strlen(message); + + // Clear the message. + ///////////////////// + memset(&gpiMessage, 0, sizeof(GPIMessage)); + + // Copy the type. + ///////////////// + gpiMessage.type = type; + + // Copy the header to the buffer. + ///////////////////////////////// + CHECK_RESULT(gpiAppendStringToBuffer(connection, &gpiMessage.buffer, "\\m\\")); + CHECK_RESULT(gpiAppendIntToBuffer(connection, &gpiMessage.buffer, type)); + CHECK_RESULT(gpiAppendStringToBuffer(connection, &gpiMessage.buffer, "\\len\\")); + CHECK_RESULT(gpiAppendIntToBuffer(connection, &gpiMessage.buffer, len)); + CHECK_RESULT(gpiAppendStringToBuffer(connection, &gpiMessage.buffer, "\\msg\\\n")); + + // Copy the message to the buffer. + ////////////////////////////////// + gpiMessage.start = gpiMessage.buffer.len; + CHECK_RESULT(gpiAppendStringToBufferLen(connection, &gpiMessage.buffer, message, len)); + CHECK_RESULT(gpiAppendCharToBuffer(connection, &gpiMessage.buffer, '\0')); + + // Add it to the list. + ////////////////////// + ArrayAppend(peer->messages, &gpiMessage); + + // Reset the timeout. + ///////////////////// + peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT); + + return GP_NO_ERROR; +} + +GPResult +gpiPeerStartTransferMessage( + GPConnection * connection, + GPIPeer * peer, + int type, + const struct GPITransferID_s * transferID +) +{ + char buffer[64]; + GPITransferID tid; + tid.count = transferID->count; + tid.profileid = transferID->profileid; + tid.time = transferID->time; + + GS_ASSERT(transferID); + if (!transferID) + return GP_NETWORK_ERROR; + // Start the message. + ///////////////////// + sprintf(buffer, "\\m\\%d\\xfer\\%d %u %u", type, tid.profileid, tid.count, tid.time); + + return gpiSendOrBufferString(connection, peer, buffer); +} + +GPResult +gpiPeerFinishTransferMessage( + GPConnection * connection, + GPIPeer * peer, + const char * message, + int len +) +{ + char buffer[32]; + GS_ASSERT(peer != NULL); + if (!peer) + return GP_NETWORK_ERROR; + + // Check the message. + ///////////////////// + if(!message) + message = ""; + + if(len == -1) + len = (int)strlen(message); + + // Set the len and the message. + /////////////////////////////// + sprintf(buffer, "\\len\\%d\\msg\\\n", len); + CHECK_RESULT(gpiSendOrBufferString(connection, peer, buffer)); + + // Copy the message to the buffer. + ////////////////////////////////// + CHECK_RESULT(gpiSendOrBufferStringLenToPeer(connection, peer, message, len)); + CHECK_RESULT(gpiSendOrBufferChar(connection, peer, '\0')); + + // Reset the timeout. + ///////////////////// + peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT); + + return GP_NO_ERROR; +} + +void gpiPeerLeftCallback(unsigned int ip, unsigned short port, GSUdpCloseReason reason, void *userData) +{ + + GPConnection *connection = (GPConnection *)userData; + GPIPeer *aPeer; + IN_ADDR anAddr; + anAddr.s_addr = ip; + aPeer = gpiGetPeerByAddr(connection, ip, port); + //gpiRemovePeer(connection, aPeer); + if (aPeer) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, + "Peer left: addr: %s:%d, profile: %d\n", inet_ntoa(anAddr), port, aPeer->profile); + aPeer->state = GPI_PEER_DISCONNECTED; + } + + GSI_UNUSED(anAddr); + GSI_UNUSED(reason); +} + +void gpiPeerMessageCallback(unsigned int ip, unsigned short port, unsigned char *message, + unsigned int messageLength, gsi_bool reliable, void *userData) +{ + GPConnection *connection = (GPConnection *)userData; + GPIPeer *aPeer; + unsigned char * buff; + int writePos; + int size; + IN_ADDR anAddr; + anAddr.s_addr = ip; + aPeer = gpiGetPeerByAddr(connection, ip, port); + if (!aPeer) + { + aPeer = gpiAddPeer(connection, -1, GPIFalse); + if (aPeer) + { + aPeer->state = GPI_PEER_WAITING; + aPeer->ip = ip; + aPeer->port = port; + } + else + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_HotError, + "gpiPeerMessageCallback: out of memory when allocating peer, addr: %s:%d", inet_ntoa(anAddr), port); + return; + } + } + + buff = (unsigned char *)aPeer->inputBuffer.buffer; + writePos = aPeer->inputBuffer.len; + size = aPeer->inputBuffer.size; + + // Check if the buffer needs to be resized. + /////////////////////////////////////////// + if((int)messageLength > (size - writePos)) + { + unsigned char *reallocedBuff; + size = (writePos + max(GPI_READ_SIZE,(int)messageLength)); + reallocedBuff = (unsigned char *)gsirealloc(buff, (unsigned int)size + 1); + if(reallocedBuff == NULL) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_HotError, + "gpiPeerMessageCallback: out of memory when reallocating buffer, addr: %s:%d", inet_ntoa(anAddr), port); + gsifree(buff); + gpiSetErrorString(connection, "Out of memory."); + gpiCallErrorCallback(connection, GP_MEMORY_ERROR, GP_NON_FATAL); + return; + } + else + buff = reallocedBuff; + } + + memcpy(&buff[writePos], message, messageLength); + + aPeer->inputBuffer.buffer = (char *)buff; + aPeer->inputBuffer.len += messageLength; + aPeer->inputBuffer.size = size; + buff[aPeer->inputBuffer.len] = '\0'; + GSI_UNUSED(reliable); + GSI_UNUSED(anAddr); +} + +void gpiPeerAcceptedCallback(unsigned int ip, unsigned short port, + GSUdpErrorCode error, gsi_bool rejected, void *userData) +{ + GPConnection *connection = (GPConnection *)userData; + GPIPeer *aPeer; + IN_ADDR anAddr; + anAddr.s_addr = ip; + + aPeer = gpiGetPeerByAddr(connection, ip, port); + if (!aPeer) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, + "Peer does not exist: ip-port: %s:%d\n", inet_ntoa(anAddr), port); + } + else + { + if (rejected) + { + aPeer->state = GPI_PEER_DISCONNECTED; + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, + "Peer Connection rejected: ip-port: %s:%d\n", inet_ntoa(anAddr), port); + return; + } + } + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, + "Peer Connection accepted: ip-port: %s:%d\n", inet_ntoa(anAddr), port); + + GSI_UNUSED(userData); + GSI_UNUSED(rejected); + GSI_UNUSED(error); + GSI_UNUSED(anAddr); +} +void gpiPeerPingReplyCallback(unsigned int ip, unsigned short port, unsigned int latency, void *userData) +{ + GSI_UNUSED(userData); + GSI_UNUSED(latency); + GSI_UNUSED(port); + GSI_UNUSED(ip); +} + +// gpiPeerAddOp notes: +// Assumes non-null inputs! +// The queue should be empty when the first element is added. +// Any new element added will be added to the end of the queue. +void gpiPeerAddOp(GPIPeer *peer, GPIPeerOp *operation) +{ + GS_ASSERT(peer); + GS_ASSERT(operation); + + if (!peer || !operation) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, "Peer operation not added"); + return; + } + // Three cases can occur: + // The list is empty - set all pointers to the new node + // The list has only one element - set the first element's next to the new + // and set the last element to the new + // The list has more than one element - add the new element to the end of + // the queue + if (peer->peerOpQueue.opList == NULL) + { + peer->peerOpQueue.first = operation; + peer->peerOpQueue.last = operation; + peer->peerOpQueue.opList = operation; + } + else if (peer->peerOpQueue.first == peer->peerOpQueue.last) + { + peer->peerOpQueue.first->next = operation; + peer->peerOpQueue.last = operation; + } + else + { + peer->peerOpQueue.last->next = operation; + peer->peerOpQueue.last = operation; + } + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer Operation Added"); +} + +// gpiPeerRemoveOp: +// Assumes the list is NOT NULL otherwise it returns. +// Assumes the operation being passed in is on the queue. +// Assumes non-null inputs! +// Completed or Timed out Operations are deleted from queue by finding +// the operation passed in. Removal of operations don't necessarily +// happen in order. +void gpiPeerRemoveOp(GPIPeer *peer, GPIPeerOp *operation) +{ + GS_ASSERT(peer); + GS_ASSERT(operation); + if (!peer || !operation) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, "Peer operation not removed"); + return; + } + + GS_ASSERT(peer->peerOpQueue.opList != NULL); + if (peer->peerOpQueue.opList == NULL) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, "Peer operation not removed"); + return; + } + + if (peer->peerOpQueue.first == peer->peerOpQueue.last && peer->peerOpQueue.first == operation) + { + peer->peerOpQueue.opList = peer->peerOpQueue.first = peer->peerOpQueue.last = operation->next; + } + else if (peer->peerOpQueue.first == operation) + { + peer->peerOpQueue.first = peer->peerOpQueue.first->next; + peer->peerOpQueue.opList = peer->peerOpQueue.first; + } + else + { + GPIPeerOp *aPrevOp = NULL; + for(aPrevOp = peer->peerOpQueue.first ; aPrevOp->next != operation ; aPrevOp = aPrevOp->next) + { + if(aPrevOp->next == NULL) + { + // Can't find this peer in the list! + //////////////////////////////////// + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Tried to remove peer operation not in list."); + return; + } + } + aPrevOp->next = operation->next; + } + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer operation removed"); + freeclear(operation); +} diff --git a/xrGameSpy/gamespy/GP/gpiPeer.h b/xrGameSpy/gamespy/GP/gpiPeer.h new file mode 100644 index 00000000000..8e864b9e2c9 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiPeer.h @@ -0,0 +1,186 @@ +/* +gpiPeer.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIPEER_H_ +#define _GPIPEER_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +// Peer states. +/////////////// +#define GPI_PEER_NOT_CONNECTED 100 +#define GPI_PEER_GETTING_SIG 101 +#define GPI_PEER_GOT_SIG 102 +#define GPI_PEER_CONNECTING 103 +#define GPI_PEER_WAITING 104 +#define GPI_PEER_CONNECTED 105 +#define GPI_PEER_DISCONNECTED 106 + +// Timeout for a peer connection, in milliseconds. +///////////////////////////////////////////// +#define GPI_PEER_TIMEOUT (10 * 1000) + +// Timeout for a peer operation, in milliseconds +//////////////////////////////////////////// +#define GPI_PEER_OP_TIMEOUT 60000 + +typedef enum +{ + GPI_PEER_OP_STATE_NONE, + GPI_PEER_OP_STATE_REQUESTED, + GPI_PEER_OP_STATE_FINISHED +} GPIPeerOpState; + +typedef struct GPITransferID_s * GPITransferID_st; + +//TYPES +/////// +// A peer message. +////////////////// +typedef struct GPIMessage +{ + GPIBuffer buffer; + int type; + int start; +} GPIMessage; + +typedef struct _GPIPeerOp +{ + GPIPeerOpState state; + void *userData; + GPCallback callback; + struct _GPIPeerOp * next; + int type; + gsi_time timeout; +} GPIPeerOp; + +typedef struct _GPIPeerOpQueue +{ + GPIPeerOp * opList; + GPIPeerOp * first; + GPIPeerOp * last; +} GPIPeerOpQueue; + +// A peer connection. +///////////////////// +typedef struct GPIPeer_s +{ + int state; + GPIBool initiated; + //SOCKET sock; + unsigned int ip; + unsigned short port; + GPProfile profile; + time_t timeout; + int nackCount; + GPIBuffer inputBuffer; + GPIBuffer outputBuffer; + DArray messages; + GPIPeerOpQueue peerOpQueue; + struct GPIPeer_s * pnext; +} GPIPeer; + +//FUNCTIONS +/////////// +GPResult +gpiProcessPeers( + GPConnection * connection +); + +GPResult +gpiPeerGetSig( + GPConnection * connection, + GPIPeer * peer +); + +GPResult +gpiPeerStartConnect( + GPConnection * connection, + GPIPeer * peer +); + +// NOTE: use this function when in a gp function +GPIPeer * gpiGetPeerByProfile(const GPConnection * connection, + int profileid); + +// NOTE: use this function only when in a UDP layer callback +GPIPeer *gpiGetPeerByAddr(const GPConnection *connection, + unsigned int ip, + unsigned short port); + +gsi_bool gpiIsPeerConnected(GPIPeer *peer); + +GPIPeer * +gpiAddPeer( + GPConnection * connection, + int profileid, + GPIBool initiate +); + +void +gpiDestroyPeer( + GPConnection * connection, + GPIPeer * peer +); + +void +gpiRemovePeer( + GPConnection * connection, + GPIPeer * peer +); + +GPResult +gpiPeerAddMessage( + GPConnection * connection, + GPIPeer * peer, + int type, + const char * message +); + +GPResult +gpiPeerStartTransferMessage( + GPConnection * connection, + GPIPeer * peer, + int type, + const struct GPITransferID_s * transferID +); + +GPResult +gpiPeerFinishTransferMessage( + GPConnection * connection, + GPIPeer * peer, + const char * message, + int len +); + +GPResult +gpiPeerSendMessages( + GPConnection * connection, + GPIPeer * peer +); + +void gpiPeerLeftCallback(unsigned int ip, unsigned short port, GSUdpCloseReason reason, void *userData); +void gpiPeerMessageCallback(unsigned int ip, unsigned short port, unsigned char *message, + unsigned int messageLength, gsi_bool reliable, void *userData); +void gpiPeerAcceptedCallback(unsigned int ip, unsigned short port, + GSUdpErrorCode error, gsi_bool rejected, void *userData); +void gpiPeerPingReplyCallback(unsigned int ip, unsigned short port, unsigned int latency, void *userData); + +void gpiPeerAddOp(GPIPeer *peer, GPIPeerOp *operation); +void gpiPeerRemoveOp(GPIPeer *peer, GPIPeerOp *operation); +void gpiCheckTimedOutPeerOperations(GPConnection * connection, GPIPeer * peer); +#endif diff --git a/xrGameSpy/gamespy/GP/gpiProfile.c b/xrGameSpy/gamespy/GP/gpiProfile.c new file mode 100644 index 00000000000..16004391925 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiProfile.c @@ -0,0 +1,1396 @@ +/* +gpiProfile.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4312) //lines: 1164, 1186, 1265 +#pragma warning(disable: 4311) //lines: 1231 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +#define GPI_PROFILE_GROW_SIZE 16 +#define GPI_PROFILE_CACHE_VERSION 2 + +// GLOBALS +////////// +static char GPIInfoCacheFilename[FILENAME_MAX + 1] = "gp.info"; + +//FUNCTIONS +/////////// +static int +gpiProfilesTableHash( + const void *arg, + int numBuckets +) +{ + const GPIProfile * profile = (const GPIProfile *)arg; + return (profile->profileId % numBuckets); +} + +static int +gpiProfilesTableCompare( + const void * arg1, + const void * arg2 +) +{ + const GPIProfile * profile1 = (const GPIProfile *)arg1; + const GPIProfile * profile2 = (const GPIProfile *)arg2; + return (profile1->profileId - profile2->profileId); +} + +static void +gpiProfilesTableFree( + void *arg +) +{ + GPIProfile * profile = (GPIProfile *)arg; + if(profile->buddyStatus) + { + freeclear(profile->buddyStatus->statusString); + freeclear(profile->buddyStatus->locationString); + freeclear(profile->buddyStatus); + } + if (profile->buddyStatusInfo) + { + freeclear(profile->buddyStatusInfo->richStatus); + freeclear(profile->buddyStatusInfo->gameType); + freeclear(profile->buddyStatusInfo->gameVariant); + freeclear(profile->buddyStatusInfo->gameMapName); + if (profile->buddyStatusInfo->extendedInfoKeys) + { + ArrayFree(profile->buddyStatusInfo->extendedInfoKeys); + profile->buddyStatusInfo->extendedInfoKeys = NULL; + } + freeclear(profile->buddyStatusInfo); + } + gpiFreeInfoCache(profile); + freeclear(profile->authSig); + freeclear(profile->peerSig); +} + +GPIBool +gpiInitProfiles( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + iconnection->profileList.numBuddies = 0; + iconnection->profileList.numBlocked = 0; + iconnection->profileList.num = 0; + iconnection->profileList.profileTable = TableNew( + sizeof(GPIProfile), + 32, + gpiProfilesTableHash, + gpiProfilesTableCompare, + gpiProfilesTableFree); + if(!iconnection->profileList.profileTable) + return GPIFalse; + + return GPITrue; +} + +#ifndef NOFILE + +static GPResult +gpiOpenDiskProfiles( + GPConnection * connection, + GPIBool write, + GPIBool * failed +) +{ + FILE * fp = NULL; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Open the file. + ///////////////// + if(write) + fp = fopen(GPIInfoCacheFilename, "wt"); + else + fp = fopen(GPIInfoCacheFilename, "rt"); + if(fp == NULL) + { + *failed = GPITrue; + return GP_NO_ERROR; + } + + // Excellent. + ///////////// + iconnection->diskCache = fp; + *failed = GPIFalse; + + return GP_NO_ERROR; + + GSI_UNUSED(write); +} + +static void +gpiCloseDiskProfiles( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Close the file. + ////////////////// + fclose(iconnection->diskCache); + iconnection->diskCache = NULL; + + return; +} + +static GPResult +gpiReadDiskKeyValue( + GPConnection * connection, + GPIBool * failed, + char key[512], + char value[512] +) +{ + int c; + FILE * fp; + GPIConnection * iconnection = (GPIConnection*)*connection; + int i; + + // Grab the file pointer. + ///////////////////////// + fp = iconnection->diskCache; + + // Read the key. + //////////////// + i = 0; + do + { + if(i == 512) + { + *failed = GPITrue; + return GP_NO_ERROR; + } + c = fgetc(fp); + if((c == EOF) || (c == '\n')) + { + *failed = GPITrue; + return GP_NO_ERROR; + } + key[i++] = (char)c; + } + while(c != '='); + key[--i] = '\0'; + + // Check for no key. + //////////////////// + if(i == 0) + { + *failed = GPITrue; + return GP_NO_ERROR; + } + + // Read the value. + ////////////////// + i = 0; + do + { + if(i == 512) + { + *failed = GPITrue; + return GP_NO_ERROR; + } + c = fgetc(fp); + if(c == EOF) + { + c = '\n'; + } + value[i++] = (char)c; + } + while(c != '\n'); + value[--i] = '\0'; + + // Done. + //////// + *failed = GPIFalse; + return GP_NO_ERROR; + + GSI_UNUSED(value); + GSI_UNUSED(key); + GSI_UNUSED(connection); +} + +static GPResult +gpiReadDiskProfile( + GPConnection * connection, + GPIBool * failedOut +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + FILE * fp; + GPIProfile profile; + int c; + int rcode; + GPIBool failed; + char key[256]; + char value[256]; + GPIInfoCache infoCache; + GPIBool valid = GPIFalse; + GPIProfile * pProfile; + char nick[GP_NICK_LEN]; + char uniquenick[GP_UNIQUENICK_LEN]; + char email[GP_EMAIL_LEN]; + char firstname[GP_FIRSTNAME_LEN]; + char lastname[GP_LASTNAME_LEN]; + char homepage[GP_HOMEPAGE_LEN]; + char aimname[GP_AIMNAME_LEN]; + + // Grab the file pointer. + ///////////////////////// + fp = iconnection->diskCache; + + // Clear the temp profile. + ////////////////////////// + memset(&profile, 0, sizeof(GPIProfile)); + + // Clear the temp cache. + //////////////////////// + memset(&infoCache, 0, sizeof(GPIInfoCache)); + infoCache.nick = nick; + infoCache.uniquenick = uniquenick; + infoCache.email = email; + infoCache.firstname = firstname; + infoCache.lastname = lastname; + infoCache.homepage = homepage; + infoCache.aimname = aimname; + nick[0] = '\0'; + uniquenick[0] = '\0'; + email[0] = '\0'; + firstname[0] = '\0'; + lastname[0] = '\0'; + homepage[0] = '\0'; + aimname[0] = '\0'; + + // Read until we hit a [. + ///////////////////////// + do + { + c = fgetc(fp); + if(c == EOF) + { + *failedOut = GPITrue; + return GP_NO_ERROR; + } + } + while(c != '['); + + // Grab the profileid. + ////////////////////// + rcode = fscanf(fp, "%d]\n", &profile.profileId); + if(rcode != 1) + { + *failedOut = GPITrue; + return GP_NO_ERROR; + } + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_Comment, + "Reading profile %d from disk cache:\n", profile.profileId); + + // Read key/value pairs. + //////////////////////// + do + { + CHECK_RESULT(gpiReadDiskKeyValue(connection, &failed, key, value)); + if(!failed) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_Comment, + "%d: %s=%s\n", profile.profileId, key, value); + + // Set the data based on the key. + ///////////////////////////////// + if(strcmp(key, "userid") == 0) + { + profile.userId = atoi(value); + } + else if(strcmp(key, "nick") == 0) + { + strzcpy(infoCache.nick, value, GP_NICK_LEN); + } + else if(strcmp(key, "uniquenick") == 0) + { + strzcpy(infoCache.uniquenick, value, GP_UNIQUENICK_LEN); + } + else if(strcmp(key, "email") == 0) + { + strzcpy(infoCache.email, value, GP_EMAIL_LEN); + } + else if(strcmp(key, "firstname") == 0) + { + strzcpy(infoCache.firstname, value, GP_FIRSTNAME_LEN); + } + else if(strcmp(key, "lastname") == 0) + { + strzcpy(infoCache.lastname, value, GP_LASTNAME_LEN); + } + else if(strcmp(key, "homepage") == 0) + { + strzcpy(infoCache.homepage, value, GP_HOMEPAGE_LEN); + } + else if(strcmp(key, "icquin") == 0) + { + infoCache.icquin = atoi(value); + } + else if(strcmp(key, "zipcode") == 0) + { + strzcpy(infoCache.zipcode, value, GP_ZIPCODE_LEN); + } + else if(strcmp(key, "countrycode") == 0) + { + strzcpy(infoCache.countrycode, value, GP_COUNTRYCODE_LEN); + } + else if(strcmp(key, "birthday") == 0) + { + infoCache.birthday = atoi(value); + } + else if(strcmp(key, "birthmonth") == 0) + { + infoCache.birthmonth = atoi(value); + } + else if(strcmp(key, "birthyear") == 0) + { + infoCache.birthyear = atoi(value); + } + else if(strcmp(key, "sex") == 0) + { + if(toupper(value[0]) == 'M') + infoCache.sex = GP_MALE; + else if(toupper(value[1] == 'F')) + infoCache.sex = GP_FEMALE; + else + infoCache.sex = GP_PAT; + } + else if(strcmp(key, "publicmask") == 0) + { + infoCache.publicmask = atoi(value); + } + else if(strcmp(key, "aimname") == 0) + { + strzcpy(infoCache.aimname, value, GP_AIMNAME_LEN); + } + else if(strcmp(key, "pic") == 0) + { + infoCache.pic = atoi(value); + } + else if(strcmp(key, "occupationid") == 0) + { + infoCache.occupationid = atoi(value); + } + else if(strcmp(key, "industryid") == 0) + { + infoCache.industryid = atoi(value); + } + else if(strcmp(key, "incomeid") == 0) + { + infoCache.incomeid = atoi(value); + } + else if(strcmp(key, "marriedid") == 0) + { + infoCache.marriedid = atoi(value); + } + else if(strcmp(key, "childcount") == 0) + { + infoCache.childcount = atoi(value); + } + else if(strcmp(key, "interests1") == 0) + { + infoCache.interests1 = atoi(value); + } + else if(strcmp(key, "ownership1") == 0) + { + infoCache.ownership1 = atoi(value); + } + else if(strcmp(key, "conntypeid") == 0) + { + infoCache.conntypeid = atoi(value); + } + else if(strcmp(key, "valid") == 0) + { + valid = (GPIBool)atoi(value); + } + else + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_HotError, + "Unrecognized profile key: %s=%s\n", key, value); + } + } + } + while(!failed); + + // Create a new profile. + //////////////////////// + pProfile = gpiProfileListAdd(connection, profile.profileId); + if(pProfile) + { + // Copy the profile we've set up into the list. + /////////////////////////////////////////////// + *pProfile = profile; + + // Copy the info if valid. + ////////////////////////// + if(valid) + gpiSetInfoCache(connection, pProfile, &infoCache); + } + *failedOut = GPIFalse; + return GP_NO_ERROR; + + GSI_UNUSED(connection); +} + +static GPResult +gpiReadVersion( + const GPConnection * connection, + int * version +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + FILE * fp; + + // Grab the file pointer. + ///////////////////////// + fp = iconnection->diskCache; + + // Read the version. + //////////////////// + if(fscanf(fp, "%d\n", version) != 1) + *version = 0; + + return GP_NO_ERROR; + + GSI_UNUSED(connection); + GSI_UNUSED(version); +} + +static void +gpiWriteVersion( + GPConnection * connection, + int version +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + FILE * fp; + + // Grab the file pointer. + ///////////////////////// + fp = iconnection->diskCache; + + // Write the version. + ///////////////////// + fprintf(fp, "%d\n", version); + + GSI_UNUSED(connection); + GSI_UNUSED(version); +} + +GPResult +gpiLoadDiskProfiles( + GPConnection * connection +) +{ + GPIBool failed; + int count; + int version = 0; + + // Open the disk cache. + /////////////////////// + CHECK_RESULT(gpiOpenDiskProfiles(connection, GPIFalse, &failed)); + if(failed) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_HotError, + "Failed to open the disk cache file.\n"); + return GP_NO_ERROR; + } + + // Check the version. + ////////////////////// + CHECK_RESULT(gpiReadVersion(connection, &version)); + if(version == GPI_PROFILE_CACHE_VERSION) + { + // Read profiles. + ///////////////// + count = 0; + do + { + CHECK_RESULT(gpiReadDiskProfile(connection, &failed)); + if(!failed) + count++; + } + while(!failed); + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_Comment, + "Loaded %d profiles from disk cache.\n", count); + } + + // Close the cache. + /////////////////// + gpiCloseDiskProfiles(connection); + + return GP_NO_ERROR; +} + +static GPIBool +gpiSaveDiskProfile( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ + FILE * fp; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Grab the file pointer. + ///////////////////////// + fp = iconnection->diskCache; + + // Write the profile id. + //////////////////////// + fprintf(fp, "[%d]\n", profile->profileId); + + // Write the userid if not 0. + ///////////////////////////// + if(profile->userId != 0) + fprintf(fp, "userid=%d\n", profile->userId); + + // Is the cache valid? + ////////////////////// + if(profile->cache) + { + fprintf(fp, "valid=1\n"); + + fprintf(fp, "nick=%s\n", profile->cache->nick); + fprintf(fp, "uniquenick=%s\n", profile->cache->uniquenick); + fprintf(fp, "email=%s\n", profile->cache->email); + fprintf(fp, "firstname=%s\n", profile->cache->firstname); + fprintf(fp, "lastname=%s\n", profile->cache->lastname); + fprintf(fp, "homepage=%s\n", profile->cache->homepage); + fprintf(fp, "icquin=%d\n", profile->cache->icquin); + fprintf(fp, "zipcode=%s\n", profile->cache->zipcode); + fprintf(fp, "countrycode=%s\n", profile->cache->countrycode); + fprintf(fp, "birthday=%d\n", profile->cache->birthday); + fprintf(fp, "birthmonth=%d\n", profile->cache->birthmonth); + fprintf(fp, "birthyear=%d\n", profile->cache->birthyear); + if(profile->cache->sex == GP_MALE) + fprintf(fp, "sex=Male\n"); + if(profile->cache->sex == GP_FEMALE) + fprintf(fp, "sex=Female\n"); + if(profile->cache->sex == GP_PAT) + fprintf(fp, "sex=Pat\n"); + fprintf(fp, "publicmask=%d\n", profile->cache->publicmask); + fprintf(fp, "aimname=%s\n", profile->cache->aimname); + fprintf(fp, "pic=%d\n", profile->cache->pic); + fprintf(fp, "occupationid=%d\n", profile->cache->occupationid); + fprintf(fp, "industryid=%d\n", profile->cache->industryid); + fprintf(fp, "incomeid=%d\n", profile->cache->incomeid); + fprintf(fp, "marriedid=%d\n", profile->cache->marriedid); + fprintf(fp, "childcount=%d\n", profile->cache->childcount); + fprintf(fp, "interests1=%d\n", profile->cache->interests1); + fprintf(fp, "ownership1=%d\n", profile->cache->ownership1); + fprintf(fp, "conntypeid=%d\n", profile->cache->conntypeid); + } + + // End this profile. + //////////////////// + fprintf(fp, "\n"); + + GSI_UNUSED(data); + GSI_UNUSED(connection); + GSI_UNUSED(profile); + + return GPITrue; +} + +GPResult +gpiSaveDiskProfiles( + GPConnection * connection +) +{ + GPIBool failed; + + // Open the disk cache. + /////////////////////// + CHECK_RESULT(gpiOpenDiskProfiles(connection, GPITrue, &failed)); + if(failed) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_HotError, + "Failed to open the disk cache file.\n"); + return GP_NO_ERROR; + } + + // Write the version. + ///////////////////// + gpiWriteVersion(connection, GPI_PROFILE_CACHE_VERSION); + + // Save profiles. + ///////////////// + gpiProfileMap(connection, gpiSaveDiskProfile, NULL); + + // Close the cache. + /////////////////// + gpiCloseDiskProfiles(connection); + + return GP_NO_ERROR; +} + +#endif + +GPResult +gpiProcessNewProfile( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + char buffer[16]; + int pid; + GPICallback callback; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // This should be \npr\. + //////////////////////// + if(strncmp(input, "\\npr\\", 5) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Get the profile id. + ////////////////////// + if(!gpiValueForKey(input, "\\profileid\\", buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + pid = atoi(buffer); + + // Call the callback. + ///////////////////// + callback = operation->callback; + if(callback.callback != NULL) + { + GPNewProfileResponseArg * arg; + arg = (GPNewProfileResponseArg *)gsimalloc(sizeof(GPNewProfileResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + arg->profile = (GPProfile)pid; + arg->result = GP_NO_ERROR; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + + // Remove the operation. + //////////////////////// + gpiRemoveOperation(connection, operation); + + return GP_NO_ERROR; +} + +GPIProfile * +gpiProfileListAdd( + GPConnection * connection, + int id +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfileList * profileList = &iconnection->profileList; + GPIProfile profile; + GPIProfile * pProfile; + + assert(id > 0); + + // Check the parameters. 2000.02.14.JED was not checked in release build. + ///////////////////////////////////////////////////////////////////////// + if(id <= 0) + return NULL; + + // Check if this id is already in the list. + /////////////////////////////////////////// + if(gpiGetProfile(connection, (GPProfile)id, &pProfile)) + return pProfile; + + // Setup the new profile. + ///////////////////////// + memset(&profile, 0, sizeof(GPIProfile)); + profile.profileId = id; + profile.userId = 0; + profile.cache = NULL; + profile.authSig = NULL; + profile.peerSig = NULL; + profile.requestCount = 0; + + // Add it to the table. + /////////////////////// + TableEnter(profileList->profileTable, &profile); + + // One new one. + /////////////// + profileList->num++; + + // Get a pointer to the profile. + //////////////////////////////// + if(gpiGetProfile(connection, (GPProfile)id, &pProfile)) + return pProfile; + + // It wasn't added. + /////////////////// + return NULL; +} + +GPIBool +gpiGetProfile( + GPConnection * connection, + GPProfile profileid, + GPIProfile ** pProfile +) +{ + GPIProfile * profile; + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfile profileTemp; + + profileTemp.profileId = profileid; + profile = (GPIProfile *)TableLookup(iconnection->profileList.profileTable, &profileTemp); + if(pProfile) + *pProfile = profile; + + return ((profile != NULL) ? GPITrue:GPIFalse); +} + +GPResult +gpiNewProfile( + GPConnection * connection, + const char nick[31], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIOperation * operation; + GPResult result; + char buffer[31]; + + // Error check. + /////////////// + if(nick == NULL) + Error(connection, GP_PARAMETER_ERROR, "Invalid nick."); + if((replace != GP_REPLACE) && (replace != GP_DONT_REPLACE)) + Error(connection, GP_PARAMETER_ERROR, "Invalid replace."); + + // Create a new operation. + ////////////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_NEW_PROFILE, NULL, &operation, blocking, callback, param)); + + // Send the request. + //////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\newprofile\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\nick\\"); + strzcpy(buffer, nick, GP_NICK_LEN); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, buffer); + if(replace == GP_REPLACE) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\replace\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, 1); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\oldnick\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, iconnection->nick); + } + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, operation->id); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); +/* + if(string.result != GP_NO_ERROR) + { + gpiRemoveOperation(connection, operation); + return string.result; + } +*/ + // Process it if blocking. + ////////////////////////// + if(operation->blocking) + { + result = gpiProcess(connection, operation->id); + if(result != GP_NO_ERROR) + { + gpiRemoveOperation(connection, operation); + return result; + } + } + + return GP_NO_ERROR; +} + +GPResult gpiProcessDeleteProfle +( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPICallback callback; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // This should be \dpr\. + //////////////////////// + if(strncmp(input, "\\dpr\\", 5) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + + // Call the callback. + ///////////////////// + callback = operation->callback; + if(callback.callback != NULL) + { + GPDeleteProfileResponseArg * arg; + arg = (GPDeleteProfileResponseArg *)gsimalloc(sizeof(GPDeleteProfileResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + arg->profile = iconnection->profileid; + arg->result = GP_NO_ERROR; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + + // Remove the operation. + //////////////////////// + gpiRemoveOperation(connection, operation); + + return GP_NO_ERROR; +} + + +GPResult +gpiDeleteProfile( + GPConnection * connection, + GPCallback callback, + void *param +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIOperation * operation; + GPResult result; + + CHECK_RESULT(gpiAddOperation(connection, GPI_DELETE_PROFILE, NULL, &operation, GP_BLOCKING, callback, param)); + // Send the message. + //////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\delprofile\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, operation->id); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + // Remove the profile object. + ///////////////////////////// + gpiRemoveProfileByID(connection, iconnection->profileid); + + // Disconnect the connection. + // PANTS|05.16.00 + ///////////////////////////// + iconnection->connectState = GPI_PROFILE_DELETING; + result = gpiProcess(connection, operation->id); + if (result != GP_NO_ERROR) + { + gpiRemoveOperation(connection, operation); + return result; + } + + gpiDisconnect(connection, GPIFalse); + return GP_NO_ERROR; +} + +void +gpiRemoveProfileByID( + GPConnection * connection, + int profileid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfile * profile; + + if(gpiGetProfile(connection, (GPProfile)profileid, &profile)) + TableRemove(iconnection->profileList.profileTable, profile); +} + +void +gpiRemoveProfile( + GPConnection * connection, + GPIProfile * profile +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + TableRemove(iconnection->profileList.profileTable, profile); +} + +typedef struct GPIFindProfileByUserData +{ + char * nick; + char * email; + GPIProfile ** profile; + GPIBool found; +} GPIFindProfileByUserData; + +static GPIBool gpiCheckProfileForUser( + GPConnection * connection, + GPIProfile * profile, + void *udata +) +{ + GPIFindProfileByUserData * data = (GPIFindProfileByUserData *)udata; + + GSI_UNUSED(connection); + + // Check for a valid cache. + /////////////////////////// + if(profile->cache) + { + // Check the nick and email. + //////////////////////////// + if((strcmp(data->nick, profile->cache->nick) == 0) && (strcmp(data->email, profile->cache->email) == 0)) + { + // Found it. + //////////// + *data->profile = profile; + data->found = GPITrue; + return GPIFalse; + } + } + + return GPITrue; +} + +GPResult +gpiFindProfileByUser( + GPConnection * connection, + char nick[GP_NICK_LEN], + char email[GP_EMAIL_LEN], + GPIProfile ** profile +) +{ + GPIFindProfileByUserData data; + + data.nick = nick; + data.email = email; + data.profile = profile; + data.found = GPIFalse; + + gpiProfileMap(connection, gpiCheckProfileForUser, &data); + + if(!data.found) + *profile = NULL; + + return GP_NO_ERROR; +} + +typedef struct GPIProfileMapData +{ + GPConnection * connection; + gpiProfileMapFunc func; + void * data; +} GPIProfileMapData; + +static int +gpiProfileMapCallback( + void *arg, + void *udata +) +{ + GPIProfile * profile = (GPIProfile *)arg; + GPIProfileMapData * data = (GPIProfileMapData *)udata; + return (int)data->func(data->connection, profile, data->data); +} + +GPIBool +gpiProfileMap( + GPConnection * connection, + gpiProfileMapFunc func, + void * data +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfileMapData mapData; + + mapData.connection = connection; + mapData.func = func; + mapData.data = data; + + return (!TableMapSafe2(iconnection->profileList.profileTable, gpiProfileMapCallback, &mapData)) ? GPITrue:GPIFalse; +} + +typedef struct GPIFindProfileData +{ + int index; + GPIProfile * profile; +} GPIFindProfileData; + +static GPIBool +gpiCheckForBuddy( + GPConnection * connection, + GPIProfile * profile, + void *udata +) +{ + GPIFindProfileData * data = (GPIFindProfileData *)udata; + if (profile->buddyStatus && (data->index == profile->buddyStatus->buddyIndex)) + { + data->profile = profile; + return GPIFalse; + } + else if (profile->buddyStatusInfo && (data->index == profile->buddyStatusInfo->buddyIndex)) + { + data->profile = profile; + return GPIFalse; + } + + GSI_UNUSED(connection); + + return GPITrue; +} + +GPIProfile * +gpiFindBuddy( + GPConnection * connection, + int buddyIndex +) +{ + GPIFindProfileData data; + + data.index = buddyIndex; + data.profile = NULL; + + gpiProfileMap(connection, gpiCheckForBuddy, &data); + + return data.profile; +} + +void gpiRemoveBuddyStatus(GPIBuddyStatus *buddyStatus) +{ + GS_ASSERT(buddyStatus); + + freeclear(buddyStatus->locationString); + freeclear(buddyStatus->statusString); + freeclear(buddyStatus); +} + +void gpiRemoveBuddyStatusInfo(GPIBuddyStatusInfo *buddyStatusInfo) +{ + GS_ASSERT(buddyStatusInfo); + + freeclear(buddyStatusInfo->richStatus); + freeclear(buddyStatusInfo->gameType); + freeclear(buddyStatusInfo->gameVariant); + freeclear(buddyStatusInfo->gameMapName); + ArrayFree(buddyStatusInfo->extendedInfoKeys); + buddyStatusInfo->extendedInfoKeys = NULL; + freeclear(buddyStatusInfo); +} + +GPIBool +gpiCanFreeProfile( + GPIProfile * profile +) +{ + return ((profile && !profile->cache && !profile->buddyStatus && !profile->buddyStatusInfo && !profile->peerSig && !profile->authSig && !profile->blocked)) ? GPITrue:GPIFalse; +} + +void gpiSetInfoCacheFilename( + const char filename[FILENAME_MAX + 1] +) +{ + strzcpy(GPIInfoCacheFilename, filename, sizeof(GPIInfoCacheFilename)); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Blocked List functionality +GPResult +gpiAddToBlockedList( + GPConnection * connection, + int profileid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfile * profile; + int index; + + // Check if profile already in list + /////////////////////////////////// + if(!gpiGetProfile(connection, profileid, &profile)) + { + // It's not, so Add profile + ///////////////////////////////////// + profile = gpiProfileListAdd(connection, profileid); + if(!profile) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + } + else + { + // Already in the list, nix the buddy status if it's a buddy + //////////////////////////////////////////////////////////// + if (profile->buddyStatus) + { + index = profile->buddyStatus->buddyIndex; + freeclear(profile->buddyStatus->statusString); + freeclear(profile->buddyStatus->locationString); + freeclear(profile->buddyStatus); + iconnection->profileList.numBuddies--; + assert(iconnection->profileList.numBuddies >= 0); +#ifndef _PS2 + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)(unsigned long)index); +#else + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)index); +#endif + } + if (profile->buddyStatusInfo) + { + index = profile->buddyStatusInfo->buddyIndex; + freeclear(profile->buddyStatusInfo->richStatus); + freeclear(profile->buddyStatusInfo->gameType); + freeclear(profile->buddyStatusInfo->gameVariant); + freeclear(profile->buddyStatusInfo->gameMapName); + freeclear(profile->buddyStatusInfo); + if (profile->buddyStatusInfo->extendedInfoKeys) + { + ArrayFree(profile->buddyStatusInfo->extendedInfoKeys); + profile->buddyStatusInfo->extendedInfoKeys = NULL; + } + + iconnection->profileList.numBuddies--; + assert(iconnection->profileList.numBuddies >= 0); +#ifndef _PS2 + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)(unsigned long)index); +#else + gpiProfileMap(connection, gpiFixBuddyIndices, (void *)index); +#endif + } + } + + // Set profile as blocked if it wasn't already + ////////////////////////////////////////////// + if (!profile->blocked) + { + profile->blocked = gsi_true; + profile->blockIndex = iconnection->profileList.numBlocked++; + +#ifdef _PS3 + // Only perform if profile isn't already locally blocked and the sync isnt taking place + /////////////////////////////////////////////////////////////////////////////////////// + if (!iconnection->npSyncLock) + gpiAddToNpBlockList(connection, profileid); +#endif + } + + // NOTE: There is no callback for this function simply in order to remain consistent + // with the existing GP structure. If an error occurs, it gets passed to the error callback + // else its considered the request was processed correctly. + + // Add to outgoing buffer - have server handle error check if block already exists (consistency) + ///////////////////////////////////////////////////////////////////////////////////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\addblock\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profileid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +static GPIBool +gpiFixBlockIndices( + GPConnection * connection, + GPIProfile * profile, + void * data +) +{ +#ifndef _PS2 + int baseIndex = (int)(unsigned long)data; +#else + int baseIndex = (int)data; +#endif + + GSI_UNUSED(connection); + + if(profile->blocked && (profile->blockIndex > baseIndex)) + profile->blockIndex--; + return GPITrue; +} + +GPResult +gpiRemoveFromBlockedList( + GPConnection * connection, + int profileid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIProfile * profile; + int index; + + // Grab the profile if already in list + ////////////////////////////////////// + if(gpiGetProfile(connection, profileid, &profile) && profile->blocked) + { + // Set profile as non-blocked + ///////////////////////////// + profile->blocked = gsi_false; + + iconnection->profileList.numBlocked--; + index = profile->blockIndex; + +#ifndef _PS2 + gpiProfileMap(connection, gpiFixBlockIndices, (void *)(unsigned long)index); +#else + gpiProfileMap(connection, gpiFixBlockIndices, (void *)index); +#endif + } + + // NOTE: There is no callback for this function simply in order to remain consistent + // with the existing GP structure. If an error occurs, it gets passed to the error callback + // else its considered the request was processed correctly. + + // Add to outgoing buffer - have server handle error check if block already removed (consistency) + ///////////////////////////////////////////////////////////////////////////////////////////////// + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\removeblock\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profileid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +static GPIBool +gpiCheckForBlock( + GPConnection * connection, + GPIProfile * profile, + void *udata +) +{ + GPIFindProfileData * data = (GPIFindProfileData *)udata; + if (profile->blocked && data->index == profile->blockIndex) + { + data->profile = profile; + return GPIFalse; + } + + GSI_UNUSED(connection); + + return GPITrue; +} + +GPIProfile * +gpiFindBlockedProfile( + GPConnection * connection, + int blockIndex +) +{ + GPIFindProfileData data; + + data.index = blockIndex; + data.profile = NULL; + + gpiProfileMap(connection, gpiCheckForBlock, &data); + + return data.profile; +} + +GPResult +gpiProcessRecvBlockedList( + GPConnection * connection, + const char * input +) +{ + int i=0, j=0; + int num = 0; + int index = 0; + char c; + char *str = NULL; + char buffer[512]; + GPIProfile * profile; + GPProfile profileid; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // Process Block List Retrieval msg - Format like: + /* =============================================== + \blk\\list\\final\ + =============================================== */ + + if(!gpiValueForKeyWithIndex(input, "\\blk\\", &index, buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + num = atoi(buffer); + + // Check to make sure list is there + /////////////////////////////////// + str = strstr(input, "\\list\\"); + if (str == NULL) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Then increment index to get ready for parsing + //////////////////////////////////////////////// + str += 6; + index += 6; + + for (i=0; i < num; i++) + { + if (i==0) + { + // Manually grab first profile in list - comma delimiter + //////////////////////////////////////////////////////// + for(j=0 ; (j < sizeof(buffer)) && ((c = str[j]) != '\0') && (c != ',') ; j++) + { + buffer[j] = c; + } + buffer[j] = '\0'; + index += j; + } + else + { + if(!gpiValueForKeyWithIndex(input, ",", &index, buffer, sizeof(buffer))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + } + + profileid = atoi(buffer); + + // Get the profile, adding if needed. + ///////////////////////////////////// + profile = gpiProfileListAdd(connection, profileid); + if(!profile) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Mark as blocked, increment list counter + ////////////////////////////////////////// + profile->blocked = gsi_true; + profile->blockIndex = iconnection->profileList.numBlocked++; + } + + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiProfile.h b/xrGameSpy/gamespy/GP/gpiProfile.h new file mode 100644 index 00000000000..b2b7683dff2 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiProfile.h @@ -0,0 +1,229 @@ +/* +gpiProfile.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIPROFILE_H_ +#define _GPIPROFILE_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +#define GPI_SIG_LEN 33 + +//TYPES +/////// +// The status for a buddy profile. +////////////////////////////////// + +// New Status Info +typedef struct _GPIBuddyStatusInfo +{ + int buddyIndex; + GPEnum statusState; + char *richStatus; + char *gameType; + char *gameVariant; + char *gameMapName; + unsigned int sessionFlags; + unsigned int buddyIp; + unsigned short buddyPort; + unsigned int hostIp; + unsigned int hostPrivateIp; + unsigned short queryPort; + unsigned short hostPort; + GPEnum quietModeFlags; + int productId; + // New Status Info extended info Keys + DArray extendedInfoKeys; +} GPIBuddyStatusInfo; + +// Old status +typedef struct +{ + int buddyIndex; + GPEnum status; + char * statusString; + char * locationString; + unsigned int ip; + unsigned short port; + GPEnum quietModeFlags; +} GPIBuddyStatus; + +// Profile data. +//////////////// +typedef struct GPIProfile +{ + int profileId; + int userId; + GPIBuddyStatus * buddyStatus; + GPIBuddyStatusInfo *buddyStatusInfo; + GPIInfoCache * cache; + char * authSig; + int requestCount; + char * peerSig; + gsi_bool blocked; + int blockIndex; + gsi_bool buddyOrBlockCache; +} GPIProfile; + +// A list of profiles. +////////////////////// +typedef struct +{ + HashTable profileTable; + int num; + int numBuddies; + int numBlocked; +} GPIProfileList; + +//FUNCTIONS +/////////// +GPIBool +gpiInitProfiles( + GPConnection * connection +); + +GPIProfile * +gpiProfileListAdd( + GPConnection * connection, + int id +); + +GPIBool +gpiGetProfile( + GPConnection * connection, + GPProfile profileid, + GPIProfile ** pProfile +); + +GPResult +gpiProcessNewProfile( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +GPResult +gpiNewProfile( + GPConnection * connection, + const char nick[GP_NICK_LEN], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiProcessDeleteProfle +( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +GPResult gpiDeleteProfile( + GPConnection * connection, + GPCallback callback, + void * param +); + +void +gpiRemoveProfile( + GPConnection * connection, + GPIProfile * profile +); + +void +gpiRemoveProfileByID( + GPConnection * connection, + int profileid +); + +GPResult +gpiLoadDiskProfiles( + GPConnection * connection +); + +GPResult +gpiSaveDiskProfiles( + GPConnection * connection +); + +GPResult +gpiFindProfileByUser( + GPConnection * connection, + char nick[GP_NICK_LEN], + char email[GP_EMAIL_LEN], + GPIProfile ** profile +); + +// return false to stop the mapping +typedef GPIBool +(* gpiProfileMapFunc)( + GPConnection * connection, + GPIProfile * profile, + void * data +); + +GPIBool +gpiProfileMap( + GPConnection * connection, + gpiProfileMapFunc func, + void * data +); + +GPIProfile * +gpiFindBuddy( + GPConnection * connection, + int buddyIndex +); + +void gpiRemoveBuddyStatus(GPIBuddyStatus *buddyStatus); +void gpiRemoveBuddyStatusInfo(GPIBuddyStatusInfo *buddyStatusInfo); + +GPIBool +gpiCanFreeProfile( + GPIProfile * profile +); + +void gpiSetInfoCacheFilename( + const char filename[FILENAME_MAX + 1] +); + +// BLOCK LIST +GPResult +gpiAddToBlockedList( + GPConnection * connection, + int profileid +); + +GPResult +gpiRemoveFromBlockedList( + GPConnection * connection, + int profileid +); + +GPIProfile * +gpiFindBlockedProfile( + GPConnection * connection, + int blockIndex +); + +GPResult +gpiProcessRecvBlockedList( + GPConnection * connection, + const char * input +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiSearch.c b/xrGameSpy/gamespy/GP/gpiSearch.c new file mode 100644 index 00000000000..52b2a1ee9e5 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiSearch.c @@ -0,0 +1,1656 @@ +/* +gpiSearch.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include +#include +#include "gpi.h" + +//DEFINES +///////// +// Search Manager Address. +////////////////////////// +#define GPI_SEARCH_MANAGER_NAME "gpsp." GSI_DOMAIN_NAME +#define GPI_SEARCH_MANAGER_PORT 29901 + + +//GLOBALS +///////// +char GPSearchManagerHostname[64] = GPI_SEARCH_MANAGER_NAME; +//char GPSearchManagerHostname[64] = "localhost"; + +//FUNCTIONS +/////////// +static GPResult +gpiStartProfileSearch( + GPConnection * connection, + GPIOperation * operation +) +{ + GPISearchData * data = (GPISearchData*)operation->data; + int rcode; + struct sockaddr_in address; + struct hostent * host; + + // Initialize the buffer. + ///////////////////////// + data->inputBuffer.size = 4096; + data->inputBuffer.buffer = (char *)gsimalloc((unsigned int)data->inputBuffer.size + 1); + if(data->inputBuffer.buffer == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Create the socket. + ///////////////////// + data->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(data->sock == INVALID_SOCKET) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error creating a socket."); + + // Make it non-blocking. + //////////////////////// + rcode = SetSockBlocking(data->sock,0); + if(rcode == 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error making a socket non-blocking."); + + // Bind the socket. + /////////////////// + /* + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + rcode = bind(data->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if (gsiSocketIsError(rcode)) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error binding a socket."); + */ + + // Get the server host. + /////////////////////// + host = gethostbyname(GPSearchManagerHostname); + if(host == NULL) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "Could not resolve search mananger host name."); + + // Connect the socket. + ////////////////////// + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = *(unsigned int *)host->h_addr_list[0]; + assert(address.sin_addr.s_addr != 0); + address.sin_port = htons(GPI_SEARCH_MANAGER_PORT); + rcode = connect(data->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); + if (gsiSocketIsError(rcode)) + { + int error = GOAGetLastError(data->sock); + if((error != WSAEWOULDBLOCK) && (error != WSAEINPROGRESS) && (error != WSAETIMEDOUT) ) + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error connecting a socket."); + } + } + + // We're waiting for the connect to complete. + ///////////////////////////////////////////// + operation->state = GPI_CONNECTING; + data->searchStartTime = current_time(); + return GP_NO_ERROR; +} + +static GPResult +gpiInitSearchData( + GPConnection * connection, + GPISearchData ** searchData, + int type +) +{ + GPISearchData * data; + + // Init the data. + ///////////////// + data = (GPISearchData *)gsimalloc(sizeof(GPISearchData)); + if(data == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + memset(data, 0, sizeof(GPISearchData)); + data->type = type; + data->sock = INVALID_SOCKET; + data->inputBuffer.buffer = NULL; + data->inputBuffer.len = 0; + data->inputBuffer.pos = 0; + data->inputBuffer.size = 0; + data->outputBuffer.len = 0; + data->outputBuffer.pos = 0; + data->outputBuffer.size = 4096; + data->outputBuffer.buffer = (char *)gsimalloc((unsigned int)data->outputBuffer.size + 1); + if(data->outputBuffer.buffer == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + data->processing = GPIFalse; + data->remove = GPIFalse; + + *searchData = data; + + return GP_NO_ERROR; +} + +static GPResult +gpiStartSearch( + GPConnection * connection, + GPISearchData * data, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIOperation * operation; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // One more search. + /////////////////// + iconnection->numSearches++; + + // Create a new operation. + ////////////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_PROFILE_SEARCH, data, &operation, blocking, callback, param)); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartProfileSearch(connection, operation)); + + // Process it if blocking. + ////////////////////////// + if(operation->blocking) + CHECK_RESULT(gpiProcess(connection, operation->id)); + + return GP_NO_ERROR; +} + +GPResult +gpiProfileSearch( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char firstname[GP_FIRSTNAME_LEN], + const char lastname[GP_LASTNAME_LEN], + int icquin, + int skip, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Error check. + /////////////// + if((nick == NULL) || (*nick == '\0')) + if((email == NULL) || (*email == '\0')) + if((firstname == NULL) || (*firstname == '\0')) + if((lastname == NULL) || (*lastname == '\0')) + if(icquin == 0) + if((uniquenick == NULL) || (*uniquenick == '\0')) + Error(connection, GP_PARAMETER_ERROR, "No search criteria."); + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_PROFILE)); + + // Fill in the data. + //////////////////// + if(nick == NULL) + data->nick[0] = '\0'; + else + strzcpy(data->nick, nick, GP_NICK_LEN); + if(uniquenick == NULL) + data->uniquenick[0] = '\0'; + else + strzcpy(data->uniquenick, uniquenick, GP_UNIQUENICK_LEN); + if(email == NULL) + data->email[0] = '\0'; + else + strzcpy(data->email, email, GP_EMAIL_LEN); + _strlwr(data->email); + if(firstname == NULL) + data->firstname[0] = '\0'; + else + strzcpy(data->firstname, firstname, GP_FIRSTNAME_LEN); + if(lastname == NULL) + data->lastname[0] = '\0'; + else + strzcpy(data->lastname, lastname, GP_LASTNAME_LEN); + data->icquin = icquin; + if(skip < 0) + skip = 0; + data->skip = skip; + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult +gpiProfileSearchUniquenick( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const int namespaceIDs[], + int numNamespaces, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Error check. + /////////////// + if((uniquenick == NULL) || (*uniquenick == '\0')) + Error(connection, GP_PARAMETER_ERROR, "No search criteria."); + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_PROFILE_UNIQUENICK)); + + // Fill in the data. + //////////////////// + strzcpy(data->uniquenick, uniquenick, GP_UNIQUENICK_LEN); + if((namespaceIDs != NULL) && (numNamespaces > 0)) + { + data->numNamespaces = min(numNamespaces, GP_MAX_NAMESPACEIDS); + memcpy(data->namespaceIDs, namespaceIDs, sizeof(namespaceIDs[0]) * data->numNamespaces); + } + else + { + data->numNamespaces = 0; + } + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult +gpiIsValidEmail( + GPConnection * connection, + const char email[GP_EMAIL_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Error check. + /////////////// + if((email == NULL) || (*email == '\0') || (strlen(email) >= GP_EMAIL_LEN)) + Error(connection, GP_PARAMETER_ERROR, "Invalid e-mail."); + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_IS_VALID)); + + // Fill in the data. + //////////////////// + strzcpy(data->email, email, GP_EMAIL_LEN); + _strlwr(data->email); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult +gpiGetUserNicks( + GPConnection * connection, + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Error check. + /////////////// + if((email == NULL) || (*email == '\0') || (strlen(email) >= GP_EMAIL_LEN)) + Error(connection, GP_PARAMETER_ERROR, "Invalid e-mail."); + if((password == NULL) || (strlen(password) >= GP_PASSWORD_LEN)) + Error(connection, GP_PARAMETER_ERROR, "Invalid password."); + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_NICKS)); + + // Fill in the data. + //////////////////// + strzcpy(data->email, email, GP_EMAIL_LEN); + _strlwr(data->email); + strzcpy(data->password, password, GP_PASSWORD_LEN); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult +gpiFindPlayers( + GPConnection * connection, + int productID, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_PLAYERS)); + + // Fill in the data. + //////////////////// + data->productID = productID; + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult gpiCheckUser( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_CHECK)); + + // Fill in the data. + //////////////////// + strzcpy(data->email, email, GP_EMAIL_LEN); + _strlwr(data->email); + strzcpy(data->nick, nick, GP_NICK_LEN); + if(password) + strzcpy(data->password, password, GP_PASSWORD_LEN); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult gpiNewUser( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_NEWUSER)); + + // Fill in the data. + //////////////////// + strzcpy(data->email, email, GP_EMAIL_LEN); + strzcpy(data->nick, nick, GP_NICK_LEN); + strzcpy(data->password, password, GP_PASSWORD_LEN); + strzcpy(data->uniquenick, uniquenick, GP_UNIQUENICK_LEN); + if(cdkey) + strzcpy(data->cdkey, cdkey, GP_CDKEY_LEN); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult gpiOthersBuddy( + GPConnection * connection, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_OTHERS_BUDDY)); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult gpiOthersBuddyList( + GPConnection * connection, + int *profiles, + int numOfProfiles, + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_OTHERS_BUDDY_LIST)); + + data->revBuddyProfileIds = profiles; + data->numOfRevBuddyProfiles = numOfProfiles; + + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +GPResult gpiSuggestUniqueNick( + GPConnection * connection, + const char desirednick[GP_NICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPISearchData * data; + + // Init the data. + ///////////////// + CHECK_RESULT(gpiInitSearchData(connection, &data, GPI_SEARCH_SUGGEST_UNIQUE)); + + // Fill in the data. + //////////////////// + strzcpy(data->uniquenick, desirednick, GP_UNIQUENICK_LEN); + + // Start the search. + //////////////////// + CHECK_RESULT(gpiStartSearch(connection, data, blocking, callback, param)); + + return GP_NO_ERROR; +} + +static GPResult +gpiProcessSearch( + GPConnection * connection, + GPIOperation * operation +) +{ + int state; + GPISearchData * data; + char key[512]; + char value[512]; + GPIBool done; + int index; + int oldIndex; + GPIBool loop; + GPIBool more; + GPICallback callback; + GPIConnection * iconnection = (GPIConnection*)*connection; + int len; + GPIBool connClosed; + GPResult result; + void * tempPtr; + GPIBool doneParsingMatch; + int rcode; + int pid; + GPProfileSearchMatch * match; + GPUniqueMatch *uniqueNickMatch; + + //password encryption stuff + char passwordenc[GP_PASSWORDENC_LEN]; + + // Get a pointer to the data. + ///////////////////////////// + data = (GPISearchData*)operation->data; + + // Loop if blocking. + //////////////////// + if(operation->blocking) + loop = GPITrue; + else + loop = GPIFalse; + + if (!operation->blocking && (current_time() - data->searchStartTime > GPI_SEARCH_TIMEOUT)) + { + data->remove = GPITrue; + CallbackError(connection, GP_NETWORK_ERROR, GP_SEARCH_TIMED_OUT, "The search timed out"); + } + + do + { + // Send anything that needs to be sent. + /////////////////////////////////////// + CHECK_RESULT(gpiSendFromBuffer(connection, data->sock, &data->outputBuffer, &connClosed, GPITrue, "SM")); + + // Is it connecting? + //////////////////// + if(operation->state == GPI_CONNECTING) + { + // Check the connect state. + /////////////////////////// + CHECK_RESULT(gpiCheckSocketConnect(connection, data->sock, &state)); + + // Check for a failed attempt. + ////////////////////////////// + if(state == GPI_DISCONNECTED) + CallbackError(connection, GP_SERVER_ERROR, GP_SEARCH_CONNECTION_FAILED, "Could not connect to the search manager."); + + // Check if finished connecting. + //////////////////////////////// + if(state == GPI_CONNECTED) + { + // Send a request based on type. + //////////////////////////////// + if(data->type == GPI_SEARCH_PROFILE) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\search\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); + if(data->nick[0] != '\0') + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->nick); + } + if(data->uniquenick[0] != '\0') + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquenick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); + } + if(data->email[0] != '\0') + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); + } + if(data->firstname[0] != '\0') + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\firstname\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->firstname); + } + if(data->lastname[0] != '\0') + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\lastname\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->lastname); + } + if(data->icquin != 0) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\icquin\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->icquin); + } + if(data->skip > 0) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\skip\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->skip); + } + } + else if(data->type == GPI_SEARCH_PROFILE_UNIQUENICK) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\searchunique\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquenick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaces\\"); + if(data->numNamespaces > 0) + { + int i; + for(i = 0 ; i < data->numNamespaces ; i++) + { + if(i > 0) + gpiAppendCharToBuffer(connection, &data->outputBuffer, ','); + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->namespaceIDs[i]); + } + } + else + { + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + } + } + else if(data->type == GPI_SEARCH_IS_VALID) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\valid\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); + } + else if(data->type == GPI_SEARCH_NICKS) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nicks\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); + + gpiEncodeString(data->password, passwordenc); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\passenc\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, passwordenc); + + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); + } + else if(data->type == GPI_SEARCH_PLAYERS) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\pmatch\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\productid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->productID); + } + else if(data->type == GPI_SEARCH_CHECK) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\check\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->nick); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); + gpiEncodeString(data->password, passwordenc); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\passenc\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, passwordenc); + } + else if(data->type == GPI_SEARCH_NEWUSER) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\newuser\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\nick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->nick); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\email\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->email); + gpiEncodeString(data->password, passwordenc); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\passenc\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, passwordenc); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\productID\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->productID); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquenick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); + if(data->cdkey[0]) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\cdkey\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->cdkey); + } + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->partnerID); + } + else if(data->type == GPI_SEARCH_OTHERS_BUDDY) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\others\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + } + else if(data->type == GPI_SEARCH_OTHERS_BUDDY_LIST) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\otherslist\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\sesskey\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\profileid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->profileid); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\numopids\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->numOfRevBuddyProfiles); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\opids\\"); + if (data->revBuddyProfileIds) + { + int i; + + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->revBuddyProfileIds[0]); + + for (i = 1; i < data->numOfRevBuddyProfiles; i++) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "|"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, data->revBuddyProfileIds[i]); + } + } + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + } + else if(data->type == GPI_SEARCH_SUGGEST_UNIQUE) + { + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\uniquesearch\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\preferrednick\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, data->uniquenick); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\namespaceid\\"); + gpiAppendIntToBuffer(connection, &data->outputBuffer, iconnection->namespaceID); + } + else + { + assert(0); + } + + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\gamename\\"); + gpiAppendStringToBuffer(connection, &data->outputBuffer, __GSIACGamename); + gpiAppendStringToBuffer(connection, &data->outputBuffer, "\\final\\"); + + // Update the state. + //////////////////// + operation->state = GPI_WAITING; + } + } + // Is it waiting? + ///////////////// + else if(operation->state == GPI_WAITING) + { + // Read from the socket. + //////////////////////// + result = gpiRecvToBuffer(connection, data->sock, &data->inputBuffer, &len, &connClosed, "SM"); + if(result != GP_NO_ERROR) + { + if(result == GP_NETWORK_ERROR) + CallbackError(connection, GP_NETWORK_ERROR, GP_SEARCH_CONNECTION_FAILED, "There was an error reading from the server."); + return result; + } + if (operation->blocking && (current_time() - data->searchStartTime > GPI_SEARCH_TIMEOUT)) + { + data->remove = GPITrue; + CallbackError(connection, GP_NETWORK_ERROR, GP_SEARCH_TIMED_OUT, "The search timed out"); + } + // Is this the end of the response? + /////////////////////////////////// + if(strstr(data->inputBuffer.buffer, "\\final\\") != NULL) + { + // Reset the index. + /////////////////// + index = 0; + + // This operation is finishing up. + ////////////////////////////////// + operation->state = GPI_FINISHING; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, data->inputBuffer.buffer, GPITrue)) + { + data->remove = GPITrue; + return GP_SERVER_ERROR; + } + + // Process it based on type. + //////////////////////////// + if((data->type == GPI_SEARCH_PROFILE) || (data->type == GPI_SEARCH_PROFILE_UNIQUENICK)) + { + GPProfileSearchResponseArg arg; + // Start setting up the arg. + //////////////////////////// + arg.result = GP_NO_ERROR; + arg.numMatches = 0; + arg.matches = NULL; + arg.more = GP_DONE; + + // Parse the message. + ///////////////////// + done = GPIFalse; + do + { + // Read the next key and value. + /////////////////////////////// + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + + // Is the list done? + //////////////////// + if(strcmp(key, "bsrdone") == 0) + { + // Check for more. + ////////////////// + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "more") == 0) + { + // Make sure there are actually more. + ///////////////////////////////////// + if(strcmp(value, "0") != 0) + arg.more = GP_MORE; + } + + // Done. + //////// + done = GPITrue; + } + else if(strcmp(key, "bsr") == 0) + { + // Create a new match. + ////////////////////// + arg.numMatches++; + arg.matches = (GPProfileSearchMatch *)gsirealloc(arg.matches, sizeof(GPProfileSearchMatch) * arg.numMatches); + if(arg.matches == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + match = &arg.matches[arg.numMatches - 1]; + memset(match, 0, sizeof(GPProfileSearchMatch)); + + // Get the profile id. + ////////////////////// + match->profile = atoi(value); + + // PANTS|05.16.00 + // Changed to be order independent, and ignore unrecognized keys. + ///////////////////////////////////////////////////////////////// + + // Read key/value pairs. + //////////////////////// + doneParsingMatch = GPIFalse; + do + { + // Read the next key/value. + /////////////////////////// + oldIndex = index; + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + + // Set the field based on the key. + ////////////////////////////////// +#ifndef GSI_UNICODE + if(strcmp(key, "nick") == 0) + strzcpy(match->nick, value, GP_NICK_LEN); + else if(strcmp(key, "uniquenick") == 0) + strzcpy(match->uniquenick, value, GP_UNIQUENICK_LEN); + else if(strcmp(key, "namespaceid") == 0) + match->namespaceID = atoi(value); + else if(strcmp(key, "firstname") == 0) + strzcpy(match->firstname, value, GP_FIRSTNAME_LEN); + else if(strcmp(key, "lastname") == 0) + strzcpy(match->lastname, value, GP_LASTNAME_LEN); + else if(strcmp(key, "email") == 0) + strzcpy(match->email, value, GP_EMAIL_LEN); + else if((strcmp(key, "bsr") == 0) || (strcmp(key, "bsrdone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#else + if(strcmp(key, "nick") == 0) + UTF8ToUCS2StringLen(value, match->nick, GP_NICK_LEN); + else if(strcmp(key, "uniquenick") == 0) + UTF8ToUCS2StringLen(value, match->uniquenick, GP_UNIQUENICK_LEN); + else if(strcmp(key, "namespaceid") == 0) + match->namespaceID = atoi(value); + else if(strcmp(key, "firstname") == 0) + UTF8ToUCS2StringLen(value, match->firstname, GP_FIRSTNAME_LEN); + else if(strcmp(key, "lastname") == 0) + UTF8ToUCS2StringLen(value, match->lastname, GP_LASTNAME_LEN); + else if(strcmp(key, "email") == 0) + UTF8ToUCS2StringLen(value, match->email, GP_EMAIL_LEN); + else if((strcmp(key, "bsr") == 0) || (strcmp(key, "bsrdone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#endif + } + while(!doneParsingMatch); + } + else + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + } + } while(!done); + + // Save the more state. + /////////////////////// + more = (GPIBool)arg.more; + + // Get the callback. + //////////////////// + callback = operation->callback; + + + // Call the callback. + ///////////////////// + if(callback.callback != NULL) + callback.callback(connection, &arg, callback.param); + + // Start a new operation if they want more matches. + /////////////////////////////////////////////////// + if((more == GP_MORE) && (arg.more == GP_MORE)) + CHECK_RESULT(gpiProfileSearch(connection, data->nick, data->uniquenick, data->email, data->firstname, data->lastname, data->icquin, arg.numMatches + data->skip, (GPEnum)operation->blocking, operation->callback.callback, operation->callback.param)); + + // We're done. + ////////////// + freeclear(arg.matches); + } + else if(data->type == GPI_SEARCH_IS_VALID) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPIsValidEmailResponseArg * arg; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "vr") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + + // Setup the arg. + ///////////////// + arg = (GPIsValidEmailResponseArg *)gsimalloc(sizeof(GPIsValidEmailResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = GP_NO_ERROR; +#ifndef GSI_UNICODE + strzcpy(arg->email, data->email, GP_EMAIL_LEN); +#else + UTF8ToUCS2String(data->email, arg->email); +#endif + if(value[0] == '0') + arg->isValid = GP_INVALID; + else + arg->isValid = GP_VALID; + + // Add the callback. + //////////////////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + } + else if(data->type == GPI_SEARCH_NICKS) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPGetUserNicksResponseArg * arg; + + // Setup the arg. + ///////////////// + arg = (GPGetUserNicksResponseArg *)gsimalloc(sizeof(GPGetUserNicksResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = GP_NO_ERROR; +#ifndef GSI_UNICODE + strcpy(arg->email, data->email); +#else + UTF8ToUCS2String(data->email, arg->email); +#endif + arg->numNicks = 0; + arg->nicks = NULL; + arg->uniquenicks = NULL; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "nr") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + + // Get the nicks. + ///////////////// + done = GPIFalse; + do + { + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "nick") == 0) + { + // Add it. + ////////// +#ifndef GSI_UNICODE + tempPtr = gsirealloc(arg->nicks, sizeof(char *) * (arg->numNicks + 1)); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->nicks = (char **)tempPtr; + tempPtr = gsimalloc(GP_NICK_LEN); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->nicks[arg->numNicks] = (gsi_char*)tempPtr; + strzcpy(arg->nicks[arg->numNicks], value, GP_NICK_LEN); + arg->numNicks++; +#else + tempPtr = gsirealloc(arg->nicks, sizeof(unsigned short *) * (arg->numNicks + 1)); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->nicks = (unsigned short **)tempPtr; + tempPtr = gsimalloc(GP_NICK_LEN * sizeof(unsigned short)); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->nicks[arg->numNicks] = (gsi_char*)tempPtr; + UTF8ToUCS2StringLen(value, arg->nicks[arg->numNicks], GP_NICK_LEN); + arg->numNicks++; +#endif + } + else if(strcmp(key, "uniquenick") == 0) + { + if(arg->numNicks <= 0) + continue; + + // Add it. + ////////// +#ifndef GSI_UNICODE + tempPtr = gsirealloc(arg->uniquenicks, sizeof(char *) * arg->numNicks); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->uniquenicks = (char **)tempPtr; + tempPtr = gsimalloc(GP_UNIQUENICK_LEN); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->uniquenicks[arg->numNicks - 1] = (gsi_char*)tempPtr; + strzcpy(arg->uniquenicks[arg->numNicks - 1], value, GP_UNIQUENICK_LEN); +#else + tempPtr = gsirealloc(arg->uniquenicks, sizeof(unsigned short *) * arg->numNicks); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->uniquenicks = (unsigned short **)tempPtr; + tempPtr = gsimalloc(GP_UNIQUENICK_LEN * sizeof(unsigned short)); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->uniquenicks[arg->numNicks - 1] = (gsi_char*)tempPtr; + UTF8ToUCS2StringLen(value, arg->uniquenicks[arg->numNicks - 1], GP_UNIQUENICK_LEN); +#endif + } + else if(strcmp(key, "ndone") == 0) + { + // Done. + //////// + done = GPITrue; + } + else + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + } + } + while(!done); + + // Do it. + ///////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_NICKS)); + } + } + else if(data->type == GPI_SEARCH_PLAYERS) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPFindPlayersResponseArg * arg; + GPFindPlayerMatch * match; + + // Start setting up the arg. + //////////////////////////// + arg = (GPFindPlayersResponseArg *)gsimalloc(sizeof(GPFindPlayersResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->productID = data->productID; + arg->result = GP_NO_ERROR; + arg->numMatches = 0; + arg->matches = NULL; + + // Parse the message. + ///////////////////// + done = GPIFalse; + do + { + // Read the next key and value. + /////////////////////////////// + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + + // Is the list done? + //////////////////// + if(strcmp(key, "psrdone") == 0) + { + // Done. + //////// + done = GPITrue; + } + else if(strcmp(key, "psr") == 0) + { + // Create a new match. + ////////////////////// + arg->numMatches++; + arg->matches = (GPFindPlayerMatch *)gsirealloc(arg->matches, sizeof(GPFindPlayerMatch) * arg->numMatches); + if(arg->matches == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + match = &arg->matches[arg->numMatches - 1]; + memset(match, 0, sizeof(GPFindPlayerMatch)); + match->status = GP_ONLINE; + + // Get the profile id. + ////////////////////// + match->profile = atoi(value); + + // PANTS|05.16.00 + // Changed to be order independent, and ignore unrecognized keys. + ///////////////////////////////////////////////////////////////// + + // Read key/value pairs. + //////////////////////// + doneParsingMatch = GPIFalse; + do + { + // Read the next key/value. + /////////////////////////// + oldIndex = index; + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + +#ifndef GSI_UNICODE + // Set the field based on the key. + ////////////////////////////////// + if(strcmp(key, "status") == 0) + strzcpy(match->statusString, value, GP_STATUS_STRING_LEN); + else if(strcmp(key, "nick") == 0) + strzcpy(match->nick, value, GP_NICK_LEN); + if(strcmp(key, "statuscode") == 0) + match->status = (GPEnum)atoi(value); + else if((strcmp(key, "psr") == 0) || (strcmp(key, "psrdone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#else + // Set the field based on the key. + ////////////////////////////////// + if(strcmp(key, "status") == 0) + UTF8ToUCS2StringLen(value, match->statusString, GP_STATUS_STRING_LEN); + else if(strcmp(key, "nick") == 0) + UTF8ToUCS2StringLen(value, match->nick, GP_NICK_LEN); + if(strcmp(key, "statuscode") == 0) + match->status = (GPEnum)atoi(value); + else if((strcmp(key, "psr") == 0) || (strcmp(key, "psrdone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#endif + } + while(!doneParsingMatch); + } + else + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + } + } while(!done); + + // Do it. + ///////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_PMATCH)); + } + } + else if(data->type == GPI_SEARCH_CHECK) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPCheckResponseArg * arg; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "cur") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + + rcode = atoi(value); + if(rcode) + { + iconnection->errorCode = (GPErrorCode)rcode; + pid = 0; + } + else + { + if(!gpiValueForKey(data->inputBuffer.buffer, "\\pid\\", value, sizeof(value))) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + pid = atoi(value); + } + + // Setup the arg. + ///////////////// + arg = (GPCheckResponseArg *)gsimalloc(sizeof(GPCheckResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = (GPResult)rcode; + arg->profile = pid; + + // Add the callback. + //////////////////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + } + else if(data->type == GPI_SEARCH_NEWUSER) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPNewUserResponseArg * arg; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "nur") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + + rcode = atoi(value); + if(rcode) + iconnection->errorCode = (GPErrorCode)rcode; + if(!gpiValueForKey(data->inputBuffer.buffer, "\\pid\\", value, sizeof(value))) + { + if(rcode == 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + pid = 0; + } + else + pid = atoi(value); + + // Setup the arg. + ///////////////// + arg = (GPNewUserResponseArg *)gsimalloc(sizeof(GPNewUserResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = (GPResult)rcode; + arg->profile = pid; + + // Add the callback. + //////////////////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + } + else if(data->type == GPI_SEARCH_OTHERS_BUDDY) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPGetReverseBuddiesResponseArg * arg; + + // Setup the arg. + ///////////////// + arg = (GPGetReverseBuddiesResponseArg *)gsimalloc(sizeof(GPGetReverseBuddiesResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = GP_NO_ERROR; + arg->numProfiles = 0; + arg->profiles = NULL; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "others") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + + // Get the profiles. + ///////////////// + done = GPIFalse; + do + { + // Read the next key and value. + /////////////////////////////// + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + + // Is the list done? + //////////////////// + if(strcmp(key, "odone") == 0) + { + // Done. + //////// + done = GPITrue; + } + else if(strcmp(key, "o") == 0) + { + // Add it. + ////////// + tempPtr = gsirealloc(arg->profiles, sizeof(GPProfileSearchMatch) * (arg->numProfiles + 1)); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->profiles = (GPProfileSearchMatch *)tempPtr; + match = &arg->profiles[arg->numProfiles]; + memset(match, 0, sizeof(GPProfileSearchMatch)); + arg->numProfiles++; + + // Get the profile id. + ////////////////////// + match->profile = atoi(value); + + // Read key/value pairs. + //////////////////////// + doneParsingMatch = GPIFalse; + do + { + // Read the next key/value. + /////////////////////////// + oldIndex = index; + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + +#ifndef GSI_UNICODE + // Set the field based on the key. + ////////////////////////////////// + if(strcmp(key, "nick") == 0) + strzcpy(match->nick, value, GP_NICK_LEN); + else if(strcmp(key, "uniquenick") == 0) + strzcpy(match->uniquenick, value, GP_UNIQUENICK_LEN); + else if(strcmp(key, "first") == 0) + strzcpy(match->firstname, value, GP_FIRSTNAME_LEN); + else if(strcmp(key, "last") == 0) + strzcpy(match->lastname, value, GP_LASTNAME_LEN); + else if(strcmp(key, "email") == 0) + strzcpy(match->email, value, GP_EMAIL_LEN); + else if((strcmp(key, "o") == 0) || (strcmp(key, "odone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#else + // Set the field based on the key. + ////////////////////////////////// + if(strcmp(key, "nick") == 0) + UTF8ToUCS2StringLen(value, match->nick, GP_NICK_LEN); + else if(strcmp(key, "uniquenick") == 0) + UTF8ToUCS2StringLen(value, match->uniquenick, GP_UNIQUENICK_LEN); + else if(strcmp(key, "first") == 0) + UTF8ToUCS2StringLen(value, match->firstname, GP_FIRSTNAME_LEN); + else if(strcmp(key, "last") == 0) + UTF8ToUCS2StringLen(value, match->lastname, GP_LASTNAME_LEN); + else if(strcmp(key, "email") == 0) + UTF8ToUCS2StringLen(value, match->email, GP_EMAIL_LEN); + else if((strcmp(key, "o") == 0) || (strcmp(key, "odone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#endif + } + while(!doneParsingMatch); + } + else + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + } + } + while(!done); + + // Do it. + ///////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_REVERSE_BUDDIES)); + } + } + else if (data->type == GPI_SEARCH_OTHERS_BUDDY_LIST) + { + callback = operation->callback; + if(callback.callback != NULL) + { + GPGetReverseBuddiesListResponseArg * arg; + + // Setup the arg. + ///////////////// + arg = (GPGetReverseBuddiesListResponseArg *)gsimalloc(sizeof(GPGetReverseBuddiesListResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = GP_NO_ERROR; + arg->numOfUniqueMatchs = 0; + arg->matches = NULL; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "otherslist") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + + // Get the profiles. + ///////////////// + done = GPIFalse; + do + { + // Read the next key and value. + /////////////////////////////// + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + + // Is the list done? + //////////////////// + if(strcmp(key, "oldone") == 0) + { + // Done. + //////// + done = GPITrue; + } + else if(strcmp(key, "o") == 0) + { + // Add it. + ////////// + tempPtr = gsirealloc(arg->matches, sizeof(GPUniqueMatch) * (arg->numOfUniqueMatchs + 1)); + if(tempPtr == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->matches = (GPUniqueMatch *)tempPtr; + uniqueNickMatch = &arg->matches[arg->numOfUniqueMatchs]; + memset(uniqueNickMatch, 0, sizeof(GPUniqueMatch)); + arg->numOfUniqueMatchs++; + + // Get the profile id. + ////////////////////// + uniqueNickMatch->profile = atoi(value); + + // Read key/value pairs. + //////////////////////// + doneParsingMatch = GPIFalse; + do + { + // Read the next key/value. + /////////////////////////// + oldIndex = index; + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + +#ifndef GSI_UNICODE + // Set the field based on the key. + ////////////////////////////////// + if(strcmp(key, "uniquenick") == 0) + strzcpy(uniqueNickMatch->uniqueNick, value, GP_UNIQUENICK_LEN); + else if((strcmp(key, "o") == 0) || (strcmp(key, "oldone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#else + // Set the field based on the key. + ////////////////////////////////// + if(strcmp(key, "uniquenick") == 0) + UTF8ToUCS2StringLen(value, uniqueNickMatch->uniqueNick, GP_UNIQUENICK_LEN); + else if((strcmp(key, "o") == 0) || (strcmp(key, "oldone") == 0)) + { + doneParsingMatch = GPITrue; + index = oldIndex; + } +#endif + } + while(!doneParsingMatch); + } + else + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + } + } + while(!done); + + // Do it. + ///////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_REVERSE_BUDDIES_LIST)); + } + + } + else if(data->type == GPI_SEARCH_SUGGEST_UNIQUE) + { + callback = operation->callback; + if(callback.callback != NULL) + { + int count = 0; + GPSuggestUniqueNickResponseArg * arg; + + // Setup the arg. + ///////////////// + arg = (GPSuggestUniqueNickResponseArg *)gsimalloc(sizeof(GPSuggestUniqueNickResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + arg->result = GP_NO_ERROR; + arg->numSuggestedNicks = 0; + arg->suggestedNicks = NULL; + + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "us") != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + arg->numSuggestedNicks = atoi(value); + + // Allocate memory for the nick array. + ////////////////////////////////////// + arg->suggestedNicks = (gsi_char **)gsimalloc(sizeof(gsi_char *) * arg->numSuggestedNicks); + if(!arg->suggestedNicks) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Get the nicks. + ///////////////// + done = GPIFalse; + do + { + CHECK_RESULT(gpiReadKeyAndValue(connection, data->inputBuffer.buffer, &index, key, value)); + if(strcmp(key, "nick") == 0) + { + // Add it. + ////////// +#ifndef GSI_UNICODE + arg->suggestedNicks[count] = gsimalloc(GP_UNIQUENICK_LEN); + if(arg->suggestedNicks[count] == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + strzcpy(arg->suggestedNicks[count], value, GP_UNIQUENICK_LEN); +#else + arg->suggestedNicks[count] = (unsigned short*)gsimalloc(GP_UNIQUENICK_LEN * sizeof(unsigned short)); + if(arg->suggestedNicks[count] == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + UTF8ToUCS2StringLen(value, arg->suggestedNicks[count], GP_UNIQUENICK_LEN); +#endif + count++; + } + else if(strcmp(key, "usdone") == 0) + { + // Check that the header matches the actual number of nicks. + //////////////////////////////////////////////////////////// + assert(count == arg->numSuggestedNicks); + arg->numSuggestedNicks = count; + + // Done. + //////// + done = GPITrue; + } + else + { + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading from the search server."); + } + } + while(!done); + + // Do it. + ///////// + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, GPI_ADD_SUGGESTED_UNIQUE)); + } + } + else + { + assert(0); + } + + // Flag the operation for removal. + ////////////////////////////////// + data->remove = GPITrue; + + // If we're looping, stop. + ////////////////////////// + loop = GPIFalse; + } + } + //PANTS|05.23.00 - removed sleep + //crt - added it back 6/13/00 + //PANTS|07.10.00 - only sleep if looping + if(loop) + msleep(10); + } while(loop); + + + + return GP_NO_ERROR; +} + +GPResult +gpiProcessSearches( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIOperation ** searchList; + GPIOperation * operation; + GPISearchData * data; + GPResult result; + int num = 0; + int i; + + // Are there any searches? + ////////////////////////// + if(iconnection->numSearches > 0) + { + // Alloc mem for a search list. + /////////////////////////////// + searchList = (GPIOperation **)gsimalloc(sizeof(GPIOperation *) * iconnection->numSearches); + if(searchList == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + // Create the search list. + ////////////////////////// + for(operation = &iconnection->operationList[0] ; operation != NULL ; operation = operation->pnext) + { + // Is this a search? + //////////////////// + if((operation->type == GPI_PROFILE_SEARCH) && (operation->state != GPI_FINISHING)) + { + // Is this search being processed already? + ////////////////////////////////////////// + if(!((GPISearchData *)operation->data)->processing) + { + assert(num < iconnection->numSearches); + searchList[num++] = operation; + ((GPISearchData *)operation->data)->processing = GPITrue; + } + } + } + + // Process the searches. + //////////////////////// + for(i = 0 ; i < num ; i++) + { + result = gpiProcessSearch(connection, searchList[i]); + if(result != GP_NO_ERROR) + searchList[i]->result = result; + } + + // Clear the processing flags, and remove searches that are done. + ///////////////////////////////////////////////////////////////// + for(i = 0 ; i < num ; i++) + { + data = ((GPISearchData *)searchList[i]->data); + data->processing = GPIFalse; + if(data->remove) + gpiRemoveOperation(connection, searchList[i]); + } + + freeclear(searchList); + } + + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiSearch.h b/xrGameSpy/gamespy/GP/gpiSearch.h new file mode 100644 index 00000000000..1321258826f --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiSearch.h @@ -0,0 +1,172 @@ +/* +gpiSearch.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPISEARCH_H_ +#define _GPISEARCH_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//TYPES +/////// +#define GPI_SEARCH_PROFILE 1 +#define GPI_SEARCH_IS_VALID 2 +#define GPI_SEARCH_NICKS 3 +#define GPI_SEARCH_PLAYERS 4 +#define GPI_SEARCH_CHECK 5 +#define GPI_SEARCH_NEWUSER 6 +#define GPI_SEARCH_OTHERS_BUDDY 7 +#define GPI_SEARCH_SUGGEST_UNIQUE 8 +#define GPI_SEARCH_OTHERS_BUDDY_LIST 9 +#define GPI_SEARCH_PROFILE_UNIQUENICK 10 + +// A timeout used to abort searches taking too long +#define GPI_SEARCH_TIMEOUT 60000 + +// Profile Search operation data. +///////////////////////////////// +typedef struct +{ + int type; + SOCKET sock; + GPIBuffer inputBuffer; + GPIBuffer outputBuffer; + char nick[GP_NICK_LEN]; + char uniquenick[GP_UNIQUENICK_LEN]; + int namespaceIDs[GP_MAX_NAMESPACEIDS]; + int numNamespaces; + char email[GP_EMAIL_LEN]; + char firstname[GP_FIRSTNAME_LEN]; + char lastname[GP_LASTNAME_LEN]; + char password[GP_PASSWORD_LEN]; + char cdkey[GP_CDKEY_LEN]; + int partnerID; + int icquin; + int skip; + int productID; + GPIBool processing; + GPIBool remove; + gsi_time searchStartTime; + int *revBuddyProfileIds; + int numOfRevBuddyProfiles; +} GPISearchData; + +//FUNCTIONS +/////////// +GPResult +gpiProfileSearch( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char firstname[GP_FIRSTNAME_LEN], + const char lastname[GP_LASTNAME_LEN], + int icquin, + int skip, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult +gpiProfileSearchUniquenick( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const int namespaceIDs[], + int numNamespaces, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult +gpiIsValidEmail( + GPConnection * connection, + const char email[GP_EMAIL_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult +gpiGetUserNicks( + GPConnection * connection, + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult +gpiFindPlayers( + GPConnection * connection, + int productID, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiCheckUser( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiNewUser( + GPConnection * connection, + const char nick[GP_NICK_LEN], + const char uniquenick[GP_UNIQUENICK_LEN], + const char email[GP_EMAIL_LEN], + const char password[GP_PASSWORD_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiOthersBuddy( + GPConnection * connection, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiOthersBuddyList( + GPConnection * connection, + int *profiles, + int numOfProfiles, + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiSuggestUniqueNick( + GPConnection * connection, + const char desirednick[GP_NICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult +gpiProcessSearches( + GPConnection * connection +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiTransfer.c b/xrGameSpy/gamespy/GP/gpiTransfer.c new file mode 100644 index 00000000000..e681414978b --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiTransfer.c @@ -0,0 +1,2005 @@ +/* +gpiTransfer.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 1363, 1520, 1528, 1529, 1530 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +//INCLUDES +////////// +#include +#ifdef _WIN32 +#include +#endif +#include +#include "gpi.h" + +#define GPI_TRANSFER_VERSION 1 +#define GPI_PEER_TIMEOUT_TIME (1 * 60000) +#define GPI_KEEPALIVE_TIME (4 * 60000) + +//#define GPI_ACKNOWLEDGED_WINDOW (100000 * 1024) +#define GPI_DATA_SIZE (1 * 1024) +//#define GPI_CONFIRM_FILES + +//FUNCTIONS +/////////// +#ifndef NOFILE +static void gpiTransferFree(void * elem) +{ + GPITransfer * transfer = (GPITransfer *)elem; + + if(transfer->message) + freeclear(transfer->message); + + if(transfer->baseDirectory) + gsifree(transfer->baseDirectory); + + if(transfer->files) + { + ArrayFree(transfer->files); + transfer->files = NULL; + } +} + +static int gpiTransferCompare(const void * elem1, const void * elem2) +{ + GPITransfer * transfer1 = (GPITransfer *)elem1; + GPITransfer * transfer2 = (GPITransfer *)elem2; + + return (transfer1->localID - transfer2->localID); +} + +static void gpiFreeFile(void * elem) +{ + GPIFile * file = (GPIFile *)elem; + gsifree(file->path); + gsifree(file->name); + +#ifdef GSI_UNICODE + gsifree(file->path_W); + gsifree(file->name_W); +#endif +} + +static GPResult +gpiFinishTransferMessage( + GPConnection * connection, + GPITransfer * transfer, + const char * message, + int len +) +{ + GPResult result = gpiPeerFinishTransferMessage(connection, transfer->peer, message, len); + + transfer->lastSend = current_time(); + + return result; +} + +GPResult gpiInitTransfers( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + iconnection->transfers = ArrayNew(sizeof(GPITransfer), 0, gpiTransferFree); + if(!iconnection->transfers) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + return GP_NO_ERROR; +} + +void gpiCleanupTransfers( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Free the transfers. + ////////////////////// + if(iconnection->transfers) + { + ArrayFree(iconnection->transfers); + iconnection->transfers = NULL; + } +} + +static GPResult gpiNewTransfer +( + GPConnection * connection, + GPITransfer ** transfer, + GPProfile profile, + GPIBool sender +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPITransfer transferTemp; + + // Fill in the object. + ////////////////////// + memset(&transferTemp, 0, sizeof(GPITransfer)); + transferTemp.files = ArrayNew(sizeof(GPIFile), 0, gpiFreeFile); + if(!transferTemp.files) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + transferTemp.localID = iconnection->nextTransferID++; + transferTemp.sender = sender; + transferTemp.profile = profile; + transferTemp.throttle = -1; + transferTemp.currentFile = -1; + + // Add it. + ////////// + ArrayAppend(iconnection->transfers, &transferTemp); + + // Get it. + ////////// + *transfer = (GPITransfer *)ArrayNth(iconnection->transfers, ArrayLength(iconnection->transfers) - 1); + + return GP_NO_ERROR; +} + +GPResult gpiNewSenderTransfer +( + GPConnection * connection, + GPITransfer ** transfer, + GPProfile profile +) +{ + GPITransfer * pTransfer; + GPIConnection * iconnection = (GPIConnection*)*connection; + unsigned long now; + + CHECK_RESULT(gpiNewTransfer(connection, transfer, profile, GPITrue)); + + now = current_time(); + + pTransfer = *transfer; + pTransfer->state = GPITransferPinging; + pTransfer->transferID.profileid = iconnection->profileid; + pTransfer->transferID.count = pTransfer->localID; + pTransfer->transferID.time = (unsigned int)now; + pTransfer->lastSend = now; + + return GP_NO_ERROR; +} + +static GPResult gpiNewReceiverTransfer +( + GPConnection * connection, + GPITransfer ** transfer, + GPProfile profile, + GPITransferID * transferID +) +{ +#ifdef WIN32 + char buffer[FILENAME_MAX]; +#endif + GPITransfer * pTransfer; + + CHECK_RESULT(gpiNewTransfer(connection, transfer, profile, GPIFalse)); + + pTransfer = *transfer; + pTransfer->state = GPITransferWaiting; + memcpy(&pTransfer->transferID, transferID, sizeof(GPITransferID)); +#ifdef WIN32 + if(GetTempPathA(sizeof(buffer), buffer) != 0) + pTransfer->baseDirectory = goastrdup(buffer); +#endif + + return GP_NO_ERROR; +} + +void gpiFreeTransfer +( + GPConnection * connection, + GPITransfer * transfer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int pos; + + // Find the transfer. + ///////////////////// + pos = ArraySearch(iconnection->transfers, transfer, gpiTransferCompare, 0, 0); + assert(pos != NOT_FOUND); + if(pos == NOT_FOUND) + return; + + // Remove it. + ///////////// + ArrayDeleteAt(iconnection->transfers, pos); +} + +void gpiCancelTransfer +( + GPConnection * connection, + GPITransfer * transfer +) +{ + // Send the cancel message. + /////////////////////////// + if(transfer->peer) + { + // Start the message. + ///////////////////// + if(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_TRANSFER_CANCEL, (GPITransferID_st)&transfer->transferID) == GP_NO_ERROR) + { + // Finish the message. + ////////////////////// + gpiFinishTransferMessage(connection, transfer, NULL, 0); + } + } +} + +void gpiTransferError +( + GPConnection * connection, + const GPITransfer * transfer +) +{ + GPTransferCallbackArg * arg; + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_ERROR; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } +} + +GPIFile * gpiAddFileToTransfer +( + GPITransfer * transfer, + const char * path, + const char * name +) +{ + GPIFile file; + char * str; + + assert(name && name[0]); + + memset(&file, 0, sizeof(GPIFile)); + + // Copy the path. + ///////////////// + if(path) + { + file.path = goastrdup(path); + if(!file.path) + return NULL; + } + + // Copy the name. + ///////////////// + file.name = goastrdup(name); + if(!file.name) + { + gsifree(file.path); + return NULL; + } + + // Change all slashes to backslashes. + ///////////////////////////////////// + while((str = strchr(file.name, '\\')) != NULL) + *str = '/'; + + // Check for a directory. + ///////////////////////// + if(name[strlen(name) - 1] == '/') + file.flags = GPI_FILE_DIRECTORY; + + // No size yet. + /////////////// + file.size = -1; + + // Add it to the list of files. + /////////////////////////////// + ArrayAppend(transfer->files, &file); + +#ifdef GSI_UNICODE + // Copy the unicode versions + file.name_W = UTF8ToUCS2StringAlloc(file.name); + file.path_W = UTF8ToUCS2StringAlloc(file.path); +#endif + + // Return the file. + /////////////////// + return (GPIFile *)ArrayNth(transfer->files, ArrayLength(transfer->files) - 1); +} + +static GPResult gpiSendTransferRequest +( + GPConnection * connection, + GPITransfer * transfer +) +{ + char buffer[32]; + GPIFile * file; + int i; + int num; + + // Get the number of files. + /////////////////////////// + num = ArrayLength(transfer->files); + + // Start the message. + ///////////////////// + CHECK_RESULT(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_SEND_REQUEST, (GPITransferID_st)&transfer->transferID)); + + // Add the rest of the headers. + /////////////////////////////// + sprintf(buffer, "\\version\\%d\\num\\%d", GPI_TRANSFER_VERSION, num); + CHECK_RESULT(gpiSendOrBufferString(connection, transfer->peer, buffer)); + for(i = 0 ; i < num ; i++) + { + file = (GPIFile *)ArrayNth(transfer->files, i); + + sprintf(buffer, "\\name%d\\", i); + CHECK_RESULT(gpiSendOrBufferString(connection, transfer->peer, buffer)); + CHECK_RESULT(gpiSendOrBufferString(connection, transfer->peer, file->name)); + + sprintf(buffer, "\\size%d\\", i); + CHECK_RESULT(gpiSendOrBufferString(connection, transfer->peer, buffer)); + CHECK_RESULT(gpiSendOrBufferInt(connection, transfer->peer, file->size)); + + sprintf(buffer, "\\mtime%d\\", i); + CHECK_RESULT(gpiSendOrBufferString(connection, transfer->peer, buffer)); + CHECK_RESULT(gpiSendOrBufferUInt(connection, transfer->peer, file->modTime)); + } + + // Finish the message. + ////////////////////// + CHECK_RESULT(gpiFinishTransferMessage(connection, transfer, transfer->message, -1)); + + return GP_NO_ERROR; +} + +static GPITransfer * gpiFindTransferByTransferID +( + GPConnection * connection, + GPITransferID * transferID +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int i; + int num; + GPITransfer * transfer; + + num = ArrayLength(iconnection->transfers); + for(i = 0 ; i < num ; i++) + { + transfer = (GPITransfer *)ArrayNth(iconnection->transfers, i); + if(memcmp(&transfer->transferID, transferID, sizeof(GPITransferID)) == 0) + return transfer; + } + + return NULL; +} + +GPITransfer * gpiFindTransferByLocalID +( + GPConnection * connection, + int localID +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int i; + int num; + GPITransfer * transfer; + + num = ArrayLength(iconnection->transfers); + for(i = 0 ; i < num ; i++) + { + transfer = (GPITransfer *)ArrayNth(iconnection->transfers, i); + if(transfer->localID == localID) + return transfer; + } + + return NULL; +} + +int gpiGetTransferLocalIDByIndex +( + GPConnection * connection, + int index +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPITransfer * transfer; + int num; + + num = ArrayLength(iconnection->transfers); + assert(index >= 0); + assert(index < num); + if((index < 0) || (index >= num)) + return -1; + + transfer = (GPITransfer *)ArrayNth(iconnection->transfers, index); + assert(transfer); + if(!transfer) + return -1; + + return transfer->localID; +} + +void gpiSkipFile +( + GPConnection * connection, + GPITransfer * transfer, + int file, + int reason +) +{ + char buffer[32]; + + if(gpiPeerStartTransferMessage(connection, transfer->peer, GP_FILE_SKIP, (GPITransferID_st)&transfer->transferID) != GP_NO_ERROR) + return; + + sprintf(buffer, "\\file\\%d\\reason\\%d", file, reason); + gpiSendOrBufferString(connection, transfer->peer, buffer); + gpiFinishTransferMessage(connection, transfer, NULL, 0); +} + +void gpiSkipCurrentFile +( + GPConnection * connection, + GPITransfer * transfer, + int reason +) +{ + gpiSkipFile(connection, transfer, transfer->currentFile, reason); + + transfer->currentFile++; +} + +static GPIBool gpiHandleSendRequest +( + GPConnection * connection, + GPIPeer * peer, + GPITransferID * transferID, + const char * headers, + const char * buffer, + int bufferLen +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPITransfer * transfer; + GPIFile * file; + GPTransferCallbackArg * arg; + char key[16]; + char intValue[16]; + int version; + int numFiles; + char name[FILENAME_MAX]; + int size; + unsigned int mtime; + int i; + size_t len; + int totalSize = 0; + + // If we don't have a callback, we're not accepting requests. + ///////////////////////////////////////////////////////////// + if(!iconnection->callbacks[GPI_TRANSFER_CALLBACK].callback) + return GPIFalse; + + // Check the version. + ///////////////////// + if(!gpiValueForKey(headers, "\\version\\", intValue, sizeof(intValue))) + return GPIFalse; + version = atoi(intValue); + if(version < 1) + return GPIFalse; + + // Get the number of files. + /////////////////////////// + if(!gpiValueForKey(headers, "\\num\\", intValue, sizeof(intValue))) + return GPIFalse; + numFiles = atoi(intValue); + if(numFiles < 1) + return GPIFalse; + + // Create the transfer object. + ////////////////////////////// + if(gpiNewReceiverTransfer(connection, &transfer, peer->profile, transferID) != GP_NO_ERROR) + return GPIFalse; + + // Set the peer. + //////////////// + transfer->peer = peer; + + // Parse the file list. + /////////////////////// + for(i = 0 ; i < numFiles ; i++) + { + sprintf(key, "\\name%d\\", i); + if(!gpiValueForKey(headers, key, name, sizeof(name))) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + len = strlen(name); + if(strstr(name, "//") || strstr(name, "./") || (name[len - 1] == '.') || (name[0] == '/') || (strcspn(name, ":*?\"<>|\n") != len)) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + + sprintf(key, "\\size%d\\", i); + if(!gpiValueForKey(headers, key, intValue, sizeof(intValue))) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + size = atoi(intValue); + if(size < 0) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + totalSize += size; + + sprintf(key, "\\mtime%d\\", i); + if(!gpiValueForKey(headers, key, intValue, sizeof(intValue))) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + mtime = (unsigned int)strtoul(intValue, NULL, 10); + + file = gpiAddFileToTransfer(transfer, NULL, name); + if(!file) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + file->size = size; + file->modTime = mtime; + } + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(!arg) + { + gpiFreeTransfer(connection, transfer); + return GPIFalse; + } + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_SEND_REQUEST; + arg->num = numFiles; +#ifndef GSI_UNICODE + arg->message = goastrdup(buffer); +#else + arg->message = UTF8ToUCS2StringAlloc(buffer); +#endif + { + GPResult aResult = gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + if (aResult != GP_NO_ERROR) + return GPIFalse; + } + + // Store the total size. + //////////////////////// + transfer->totalSize = totalSize; + + return GPITrue; + + GSI_UNUSED(bufferLen); +} + +static GPIBool gpiHandleSendReply +( + GPConnection * connection, + GPITransfer * transfer, + const char * headers, + const char * buffer, + int bufferLen +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + char intValue[16]; + int version; + int result; + + if(!transfer->sender) + return GPIFalse; + + // Check the version. + //////////////////// + if(!gpiValueForKey(headers, "\\version\\", intValue, sizeof(intValue))) + return GPIFalse; + version = atoi(intValue); + if(version < 1) + return GPIFalse; + + // Get the result. + ////////////////// + if(!gpiValueForKey(headers, "\\result\\", intValue, sizeof(intValue))) + return GPIFalse; + result = atoi(intValue); + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + if(result == GPI_ACCEPTED) + arg->type = GP_TRANSFER_ACCEPTED; + else if(result == GPI_REJECTED) + arg->type = GP_TRANSFER_REJECTED; + else + arg->type = GP_TRANSFER_NOT_ACCEPTING; + +#ifndef GSI_UNICODE + arg->message = goastrdup(buffer); +#else + arg->message = UTF8ToUCS2StringAlloc(buffer); +#endif + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Update transfer state if accepted. + ///////////////////////////////////// + if(result == GPI_ACCEPTED) + { + transfer->state = GPITransferTransferring; + transfer->currentFile = 0; + } + + return GPITrue; + + GSI_UNUSED(bufferLen); +} + +static GPIBool gpiHandleBegin +( + GPConnection * connection, + GPITransfer * transfer, + const char * headers +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + GPIFile * file; + char intValue[16]; + int fileIndex; + int size; + unsigned int mtime; + char buffer[FILENAME_MAX]; + int count; + + if(transfer->sender) + return GPIFalse; + + // Get the file. + //////////////// + if(!gpiValueForKey(headers, "\\file\\", intValue, sizeof(intValue))) + return GPIFalse; + fileIndex = atoi(intValue); + if((fileIndex < 0) || (fileIndex >= ArrayLength(transfer->files))) + return GPIFalse; + if(fileIndex != transfer->currentFile) + return GPIFalse; + file = (GPIFile *)ArrayNth(transfer->files, fileIndex); + + // Is this a directory? + /////////////////////// + if(file->flags & GPI_FILE_DIRECTORY) + return GPIFalse; + + // Get the size. + //////////////// + if(!gpiValueForKey(headers, "\\size\\", intValue, sizeof(intValue))) + return GPIFalse; + size = atoi(intValue); + if(size < 0) + return GPIFalse; + + // Update the total size. + ///////////////////////// + transfer->totalSize -= file->size; + transfer->totalSize += size; + + // Get the mod time. + //////////////////// + if(!gpiValueForKey(headers, "\\mtime\\", intValue, sizeof(intValue))) + return GPIFalse; + mtime = (unsigned int)strtoul(intValue, NULL, 10); + + // Set file stuff. + ////////////////// + MD5Init(&file->md5); + file->modTime = mtime; + file->size = size; + + // Setup the temp path. + /////////////////////// + count = 0; + do + { + sprintf(buffer, "%sgpt_%d_%d_%d.gpt", transfer->baseDirectory, transfer->localID, fileIndex, rand()); + file->file = fopen(buffer, "wb"); + count++; + } + while(!file->file && (count < 5)); + + // Copy off the path. + ///////////////////// + if(file->file) + { + file->path = goastrdup(buffer); + if(!file->path) + return GPIFalse; + +#ifdef GSI_UNICODE + file->path_W = UTF8ToUCS2StringAlloc(file->path); +#endif + } + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = fileIndex; + if(file->file) + { + arg->type = GP_FILE_BEGIN; + } + else + { + arg->type = GP_FILE_FAILED; + arg->num = GP_FILE_WRITE_ERROR; + } + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Did it fail? + /////////////// + if(!file->file) + { + gpiSkipCurrentFile(connection, transfer, GPI_SKIP_WRITE_ERROR); + file->flags |= GPI_FILE_FAILED; + file->reason = GP_FILE_WRITE_ERROR; + } + + return GPITrue; +} + +static GPIBool gpiHandleEnd +( + GPConnection * connection, + GPITransfer * transfer, + const char * headers +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + GPIFile * file; + GPIBool md5Failed = GPITrue; + unsigned char rawMD5[16]; + char localMD5[33]; + char remoteMD5[33]; + char intValue[16]; + int fileIndex; + + if(transfer->currentFile == -1) + return GPIFalse; + + // Check the file index. + //////////////////////// + if(!gpiValueForKey(headers, "\\file\\", intValue, sizeof(intValue))) + return GPIFalse; + fileIndex = atoi(intValue); + if((fileIndex < 0) || (fileIndex >= ArrayLength(transfer->files))) + return GPIFalse; + if(fileIndex != transfer->currentFile) + return GPITrue; + + // Get the current file. + //////////////////////// + file = (GPIFile *)ArrayNth(transfer->files, transfer->currentFile); + + // Sender? + ////////// + if(transfer->sender) + { +#ifdef GPI_CONFIRM_FILES + // We should be waiting for confirmation. + ///////////////////////////////////////// + assert(file->flags & GPI_FILE_CONFIRMING); + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_END; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Done with the file. + ////////////////////// + file->flags &= ~GPI_FILE_CONFIRMING; + file->flags |= GPI_FILE_COMPLETED; + transfer->currentFile++; +#endif + return GPITrue; + } + + // Is this a directory? + /////////////////////// + if(file->flags & GPI_FILE_DIRECTORY) + { + // Directory completed. + /////////////////////// + file->flags |= GPI_FILE_COMPLETED; + } + else + { + // Check the file. + ////////////////// + assert(file->file); + if(!file->file) + return GPIFalse; + + // Get the remote md5. + ////////////////////// + if(!gpiValueForKey(headers, "\\md5\\", remoteMD5, sizeof(remoteMD5))) + return GPIFalse; + + // Get the local md5. + ///////////////////// + MD5Final(rawMD5, &file->md5); + MD5Print(rawMD5, localMD5); + + // Check the md5. + ///////////////// + md5Failed = (memcmp(localMD5, remoteMD5, 32) != 0) ? GPITrue:GPIFalse; + + // Set the state. + ///////////////// + if(md5Failed) + { + file->flags |= GPI_FILE_FAILED; + file->reason = GP_FILE_DATA_ERROR; + } + else + file->flags |= GPI_FILE_COMPLETED; + + // Close the file. + ////////////////// + fclose(file->file); + file->file = NULL; + + // If the md5 failed, remove the file. + ////////////////////////////////////// + if(md5Failed) + remove(file->path); + +#ifdef GPI_CONFIRM_FILES + // Send a confirmation. + /////////////////////// + if(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_END, (GPITransferID_st)&transfer->transferID) != GP_NO_ERROR) + return GPIFalse; + gpiFinishTransferMessage(connection, transfer, NULL, 0); +#endif + } + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + if(file->flags & GPI_FILE_DIRECTORY) + { + arg->type = GP_FILE_DIRECTORY; + } + else if(md5Failed) + { + arg->type = GP_FILE_FAILED; + arg->num = GP_FILE_DATA_ERROR; + } + else + { + arg->type = GP_FILE_END; + } + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Next file. + ///////////// + transfer->currentFile++; + + // Done? + //////// + if(transfer->currentFile == ArrayLength(transfer->files)) + { + // The transfer is complete. + //////////////////////////// + transfer->state = GPITransferComplete; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_DONE; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + } + + return GPITrue; +} + +static GPIBool gpiHandleData +( + GPConnection * connection, + GPITransfer * transfer, + const char * headers, + const char * buffer, + int bufferLen +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + GPIFile * file; + GPIBool writeFailed; + char intValue[16]; + int fileIndex; + + if(transfer->currentFile == -1) + return GPIFalse; + + // Check the file index. + //////////////////////// + if(!gpiValueForKey(headers, "\\file\\", intValue, sizeof(intValue))) + return GPIFalse; + fileIndex = atoi(intValue); + if((fileIndex < 0) || (fileIndex >= ArrayLength(transfer->files))) + return GPIFalse; + if(fileIndex != transfer->currentFile) + return GPITrue; + + // Get the current file. + //////////////////////// + file = (GPIFile *)ArrayNth(transfer->files, transfer->currentFile); + + // Is this a directory? + /////////////////////// + if(file->flags & GPI_FILE_DIRECTORY) + return GPIFalse; + +#ifdef GPI_ACKNOWLEDGED_WINDOW + // Sender? + ////////// + if(transfer->sender) + { + char intValue[16]; + + // Get the progress. + //////////////////// + if(!gpiValueForKey(headers, "\\pro\\", intValue, sizeof(intValue))) + return GPIFalse; + file->acknowledged = atoi(intValue); + + return GPITrue; + } +#endif + + // Check the file. + ////////////////// + assert(file->file); + if(!file->file) + return GPIFalse; + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_RawDump, + "HNDLDATA(PT): %d\n", bufferLen); + + // Write the data. + ////////////////// + writeFailed = (GPIBool)(fwrite(buffer, 1, bufferLen, file->file) != (size_t)bufferLen); + if(writeFailed) + { + // Flag the errors. + /////////////////// + file->flags |= GPI_FILE_FAILED; + file->reason = GP_FILE_WRITE_ERROR; + + // Remove the file. + /////////////////// + fclose(file->file); + file->file = NULL; + remove(file->path); + } + else + { + // Update the MD5. + /////////////////// + MD5Update(&file->md5, (unsigned char *)buffer, bufferLen); + + // Update the progress. + /////////////////////// + file->progress += bufferLen; + transfer->progress += bufferLen; + +#ifdef GPI_ACKNOWLEDGED_WINDOW + // Send an acknowledgment. + ////////////////////////// + if(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_DATA, (GPITransferID_st)&transfer->transferID) != GP_NO_ERROR) + return GPIFalse; + gpiSendOrBufferString(connection, transfer->peer, "\\pro\\"); + gpiSendOrBufferInt(connection, transfer->peer, file->progress); + gpiFinishTransferMessage(connection, transfer, NULL, 0); +#endif + } + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + if(!writeFailed) + { + arg->type = GP_FILE_PROGRESS; + arg->num = file->progress; + } + else + { + arg->type = GP_FILE_FAILED; + arg->num = GP_FILE_WRITE_ERROR; + } + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Did it fail? + /////////////// + if(writeFailed) + { + // Skip the file. + ///////////////// + gpiSkipCurrentFile(connection, transfer, GPI_SKIP_WRITE_ERROR); + } + + return GPITrue; +} + +static GPIBool gpiHandleSkip +( + GPConnection * connection, + GPITransfer * transfer, + const char * headers +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + GPIFile * file; + char intValue[16]; + int fileIndex; + int reason; + + // Get the file. + //////////////// + if(!gpiValueForKey(headers, "\\file\\", intValue, sizeof(intValue))) + return GPIFalse; + fileIndex = atoi(intValue); + if((fileIndex < 0) || (fileIndex >= ArrayLength(transfer->files))) + return GPIFalse; + file = (GPIFile *)ArrayNth(transfer->files, fileIndex); + + // Get the reason. + ////////////////// + if(!gpiValueForKey(headers, "\\reason\\", intValue, sizeof(intValue))) + return GPIFalse; + reason = atoi(intValue); + + // Is it not the current file? + ////////////////////////////// + if(fileIndex != transfer->currentFile) + { + // Check if we already finished this file. + ////////////////////////////////////////// + if(fileIndex < transfer->currentFile) + return GPIFalse; + + // Mark it for skipping later. + ////////////////////////////// + if(reason == GPI_SKIP_USER_SKIP) + { + file->flags |= GPI_FILE_SKIP; + } + else + { + file->flags |= GPI_FILE_FAILED; + if(reason == GPI_SKIP_READ_ERROR) + file->reason = GP_FILE_READ_ERROR; + else + file->reason = GP_FILE_WRITE_ERROR; + } + + return GPITrue; + } + + // Delete the file if its already opened. + ///////////////////////////////////////// + if(!transfer->sender && file->file) + { + fclose(file->file); + file->file = NULL; + remove(file->path); + } + + // Next file. + ///////////// + transfer->currentFile++; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = fileIndex; + if(reason == GPI_SKIP_USER_SKIP) + { + arg->type = GP_FILE_SKIP; + } + else + { + arg->type = GP_FILE_FAILED; + if(reason == GPI_SKIP_READ_ERROR) + arg->num = GP_FILE_READ_ERROR; + else + arg->num = GP_FILE_WRITE_ERROR; + } + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + return GPITrue; +} + +static GPIBool gpiHandleTransferThrottle +( + GPConnection * connection, + GPITransfer * transfer, + const char * headers +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int throttle; + char intValue[16]; + GPTransferCallbackArg * arg; + + // Get the throttle. + //////////////////// + if(!gpiValueForKey(headers, "\\rate\\", intValue, sizeof(intValue))) + return GPIFalse; + throttle = atoi(intValue); + + // Store the throttle. + ////////////////////// + transfer->throttle = throttle; + + // If we're the sender, send this back. + /////////////////////////////////////// + if(transfer->sender) + { + if(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_TRANSFER_THROTTLE, (GPITransferID_st)&transfer->transferID) != GP_NO_ERROR) + return GPIFalse; + gpiSendOrBufferString(connection, transfer->peer, "\\rate\\"); + gpiSendOrBufferInt(connection, transfer->peer, throttle); + gpiFinishTransferMessage(connection, transfer, NULL, 0); + } + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_THROTTLE; + arg->num = throttle; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + return GPITrue; +} + +static GPIBool gpiHandleTransferCancel +( + GPConnection * connection, + GPITransfer * transfer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + +// if(transfer->sender) +// return GPIFalse; + + // Mark the transfer cancelled. + /////////////////////////////// + transfer->state = GPITransferCancelled; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_CANCELLED; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + return GPITrue; +} + +static GPIBool gpiHandleTransferKeepalive +( + GPConnection * connection, + GPITransfer * transfer +) +{ + GSI_UNUSED(connection); + GSI_UNUSED(transfer); + + // Ignore keep-alive. + ///////////////////// + return GPITrue; +} + +static GPResult gpiSendFileEnd +( + GPConnection * connection, + GPITransfer * transfer, + GPIFile * file +) +{ + CHECK_RESULT(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_END, (GPITransferID_st)&transfer->transferID)); + + // Add the file index. + ////////////////////// + gpiSendOrBufferStringLenToPeer(connection, transfer->peer, "\\file\\", 6); + gpiSendOrBufferInt(connection, transfer->peer, transfer->currentFile); + + // Only add the MD5 for files. + ////////////////////////////// + if(!(file->flags & GPI_FILE_DIRECTORY)) + { + unsigned char md5Raw[16]; + char md5[33]; + + // Get the MD5. + /////////////// + MD5Final(md5Raw, &file->md5); + MD5Print(md5Raw, md5); + + // Add it. + ////////// + gpiSendOrBufferString(connection, transfer->peer, "\\md5\\"); + gpiSendOrBufferString(connection, transfer->peer, md5); + } + + gpiFinishTransferMessage(connection, transfer, NULL, 0); + + return GP_NO_ERROR; +} + +static GPResult gpiSendFileBegin +( + GPConnection * connection, + GPITransfer * transfer, + GPIFile * file +) +{ + char buffer[64]; + + // Get the file info. + ///////////////////// + if(!gpiGetTransferFileInfo(file->file, &file->size, &file->modTime)) + Error(connection, GP_PARAMETER_ERROR, "Can't get info on file."); + + CHECK_RESULT(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_BEGIN, (GPITransferID_st)&transfer->transferID)); + sprintf(buffer, "\\file\\%d\\size\\%d\\mtime\\%u", transfer->currentFile, file->size, (unsigned int)file->modTime); + gpiSendOrBufferString(connection, transfer->peer, buffer); + gpiFinishTransferMessage(connection, transfer, NULL, 0); + + return GP_NO_ERROR; +} + +static GPResult gpiSendFileData +( + GPConnection * connection, + GPITransfer * transfer, + unsigned char * data, + size_t len +) +{ + CHECK_RESULT(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_DATA, (GPITransferID_st)&transfer->transferID)); + + // Add the file index. + ////////////////////// + gpiSendOrBufferStringLenToPeer(connection, transfer->peer, "\\file\\", 6); + gpiSendOrBufferInt(connection, transfer->peer, transfer->currentFile); + + gpiFinishTransferMessage(connection, transfer, (char *)data, len); + + return GP_NO_ERROR; +} + +GPResult gpiProcessCurrentFile +( + GPConnection * connection, + GPITransfer * transfer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPIFile * file; + GPTransferCallbackArg * arg; + size_t num; + int i; + int total; + + assert(transfer->currentFile >= 0); + assert(transfer->currentFile < ArrayLength(transfer->files)); + + // Get the current file. + //////////////////////// + file = (GPIFile *)ArrayNth(transfer->files, transfer->currentFile); + + assert(!(file->flags & GPI_FILE_FAILED)); + +#ifdef GPI_CONFIRM_FILES + // If it's being confirmed, just wait. + ////////////////////////////////////// + if(file->flags & GPI_FILE_CONFIRMING) + return GP_NO_ERROR; +#endif + + // Check if its been marked for skipping. + ///////////////////////////////////////// + if(file->flags & GPI_FILE_SKIP) + { + // Skip it. + /////////// + gpiSkipCurrentFile(connection, transfer, GPI_SKIP_USER_SKIP); + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_SKIP; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + } + else + { + // Is this a directory? + /////////////////////// + if(file->flags & GPI_FILE_DIRECTORY) + { + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_DIRECTORY; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Send the end. + //////////////// + gpiSendFileEnd(connection, transfer, file); + file->flags |= GPI_FILE_COMPLETED; + transfer->currentFile++; + } + else + { + static char buffer[GPI_DATA_SIZE]; + + // Open the file if we need to. + /////////////////////////////// + if(!file->file) + { + // Open it. + /////////// + file->file = fopen(file->path, "rb"); + if(file->file) + { + // Send the begin. + ////////////////// + CHECK_RESULT(gpiSendFileBegin(connection, transfer, file)); + + // Init the md5. + //////////////// + MD5Init(&file->md5); + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_BEGIN; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + } + else + { + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_FAILED; + arg->num = GP_FILE_READ_ERROR; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Failed to open. + ////////////////// + gpiSkipCurrentFile(connection, transfer, GPI_SKIP_READ_ERROR); + file->flags |= GPI_FILE_FAILED; + file->reason = GP_FILE_READ_ERROR; + + return GP_NO_ERROR; + } + } + + // TODO: THROTTLING + + // Send until done, and while messages are actually being sent. + /////////////////////////////////////////////////////////////// + total = 0; + for(i = 0 ; (file->progress < file->size) && !transfer->peer->outputBuffer.len /*&& (i < 20)*/ ; i++) + { +#ifdef GPI_ACKNOWLEDGED_WINDOW + // Don't get too far ahead. + /////////////////////////// + if((file->acknowledged + GPI_ACKNOWLEDGED_WINDOW) < file->progress) + break; +#endif + + // Read data. + ///////////// + num = fread(buffer, 1, sizeof(buffer), file->file); + if(num) + { + // Update the md5. + ////////////////// + MD5Update(&file->md5, (unsigned char*)buffer, num); + + // Send the data. + ///////////////// + CHECK_RESULT(gpiSendFileData(connection, transfer, (unsigned char*)buffer, num)); + + // Update progress. + /////////////////// + transfer->progress += num; + file->progress += num; + total += num; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_PROGRESS; + arg->num = file->progress; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + } + + // Did we not get to the end? + ///////////////////////////// + if((num < sizeof(buffer)) && (file->progress != file->size)) + { + // Failed reading. + ////////////////// + gpiSkipCurrentFile(connection, transfer, GPI_SKIP_READ_ERROR); + file->flags |= GPI_FILE_FAILED; + file->reason = GP_FILE_READ_ERROR; + + return GP_NO_ERROR; + } + } + + if(total) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_File, GSIDebugLevel_RawDump, + "SENTTOTL(PT): %d\n", total); + } + + // Did we finish the file? + ////////////////////////// + if(file->progress == file->size) + { + // Close the file. + ////////////////// + fclose(file->file); + file->file = NULL; + + // Send the end. + //////////////// + gpiSendFileEnd(connection, transfer, file); + +#ifdef GPI_CONFIRM_FILES + // Wait for the confirmation. + ///////////////////////////// + file->flags |= GPI_FILE_CONFIRMING; +#else + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->index = transfer->currentFile; + arg->type = GP_FILE_END; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Done with the file. + ////////////////////// + file->flags |= GPI_FILE_COMPLETED; + transfer->currentFile++; +#endif + } + } + } + + return GP_NO_ERROR; +} + +GPResult gpiProcessTransfer +( + GPConnection * connection, + GPITransfer * transfer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int currentFile; + int len; + GPTransferCallbackArg * arg; + unsigned long now; + + // We only process sending transfers. + ///////////////////////////////////// + if(!transfer->sender) + return GP_NO_ERROR; + + // Is the transfer finished? + //////////////////////////// + if(transfer->state >= GPITransferComplete) + return GP_NO_ERROR; + + // Get the time. + //////////////// + now = current_time(); + + // Check for no peer connection established. + //////////////////////////////////////////// + if(!transfer->peer) + { + // If its been too long, the person probably isn't really online. + ///////////////////////////////////////////////////////////////// + if((now - transfer->lastSend) > GPI_PEER_TIMEOUT_TIME) + { + GPTransferCallbackArg * arg; + + // We couldn't connect. + /////////////////////// + transfer->state = GPITransferNoConnection; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_NO_CONNECTION; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + return GP_NO_ERROR; + } + } + else + { + // Check for inactivity. + //////////////////////// + if((now - transfer->lastSend) > GPI_KEEPALIVE_TIME) + { + // Send a keepalive. + //////////////////// + CHECK_RESULT(gpiPeerStartTransferMessage(connection, transfer->peer, GPI_BM_FILE_TRANSFER_KEEPALIVE, (GPITransferID_st)&transfer->transferID)); + gpiFinishTransferMessage(connection, transfer, NULL, 0); + } + } + + // If we're paused, there's nothing else to do. + /////////////////////////////////////////////// + if(transfer->throttle == 0) + return GP_NO_ERROR; + + // Don't send files if we're not transfering yet. + ////////////////////////////////////////////////// + if(transfer->state < GPITransferTransferring) + return GP_NO_ERROR; + + // Don't send files if we have regular messages pending. + //////////////////////////////////////////////////////// + if(ArrayLength(transfer->peer->messages)) + return GP_NO_ERROR; + + // Process the current file. + //////////////////////////// + len = ArrayLength(transfer->files); + while(transfer->currentFile < len) + { + currentFile = transfer->currentFile; + CHECK_RESULT(gpiProcessCurrentFile(connection, transfer)); + if(currentFile == transfer->currentFile) + break; + } + + // Did we finish? + ///////////////// + if(transfer->currentFile == len) + { + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_DONE; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // Mark it as complete. + /////////////////////// + transfer->state = GPITransferComplete; + } + + return GP_NO_ERROR; +} + +GPResult gpiProcessTransfers +( + GPConnection * connection +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + int len; + int i; + GPITransfer * transfer; + + // Go through each transfer. + //////////////////////////// + len = ArrayLength(iconnection->transfers); + for(i = 0 ; i < len ; i++) + { + // Get the transfer. + //////////////////// + transfer = (GPITransfer *)ArrayNth(iconnection->transfers, i); + + // Process it. + ////////////// + gpiProcessTransfer(connection, transfer); + } + + return GP_NO_ERROR; +} + +GPIBool gpiGetTransferFileInfo +( + FILE * file, + int * size, + gsi_time * modTime +) +{ +#ifdef _WIN32 + struct _stat stats; + + if(_fstat(_fileno(file), &stats) != 0) + return GPIFalse; + + *size = (int)stats.st_size; + *modTime = (gsi_time)stats.st_mtime; +#else + if(fseek(file, 0, SEEK_END) != 0) + return GPIFalse; + + *size = (int)ftell(file); + if(*size == -1) + return GPIFalse; + + *modTime = 0; + + fseek(file, 0, SEEK_SET); +#endif + + return GPITrue; +} + +void gpiTransferPeerDestroyed +( + GPConnection * connection, + GPIPeer * peer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPTransferCallbackArg * arg; + GPITransfer * transfer; + int i; + int len; + + // Search for transfers that use this peer. + /////////////////////////////////////////// + len = ArrayLength(iconnection->transfers); + for(i = 0 ; i < len ; i++) + { + transfer = (GPITransfer *)ArrayNth(iconnection->transfers, i); + + if (transfer->peer == peer) + { + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_LOST_CONNECTION; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + + // So long tranfer. + /////////////////// + transfer->state = GPITransferNoConnection; + } + } + +} + +void gpiTransfersHandlePong +( + GPConnection * connection, + GPProfile profile, + GPIPeer * peer +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + GPITransfer * transfer; + int i; + int len; + + // Go through all the transfers. + //////////////////////////////// + len = ArrayLength(iconnection->transfers); + for(i = 0 ; i < len ; i++) + { + // Get this transfer. + ///////////////////// + transfer = (GPITransfer *)ArrayNth(iconnection->transfers, i); + assert(transfer); + + // Is it waiting on a pong from this profile? + ///////////////////////////////////////////// + if((transfer->state == GPITransferPinging) && (transfer->profile == profile)) + { + // Did we not get a connection? + /////////////////////////////// + if(!peer) + { + GPTransferCallbackArg * arg; + + // We couldn't connect. + /////////////////////// + transfer->state = GPITransferNoConnection; + + // Call the callback. + ///////////////////// + arg = (GPTransferCallbackArg *)gsimalloc(sizeof(GPTransferCallbackArg)); + if(arg) + { + memset(arg, 0, sizeof(GPTransferCallbackArg)); + arg->transfer = transfer->localID; + arg->type = GP_TRANSFER_NO_CONNECTION; + gpiAddCallback(connection, iconnection->callbacks[GPI_TRANSFER_CALLBACK], arg, NULL, GPI_ADD_TRANSFER_CALLBACK); + } + } + else + { + // Store the peer we're connected on. + ///////////////////////////////////// + transfer->peer = peer; + + // We're connected, so send our request. + //////////////////////////////////////// + gpiSendTransferRequest(connection, transfer); + + // Waiting for a response. + ////////////////////////// + transfer->state = GPITransferWaiting; + } + } + } +} +#endif + +GPResult gpiSendTransferReply +( + GPConnection * connection, + const GPITransferID * transferID, + GPIPeer * peer, + int result, + const char * msg +) +{ + char buffer[32]; + + if(!msg) + msg = ""; + + // Start the message. + ///////////////////// + CHECK_RESULT(gpiPeerStartTransferMessage(connection, peer, GPI_BM_FILE_SEND_REPLY, transferID)); + + // Add the rest of the headers. + /////////////////////////////// + sprintf(buffer, "\\version\\%d\\result\\%d", GPI_TRANSFER_VERSION, result); + CHECK_RESULT(gpiSendOrBufferString(connection, peer, buffer)); + + // Finish the message. + ////////////////////// + CHECK_RESULT(gpiPeerFinishTransferMessage(connection, peer, msg, -1)); + + return GP_NO_ERROR; +} + +void gpiHandleTransferMessage +( + GPConnection * connection, + GPIPeer * peer, + int type, + const char * headers, + const char * buffer, + int len +) +{ + char value[64]; + GPITransferID transferID; +#ifndef NOFILE + GPITransfer * transfer; + GPIBool success; +#endif + + // Get the transfer ID. + /////////////////////// + if(!gpiValueForKey(headers, "\\xfer\\", value, sizeof(value))) + return; + if(sscanf(value, "%d %u %u", &transferID.profileid, &transferID.count, &transferID.time) != 3) + return; + +#ifdef NOFILE + gpiSendTransferReply(connection, &transferID, peer, GPI_NOT_ACCEPTING, NULL); +#else + + // Send request messages don't yet have a transfer object. + ////////////////////////////////////////////////////////// + if(type == GPI_BM_FILE_SEND_REQUEST) + { + // Check for not accepting connections. + /////////////////////////////////////// + if(!gpiHandleSendRequest(connection, peer, &transferID, headers, buffer, len)) + gpiSendTransferReply(connection, &transferID, peer, GPI_NOT_ACCEPTING, NULL); + + return; + } + + // Find the transfer based on the ID. + ///////////////////////////////////// + transfer = gpiFindTransferByTransferID(connection, &transferID); + if(!transfer || (transfer->peer != peer)) + return; + + // Handle it based on the type. + /////////////////////////////// + switch(type) + { + case GPI_BM_FILE_SEND_REPLY: + success = gpiHandleSendReply(connection, transfer, headers, buffer, len); + break; + case GPI_BM_FILE_BEGIN: + success = gpiHandleBegin(connection, transfer, headers); + break; + case GPI_BM_FILE_END: + success = gpiHandleEnd(connection, transfer, headers); + break; + case GPI_BM_FILE_DATA: + success = gpiHandleData(connection, transfer, headers, buffer, len); + break; + case GPI_BM_FILE_SKIP: + success = gpiHandleSkip(connection, transfer, headers); + break; + case GPI_BM_FILE_TRANSFER_THROTTLE: + success = gpiHandleTransferThrottle(connection, transfer, headers); + break; + case GPI_BM_FILE_TRANSFER_CANCEL: + success = gpiHandleTransferCancel(connection, transfer); + break; + case GPI_BM_FILE_TRANSFER_KEEPALIVE: + success = gpiHandleTransferKeepalive(connection, transfer); + break; + default: + success = GPITrue; + } + + // Check if there was a transfer error. + /////////////////////////////////////// + if(!success) + gpiTransferError(connection, transfer); +#endif + + GSI_UNUSED(type); + GSI_UNUSED(buffer); + GSI_UNUSED(len); +} diff --git a/xrGameSpy/gamespy/GP/gpiTransfer.h b/xrGameSpy/gamespy/GP/gpiTransfer.h new file mode 100644 index 00000000000..630a6e36ec5 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiTransfer.h @@ -0,0 +1,210 @@ +/* +gpiTransfer.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPITRANSFER_H_ +#define _GPITRANSFER_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +#define GPI_FILE_DIRECTORY (1 << 1) +#define GPI_FILE_SKIP (1 << 2) +#define GPI_FILE_FAILED (1 << 3) +#define GPI_FILE_COMPLETED (1 << 4) +#define GPI_FILE_CONFIRMING (1 << 5) + +#define GPI_ACCEPTED 0 +#define GPI_REJECTED 1 +#define GPI_NOT_ACCEPTING 2 + +#define GPI_SKIP_READ_ERROR 0 +#define GPI_SKIP_WRITE_ERROR 1 +#define GPI_SKIP_USER_SKIP 2 + +//TYPES +/////// +typedef enum +{ + GPITransferPinging, + GPITransferWaiting, + GPITransferTransferring, + GPITransferComplete, + GPITransferCancelled, + GPITransferNoConnection +} GPITransferState; + +typedef struct GPITransferID_s +{ + int profileid; + unsigned int count; + unsigned int time; +} GPITransferID; + +typedef struct +{ + GPITransferState state; + DArray files; + GPITransferID transferID; + int localID; + GPIBool sender; + GPProfile profile; + GPIPeer * peer; + int currentFile; + int throttle; + char * baseDirectory; + unsigned long lastSend; + char * message; + int totalSize; + int progress; + void * userData; +} GPITransfer; + +typedef struct +{ + char * path; + char * name; + +#ifdef GSI_UNICODE + unsigned short* name_W; // must have this since developers are given pointers to internal memory + unsigned short* path_W; +#endif + + int progress; + int size; + int acknowledged; + FILE * file; + int flags; + gsi_time modTime; + MD5_CTX md5; + int reason; +} GPIFile; + +//FUNCTIONS +/////////// +#ifndef NOFILE +GPResult gpiInitTransfers( + GPConnection * connection +); + +void gpiCleanupTransfers( + GPConnection * connection +); + +GPResult gpiProcessTransfers +( + GPConnection * connection +); + +GPResult gpiNewSenderTransfer +( + GPConnection * connection, + GPITransfer ** transfer, + GPProfile profile +); + +void gpiFreeTransfer +( + GPConnection * connection, + GPITransfer * transfer +); + +void gpiCancelTransfer +( + GPConnection * connection, + GPITransfer * transfer +); + +void gpiTransferError +( + GPConnection * connection, + const GPITransfer * transfer +); + +GPITransfer * gpiFindTransferByLocalID +( + GPConnection * connection, + int localID +); + +int gpiGetTransferLocalIDByIndex +( + GPConnection * connection, + int index +); + +GPIFile * gpiAddFileToTransfer +( + GPITransfer * transfer, + const char * path, + const char * name +); + +void gpiSkipFile +( + GPConnection * connection, + GPITransfer * transfer, + int file, + int reason +); + +void gpiSkipCurrentFile +( + GPConnection * connection, + GPITransfer * transfer, + int reason +); + +GPIBool gpiGetTransferFileInfo +( + FILE * file, + int * size, + gsi_time * modTime +); + +void gpiTransferPeerDestroyed +( + GPConnection * connection, + GPIPeer * peer +); + +void gpiTransfersHandlePong +( + GPConnection * connection, + GPProfile profile, + GPIPeer * peer +); +#endif + +GPResult gpiSendTransferReply +( + GPConnection * connection, + const GPITransferID * transferID, + GPIPeer * peer, + int result, + const char * message +); + +void gpiHandleTransferMessage +( + GPConnection * connection, + GPIPeer * peer, + int type, + const char * headers, + const char * buffer, + int len +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiUnique.c b/xrGameSpy/gamespy/GP/gpiUnique.c new file mode 100644 index 00000000000..2f1b8437ab4 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiUnique.c @@ -0,0 +1,234 @@ +/* +gpiUnique.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +//INCLUDES +////////// +#include "gpi.h" + +//FUNCTIONS +/////////// +static GPResult +gpiSendRegisterUniqueNick( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const char cdkey[GP_CDKEY_LEN], + int operationid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\registernick\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\uniquenick\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, uniquenick); + if(cdkey) + { + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\cdkey\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, cdkey); + } + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\partnerid\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->partnerID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, operationid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult gpiRegisterUniqueNick( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIOperation * operation = NULL; + GPResult result; + + // Add the operation. + ///////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_REGISTER_UNIQUENICK, NULL, &operation, blocking, callback, param)); + + // Send a request for info. + /////////////////////////// + result = gpiSendRegisterUniqueNick(connection, uniquenick, cdkey, operation->id); + CHECK_RESULT(result); + + // Process it if blocking. + ////////////////////////// + if(blocking) + { + result = gpiProcess(connection, operation->id); + CHECK_RESULT(result); + } + + return GP_NO_ERROR; +} + +GPResult gpiProcessRegisterUniqueNick( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + GPICallback callback; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // This should be \rn\. + /////////////////////// + if(strncmp(input, "\\rn\\", 4) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Call the callback. + ///////////////////// + callback = operation->callback; + if(callback.callback != NULL) + { + GPRegisterUniqueNickResponseArg * arg; + arg = (GPRegisterUniqueNickResponseArg *)gsimalloc(sizeof(GPRegisterUniqueNickResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + arg->result = GP_NO_ERROR; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + + // This operation is complete. + ////////////////////////////// + gpiRemoveOperation(connection, operation); + + return GP_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Registration of cdKey now offered separately from uniquenick +static GPResult +gpiSendRegisterCdKey( + GPConnection * connection, + const char cdkey[GP_CDKEY_LEN], + int operationid +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Encrypt the cdkey (xor with random values) + const int useAlternateEncoding = 1; + char cdkeyxor[GP_CDKEY_LEN]; + char cdkeyenc[GP_CDKEYENC_LEN]; + int cdkeylen = (int)strlen(cdkey); + int i=0; + + Util_RandSeed((unsigned long)GP_XOR_SEED); + for (i=0; i < cdkeylen; i++) + { + // XOR each character with the next rand + char aRand = (char)Util_RandInt(0, 0xFF); + cdkeyxor[i] = (char)(cdkey[i] ^ aRand); + } + cdkeyxor[i] = '\0'; + + // Base 64 it (printable chars only) + B64Encode(cdkeyxor, cdkeyenc, (int)cdkeylen, useAlternateEncoding); + + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\registercdkey\\\\sesskey\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\cdkeyenc\\"); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, cdkeyenc); +// gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\partnerid\\"); +// gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->partnerID); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\id\\"); + gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, operationid); + gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\"); + + return GP_NO_ERROR; +} + +GPResult gpiRegisterCdKey( + GPConnection * connection, + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +) +{ + GPIOperation * operation = NULL; + GPResult result; + + // Add the operation. + ///////////////////// + CHECK_RESULT(gpiAddOperation(connection, GPI_REGISTER_CDKEY, NULL, &operation, blocking, callback, param)); + + // Send a request for info. + /////////////////////////// + result = gpiSendRegisterCdKey(connection, cdkey, operation->id); + CHECK_RESULT(result); + + // Process it if blocking. + ////////////////////////// + if(blocking) + { + result = gpiProcess(connection, operation->id); + CHECK_RESULT(result); + } + + return GP_NO_ERROR; +} + +GPResult gpiProcessRegisterCdKey( + GPConnection * connection, + GPIOperation * operation, + const char * input +) +{ + GPICallback callback; + + // Check for an error. + ////////////////////// + if(gpiCheckForError(connection, input, GPITrue)) + return GP_SERVER_ERROR; + + // This should be \rc\. + /////////////////////// + if(strncmp(input, "\\rc\\", 4) != 0) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server."); + + // Call the callback. + ///////////////////// + callback = operation->callback; + if(callback.callback != NULL) + { + GPRegisterCdKeyResponseArg * arg; + arg = (GPRegisterCdKeyResponseArg *)gsimalloc(sizeof(GPRegisterCdKeyResponseArg)); + if(arg == NULL) + Error(connection, GP_MEMORY_ERROR, "Out of memory."); + + arg->result = GP_NO_ERROR; + + CHECK_RESULT(gpiAddCallback(connection, callback, arg, operation, 0)); + } + + // This operation is complete. + ////////////////////////////// + gpiRemoveOperation(connection, operation); + + return GP_NO_ERROR; +} diff --git a/xrGameSpy/gamespy/GP/gpiUnique.h b/xrGameSpy/gamespy/GP/gpiUnique.h new file mode 100644 index 00000000000..82dbd0558ff --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiUnique.h @@ -0,0 +1,53 @@ +/* +gpiUnique.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIUNIQUE_H_ +#define _GPIUNIQUE_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//FUNCTIONS +/////////// +GPResult gpiRegisterUniqueNick( + GPConnection * connection, + const char uniquenick[GP_UNIQUENICK_LEN], + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiProcessRegisterUniqueNick( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +// Seperated registration of unique nick and cdkey +GPResult gpiRegisterCdKey( + GPConnection * connection, + const char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param +); + +GPResult gpiProcessRegisterCdKey( + GPConnection * connection, + GPIOperation * operation, + const char * input +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpiUtility.c b/xrGameSpy/gamespy/GP/gpiUtility.c new file mode 100644 index 00000000000..80ac4fbdbe3 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiUtility.c @@ -0,0 +1,413 @@ +/* +gpiUtility.c +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 333 +#pragma warning(disable: 4267) //lines: 142 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +//INCLUDES +////////// +#include +#include +#include +#include +#include "gpi.h" + +//DEFINES +///////// +#define OUTPUT_MAX_COL 100 + +// Disable compiler warnings for issues that are unavoidable. +///////////////////////////////////////////////////////////// +#if defined(_MSC_VER) // DevStudio +// Level4, "conditional expression is constant". +// Occurs with use of the MS provided macro FD_SET +#pragma warning ( disable: 4127 ) +#endif // _MSC_VER + +//FUNCTIONS +/////////// +void +strzcpy( + char * dest, + const char * src, + size_t len +) +{ + assert(dest != NULL); + assert(src != NULL); + + strncpy(dest, src, len); + dest[len - 1] = '\0'; +} + +GPIBool +gpiCheckForError( + GPConnection * connection, + const char * input, + GPIBool callErrorCallback +) +{ + char buffer[16]; + GPIConnection * iconnection = (GPIConnection*)*connection; + + if(strncmp(input, "\\error\\", 7) == 0) + { + // Get the err code. + //////////////////// + if(gpiValueForKey(input, "\\err\\", buffer, sizeof(buffer))) + iconnection->errorCode = (GPErrorCode)atoi(buffer); + + // Get the error string. + //////////////////////// + if(!gpiValueForKey(input, "\\errmsg\\", iconnection->errorString, sizeof(iconnection->errorString))) + iconnection->errorString[0] = '\0'; + +#ifdef GSI_UNICODE + // Update the UNICODE version + UTF8ToUCS2String(iconnection->errorString, iconnection->errorString_W); +#endif + // Call the error callback? + /////////////////////////// + if(callErrorCallback) + { + GPIBool fatal = (GPIBool)(strstr(input, "\\fatal\\") != NULL); + gpiCallErrorCallback(connection, GP_SERVER_ERROR, fatal ? GP_FATAL : GP_NON_FATAL); + } + + return GPITrue; + } + + return GPIFalse; +} + +GPIBool +gpiValueForKeyWithIndex( + const char * command, + const char * key, + int * index, + char * value, + int len +) +{ + char delimiter; + const char * start; + int i; + char c; + + // Check for NULL. + ////////////////// + assert(command != NULL); + assert(key != NULL); + assert(value != NULL); + assert(len > 0); + + // Find which char is the delimiter. + //////////////////////////////////// + delimiter = key[0]; + + // Find the key - first navigate to the index + ///////////////////////////////////////////// + command += *index; + start = strstr(command, key); + if(start == NULL) + return GPIFalse; + + // Get to the start of the value. + ///////////////////////////////// + start += strlen(key); + + // Copy in the value. + ///////////////////// + len--; + for(i = 0 ; (i < len) && ((c = start[i]) != '\0') && (c != delimiter) ; i++) + { + value[i] = c; + } + value[i] = '\0'; + + // Copy back current end point for index + //////////////////////////////////////// + *index += ((start - command) + strlen(value)); + + return GPITrue; +} + +GPIBool +gpiValueForKey( + const char * command, + const char * key, + char * value, + int len +) +{ + char delimiter; + const char * start; + int i; + char c; + + // Check for NULL. + ////////////////// + assert(command != NULL); + assert(key != NULL); + assert(value != NULL); + assert(len > 0); + + // Find which char is the delimiter. + //////////////////////////////////// + delimiter = key[0]; + + // Find the key. + //////////////// + start = strstr(command, key); + if(start == NULL) + return GPIFalse; + + // Get to the start of the value. + ///////////////////////////////// + start += strlen(key); + + // Copy in the value. + ///////////////////// + len--; + for(i = 0 ; (i < len) && ((c = start[i]) != '\0') && (c != delimiter) ; i++) + { + value[i] = c; + } + value[i] = '\0'; + + return GPITrue; +} + +char * +gpiValueForKeyAlloc( + const char * command, + const char * key +) +{ + char delimiter; + const char * start; + char c; + char * value; + int len; + + // Check for NULL. + ////////////////// + assert(command != NULL); + assert(key != NULL); + + // Find which char is the delimiter. + //////////////////////////////////// + delimiter = key[0]; + + // Find the key. + //////////////// + start = strstr(command, key); + if(start == NULL) + return NULL; + + // Get to the start of the value. + ///////////////////////////////// + start += strlen(key); + + // Find the key length. + /////////////////////// + for(len = 0 ; ((c = start[len]) != '\0') && (c != delimiter) ; len++) { }; + + // Allocate the value. + ////////////////////// + value = (char *)gsimalloc((unsigned int)len + 1); + if(!value) + return NULL; + + // Copy in the value. + ///////////////////// + memcpy(value, start, (unsigned int)len); + value[len] = '\0'; + + return value; +} + +GPResult +gpiCheckSocketConnect( + GPConnection * connection, + SOCKET sock, + int * state +) +{ + int aWriteFlag = 0; + int aExceptFlag = 0; + int aReturnCode = 0; + + // Check if the connect is completed. + ///////////////////////////////////// + aReturnCode = GSISocketSelect(sock, NULL, &aWriteFlag, &aExceptFlag); + if ( gsiSocketIsError(aReturnCode)) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, + "Error connecting\n"); + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error checking for a completed connection."); + } + + if (aReturnCode > 0) + { + // Check for a failed attempt. + ////////////////////////////// + if(aExceptFlag) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, + "Connection rejected\n"); + *state = GPI_DISCONNECTED; + return GP_NO_ERROR; + } + + // Check for a successful attempt. + ////////////////////////////////// + if(aWriteFlag) + { + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, + "Connection accepted\n"); + *state = GPI_CONNECTED; + return GP_NO_ERROR; + } + } + + // Not connected yet. + ///////////////////// + *state = GPI_NOT_CONNECTED; + return GP_NO_ERROR; +} + +GPResult +gpiReadKeyAndValue( + GPConnection * connection, + const char * buffer, + int * index, + char key[512], + char value[512] +) +{ + int c; + int i; + char * start; + + assert(buffer != NULL); + assert(key != NULL); + assert(value != NULL); + + buffer += *index; + start = (char *)buffer; + + if(*buffer++ != '\\') + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); + + for(i = 0 ; (c = *buffer++) != '\\' ; i++) + { + if(c == '\0') + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); + if(i == 511) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); + *key++ = (char)c; + } + *key = '\0'; + + for(i = 0 ; ((c = *buffer++) != '\\') && (c != '\0') ; i++) + { + if(i == 511) + CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); + *value++ = (char)c; + } + *value = '\0'; + + *index += (buffer - start - 1); + + return GP_NO_ERROR; +} + +void +gpiSetError( + GPConnection * connection, + GPErrorCode errorCode, + const char * errorString +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Copy the string. + /////////////////// + strzcpy(iconnection->errorString, errorString, GP_ERROR_STRING_LEN); + +#ifdef GSI_UNICODE + // Update the unicode version + UTF8ToUCS2StringLen(iconnection->errorString, iconnection->errorString_W, GP_ERROR_STRING_LEN); +#endif + + // Set the code. + //////////////// + iconnection->errorCode = errorCode; +} + +void +gpiSetErrorString( + GPConnection * connection, + const char * errorString +) +{ + GPIConnection * iconnection = (GPIConnection*)*connection; + + // Copy the string. + /////////////////// + strzcpy(iconnection->errorString, errorString, GP_ERROR_STRING_LEN); + +#ifdef GSI_UNICODE + // Update the unicode version + UTF8ToUCS2StringLen(iconnection->errorString, iconnection->errorString_W, GP_ERROR_STRING_LEN); +#endif + +} + +void +gpiEncodeString( + const char * unencodedString, + char * encodedString +) +{ + size_t i; + const int useAlternateEncoding = 1; + + // Encrypt the password (xor with random values) + char passwordxor[GP_PASSWORD_LEN]; + size_t passwordlen = strlen(unencodedString); + + Util_RandSeed((unsigned long)GP_XOR_SEED); + for (i=0; i < passwordlen; i++) + { + // XOR each character with the next rand + char aRand = (char)Util_RandInt(0, 0xFF); + passwordxor[i] = (char)(unencodedString[i] ^ aRand); + } + passwordxor[i] = '\0'; + + // Base 64 it (printable chars only) + B64Encode(passwordxor, encodedString, (int)passwordlen, useAlternateEncoding); +} + + +// Re-enable previously disabled compiler warnings +/////////////////////////////////////////////////// +#if defined(_MSC_VER) +#pragma warning ( default: 4127 ) +#endif // _MSC_VER + diff --git a/xrGameSpy/gamespy/GP/gpiUtility.h b/xrGameSpy/gamespy/GP/gpiUtility.h new file mode 100644 index 00000000000..25891109047 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpiUtility.h @@ -0,0 +1,127 @@ +/* +gpiUtility.h +GameSpy Presence SDK +Dan "Mr. Pants" Schoenblum + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +*********************************************************************** +Please see the GameSpy Presence SDK documentation for more information +**********************************************************************/ + +#ifndef _GPIUTILITY_H_ +#define _GPIUTILITY_H_ + +//INCLUDES +////////// +#include "gpi.h" + +//DEFINES +///////// +// Buffer read size. +//////////////////// +#define GPI_READ_SIZE (16 * 1024) + +//MACROS +//////// +#define freeclear(mem) { gsifree(mem); (mem) = NULL; } + +#define Error(connection, result, string) { gpiSetErrorString(connection, string);\ + return (result);} + +#define CallbackError(connection, result, code, string) { gpiSetError(connection, code, string);\ + gpiCallErrorCallback(connection, result, GP_NON_FATAL);\ + return result;} + +#define CallbackFatalError(connection, result, code, string) { gpiSetError(connection, code, string);\ + gpiCallErrorCallback(connection, result, GP_FATAL);\ + return result;} + +#define CHECK_RESULT(result) { GPResult __result__ = (result);\ + if(__result__ != GP_NO_ERROR){\ + return __result__;}} + +//FUNCTIONS +/////////// +void +strzcpy( + char * dest, + const char * src, + size_t len // length of buffer, including space for '\0' +); + +void +gpiDebug( + GPConnection * connection, + const char * fmt, + ... +); + +GPIBool +gpiValueForKeyWithIndex( + const char * command, + const char * key, + int * index, + char * value, + int len +); + +GPIBool +gpiValueForKey( + const char * command, + const char * key, + char * value, + int len +); + +char * +gpiValueForKeyAlloc( + const char * command, + const char * key +); + +GPResult +gpiCheckSocketConnect( + GPConnection * connection, + SOCKET sock, + int * state +); + +GPResult +gpiReadKeyAndValue( + GPConnection * connection, + const char * buffer, + int * index, + char key[512], + char value[512] +); + +GPIBool +gpiCheckForError( + GPConnection * connection, + const char * input, + GPIBool callErrorCallback +); + +void +gpiSetError( + GPConnection * connection, + GPErrorCode errorCode, + const char * errorString +); + +void +gpiSetErrorString( + GPConnection * connection, + const char * errorString +); + +void +gpiEncodeString( + const char * unencodedString, + char * encodedString +); + +#endif diff --git a/xrGameSpy/gamespy/GP/gpstress/gpstress.c b/xrGameSpy/gamespy/GP/gpstress/gpstress.c new file mode 100644 index 00000000000..0c1307e9999 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpstress/gpstress.c @@ -0,0 +1,1707 @@ +// GameSpy Presence and Messaging SDK Stress Test +// Dan "Mr. Pants" Schoenblum +// Copyright 2000 GameSpy Industries, Inc + +/************* +** INCLUDES ** +*************/ +#include +#include "../gp.h" +#include "../../common/gsAvailable.h" + +/************ +** DEFINES ** +************/ +//#define CONNECTION_MANAGER "localhost" + +#define PROFILES_MAX 10000 + +#define LOG_FILE "gpstress.log" + +#define NEXT_OP_TIME_MIN 2000000 +#define NEXT_OP_TIME_MAX 2000000 + +#define IS_INSTANT_OP(op) (((op) >= FIRST_INSTANT_OP) && ((op) <= LAST_INSTANT_OP)) + +#define CONNECT_TIME_MIN 20000 +#define CONNECT_TIME_MAX 20000 + +#define SHUTDOWN_DISCONNECTS_PER_SEC 50 + +#define DEFAULT_RUN_TIME (2 * 60 * 60 * 1000) +#define DEFAULT_MAX_CONNECTED 100 + +#define SHOW_INFO_TIME 1000 + +#define DEFAULT_CONNECTS_PER_SEC 15 + +#define MAX_OTHERS 20 + +#define PRODUCT_ID_MAX 18 + +#define VALIDATION_MAX_NICKS 512 + +#define MAX_OUTSTANDING_CONNECTIONS 1 + +/********** +** TYPES ** +**********/ +#ifndef __cplusplus +typedef enum +{ + false, + true +} bool; +#endif + +typedef enum +{ + // No active operation. + /////////////////////// + OpNull = -1, + + // These operations all take a ceratin amount of time. + ////////////////////////////////////////////////////// + OpConnect, + OpNewProfile, + OpGetInfo, +#ifdef TEST_SEARCH + OpProfileSearch, + OpFindPlayers, +#endif + + // These are all instant operations. + //////////////////////////////////// +#define FIRST_INSTANT_OP OpSetInfo + OpSetInfo, + OpBuddyRequest, + OpDeleteBuddy, + OpSetStatus1, // Do setstatus 5x as often as other ops + OpSetStatus2, + OpSetStatus3, + OpSetStatus4, + OpSetStatus5, + OpSendBuddyMessage, + OpSetInvitable, +#define LAST_INSTANT_OP OpSetInvitable + + // The number of possible operations. + ///////////////////////////////////// + NumOps +} Op; + +typedef struct +{ + // The index of this profile in the list. + ///////////////////////////////////////// + int index; + + // Loaded profile info. + /////////////////////// + int userID; + char email[GP_EMAIL_LEN]; + char password[GP_PASSWORD_LEN]; + int profileID; + char nick[GP_NICK_LEN]; + bool invalid; + + // GP stuff. + //////////// + GPConnection gp; // The profile's GP object. + bool gpInitialized; // False until gpInitialize is called for this profile. + unsigned long disconnectTime; // Disconnect at this time. + GPProfile others[MAX_OTHERS]; // Remote profiles that this profile knows about. + int numOthers; // The number of others. + unsigned long connectTime; // When the connect attempt was made. + bool connected; // True when gpConnect finished successfully. + + // Op data. + /////////// + Op activeOp; // The active operation, OpNull between operations. + unsigned long nextOpTime; // At this time, pick a new random operation. + int completedOps; // Total number of operations completed. +} Profile; + +typedef struct +{ + GPResult result; + char nicks[VALIDATION_MAX_NICKS][GP_NICK_LEN]; + int numNicks; + Profile * profile; +} ValidationData; + +/************ +** GLOBALS ** +************/ +char profilesFile[MAX_PATH]; // The file from which to load the profiles. +Profile profiles[PROFILES_MAX]; // All of the loaded profiles. +int numProfiles; // The number of loaded profiles. +int numConnections; // The number of profiles that are initialized/connected. +int maxConnections; // The maximum number of connected profiles. +int highestConnections; // The highest number of connections. +int totalConnections; // The total number of connections. +int numConnected; // The number of profiles that are actually logged in. +int highestConnected; // The highest simultaneous connected. +int totalConnected; // The total number connected over the entire run. +int connectsPerSecond; // Number of connection attempts per second. +unsigned long lastConnectTime; // The last time there was a connect. +unsigned long startShutdownTime; // When to start shutting down. +bool shuttingDown; // True if we're in the process of shutting down. +unsigned long runTime; // How long to run for. + +/******************** +** PROFILE LOADING ** +********************/ +// This warning needs to be fixed for this file +// Disabling for now +#pragma warning ( disable: 4702 ) +#pragma warning ( disable: 4127 ) +bool ReadField(FILE * fp, char * field) +{ + char * str = field; + int c; + *str = '\0'; + while(1) + { + // Get a char. + ////////////// + c = fgetc(fp); + + // Check for end of field. + ////////////////////////// + if((c == ',') || (c == '\n') || (c == -1)) + { + // Check for no chars read. + /////////////////////////// + if(field == str) + return false; + + // Cap it off and return. + ///////////////////////// + *str = '\0'; + return true; + } + + *str++ = (char)c; + } + + return false; +} + +bool ReadProfile(FILE * fp, Profile * profile) +{ + char intBuffer[16]; + + // Read the user id. + //////////////////// + if(!ReadField(fp, intBuffer)) + return false; + profile->userID = atoi(intBuffer); + assert(profile->userID); + + // Read the email. + ////////////////// + ReadField(fp, profile->email); + + // Read the password. + ///////////////////// + ReadField(fp, profile->password); + + // Read the profile id. + /////////////////////// + ReadField(fp, intBuffer); + profile->profileID = atoi(intBuffer); + assert(profile->profileID); + + // Read the nick. + ///////////////// + ReadField(fp, profile->nick); + + return true; +} + +bool LoadProfiles(void) +{ +#if 0 + FILE * fp; + + // Open the file. + ///////////////// + fp = fopen(profilesFile, "rt"); + if(!fp) + { + printf("Failed to open the profiles file (%s)!\n", profilesFile); + return false; + } + + // Read the profiles. + ///////////////////// + while(ReadProfile(fp, &profiles[numProfiles])) + { + // One more. + //////////// + numProfiles++; + + // Check for too many. + ////////////////////// + if(numProfiles == PROFILES_MAX) + { + printf("Too many profiles in the profile file!\nIncrease PROFILES_MAX (%d)\n", PROFILES_MAX); + return false; + } + } + + // Close the file. + ////////////////// + fclose(fp); + + printf("Loaded %d profiles from %s\n", numProfiles, profilesFile); +#else + int i; + + for(i = 0 ; i < maxConnections ; i++) + { + strcpy(profiles[i].nick, "gpstress"); + sprintf(profiles[i].email, "gpstress%04d@gamespy.com", i); + strcpy(profiles[i].password, "gpstress"); + } + + numProfiles = i; +#endif + + return true; +} + +/********************* +** RANDOM FUNCTIONS ** +**********************/ +char RandomChar(void) +{ + static const char characters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789!@#$%^&*()_+-=~`<,>.?/:;\"'{[}]|\\"; + int index; + + index = (rand() % (sizeof(characters) - 1)); + + return characters[index]; +} + +char * RandomString(char * buffer) +{ + int i; + int len; + + // Random length. + ///////////////// + len = ((rand() % 10) + 5); + + // Set random chars. + //////////////////// + for(i = 0 ; i < len ; i++) + buffer[i] = RandomChar(); + buffer[i] = '\0'; + + return buffer; +} + +// min & max are inclusive. +/////////////////////////// +int RandomInt(int min, int max) +{ + int range = ((max - min) + 1); + return (min + ((rand() * range) / (RAND_MAX + 1))); +} + +bool RandomBool(void) +{ + return (bool)RandomInt(0, 1); +} + +GPProfile RandomOther(Profile * profile) +{ + int nIndex; + + assert(profile->numOthers > 0); + + nIndex = RandomInt(0, profile->numOthers - 1); + assert(nIndex >= 0); + assert(nIndex < profile->numOthers); + + return profile->others[nIndex]; +} + +void RandomServer(void) +{ +#if 0 + strcpy(GPConnectionManagerHostname, "mrpants"); +#else + static const char * servers[] = + { +#if 1 + "mrpants", + "mrpants1" +#else + "aphexgp1", + "aphexgp2" +#endif + }; + + const char * server = servers[RandomInt(0, (sizeof(servers) / sizeof(*servers)) - 1)]; + strcpy(GPConnectionManagerHostname, server); +#endif +} + +/************ +** GENERAL ** +************/ +void MessageOther(Profile * profile, GPProfile other) +{ +#if 1 + int pid; + + // Filter out certain profiles. + /////////////////////////////// + gpIDFromProfile(&profile->gp, other, &pid); + switch(pid) + { + case 100001: // Mr. Pants@dan@gamespy.com + case 100002: // walla@bryan@gamespy.com + case 100013: // lumberjack@jason@gamespy.com + return; + } + + gpSendBuddyMessage(&profile->gp, other, "STRESS-TEST"); +#endif +} + +void Log(const char * buffer) +{ + FILE * fp; + + static char timeBuffer[64]; + time_t thetime; + struct tm *ltime; + time(&thetime); + ltime = localtime(&thetime); + sprintf(timeBuffer, "%-2.2d/%-2.2d/%-2.2d %-2.2d:%-2.2d:%-2.2d: ", ltime->tm_mon+1, ltime->tm_mday, ltime->tm_year % 100, ltime->tm_hour, ltime->tm_min, ltime->tm_sec); + + fp = fopen(LOG_FILE, "at"); + if(fp) + { + fprintf(fp, "%s%s", timeBuffer, buffer); + fclose(fp); + } + + OutputDebugString(timeBuffer); + OutputDebugString(buffer); + + printf("%s%s", timeBuffer, buffer); +} + +/************************ +** GP GLOBAL CALLBACKS ** +************************/ +void GetInfoCallback(GPConnection * connnection, GPGetInfoResponseArg * arg, Profile * profile); +void AddOther(Profile * profile, GPProfile gpProfile); +void PrintOp(Profile * profile, const char * opString); + +void ErrorCallback(GPConnection * connection, GPErrorArg * arg, Profile * profile) +{ + char * errorCodeString; + char * resultString; + static char buffer[4098]; + + // Ignore errors that we're expecting to generate (due to randomness). + ////////////////////////////////////////////////////////////////////// + switch(arg->errorCode) + { + case GP_ADDBUDDY_ALREADY_BUDDY: + case GP_BM_NOT_BUDDY: + return; + } + + // Get a string for the result. + /////////////////////////////// +#define RESULT(x) case x: resultString = #x; break; + switch(arg->result) + { + RESULT(GP_NO_ERROR) + RESULT(GP_MEMORY_ERROR) + RESULT(GP_PARAMETER_ERROR) + RESULT(GP_NETWORK_ERROR) + RESULT(GP_SERVER_ERROR) + default: + resultString = "Unknown result!\n"; + } + + // Get a string for the error code. + /////////////////////////////////// +#define ERRORCODE(x) case x: errorCodeString = #x; break; + switch(arg->errorCode) + { + ERRORCODE(GP_GENERAL) + ERRORCODE(GP_PARSE) + ERRORCODE(GP_NOT_LOGGED_IN) + ERRORCODE(GP_BAD_SESSKEY) + ERRORCODE(GP_DATABASE) + ERRORCODE(GP_NETWORK) + ERRORCODE(GP_FORCED_DISCONNECT) + ERRORCODE(GP_CONNECTION_CLOSED) + ERRORCODE(GP_LOGIN) + ERRORCODE(GP_LOGIN_TIMEOUT) + ERRORCODE(GP_LOGIN_BAD_NICK) + ERRORCODE(GP_LOGIN_BAD_EMAIL) + ERRORCODE(GP_LOGIN_BAD_PASSWORD) + ERRORCODE(GP_LOGIN_BAD_PROFILE) + ERRORCODE(GP_LOGIN_PROFILE_DELETED) + ERRORCODE(GP_LOGIN_CONNECTION_FAILED) + ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED) + ERRORCODE(GP_LOGIN_BAD_UNIQUENICK) + ERRORCODE(GP_LOGIN_BAD_PREAUTH) + ERRORCODE(GP_NEWUSER) + ERRORCODE(GP_NEWUSER_BAD_NICK) + ERRORCODE(GP_NEWUSER_BAD_PASSWORD) + ERRORCODE(GP_NEWUSER_UNIQUENICK_INVALID) + ERRORCODE(GP_NEWUSER_UNIQUENICK_INUSE) + ERRORCODE(GP_UPDATEUI) + ERRORCODE(GP_UPDATEUI_BAD_EMAIL) + ERRORCODE(GP_NEWPROFILE) + ERRORCODE(GP_NEWPROFILE_BAD_NICK) + ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK) + ERRORCODE(GP_UPDATEPRO) + ERRORCODE(GP_UPDATEPRO_BAD_NICK) + ERRORCODE(GP_ADDBUDDY) + ERRORCODE(GP_ADDBUDDY_BAD_FROM) + ERRORCODE(GP_ADDBUDDY_BAD_NEW) + ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY) + ERRORCODE(GP_AUTHADD) + ERRORCODE(GP_AUTHADD_BAD_FROM) + ERRORCODE(GP_AUTHADD_BAD_SIG) + ERRORCODE(GP_STATUS) + ERRORCODE(GP_BM) + ERRORCODE(GP_BM_NOT_BUDDY) + ERRORCODE(GP_GETPROFILE) + ERRORCODE(GP_GETPROFILE_BAD_PROFILE) + ERRORCODE(GP_DELBUDDY) + ERRORCODE(GP_DELBUDDY_NOT_BUDDY) + ERRORCODE(GP_DELPROFILE) + ERRORCODE(GP_DELPROFILE_LAST_PROFILE) + ERRORCODE(GP_SEARCH) + ERRORCODE(GP_SEARCH_CONNECTION_FAILED) + ERRORCODE(GP_CHECK) + ERRORCODE(GP_CHECK_BAD_EMAIL) + ERRORCODE(GP_CHECK_BAD_NICK) + ERRORCODE(GP_CHECK_BAD_PASSWORD) + ERRORCODE(GP_REVOKE) + ERRORCODE(GP_REVOKE_NOT_BUDDY) + ERRORCODE(GP_REGISTERUNIQUENICK) + ERRORCODE(GP_REGISTERUNIQUENICK_TAKEN) + ERRORCODE(GP_REGISTERUNIQUENICK_RESERVED) + ERRORCODE(GP_REGISTERUNIQUENICK_BAD_NAMESPACE) + default: + errorCodeString = "Unknown error code!\n"; + } + + // Print out the info. + ////////////////////// + if(arg->fatal) + sprintf(buffer, "%04d: FATAL ERROR", profile->index); + else + sprintf(buffer, "%04d: ERROR", profile->index); + sprintf(buffer + strlen(buffer), ", RESULT: %s (%d)", resultString, arg->result); + sprintf(buffer + strlen(buffer), ", ERROR CODE: %s (0x%X)", errorCodeString, arg->errorCode); + sprintf(buffer + strlen(buffer), ", ERROR STRING: %s\n", arg->errorString); + Log(buffer); + + // Disconnect. + ////////////// + profile->disconnectTime = 0; + GSI_UNUSED(connection); +} + +void RecvBuddyStatusCallback(GPConnection * connection, GPRecvBuddyStatusArg * arg, Profile * profile) +{ + PrintOp(profile, "RecvBuddyStatusCallback"); + +#if 1 + // Get info half the time. + ////////////////////////// + if(RandomBool()) + gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + + // Send a message sometimes. + //////////////////////////// + if(RandomInt(0, 9) == 0) + MessageOther(profile, arg->profile); + + // Add the other. + ///////////////// + AddOther(profile, arg->profile); +#endif + GSI_UNUSED(connection); +} + +#if 1 +void RecvBuddyRequestCallback(GPConnection * connection, GPRecvBuddyRequestArg * arg, Profile * profile) +{ + PrintOp(profile, "RecvBuddyRequestCallback"); + + // Get info half the time. + ////////////////////////// + if(RandomBool()) + gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + + // Accept it half the time. + /////////////////////////// + if(RandomBool()) + gpAuthBuddyRequest(&profile->gp, arg->profile); + + // Add the other. + ///////////////// + AddOther(profile, arg->profile); + GSI_UNUSED(connection); +} + +void RecvBuddyMessageCallback(GPConnection * connection, GPRecvBuddyMessageArg * arg, Profile * profile) +{ + PrintOp(profile, "RecvBuddyMessageCallback"); + + // Get info half the time. + ////////////////////////// + if(RandomBool()) + gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + + // Reply sometimes. + /////////////////// + if(RandomInt(0, 9) == 0) + MessageOther(profile, arg->profile); + + // Add the other. + ///////////////// + AddOther(profile, arg->profile); + GSI_UNUSED(connection); +} + +void RecvGameInviteCallback(GPConnection * connection, GPRecvGameInviteArg * arg, Profile * profile) +{ + PrintOp(profile, "RecvGameInviteCallback"); + + // Get info half the time. + ////////////////////////// + if(RandomBool()) + gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + + // Send a message sometimes. + //////////////////////////// + if(RandomInt(0, 9) == 0) + MessageOther(profile, arg->profile); + + // Add the other. + ///////////////// + AddOther(profile, arg->profile); + GSI_UNUSED(connection); +} +#endif + +/******************** +** GP OP CALLBACKS ** +********************/ +void EndOp(Profile * profile); + +const int RemoteAuthProfiles[] = +{ + 58214083, + 58214074, + 58214075, + 58214076, + 58214077, + 58214078, + 58214079, + 58214080, + 58214081, + 58214082 +}; + +void ConnectCallback(GPConnection * connection, GPConnectResponseArg * arg, Profile * profile) +{ + if(arg->result == GP_NO_ERROR) + { + // Finished connecting. + /////////////////////// + profile->connected = true; + numConnected++; + totalConnected++; + highestConnected = max(numConnected, highestConnected); + + if(arg->profile != RemoteAuthProfiles[profile->index % 10]) + { + char buffer[4096]; + gsi_time ms = (current_time() - profile->connectTime); + sprintf(buffer, "%d: XXX Connection ProfileID Error (%d != %d) [%d]: %d.%03ds\n", totalConnected, arg->profile, RemoteAuthProfiles[profile->index % 10], (profile->index % 10), ms / 1000, ms % 1000); + Log(buffer); + } + +#if 1 + // log the connection + { + char buffer[256]; + gsi_time ms = (current_time() - profile->connectTime); + sprintf(buffer, "%sConnected: %d time: %d.%03ds\n", (ms>=1000)?"XX ":"", totalConnected, ms / 1000, ms % 1000); + Log(buffer); + } +#endif + +#if 1 + // always disconnect right away + profile->disconnectTime = 0; +#endif + } + else + { +#if 1 + // log the error + { + char buffer[4096]; + gsi_time ms = (current_time() - profile->connectTime); + sprintf(buffer, "%d: XXX Connection Failed [%d]: %d.%03ds\n", totalConnected, (profile->index % 10), ms / 1000, ms % 1000); + Log(buffer); + } +#endif + // Disconnect this profile. + /////////////////////////// + profile->disconnectTime = 0; + } + + // End the op. + ////////////// + EndOp(profile); + GSI_UNUSED(connection); +} + +void GetInfoCallback(GPConnection * connection, GPGetInfoResponseArg * arg, Profile * profile) +{ + if(arg->result != GP_NO_ERROR) + { + printf("%04d: gpGetInfo failed\n", profile->index); + return; + } + GSI_UNUSED(connection); +} + +void FindPlayersCallback(GPConnection * connection, GPFindPlayersResponseArg * arg, Profile * profile) +{ + int i; + + if(arg->result != GP_NO_ERROR) + { + printf("%04d: gpFindPlayers failed\n", profile->index); + return; + } + + // Get all of their info. + ///////////////////////// + for(i = 0 ; i < arg->numMatches ; i++) + gpGetInfo(&profile->gp, arg->matches[i].profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + + // Invite someone. + ////////////////// + if(arg->numMatches > 0) + { + int index = RandomInt(0, arg->numMatches - 1); + int productID = RandomInt(1, PRODUCT_ID_MAX); + + gpInvitePlayer(&profile->gp, arg->matches[index].profile, productID,NULL); + } + GSI_UNUSED(connection); +} + +void ProfileSearchCallback(GPConnection * connection, GPProfileSearchResponseArg * arg, Profile * profile) +{ + int i; + + if(arg->result != GP_NO_ERROR) + { + printf("%04d: gpProfileSearch failed\n", profile->index); + return; + } + + // Get all of their info. + ///////////////////////// + for(i = 0 ; i < arg->numMatches ; i++) + gpGetInfo(&profile->gp, arg->matches[i].profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + GSI_UNUSED(connection); +} + +/***************** +** OP FUNCTIONS ** +*****************/ +void AddOther(Profile * profile, GPProfile gpProfile) +{ + int i; + + // Check for full. + ////////////////// + if(profile->numOthers == MAX_OTHERS) + return; + + // Check if we already have this one. + ///////////////////////////////////// + for(i = 0 ; i < profile->numOthers ; i++) + if(profile->others[i] == gpProfile) + return; + + // Add it. + ////////// + profile->others[profile->numOthers] = gpProfile; + profile->numOthers++; +} + +unsigned long GetRandomOpTime(void) +{ + // Between NEXT_OP_TIME_MIN and NEXT_OP_TIME_MAX. + ///////////////////////////////////////////////// + return RandomInt(NEXT_OP_TIME_MIN, NEXT_OP_TIME_MAX); +} + +Op GetRandomOp(void) +{ + // Between 1 (skip OpConnect) and (NumOps - 1). + /////////////////////////////////////////////// + Op op = (Op)(((rand() * (NumOps - 1)) / (RAND_MAX + 1)) + 1); + + assert(op > OpConnect); + assert(op < NumOps); + + return op; +} + +void NewOp(Profile * profile) +{ + // Is this the first op? + //////////////////////// + if(profile->completedOps == 0) + { + // The first op is always connect. + ////////////////////////////////// + profile->activeOp = OpConnect; + } + else + { +#if 1 + // Pick a random op. + //////////////////// + profile->activeOp = GetRandomOp(); +#else + // Always do status. + //////////////////// + profile->activeOp = OpSetStatus1; +#endif + } +} + +void EndOp(Profile * profile) +{ + // No active op. + //////////////// + profile->activeOp = OpNull; + + // Set the next op time. + //////////////////////// + profile->nextOpTime = (current_time() + GetRandomOpTime()); + + // One more op completed. + ///////////////////////// + profile->completedOps++; +} + +void PrintOp(Profile * profile, const char * opString) +{ +#if 0 + static char buffer[256]; + sprintf(buffer, "%04d: %s\n", profile->index, opString); + OutputDebugString(buffer); +#endif + GSI_UNUSED(profile); + GSI_UNUSED(opString); +} + +void StartOp(Profile * profile) +{ + int i; + int num; + int intArray[16]; + char string1[16]; + char string2[16]; + + // Handle based on op. + ////////////////////// + switch(profile->activeOp) + { + case OpNull: + assert(0); + printf("%04d: Tried to start null op\n", profile->index); + break; + + case OpConnect: + PrintOp(profile, "OpConnect"); + + // Start the connect. + ///////////////////// +#if 0 + RandomServer(); +#endif +#if 0 + gpConnect(&profile->gp, profile->nick, profile->email, profile->password, (RandomInt(0, 9) == 0)?GP_FIREWALL:GP_NO_FIREWALL, GP_NON_BLOCKING, ConnectCallback, profile); +#else + { + const char * authtokens[] = + { + "GMT/61LHe4Yu+pHI0eDXu8GMdc51iXjsNvcz1GGoWJ9orpnbZIbp3CVBQddeSZOSq58", + "GMTcUM+iiQuzaw8crHxBFPCVV6J9V14KnSNHnHbQIXGwN6XpKv97yqSbOqxrgIWZCeZ", + "GMTxiKFKsnGdOeBaJxmJOQBNSqbm9zOjbu/cTiqpBJp1pqqOAnI1Jh81TPlWmFuvt0h", + "GMTqUg6QEerwnwi87fZQMcfzQ0xA/zNC96VCtx6GavTv7wzDtGpOWxJHUkm20qMxVsg", + "GMTV2uHalvcDgtvBsz62QF1ifbCJJ93QONO9TNGVGlDghs6ocL2qOiQVqNJS7LvTZ39", + "GMTq9Z7Tg/tkEMzqEODuQdNSQPgt5MdAwH26+lQGHliL9n3nH0b0D38fTFWRbkmk4K9", + "GMTwHyinDuomW0XmQswNyVpgdlQvnuGCR1it+kHCnUDmR5CG3svSufrDcjuHdlwfVON", + "GMTBZgPikENuiEON0by04RMR112ShZsDctzVbqljZ3ZufDvyugygztRlKIM9gyLwSdy", + "GMTmHNpmNufV9WuGIGET8E0Xd//56eYWO4mDaD+4KebWQWvc8CqWbqSeII6x9BxQMxQ", + "GMTyI447fNIYVh1vdI6aErka4TzJcYWctTU/Dzi2GK+4J3Vf/VAqQOs43R73I7dyX+u" + }; + const char * partnerchallenges[] = + { + "WI[A)IuA", + "RNd$)q)0", + "LQTi;4#X", + "AOA)(57=", + "ob=0XiWJ", + "mRnTENJ@", + "9%@A+NKA", + "L=0O)Lg2", + "YR6[Zz%B", + "$kWZ%]~@" + }; + int tokenIndex = (profile->index % 10); + gpConnectPreAuthenticated(&profile->gp, authtokens[tokenIndex], partnerchallenges[tokenIndex], GP_FIREWALL, GP_NON_BLOCKING, ConnectCallback, profile); + } +#endif + break; + + case OpNewProfile: + PrintOp(profile, "OpNewProfile"); + + // Pretend this op didn't happen, another will be picked next frame. + //////////////////////////////////////////////////////////////////// + profile->activeOp = OpNull; + break; + + case OpGetInfo: + PrintOp(profile, "OpGetInfo"); + + // Do we know of any other profiles? + //////////////////////////////////// + if(profile->numOthers > 0) + gpGetInfo(&profile->gp, RandomOther(profile), GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile); + else + profile->activeOp = OpNull; + break; + +#ifdef TEST_SEARCH + case OpProfileSearch: + PrintOp(profile, "OpProfileSearch"); + + // Do a search. + /////////////// + num = RandomInt(0, 3); + if(num == 0) + gpProfileSearch(&profile->gp, "pants", "dan@gamespy.com", NULL, NULL, 0, GP_NON_BLOCKING, ProfileSearchCallback, profile); + else if(num == 1) + gpProfileSearch(&profile->gp, "crt", NULL, NULL, NULL, 0, GP_NON_BLOCKING, ProfileSearchCallback, profile); + else + gpProfileSearch(&profile->gp, "STRESS-TEST", NULL, NULL, NULL, 0, GP_NON_BLOCKING, ProfileSearchCallback, profile); + break; + + case OpFindPlayers: + PrintOp(profile, "OpFindPlayers"); + + // Find some players. + ///////////////////// + gpFindPlayers(&profile->gp, RandomInt(1, PRODUCT_ID_MAX), GP_NON_BLOCKING, FindPlayersCallback, profile); + break; +#endif + + case OpSetInfo: + PrintOp(profile, "OpSetInfo"); + + // Set some random info. + //////////////////////// + gpSetInfos(&profile->gp, GP_FIRSTNAME, "STRESS-TEST"); + gpSetInfos(&profile->gp, GP_LASTNAME, "STRESS-TEST"); + gpSetInfoi(&profile->gp, GP_ICQUIN, RandomInt(100000, 40000000)); + gpSetInfos(&profile->gp, GP_HOMEPAGE, "STRESS-TEST"); + gpSetInfod(&profile->gp, GP_BIRTHDAY, RandomInt(1, 28), RandomInt(1, 12), RandomInt(1940, 1990)); + break; + + case OpBuddyRequest: + PrintOp(profile, "OpBuddyRequest"); + +#if 1 + // Pretend this op didn't happen, another will be picked next frame. + //////////////////////////////////////////////////////////////////// + profile->activeOp = OpNull; +#else + // Send someone a buddy request. + //////////////////////////////// + if(profile->numOthers > 0) + gpSendBuddyRequest(&profile->gp, RandomOther(profile), "STRESS-TEST"); +#endif + break; + + case OpDeleteBuddy: + PrintOp(profile, "OpDeleteBuddy"); + + // Pretend this op didn't happen, another will be picked next frame. + //////////////////////////////////////////////////////////////////// + profile->activeOp = OpNull; + break; + + case OpSetStatus1: + case OpSetStatus2: + case OpSetStatus3: + case OpSetStatus4: + case OpSetStatus5: + PrintOp(profile, "OpSetStatus"); + + // Set the status to some random stuff. + /////////////////////////////////////// + gpSetStatus(&profile->gp, GP_ONLINE, RandomString(string1), RandomString(string2)); + break; + + case OpSendBuddyMessage: + PrintOp(profile, "OpSendBuddyMessage"); + + // Send someone a message. + ///////////////////////// + if(profile->numOthers > 0) + MessageOther(profile, RandomOther(profile)); + break; + + case OpSetInvitable: + PrintOp(profile, "OpSetInvitable"); + + // Get the num games. + ///////////////////// + num = RandomInt(0, 10); + + // Get the product ids. + /////////////////////// + for(i = 0 ; i < num ; i++) + intArray[i] = RandomInt(1, PRODUCT_ID_MAX); + + // Set the games. + ///////////////// + gpSetInvitableGames(&profile->gp, num, intArray); + break; + + default: + assert(0); + printf("%04d: Tried to start unknown op: %d\n", profile->index, profile->activeOp); + break; + } + + // Was this an instant op? + ////////////////////////// + if(IS_INSTANT_OP(profile->activeOp)) + { + // End it. + ////////// + EndOp(profile); + } +} + +/********************** +** PROFILE FUNCTIONS ** +**********************/ +void ProcessProfile(Profile * profile) +{ + DWORD now = current_time(); + + // Is GP initialized? + ///////////////////// + if(profile->gpInitialized) + { + // Do GP processing. + //////////////////// + gpProcess(&profile->gp); + + // Has a connection attempt been going for 2 minutes? + ///////////////////////////////////////////////////// + if((profile->activeOp == OpConnect) && ((current_time() - profile->connectTime) > (200 * 60 * 1000))) + { + char buffer[256]; + gsi_time ms = (current_time() - profile->connectTime); + sprintf(buffer, "%04d: XXX Excessive Connect Time: %d.%03ds\n", profile->index, ms / 1000, ms % 1000); + Log(buffer); + } + + // Check for disconnect. + //////////////////////// + if((now > profile->disconnectTime) && ((profile->activeOp != OpConnect) || shuttingDown)) + { + // Cleanup GP for this profile. + /////////////////////////////// + if(profile->connected) + { + numConnected--; + gpDisconnect(&profile->gp); + } + gpDestroy(&profile->gp); + + // We're no longer initialized/connected. + ///////////////////////////////////////// + profile->gpInitialized = false; + numConnections--; + } + // Is there no active op? + ///////////////////////// + else if(!shuttingDown && (profile->activeOp == OpNull)) + { + // Is it time for a new op? + /////////////////////////// +#if 1 + if(now > profile->nextOpTime) +#else + if((now > profile->nextOpTime) && (profile->completedOps == 0)) +#endif + { + // Select a new op. + /////////////////// + NewOp(profile); + + // Start the op. + //////////////// + StartOp(profile); + } + } + } +} + +Profile * GetUninitializedProfile(void) +{ + int index; + + // Loop until we get an uninitialized (and valid) profile. + ////////////////////////////////////////////////////////// + do + { + // Get an index between 0 and (numProfiles - 1). + //////////////////////////////////////////////// + index = ((rand() * numProfiles) / (RAND_MAX + 1)); + assert(index >= 0); + assert(index < numProfiles); + } + while(profiles[index].gpInitialized || profiles[index].invalid); + + return &profiles[index]; +} + +void InitializeProfile(Profile * profile) +{ + GPResult result; + + // Init the profile's GP object. + //////////////////////////////// + result = gpInitialize(&profile->gp, 0, 0, GP_PARTNERID_GAMESPY); + if(result != GP_NO_ERROR) + { + printf("%04d: Failed to initialize GP for %s@%s\n", profile->index, profile->nick, profile->email); + return; + } + + // Set the GP global callbacks. + /////////////////////////////// + gpSetCallback(&profile->gp, GP_ERROR, ErrorCallback, profile); + gpSetCallback(&profile->gp, GP_RECV_BUDDY_STATUS, RecvBuddyStatusCallback, profile); +#if 1 + gpSetCallback(&profile->gp, GP_RECV_BUDDY_REQUEST, RecvBuddyRequestCallback, profile); + gpSetCallback(&profile->gp, GP_RECV_BUDDY_MESSAGE, RecvBuddyMessageCallback, profile); + gpSetCallback(&profile->gp, GP_RECV_GAME_INVITE, RecvGameInviteCallback, profile); +#endif + + // We're initialized. + ///////////////////// + profile->gpInitialized = true; + + // Not connected yet. + ///////////////////// + profile->connected = false; + + // Remember when we tried to connect. + ///////////////////////////////////// + profile->connectTime = current_time(); + + // Haven't checked yet. + /////////////////////// + profile->invalid = false; + + // When to disconnect. + ////////////////////// + profile->disconnectTime = current_time(); + profile->disconnectTime += (((rand() * (CONNECT_TIME_MAX - CONNECT_TIME_MIN)) / RAND_MAX) + CONNECT_TIME_MIN); + + // No others yet. + ///////////////// + profile->numOthers = 0; + + // Op stuff. + //////////// + profile->activeOp = OpNull; + profile->nextOpTime = 0; + profile->completedOps = 0; + + // It's a connection, but we're not connected. + ////////////////////////////////////////////// + numConnections++; + totalConnections++; + highestConnections = max(highestConnections, numConnections); +} + +/*************** +** VALIDATION ** +***************/ +void GetUserNicksCallback(GPConnection * connection, GPGetUserNicksResponseArg * arg, ValidationData * validationData) +{ + int i; + + // Copy the result. + /////////////////// + validationData->result = arg->result; + + // Check for error. + /////////////////// + if(arg->result != GP_NO_ERROR) + { + printf("%04d: gpGetUserNicks failed\n", validationData->profile->index); + return; + } + + // Copy the nicks. + ////////////////// + validationData->numNicks = min(arg->numNicks, VALIDATION_MAX_NICKS); + for(i = 0 ; i < arg->numNicks ; i++) + strcpy(validationData->nicks[i], arg->nicks[i]); + GSI_UNUSED(connection); +} + +void NewUserResponse(GPConnection * connection, GPNewUserResponseArg * arg, void * param) +{ + GSI_UNUSED(connection); + GSI_UNUSED(arg); + GSI_UNUSED(param); +} + +bool Validate(void) +{ + int i; + GPConnection gp; + char email[GP_EMAIL_LEN] = ""; + Profile * profile; + ValidationData validationData; + + validationData.profile = NULL; + validationData.result = GP_NO_ERROR; + validationData.numNicks = 0; + // Set this here so ctrl-c can cancel the validation. + ///////////////////////////////////////////////////// + startShutdownTime = ULONG_MAX; + + // Init GP. + /////////// + if(gpInitialize(&gp, 0, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR) + { + printf("Failed to initialize GP for validation\n"); + return false; + } +/* + for(i = 41 ; i <= 1000 ; i++) + { + sprintf(email, "gpstress%04d@gamespy.com", i); + gpNewUser(&gp, "gpstress", email, "gpstress", GP_BLOCKING, NewUserResponse, NULL); + printf("%d\n", i); + } +*/ + // Loop through all the profiles. + ///////////////////////////////// + for(i = 0 ; i < numProfiles ; i++) + { + // Check for shutdown. + ////////////////////// + if(current_time() > startShutdownTime) + return false; + + // Cache the profile. + ///////////////////// + profile = &profiles[i]; + + // Is the e-mail address different than the previous one? + ///////////////////////////////////////////////////////// + if(strcmp(email, profile->email) != 0) + { + // Copy the e-mail. + /////////////////// + strcpy(email, profile->email); + + // Put the profile in the validation struct. + //////////////////////////////////////////// + validationData.profile = profile; + + // Show what we're doing. + ///////////////////////// + printf("%04d: Getting nicks for: %s\n", profile->index, email); + + // Get the nicks for this e-mail. + ///////////////////////////////// + gpGetUserNicks(&gp, email, profile->password, GP_BLOCKING, GetUserNicksCallback, &validationData); + } + + // Only do this if the validation succeeded. + //////////////////////////////////////////// + if(validationData.result == GP_NO_ERROR) + { + int n; + bool match = false; + + // Loop through the nicks. + ////////////////////////// + for(n = 0 ; (n < validationData.numNicks) && !match ; n++) + { + // Does this nick match the one being validated? + //////////////////////////////////////////////// + if(strcasecmp(profile->nick, validationData.nicks[n]) == 0) + match = true; + } + + // Set invalid based on match. + ////////////////////////////// + profile->invalid = !match; + } + else + { + // Probably invalid e-mail. + /////////////////////////// + profile->invalid = true; + } + + // Show if we got something invalid. + //////////////////////////////////// + if(profile->invalid) + { + static char buffer[256]; + sprintf(buffer, "%s (%d) : %04d: Invalid profile (%s@%s)\n", profilesFile, (profile->index + 1), profile->index, profile->nick, profile->email); + printf(buffer); + OutputDebugString(buffer); + } + } + + return true; +} + +/******************* +** MAIN FUNCTIONS ** +*******************/ +#ifdef WIN32 +BOOL WINAPI CtrlHandlerRoutine(DWORD dwCtrlType) +{ + // Start shutting down soon. + //////////////////////////// + startShutdownTime = 0; + + GSI_UNUSED(dwCtrlType); + // Handled. + return TRUE; +} +#endif + +bool Initialize(void) +{ + int i; + Profile * profile; + DWORD now; + GSIACResult aResult = GSIACWaiting; + + // Seed the random number generator. + //////////////////////////////////// + srand(time(NULL)); + + // Perform the availability check + GSIStartAvailableCheck("gmtest"); + while(aResult == GSIACWaiting) + aResult = GSIAvailableCheckThink(); + if (aResult != GSIACAvailable) + { + printf("Backend services are not available.\r\n"); + return false; + } + + +#ifdef WIN32 + // Set the ctrl-c handler. + ////////////////////////// + SetConsoleCtrlHandler(CtrlHandlerRoutine, TRUE); +#endif + + // Set our own hostname. + //////////////////////// +#ifdef CONNECTION_MANAGER + if(CONNECTION_MANAGER[0]) + strcpy(GPConnectionManagerHostname, CONNECTION_MANAGER); +#endif + + // Load the profiles. + ///////////////////// + if(!LoadProfiles()) + return false; + + // Cap off the max connected profiles. + ////////////////////////////////////// + if(maxConnections > numProfiles) + maxConnections = numProfiles; + + // Get the current time. + //////////////////////// + now = current_time(); + + // Initalize profile stuff. + /////////////////////////// + for(i = 0 ; i < numProfiles ; i++) + { + // Cache the profile pointer. + /////////////////////////////. + profile = &profiles[i]; + + // Set its index. + ///////////////// + profile->index = i; + + // No op yet. + ///////////// + profile->activeOp = OpNull; + + // Print out a message every 100. + ///////////////////////////////// +#if 0 + if(((i + 1) % 100) == 0) + { + printf("%d/%d profiles initialized\n", i + 1, numProfiles); + msleep(1); + } +#endif + } + + return true; +} + +void Shutdown(void) +{ + int i; + + // Cleanup all the GP objects. + ////////////////////////////// + for(i = 0 ; i < numProfiles ; i++) + { + // Check if GP was intialized. + ////////////////////////////// + if(profiles[i].gpInitialized) + { + // Destroy the GP object. + ///////////////////////// + gpDestroy(&profiles[i].gp); + + // Print out a message every 100. + ///////////////////////////////// + if(((i + 1) % 100) == 0) + { + printf("%d/%d profiles destroyed\n", i + 1, numProfiles); + msleep(1); + } + } + } +} + +void StartShutdown(unsigned long now) +{ + Profile * profile; + int i; + + // Loop through all the profiles. + ///////////////////////////////// + for(i = 0 ; i < numProfiles ; i++) + { + // Cache the profile pointer. + ///////////////////////////// + profile = &profiles[i]; + + // Check if its GP object is initialized. + ///////////////////////////////////////// + if(profile->gpInitialized) + { +#if 0 + // Is it not actually connected yet? + //////////////////////////////////// + if(!profile->connected) + { + char buffer[64]; + + // How long has it been waiting? + //////////////////////////////// + sprintf(buffer, "%04d: Waiting %ds for connection attempt\n", profile->index, (current_time() - profile->connectTime) / 1000); + Log(buffer); + } +#endif + + // Set when to disconnect, + ////////////////////////// + profile->disconnectTime = (now + ((rand() * ((numConnections / SHUTDOWN_DISCONNECTS_PER_SEC) * 1000)) / RAND_MAX)); + } + } + + // We're shutting down, don't add new connections, etc. + /////////////////////////////////////////////////////// + shuttingDown = true; +} + +void Frame(unsigned long now) +{ + int i; + + // Is it time to connect a new profile? + /////////////////////////////////////// + if(!shuttingDown && (numConnections < maxConnections) && ((numConnections - numConnected) < MAX_OUTSTANDING_CONNECTIONS)) + { + Profile * profile; + unsigned long timeDiff; + int numConnects; + + // How long since the last connect? + /////////////////////////////////// + timeDiff = (now - lastConnectTime); + + // How many connects should we do? + ////////////////////////////////// + numConnects = ((timeDiff * connectsPerSecond) / 1000); + numConnects = min(numConnects, (MAX_OUTSTANDING_CONNECTIONS - (numConnections - numConnected))); + + // Do the connects. + /////////////////// + for(i = 0 ; i < numConnects ; i++) + { + // Need to check because it can change in the loop. + /////////////////////////////////////////////////// + if(numConnections < maxConnections) + { + // Pick a random profile. + ///////////////////////// + profile = GetUninitializedProfile(); + + // Init it. + /////////// + InitializeProfile(profile); + + // Remember when we did the connect(s). + /////////////////////////////////////// + lastConnectTime = now; + } + } + } + + // Loop through all the profiles. + ///////////////////////////////// + for(i = 0 ; i < numProfiles ; i++) + { + // Process the profile. + /////////////////////// + ProcessProfile(&profiles[i]); + } +} + +void Run(void) +{ + bool done; + unsigned long now; +#if 0 + unsigned long nextInfoTime = 0; +#endif + // Get the current time. + //////////////////////// + now = current_time(); + + // Set when to shut down. + ///////////////////////// + startShutdownTime = (now + runTime); + + // Make up the last connect time. + ///////////////////////////////// + lastConnectTime = (now - 100); + + // Loop until we're done. + ///////////////////////// + for(done = false ; !done ; ) + { + // Get the current time. + //////////////////////// + now = current_time(); + + // Are we shutting down? + //////////////////////// + if(shuttingDown) + { + // Are we done? + /////////////// + if(numConnections == 0) + { + done = true; + } + } + else if(now > startShutdownTime) + { + // Time to start shutting down. + /////////////////////////////// + StartShutdown(now); + } + +#if 0 + // Is it time to print some info? + ///////////////////////////////// + if(now > nextInfoTime) + { + static char buffer[256]; + + // Set when to next show info. + ////////////////////////////// + nextInfoTime = (now + SHOW_INFO_TIME); + + // Show the connection numbers. + /////////////////////////////// + sprintf(buffer, "INFO: Connections: %d current, %d highest, %d total\n", numConnections, highestConnections, totalConnections); + Log(buffer); + + // Show the connected numbers. + ////////////////////////////// + sprintf(buffer, "INFO: Connected: %d current, %d highest, %d total\n", numConnected, highestConnected, totalConnected); + Log(buffer); + + // Show that we're shutting down, or when we're shutting down. + ////////////////////////////////////////////////////////////// + if(shuttingDown) + sprintf(buffer, "INFO: Shutting down\n"); + else + { + unsigned long totalSeconds = ((startShutdownTime - now) / 1000); + unsigned long hours, minutes, seconds; + seconds = (totalSeconds % 60); + minutes = (totalSeconds / 60 % 60); + hours = (totalSeconds / 60 / 60); + sprintf(buffer, "INFO: Shut down in %d:%02d:%02d\n", hours, minutes, seconds); + } + Log(buffer); + } +#endif + + // Run a frame. + /////////////// + Frame(now); + + // Take a break. + //////////////// + msleep(10); + } +} + +bool ParseArgs(int argc, char ** argv) +{ + int i; +/* + // Check for the file index. + //////////////////////////// + if(argc < 2) + { + printf("Usage: %s \n", argv[0]); + return false; + } + sprintf(profilesFile, "stress%d.txt", atoi(argv[1])); +*/ + // Set defaults. + //////////////// + maxConnections = DEFAULT_MAX_CONNECTED; + runTime = DEFAULT_RUN_TIME; + connectsPerSecond = DEFAULT_CONNECTS_PER_SEC; + + // Check args. + ////////////// + for(i = 1 ; i < argc ; i++) + { + // Check for max connected profiles. + //////////////////////////////////// + if(strcasecmp(argv[i], "-m") == 0) + { + if(++i < argc) + { + maxConnections = atoi(argv[i]); + if(maxConnections <= 0) + maxConnections = DEFAULT_MAX_CONNECTED; + } + } + // Check for how long to run. + ///////////////////////////// + else if(strcasecmp(argv[i], "-t") == 0) + { + if(++i < argc) + { + runTime = (atoi(argv[i]) * 1000); + if(runTime <= 0) + runTime = DEFAULT_RUN_TIME; + } + } + // Check for connections per second. + //////////////////////////////////// + else if(strcasecmp(argv[i], "-s") == 0) + { + if(++i < argc) + { + connectsPerSecond = atoi(argv[i]); + if(connectsPerSecond <= 0) + connectsPerSecond = DEFAULT_CONNECTS_PER_SEC; + } + } + } + + return true; +} + +int main(int argc, char ** argv) +{ + // Parse args. + ////////////// + if(!ParseArgs(argc, argv)) + return 1; + + // Initialize. + ////////////// + if(!Initialize()) + return 1; + +#if 0 + // Validate the loaded profiles. + //////////////////////////////// + if(!Validate()) + return 1; +#endif + + // Do all that stuff. + ///////////////////// + Run(); + + // Cleanup. + /////////// + Shutdown(); + + return 0; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/GP/gpstress/gpstress.dsp b/xrGameSpy/gamespy/GP/gpstress/gpstress.dsp new file mode 100644 index 00000000000..4c862c87b96 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpstress/gpstress.dsp @@ -0,0 +1,426 @@ +# Microsoft Developer Studio Project File - Name="gpstress" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gpstress - 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 "gpstress.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 "gpstress.mak" CFG="gpstress - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gpstress - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gpstress - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gpstress - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /WX /GX /O2 /I "../../common" /I "../../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /FD /c +# SUBTRACT CPP /YX +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gpstress - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gpstress___Win32_Debug" +# PROP BASE Intermediate_Dir "gpstress___Win32_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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /I "../../common" /I "../../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gpstress - Win32 Release" +# Name "gpstress - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gpstress.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\gp.c +# End Source File +# Begin Source File + +SOURCE=..\gp.h +# End Source File +# Begin Source File + +SOURCE=..\gpi.c +# End Source File +# Begin Source File + +SOURCE=..\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\gpiBuddy.c +# End Source File +# Begin Source File + +SOURCE=..\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\gpiBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiCallback.c +# End Source File +# Begin Source File + +SOURCE=..\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\gpiConnect.c +# End Source File +# Begin Source File + +SOURCE=..\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\gpiInfo.c +# End Source File +# Begin Source File + +SOURCE=..\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\gpiOperation.c +# End Source File +# Begin Source File + +SOURCE=..\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\gpiPeer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiProfile.c +# End Source File +# Begin Source File + +SOURCE=..\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\gpiSearch.c +# End Source File +# Begin Source File + +SOURCE=..\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\gpiTransfer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiUnique.c +# End Source File +# Begin Source File + +SOURCE=..\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\gpiUtility.c +# End Source File +# Begin Source File + +SOURCE=..\gpiUtility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj b/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj new file mode 100644 index 00000000000..08fa328114f --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj @@ -0,0 +1,869 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gpstress/gpstress_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/GP/gptest/StdAfx.cpp b/xrGameSpy/gamespy/GP/gptest/StdAfx.cpp new file mode 100644 index 00000000000..e5d5a392108 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// gptest.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/GP/gptest/StdAfx.h b/xrGameSpy/gamespy/GP/gptest/StdAfx.h new file mode 100644 index 00000000000..9b70ff8ddcd --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/StdAfx.h @@ -0,0 +1,30 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__8A9E3741_2C27_4AC4_AB95_C33A19DEB835__INCLUDED_) +#define AFX_STDAFX_H__8A9E3741_2C27_4AC4_AB95_C33A19DEB835__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC socket extensions + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#include "../gp.h" +#include "../../common/gsAvailable.h" + +#endif // !defined(AFX_STDAFX_H__8A9E3741_2C27_4AC4_AB95_C33A19DEB835__INCLUDED_) diff --git a/xrGameSpy/gamespy/GP/gptest/gptest.cpp b/xrGameSpy/gamespy/GP/gptest/gptest.cpp new file mode 100644 index 00000000000..615e5ade675 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest.cpp @@ -0,0 +1,85 @@ +// gptest.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "gptest.h" +#include "gptestDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CGptestApp + +BEGIN_MESSAGE_MAP(CGptestApp, CWinApp) + //{{AFX_MSG_MAP(CGptestApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGptestApp construction + +CGptestApp::CGptestApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CGptestApp object + +CGptestApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CGptestApp initialization + +BOOL CGptestApp::InitInstance() +{ + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CGptestDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} + +int CGptestApp::ExitInstance() +{ + // TODO: Add your specialized code here and/or call the base class + + return CWinApp::ExitInstance(); +} diff --git a/xrGameSpy/gamespy/GP/gptest/gptest.dsp b/xrGameSpy/gamespy/GP/gptest/gptest.dsp new file mode 100644 index 00000000000..049f1ae8d71 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest.dsp @@ -0,0 +1,430 @@ +# Microsoft Developer Studio Project File - Name="gptest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=gptest - 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 "gptest.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 "gptest.mak" CFG="gptest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gptest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "gptest - 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)" == "gptest - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "gptest - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".." /I "..\..\\" /I "..\..\common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gptest - Win32 Release" +# Name "gptest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gptest.cpp +# End Source File +# Begin Source File + +SOURCE=.\gptest.rc +# End Source File +# Begin Source File + +SOURCE=.\gptestDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gptest.h +# End Source File +# Begin Source File + +SOURCE=.\gptestDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\gptest.ico +# End Source File +# Begin Source File + +SOURCE=.\res\gptest.rc2 +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\gp.c +# End Source File +# Begin Source File + +SOURCE=..\gpi.c +# End Source File +# Begin Source File + +SOURCE=..\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\gpiBuddy.c +# End Source File +# Begin Source File + +SOURCE=..\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\gpiBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiCallback.c +# End Source File +# Begin Source File + +SOURCE=..\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\gpiConnect.c +# End Source File +# Begin Source File + +SOURCE=..\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\gpiInfo.c +# End Source File +# Begin Source File + +SOURCE=..\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\gpiOperation.c +# End Source File +# Begin Source File + +SOURCE=..\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\gpiPeer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiProfile.c +# End Source File +# Begin Source File + +SOURCE=..\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\gpiSearch.c +# End Source File +# Begin Source File + +SOURCE=..\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\gpiTransfer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiUnique.c +# End Source File +# Begin Source File + +SOURCE=..\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\gpiUtility.c +# End Source File +# Begin Source File + +SOURCE=..\gpiUtility.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/GP/gptest/gptest.h b/xrGameSpy/gamespy/GP/gptest/gptest.h new file mode 100644 index 00000000000..4be6f8ddcd7 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest.h @@ -0,0 +1,50 @@ +// gptest.h : main header file for the GPTEST application +// + +#if !defined(AFX_GPTEST_H__FFE82BD6_F31E_4222_818F_A8EE211E15E4__INCLUDED_) +#define AFX_GPTEST_H__FFE82BD6_F31E_4222_818F_A8EE211E15E4__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CGptestApp: +// See gptest.cpp for the implementation of this class +// + +class CGptestApp : public CWinApp +{ +public: + CGptestApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGptestApp) + public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CGptestApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GPTEST_H__FFE82BD6_F31E_4222_818F_A8EE211E15E4__INCLUDED_) diff --git a/xrGameSpy/gamespy/GP/gptest/gptest.rc b/xrGameSpy/gamespy/GP/gptest/gptest.rc new file mode 100644 index 00000000000..b6407021c17 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest.rc @@ -0,0 +1,397 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\gptest.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\gptest.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_GPTEST_DIALOG DIALOGEX 0, 0, 610, 457 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "gptest" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_EMAIL,61,29,111,12,ES_AUTOHSCROLL + EDITTEXT IDC_NICK,61,43,111,12,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,61,57,111,12,ES_PASSWORD | ES_AUTOHSCROLL + PUSHBUTTON "Connect",IDC_CONNECT,15,101,48,14 + PUSHBUTTON "Disconnect",IDC_DISCONNECT,205,101,55,14 + CONTROL "Blocking",IDC_BLOCKING,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,192,86,41,8 + PUSHBUTTON "Check User",IDC_CHECK,192,29,55,12 + PUSHBUTTON "New User",IDC_NEWUSER,192,43,55,12 + PUSHBUTTON "Update",IDC_UPDATE,192,57,55,12 + PUSHBUTTON "Delete",IDC_DELETEPRO,275,15,31,12 + PUSHBUTTON "New:",IDC_NEWPRO,313,15,30,12 + EDITTEXT IDC_NEWNICK,348,14,50,12,ES_AUTOHSCROLL + CONTROL "R",IDC_REPLACE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,401,15,20,10 + EDITTEXT IDC_SNICK,315,41,104,12,ES_AUTOHSCROLL + EDITTEXT IDC_SFIRSTNAME,315,67,104,12,ES_AUTOHSCROLL + EDITTEXT IDC_SLASTNAME,315,80,104,12,ES_AUTOHSCROLL + EDITTEXT IDC_SEMAIL,315,93,104,12,ES_AUTOHSCROLL + EDITTEXT IDC_SICQUIN,315,106,104,12,ES_AUTOHSCROLL + PUSHBUTTON "Search",IDC_SEARCH,275,123,28,14 + PUSHBUTTON "Valid Email?",IDC_VALIDATE,307,123,43,14 + PUSHBUTTON "Nicks",IDC_NICKS,355,123,23,14 + LISTBOX IDC_RESULTS,275,154,145,90,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + EDITTEXT IDC_REASON,321,263,99,12,ES_AUTOHSCROLL + PUSHBUTTON "Send Buddy Request",IDC_SENDREQUEST,276,247,75,13 + EDITTEXT IDC_SEARCH_SERVER,321,277,99,12,ES_AUTOHSCROLL + EDITTEXT IDC_STATUS,325,302,65,12,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_STATUSSTRING,325,316,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_LOCATIONSTRING,325,332,65,12,ES_AUTOHSCROLL + PUSHBUTTON " Set Status",IDC_SET,395,302,25,40,BS_CENTER | BS_MULTILINE + CONTROL "nick",IDC_RNICK,"Button",BS_AUTORADIOBUTTON | WS_GROUP,275,356,30,10 + CONTROL "name",IDC_RNAME,"Button",BS_AUTORADIOBUTTON,305,356,30,10 + CONTROL "e-mail",IDC_REMAIL,"Button",BS_AUTORADIOBUTTON,335,356,30,10 + PUSHBUTTON "Report",IDC_REPORT,379,356,40,11,WS_GROUP + CONTROL "Auto",IDC_SAUTO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,275,379,30,10 + CONTROL "1",IDC_S1,"Button",BS_AUTORADIOBUTTON,305,379,20,10 + CONTROL "2",IDC_S2,"Button",BS_AUTORADIOBUTTON,325,379,20,10 + CONTROL "3",IDC_S3,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,345,379,20,10 + CONTROL "4",IDC_S4,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,365,379,20,10 + CONTROL "5",IDC_S5,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,385,379,20,10 + CONTROL "6",IDC_S6,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,405,379,17,10 + CONTROL "Local",IDC_S7,"Button",BS_AUTORADIOBUTTON,275,395,33,10 + CONTROL "Other:",IDC_SOTHER,"Button",BS_AUTORADIOBUTTON,307,395,30,10 + EDITTEXT IDC_OTHER_SERVER,339,393,80,12,ES_AUTOHSCROLL | WS_GROUP + EDITTEXT IDC_PATH,300,419,80,12,ES_AUTOHSCROLL + EDITTEXT IDC_NAME,300,435,80,12,ES_AUTOHSCROLL + PUSHBUTTON "Send",IDC_SEND_FILES,386,419,35,25 + LISTBOX IDC_BUDDIES,10,169,63,164,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + EDITTEXT IDC_IFIRSTNAME,179,170,35,12,ES_AUTOHSCROLL + EDITTEXT IDC_ILASTNAME,215,170,45,12,ES_AUTOHSCROLL + EDITTEXT IDC_INICK,200,199,60,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_IEMAIL,200,214,60,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_IICQUIN,200,228,60,12,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_IHOMEPAGE,200,244,60,12,ES_AUTOHSCROLL + EDITTEXT IDC_IBIRTHMONTH,190,259,15,12,ES_AUTOHSCROLL + EDITTEXT IDC_IBIRTHDAY,210,259,15,12,ES_AUTOHSCROLL + EDITTEXT IDC_IBIRTHYEAR,230,259,30,12,ES_AUTOHSCROLL + EDITTEXT IDC_ISEX,200,274,60,12,ES_AUTOHSCROLL + EDITTEXT IDC_ICOUNTRYCODE,200,289,60,12,ES_AUTOHSCROLL + EDITTEXT IDC_IZIPCODE,200,304,60,12,ES_AUTOHSCROLL + PUSHBUTTON "Set Info",IDC_SETINFO,204,393,48,13 + CONTROL "homepage",IDC_IPMHOMEPAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,396,50,10 + CONTROL "zipcode",IDC_IPMZIPCODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,385,40,10 + CONTROL "countrycode",IDC_IPMCOUNTRYCODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,385,52,10 + CONTROL "birthday",IDC_IPMBIRTHDAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,396,40,10 + CONTROL "sex",IDC_IPMSEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,407,25,10 + CONTROL "e-mail",IDC_IPMEMAIL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,143,418,35,10 + EDITTEXT IDC_IADDRESS,200,363,60,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_MESSAGE,48,436,142,12,ES_AUTOHSCROLL | ES_WANTRETURN + PUSHBUTTON "Send",IDC_SEND,194,435,33,13 + PUSHBUTTON "Delete",IDC_DELETE,17,337,46,12 + PUSHBUTTON "Delete All",IDC_DELETEALL,17,354,46,12,WS_GROUP + PUSHBUTTON "Refresh",IDC_REFRESH,17,370,46,12 + CONTROL "cache info",IDC_INFO_CACHE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,203,411,51,10 + PUSHBUTTON "Invite Player",IDC_INVITE_PLAYER,437,425,48,12 + EDITTEXT IDC_INVITE_PLAYER_ID,537,425,57,12,ES_AUTOHSCROLL | ES_WANTRETURN + EDITTEXT IDC_CODE,451,19,142,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_STRING,451,35,142,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "e-mail:",IDC_STATIC,15,31,21,8 + LTEXT "password:",IDC_STATIC,15,59,33,8 + LTEXT "nick:",IDC_STATIC,15,44,16,8 + GROUPBOX "Login",IDC_STATIC,10,5,256,155 + GROUPBOX "Buddies",IDC_STATIC,7,160,68,266 + GROUPBOX "Status",IDC_STATIC,269,292,155,55 + LTEXT "status:",IDC_STATIC,275,304,21,8 + LTEXT "locationString:",IDC_STATIC,275,334,46,8 + LTEXT "statusString:",IDC_STATIC,275,319,41,8 + LTEXT "birthday:",IDC_STATIC,154,259,30,8 + LTEXT "name:",IDC_STATIC,155,171,20,8 + LTEXT "countrycode:",IDC_STATIC,154,289,43,8 + LTEXT "e-mail:",IDC_STATIC,154,214,23,8 + LTEXT "nick:",IDC_STATIC,154,199,20,8 + LTEXT "homepage:",IDC_STATIC,154,244,35,8 + LTEXT "icquin:",IDC_STATIC,154,228,23,8 + LTEXT "zipcode:",IDC_STATIC,154,304,27,8 + LTEXT "sex:",IDC_STATIC,154,274,14,8 + LTEXT "address:",IDC_STATIC,154,364,27,8 + LTEXT " message:",IDC_STATIC,13,438,33,8 + GROUPBOX "Search",IDC_STATIC,269,32,155,260 + LTEXT "e-mail:",IDC_STATIC,275,93,21,8 + LTEXT "nick:",IDC_STATIC,275,41,16,8 + LTEXT "first name:",IDC_STATIC,275,67,34,8 + LTEXT "last name:",IDC_STATIC,275,80,33,8 + LTEXT "icq uin:",IDC_STATIC,275,106,24,8 + LTEXT "RESULTS:",IDC_STATIC,275,143,40,8 + GROUPBOX "Error",IDC_STATIC,426,5,177,49 + LTEXT "code:",IDC_STATIC,431,21,18,8 + LTEXT "string:",IDC_STATIC,431,36,19,8 + LTEXT "reason:",IDC_STATIC,275,263,24,8 + GROUPBOX "Identify by",IDC_STATIC,269,347,100,23 + CONTROL "/",IDC_STATIC,"Static",SS_SIMPLE | WS_GROUP,204,259,8,8 + CONTROL "/",IDC_STATIC,"Static",SS_SIMPLE | WS_GROUP,224,259,8,8 + GROUPBOX "Profiles",IDC_STATIC,269,5,155,27 + GROUPBOX "Inviting",IDC_STATIC,426,408,177,42 + LTEXT "Product ID:",IDC_STATIC,493,427,37,8 + GROUPBOX "Profiles",IDC_STATIC,375,347,50,23 + GROUPBOX "Server",IDC_STATIC,269,370,155,39 + GROUPBOX "Send Files",IDC_STATIC,269,410,155,40 + LTEXT "Path:",IDC_STATIC,276,421,18,8 + LTEXT "Name:",IDC_STATIC,275,435,22,8 + LTEXT "search server:",IDC_STATIC,274,278,47,8 + CONTROL "Firewall",IDC_FIREWALL,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,192,74,40,8 + PUSHBUTTON "All",IDC_PUBLICMASK_ALL,83,409,25,16 + PUSHBUTTON "None",IDC_PUBLICMASK_NONE,111,409,26,16 + EDITTEXT IDC_ILONGITUDE,200,319,60,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "longitude:",IDC_STATIC,154,319,35,8 + EDITTEXT IDC_ILATITUDE,200,334,60,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "latitude:",IDC_STATIC,154,334,25,8 + EDITTEXT IDC_IPLACE,200,348,60,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "place:",IDC_STATIC,154,348,23,8 + GROUPBOX "publicmask",IDC_STATIC,79,376,105,54 + PUSHBUTTON "Revoke Buddy Auth",IDC_REVOKE,16,388,48,20,BS_MULTILINE + EDITTEXT IDC_SUNIQUENICK,315,54,104,12,ES_AUTOHSCROLL + LTEXT "unique nick:",IDC_STATIC,275,54,40,8 + EDITTEXT IDC_UNIQUENICK,61,72,111,12,ES_AUTOHSCROLL + LTEXT "uniquenick:",IDC_STATIC,15,74,38,8 + EDITTEXT IDC_IUNIQUENICK,200,185,60,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "uniquenick:",IDC_STATIC,154,185,38,8 + PUSHBUTTON "Suggest",IDC_SUGGEST,383,123,31,14 + PUSHBUTTON "ConnectUniquenick",IDC_CONNECTUNIQUE,67,101,72,14 + PUSHBUTTON "ConnectPreAuth",IDC_CONNECTPREAUTH,143,101,58,14 + EDITTEXT IDC_AUTHTOKEN,61,116,198,12,ES_AUTOHSCROLL + EDITTEXT IDC_PARTNERCHALLENGE,61,130,198,12,ES_AUTOHSCROLL + EDITTEXT IDC_NAMESPACE,65,14,31,12,ES_AUTOHSCROLL + LTEXT "namespaceid:",IDC_STATIC,15,16,45,8 + PUSHBUTTON "Initialize",IDC_INITIALIZE,177,14,42,12 + PUSHBUTTON "Destroy",IDC_DESTROY,221,14,42,12 + PUSHBUTTON "UTM",IDC_UTM,229,435,30,13 + EDITTEXT IDC_PARTNERID,131,14,41,12,ES_AUTOHSCROLL + LTEXT "partnerid:",IDC_STATIC,99,16,30,8 + EDITTEXT IDC_PRODUCTID,61,86,111,12,ES_AUTOHSCROLL + LTEXT "productid:",IDC_STATIC,15,88,32,8 + GROUPBOX "Basic Status Info",IDC_STATIC,426,55,177,232,WS_DISABLED + COMBOBOX IDC_STATUS_STATE,461,71,73,66,CBS_DROPDOWN | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + LTEXT "State:",IDC_STATELABEL,434,72,19,8 + LTEXT "Rich Status:",IDC_RSLABEL,433,270,40,8 + EDITTEXT IDC_RICH_STATUS,494,268,101,12,ES_AUTOHSCROLL | WS_DISABLED + EDITTEXT IDC_QPORT,494,126,101,13,ES_AUTOHSCROLL | WS_DISABLED + EDITTEXT IDC_HPORT,494,143,101,13,ES_AUTOHSCROLL | WS_DISABLED + LISTBOX IDC_SFLAGS,520,159,75,54,LBS_SORT | LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + LTEXT "Host IP:",IDC_HOSTIPLABEL,433,91,28,13 + LTEXT "Host Private IP:",IDC_HOSTPRIVIPLABEL,433,110,50,11 + LTEXT "Query Port:",IDC_QPORTLABEL,433,128,38,11 + LTEXT "Host Port:",IDC_HPORTLABEL,433,145,38,11 + LTEXT "Session Flags:",IDC_SFLAGESLABEL,433,182,59,10 + LTEXT "Game Type:",IDC_GTLABEL,433,217,39,11 + LTEXT "Game Variant:",IDC_GVLABEL,433,235,49,11 + EDITTEXT IDC_GAME_TYPE,494,216,101,12,ES_AUTOHSCROLL | WS_DISABLED + EDITTEXT IDC_GAME_VARIANT,494,233,101,12,ES_AUTOHSCROLL | WS_DISABLED + EDITTEXT IDC_GAME_MAPNAME,494,249,101,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Game Mapname:",IDC_GMLABEL,433,251,56,11 + PUSHBUTTON "Set Status Info",IDC_SETSTATUSINFO,537,70,59,14,WS_DISABLED + GROUPBOX "Extended Status Info",IDC_EXTSTATUSINFO,426,292,177,113,WS_DISABLED + EDITTEXT IDC_EDIT1,493,303,102,12,ES_AUTOHSCROLL | WS_DISABLED + EDITTEXT IDC_EDIT2,493,318,102,12,ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Key Name:",IDC_STATIC,433,306,39,9 + LTEXT "Key Value:",IDC_STATIC,433,320,35,9 + PUSHBUTTON "Add/Set",IDC_BUTTON2,435,339,42,14,WS_DISABLED + PUSHBUTTON "Delete",IDC_BUTTON3,485,339,37,14,WS_DISABLED + PUSHBUTTON "Get Value for Key",IDC_BUTTON4,531,339,64,14,WS_DISABLED + PUSHBUTTON "Get them!",IDC_BUTTON5,481,385,64,14,WS_DISABLED + LTEXT "Get Buddies Keys and Values (Buddy must be selected)",IDC_STATIC,465,364,98,20 + EDITTEXT IDC_HOST_IP,494,91,101,12,ES_AUTOHSCROLL | WS_DISABLED + EDITTEXT IDC_HOST_PRIVATE_IP,494,109,101,12,ES_AUTOHSCROLL | WS_DISABLED + PUSHBUTTON "Register CDKey",IDC_REGISTER_CDKEY,183,144,77,13 + EDITTEXT IDC_CDKEY,61,144,110,12,ES_AUTOHSCROLL + LTEXT "cdkey:",IDC_STATIC,15,145,33,8 + LTEXT "authtoken:",IDC_STATIC,15,118,37,8 + LTEXT "challenge:",IDC_STATIC,15,132,37,8 + GROUPBOX "Player Info",IDC_STATIC,151,160,114,218 + LISTBOX IDC_BLOCKLIST,82,169,62,164,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + GROUPBOX "Blocked List",IDC_STATIC,79,160,68,214 + PUSHBUTTON "Get Blocked List",IDC_GET_BLOCKEDLIST,84,337,58,13 + PUSHBUTTON "Remove Block",IDC_REMOVE_BLOCK,84,354,58,13 + PUSHBUTTON "Add Block",IDC_ADD_BLOCK,360,247,58,13 + GROUPBOX "Messaging",IDC_STATIC,7,428,258,22 + GROUPBOX "Set Player Info",IDC_STATIC,193,381,70,49 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "FileDescription", "gptest MFC Application" + VALUE "FileVersion", "1, 0, 0, 1" + VALUE "InternalName", "gptest" + VALUE "LegalCopyright", "Copyright (C) 1999" + VALUE "OriginalFilename", "gptest.EXE" + VALUE "ProductName", "gptest Application" + VALUE "ProductVersion", "1, 0, 0, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_GPTEST_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 603 + TOPMARGIN, 7 + BOTTOMMARGIN, 450 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_GPTEST_DIALOG DLGINIT +BEGIN + IDC_STATUS_STATE, 0x403, 8, 0 +0x664f, 0x6c66, 0x6e69, 0x0065, + IDC_STATUS_STATE, 0x403, 7, 0 +0x6e4f, 0x696c, 0x656e, "\000" + IDC_STATUS_STATE, 0x403, 8, 0 +0x6c50, 0x7961, 0x6e69, 0x0067, + IDC_STATUS_STATE, 0x403, 8, 0 +0x7453, 0x6761, 0x6e69, 0x0067, + IDC_STATUS_STATE, 0x403, 9, 0 +0x6843, 0x7461, 0x6974, 0x676e, "\000" + IDC_STATUS_STATE, 0x403, 5, 0 +0x7741, 0x7961, "\000" + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\gptest.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/GP/gptest/gptestDlg.cpp b/xrGameSpy/gamespy/GP/gptest/gptestDlg.cpp new file mode 100644 index 00000000000..442ea48a137 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptestDlg.cpp @@ -0,0 +1,2056 @@ +// gptestDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "gptest.h" +#include "gptestDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CGptestDlg * dlg; + +#define CHECK(result) { if((result) != GP_NO_ERROR) { OutputDebugString(#result " failed\n");}} + +#define PROCESS_TIME 20 + +#define GSI_DEFAULT_NAMESPACE 1 +#define GSI_TEST_PRODUCTID 0 +#define GSI_TEST_GAMENAME "gmtest" + + +void vsDebugOut(va_list args, const char * format, ...) +{ +#ifdef GSI_COMMON_DEBUG + char buffer[256]; + + // If args list is null then build it. + if(args == NULL) + { + va_start(args, format); + _vsnprintf(buffer, sizeof(buffer), format, args); + va_end(args); + } + else + _vsnprintf(buffer, sizeof(buffer), format, args); + + OutputDebugString(buffer); +#endif + GSI_UNUSED(args); + GSI_UNUSED(format); +} + +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + + vsDebugOut(NULL, "[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + vsDebugOut(theParamList, theTokenStr); + } +#endif + + +///////////////////////////////////////////////////////////////////////////// +// CGptestDlg dialog + +CGptestDlg::CGptestDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGptestDlg::IDD, pParent) + , m_StatusState(0) + , m_QueryPort(0) + , m_HostPort(0) + , m_RichStatus(_T("")) + , m_GameType(_T("")) + , m_GameVariant(_T("")) + , m_GameMapname(_T("")) + , m_KeyName(_T("")) + , m_KeyValue(_T("")) + , m_HostIp(_T("")) + , m_HostPrivateIp(_T("")) + , m_cdkey(_T("")) +{ + //{{AFX_DATA_INIT(CGptestDlg) + m_partnerid = 0; + m_email = _T(""); + m_nick = _T(""); + m_password = _T(""); + m_locationString = _T(""); + m_status = 1; + m_statusString = _T(""); + m_iaddress = _T(""); + m_icountrycode = _T(""); + m_iemail = _T(""); + m_ihomepage = _T(""); + m_iicquin = 0; + m_inick = _T(""); + m_isex = _T(""); + m_message = _T("Hi. This is a message!"); + m_sfirstname = _T(""); + m_snick = _T(""); + m_sicquin = 0; + m_slastname = _T(""); + m_semail = _T(""); + m_string = _T(""); + m_code = _T(""); + m_reason = _T("Hello."); + m_rnick = 0; + m_infoCache = TRUE; + m_blocking = FALSE; + m_ilastname = _T(""); + m_ifirstname = _T(""); + m_ibirthday = 0; + m_ibirthmonth = 0; + m_ibirthyear = 0; + m_ipmbirthday = FALSE; + m_ipmcountrycode = FALSE; + m_ipmhomepage = FALSE; + m_ipmsex = FALSE; + m_ipmzipcode = FALSE; + m_newnick = _T(""); + m_replace = FALSE; + m_izipcode = _T(""); + m_invitePlayerID = 1; + m_server = 0; + m_otherServer = _T(""); + m_name = _T(""); + m_path = _T(""); + m_searchServer = _T(""); + m_ipmemail = FALSE; + m_firewall = FALSE; + m_ilatitude = 0.0f; + m_iplace = _T(""); + m_ilongitude = 0.0f; + m_suniquenick = _T(""); + m_iuniquenick = _T(""); + m_uniquenick = _T(""); + m_authtoken = _T(""); + m_partnerchallenge = _T(""); + m_namespace = _T(""); + m_productid = 0; + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + + +} + +void CGptestDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGptestDlg) + DDX_Control(pDX, IDC_CONNECTUNIQUE, m_connectunique); + DDX_Control(pDX, IDC_CONNECTPREAUTH, m_connectpreauth); + DDX_Control(pDX, IDC_NEWUSER, m_newuser); + DDX_Control(pDX, IDC_SEARCH, m_search); + DDX_Control(pDX, IDC_RESULTS, m_results); + DDX_Control(pDX, IDC_UPDATE, m_update); + DDX_Control(pDX, IDC_SEND, m_send); + DDX_Control(pDX, IDC_SET, m_set); + DDX_Control(pDX, IDC_BUDDIES, m_buddies); + DDX_Control(pDX, IDC_DISCONNECT, m_disconnect); + DDX_Control(pDX, IDC_CONNECT, m_connect); + DDX_Text(pDX, IDC_PARTNERID, m_partnerid); + DDX_Text(pDX, IDC_EMAIL, m_email); + DDV_MaxChars(pDX, m_email, 50); + DDX_Text(pDX, IDC_NICK, m_nick); + DDV_MaxChars(pDX, m_nick, 30); + DDX_Text(pDX, IDC_PASSWORD, m_password); + DDV_MaxChars(pDX, m_password, 30); + DDX_Text(pDX, IDC_LOCATIONSTRING, m_locationString); + DDV_MaxChars(pDX, m_locationString, 255); + DDX_Text(pDX, IDC_STATUS, m_status); + DDV_MinMaxInt(pDX, m_status, 0, 100); + DDX_Text(pDX, IDC_STATUSSTRING, m_statusString); + DDV_MaxChars(pDX, m_statusString, 255); + DDX_Text(pDX, IDC_IADDRESS, m_iaddress); + DDX_Text(pDX, IDC_ICOUNTRYCODE, m_icountrycode); + DDV_MaxChars(pDX, m_icountrycode, 2); + DDX_Text(pDX, IDC_IEMAIL, m_iemail); + DDX_Text(pDX, IDC_IHOMEPAGE, m_ihomepage); + DDX_Text(pDX, IDC_IICQUIN, m_iicquin); + DDX_Text(pDX, IDC_INICK, m_inick); + DDX_Text(pDX, IDC_ISEX, m_isex); + DDX_Text(pDX, IDC_MESSAGE, m_message); + DDV_MaxChars(pDX, m_message, 1000); + DDX_Text(pDX, IDC_SFIRSTNAME, m_sfirstname); + DDV_MaxChars(pDX, m_sfirstname, 30); + DDX_Text(pDX, IDC_SNICK, m_snick); + DDV_MaxChars(pDX, m_snick, 30); + DDX_Text(pDX, IDC_SICQUIN, m_sicquin); + DDX_Text(pDX, IDC_SLASTNAME, m_slastname); + DDV_MaxChars(pDX, m_slastname, 30); + DDX_Text(pDX, IDC_SEMAIL, m_semail); + DDV_MaxChars(pDX, m_semail, 50); + DDX_Text(pDX, IDC_STRING, m_string); + DDX_Text(pDX, IDC_CODE, m_code); + DDX_Text(pDX, IDC_REASON, m_reason); + DDV_MaxChars(pDX, m_reason, 1024); + DDX_Radio(pDX, IDC_RNICK, m_rnick); + DDX_Check(pDX, IDC_INFO_CACHE, m_infoCache); + DDX_Check(pDX, IDC_BLOCKING, m_blocking); + DDX_Text(pDX, IDC_ILASTNAME, m_ilastname); + DDX_Text(pDX, IDC_IFIRSTNAME, m_ifirstname); + DDX_Text(pDX, IDC_IBIRTHDAY, m_ibirthday); + DDX_Text(pDX, IDC_IBIRTHMONTH, m_ibirthmonth); + DDX_Text(pDX, IDC_IBIRTHYEAR, m_ibirthyear); + DDX_Check(pDX, IDC_IPMBIRTHDAY, m_ipmbirthday); + DDX_Check(pDX, IDC_IPMCOUNTRYCODE, m_ipmcountrycode); + DDX_Check(pDX, IDC_IPMHOMEPAGE, m_ipmhomepage); + DDX_Check(pDX, IDC_IPMSEX, m_ipmsex); + DDX_Check(pDX, IDC_IPMZIPCODE, m_ipmzipcode); + DDX_Text(pDX, IDC_NEWNICK, m_newnick); + DDX_Check(pDX, IDC_REPLACE, m_replace); + DDX_Text(pDX, IDC_IZIPCODE, m_izipcode); + DDX_Text(pDX, IDC_INVITE_PLAYER_ID, m_invitePlayerID); + DDX_Radio(pDX, IDC_SAUTO, m_server); + DDX_Text(pDX, IDC_OTHER_SERVER, m_otherServer); + DDX_Text(pDX, IDC_NAME, m_name); + DDX_Text(pDX, IDC_PATH, m_path); + DDX_Text(pDX, IDC_SEARCH_SERVER, m_searchServer); + DDX_Check(pDX, IDC_IPMEMAIL, m_ipmemail); + DDX_Check(pDX, IDC_FIREWALL, m_firewall); + DDX_Text(pDX, IDC_ILATITUDE, m_ilatitude); + DDX_Text(pDX, IDC_IPLACE, m_iplace); + DDX_Text(pDX, IDC_ILONGITUDE, m_ilongitude); + DDX_Text(pDX, IDC_SUNIQUENICK, m_suniquenick); + DDV_MaxChars(pDX, m_suniquenick, 50); + DDX_Text(pDX, IDC_IUNIQUENICK, m_iuniquenick); + DDX_Text(pDX, IDC_UNIQUENICK, m_uniquenick); + DDV_MaxChars(pDX, m_uniquenick, 50); + DDX_Text(pDX, IDC_AUTHTOKEN, m_authtoken); + DDV_MaxChars(pDX, m_authtoken, 255); + DDX_Text(pDX, IDC_PARTNERCHALLENGE, m_partnerchallenge); + DDV_MaxChars(pDX, m_partnerchallenge, 255); + DDX_Text(pDX, IDC_NAMESPACE, m_namespace); + DDX_Text(pDX, IDC_PRODUCTID, m_productid); + //}}AFX_DATA_MAP + DDX_CBIndex(pDX, IDC_STATUS_STATE, m_StatusState); + DDX_Text(pDX, IDC_QPORT, m_QueryPort); + DDX_Text(pDX, IDC_HPORT, m_HostPort); + DDX_Control(pDX, IDC_SFLAGS, m_SessionFlags); + DDX_Text(pDX, IDC_RICH_STATUS, m_RichStatus); + DDX_Text(pDX, IDC_GAME_TYPE, m_GameType); + DDX_Text(pDX, IDC_GAME_VARIANT, m_GameVariant); + DDX_Text(pDX, IDC_GAME_MAPNAME, m_GameMapname); + DDX_Text(pDX, IDC_EDIT1, m_KeyName); + DDX_Text(pDX, IDC_EDIT2, m_KeyValue); + DDX_Text(pDX, IDC_HOST_IP, m_HostIp); + DDX_Text(pDX, IDC_HOST_PRIVATE_IP, m_HostPrivateIp); + DDX_Text(pDX, IDC_CDKEY, m_cdkey); + DDX_Control(pDX, IDC_BLOCKLIST, m_blocklist); + DDX_Control(pDX, IDC_GET_BLOCKEDLIST, m_getblockedlist); + DDX_Control(pDX, IDC_ADD_BLOCK, m_addblock); + DDX_Control(pDX, IDC_REMOVE_BLOCK, m_removeblock); +} + +BEGIN_MESSAGE_MAP(CGptestDlg, CDialog) + //{{AFX_MSG_MAP(CGptestDlg) + ON_WM_QUERYDRAGICON() + ON_WM_TIMER() + ON_BN_CLICKED(IDC_CONNECT, OnConnect) + ON_BN_CLICKED(IDC_DISCONNECT, OnDisconnect) + ON_WM_DESTROY() + ON_BN_CLICKED(IDC_SET, OnSet) + ON_LBN_SELCHANGE(IDC_BUDDIES, OnSelchangeBuddies) + ON_BN_CLICKED(IDC_SEND, OnSend) + ON_BN_CLICKED(IDC_REFRESH, OnRefresh) + ON_BN_CLICKED(IDC_UPDATE, OnUpdate) + ON_BN_CLICKED(IDC_SEARCH, OnSearch) + ON_LBN_SELCHANGE(IDC_RESULTS, OnSelchangeResults) + ON_BN_CLICKED(IDC_NEWUSER, OnNewuser) + ON_BN_CLICKED(IDC_SENDREQUEST, OnSendrequest) + ON_BN_CLICKED(IDC_INFO_CACHE, OnInfoCache) + ON_BN_CLICKED(IDC_DELETE, OnDelete) + ON_BN_CLICKED(IDC_SETINFO, OnSetinfo) + ON_BN_CLICKED(IDC_DELETEPRO, OnDeletepro) + ON_BN_CLICKED(IDC_NEWPRO, OnNewpro) + ON_BN_CLICKED(IDC_DELETEALL, OnDeleteall) + ON_BN_CLICKED(IDC_VALIDATE, OnValidate) + ON_BN_CLICKED(IDC_NICKS, OnNicks) + ON_BN_CLICKED(IDC_INVITE_PLAYER, OnInvitePlayer) + ON_BN_CLICKED(IDC_REPORT, OnReport) + ON_BN_CLICKED(IDC_CHECK, OnCheck) + ON_BN_CLICKED(IDC_SEND_FILES, OnSendFiles) + ON_EN_CHANGE(IDC_SEARCH_SERVER, OnChangeSearchServer) + ON_BN_CLICKED(IDC_PUBLICMASK_ALL, OnPublicmaskAll) + ON_BN_CLICKED(IDC_PUBLICMASK_NONE, OnPublicmaskNone) + ON_BN_CLICKED(IDC_REVOKE, OnRevoke) + ON_BN_CLICKED(IDC_SUGGEST, OnSuggest) + ON_BN_CLICKED(IDC_CONNECTUNIQUE, OnConnectunique) + ON_BN_CLICKED(IDC_CONNECTPREAUTH, OnConnectpreauth) + ON_BN_CLICKED(IDC_INITIALIZE, OnInitialize) + ON_BN_CLICKED(IDC_DESTROY, OnDestroyGP) + ON_WM_CREATE() + ON_BN_CLICKED(IDC_UTM, OnUTM) + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_SETSTATUSINFO, OnSetstatusinfo) + ON_BN_CLICKED(IDC_BUTTON2, OnAddSetKey) + ON_BN_CLICKED(IDC_BUTTON4, OnGetKeyValue) + ON_BN_CLICKED(IDC_BUTTON5, OnGetBuddyKeys) + ON_BN_CLICKED(IDC_BUTTON3, OnDelKeyVal) + ON_BN_CLICKED(IDC_REGISTER_CDKEY, OnRegisterCdKey) + ON_BN_CLICKED(IDC_GET_BLOCKEDLIST, OnGetBlocked) + ON_LBN_SELCHANGE(IDC_BLOCKLIST, OnSelchangeBlocklist) + ON_BN_CLICKED(IDC_ADD_BLOCK, OnAddBlock) + ON_BN_CLICKED(IDC_REMOVE_BLOCK, OnRemoveBlock) +END_MESSAGE_MAP() + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CGptestDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +//GP CALLBACKS +////////////// +void ConnectResponse(GPConnection * connection, void * arg_, void * param) +{ + GPConnectResponseArg * arg = (GPConnectResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + dlg->m_StatusState = dlg->m_status = GP_ONLINE; + dlg->m_statusString = "Online"; + dlg->m_locationString = ""; + + dlg->m_uniquenick = arg->uniquenick; + //dlg->m_RichStatus = "Online"; + dlg->UpdateData(FALSE); + + gpSetStatus(connection, (GPEnum)dlg->m_status, dlg->m_statusString, dlg->m_locationString); + //gpSetStatusInfo(connection, (GPEnum)dlg->m_StatusState, 0, 0, 0, 0, 0, dlg->m_RichStatus, dlg->m_RichStatus.GetLength(), "", 0, "", 0, "", 0); + CString text; + text.Format("Connected as profileid %d\r\n", arg->profile); + OutputDebugString((LPCSTR)text); + } + else + { + dlg->MessageBox("Connect failed"); + } + GSI_UNUSED(param); +} + +void CheckResponse(GPConnection * connection, void * arg_, void * param) +{ + GPCheckResponseArg * arg = (GPCheckResponseArg *)arg_; + + CString strMessage; + char buf[16]; + + strMessage.Format("%s@%s (%s)\n", dlg->m_nick, dlg->m_email, dlg->m_password); + + if(arg->result == GP_NO_ERROR) + { + strMessage += "pid = "; + itoa(arg->profile, buf, 10); + strMessage += buf; + } + else + { + GPErrorCode errorCode; + gpGetErrorCode(connection, &errorCode); + if(errorCode == GP_CHECK_BAD_EMAIL) + strMessage += "Invalid e-mail"; + else if(errorCode == GP_CHECK_BAD_PASSWORD) + strMessage += "Invalid password"; + else if(errorCode == GP_CHECK_BAD_NICK) + strMessage += "Invalid nick"; + } + + dlg->MessageBox(strMessage); + GSI_UNUSED(param); +} + +void NewUserResponse(GPConnection * connection, void * arg_, void * param) +{ + GPNewUserResponseArg * arg = (GPNewUserResponseArg *)arg_; + + CString strMessage; + char buf[16]; + + if(arg->result == GP_NO_ERROR) + { + strMessage = "Success\n"; + + strMessage += "pid = "; + itoa(arg->profile, buf, 10); + strMessage += buf; + } + else + { + strMessage += "Error\n"; + + GPErrorCode errorCode; + gpGetErrorCode(connection, &errorCode); + if(errorCode == GP_NEWUSER_BAD_PASSWORD) + strMessage += "Invalid password"; + else if(errorCode == GP_NEWUSER_BAD_NICK) + { + strMessage += "Profile already exists: "; + itoa(arg->profile, buf, 10); + strMessage += buf; + } + else if(errorCode == GP_NEWUSER_UNIQUENICK_INUSE) + strMessage += "Uniquenick in use"; + else if(errorCode == GP_NEWUSER_UNIQUENICK_INVALID) + strMessage += "Uniquenick invalid"; + } + + dlg->MessageBox(strMessage, "New User"); + GSI_UNUSED(param); +} + +void RecvBuddyStatus(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyStatusArg * arg = (GPRecvBuddyStatusArg *)arg_; + GPBuddyStatus status; + + char intValue[16]; + int index; + CString string; + int i; + int count; + bool online; + static int onlinecount; + + //CHECK(gpGetBuddyStatusInfo(connection, arg->index, &status)); + CHECK(gpGetBuddyStatus(connection, arg->index, &status)); + + if(status.status == GP_ONLINE) + { + string = "ON:"; + online = true; + } + sprintf(intValue, "%04d", arg->profile); + string += intValue; + + count = dlg->m_buddies.GetCount(); + for(i = 0 ; i < count ; i++) + if(dlg->m_buddies.GetItemData(i) == (DWORD)arg->profile) + dlg->m_buddies.DeleteString(i); + + CString text; + count = dlg->m_buddies.GetCount(); + for(i = 0 ; i < count ; i++) + { + dlg->m_buddies.GetText(i, text); + if(text.Left(3).Compare("ON:") != 0) + break; + } + index = dlg->m_buddies.InsertString(i, string); + dlg->m_buddies.SetItemData(index, (DWORD)arg->profile); + GSI_UNUSED(param); +} + +void GetInfoResponse(GPConnection * connection, void * arg_, void * param) +{ + GPGetInfoResponseArg * arg = (GPGetInfoResponseArg *)arg_; + + int index; + //GPBuddyStatusInfo statusInfo; + GPBuddyStatus status; + IN_ADDR addr; + char intValue[16]; + addr.s_addr = 0; + if(arg->result == GP_NO_ERROR) + { + // Get this guy's buddy status. + /////////////////////////////// + if(arg->profile) + { + gpGetBuddyIndex(&dlg->m_connection, arg->profile, &index); + if(index != -1) + { + //gpGetBuddyStatusInfo(&dlg->m_connection, index, &statusInfo); + gpGetBuddyStatus(&dlg->m_connection, index, &status); + //addr.S_un.S_addr = statusInfo.buddyIp; + addr.S_un.S_addr = status.ip; + } + } + else + { + index = -1; + } + + // Set the stuff. + ///////////////// + dlg->UpdateData(); + dlg->m_ifirstname = arg->firstname; + dlg->m_ilastname = arg->lastname; + dlg->m_inick = arg->nick; + dlg->m_iuniquenick = arg->uniquenick; + dlg->m_iemail = arg->email; + dlg->m_iicquin = arg->icquin; + dlg->m_ihomepage = arg->homepage; + dlg->m_ibirthday = arg->birthday; + dlg->m_ibirthmonth = arg->birthmonth; + dlg->m_ibirthyear = arg->birthyear; + dlg->m_isex = (arg->sex == GP_MALE)?"Male":((arg->sex == GP_FEMALE)?"Female":"Pat"); + dlg->m_icountrycode = arg->countrycode; + dlg->m_izipcode = arg->zipcode; + dlg->m_ilongitude = arg->longitude; + dlg->m_ilatitude = arg->latitude; + dlg->m_iplace = arg->place; + dlg->m_ipmhomepage = (arg->publicmask & GP_MASK_HOMEPAGE)?TRUE:FALSE; + dlg->m_ipmzipcode = (arg->publicmask & GP_MASK_ZIPCODE)?TRUE:FALSE; + dlg->m_ipmcountrycode = (arg->publicmask & GP_MASK_COUNTRYCODE)?TRUE:FALSE; + dlg->m_ipmbirthday = (arg->publicmask & GP_MASK_BIRTHDAY)?TRUE:FALSE; + dlg->m_ipmsex = (arg->publicmask & GP_MASK_SEX)?TRUE:FALSE; + dlg->m_ipmemail = (arg->publicmask & GP_MASK_EMAIL)?TRUE:FALSE; + if(index != -1) + { + dlg->m_iaddress = inet_ntoa(addr); + dlg->m_iaddress += ":"; + //itoa(statusInfo.buddyPort, intValue, 10); + itoa(status.port, intValue, 10); + dlg->m_iaddress += intValue; + dlg->m_status = status.status; + dlg->m_statusString = status.statusString; + dlg->m_locationString = status.locationString; + + /* + dlg->m_StatusState = statusInfo.statusState; + dlg->m_RichStatus = statusInfo.richStatus; + dlg->m_GameType = statusInfo.gameType; + dlg->m_GameVariant = statusInfo.gameVariant; + dlg->m_GameMapname = statusInfo.gameMapName; + addr.s_addr = statusInfo.hostIp; + dlg->m_HostIp = inet_ntoa(addr); + addr.s_addr = statusInfo.hostPrivateIp; + dlg->m_HostPrivateIp = inet_ntoa(addr); + dlg->m_HostPort = statusInfo.hostPort; + dlg->m_QueryPort = statusInfo.queryPort; + + for (int i = 0; i < dlg->m_SessionFlags.GetCount(); i++) + { + int flag = dlg->m_SessionFlags.GetItemData(i); + if (statusInfo.sessionFlags & flag) + dlg->m_SessionFlags.SetSel(i, TRUE); + else + dlg->m_SessionFlags.SetSel(i, FALSE); + } + */ + } + else + { + dlg->m_iaddress = ""; + dlg->m_StatusState = 0; + //dlg->m_statusString = ""; + //dlg->m_locationString = ""; + + dlg->m_RichStatus = ""; + dlg->m_GameType = ""; + dlg->m_GameVariant = ""; + dlg->m_GameMapname = ""; + dlg->m_HostIp = "0.0.0.0"; + dlg->m_HostPrivateIp = "0.0.0.0"; + dlg->m_HostPort = 0; + dlg->m_QueryPort = 0; + + for (int i=0; i < dlg->m_SessionFlags.GetCount(); i++) + dlg->m_SessionFlags.SetSel(0, FALSE); + + } + dlg->UpdateData(FALSE); + } + else + { + dlg->MessageBox("GetInfo failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void Error(GPConnection * connection, void * arg_, void * param) +{ + GPErrorArg * arg = (GPErrorArg *)arg_; + + if(arg->fatal == GP_FATAL) + { + MessageBox(NULL, arg->errorString, "Fatal Error", MB_OK | MB_ICONERROR | MB_APPLMODAL); + } + else + { + MessageBox(NULL, arg->errorString, "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +char whois[128]; + +void Whois(GPConnection * connection, void * arg_, void * param) +{ + GPGetInfoResponseArg * arg = (GPGetInfoResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + dlg->UpdateData(); + switch(dlg->m_rnick) + { + // Nick. + //////// + case 0: + strcpy(whois, arg->nick); + break; + // Name. + //////// + case 1: + strcpy(whois, arg->firstname); + strcat(whois, " "); + strcat(whois, arg->lastname); + break; + // Email. + ///////// + case 2: + strcpy(whois, arg->email); + break; + } + } + else + { + dlg->MessageBox("Whois failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvBuddyMessage(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyMessageArg * arg = (GPRecvBuddyMessageArg *)arg_; + + dlg->UpdateData(); + gpGetInfo(connection, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, Whois, NULL); + + char msg[4096]; + sprintf(msg, "%s: %s", whois, arg->message); + char * str = gsiSecondsToString((time_t *)&arg->date); + char date[256]; + strcpy(date, str); + date[strlen(str) - 1] = '\0'; + +#if 0 + OutputDebugString(msg); + OutputDebugString("\n"); +#else + if(MessageBox(NULL, msg, date, MB_YESNO | MB_APPLMODAL) == IDYES) + { + gpSendBuddyMessage(connection, arg->profile, "Thanks for the message!"); + } +#endif + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvBuddyUTM(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyUTMArg * arg = (GPRecvBuddyUTMArg *)arg_; + + dlg->UpdateData(); + gpGetInfo(connection, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, Whois, NULL); + + char msg[4096]; + sprintf(msg, "[UTM] %s: %s", whois, arg->message); + char * str = gsiSecondsToString((time_t *)&arg->date); + char date[256]; + strcpy(date, str); + date[strlen(str) - 1] = '\0'; + +#if 0 + OutputDebugString(msg); + OutputDebugString("\n"); +#else + if(MessageBox(NULL, msg, date, MB_YESNO | MB_APPLMODAL) == IDYES) + { + char* message = "Thanks for the message!"; + gpSendBuddyUTM(connection, arg->profile, message, 0); + } +#endif + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvBuddyRevoke(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyRevokeArg * arg = (GPRecvBuddyRevokeArg *)arg_; + + dlg->UpdateData(); + + if (gpIsBuddy(connection, arg->profile)) + { + char * str = gsiSecondsToString((time_t *)&arg->date); + char date[256]; + strcpy(date, str); + date[strlen(str) - 1] = '\0'; + + CString message; + message.Format("User %d has revoked their buddy authorization.", arg->profile); + MessageBox(NULL, (LPCSTR)message, date, MB_OK); + + // Remove them from the UI list + int index = 0; + while (index < dlg->m_buddies.GetCount()) + { + GPProfile profile = (GPProfile)dlg->m_buddies.GetItemData(index); + if (profile == arg->profile) + { + dlg->m_buddies.DeleteString(index); + break; + } + index++; + } + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +GPProfileSearchMatch searchMatches[100]; + +void ProfileSearchResponse(GPConnection * connection, void * arg_, void * param) +{ + GPProfileSearchResponseArg * arg = (GPProfileSearchResponseArg *)arg_; + + // Check the results. + ///////////////////// + if(arg->result == GP_NO_ERROR) + { + // Loop through the matches. + //////////////////////////// + for(int i = 0 ; (i < arg->numMatches) && (i < (sizeof(searchMatches) / sizeof(searchMatches[0]))) ; i++) + { + // Add it to the list. + ////////////////////// + dlg->m_results.InsertString(i, arg->matches[i].nick); + dlg->m_results.SetItemData(i, (DWORD)arg->matches[i].profile); + // Save the match. + ////////////////// + memcpy(&searchMatches[i], &arg->matches[i], sizeof(GPProfileSearchMatch)); + } + + if(arg->more == GP_MORE) + { + if(dlg->MessageBox("More search results?", "Profile Search", MB_YESNO | MB_TASKMODAL) == IDNO) + { + arg->more = GP_DONE; + } + } + } + else + { + dlg->MessageBox("ProfileSearch failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvBuddyRequest(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyRequestArg * arg = (GPRecvBuddyRequestArg *)arg_; + + // Show who the buddy request is from. + // PANTS|05.18.00 + ////////////////////////////////////// + gpGetInfo(connection, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, Whois, NULL); + CString message = "Buddy Request from "; + message += whois; + if(MessageBox(dlg->m_hWnd, arg->reason, message, MB_YESNO) == IDYES) + gpAuthBuddyRequest(connection, arg->profile); + else + gpDenyBuddyRequest(connection, arg->profile); + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvBuddyAuth(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyAuthArg * arg = (GPRecvBuddyAuthArg *)arg_; + dlg->UpdateData(); + + gpGetInfo(connection, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, Whois, NULL); + + CString msg_for_requester = whois; + msg_for_requester += ": Yo man, joo on ma buddy list"; + MessageBox(dlg->m_hWnd, msg_for_requester, "Received Buddy Auth", MB_ICONINFORMATION); + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void NewProfileResponse(GPConnection * connection, void * arg_, void * param) +{ + GPNewProfileResponseArg * arg = (GPNewProfileResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + dlg->MessageBox("New profile created"); + } + else + { + dlg->MessageBox("NewProfile failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void IsValidEmailResponse(GPConnection * connection, void * arg_, void * param) +{ + char buffer[128]; + GPIsValidEmailResponseArg * arg = (GPIsValidEmailResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + if(arg->isValid) + sprintf(buffer, "%s is a valid e-mail address.", arg->email); + else + sprintf(buffer, "%s is NOT a valid e-mail address.", arg->email); + } + else + { + sprintf(buffer, "IsValidEmail failed"); + } + + dlg->MessageBox(buffer); + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void GetUserNicksResponse(GPConnection * connection, void * arg_, void * param) +{ + GPGetUserNicksResponseArg * arg = (GPGetUserNicksResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + int i; + for(i = 0 ; i < arg->numNicks ; i++) + { + dlg->m_results.InsertString(i, arg->nicks[i]); + dlg->m_results.SetItemData(i, 0); + memset(&searchMatches[i], 0, sizeof(GPProfileSearchMatch)); + strcpy(searchMatches[i].nick, arg->nicks[i]); + strcpy(searchMatches[i].uniquenick, arg->uniquenicks[i]); + } + } + else + { + dlg->MessageBox("GetUserNicksResponse failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void SuggestUniqueNickResponse(GPConnection * connection, void * arg_, void * param) +{ + GPSuggestUniqueNickResponseArg * arg = (GPSuggestUniqueNickResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + int i; + for(i = 0 ; i < arg->numSuggestedNicks ; i++) + { + dlg->m_results.InsertString(i, arg->suggestedNicks[i]); + dlg->m_results.SetItemData(i, 0); + // don't get info for this one + searchMatches[i].profile = -1; + } + } + else + { + dlg->MessageBox("GetUserNicksResponse failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void GetReverseBuddiesResponse(GPConnection * connection, void * arg_, void * param) +{ + GPGetReverseBuddiesResponseArg * arg = (GPGetReverseBuddiesResponseArg *)arg_; + + if(arg->result == GP_NO_ERROR) + { + int i; + CString str; + int rcode; + GPProfileSearchMatch * match; + + for(i = 0 ; i < arg->numProfiles ; i++) + { + match = &arg->profiles[i]; + + str.Format("Revoke %s [%s] (%s %s, %s, %d)?", match->nick, match->uniquenick, match->firstname, match->lastname, match->email, match->profile); + rcode = dlg->MessageBox(str, NULL, MB_YESNOCANCEL); + if(rcode == IDYES) + gpRevokeBuddyAuthorization(connection, match->profile); + else if(rcode == IDCANCEL) + break; + } + } + else + { + dlg->MessageBox("GetReverseBuddiesResponse failed"); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvGameInvite(GPConnection * connection, void * arg_, void * param) +{ + GPRecvGameInviteArg * arg = (GPRecvGameInviteArg *)arg_; + + gpGetInfo(connection, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, Whois, NULL); + + char msg[4096]; + sprintf(msg, "%s has invited you to play the game with product ID %d", whois, arg->productID); + + dlg->MessageBox(msg); + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void GetInfoForBuddyKeys(GPConnection * theConnection, void * theArg, void * theParam) +{ + GPGetInfoResponseArg *anArg = (GPGetInfoResponseArg *)theArg; + GPGetInfoResponseArg **anInfoArg = (GPGetInfoResponseArg **)theParam; + + memcpy(*anInfoArg,anArg, sizeof(GPGetInfoResponseArg)); + GSI_UNUSED(theConnection); +} + +void GetBuddyKeysCallback(GPConnection * theConnection, void * theArg, void * theParam) +{ + GPGetBuddyStatusInfoKeysArg *anArg = (GPGetBuddyStatusInfoKeysArg *)theArg; + GPGetInfoResponseArg *anInfoArg = new GPGetInfoResponseArg; + gpGetInfo(theConnection, anArg->profile, GP_CHECK_CACHE, GP_BLOCKING, GetInfoForBuddyKeys, (void *)&anInfoArg); + + CString aUniqueNick = anInfoArg->uniquenick; + CString aBuddyeKeys = ""; + + for (int i = 0; i < anArg->numKeys; i++) + { + if (i == 0) + { + aBuddyeKeys += anArg->keys[i]; + aBuddyeKeys += " = "; + aBuddyeKeys += anArg->values[i]; + } + else + { + aBuddyeKeys += "\n"; + aBuddyeKeys += anArg->keys[i]; + aBuddyeKeys += " = "; + aBuddyeKeys += anArg->values[i]; + } + } + + CString aMessage = "Buddy: " + aUniqueNick; + aMessage += "\n"; + aMessage += aBuddyeKeys; + + dlg->MessageBox(aMessage, "Buddy Keys"); + delete anInfoArg; + GSI_UNUSED(theParam); +} + +void RegisterCdKeyCallback(GPConnection * connection, void * _arg, void * param) +{ + GPRegisterCdKeyResponseArg *arg = (GPRegisterCdKeyResponseArg *)_arg; + + if (arg->result == GP_NO_ERROR) + { + CString msg = "CDKey is now associated with your account"; + dlg->MessageBox(msg); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +LPCSTR TypeToString(GPEnum type) +{ + switch(type) + { + case GP_TRANSFER_SEND_REQUEST: + return "GP_TRANSFER_SEND_REQUEST"; + case GP_TRANSFER_ACCEPTED: + return "GP_TRANSFER_ACCEPTED"; + case GP_TRANSFER_REJECTED: + return "GP_TRANSFER_REJECTED"; + case GP_TRANSFER_NOT_ACCEPTING: + return "GP_TRANSFER_NOT_ACCEPTING"; + case GP_TRANSFER_NO_CONNECTION: + return "GP_TRANSFER_NO_CONNECTION"; + case GP_TRANSFER_DONE: + return "GP_TRANSFER_DONE"; + case GP_TRANSFER_CANCELLED: + return "GP_TRANSFER_CANCELLED"; + case GP_TRANSFER_LOST_CONNECTION: + return "GP_TRANSFER_LOST_CONNECTION"; + case GP_TRANSFER_ERROR: + return "GP_TRANSFER_ERROR"; + case GP_TRANSFER_THROTTLE: + return "GP_TRANSFER_THROTTLE"; + case GP_FILE_BEGIN: + return "GP_FILE_BEGIN"; + case GP_FILE_PROGRESS: + return "GP_FILE_PROGRESS"; + case GP_FILE_END: + return "GP_FILE_END"; + case GP_FILE_DIRECTORY: + return "GP_FILE_DIRECTORY"; + case GP_FILE_SKIP: + return "GP_FILE_SKIP"; + case GP_FILE_FAILED: + return "GP_FILE_FAILED"; + } + + return "!!!!!!!BAD TYPE!!!!!!!"; +} + +void TransferCallback(GPConnection * connection, void * arg_, void * param) +{ + GPTransferCallbackArg * arg = (GPTransferCallbackArg *)arg_; + static DWORD transferStart; + char * name; + char * path; + GPEnum side; + + CString str; + str.Format("%s - %d - %d - %s\n", TypeToString(arg->type), arg->index, arg->num, arg->message); + OutputDebugString(str); + + switch(arg->type) + { + case GP_TRANSFER_SEND_REQUEST: + transferStart = GetTickCount(); + CHECK(gpAcceptTransfer(connection, arg->transfer, "I'd like your file")); + break; + + case GP_FILE_END: + gpGetTransferSide(connection, arg->transfer, &side); + if(side == GP_TRANSFER_RECEIVER) + { + gpGetFileName(connection, arg->transfer, arg->index, &name); + gpGetFilePath(connection, arg->transfer, arg->index, &path); + rename(path, "file.ext"); + } + break; + + case GP_TRANSFER_REJECTED: + case GP_TRANSFER_NOT_ACCEPTING: + case GP_TRANSFER_NO_CONNECTION: + case GP_TRANSFER_DONE: + case GP_TRANSFER_CANCELLED: + case GP_TRANSFER_LOST_CONNECTION: + case GP_TRANSFER_ERROR: + gpFreeTransfer(connection, arg->transfer); + break; + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +// Utility func for converting an error code to a string. +///////////////////////////////////////////////////////// +#define CtoS(code) case code: string += " (" #code ")"; return; +void CGptestDlg::CodeToString(CString & string) +{ + GPErrorCode code; + gpGetErrorCode(&m_connection, &code); + + switch(code) + { + CtoS(GP_GENERAL) + CtoS(GP_PARSE) + CtoS(GP_NOT_LOGGED_IN) + CtoS(GP_BAD_SESSKEY) + CtoS(GP_DATABASE) + CtoS(GP_NETWORK) + CtoS(GP_FORCED_DISCONNECT) + CtoS(GP_CONNECTION_CLOSED) + CtoS(GP_LOGIN) + CtoS(GP_LOGIN_TIMEOUT) + CtoS(GP_LOGIN_BAD_NICK) + CtoS(GP_LOGIN_BAD_EMAIL) + CtoS(GP_LOGIN_BAD_PASSWORD) + CtoS(GP_LOGIN_BAD_PROFILE) + CtoS(GP_LOGIN_PROFILE_DELETED) + CtoS(GP_LOGIN_CONNECTION_FAILED) + CtoS(GP_LOGIN_SERVER_AUTH_FAILED) + CtoS(GP_LOGIN_BAD_UNIQUENICK) + CtoS(GP_LOGIN_BAD_PREAUTH) + CtoS(GP_NEWUSER) + CtoS(GP_NEWUSER_BAD_NICK) + CtoS(GP_NEWUSER_BAD_PASSWORD) + CtoS(GP_NEWUSER_UNIQUENICK_INVALID) + CtoS(GP_NEWUSER_UNIQUENICK_INUSE) + CtoS(GP_UPDATEUI) + CtoS(GP_UPDATEUI_BAD_EMAIL) + CtoS(GP_NEWPROFILE) + CtoS(GP_NEWPROFILE_BAD_NICK) + CtoS(GP_NEWPROFILE_BAD_OLD_NICK) + CtoS(GP_UPDATEPRO) + CtoS(GP_UPDATEPRO_BAD_NICK) + CtoS(GP_ADDBUDDY) + CtoS(GP_ADDBUDDY_BAD_FROM) + CtoS(GP_ADDBUDDY_BAD_NEW) + CtoS(GP_ADDBUDDY_ALREADY_BUDDY) + CtoS(GP_AUTHADD) + CtoS(GP_AUTHADD_BAD_FROM) + CtoS(GP_AUTHADD_BAD_SIG) + CtoS(GP_STATUS) + CtoS(GP_BM) + CtoS(GP_BM_NOT_BUDDY) + CtoS(GP_GETPROFILE) + CtoS(GP_GETPROFILE_BAD_PROFILE) + CtoS(GP_DELBUDDY) + CtoS(GP_DELBUDDY_NOT_BUDDY) + CtoS(GP_DELPROFILE) + CtoS(GP_DELPROFILE_LAST_PROFILE) + CtoS(GP_SEARCH) + CtoS(GP_SEARCH_CONNECTION_FAILED) + CtoS(GP_CHECK) + CtoS(GP_CHECK_BAD_EMAIL) + CtoS(GP_CHECK_BAD_NICK) + CtoS(GP_CHECK_BAD_PASSWORD) + CtoS(GP_REGISTERUNIQUENICK) + CtoS(GP_REGISTERUNIQUENICK_TAKEN) + CtoS(GP_REGISTERUNIQUENICK_RESERVED) + CtoS(GP_REGISTERUNIQUENICK_BAD_NAMESPACE) + CtoS(GP_REGISTERCDKEY_BAD_KEY) + CtoS(GP_REGISTERCDKEY_ALREADY_SET) + CtoS(GP_REGISTERCDKEY_ALREADY_TAKEN) + } + + string += " (XXXUNKOWNXXX)"; + return; +} + +///////////////////////////////////////////////////////////////////////////// +// CGptestDlg message handlers + +CString GPServerDefault; +CString GPSearchServerDefault; + +BOOL CGptestDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + dlg = this; + m_connection = NULL; + + GPServerDefault = GPConnectionManagerHostname; + GPSearchServerDefault = GPSearchManagerHostname; + + UpdateData(); + + CString str = "Closed"; + m_SessionFlags.InsertString(0, str); + m_SessionFlags.SetItemData(0, GP_SESS_IS_CLOSED); + + str = "Open"; + m_SessionFlags.InsertString(1, str); + m_SessionFlags.SetItemData(1, GP_SESS_IS_OPEN); + + str = "Has Password"; + m_SessionFlags.InsertString(2, str); + m_SessionFlags.SetItemData(2, GP_SESS_HAS_PASSWORD); + + str = "Behind NAT"; + m_SessionFlags.InsertString(3, str); + m_SessionFlags.SetItemData(3, GP_SESS_IS_BEHIND_NAT); + + str = "Ranked"; + m_SessionFlags.InsertString(4, str); + m_SessionFlags.SetItemData(4, GP_SESS_IS_RANKED); + + SetTimer(1, PROCESS_TIME, NULL); + SetTimer(2, 500, NULL); + + m_namespace.Format("%d", GSI_DEFAULT_NAMESPACE); + m_productid = GSI_TEST_PRODUCTID; + + UpdateData(FALSE); + FILE * file; + file = fopen("login.txt", "rt"); + if(file) + { + char buffer[256]; + if(fgets(buffer, sizeof(buffer), file)) + { + m_email = buffer; + m_email.Remove('\n'); + } + if(fgets(buffer, sizeof(buffer), file)) + { + m_nick = buffer; + m_nick.Remove('\n'); + } + if(fgets(buffer, sizeof(buffer), file)) + { + m_password = buffer; + m_password.Remove('\n'); + } + if(fgets(buffer, sizeof(buffer), file)) + { + m_uniquenick = buffer; + m_uniquenick.Remove('\n'); + } + fclose(file); + } + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CGptestDlg::OnDestroy() +{ + if(m_connection) + OnDestroyGP(); + + UpdateData(); + FILE * file; + file = fopen("login.txt", "wt"); + if(file) + { + fprintf(file, "%s\n%s\n%s\n%s", m_email, m_nick, m_password, m_uniquenick); + fclose(file); + } + + CDialog::OnDestroy(); +} + +void CGptestDlg::OnInitialize() +{ + if(m_connection) + { + MessageBox("GP is already initialized"); + return; + } + + +#ifdef GSI_COMMON_DEBUG + // Define GSI_COMMON_DEBUG if you want to view the SDK debug output + // Set the SDK debug log file, or set your own handler using gsSetDebugCallback + gsSetDebugCallback(DebugCallback); + + // Set some debug levels + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Debug); +#endif + + // check that the game's backend is available + GSIACResult result; + GSIStartAvailableCheck(GSI_TEST_GAMENAME); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + MessageBox("The backend is not available\n"); + return; + } + + UpdateData(); + + if(m_namespace.IsEmpty() || !isdigit(m_namespace.GetAt(0))) + { + MessageBox("Enter a namespace of 0 or greater"); + return; + } + + CHECK(gpInitialize(&m_connection, m_productid, atoi(m_namespace), m_partnerid)); + CHECK(gpSetCallback(&m_connection, GP_RECV_BUDDY_STATUS, RecvBuddyStatus, NULL)); + CHECK(gpSetCallback(&m_connection, GP_RECV_BUDDY_AUTH, RecvBuddyAuth, NULL)); + CHECK(gpSetCallback(&m_connection, GP_ERROR, Error, NULL)); + CHECK(gpSetCallback(&m_connection, GP_RECV_BUDDY_MESSAGE, RecvBuddyMessage, NULL)); + CHECK(gpSetCallback(&m_connection, GP_RECV_BUDDY_REQUEST, RecvBuddyRequest, NULL)); + CHECK(gpSetCallback(&m_connection, GP_RECV_GAME_INVITE, RecvGameInvite, NULL)); + CHECK(gpSetCallback(&m_connection, GP_TRANSFER_CALLBACK, TransferCallback, NULL)); + CHECK(gpSetCallback(&m_connection, GP_RECV_BUDDY_UTM, RecvBuddyUTM, NULL)); + CHECK(gpSetCallback(&m_connection, GP_RECV_BUDDY_REVOKE, RecvBuddyRevoke, NULL)); +} + +void CGptestDlg::OnDestroyGP() +{ + if(!m_connection) + return; + + gpDestroy(&m_connection); + m_connection = NULL; +} + +void CGptestDlg::SetHost() +{ + if(m_server == 0) + strcpy(GPConnectionManagerHostname, GPServerDefault); + else if(m_server == 1) + strcpy(GPConnectionManagerHostname, "aphexgp1"); + else if(m_server == 2) + strcpy(GPConnectionManagerHostname, "aphexgp2"); +#if 0 + else if(m_server == 3) + strcpy(GPConnectionManagerHostname, "aphexapp3"); + else if(m_server == 4) + strcpy(GPConnectionManagerHostname, "aphexapp4"); + else if(m_server == 5) + strcpy(GPConnectionManagerHostname, "chat3"); + else if(m_server == 6) + strcpy(GPConnectionManagerHostname, "chat4"); +#endif + else if(m_server == 7) + strcpy(GPConnectionManagerHostname, "localhost"); + else if(m_server == 8) + strcpy(GPConnectionManagerHostname, m_otherServer); +} + +void CGptestDlg::OnConnect() +{ + if(!m_connection) + return; + + UpdateData(); + + // Set which server to use. + /////////////////////////// + SetHost(); + CHECK(gpConnect(&m_connection, m_nick, m_email, m_password, (GPEnum)m_firewall, (GPEnum)m_blocking, ConnectResponse, NULL)); +} + +void CGptestDlg::OnConnectunique() +{ + if(!m_connection) + return; + + UpdateData(); + + // Set which server to use. + /////////////////////////// + SetHost(); + + CHECK(gpConnectUniqueNick(&m_connection, m_uniquenick, m_password, (GPEnum)m_firewall, (GPEnum)m_blocking, ConnectResponse, NULL)); +} + +void CGptestDlg::OnConnectpreauth() +{ + if(!m_connection) + return; + + UpdateData(); + + // Set which server to use. + /////////////////////////// + SetHost(); + + CHECK(gpConnectPreAuthenticated(&m_connection, m_authtoken, m_partnerchallenge, (GPEnum)m_firewall, (GPEnum)m_blocking, ConnectResponse, NULL)); +} + +void CGptestDlg::OnDisconnect() +{ + if(!m_connection) + return; + + gpDisconnect(&m_connection); + + m_buddies.ResetContent(); +} + +void CGptestDlg::OnCheck() +{ + if(!m_connection) + return; + + UpdateData(); + CHECK(gpCheckUser(&m_connection, m_nick, m_email, m_password, (GPEnum)m_blocking, CheckResponse, NULL)); +} + +void CGptestDlg::OnNewuser() +{ + if(!m_connection) + return; + + UpdateData(); + SetHost(); +CHECK(gpNewUser(&m_connection, m_nick, m_uniquenick, m_email, m_password, NULL, (GPEnum)m_blocking, NewUserResponse, NULL)); +// CHECK(gpConnectNewUser(&m_connection, m_nick, m_uniquenick, m_email, m_password, NULL, (GPEnum)m_firewall, (GPEnum)m_blocking, ConnectResponse, NULL)); +} + +void CGptestDlg::OnUpdate() +{ + if(!m_connection) + return; + + // Update some info. + //////////////////// + UpdateData(); + CHECK(gpSetInfos(&m_connection, GP_EMAIL, m_email)); + CHECK(gpSetInfos(&m_connection, GP_NICK, m_nick)); + CHECK(gpSetInfos(&m_connection, GP_PASSWORD, m_password)); + CHECK(gpSetInfos(&m_connection, GP_UNIQUENICK, m_uniquenick)); +} + + +void CGptestDlg::OnTimer(UINT nIDEvent) +{ + if(!m_connection) + return; + + if (m_InTimer == 1) + return; + m_InTimer = 1; + + if(nIDEvent == 1) + { + CHECK(gpProcess(&m_connection)); + } + + if(nIDEvent == 2) + { + char buffer[256]; + GPErrorCode code; + + UpdateData(); + gpGetErrorCode(&m_connection, &code); + sprintf(buffer, "0x%04X", code); + m_code = buffer; + CodeToString(m_code); + gpGetErrorString(&m_connection, buffer); + m_string = buffer; + UpdateData(FALSE); + } + + CDialog::OnTimer(nIDEvent); + + m_InTimer = 0; +} + +void CGptestDlg::OnSelchangeBuddies() +{ + if(!m_connection) + return; + + // Get the profile for this item. + ///////////////////////////////// + int index = m_buddies.GetCurSel(); + UpdateData(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Get the info on this buddy. + ////////////////////////////// + if(profile != -1) + CHECK(gpGetInfo(&m_connection, profile, GP_CHECK_CACHE, (GPEnum)m_blocking, GetInfoResponse, NULL)); + } +} + +void CGptestDlg::OnSet() +{ + if(!m_connection) + return; + + UpdateData(); + + CHECK(gpSetStatus(&m_connection, (GPEnum)m_status, m_statusString, m_locationString)); +} + +void CGptestDlg::OnSend() +{ + if(!m_connection) + return; + + int index = m_buddies.GetCurSel(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Send a message to this guy. + ////////////////////////////// + UpdateData(); + CHECK(gpSendBuddyMessage(&m_connection, profile, m_message)); + } +} + +void CGptestDlg::OnRefresh() +{ + if(!m_connection) + return; + + // Get the profile for this item. + ///////////////////////////////// + int index = m_buddies.GetCurSel(); + UpdateData(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Get the info on this buddy. + ////////////////////////////// + CHECK(gpGetInfo(&m_connection, profile, GP_DONT_CHECK_CACHE, (GPEnum)m_blocking, GetInfoResponse, NULL)); + } +} + +void CGptestDlg::OnSearch() +{ + if(!m_connection) + return; + + // Search. + ////////// + UpdateData(); + dlg->m_results.ResetContent(); + CHECK(gpProfileSearch(&m_connection, m_snick, m_suniquenick, m_semail, m_sfirstname, m_slastname, m_sicquin, (GPEnum)m_blocking, ProfileSearchResponse, NULL)); +} + +void CGptestDlg::OnValidate() +{ + if(!m_connection) + return; + + UpdateData(); + CHECK(gpIsValidEmail(&m_connection, m_semail, (GPEnum)m_blocking, IsValidEmailResponse, NULL)); +} + +void CGptestDlg::OnNicks() +{ + if(!m_connection) + return; + + UpdateData(); + if(m_semail.IsEmpty()) + { + MessageBox("Type in an email for which to find nicks"); + return; + } + dlg->m_results.ResetContent(); + CHECK(gpGetUserNicks(&m_connection, m_semail, m_password, (GPEnum)m_blocking, GetUserNicksResponse, NULL)); +} + +void CGptestDlg::OnSuggest() +{ + if(!m_connection) + return; + + UpdateData(); + if(m_suniquenick.IsEmpty()) + { + MessageBox("Type in a desired unique nick"); + return; + } + dlg->m_results.ResetContent(); + CHECK(gpSuggestUniqueNick(&m_connection, m_suniquenick, (GPEnum)m_blocking, SuggestUniqueNickResponse, NULL)); +} + +void CGptestDlg::OnSelchangeResults() +{ + if(!m_connection) + return; + + int index = m_results.GetCurSel(); + if(index != LB_ERR) + { + // Get the profile. + int profile = m_results.GetItemData(index); + if(profile == -1) + return; + + // Put in what we now. + ////////////////////// + GPGetInfoResponseArg arg; + memset(&arg, 0, sizeof(arg)); + arg.profile = searchMatches[index].profile; + strcpy(arg.nick, searchMatches[index].nick); + strcpy(arg.uniquenick, searchMatches[index].uniquenick); + strcpy(arg.firstname, searchMatches[index].firstname); + strcpy(arg.lastname, searchMatches[index].lastname); + strcpy(arg.email, searchMatches[index].email); + GetInfoResponse(&m_connection, &arg, NULL); + + // Do a full get info if connected. + /////////////////////////////////// + GPEnum connected; + GPResult result = gpIsConnected(&m_connection, &connected); + if((result == GP_NO_ERROR) && connected && profile) + { + CHECK(gpGetInfo(&m_connection, profile, GP_CHECK_CACHE, (GPEnum)m_blocking, GetInfoResponse, NULL)); + } + } +} + +void CGptestDlg::OnSendrequest() +{ + if(!m_connection) + return; + + int index = m_results.GetCurSel(); + if(index != LB_ERR) + { + UpdateData(); + GPProfile profile = (GPProfile)m_results.GetItemData(index); + CHECK(gpSendBuddyRequest(&m_connection, profile, m_reason)); + } +} + +void CGptestDlg::OnInfoCache() +{ + if(!m_connection) + return; + + UpdateData(); + if(m_infoCache) + { + CHECK(gpEnable(&m_connection, GP_INFO_CACHING)); + } + else + { + CHECK(gpDisable(&m_connection, GP_INFO_CACHING)); + } +} + +void CGptestDlg::OnDelete() +{ + if(!m_connection) + return; + + // Get the profile for this item. + ///////////////////////////////// + int index = m_buddies.GetCurSel(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Delete this buddy. + ///////////////////// + CHECK(gpDeleteBuddy(&m_connection, profile)); + + m_buddies.DeleteString(index); + } +} + +void CGptestDlg::OnSetinfo() +{ + if(!m_connection) + return; + + int mask; + UpdateData(); + gpSetInfos(&m_connection, GP_FIRSTNAME, m_ifirstname); + gpSetInfos(&m_connection, GP_LASTNAME, m_ilastname); + gpSetInfoi(&m_connection, GP_ICQUIN, m_iicquin); + gpSetInfos(&m_connection, GP_HOMEPAGE, m_ihomepage); + gpSetInfos(&m_connection, GP_ZIPCODE, m_izipcode); + if(!m_icountrycode.IsEmpty()) + gpSetInfos(&m_connection, GP_COUNTRYCODE, m_icountrycode); + gpSetInfod(&m_connection, GP_BIRTHDAY, m_ibirthday, m_ibirthmonth, m_ibirthyear); + gpSetInfos(&m_connection, GP_SEX, m_isex); + mask = 0; + if(m_ipmhomepage) + mask |= GP_MASK_HOMEPAGE; + if(m_ipmzipcode) + mask |= GP_MASK_ZIPCODE; + if(m_ipmcountrycode) + mask |= GP_MASK_COUNTRYCODE; + if(m_ipmbirthday) + mask |= GP_MASK_BIRTHDAY; + if(m_ipmsex) + mask |= GP_MASK_SEX; + if(m_ipmemail) + mask |= GP_MASK_EMAIL; + gpSetInfoMask(&m_connection, (GPEnum)mask); +} + +static void DeleteResponseCallback(GPConnection *connection, void * _arg, void *param) +{ + GPDeleteProfileResponseArg *anArg = (GPDeleteProfileResponseArg *)_arg; + + if (anArg->result == GP_NO_ERROR) + { + AfxMessageBox("Profile delete success!", MB_ICONINFORMATION|MB_OK); + } + else + { + AfxMessageBox("Profile delete failed.", MB_ICONERROR|MB_OK); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void CGptestDlg::OnDeletepro() +{ + if(!m_connection) + return; + + CHECK(gpDeleteProfile(&m_connection, DeleteResponseCallback, NULL)); + +} + +void CGptestDlg::OnNewpro() +{ + if(!m_connection) + return; + + UpdateData(); + CHECK(gpNewProfile(&m_connection, m_newnick, m_replace?GP_REPLACE:GP_DONT_REPLACE, (GPEnum)m_blocking, NewProfileResponse, NULL)); +} + +void CGptestDlg::OnDeleteall() +{ + if(!m_connection) + return; + + int num; + GPBuddyStatus status; + + while(1) + { + gpGetNumBuddies(&m_connection, &num); + if(num == 0) + return; + gpGetBuddyStatus(&m_connection, 0, &status); + gpDeleteBuddy(&m_connection, status.profile); + } +} + +void CGptestDlg::OnInvitePlayer() +{ + if(!m_connection) + return; + + UpdateData(); + + // Get the profile for this item. + ///////////////////////////////// + int index = m_buddies.GetCurSel(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Invite this player. + ////////////////////// + CHECK(gpInvitePlayer(&m_connection, profile, m_invitePlayerID, NULL)); + } +} + +void report(const char * text) +{ + OutputDebugString(text); + OutputDebugString("\n"); +} + +void CGptestDlg::OnReport() +{ +#ifdef _DEBUG + gpProfilesReport(&m_connection, report); +#endif +} + +void SendFilesCallback(GPConnection * connection, int index, const char ** path, const char ** name, void * param) +{ + if(index == 0) + { + *path = dlg->m_path; + *name = dlg->m_name; + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void CGptestDlg::OnSendFiles() +{ + if(!m_connection) + return; + + int index = m_buddies.GetCurSel(); + if(index != LB_ERR) + { + GPTransfer transfer; + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Send a file. + /////////////// + UpdateData(); + CHECK(gpSendFiles(&m_connection, &transfer, profile, "Want this file?", SendFilesCallback, NULL)); + } +} + +void CGptestDlg::OnChangeSearchServer() +{ + if(!m_connection) + return; + + UpdateData(); + + if(!m_searchServer) + strcpy(GPSearchManagerHostname, GPSearchServerDefault); + else + strcpy(GPSearchManagerHostname, m_searchServer); +} + +void CGptestDlg::OnPublicmaskAll() +{ + if(!m_connection) + return; + + UpdateData(); + + m_ipmhomepage = TRUE; + m_ipmzipcode = TRUE; + m_ipmcountrycode = TRUE; + m_ipmbirthday = TRUE; + m_ipmsex = TRUE; + m_ipmemail = TRUE; + + UpdateData(FALSE); +} + +void CGptestDlg::OnPublicmaskNone() +{ + if(!m_connection) + return; + + UpdateData(); + + m_ipmhomepage = FALSE; + m_ipmzipcode = FALSE; + m_ipmcountrycode = FALSE; + m_ipmbirthday = FALSE; + m_ipmsex = FALSE; + m_ipmemail = FALSE; + + UpdateData(FALSE); +} + +void CGptestDlg::OnRevoke() +{ + if(!m_connection) + return; + + CHECK(gpGetReverseBuddies(&m_connection, (GPEnum)m_blocking, GetReverseBuddiesResponse, NULL)); +} + +void CGptestDlg::OnUTM() +{ + if(!m_connection) + return; + + int index = m_buddies.GetCurSel(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + + // Send a message to this guy. + ////////////////////////////// + UpdateData(); + CHECK(gpSendBuddyUTM(&m_connection, profile, (LPCSTR)m_message, 0)); + } +} + +void CGptestDlg::OnSetstatusinfo() +{ + if (!m_connection) + return; + + UpdateData(); + + /* + GPEnum aStatusState = (GPEnum)m_StatusState; + unsigned int aHostIp = inet_addr(m_HostIp); + unsigned int aHostPrivateIp = inet_addr(m_HostPrivateIp); + unsigned short aHostPort = m_HostPort; + unsigned short aQueryPort = m_QueryPort; + int *aSessionFlagsSelected = new int[m_SessionFlags.GetSelCount()]; + unsigned int sessFlags = 0; + m_SessionFlags.GetSelItems(m_SessionFlags.GetSelCount(), aSessionFlagsSelected); + + for (int i = 0; i < m_SessionFlags.GetSelCount(); i++) + { + int itemData = m_SessionFlags.GetItemData(aSessionFlagsSelected[i]); + sessFlags+= itemData; + } + + gpSetStatusInfo(&m_connection, aStatusState, aHostIp, aHostPrivateIp, aQueryPort, aHostPort, sessFlags, (LPCSTR)m_RichStatus, + m_RichStatus.GetLength(), (LPCSTR)m_GameType, m_GameType.GetLength(), (LPCSTR)m_GameVariant, m_GameVariant.GetLength(), + (LPCSTR)m_GameMapname, m_GameMapname.GetLength()); + delete[] aSessionFlagsSelected; + */ +} + +void CGptestDlg::OnAddSetKey() +{ + if (!m_connection) + return; + + UpdateData(); + /* + char *keyValue = NULL; + gpGetStatusInfoKeyVal(&m_connection, (LPCSTR)m_KeyName, &keyValue); + if (keyValue) + gpSetStatusInfoKey(&m_connection, (LPCSTR)m_KeyName, (LPCSTR)m_KeyValue); + else + gpAddStatusInfoKey(&m_connection, (LPCSTR)m_KeyName, (LPCSTR)m_KeyValue); + */ +} + +void CGptestDlg::OnGetKeyValue() +{ + if (!m_connection) + return; + + UpdateData(); + /* + char *keyValue = NULL; + gpGetStatusInfoKeyVal(&m_connection, (LPCSTR)m_KeyName, &keyValue); + if (keyValue) + m_KeyValue = keyValue; + */ +} + +void CGptestDlg::OnGetBuddyKeys() +{ + if(!m_connection) + return; + + /* + int index = m_buddies.GetCurSel(); + if(index != LB_ERR) + { + GPProfile profile = (GPProfile)m_buddies.GetItemData(index); + + // Send a message to this guy. + ////////////////////////////// + UpdateData(); + int bIndex; + gpGetBuddyIndex(&m_connection, profile, &bIndex); + + CHECK(gpGetBuddyStatusInfoKeys(&m_connection, bIndex, GetBuddyKeysCallback, NULL)); + } + */ +} + +void CGptestDlg::OnDelKeyVal() +{ + if (!m_connection) + return; + + UpdateData(); + /* + char *keyValue = NULL; + gpGetStatusInfoKeyVal(&m_connection, (LPCSTR)m_KeyName, &keyValue); + if (keyValue) + gpDelStatusInfoKeyA(&m_connection, (LPCSTR)m_KeyName); + */ +} + +void CGptestDlg::OnRegisterCdKey() +{ + if (!m_connection) + return; + + UpdateData(); + + // make sure the length isn't too much + if (m_cdkey.GetLength() > GP_CDKEY_LEN) + return; + + // Register CDkey + CHECK(gpRegisterCdKey(&m_connection, (LPCSTR)m_cdkey, GP_BLOCKING, RegisterCdKeyCallback, NULL)); +} + +void CGptestDlg::OnGetBlocked() +{ + if(!m_connection) + return; + + m_blocklist.ResetContent(); + UpdateData(); + + // Grab block list + GPProfile profile; + int numBlocked; + CHECK(gpGetNumBlocked(&m_connection, &numBlocked)); + + int i=0; + for (i=0; i 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CGptestDlg dialog + +class CGptestDlg : public CDialog +{ +// Construction +public: + CGptestDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CGptestDlg) + enum { IDD = IDD_GPTEST_DIALOG }; + CButton m_connectunique; + CButton m_connectpreauth; + CButton m_newuser; + CButton m_search; + CListBox m_results; + CButton m_update; + CButton m_send; + CButton m_set; + CListBox m_buddies; + CButton m_disconnect; + CButton m_connect; + int m_partnerid; + CString m_email; + CString m_nick; + CString m_password; + GPConnection m_connection; + CString m_locationString; + int m_status; + CString m_statusString; + CString m_iaddress; + CString m_icountrycode; + CString m_iemail; + CString m_ihomepage; + int m_iicquin; + CString m_inick; + CString m_isex; + CString m_message; + CString m_sfirstname; + CString m_snick; + int m_sicquin; + CString m_slastname; + CString m_semail; + CString m_string; + CString m_code; + CString m_reason; + int m_rnick; + BOOL m_infoCache; + BOOL m_blocking; + CString m_ilastname; + CString m_ifirstname; + int m_ibirthday; + int m_ibirthmonth; + int m_ibirthyear; + BOOL m_ipmbirthday; + BOOL m_ipmcountrycode; + BOOL m_ipmhomepage; + BOOL m_ipmsex; + BOOL m_ipmzipcode; + CString m_newnick; + BOOL m_replace; + CString m_izipcode; + UINT m_invitePlayerID; + int m_server; + CString m_otherServer; + CString m_name; + CString m_path; + CString m_searchServer; + BOOL m_ipmemail; + BOOL m_firewall; + float m_ilatitude; + CString m_iplace; + float m_ilongitude; + CString m_suniquenick; + CString m_iuniquenick; + CString m_uniquenick; + CString m_authtoken; + CString m_partnerchallenge; + CString m_namespace; + int m_productid; + CListBox m_blocklist; + CButton m_getblockedlist; + CButton m_addblock; + CButton m_removeblock; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGptestDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + mutable long m_InTimer; + + + + void CodeToString(CString & string); + void SetHost(); + + // Generated message map functions + //{{AFX_MSG(CGptestDlg) + virtual BOOL OnInitDialog(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnConnect(); + afx_msg void OnDisconnect(); + afx_msg void OnDestroy(); + afx_msg void OnSet(); + afx_msg void OnSelchangeBuddies(); + afx_msg void OnSend(); + afx_msg void OnRefresh(); + afx_msg void OnUpdate(); + afx_msg void OnSearch(); + afx_msg void OnSelchangeResults(); + afx_msg void OnNewuser(); + afx_msg void OnSendrequest(); + afx_msg void OnInfoCache(); + afx_msg void OnDelete(); + afx_msg void OnTest(); + afx_msg void OnSetinfo(); + afx_msg void OnDeletepro(); + afx_msg void OnNewpro(); + afx_msg void OnDeleteall(); + afx_msg void OnValidate(); + afx_msg void OnNicks(); + afx_msg void OnInvitePlayer(); + afx_msg void OnReport(); + afx_msg void OnCheck(); + afx_msg void OnSendFiles(); + afx_msg void OnChangeSearchServer(); + afx_msg void OnPublicmaskAll(); + afx_msg void OnPublicmaskNone(); + afx_msg void OnReverseBuddies(); + afx_msg void OnRevoke(); + afx_msg void OnSuggest(); + afx_msg void OnConnectunique(); + afx_msg void OnConnectpreauth(); + afx_msg void OnInitialize(); + afx_msg void OnDestroyGP(); + afx_msg void OnUTM(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +public: + int m_StatusState; + + short m_QueryPort; + short m_HostPort; + afx_msg void OnSetstatusinfo(); + CListBox m_SessionFlags; + CString m_RichStatus; + CString m_GameType; + CString m_GameVariant; + CString m_GameMapname; + afx_msg void OnAddSetKey(); + CString m_KeyName; + CString m_KeyValue; + afx_msg void OnGetKeyValue(); + afx_msg void OnGetBuddyKeys(); + CString m_HostIp; + CString m_HostPrivateIp; + afx_msg void OnDelKeyVal(); + CString m_cdkey; + afx_msg void OnRegisterCdKey(); + afx_msg void OnGetBlocked(); + afx_msg void OnAddBlock(); + afx_msg void OnRemoveBlock(); + afx_msg void OnSelchangeBlocklist(); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GPTESTDLG_H__AA6A1E3F_9C28_4A6C_902F_328A8707E479__INCLUDED_) diff --git a/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj b/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj new file mode 100644 index 00000000000..177b0c4be57 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj @@ -0,0 +1,1265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/gptest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/GP/gptest/res/gptest.ico b/xrGameSpy/gamespy/GP/gptest/res/gptest.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/GP/gptest/res/gptest.ico differ diff --git a/xrGameSpy/gamespy/GP/gptest/res/gptest.rc2 b/xrGameSpy/gamespy/GP/gptest/res/gptest.rc2 new file mode 100644 index 00000000000..c80d29ab45d --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/res/gptest.rc2 @@ -0,0 +1,13 @@ +// +// GPTEST.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/GP/gptest/resource.h b/xrGameSpy/gamespy/GP/gptest/resource.h new file mode 100644 index 00000000000..966af587aab --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptest/resource.h @@ -0,0 +1,159 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by gptest.rc +// +#define IDD_GPTEST_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_EMAIL 1000 +#define IDC_NICK 1001 +#define IDC_PASSWORD 1002 +#define IDC_CONNECT 1003 +#define IDC_DISCONNECT 1004 +#define IDC_BUDDIES 1005 +#define IDC_STATUS 1006 +#define IDC_STATUSSTRING 1007 +#define IDC_LOCATIONSTRING 1008 +#define IDC_SET 1009 +#define IDC_UPDATE 1010 +#define IDC_IFIRSTNAME 1011 +#define IDC_INICK 1012 +#define IDC_IEMAIL 1013 +#define IDC_IICQUIN 1014 +#define IDC_IHOMEPAGE 1015 +#define IDC_IBIRTHMONTH 1016 +#define IDC_ISEX 1017 +#define IDC_ICOUNTRYCODE 1018 +#define IDC_IZIPCODE 1019 +#define IDC_CHECK 1020 +#define IDC_IADDRESS 1021 +#define IDC_ISTATUS 1022 +#define IDC_ILONGITUDE 1022 +#define IDC_MESSAGE 1023 +#define IDC_SEND 1024 +#define IDC_REFRESH 1025 +#define IDC_SEMAIL 1026 +#define IDC_SNICK 1027 +#define IDC_SFIRSTNAME 1028 +#define IDC_SLASTNAME 1029 +#define IDC_SICQUIN 1030 +#define IDC_SEARCH 1031 +#define IDC_RESULTS 1032 +#define IDC_MPROFILE 1033 +#define IDC_AUTHTOKEN 1033 +#define IDC_NEWUSER 1034 +#define IDC_MNAME 1035 +#define IDC_PARTNERCHALLENGE 1035 +#define IDC_SENDREQUEST 1036 +#define IDC_MEMAIL 1037 +#define IDC_INITIALIZE 1037 +#define IDC_REASON 1038 +#define IDC_CLEAR 1039 +#define IDC_DESTROY 1039 +#define IDC_CODE 1040 +#define IDC_STRING 1041 +#define IDC_DELETE 1042 +#define IDC_RNICK 1043 +#define IDC_RNAME 1044 +#define IDC_REMAIL 1045 +#define IDC_INFO_CACHE 1046 +#define IDC_ISTATUSSTRING 1047 +#define IDC_SET_INVITABLE 1047 +#define IDC_BLOCKING 1048 +#define IDC_ILOCATION 1049 +#define IDC_FIND_PLAYERS 1049 +#define IDC_SETINFO 1050 +#define IDC_ILASTNAME 1051 +#define IDC_IBIRTHDAY 1052 +#define IDC_IBIRTHYEAR 1053 +#define IDC_IPMHOMEPAGE 1054 +#define IDC_IPMZIPCODE 1055 +#define IDC_IPMCOUNTRYCODE 1056 +#define IDC_IPMBIRTHDAY 1057 +#define IDC_IPMSEX 1058 +#define IDC_DELETEPRO 1059 +#define IDC_NEWNICK 1060 +#define IDC_NEWPRO 1061 +#define IDC_REPLACE 1062 +#define IDC_SEARCH_SERVER 1063 +#define IDC_VALIDATE 1064 +#define IDC_DELETEALL 1065 +#define IDC_NICKS 1066 +#define IDC_INVITE_PLAYER 1067 +#define IDC_IPMEMAIL 1068 +#define IDC_FIREWALL 1069 +#define IDC_ILATITUDE 1070 +#define IDC_INVITE_PLAYER_ID 1073 +#define IDC_REPORT 1074 +#define IDC_SAUTO 1075 +#define IDC_S1 1076 +#define IDC_S2 1077 +#define IDC_S3 1078 +#define IDC_S4 1079 +#define IDC_SOTHER 1080 +#define IDC_OTHER_SERVER 1081 +#define IDC_S5 1082 +#define IDC_S6 1083 +#define IDC_SEND_FILES 1084 +#define IDC_PATH 1085 +#define IDC_NAME 1086 +#define IDC_S7 1087 +#define IDC_IPLACE 1088 +#define IDC_PUBLICMASK_ALL 1089 +#define IDC_PUBLICMASK_NONE 1090 +#define IDC_REVOKE 1091 +#define IDC_SUNIQUENICK 1092 +#define IDC_UNIQUENICK 1093 +#define IDC_NAMESPACE 1094 +#define IDC_IUNIQUENICK 1095 +#define IDC_SUGGEST 1096 +#define IDC_CONNECTUNIQUE 1097 +#define IDC_CONNECTPREAUTH 1098 +#define IDC_UTM 1099 +#define IDC_PARTNERID 1100 +#define IDC_PRODUCTID 1101 +#define IDC_REGISTER_CDKEY 1102 +#define IDC_STATUS_STATE 1103 +#define IDC_RICH_STATUS 1104 +#define IDC_CDKEY 1105 +#define IDC_BLOCKLIST 1106 +#define IDC_QPORT 1107 +#define IDC_GAME_TYPE 1108 +#define IDC_HPORT 1109 +#define IDC_SFLAGS 1110 +#define IDC_STATELABEL 1111 +#define IDC_GAME_VARIANT 1112 +#define IDC_HOSTIPLABEL 1113 +#define IDC_HOSTPRIVIPLABEL 1114 +#define IDC_QPORTLABEL 1115 +#define IDC_GAME_MAPNAME 1116 +#define IDC_HPORTLABEL 1117 +#define IDC_SFLAGESLABEL 1118 +#define IDC_GTLABEL 1119 +#define IDC_GVLABEL 1120 +#define IDC_GMLABEL 1121 +#define IDC_RSLABEL 1122 +#define IDC_HOST_IP 1123 +#define IDC_HOST_PRIVATE_IP 1124 +#define IDC_GET_BLOCKEDLIST 1125 +#define IDC_SETSTATUSINFO 1126 +#define IDC_EXTSTATUSINFO 1127 +#define IDC_EDIT1 1128 +#define IDC_EDIT2 1129 +#define IDC_BUTTON2 1130 +#define IDC_BUTTON3 1131 +#define IDC_BUTTON4 1132 +#define IDC_BUTTON5 1133 +#define IDC_REMOVE_BLOCK 1134 +#define IDC_ADD_BLOCK 1135 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 132 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1136 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/GP/gptestc/gplinux/Makefile b/xrGameSpy/gamespy/GP/gptestc/gplinux/Makefile new file mode 100644 index 00000000000..50a91293f07 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gplinux/Makefile @@ -0,0 +1,72 @@ +# GameSpy Presence & Messaging SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=gpsdk + +CC=gcc +BASE_CFLAGS=-D_LINUX -D_NO_NOPORT_H_ + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsUdpEngine.o\ + ../../../common/linux/LinuxCommon.o\ + ../../gp.o\ + ../../gpi.o\ + ../../gpiBuddy.o\ + ../../gpiBuffer.o\ + ../../gpiCallback.o\ + ../../gpiConnect.o\ + ../../gpiInfo.o\ + ../../gpiKeys.o\ + ../../gpiOperation.o\ + ../../gpiPeer.o\ + ../../gpiProfile.o\ + ../../gpiSearch.o\ + ../../gpiUnique.o\ + ../../gpiUtility.o\ + ../../gpiTransfer.o\ + ../gptestc.o\ + ../../../gt2/gt2Auth.o\ + ../../../gt2/gt2Buffer.o\ + ../../../gt2/gt2Callback.o\ + ../../../gt2/gt2Connection.o\ + ../../../gt2/gt2Encode.o\ + ../../../gt2/gt2Filter.o\ + ../../../gt2/gt2Main.o\ + ../../../gt2/gt2Message.o\ + ../../../gt2/gt2Socket.o\ + ../../../gt2/gt2Utility.o + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/GP/gptestc/gpmacosx/Makefile b/xrGameSpy/gamespy/GP/gptestc/gpmacosx/Makefile new file mode 100644 index 00000000000..2699eeae28c --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpmacosx/Makefile @@ -0,0 +1,48 @@ +# GameSpy Presence & Messaging SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=gptestc + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsUdpEngine.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../gp.o\ + ../../gpi.o\ + ../../gpiBuddy.o\ + ../../gpiBuffer.o\ + ../../gpiCallback.o\ + ../../gpiConnect.o\ + ../../gpiInfo.o\ + ../../gpiKeys.o\ + ../../gpiOperation.o\ + ../../gpiPeer.o\ + ../../gpiProfile.o\ + ../../gpiSearch.o\ + ../../gpiUnique.o\ + ../../gpiUtility.o\ + ../../gpiTransfer.o\ + ../gptestc.o\ + ../../../gt2/gt2Auth.o\ + ../../../gt2/gt2Buffer.o\ + ../../../gt2/gt2Callback.o\ + ../../../gt2/gt2Connection.o\ + ../../../gt2/gt2Encode.o\ + ../../../gt2/gt2Filter.o\ + ../../../gt2/gt2Main.o\ + ../../../gt2/gt2Message.o\ + ../../../gt2/gt2Socket.o\ + ../../../gt2/gt2Utility.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/Nitro.lcf b/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/gpnitrocw.mcp b/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/gpnitrocw.mcp new file mode 100644 index 00000000000..878b88e6aec Binary files /dev/null and b/xrGameSpy/gamespy/GP/gptestc/gpnitrocw/gpnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps2/Makefile b/xrGameSpy/gamespy/GP/gptestc/gpps2/Makefile new file mode 100644 index 00000000000..e20765f7978 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps2/Makefile @@ -0,0 +1,40 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = gptestc + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../md5c.o \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../stringutil.o\ + ../../../available.o\ + ../../gp.o \ + ../../gpi.o \ + ../../gpiBuddy.o \ + ../../gpiBuffer.o \ + ../../gpiCallback.o \ + ../../gpiConnect.o \ + ../../gpiInfo.o \ + ../../gpiOperation.o \ + ../../gpiPeer.o \ + ../../gpiProfile.o \ + ../../gpiSearch.o \ + ../../gpiUnique.o \ + ../../gpiUtility.o \ + ../../gpiTransfer.o \ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps2cw/gpps2cw.mcp b/xrGameSpy/gamespy/GP/gptestc/gpps2cw/gpps2cw.mcp new file mode 100644 index 00000000000..424def05726 Binary files /dev/null and b/xrGameSpy/gamespy/GP/gptestc/gpps2cw/gpps2cw.mcp differ diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.dsp b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.dsp new file mode 100644 index 00000000000..c403eb2b5a6 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.dsp @@ -0,0 +1,444 @@ +# Microsoft Developer Studio Project File - Name="gpps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gpps2prodg - Win32 PS2 EE Release Insock +!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 "gpps2prodg.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 "gpps2prodg.mak" CFG="gpps2prodg - Win32 PS2 EE Release Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gpps2prodg - Win32 PS2 EE Debug EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gpps2prodg - Win32 PS2 EE Debug SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "gpps2prodg - Win32 PS2 EE Debug Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "gpps2prodg - Win32 PS2 EE Release EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gpps2prodg - Win32 PS2 EE Release SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "gpps2prodg - Win32 PS2 EE Release Insock" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/GP/gptestc/gpps2prodg", PSEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gpps2prodg - Win32 PS2 EE Debug EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Debug EENet" +# PROP BASE Intermediate_Dir "PS2 EE Debug EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libcdvd.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gpps2prodg - Win32 PS2 EE Debug SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Debug SNSystems" +# PROP BASE Intermediate_Dir "PS2 EE Debug SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\gpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gpps2prodg - Win32 PS2 EE Debug Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gpps2prodg___Win32_PS2_EE_Debug_Insock" +# PROP BASE Intermediate_Dir "gpps2prodg___Win32_PS2_EE_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "INSOCK" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libcdvd.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\gpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gpps2prodg - Win32 PS2 EE Release EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Release EENet" +# PROP BASE Intermediate_Dir "PS2 EE Release EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libcdvd.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\gpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gpps2prodg - Win32 PS2 EE Release SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Release SNSystems" +# PROP BASE Intermediate_Dir "PS2 EE Release SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\gpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gpps2prodg - Win32 PS2 EE Release Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gpps2prodg___Win32_PS2_EE_Release_Insock" +# PROP BASE Intermediate_Dir "gpps2prodg___Win32_PS2_EE_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "INSOCK" /FD /debug /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Release_Insock\gpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Release_Insock\gpps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "gpps2prodg - Win32 PS2 EE Debug EENet" +# Name "gpps2prodg - Win32 PS2 EE Debug SNSystems" +# Name "gpps2prodg - Win32 PS2 EE Debug Insock" +# Name "gpps2prodg - Win32 PS2 EE Release EENet" +# Name "gpps2prodg - Win32 PS2 EE Release SNSystems" +# Name "gpps2prodg - Win32 PS2 EE Release Insock" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\gptestc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gp.c +# End Source File +# Begin Source File + +SOURCE=..\..\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpi.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiBuddy.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiCallback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiConnect.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiInfo.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiOperation.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiPeer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiProfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiSearch.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiTransfer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiUnique.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpiUtility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gpiUtility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.dsw b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.dsw new file mode 100644 index 00000000000..e3a739b4729 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gpps2prodg"=.\gpps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/GP/gptestc/gpps2prodg", PSEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/gamespy/goa/gp/gptestc/gpps2prodg", PSEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.sln b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.sln new file mode 100644 index 00000000000..be950b8e60f --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.sln @@ -0,0 +1,49 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpps2prodg", "gpps2prodg.vcproj", "{93A0A53A-16D0-4ACE-9103-262B0DF81F3B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gpps2prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EE Debug|Win32 = PS2 EE Debug|Win32 + PS2 EE Release|Win32 = PS2 EE Release|Win32 + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EE Debug|Win32.ActiveCfg = PS2 EE Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EE Debug|Win32.Build.0 = PS2 EE Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EE Release|Win32.ActiveCfg = PS2 EE Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EE Release|Win32.Build.0 = PS2 EE Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EE Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EENET Debug|Win32.Build.0 = PS2 EE Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EENET Release|Win32.ActiveCfg = PS2 EE Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 EENET Release|Win32.Build.0 = PS2 EE Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {93A0A53A-16D0-4ACE-9103-262B0DF81F3B}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.vcproj b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.vcproj new file mode 100644 index 00000000000..ca119f9cd62 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps2prodg/gpps2prodg.vcproj @@ -0,0 +1,849 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps3/Makefile b/xrGameSpy/gamespy/GP/gptestc/gpps3/Makefile new file mode 100644 index 00000000000..e03f78d97ba --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps3/Makefile @@ -0,0 +1,44 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = gptestc + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../../common/gsAvailable.o \ + ../../../hashtable.o \ + ../../../darray.o \ + ../../../md5c.o \ + ../../gp.o \ + ../../gpi.o \ + ../../gpiBuddy.o \ + ../../gpiBuffer.o \ + ../../gpiCallback.o \ + ../../gpiConnect.o \ + ../../gpiInfo.o \ + ../../gpiOperation.o \ + ../../gpiPeer.o \ + ../../gpiProfile.o \ + ../../gpiSearch.o \ + ../../gpiUnique.o \ + ../../gpiUtility.o \ + ../../gpiTransfer.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps3prodg/gpps3prodg.sln b/xrGameSpy/gamespy/GP/gptestc/gpps3prodg/gpps3prodg.sln new file mode 100644 index 00000000000..c20b74a54f8 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps3prodg/gpps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpps3prodg", "gpps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gpps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/GP/gptestc/gpps3prodg/gpps3prodg.vcproj b/xrGameSpy/gamespy/GP/gptestc/gpps3prodg/gpps3prodg.vcproj new file mode 100644 index 00000000000..eb775604ad4 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpps3prodg/gpps3prodg.vcproj @@ -0,0 +1,583 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptestc/gppsp/Makefile b/xrGameSpy/gamespy/GP/gptestc/gppsp/Makefile new file mode 100644 index 00000000000..4f4897f9f16 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gppsp/Makefile @@ -0,0 +1,44 @@ +#GameSpy.net PSP Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID -DGSI_MEM_MANAGED -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +#SDK_LIBS = + +#Name of the SDK sample +TARGET = gptestc + +#All the object files needed for this SDK +OBJS = ../../../common/psp/pspcommon.o\ + ../../../common/psp/gsUtilPSP.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../md5c.o\ + ../../gp.o\ + ../../gpi.o\ + ../../gpiBuddy.o\ + ../../gpiBuffer.o\ + ../../gpiCallback.o\ + ../../gpiConnect.o\ + ../../gpiInfo.o\ + ../../gpiOperation.o\ + ../../gpiPeer.o\ + ../../gpiProfile.o\ + ../../gpiSearch.o\ + ../../gpiTransfer.o\ + ../../gpiUnique.o\ + ../../gpiUtility.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/psp/Makefile.common + diff --git a/xrGameSpy/gamespy/GP/gptestc/gppspprodg/gppspprodg.sln b/xrGameSpy/gamespy/GP/gptestc/gppspprodg/gppspprodg.sln new file mode 100644 index 00000000000..926591a4158 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gppspprodg/gppspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gppspprodg", "gppspprodg.vcproj", "{E95E1EE9-B275-43C2-A90F-11B505A22EA0}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gppspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E95E1EE9-B275-43C2-A90F-11B505A22EA0}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {E95E1EE9-B275-43C2-A90F-11B505A22EA0}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {E95E1EE9-B275-43C2-A90F-11B505A22EA0}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {E95E1EE9-B275-43C2-A90F-11B505A22EA0}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {E95E1EE9-B275-43C2-A90F-11B505A22EA0}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {E95E1EE9-B275-43C2-A90F-11B505A22EA0}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/GP/gptestc/gppspprodg/gppspprodg.vcproj b/xrGameSpy/gamespy/GP/gptestc/gppspprodg/gppspprodg.vcproj new file mode 100644 index 00000000000..f502b86176e --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gppspprodg/gppspprodg.vcproj @@ -0,0 +1,630 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptestc/gprevolutioncw/gprevolutioncw.mcp b/xrGameSpy/gamespy/GP/gptestc/gprevolutioncw/gprevolutioncw.mcp new file mode 100644 index 00000000000..33c708a4956 Binary files /dev/null and b/xrGameSpy/gamespy/GP/gptestc/gprevolutioncw/gprevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/GP/gptestc/gptestc.c b/xrGameSpy/gamespy/GP/gptestc/gptestc.c new file mode 100644 index 00000000000..c3e48db23f0 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gptestc.c @@ -0,0 +1,654 @@ +#include "../gp.h" +#include "../../common/gsAvailable.h" + +#if defined(_WIN32) && !defined(UNDER_CE) + #include +#endif + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#if defined(_WIN32) +// disable the warning about our while(1) statement +#pragma warning(disable:4127) +#endif + +#ifdef __MWERKS__ // CodeWarrior will warn if function is not prototyped +int test_main(int argc, char **argv); +#endif + +#define GPTC_PRODUCTID 0 +#define GPTC_GAMENAME _T("gmtest") +#define GPTC_NICK1 _T("gptestc1") +#define GPTC_NICK2 _T("gptestc2") +#define GPTC_NICK3 _T("gptestc3") +#define GPTC_EMAIL1 _T("gptestc@gptestc.com") +#define GPTC_EMAIL2 _T("gptestc2@gptestc.com") +#define GPTC_EMAIL3 _T("gptestc3@gptestc.com") +#define GPTC_PASSWORD _T("gptestc") +#define GPTC_PID1 2957553 +#define GPTC_PID2 3052160 +#define GPTC_PID3 118305038 +#define GPTC_FIREWALL_OPTION GP_FIREWALL + +#define CHECK_GP_RESULT(func, errString) if(func != GP_NO_ERROR) { printf("%s\n", errString); /*return 1;*/ } + +GPConnection * pconn; +GPProfile other; +GPProfile otherBlock; +int otherIndex = -1; +int appState = -1; +gsi_bool receivedLastMessage = gsi_false; +gsi_bool gotStoodUp = gsi_false; +gsi_bool blockTesting = gsi_false; +int noComLineArgs; +int namespaceIds[GP_MAX_NAMESPACEIDS] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + + +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); + } +#endif + +static void Error(GPConnection * pconnection, GPErrorArg * arg, void * param) +{ + gsi_char * errorCodeString; + gsi_char * resultString; + +#define RESULT(x) case x: resultString = _T(#x); break; + switch(arg->result) + { + RESULT(GP_NO_ERROR) + RESULT(GP_MEMORY_ERROR) + RESULT(GP_PARAMETER_ERROR) + RESULT(GP_NETWORK_ERROR) + RESULT(GP_SERVER_ERROR) + default: + resultString = _T("Unknown result!\n"); + } + +#define ERRORCODE(x) case x: errorCodeString = _T(#x); break; + switch(arg->errorCode) + { + ERRORCODE(GP_GENERAL) + ERRORCODE(GP_PARSE) + ERRORCODE(GP_NOT_LOGGED_IN) + ERRORCODE(GP_BAD_SESSKEY) + ERRORCODE(GP_DATABASE) + ERRORCODE(GP_NETWORK) + ERRORCODE(GP_FORCED_DISCONNECT) + ERRORCODE(GP_CONNECTION_CLOSED) + ERRORCODE(GP_LOGIN) + ERRORCODE(GP_LOGIN_TIMEOUT) + ERRORCODE(GP_LOGIN_BAD_NICK) + ERRORCODE(GP_LOGIN_BAD_EMAIL) + ERRORCODE(GP_LOGIN_BAD_PASSWORD) + ERRORCODE(GP_LOGIN_BAD_PROFILE) + ERRORCODE(GP_LOGIN_PROFILE_DELETED) + ERRORCODE(GP_LOGIN_CONNECTION_FAILED) + ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED) + ERRORCODE(GP_NEWUSER) + ERRORCODE(GP_NEWUSER_BAD_NICK) + ERRORCODE(GP_NEWUSER_BAD_PASSWORD) + ERRORCODE(GP_UPDATEUI) + ERRORCODE(GP_UPDATEUI_BAD_EMAIL) + ERRORCODE(GP_NEWPROFILE) + ERRORCODE(GP_NEWPROFILE_BAD_NICK) + ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK) + ERRORCODE(GP_UPDATEPRO) + ERRORCODE(GP_UPDATEPRO_BAD_NICK) + ERRORCODE(GP_ADDBUDDY) + ERRORCODE(GP_ADDBUDDY_BAD_FROM) + ERRORCODE(GP_ADDBUDDY_BAD_NEW) + ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY) + ERRORCODE(GP_AUTHADD) + ERRORCODE(GP_AUTHADD_BAD_FROM) + ERRORCODE(GP_AUTHADD_BAD_SIG) + ERRORCODE(GP_STATUS) + ERRORCODE(GP_BM) + ERRORCODE(GP_BM_NOT_BUDDY) + ERRORCODE(GP_GETPROFILE) + ERRORCODE(GP_GETPROFILE_BAD_PROFILE) + ERRORCODE(GP_DELBUDDY) + ERRORCODE(GP_DELBUDDY_NOT_BUDDY) + ERRORCODE(GP_DELPROFILE) + ERRORCODE(GP_DELPROFILE_LAST_PROFILE) + ERRORCODE(GP_SEARCH) + ERRORCODE(GP_SEARCH_CONNECTION_FAILED) + default: + errorCodeString = _T("Unknown error code!\n"); + } + + if(arg->fatal) + { + printf( "-----------\n"); + printf( "FATAL ERROR\n"); + printf( "-----------\n"); + } + else + { + printf( "-----\n"); + printf( "ERROR\n"); + printf( "-----\n"); + } + _tprintf( _T("RESULT: %s (%d)\n"), resultString, arg->result); + _tprintf( _T("ERROR CODE: %s (0x%X)\n"), errorCodeString, arg->errorCode); + _tprintf( _T("ERROR STRING: %s\n"), arg->errorString); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +gsi_char whois[GP_NICK_LEN]; +static void Whois(GPConnection * pconnection, GPGetInfoResponseArg * arg, void * param) +{ + if(arg->result == GP_NO_ERROR) + { + _tcscpy(whois, arg->nick); + /*if (_tcscmp(arg->email, "")) { + _tcscat(whois, _T("@")); + _tcscat(whois, arg->email); + }*/ + } + else + printf( "WHOIS FAILED\n"); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void ConnectResponse(GPConnection * pconnection, GPConnectResponseArg * arg, void * param) +{ + if(arg->result == GP_NO_ERROR) + printf("Connected\n"); + else + printf( "CONNECT FAILED\n"); + + gpSetStatus(pconnection, (GPEnum)GP_ONLINE, _T("Not Ready"), _T("gptestc")); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void ProfileSearchResponse(GPConnection * pconnection, GPProfileSearchResponseArg * arg, void * param) +{ + GPResult result; + int i; + if(arg->result == GP_NO_ERROR) + { + if(arg->numMatches > 0) + { + for(i = 0 ; i < arg->numMatches ; i++) + { + result = gpGetInfo(pconn, arg->matches[i].profile, GP_DONT_CHECK_CACHE, GP_BLOCKING, (GPCallback)Whois, NULL); + if(result != GP_NO_ERROR) + printf(" gpGetInfo failed\n"); + else + _tprintf(_T(" Found: %s\n"), whois); + } + } + else + printf( " NO MATCHES\n"); + } + else + printf( " SEARCH FAILED\n"); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +int msgCount = 0; +static void RecvBuddyMessage(GPConnection * pconnection, void * theArg, void * param) +{ + GPRecvBuddyMessageArg *arg; + GPResult result; + + arg = (GPRecvBuddyMessageArg *)theArg; + + result = gpGetInfo(pconn, arg->profile, GP_DONT_CHECK_CACHE, GP_BLOCKING, (GPCallback)Whois, NULL); + if(result != GP_NO_ERROR) + printf(" gpGetInfo failed\n"); + else + _tprintf(_T(" Received buddy message: %s: %s\n"), whois, arg->message); + + if (!(_tcscmp(arg->message, "5_Hello!"))) { + receivedLastMessage = gsi_true; + } + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + + +static void GetInfoResponse(GPConnection * pconnection, GPGetInfoResponseArg * arg, void * param) +{ + //_tprintf(_T(" First Name: %s Last Name: %s (%s@%s)\n"), arg->firstname, arg->lastname, arg->nick, arg->email); + _tprintf(_T(" First Name: %s Last Name: %s (%s)\n"), arg->firstname, arg->lastname, arg->nick); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +void RecvBuddyStatus(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyStatusArg * arg = (GPRecvBuddyStatusArg *)arg_; + GPBuddyStatus status; + static char* statusToString[6] = + { + "GP_OFFLINE", + "GP_ONLINE", + "GP_PLAYING", + "GP_STAGING", + "GP_CHATTING", + "GP_AWAY" + }; + + printf(" Buddy index: %d\n", arg->index); + + if (arg->profile == other) + { + if (appState < 0) + appState = 0; + otherIndex = arg->index; + gpGetBuddyStatus(connection, arg->index, &status); + if (status.status == 1 && _tcscmp(status.statusString, "Ready") && _tcscmp(status.statusString, "BlockTime")) { + if (appState < 1) { + appState = 1; + //printf("Buddy is online!\n"); + CHECK_GP_RESULT(gpSetStatus(pconn, (GPEnum) GP_ONLINE, _T("Ready"), _T("gptestc")), "gpSetStatus failed"); + //printf("Now wait until buddy is ready to message...\n"); + } + } + else if (status.status == 1 && !(_tcscmp(status.statusString, "Ready"))) { + if (appState < 2) { + appState = 2; + //printf("Buddy is ready to message!\n"); + CHECK_GP_RESULT(gpSetStatus(pconn, (GPEnum) GP_ONLINE, _T("Ready"), _T("gptestc")), "gpSetStatus failed"); + } + } + else if (status.status == 1 && !(_tcscmp(status.statusString, "BlockTime"))) { + if (appState < 3) + appState = 3; + //printf("Buddy is ready to block test!\n"); + } + } + printf(" "); + gpGetInfo(connection, arg->profile, GP_DONT_CHECK_CACHE, GP_BLOCKING, (GPCallback)GetInfoResponse, NULL); + + gpGetBuddyStatus(connection, arg->index, &status); + + printf(" Status: %s, Status String: %s, Location String: %s, IP: %d, Port: %d\n", statusToString[status.status], status.statusString, status.locationString, status.ip, status.port); + + GSI_UNUSED(param); +} + +void RecvBuddyRequest(GPConnection * connection, void * arg_, void * param) +{ + GPRecvBuddyRequestArg * arg = (GPRecvBuddyRequestArg *)arg_; + + gsi_char buddy1[50]; + gsi_char buddy2[50]; + + gpGetInfo(connection, arg->profile, GP_CHECK_CACHE, GP_BLOCKING, (GPCallback)Whois, NULL); + printf("\nBuddy Request from %s\n", whois); +#ifdef GSI_UNICODE + _stprintf(buddy1, sizeof(buddy1), _T("%s"), GPTC_NICK1); + _stprintf(buddy2, sizeof(buddy2), _T("%s"), GPTC_NICK2); +#else + _stprintf(buddy1, _T("%s"), GPTC_NICK1); + _stprintf(buddy2, _T("%s"), GPTC_NICK2); +#endif + + if (!_tcscmp(whois, buddy1) || !_tcscmp(whois, buddy2)) + { + printf("Authorizing buddy request\n"); + gpAuthBuddyRequest(connection, arg->profile); + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + if (blockTesting) { + appState = 4; + if (!noComLineArgs) { + gpSendBuddyRequest(pconn, other, _T("testing")); + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + } + } + } + else + { + printf("Denying buddy request\n"); + gpDenyBuddyRequest(connection, arg->profile); + } + GSI_UNUSED(connection); + GSI_UNUSED(param); +} + +void RecvBuddyRevoke(GPConnection * connection, void * arg_, void * param) +{ + printf("Buddy Revoke received...\n"); + + if (appState == 2) { + appState = 3; + } + + GSI_UNUSED(connection); + GSI_UNUSED(param); + GSI_UNUSED(arg_); +} + +static void printBlockedList() +{ + int i=0; + int numBlocked; + int pid; + + gpGetNumBlocked(pconn, &numBlocked); + printf("Get blocked list: num = %d\n", numBlocked); + + for (i=0; i 10000) + { + if (appState == -1) // buddy is not actually on our buddy list + { + if (noComLineArgs) + printf(" %s is not on our buddy list! Sending him a buddy request and waiting for a response...\n", GPTC_NICK2); + else + printf("%s is not on our buddy list! Sending him a buddy request and waiting for a response...\n", GPTC_NICK1); + + gpSendBuddyRequest(pconn, other, _T("testing")); + + totalTime = 0; + while (totalTime < 10000 && appState != 2) { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + totalTime += 50; + } + totalTime = 12001; + if (appState != 2) + { + if (noComLineArgs) + printf("\n%s never showed up =(\n", GPTC_NICK2); + else + printf("\n%s never showed up =(\n", GPTC_NICK1); + gotStoodUp = gsi_true; + break; + } + } + else // buddy is on our buddy list but did not come online and set status to "Ready" + { + if (noComLineArgs) + printf("\n%s never showed up =(\n", GPTC_NICK2); + else + printf("\n%s never showed up =(\n", GPTC_NICK1); + gotStoodUp = gsi_true; + break; + } + } + } + + if (!gotStoodUp) + { + printf("\nSending messages to buddy (and receiving messages from him)\n"); + totalTime = 0; + messagesSent = 0; + while(messagesSent < 5) + { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + totalTime += 50; + if (totalTime % 1000 == 0) + { +#ifdef GSI_UNICODE + _stprintf(messageToSend, sizeof(messageToSend), _T("%d_Hello!"), (int)(totalTime/1000)); +#else + _stprintf(messageToSend, _T("%d_Hello!"), (int)(totalTime/1000)); +#endif + CHECK_GP_RESULT(gpSendBuddyMessage(pconn, other, messageToSend), "gpSendBuddyMessage failed"); + messagesSent++; + } + } + + while(!receivedLastMessage) + { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + } + + CHECK_GP_RESULT(gpSetStatus(pconn, (GPEnum) GP_ONLINE, _T("BlockTime"), _T("gptestc")), "gpSetStatus failed"); + + while(appState != 3) + { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + } + } + else + appState = 3; + + blockTesting = gsi_true; + if (noComLineArgs) { + // block buddy + if (gotStoodUp) { + CHECK_GP_RESULT(gpProfileFromID(pconn, &other, GPTC_PID3), "gpProfileFromID failed"); + printf("\nBlocking %s\n", GPTC_NICK3); + } + else + printf("\nBlocking %s\n", GPTC_NICK2); + + CHECK_GP_RESULT(gpAddToBlockedList(pconn, other), "gpAddToBlockedList failed"); + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + printBlockedList(); + + if (!gotStoodUp) { + printf("Checking if %s is on our buddy list...\n", GPTC_NICK2); + if (gpIsBuddy(pconn, other)) + printf("Yup.\n"); + else + printf("Nope.\n"); + + printf("Wait while %s tries to message us...\n", GPTC_NICK2); + totalTime = 0; + while (totalTime < 5000) { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + totalTime += 50; + } + } + if (!gotStoodUp) + printf("\nUnblocking %s\n", GPTC_NICK2); + else + printf("\nUnblocking %s\n", GPTC_NICK3); + CHECK_GP_RESULT(gpRemoveFromBlockedList(pconn, other), "gpRemoveFromBlockedList"); + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + printBlockedList(); + + CHECK_GP_RESULT(gpSetStatus(pconn, (GPEnum) GP_ONLINE, _T("DoneBlockTesting"), _T("gptestc")), "gpSetStatus failed"); + + if (!gotStoodUp) { + printf("Sending a buddy request to %s\n", GPTC_NICK2); + gpSendBuddyRequest(pconn, other, _T("testing")); + + printf("Waiting to get buddy requested back...\n"); + while (appState != 4) { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + } + } + } + else { + if (!gotStoodUp) { + printf("Waiting for %s to block us...\n", GPTC_NICK1); + while (gpIsBuddy(pconn, other)) { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + } + printf("We have been blocked. Trying to send buddy message to %s\n", GPTC_NICK1); + CHECK_GP_RESULT(gpSendBuddyMessage(pconn, other, _T("Why did you block me?")), "gpSendBuddyMessage failed"); + + printf("Waiting to get unblocked and buddy requested...\n"); + while (appState != 4) { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(50); + } + CHECK_GP_RESULT(gpSetStatus(pconn, (GPEnum) GP_ONLINE, _T("DoneBlockTesting"), _T("gptestc")), "gpSetStatus failed"); + } + } + + printf("\nDONE - Press any key to exit.\n\n"); + +#if defined(_WIN32) && !defined(UNDER_CE) + while (1) + { + CHECK_GP_RESULT(gpProcess(pconn), "gpProcess failed"); + msleep(10); + if (_kbhit()) { + break; + } + } +#endif + +//#if defined(_WIN32) && !defined(UNDER_CE) + //DISCONNECT + //////////// + gpDisconnect(pconn); + printf("Disconnected\n"); + + //DESTROY + ///////// + gpDestroy(pconn); + printf("Destroyed\n"); + return 0; +//#endif +} + + diff --git a/xrGameSpy/gamespy/GP/gptestc/gptestc.dsp b/xrGameSpy/gamespy/GP/gptestc/gptestc.dsp new file mode 100644 index 00000000000..edb08f06444 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gptestc.dsp @@ -0,0 +1,480 @@ +# Microsoft Developer Studio Project File - Name="gptestc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gptestc - Win32 Unicode 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 "gptestc.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 "gptestc.mak" CFG="gptestc - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gptestc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gptestc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "gptestc - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "gptestc - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gptestc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gptestc___Win32_Release" +# PROP BASE Intermediate_Dir "gptestc___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /WX /GX /O2 /I "..\..\\" /I "..\..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /D "GSI_MEM_MANAGED" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gptestc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gptestc___Win32_Debug" +# PROP BASE Intermediate_Dir "gptestc___Win32_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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /D "GSI_MEM_MANAGED" /FD /GZ /c +# SUBTRACT CPP /YX +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "gptestc - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Unicode Debug" +# PROP BASE Intermediate_Dir "Unicode Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Unicode Debug" +# PROP Intermediate_Dir "Unicode Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /I "..\..\\" /I "..\..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /D "GSI_MEM_MANAGED" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "gptestc - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Unicode Release" +# PROP BASE Intermediate_Dir "Unicode Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Unicode Release" +# PROP Intermediate_Dir "Unicode Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /WX /GX /O2 /I "..\..\\" /I "..\..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /D "GSI_MEM_MANAGED" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ENDIF + +# Begin Target + +# Name "gptestc - Win32 Release" +# Name "gptestc - Win32 Debug" +# Name "gptestc - Win32 Unicode Debug" +# Name "gptestc - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gptestc.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\gp.c +# End Source File +# Begin Source File + +SOURCE=..\gp.h +# End Source File +# Begin Source File + +SOURCE=..\gpi.c +# End Source File +# Begin Source File + +SOURCE=..\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\gpiBuddy.c +# End Source File +# Begin Source File + +SOURCE=..\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\gpiBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiCallback.c +# End Source File +# Begin Source File + +SOURCE=..\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\gpiConnect.c +# End Source File +# Begin Source File + +SOURCE=..\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\gpiInfo.c +# End Source File +# Begin Source File + +SOURCE=..\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\gpiOperation.c +# End Source File +# Begin Source File + +SOURCE=..\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\gpiPeer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiProfile.c +# End Source File +# Begin Source File + +SOURCE=..\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\gpiSearch.c +# End Source File +# Begin Source File + +SOURCE=..\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\gpiTransfer.c +# End Source File +# Begin Source File + +SOURCE=..\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\gpiUnique.c +# End Source File +# Begin Source File + +SOURCE=..\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\gpiUtility.c +# End Source File +# Begin Source File + +SOURCE=..\gpiUtility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj b/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj new file mode 100644 index 00000000000..6ead76726bd --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj @@ -0,0 +1,1320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..91a0bd9a062 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gptestc_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/GP/gptestc/gpx360/gpx360.sln b/xrGameSpy/gamespy/GP/gptestc/gpx360/gpx360.sln new file mode 100644 index 00000000000..8ef6f2e16cd --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpx360/gpx360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpx360", "gpx360.vcproj", "{51CF330D-9E84-42F4-B704-11A9FF0364CB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {51CF330D-9E84-42F4-B704-11A9FF0364CB}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/GP/gptestc/gpx360/gpx360.vcproj b/xrGameSpy/gamespy/GP/gptestc/gpx360/gpx360.vcproj new file mode 100644 index 00000000000..1e35145b2cc --- /dev/null +++ b/xrGameSpy/gamespy/GP/gptestc/gpx360/gpx360.vcproj @@ -0,0 +1,632 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/GameSpy SDK Help.chm b/xrGameSpy/gamespy/GameSpy SDK Help.chm new file mode 100644 index 00000000000..ed2f1bb3dc9 Binary files /dev/null and b/xrGameSpy/gamespy/GameSpy SDK Help.chm differ diff --git a/xrGameSpy/gamespy/Peer/Peer.dsp b/xrGameSpy/gamespy/Peer/Peer.dsp new file mode 100644 index 00000000000..d326c5a29fe --- /dev/null +++ b/xrGameSpy/gamespy/Peer/Peer.dsp @@ -0,0 +1,452 @@ +# Microsoft Developer Studio Project File - Name="Peer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=Peer - 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 "Peer.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 "Peer.mak" CFG="Peer - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Peer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "Peer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Peer", OWNAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Peer - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "Peer - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "Peer - Win32 Release" +# Name "Peer - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\peerAutoMatch.c +# End Source File +# Begin Source File + +SOURCE=.\peerCallbacks.c +# End Source File +# Begin Source File + +SOURCE=.\peerGlobalCallbacks.c +# End Source File +# Begin Source File + +SOURCE=.\peerHost.c +# End Source File +# Begin Source File + +SOURCE=.\peerKeys.c +# End Source File +# Begin Source File + +SOURCE=.\peerMain.c +# End Source File +# Begin Source File + +SOURCE=.\peerMangle.c +# End Source File +# Begin Source File + +SOURCE=.\peerOperations.c +# End Source File +# Begin Source File + +SOURCE=.\peerPing.c +# End Source File +# Begin Source File + +SOURCE=.\peerPlayers.c +# End Source File +# Begin Source File + +SOURCE=.\peerQR.c +# End Source File +# Begin Source File + +SOURCE=.\peerRooms.c +# End Source File +# Begin Source File + +SOURCE=.\peerSB.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\peer.h +# End Source File +# Begin Source File + +SOURCE=.\peerAutoMatch.h +# End Source File +# Begin Source File + +SOURCE=.\peerCallbacks.h +# End Source File +# Begin Source File + +SOURCE=.\peerGlobalCallbacks.h +# End Source File +# Begin Source File + +SOURCE=.\peerHost.h +# End Source File +# Begin Source File + +SOURCE=.\peerKeys.h +# End Source File +# Begin Source File + +SOURCE=.\peerMain.h +# End Source File +# Begin Source File + +SOURCE=.\peerMangle.h +# End Source File +# Begin Source File + +SOURCE=.\peerOperations.h +# End Source File +# Begin Source File + +SOURCE=.\peerPing.h +# End Source File +# Begin Source File + +SOURCE=.\peerPlayers.h +# End Source File +# Begin Source File + +SOURCE=.\peerQR.h +# End Source File +# Begin Source File + +SOURCE=.\peerRooms.h +# End Source File +# Begin Source File + +SOURCE=.\peerSB.h +# End Source File +# End Group +# Begin Group "ChatSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\chat\chat.h +# End Source File +# Begin Source File + +SOURCE=..\chat\chatCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\chat\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\chat\chatChannel.c +# End Source File +# Begin Source File + +SOURCE=..\chat\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\Chat\chatCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\Chat\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\chat\chatHandlers.c +# End Source File +# Begin Source File + +SOURCE=..\chat\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\chat\chatMain.c +# End Source File +# Begin Source File + +SOURCE=..\chat\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\chat\chatSocket.c +# End Source File +# Begin Source File + +SOURCE=..\chat\chatSocket.h +# End Source File +# End Group +# Begin Group "Pinger" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\pinger\pinger.h +# End Source File +# Begin Source File + +SOURCE=..\pinger\pingerMain.c +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\qr2\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\serverbrowsing\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_server.c +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\serverbrowsing\sb_serverlist.c +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\md5c.c +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Peer/Peer.dsw b/xrGameSpy/gamespy/Peer/Peer.dsw new file mode 100644 index 00000000000..ea144a2ba9b --- /dev/null +++ b/xrGameSpy/gamespy/Peer/Peer.dsw @@ -0,0 +1,85 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Peer"=.\Peer.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer", OWNAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PeerLobby"=.\PeerLobby\PeerLobby.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer/PeerLobby", MDWAAAAA + .\peerlobby + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PeerTest"=.\PeerTest\PeerTest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer/PeerTest", EBOAAAAA + .\peertest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "peerc"=.\peerc\peerc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer/peerc", GSUAAAAA + .\peerc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer", OWNAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/ConnectPage.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/ConnectPage.cpp new file mode 100644 index 00000000000..6194c4f5d68 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/ConnectPage.cpp @@ -0,0 +1,762 @@ +// ConnectPage.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "ConnectPage.h" +#include "TitlePage.h" +#include "LobbyWizard.h" +#include "GroupPage.h" +#include "StagingPage.h" +#include "CreatePage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CConnectPage * ConnectPage; + +///////////////////////////////////////////////////////////////////////////// +// CConnectPage property page + +IMPLEMENT_DYNCREATE(CConnectPage, CPropertyPage) + +// Set page defaults. +///////////////////// +CConnectPage::CConnectPage() : CPropertyPage(CConnectPage::IDD) +{ + //{{AFX_DATA_INIT(CConnectPage) + m_nick = _T("PeerPlayer"); + m_title = _T("gmtest"); + m_groupRooms = FALSE; + m_key = _T("HA6zkS"); + //}}AFX_DATA_INIT +} + +CConnectPage::~CConnectPage() +{ +} + +void CConnectPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CConnectPage) + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_TITLE, m_title); + DDX_Check(pDX, IDC_GROUP_ROOMS, m_groupRooms); + DDX_Text(pDX, IDC_KEY, m_key); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CConnectPage, CPropertyPage) + //{{AFX_MSG_MAP(CConnectPage) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +// Used for printing callback info to the debug window. +/////////////////////////////////////////////////////// +static void PrintCallback(const char * callback) +{ + CString buffer; + buffer = callback; + buffer += " (callback)\n"; + OutputDebugString(buffer); +} +static void PrintStringParam(const char * param, const char * value) +{ + CString buffer; + buffer += " "; + buffer += param; + buffer += " = \""; + buffer += value; + buffer += "\"\n"; + OutputDebugString(buffer); +} +static void PrintIntParam(const char * param, int value) +{ + char string[16]; + sprintf(string, "%d", value); + PrintStringParam(param, string); +} +static void PrintBoolParam(const char * param, PEERBool value) +{ + if(value) + PrintStringParam(param, "True"); + else + PrintStringParam(param, "False"); +} +static void PrintRoomParam(const char * param, RoomType roomType) +{ + if(roomType == TitleRoom) + PrintStringParam("roomType", "Title Room"); + else if(roomType == GroupRoom) + PrintStringParam("roomType", "Group Room"); + else if(roomType == StagingRoom) + PrintStringParam("roomType", "Staging Room"); + else + PrintStringParam("roomType", ""); + + GSI_UNUSED(param); +} + +/////////////////////////// +// Peer Global Callbacks // +/////////////////////////// + +// Called if peer gets disconnected from chat. +////////////////////////////////////////////// +static void DisconnectedCallback +( + PEER peer, + const char * reason, + void * param +) +{ + PrintCallback("Disconnected"); + PrintStringParam("reason", reason); + + CString text = "You were disconnected from the server: "; + if(reason) + text += reason; + Wizard->MessageBox(text); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called when a message arrives in a room. +/////////////////////////////////////////// +static void RoomMessageCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * message, + MessageType messageType, + void * param +) +{ + PrintCallback("RoomMessage"); + PrintStringParam("nick", nick); + PrintStringParam("message", message); + + // Form the message. + //////////////////// + CString buffer; + if(messageType == NormalMessage) + buffer.Format("%s: %s", nick, message); + else if(messageType == ActionMessage) + buffer.Format("%s %s", nick, message); + else + buffer.Format("*%s* %s", nick, message); + + // Send it to the right place. + ////////////////////////////// + if(roomType == StagingRoom) + { + StagingPage->m_chatWindow.InsertString(-1, buffer); + StagingPage->m_chatWindow.SetTopIndex(StagingPage->m_chatWindow.GetCount() - 1); + } + else if((roomType == GroupRoom) || !Wizard->m_groupRooms) + { + GroupPage->m_chatWindow.InsertString(-1, buffer); + GroupPage->m_chatWindow.SetTopIndex(GroupPage->m_chatWindow.GetCount() - 1); + } + else + { + TitlePage->m_chatWindow.InsertString(-1, buffer); + TitlePage->m_chatWindow.SetTopIndex(TitlePage->m_chatWindow.GetCount() - 1); + } + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called when a staging room player's ready state changes. +/////////////////////////////////////////////////////////// +static void ReadyChangedCallback +( + PEER peer, + const char * nick, + PEERBool ready, + void * param +) +{ + PrintCallback("ReadyChanged"); + PrintStringParam("nick", nick); + PrintBoolParam("ready", ready); + + // Update his ready state. + ////////////////////////// + StagingPage->UpdatePlayerReady(nick, (BOOL)ready); + + // Check if we should enable the finish button. + /////////////////////////////////////////////// + if(Wizard->m_hosting) + StagingPage->CheckEnableFinish(); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called when the game launches in a staging room we've joined. +//////////////////////////////////////////////////////////////// +static void GameStartedCallback +( + PEER peer, + SBServer server, + const char * message, + void * param +) +{ + const char * address = SBServerGetPublicAddress(server); + + PrintCallback("GameStarted"); + PrintStringParam("IP", address); + PrintStringParam("message", message); + + char buffer[256]; + sprintf(buffer, + "The game has been started.\n" + "The host is at %s.\n" + "Message: %s\n" + "Hit OK to return to the staging room.", + address, + message); + StagingPage->MessageBox(buffer); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called when a player joins a room we're in. +////////////////////////////////////////////// +static void PlayerJoinedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + void * param +) +{ + PrintCallback("PlayerJoined"); + PrintRoomParam("roomType", roomType); + PrintStringParam("nick", nick); + + if(roomType == StagingRoom) + { + StagingPage->UpdatePlayerPing(nick, 9999); + + if(Wizard->m_hosting) + Wizard->SetWizardButtons(PSWIZB_BACK | PSWIZB_DISABLEDFINISH); + } + else if((roomType == GroupRoom) || !Wizard->m_groupRooms) + GroupPage->UpdatePlayerPing(nick, 9999); + else + TitlePage->UpdatePlayerPing(nick, 9999); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called when a player leaves a room we're in. +/////////////////////////////////////////////// +static void PlayerLeftCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * reason, + void * param +) +{ + PrintCallback("PlayerLeft"); + PrintRoomParam("roomType", roomType); + PrintStringParam("nick", nick); + + if(roomType == StagingRoom) + { + StagingPage->RemovePlayer(nick); + + if(Wizard->m_hosting) + StagingPage->CheckEnableFinish(); + } + else if((roomType == GroupRoom) || !Wizard->m_groupRooms) + GroupPage->RemovePlayer(nick); + else + TitlePage->RemovePlayer(nick); + + GSI_UNUSED(param); + GSI_UNUSED(reason); + GSI_UNUSED(peer); +} + +// Called when a player's nickname changes. +/////////////////////////////////////////// +static void PlayerChangedNickCallback +( + PEER peer, + RoomType roomType, + const char * oldNick, + const char * newNick, + void * param +) +{ + PrintCallback("PlayerChangedNick"); + PrintRoomParam("roomType", roomType); + PrintStringParam("oldNick", oldNick); + PrintStringParam("newNick", newNick); + + if(roomType == StagingRoom) + StagingPage->ChangePlayerNick(oldNick, newNick); + else if((roomType == GroupRoom) || !Wizard->m_groupRooms) + GroupPage->ChangePlayerNick(oldNick, newNick); + else + TitlePage->ChangePlayerNick(oldNick, newNick); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called whenever a new ping time is available. +//////////////////////////////////////////////// +static void PingCallback +( + PEER peer, + const char * nick, + int ping, + void * param +) +{ + PrintCallback("Ping"); + PrintStringParam("nick", nick); + PrintIntParam("ping", ping); + + if(Wizard->m_groupRooms && TitlePage->m_hWnd && TitlePage->FindPlayer(nick) != -1) + TitlePage->UpdatePlayerPing(nick, ping); + if(GroupPage->m_hWnd && GroupPage->FindPlayer(nick) != -1) + GroupPage->UpdatePlayerPing(nick, ping); + if(StagingPage->m_hWnd && StagingPage->FindPlayer(nick) != -1) + StagingPage->UpdatePlayerPing(nick, ping); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called whenever a crossping is available. +//////////////////////////////////////////// +static void CrossPingCallback +( + PEER peer, + const char * nick1, + const char * nick2, + int crossPing, + void * param +) +{ + PrintCallback("CrossPing"); + PrintStringParam("nick1", nick1); + PrintStringParam("nick2", nick2); + PrintIntParam("crossPing", crossPing); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Player info for server reporting. +//////////////////////////////////// +const int NumPlayers = 2; +const char * Players[] = { "Bob", "Joe" }; + +// Converts a key index to a string. +//////////////////////////////////// +static const char * KeyToString(int key) +{ + return qr2_registered_key_list[key]; +} + +// Converts a key type to a string. +/////////////////////////////////// +static const char * KeyTypeToString(qr2_key_type type) +{ + switch(type) + { + case key_server: + return "server"; + case key_player: + return "player"; + case key_team: + return "team"; + } + + ASSERT(0); + return "Unkown key type"; +} + +// Converts an error code to a string. +////////////////////////////////////// +static const char * ErrorTypeToString(qr2_error_t error) +{ + switch(error) + { + case e_qrnoerror: + return "noerror"; + case e_qrwsockerror: + return "wsockerror"; + case e_qrbinderror: + return "rbinderror"; + case e_qrdnserror: + return "dnserror"; + case e_qrconnerror: + return "connerror"; + } + + ASSERT(0); + return "Unknown error type"; +} + +// Reports server keys. +/////////////////////// +static void QRServerKeyCallback +( + PEER peer, + int key, + qr2_buffer_t buffer, + void * param +) +{ + PrintCallback("QRServerKey"); + PrintStringParam("key", KeyToString(key)); + + switch(key) + { + case GAMEVER_KEY: + qr2_buffer_add(buffer, "1.01"); + break; + case HOSTNAME_KEY: + qr2_buffer_add(buffer, (LPCSTR)CreatePage->m_name); + break; + case NUMPLAYERS_KEY: + qr2_buffer_add_int(buffer, NumPlayers); + break; + case MAXPLAYERS_KEY: + qr2_buffer_add_int(buffer, NumPlayers + 2); + break; + default: + qr2_buffer_add(buffer, ""); + break; + } + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Reports player keys. +/////////////////////// +static void QRPlayerKeyCallback +( + PEER peer, + int key, + int index, + qr2_buffer_t buffer, + void * param +) +{ + PrintCallback("QRPlayerKey"); + PrintStringParam("key", KeyToString(key)); + PrintIntParam("index", index); + + switch(key) + { + case PLAYER__KEY: + qr2_buffer_add(buffer, Players[index]); + break; + case PING__KEY: + qr2_buffer_add_int(buffer, rand() % 100); + break; + default: + qr2_buffer_add(buffer, ""); + break; + } + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Reports team keys. +///////////////////// +static void QRTeamKeyCallback +( + PEER peer, + int key, + int index, + qr2_buffer_t buffer, + void * param +) +{ + PrintCallback("QRTeamKey"); + PrintStringParam("key", KeyToString(key)); + PrintIntParam("index", index); + + // we don't report teams, so this shouldn't get called + qr2_buffer_add(buffer, ""); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Reports supported keys. +////////////////////////// +static void QRKeyListCallback +( + PEER peer, + qr2_key_type type, + qr2_keybuffer_t keyBuffer, + void * param +) +{ + PrintCallback("QRKeyList"); + PrintStringParam("type", KeyTypeToString(type)); + + // register the keys we use + switch(type) + { + case key_server: + qr2_keybuffer_add(keyBuffer, GAMEVER_KEY); + break; + case key_player: + // no custom player keys + break; + case key_team: + // no custom team keys + break; + } + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Reports the players and team counts. +/////////////////////////////////////// +static int QRCountCallback +( + PEER peer, + qr2_key_type type, + void * param +) +{ + PrintCallback("QRCount"); + PrintStringParam("type", KeyTypeToString(type)); + + if(type == key_player) + return NumPlayers; + else if(type == key_team) + return 0; + + return 0; + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Called when there is a server reporting error. +///////////////////////////////////////////////// +static void QRAddErrorCallback +( + PEER peer, + qr2_error_t error, + char * errorString, + void * param +) +{ + PrintCallback("QRKeyList"); + PrintStringParam("type", ErrorTypeToString(error)); + PrintStringParam("errorString", errorString); + + CString str; + str.Format("Peer: Server Reporting error: %s (%s)", ErrorTypeToString(error), errorString); + Wizard->MessageBox(str); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Switching to this page. +////////////////////////// +BOOL CConnectPage::OnSetActive() +{ + // Set which buttons the wizard shows. + ////////////////////////////////////// + Wizard->SetWizardButtons(PSWIZB_NEXT); + +//PEERSTART + if(Wizard->m_peer) + { + // Shutdown peer. + ///////////////// + peerShutdown(Wizard->m_peer); + Wizard->m_peer = NULL; + } +//PEERSTOP + + return CPropertyPage::OnSetActive(); +} + +// Called when peerConnect completes. +///////////////////////////////////// +static PEERBool connectSuccess; +static void ConnectCallback +( + PEER peer, + PEERBool success, + int failureReason, + void * param +) +{ + connectSuccess = success; + + if(!success) + ConnectPage->MessageBox("Failed to connect."); + + GSI_UNUSED(param); + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(failureReason); +} + +// Called if there's an error with the nick. +//////////////////////////////////////////// +static void NickErrorCallback +( + PEER peer, + int type, + const char * nick, + int numSuggestedNicks, + const char ** suggestedNicks, + void * param +) +{ + connectSuccess = PEERFalse; + + // Let the user know. + ///////////////////// + if(type == PEER_IN_USE) + ConnectPage->MessageBox("That nickname is already taken, please choose another one."); + else + ConnectPage->MessageBox("That nickname contains at least 1 invalid character, please choose another one."); + +//PEERSTART + // Cancel the connect. + // Could display a window here asking for an alternate nick. + //////////////////////////////////////////////////////////// + peerRetryWithNick(peer, NULL); +//PEERSTOP + + GSI_UNUSED(param); + GSI_UNUSED(suggestedNicks); + GSI_UNUSED(numSuggestedNicks); + GSI_UNUSED(nick); +} + +// Going to the next page. +////////////////////////// +LRESULT CConnectPage::OnWizardNext() +{ + // Check data. + ////////////// + UpdateData(); + Wizard->m_groupRooms = m_groupRooms; + if(m_nick == "") + { + MessageBox("You must enter a nickname."); + return -1; + } + if(m_title == "") + { + MessageBox("You must enter a title."); + return -1; + } + +//PEERSTART + // Check that the game's backend is available. + ////////////////////////////////////////////// + GSIACResult result; + GSIStartAvailableCheck(m_title); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + MessageBox("The backend is not available\n"); + return -1; + } + + // Setup the callbacks. + /////////////////////// + PEERCallbacks callbacks; + memset(&callbacks, 0, sizeof(PEERCallbacks)); + callbacks.disconnected = DisconnectedCallback; + callbacks.readyChanged = ReadyChangedCallback; + callbacks.roomMessage = RoomMessageCallback; + callbacks.gameStarted = GameStartedCallback; + callbacks.playerJoined = PlayerJoinedCallback; + callbacks.playerLeft = PlayerLeftCallback; + callbacks.playerChangedNick = PlayerChangedNickCallback; + callbacks.ping = PingCallback; + callbacks.crossPing = CrossPingCallback; + callbacks.qrServerKey = QRServerKeyCallback; + callbacks.qrPlayerKey = QRPlayerKeyCallback; + callbacks.qrTeamKey = QRTeamKeyCallback; + callbacks.qrKeyList = QRKeyListCallback; + callbacks.qrCount = QRCountCallback; + callbacks.qrAddError = QRAddErrorCallback; + callbacks.param = NULL; + + // Init peer. + ///////////// + Wizard->m_peer = peerInitialize(&callbacks); + if(!Wizard->m_peer) + { + MessageBox("Error initializing peer."); + return -1; + } + + // Setup which rooms to do pings and cross-pings in. + //////////////////////////////////////////////////// + PEERBool pingRooms[NumRooms]; + PEERBool crossPingRooms[NumRooms]; + pingRooms[TitleRoom] = PEERFalse; + pingRooms[GroupRoom] = PEERTrue; + pingRooms[StagingRoom] = PEERTrue; + crossPingRooms[TitleRoom] = PEERFalse; + crossPingRooms[GroupRoom] = PEERFalse; + crossPingRooms[StagingRoom] = PEERTrue; + + // Set the title. + ///////////////// + if(!peerSetTitle(Wizard->m_peer, m_title, m_key, m_title, m_key, 0, 30, PEERFalse, pingRooms, crossPingRooms)) + { + MessageBox("Error setting title."); + peerShutdown(Wizard->m_peer); + Wizard->m_peer = NULL; + return -1; + } + + // Connect to chat. + /////////////////// + Wizard->StartHourglass(); + peerConnect(Wizard->m_peer, m_nick, 0, NickErrorCallback, ConnectCallback, NULL, PEERTrue); + Wizard->StopHourglass(); + if(!connectSuccess) + { + MessageBox("Error connecting."); + peerShutdown(Wizard->m_peer); + Wizard->m_peer = NULL; + return -1; + } +//PEERSTOP + + if(!m_groupRooms) + return IDD_GROUP_PAGE; + + return CPropertyPage::OnWizardNext(); +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/ConnectPage.h b/xrGameSpy/gamespy/Peer/PeerLobby/ConnectPage.h new file mode 100644 index 00000000000..e4b6c9861e5 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/ConnectPage.h @@ -0,0 +1,57 @@ +#if !defined(AFX_CONNECTPAGE_H__70C3619F_ED14_49F8_9155_9F96147FF4C2__INCLUDED_) +#define AFX_CONNECTPAGE_H__70C3619F_ED14_49F8_9155_9F96147FF4C2__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ConnectPage.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CConnectPage dialog + +class CConnectPage : public CPropertyPage +{ + DECLARE_DYNCREATE(CConnectPage) + +// Construction +public: + CConnectPage(); + ~CConnectPage(); + +// Dialog Data + //{{AFX_DATA(CConnectPage) + enum { IDD = IDD_CONNECT_PAGE }; + CString m_nick; + CString m_title; + BOOL m_groupRooms; + CString m_key; + //}}AFX_DATA + + +// Overrides + // ClassWizard generate virtual function overrides + //{{AFX_VIRTUAL(CConnectPage) + public: + virtual BOOL OnSetActive(); + virtual LRESULT OnWizardNext(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CConnectPage) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +extern CConnectPage * ConnectPage; + +#endif // !defined(AFX_CONNECTPAGE_H__70C3619F_ED14_49F8_9155_9F96147FF4C2__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/CreatePage.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/CreatePage.cpp new file mode 100644 index 00000000000..473352bda55 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/CreatePage.cpp @@ -0,0 +1,115 @@ +// CreatePage.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "CreatePage.h" +#include "LobbyWizard.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CCreatePage * CreatePage; + +///////////////////////////////////////////////////////////////////////////// +// CCreatePage property page + +IMPLEMENT_DYNCREATE(CCreatePage, CPropertyPage) + +// Set page defaults. +///////////////////// +CCreatePage::CCreatePage() : CPropertyPage(CCreatePage::IDD) +{ + //{{AFX_DATA_INIT(CCreatePage) + m_name = _T("My Server"); + m_maxPlayers = 8; + //}}AFX_DATA_INIT +} + +CCreatePage::~CCreatePage() +{ +} + +void CCreatePage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CCreatePage) + DDX_Text(pDX, IDC_NAME, m_name); + DDX_Text(pDX, IDC_MAX_PLAYERS, m_maxPlayers); + DDV_MinMaxInt(pDX, m_maxPlayers, 2, 9999); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CCreatePage, CPropertyPage) + //{{AFX_MSG_MAP(CCreatePage) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +// Switching to this page. +////////////////////////// +BOOL CCreatePage::OnSetActive() +{ + // Show the back and next buttons. + ////////////////////////////////// + Wizard->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT); + + // We're hosting the room. + ////////////////////////// + Wizard->m_hosting = TRUE; + + return CPropertyPage::OnSetActive(); +} + +// Going to the previous page. +////////////////////////////// +LRESULT CCreatePage::OnWizardBack() +{ + // Not hosting anymore. + /////////////////////// + Wizard->m_hosting = FALSE; + + return CPropertyPage::OnWizardBack(); +} + +// Called when the staging room has been created (or the attempt failed). +///////////////////////////////////////////////////////////////////////// +static PEERBool createStagingSuccess; +static void CreateStagingRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + createStagingSuccess = success; + + GSI_UNUSED(param); + GSI_UNUSED(roomType); + GSI_UNUSED(result); + GSI_UNUSED(peer); +} + +// Going to the next page. +////////////////////////// +LRESULT CCreatePage::OnWizardNext() +{ + // Update the data. + /////////////////// + UpdateData(); + +//PEERSTART + // Create the room. + /////////////////// + Wizard->StartHourglass(); + peerCreateStagingRoom(Wizard->m_peer, m_name, m_maxPlayers, NULL, CreateStagingRoomCallback, NULL, PEERTrue); + Wizard->StopHourglass(); +//PEERSTOP + + return CPropertyPage::OnWizardNext(); +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/CreatePage.h b/xrGameSpy/gamespy/Peer/PeerLobby/CreatePage.h new file mode 100644 index 00000000000..7c08ec3a3ba --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/CreatePage.h @@ -0,0 +1,55 @@ +#if !defined(AFX_CREATEPAGE_H__4FC1C8CA_9B4C_47F6_B226_C211DC74D504__INCLUDED_) +#define AFX_CREATEPAGE_H__4FC1C8CA_9B4C_47F6_B226_C211DC74D504__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// CreatePage.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CCreatePage dialog + +class CCreatePage : public CPropertyPage +{ + DECLARE_DYNCREATE(CCreatePage) + +// Construction +public: + CCreatePage(); + ~CCreatePage(); + +// Dialog Data + //{{AFX_DATA(CCreatePage) + enum { IDD = IDD_CREATE_PAGE }; + CString m_name; + int m_maxPlayers; + //}}AFX_DATA + + +// Overrides + // ClassWizard generate virtual function overrides + //{{AFX_VIRTUAL(CCreatePage) + public: + virtual BOOL OnSetActive(); + virtual LRESULT OnWizardBack(); + virtual LRESULT OnWizardNext(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CCreatePage) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +extern CCreatePage * CreatePage; + +#endif // !defined(AFX_CREATEPAGE_H__4FC1C8CA_9B4C_47F6_B226_C211DC74D504__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/GroupPage.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/GroupPage.cpp new file mode 100644 index 00000000000..7defec5e341 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/GroupPage.cpp @@ -0,0 +1,668 @@ +// GroupPage.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "GroupPage.h" +#include "LobbyWizard.h" +#include "ConnectPage.h" +#include "TitlePage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CGroupPage * GroupPage; + +#define COL_NAME 0 +#define COL_PING 1 +#define COL_RUNNING 2 +#define COL_NUM_PLAYERS 3 + +///////////////////////////////////////////////////////////////////////////// +// CGroupPage property page + +IMPLEMENT_DYNCREATE(CGroupPage, CPropertyPage) + +// Set page defaults. +///////////////////// +CGroupPage::CGroupPage() : CPropertyPage(CGroupPage::IDD) +{ + //{{AFX_DATA_INIT(CGroupPage) + m_message = _T(""); + //}}AFX_DATA_INIT +} + +CGroupPage::~CGroupPage() +{ +} + +void CGroupPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGroupPage) + DDX_Control(pDX, IDC_PLAYERS, m_players); + DDX_Control(pDX, IDC_GAMES, m_games); + DDX_Control(pDX, IDC_CHAT_WINDOW, m_chatWindow); + DDX_Control(pDX, IDC_PROGRESS, m_progress); + DDX_Text(pDX, IDC_MESSAGE, m_message); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CGroupPage, CPropertyPage) + //{{AFX_MSG_MAP(CGroupPage) + ON_BN_CLICKED(IDC_CREATE, OnCreate) + ON_NOTIFY(NM_CLICK, IDC_GAMES, OnClickGames) + ON_NOTIFY(LVN_BEGINDRAG, IDC_GAMES, OnBegindragGames) + ON_NOTIFY(NM_DBLCLK, IDC_GAMES, OnDblclkGames) + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +// Gets called to maintain the game list. +///////////////////////////////////////// +static void ListingGamesCallback +( + PEER peer, + PEERBool success, + const char * name, + SBServer server, + PEERBool staging, + int msg, + int progress, + void * param +) +{ + LVITEM item; + + // Check for failure. + ///////////////////// + if(!success) + { + Wizard->MessageBox("Listing games failed!"); + Wizard->EndDialog(IDOK); + return; + } + + // Cache pointers. + ////////////////// + CListCtrl * games = &GroupPage->m_games; + CListedGame * game = NULL; + BOOL doUpdate = FALSE; + int nIndex = -1; + + // Set the progress. + //////////////////// + GroupPage->m_progress.SetPos(progress); + + // Handle the message based on its type. + //////////////////////////////////////// + if(msg == PEER_CLEAR) + { + GroupPage->ClearGames(); + } + else if(msg == PEER_ADD) + { + // Add this to the list. + //////////////////////// + game = new CListedGame; + game->server = server; + game->name = name; + game->staging = staging; + game->ping = SBServerGetPing(server); + game->numPlayers = SBServerGetIntValue(server, "numplayers", 0); + game->maxPlayers = SBServerGetIntValue(server, "maxplayers", 0); + + nIndex = games->InsertItem(LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE, + 0, + (LPCTSTR)name, + 0, 0, + staging ? Wizard->m_stagingRoomIndex : Wizard->m_runningGameIndex, + (LPARAM)game); + if(nIndex == -1) + { + delete game; + return; + } + + doUpdate = TRUE; + } + else if(msg == PEER_UPDATE) + { + nIndex = GroupPage->FindListedGame(server); + if(nIndex != -1) + { + // Update values. + ///////////////// + game = (CListedGame *)games->GetItemData(nIndex); + game->name = name; + game->staging = staging; + game->ping = SBServerGetPing(server); + game->numPlayers = SBServerGetIntValue(server, "numplayers", 0); + game->maxPlayers = SBServerGetIntValue(server, "maxplayers", 0); + + // Update the list. + /////////////////// + item.mask = LVIF_IMAGE; + item.iItem = nIndex; + item.iSubItem = 0; + item.iImage = staging ? Wizard->m_stagingRoomIndex : Wizard->m_runningGameIndex; + games->SetItem(&item); + + doUpdate = TRUE; + } + } + else if(msg == PEER_REMOVE) + { + nIndex = GroupPage->FindListedGame(server); + if(nIndex != -1) + { + delete (CListedGame *)games->GetItemData(nIndex); + games->DeleteItem(nIndex); + } + } + + if(doUpdate) + { + item.mask = LVIF_TEXT; + item.iItem = nIndex; + item.iSubItem = COL_PING; + char buffer[32]; + sprintf(buffer, "%d", game->ping); + item.pszText = buffer; + games->SetItem(&item); + item.iSubItem = COL_RUNNING; + if(staging) + item.pszText = "No"; + else + item.pszText = "Yes"; + games->SetItem(&item); + item.iSubItem = COL_NUM_PLAYERS; + sprintf(buffer, "%d/%d", game->numPlayers, game->maxPlayers); + item.pszText = buffer; + games->SetItem(&item); + } + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +// Used to list the players in the room. +//////////////////////////////////////// +static void EnumPlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const char * nick, + int flags, + void * param +) +{ + if(!success) + { + Wizard->MessageBox("Error listing players."); + return; + } + + if(index == -1) + return; + + GroupPage->UpdatePlayerPing(nick, 9999); + + GSI_UNUSED(param); + GSI_UNUSED(flags); + GSI_UNUSED(roomType); + GSI_UNUSED(peer); +} + +static PEERBool joinSuccess; +static void JoinTitleRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + joinSuccess = success; + + if(success) + { +//PEERSTART + // List the players in the room. + //////////////////////////////// + peerEnumPlayers(Wizard->m_peer, TitleRoom, EnumPlayersCallback, NULL); +//PEERSTOP + } + + GSI_UNUSED(param); + GSI_UNUSED(roomType); + GSI_UNUSED(result); + GSI_UNUSED(peer); +} + +// Switching to this page. +////////////////////////// +BOOL CGroupPage::OnSetActive() +{ + // Start off with only a back button. + ///////////////////////////////////// + Wizard->SetWizardButtons(PSWIZB_BACK); + + // Rename the next button. + ////////////////////////// + ::SetWindowText(Wizard->m_nextButtonWnd, "&Join >"); + + // Clear the progress bar. + ////////////////////////// + m_progress.SetPos(0); + + // Clear the game list. + /////////////////////// + ClearGames(); + + // Clear the chat log. + ////////////////////// + m_chatWindow.ResetContent(); + +//PEERSTART + if(!Wizard->m_groupRooms) + { + // Join the title room. + /////////////////////// + Wizard->StartHourglass(); + peerJoinTitleRoom(Wizard->m_peer, NULL, JoinTitleRoomCallback, NULL, PEERTrue); + Wizard->StopHourglass(); + if(!joinSuccess) + { + MessageBox("Error joining the title room."); + return FALSE; + } + } + else + { + // List the players in the room. + //////////////////////////////// + peerEnumPlayers(Wizard->m_peer, GroupRoom, EnumPlayersCallback, NULL); + } + + // Start listing games. + //////////////////////// + unsigned char fields[] = { GAMEVER_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY }; + peerStartListingGames(Wizard->m_peer, fields, sizeof(fields), NULL, ListingGamesCallback, NULL); +//PEERSTOP + + // Setup the player's box columns. + ////////////////////////////////// + if(Wizard->m_groupRooms) + { + m_players.InsertColumn(COL_NAME, "Player", LVCFMT_LEFT, 70); + m_players.InsertColumn(COL_PING, "Ping", LVCFMT_LEFT, 50); + } + else + m_players.InsertColumn(COL_NAME, "Player", LVCFMT_LEFT, 120); + + return CPropertyPage::OnSetActive(); +} + +// Leaving this page. +///////////////////// +BOOL CGroupPage::OnKillActive() +{ +//PEERSTART + if(!Wizard->m_groupRooms) + peerLeaveRoom(Wizard->m_peer, TitleRoom, NULL); +//PEERSTOP + + // Delete player columns. + ///////////////////////// + m_players.DeleteColumn(0); + if(Wizard->m_groupRooms) + m_players.DeleteColumn(1); + + // Reset the "next" button's name. + ////////////////////////////////// + ::SetWindowText(Wizard->m_nextButtonWnd, "&Next >"); + + // Clear the players. + ///////////////////// + m_players.DeleteAllItems(); + + return CPropertyPage::OnKillActive(); +} + +// Going to the next page. +////////////////////////// +LRESULT CGroupPage::OnWizardNext() +{ + // Update vars. + /////////////// + UpdateData(); + + // Make sure something was selected. + //////////////////////////////////// + int nIndex = m_games.GetSelectionMark(); + if(nIndex == -1) + { + MessageBox("You must have a game selected."); + return -1; + } + + // Join the game. + ///////////////// + JoinGame(nIndex); + + return (LRESULT)1; +} + +LRESULT CGroupPage::OnWizardBack() +{ +//PEERSTART + // Leave the group room. + //////////////////////// + if(Wizard->m_groupRooms) + peerLeaveRoom(Wizard->m_peer, GroupRoom, NULL); + else + return IDD_CONNECT_PAGE; +//PEERSTOP + + return CPropertyPage::OnWizardBack(); +} + +// Init the page. +///////////////// +BOOL CGroupPage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + // Set the games columns. + ///////////////////////// + m_games.InsertColumn(COL_NAME, "Server Name", LVCFMT_LEFT, 170); + m_games.InsertColumn(COL_PING, "Ping", LVCFMT_LEFT, 50); + m_games.InsertColumn(COL_RUNNING, "Running", LVCFMT_LEFT, 60); + m_games.InsertColumn(COL_NUM_PLAYERS, "Num Players", LVCFMT_LEFT, 75); + ListView_SetExtendedListViewStyle(m_games.m_hWnd,LVS_EX_FULLROWSELECT); + + // Image list setup. + //////////////////// + m_games.SetImageList(&Wizard->m_imageList, LVSIL_SMALL); + + return TRUE; +} + +// Cleanup the page. +//////////////////// +void CGroupPage::OnDestroy() +{ + CPropertyPage::OnDestroy(); + + // Clear the game list. + /////////////////////// + ClearGames(); +} + +// Clear the list of games. +/////////////////////////// +void CGroupPage::ClearGames() +{ + // Free the data first. + /////////////////////// + int count = m_games.GetItemCount(); + int i; + for(i = 0 ; i < count ; i++) + { + LVITEM item; + item.mask = LVIF_PARAM; + item.iItem = i; + item.iSubItem = 0; + if(m_games.GetItem(&item) && item.lParam) + delete (CListedGame *)item.lParam; + } + + // Clear the list. + ////////////////// + m_games.DeleteAllItems(); +} + +// Create a staging room. +///////////////////////// +void CGroupPage::OnCreate() +{ +//PEERSTART + // Stop listing games. + ////////////////////// + peerStopListingGames(Wizard->m_peer); +//PEERSTOP + + // Goto the create page. + //////////////////////// + Wizard->SetActivePage(CREATE_PAGE); +} + +// Join a game. +/////////////// +void CGroupPage::OnDblclkGames(NMHDR* pNMHDR, LRESULT* pResult) +{ + NMHEADER * header = (NMHEADER *)pNMHDR; + + // If something was double-clicked, join it. + //////////////////////////////////////////// + if(header->iItem != -1) + JoinGame(header->iItem); + + *pResult = 0; +} + +// Handle game list clicks. +/////////////////////////// +void CGroupPage::OnClickGames(NMHDR* pNMHDR, LRESULT* pResult) +{ + // Enable/Disable join based on if something is selected. + ///////////////////////////////////////////////////////// + BOOL enable = (m_games.GetSelectedCount() > 0); + ::EnableWindow(Wizard->m_nextButtonWnd, enable); + + *pResult = 0; + + GSI_UNUSED(pNMHDR); +} +void CGroupPage::OnBegindragGames(NMHDR* pNMHDR, LRESULT* pResult) +{ + // Treat this like a click. + // (OnClick() isn't called for "drags". + /////////////////////////////////////// + OnClickGames(pNMHDR, pResult); +} + +// Find the index of a game in the list by its SBServer object. +/////////////////////////////////////////////////////////////// +int CGroupPage::FindListedGame(SBServer server) +{ + int count = m_games.GetItemCount(); + int i; + CListedGame * game; + for(i = 0 ; i < count ; i++) + { + game = (CListedGame *)m_games.GetItemData(i); + if(game && game->server == server) + return i; + } + return -1; +} + +// Find the index of a player in the list by its nick. +////////////////////////////////////////////////////// +int CGroupPage::FindPlayer(const char * nick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Look for this player. + //////////////////////// + LVFINDINFO findInfo; + findInfo.flags = LVFI_STRING; + findInfo.psz = nick; + + // Find the player. + /////////////////// + int nIndex = m_players.FindItem(&findInfo); + + return nIndex; +} + +// Updates the player's ping in the player list, and adds the player +// if its not on the list. +//////////////////////////////////////////////////////////////////// +void CGroupPage::UpdatePlayerPing(const char * nick, int ping) +{ + LVITEM item; + + // Is this us? + ////////////// + if(strcasecmp(nick, ConnectPage->m_nick) == 0) + ping = 0; + + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Check for a new nick. + //////////////////////// + if(nIndex == -1) + { + item.iItem = 0; + item.iSubItem = 0; + item.mask = LVIF_TEXT; + item.pszText = (char *)nick; + + nIndex = m_players.InsertItem(&item); + if(nIndex == -1) + return; + } + + // Add the ping. + //////////////// + char intValue[16]; + sprintf(intValue, "%d", ping); + item.iItem = nIndex; + item.iSubItem = 1; + item.mask = LVIF_TEXT; + item.pszText = intValue; + m_players.SetItem(&item); +} + +// Remove the player from the list. +/////////////////////////////////// +void CGroupPage::RemovePlayer(const char * nick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Remove it. + ///////////// + m_players.DeleteItem(nIndex); +} + +// Change a nick in the player list. +//////////////////////////////////// +void CGroupPage::ChangePlayerNick(const char * oldNick, const char * newNick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = oldNick; + loweredNick.MakeLower(); + oldNick = loweredNick; + loweredNick = newNick; + loweredNick.MakeLower(); + newNick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(oldNick); + + // Update the nick. + /////////////////// + LVITEM item; + item.iItem = nIndex; + item.iSubItem = 0; + item.mask = LVIF_TEXT; + item.pszText = (char *)newNick; + m_players.SetItem(&item); +} + +// Join a game based on its index in the game list. +/////////////////////////////////////////////////// +void CGroupPage::JoinGame(int nIndex) +{ + // Get the data. + //////////////// + CListedGame * game = (CListedGame *)m_games.GetItemData(nIndex); + ASSERT(game); + + // Is it staging? + ///////////////// + if(game->staging) + { + // Goto the staging room page. + ////////////////////////////// + Wizard->SetActivePage(STAGING_PAGE); + } + else + { +//PEERSTART + // Because there's no staging room for this game, it can just be joined. + // You can get info on the server using the GOA ServerGet*() functions. + //////////////////////////////////////////////////////////////////////// + CString buffer = "You are now playing at "; + buffer += SBServerGetPublicAddress(game->server); + buffer += ".\nHit enter when you are done."; + MessageBox(buffer); +//PEERSTOP + } +} + +// Does the actual chat message sending. +//////////////////////////////////////// +void CGroupPage::SendMessage() +{ + UpdateData(); + + // Ignore blank message. + //////////////////////// + if(m_message == "") + return; + +//PEERSTART + // Send it. + /////////// + peerMessageRoom(Wizard->m_peer, Wizard->m_groupRooms?GroupRoom:TitleRoom, m_message, NormalMessage); +//PEERSTOP + + // Clear it. + //////////// + m_message = ""; + + UpdateData(FALSE); +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/GroupPage.h b/xrGameSpy/gamespy/Peer/PeerLobby/GroupPage.h new file mode 100644 index 00000000000..4c8bca84e98 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/GroupPage.h @@ -0,0 +1,88 @@ +#if !defined(AFX_GROUPPAGE_H__BC96C600_E6B9_49FF_8E49_75A013B824B2__INCLUDED_) +#define AFX_GROUPPAGE_H__BC96C600_E6B9_49FF_8E49_75A013B824B2__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// GroupPage.h : header file +// + +#include "../peer.h" + +///////////////////////////////////////////////////////////////////////////// +// CGroupPage dialog + +struct CListedGame +{ + SBServer server; + CString name; + PEERBool staging; + int ping; + int numPlayers; + int maxPlayers; +}; + +class CGroupPage : public CPropertyPage +{ + DECLARE_DYNCREATE(CGroupPage) + +// Construction +public: + CGroupPage(); + ~CGroupPage(); + +// Dialog Data + //{{AFX_DATA(CGroupPage) + enum { IDD = IDD_GROUP_PAGE }; + CListCtrl m_players; + CListCtrl m_games; + CListBox m_chatWindow; + CProgressCtrl m_progress; + CButton m_sendButton; + CString m_message; + //}}AFX_DATA + + void ClearGames(); + int FindListedGame(SBServer server); + + int FindPlayer(const char * nick); + void UpdatePlayerPing(const char * nick, int ping); + void RemovePlayer(const char * nick); + void ChangePlayerNick(const char * oldNick, const char * newNick); + + void JoinGame(int nIndex); + + void SendMessage(); + +// Overrides + // ClassWizard generate virtual function overrides + //{{AFX_VIRTUAL(CGroupPage) + public: + virtual BOOL OnSetActive(); + virtual LRESULT OnWizardNext(); + virtual BOOL OnKillActive(); + virtual LRESULT OnWizardBack(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CGroupPage) + virtual BOOL OnInitDialog(); + afx_msg void OnCreate(); + afx_msg void OnClickGames(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBegindragGames(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDblclkGames(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +extern CGroupPage * GroupPage; + +#endif // !defined(AFX_GROUPPAGE_H__BC96C600_E6B9_49FF_8E49_75A013B824B2__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/LobbyWizard.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/LobbyWizard.cpp new file mode 100644 index 00000000000..ac720e0f0cd --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/LobbyWizard.cpp @@ -0,0 +1,200 @@ +// LobbyWizard.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "LobbyWizard.h" +#include "GroupPage.h" +#include "StagingPage.h" +#include "TitlePage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CLobbyWizard * Wizard; + +#define THINK_TIMER 100 + +///////////////////////////////////////////////////////////////////////////// +// CLobbyWizard + +IMPLEMENT_DYNAMIC(CLobbyWizard, CPropertySheet) + +CLobbyWizard::CLobbyWizard(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + :CPropertySheet(nIDCaption, pParentWnd, iSelectPage) +{ +//PEERSTART + // Initialize our peer pointer to NULL. + /////////////////////////////////////// + m_peer = NULL; +//PEERSTOP +} + +CLobbyWizard::CLobbyWizard(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) + :CPropertySheet(pszCaption, pParentWnd, iSelectPage) +{ +//PEERSTART + // Initialize our peer pointer to NULL. + /////////////////////////////////////// + m_peer = NULL; +//PEERSTOP +} + +CLobbyWizard::~CLobbyWizard() +{ +} + + +BEGIN_MESSAGE_MAP(CLobbyWizard, CPropertySheet) + //{{AFX_MSG_MAP(CLobbyWizard) + ON_WM_TIMER() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLobbyWizard message handlers + +// Init the wizard. +/////////////////// +BOOL CLobbyWizard::OnInitDialog() +{ + BOOL bResult = CPropertySheet::OnInitDialog(); + + // Get the "next" button wnd. + ///////////////////////////// + m_nextButtonWnd = ::FindWindowEx(this->m_hWnd, NULL, "Button", "&Next >"); + + // Rename "Cancel" to "Quit". + ///////////////////////////// + HWND hWnd = ::FindWindowEx(this->m_hWnd, NULL, "Button", "Cancel"); + if(hWnd) + ::SetWindowText(hWnd, "&Quit"); + + // Hide the "Help" button. + ////////////////////////// + hWnd = ::FindWindowEx(this->m_hWnd, NULL, "Button", "Help"); + if(hWnd) + ::ShowWindow(hWnd, SW_HIDE); + + // Load icons. + ////////////// + m_greenSmileyIcon = AfxGetApp()->LoadIcon(IDI_GREEN_SMILEY); + m_yellowSmileyIcon = AfxGetApp()->LoadIcon(IDI_YELLOW_SMILEY); + m_redSmileyIcon = AfxGetApp()->LoadIcon(IDI_RED_SMILEY); + m_stagingRoomIcon = AfxGetApp()->LoadIcon(IDI_STAGING_ROOM); + m_runningGameIcon = AfxGetApp()->LoadIcon(IDI_RUNNING_GAME); + if(!m_greenSmileyIcon || !m_yellowSmileyIcon || !m_redSmileyIcon || !m_stagingRoomIcon || !m_runningGameIcon) + return FALSE; + + // Create the image list. + ///////////////////////// + if(!m_imageList.Create(16, 16, ILC_COLOR, 5, 5)) + return FALSE; + m_greenSmileyIndex = m_imageList.Add(m_greenSmileyIcon); + m_yellowSmileyIndex = m_imageList.Add(m_yellowSmileyIcon); + m_redSmileyIndex = m_imageList.Add(m_redSmileyIcon); + m_stagingRoomIndex = m_imageList.Add(m_stagingRoomIcon); + m_runningGameIndex = m_imageList.Add(m_runningGameIcon); + if((m_yellowSmileyIndex == -1) || (m_redSmileyIndex == -1) || (m_greenSmileyIndex == -1) || (m_runningGameIndex == -1) || (m_stagingRoomIndex == -1)) + return FALSE; + +//PEERSTART + // We're not hosting. + ///////////////////// + m_hosting = FALSE; + + // Set the timer for every 10 seconds. + ////////////////////////////////////// + SetTimer(THINK_TIMER, 10, NULL); +//PEERSTOP + + return bResult; +} + +// Think every 10ms. +//////////////////// +void CLobbyWizard::OnTimer(UINT nIDEvent) +{ + if(nIDEvent == THINK_TIMER) + { +//PEERSTART + // Let peer think. + ////////////////// + if(m_peer) + peerThink(m_peer); +//PEERSTOP + } + + CPropertySheet::OnTimer(nIDEvent); +} + +// Show the hourglass. +////////////////////// +void CLobbyWizard::StartHourglass() +{ + // Load the hourglass. + ////////////////////// + HCURSOR hourglass = LoadCursor(NULL, IDC_WAIT); + if(!hourglass) + return; + + // Set the cursor. + ////////////////// + m_lastCursor = SetCursor(hourglass); +} + +// Back to normal pointer. +////////////////////////// +void CLobbyWizard::StopHourglass() +{ + // Reset the old cursor. + //////////////////////// + SetCursor(m_lastCursor); +} + +// Catch [Enter] when pressed in a chat message box. +//////////////////////////////////////////////////// +BOOL CLobbyWizard::PreTranslateMessage(MSG* pMsg) +{ + // Check for enter. + /////////////////// + if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == 0x0d)) + { + // Check what page we're on. + ///////////////////////////// + int page = GetActiveIndex(); + CWnd * focus; + if(page == TITLE_PAGE) + { + focus = TitlePage->GetFocus(); + if(focus->m_hWnd == TitlePage->GetDlgItem(IDC_MESSAGE)->m_hWnd) + { + TitlePage->SendMessage(); + return TRUE; + } + } + else if(page == GROUP_PAGE) + { + focus = GroupPage->GetFocus(); + if(focus->m_hWnd == GroupPage->GetDlgItem(IDC_MESSAGE)->m_hWnd) + { + GroupPage->SendMessage(); + return TRUE; + } + } + else if(page == STAGING_PAGE) + { + focus = StagingPage->GetFocus(); + if(focus->m_hWnd == StagingPage->GetDlgItem(IDC_MESSAGE)->m_hWnd) + { + StagingPage->SendMessage(); + return TRUE; + } + } + } + + return CPropertySheet::PreTranslateMessage(pMsg); +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/LobbyWizard.h b/xrGameSpy/gamespy/Peer/PeerLobby/LobbyWizard.h new file mode 100644 index 00000000000..9fe58b4d8ad --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/LobbyWizard.h @@ -0,0 +1,84 @@ +#if !defined(AFX_LOBBYWIZARD_H__683E0CE1_CBA4_46D1_948A_6047481CDBF6__INCLUDED_) +#define AFX_LOBBYWIZARD_H__683E0CE1_CBA4_46D1_948A_6047481CDBF6__INCLUDED_ + +#include "../peer.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LobbyWizard.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLobbyWizard + +#define CONNECT_PAGE 0 +#define TITLE_PAGE 1 +#define GROUP_PAGE 2 +#define CREATE_PAGE 3 +#define STAGING_PAGE 4 + +class CLobbyWizard : public CPropertySheet +{ + DECLARE_DYNAMIC(CLobbyWizard) + +// Construction +public: + CLobbyWizard(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + CLobbyWizard(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + +// Attributes +public: + PEER m_peer; // The peer object. + BOOL m_hosting; // TRUE if hosting a game. + BOOL m_groupRooms; // TRUE if using group rooms. + + HWND m_nextButtonWnd; + + HICON m_greenSmileyIcon; + int m_greenSmileyIndex; + HICON m_yellowSmileyIcon; + int m_yellowSmileyIndex; + HICON m_redSmileyIcon; + int m_redSmileyIndex; + HICON m_stagingRoomIcon; + int m_stagingRoomIndex; + HICON m_runningGameIcon; + int m_runningGameIndex; + CImageList m_imageList; + + HCURSOR m_lastCursor; + +// Operations +public: + void StartHourglass(); + void StopHourglass(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLobbyWizard) + public: + virtual BOOL OnInitDialog(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CLobbyWizard(); + + // Generated message map functions +protected: + //{{AFX_MSG(CLobbyWizard) + afx_msg void OnTimer(UINT nIDEvent); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +extern CLobbyWizard * Wizard; + +#endif // !defined(AFX_LOBBYWIZARD_H__683E0CE1_CBA4_46D1_948A_6047481CDBF6__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.cpp new file mode 100644 index 00000000000..c2cb4a246a1 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.cpp @@ -0,0 +1,101 @@ +// PeerLobby.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "ConnectPage.h" +#include "TitlePage.h" +#include "GroupPage.h" +#include "CreatePage.h" +#include "StagingPage.h" +#include "LobbyWizard.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPeerLobbyApp + +BEGIN_MESSAGE_MAP(CPeerLobbyApp, CWinApp) + //{{AFX_MSG_MAP(CPeerLobbyApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPeerLobbyApp construction + +CPeerLobbyApp::CPeerLobbyApp() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CPeerLobbyApp object + +CPeerLobbyApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CPeerLobbyApp initialization + +BOOL CPeerLobbyApp::InitInstance() +{ + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + // Setup the wizard. + //////////////////// + CLobbyWizard wizard("Peer Lobby"); + Wizard = &wizard; + CConnectPage connectPage; + ConnectPage = &connectPage; + CTitlePage titlePage; + TitlePage = &titlePage; + CGroupPage groupPage; + GroupPage = &groupPage; + CCreatePage createPage; + CreatePage = &createPage; + CStagingPage stagingPage; + StagingPage = &stagingPage; + wizard.AddPage(ConnectPage); + wizard.AddPage(TitlePage); + wizard.AddPage(GroupPage); + wizard.AddPage(CreatePage); + wizard.AddPage(StagingPage); + wizard.SetWizardMode(); + + // Main loop. + ///////////// + wizard.DoModal(); + +//PEERSTART + // Shutdown peer. + ///////////////// + if(wizard.m_peer) + peerShutdown(wizard.m_peer); +//PEERSTOP + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.dsp b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.dsp new file mode 100644 index 00000000000..572d693ae61 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.dsp @@ -0,0 +1,673 @@ +# Microsoft Developer Studio Project File - Name="PeerLobby" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=PeerLobby - 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 "PeerLobby.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 "PeerLobby.mak" CFG="PeerLobby - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PeerLobby - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "PeerLobby - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Peer/PeerLobby", MDWAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +# PROP BASE Use_MFC 5 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# 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 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# 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 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 /ignore:4089 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# PROP BASE Use_MFC 5 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# 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 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "IRC_LOG" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# 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 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "PeerLobby - Win32 Release" +# Name "PeerLobby - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ConnectPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\CreatePage.cpp +# End Source File +# Begin Source File + +SOURCE=.\GroupPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\LobbyWizard.cpp +# End Source File +# Begin Source File + +SOURCE=.\PeerLobby.cpp +# End Source File +# Begin Source File + +SOURCE=.\PeerLobby.rc +# End Source File +# Begin Source File + +SOURCE=.\StagingPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\TitlePage.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ConnectPage.h +# End Source File +# Begin Source File + +SOURCE=.\CreatePage.h +# End Source File +# Begin Source File + +SOURCE=.\GroupPage.h +# End Source File +# Begin Source File + +SOURCE=.\LobbyWizard.h +# End Source File +# Begin Source File + +SOURCE=.\PeerLobby.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StagingPage.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\TitlePage.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\ico00001.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ico00002.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ico00003.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ico00004.ico +# End Source File +# Begin Source File + +SOURCE=.\res\icon1.ico +# End Source File +# Begin Source File + +SOURCE=.\res\PeerLobby.ico +# End Source File +# Begin Source File + +SOURCE=.\res\PeerLobby.rc2 +# End Source File +# End Group +# Begin Group "PeerSDK" + +# PROP Default_Filter "" +# Begin Group "ChatSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\chat\chat.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatChannel.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCrypt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatHandlers.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatSocket.h +# End Source File +# End Group +# Begin Group "Pinger" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\pinger\pinger.h +# End Source File +# Begin Source File + +SOURCE=..\..\pinger\pingerMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_crypt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_queryengine.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_server.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverbrowsing.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverlist.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\peer.h +# End Source File +# Begin Source File + +SOURCE=..\peerAutoMatch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerAutoMatch.h +# End Source File +# Begin Source File + +SOURCE=..\peerCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\peerGlobalCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerGlobalCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\peerHost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerHost.h +# End Source File +# Begin Source File + +SOURCE=..\peerKeys.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerKeys.h +# End Source File +# Begin Source File + +SOURCE=..\peerMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerMain.h +# End Source File +# Begin Source File + +SOURCE=..\peerMangle.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerMangle.h +# End Source File +# Begin Source File + +SOURCE=..\peerOperations.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerOperations.h +# End Source File +# Begin Source File + +SOURCE=..\peerPing.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerPing.h +# End Source File +# Begin Source File + +SOURCE=..\peerPlayers.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerPlayers.h +# End Source File +# Begin Source File + +SOURCE=..\peerQR.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerQR.h +# End Source File +# Begin Source File + +SOURCE=..\peerRooms.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerRooms.h +# End Source File +# Begin Source File + +SOURCE=..\peerSB.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerSB.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c + +!IF "$(CFG)" == "PeerLobby - Win32 Release" + +!ELSEIF "$(CFG)" == "PeerLobby - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.h b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.h new file mode 100644 index 00000000000..2187defa5cd --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.h @@ -0,0 +1,48 @@ +// PeerLobby.h : main header file for the PEERLOBBY application +// + +#if !defined(AFX_PEERLOBBY_H__A167413C_51DD_4C60_BA40_97CCA3876DDB__INCLUDED_) +#define AFX_PEERLOBBY_H__A167413C_51DD_4C60_BA40_97CCA3876DDB__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CPeerLobbyApp: +// See PeerLobby.cpp for the implementation of this class +// + +class CPeerLobbyApp : public CWinApp +{ +public: + CPeerLobbyApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPeerLobbyApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CPeerLobbyApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PEERLOBBY_H__A167413C_51DD_4C60_BA40_97CCA3876DDB__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.rc b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.rc new file mode 100644 index 00000000000..413bbbb533a --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby.rc @@ -0,0 +1,308 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\PeerLobby.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\PeerLobby.ico" +IDI_GREEN_SMILEY ICON DISCARDABLE "res\\ico00004.ico" +IDI_RED_SMILEY ICON DISCARDABLE "res\\ico00001.ico" +IDI_RUNNING_GAME ICON DISCARDABLE "res\\ico00002.ico" +IDI_STAGING_ROOM ICON DISCARDABLE "res\\ico00003.ico" +IDI_YELLOW_SMILEY ICON DISCARDABLE "res\\icon1.ico" + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "PeerLobby MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "PeerLobby\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "PeerLobby.EXE\0" + VALUE "ProductName", "PeerLobby Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONNECT_PAGE DIALOG DISCARDABLE 0, 0, 277, 242 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Connect" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Enter your nickname:",IDC_STATIC,86,96,68,8 + EDITTEXT IDC_NICK,86,109,95,12,ES_AUTOHSCROLL + EDITTEXT IDC_TITLE,220,0,55,12,ES_AUTOHSCROLL + CONTROL "Use Group Rooms",IDC_GROUP_ROOMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,86,128,74,10 + LTEXT "The use of group rooms is game-dependant. Group rooms are used to split up staging rooms (and running games) into various sections, grouped by type of game, skill level, or any other criteria.", + IDC_STATIC,86,145,154,45 + LTEXT "Title:",IDC_STATIC,200,2,16,8 + EDITTEXT IDC_KEY,220,15,55,12,ES_AUTOHSCROLL + LTEXT "Key:",IDC_STATIC,200,17,15,8 +END + +IDD_GROUP_PAGE DIALOGEX 0, 0, 277, 242 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Lobby" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_MESSAGE,10,216,168,15,ES_AUTOHSCROLL | ES_WANTRETURN + PUSHBUTTON "&Create Game",IDC_CREATE,7,7,50,14 + CONTROL "List2",IDC_GAMES,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + WS_BORDER | WS_TABSTOP,7,30,263,82 + CONTROL "List2",IDC_PLAYERS,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + WS_BORDER | WS_TABSTOP,182,124,83,107 + LISTBOX IDC_CHAT_WINDOW,10,124,168,92,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Chat",IDC_STATIC,7,115,263,120 + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,61,7,143,14 + ICON IDI_STAGING_ROOM,IDC_STATIC,207,1,20,20,SS_REALSIZEIMAGE | + WS_BORDER,WS_EX_CLIENTEDGE + LTEXT "Staging Room",IDC_STATIC,222,3,46,8 + ICON IDI_RUNNING_GAME,IDC_STATIC,207,15,20,20, + SS_REALSIZEIMAGE | WS_BORDER,WS_EX_CLIENTEDGE + LTEXT "Running Game",IDC_STATIC,222,17,48,8 +END + +IDD_CREATE_PAGE DIALOG DISCARDABLE 0, 0, 277, 242 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Create" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Enter the room name:",IDC_STATIC,46,87,68,8 + EDITTEXT IDC_NAME,46,100,175,12,ES_AUTOHSCROLL + LTEXT "Set the maximum number of players:",IDC_STATIC,46,127, + 114,8 + EDITTEXT IDC_MAX_PLAYERS,46,142,30,12,ES_AUTOHSCROLL | ES_NUMBER +END + +IDD_STAGING_PAGE DIALOGEX 0, 0, 277, 242 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Staging" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_MESSAGE,7,219,175,15,ES_AUTOHSCROLL | ES_WANTRETURN + CONTROL "Not Ready",IDC_NOT_READY,"Button",BS_AUTORADIOBUTTON | + BS_PUSHLIKE | WS_GROUP,185,7,40,20 + CONTROL "Ready",IDC_READY,"Button",BS_AUTORADIOBUTTON | + BS_PUSHLIKE,230,7,40,20 + CONTROL "List2",IDC_PLAYERS,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + WS_BORDER | WS_GROUP | WS_TABSTOP,185,59,85,176 + LISTBOX IDC_CHAT_WINDOW,7,7,175,211,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_GROUP | + WS_TABSTOP + ICON IDI_GREEN_SMILEY,IDC_STATIC,197,31,20,20, + SS_REALSIZEIMAGE | WS_BORDER,WS_EX_CLIENTEDGE + LTEXT "Ready",IDC_STATIC,213,33,22,8 + ICON IDI_RED_SMILEY,IDC_STATIC,197,44,20,20,SS_REALSIZEIMAGE | + WS_BORDER,WS_EX_CLIENTEDGE + LTEXT "Not Ready",IDC_STATIC,213,47,35,8 +END + +IDD_TITLE_PAGE DIALOG DISCARDABLE 0, 0, 277, 242 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Title" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_MESSAGE,10,216,168,15,ES_AUTOHSCROLL | ES_WANTRETURN + CONTROL "List2",IDC_PLAYERS,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + WS_BORDER | WS_TABSTOP,182,124,83,107 + LISTBOX IDC_CHAT_WINDOW,10,124,168,92,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Chat",IDC_STATIC,7,115,263,120 + CONTROL "List2",IDC_GROUPS,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + WS_BORDER | WS_TABSTOP,7,10,263,102 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_CONNECT_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 270 + TOPMARGIN, 7 + BOTTOMMARGIN, 235 + END + + IDD_GROUP_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 270 + TOPMARGIN, 7 + BOTTOMMARGIN, 235 + END + + IDD_CREATE_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 270 + TOPMARGIN, 7 + BOTTOMMARGIN, 235 + END + + IDD_STAGING_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 270 + TOPMARGIN, 7 + BOTTOMMARGIN, 235 + END + + IDD_TITLE_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 270 + TOPMARGIN, 7 + BOTTOMMARGIN, 235 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\PeerLobby.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby_vs2005.vcproj b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby_vs2005.vcproj new file mode 100644 index 00000000000..36e2374bd32 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby_vs2005.vcproj @@ -0,0 +1,1714 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/PeerLobby_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/ReadMe.txt b/xrGameSpy/gamespy/Peer/PeerLobby/ReadMe.txt new file mode 100644 index 00000000000..9b1b93d311d --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/ReadMe.txt @@ -0,0 +1,88 @@ +======================================================================== + MICROSOFT FOUNDATION CLASS LIBRARY : PeerLobby +======================================================================== + + +AppWizard has created this PeerLobby application for you. This application +not only demonstrates the basics of using the Microsoft Foundation classes +but is also a starting point for writing your application. + +This file contains a summary of what you will find in each of the files that +make up your PeerLobby application. + +PeerLobby.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +PeerLobby.h + This is the main header file for the application. It includes other + project specific headers (including Resource.h) and declares the + CPeerLobbyApp application class. + +PeerLobby.cpp + This is the main application source file that contains the application + class CPeerLobbyApp. + +PeerLobby.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +PeerLobby.clw + This file contains information used by ClassWizard to edit existing + classes or add new classes. ClassWizard also uses this file to store + information needed to create and edit message maps and dialog data + maps and to create prototype member functions. + +res\PeerLobby.ico + This is an icon file, which is used as the application's icon. This + icon is included by the main resource file PeerLobby.rc. + +res\PeerLobby.rc2 + This file contains resources that are not edited by Microsoft + Visual C++. You should place all resources not editable by + the resource editor in this file. + + + + +///////////////////////////////////////////////////////////////////////////// + +AppWizard creates one dialog class: + +PeerLobbyDlg.h, PeerLobbyDlg.cpp - the dialog + These files contain your CPeerLobbyDlg class. This class defines + the behavior of your application's main dialog. The dialog's + template is in PeerLobby.rc, which can be edited in Microsoft + Visual C++. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named PeerLobby.pch and a precompiled types file named StdAfx.obj. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +If your application uses MFC in a shared DLL, and your application is +in a language other than the operating system's current language, you +will need to copy the corresponding localized resources MFC42XXX.DLL +from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, +and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. +For example, MFC42DEU.DLL contains resources translated to German.) If you +don't do this, some of the UI elements of your application will remain in the +language of the operating system. + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/SideBarCtrl.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/SideBarCtrl.cpp new file mode 100644 index 00000000000..e11ede56bae --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/SideBarCtrl.cpp @@ -0,0 +1,217 @@ +// SideBarCtrl.cpp : implementation file +// + +#include "stdafx.h" +#include "peerlobby.h" +#include "SideBarCtrl.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSideBarCtrl + +CSideBarCtrl::CSideBarCtrl() +{ +} + +CSideBarCtrl::~CSideBarCtrl() +{ +} + + +BEGIN_MESSAGE_MAP(CSideBarCtrl, CStatic) + //{{AFX_MSG_MAP(CSideBarCtrl) + ON_WM_ERASEBKGND() + ON_WM_PAINT() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSideBarCtrl message handlers + +BOOL CSideBarCtrl::OnEraseBkgnd(CDC* pDC) +{ + return TRUE; + +// return CStatic::OnEraseBkgnd(pDC); +} + +void CSideBarCtrl::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + CRect rcClient; + GetClientRect(rcClient); + + DrawGradient(&dc, rcClient, RGB(0,0,0), RGB(0,255,0), TRUE ); + + int oldBkMode = dc.SetBkMode(TRANSPARENT); + HFONT oldFont = (HFONT)dc.SelectObject( (HFONT)::GetStockObject(ANSI_VAR_FONT) ); + COLORREF oldTextColor = dc.SetTextColor( RGB(0,204,0) ); + + // + // Bottom Text + // + CString str; + GetWindowText(str); + + CRect rcText = rcClient; + rcText.DeflateRect(3,3); + + dc.DrawText( str, rcText, DT_BOTTOM|DT_CENTER|DT_SINGLELINE ); + + rcText.OffsetRect(-1,-1); + + dc.SetTextColor( RGB(0,0,0) ); + + dc.DrawText( str, rcText, DT_BOTTOM|DT_CENTER|DT_SINGLELINE ); + + + // + // Top Text + // + CFont fntBold; + LOGFONT lf = {0}; + ::GetObject((HFONT)::GetStockObject(ANSI_VAR_FONT),sizeof(LOGFONT),&lf); + lf.lfWeight = FW_SEMIBOLD; + fntBold.CreateFontIndirect(&lf); + + dc.SelectObject(fntBold); + + dc.SetTextColor(RGB(255,255,255)); + + dc.DrawText("\nGameSpy\n\n\"PeerLobby\"\n\nSample\nApplication",-1,rcClient,DT_CENTER); + + + // + // Cleanup + // + + dc.SetTextColor(oldTextColor); + dc.SetBkMode(oldBkMode); + dc.SelectObject(oldFont); + + fntBold.DeleteObject(); +} + +// +// Helpers +// +BYTE findMidTone( BYTE bColorOne, BYTE bColorTwo ) +{ + BYTE bResult = 0; + WORD wMax = (WORD)(bColorOne + bColorTwo); + if( wMax > 0 ) + { + bResult = ( (BYTE)(wMax/2) ); + } + return bResult; +} + +COLORREF findMidColor( COLORREF cOne, COLORREF cTwo ) +{ + return( RGB( findMidTone( GetRValue(cOne), GetRValue(cTwo) ), + findMidTone( GetGValue(cOne), GetGValue(cTwo) ), + findMidTone( GetBValue(cOne), GetBValue(cTwo) ) ) ); +} + +/***************************************************************************** +* NAME: +* DrawGradient +* +* DESCRIPTION: +* Found this as part of an overly complicated gradient progress bar on codeguru +* So, I simplified it for my own uses :) -Lumberjack +* +*******************************************************************************/ +void CSideBarCtrl::DrawGradient(CDC* pDC, const CRect &rcGrad, COLORREF clrStart, COLORREF clrEnd, BOOL bVertical, COLORREF clrDither /*=0xFFFFFFFF*/ ) +{ + // Split colors to RGB chanels, find chanel with maximum difference + // between the start and end colors. This distance will determine + // number of steps of gradient + int r = (GetRValue(clrEnd) - GetRValue(clrStart)); + int g = (GetGValue(clrEnd) - GetGValue(clrStart)); + int b = (GetBValue(clrEnd) - GetBValue(clrStart)); + int nSteps = max(abs(r), max(abs(g), abs(b))); + // if number of pixels in gradient less than number of steps - + // use it as numberof steps + int nPixels = rcGrad.Width(); + nSteps = min(nPixels, nSteps); + if(nSteps == 0) nSteps = 1; + + float rStep = (float)r/nSteps; + float gStep = (float)g/nSteps; + float bStep = (float)b/nSteps; + + r = GetRValue(clrStart); + g = GetGValue(clrStart); + b = GetBValue(clrStart); + + BOOL fLowColor = pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE; + if(!fLowColor && nSteps > 1) + if(pDC->GetDeviceCaps(BITSPIXEL)*pDC->GetDeviceCaps(PLANES) < 8) + nSteps = 1; // for 16 colors no gradient + + float nSpacePerStep = bVertical?(float)rcGrad.Height()/nSteps:(float)rcGrad.Width()/nSteps; + CRect rcFill(rcGrad); + CBrush br; + + // Start filling + for (int i = 0; i < nSteps; i++) + { + if( bVertical ) + { + rcFill.top = rcGrad.top + (int)(nSpacePerStep * i); + rcFill.bottom = rcGrad.top + (int)(nSpacePerStep * (i+1)); + if(i == nSteps-1) //last step (because of problems with float) + rcFill.bottom = rcGrad.bottom; + } + else + { + rcFill.left = rcGrad.left + (int)(nSpacePerStep * i); + rcFill.right = rcGrad.left + (int)(nSpacePerStep * (i+1)); + if(i == nSteps-1) //last step (because of problems with float) + rcFill.right = rcGrad.right; + } + + COLORREF clrFill = RGB(r + (int)(i * rStep), g + (int)(i * gStep), b + (int)(i * bStep)); + + if( fLowColor ) + { + br.CreateSolidBrush(clrFill); + // CDC::FillSolidRect is faster, but it does not handle 8-bit color depth + pDC->FillRect(&rcFill, &br); + br.DeleteObject(); + } + else + { + if( 0xFFFFFFFF != clrDither ) + { + COLORREF crExisting = 0; + for( int nHoriz = rcFill.left; nHoriz < rcFill.right; nHoriz++ ) + { + for( int nVert = rcFill.top; nVert < rcFill.bottom; nVert++ ) + { + crExisting = pDC->GetPixel(nHoriz,nVert); + if( crExisting == clrDither ) + { + pDC->SetPixel(nHoriz,nVert,findMidColor(clrFill,clrDither) ); + } + else + { + pDC->SetPixel(nHoriz,nVert,clrFill); + } + } + } + } + else + { + pDC->FillSolidRect(&rcFill, clrFill); + } + } + } +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/SideBarCtrl.h b/xrGameSpy/gamespy/Peer/PeerLobby/SideBarCtrl.h new file mode 100644 index 00000000000..6af569edc79 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/SideBarCtrl.h @@ -0,0 +1,51 @@ +#if !defined(AFX_SIDEBARCTRL_H__CC0DCA41_C330_11D5_A480_000102C2601F__INCLUDED_) +#define AFX_SIDEBARCTRL_H__CC0DCA41_C330_11D5_A480_000102C2601F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SideBarCtrl.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSideBarCtrl window + +class CSideBarCtrl : public CStatic +{ +// Construction +public: + CSideBarCtrl(); + +// Attributes +public: + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSideBarCtrl) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CSideBarCtrl(); + + // Generated message map functions +protected: + //{{AFX_MSG(CSideBarCtrl) + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnPaint(); + //}}AFX_MSG + + void DrawGradient(CDC* pDC, const CRect &rcGrad, COLORREF clrStart, COLORREF clrEnd, BOOL bVertical, COLORREF clrDither = 0xFFFFFFFF ); + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SIDEBARCTRL_H__CC0DCA41_C330_11D5_A480_000102C2601F__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/StagingPage.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/StagingPage.cpp new file mode 100644 index 00000000000..bc1464e1fb8 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/StagingPage.cpp @@ -0,0 +1,486 @@ +// StagingPage.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "StagingPage.h" +#include "LobbyWizard.h" +#include "GroupPage.h" +#include "ConnectPage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CStagingPage * StagingPage; + +#define COL_NAME 0 +#define COL_PING 1 + +///////////////////////////////////////////////////////////////////////////// +// CStagingPage property page + +IMPLEMENT_DYNCREATE(CStagingPage, CPropertyPage) + +// Set page defaults. +///////////////////// +CStagingPage::CStagingPage() : CPropertyPage(CStagingPage::IDD) +{ + //{{AFX_DATA_INIT(CStagingPage) + m_message = _T(""); + m_ready = 0; + //}}AFX_DATA_INIT +} + +CStagingPage::~CStagingPage() +{ +} + +void CStagingPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CStagingPage) + DDX_Control(pDX, IDC_PLAYERS, m_players); + DDX_Control(pDX, IDC_CHAT_WINDOW, m_chatWindow); + DDX_Text(pDX, IDC_MESSAGE, m_message); + DDX_Radio(pDX, IDC_NOT_READY, m_ready); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CStagingPage, CPropertyPage) + //{{AFX_MSG_MAP(CStagingPage) + ON_BN_CLICKED(IDC_READY, OnReady) + ON_BN_CLICKED(IDC_NOT_READY, OnNotReady) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +// Used to list staging room players. +///////////////////////////////////// +static void EnumStagingPlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const char * nick, + int flags, + void * param +) +{ + // Add the player to the list. + ////////////////////////////// + if(nick) + StagingPage->UpdatePlayerPing(nick, 9999); + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(flags); + GSI_UNUSED(index); + GSI_UNUSED(roomType); + GSI_UNUSED(success); +} + +// Called when the join attempt has completed (successfully or unsuccessfully). +/////////////////////////////////////////////////////////////////////////////// +PEERBool joinStagingSuccess; +void JoinStagingRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + joinStagingSuccess = success; + GSI_UNUSED(peer); + GSI_UNUSED(roomType); + GSI_UNUSED(param); + GSI_UNUSED(result); +} + +// Switching to this page. +////////////////////////// +BOOL CStagingPage::OnSetActive() +{ + // Show back and a disabled-finish. + /////////////////////////////////// + Wizard->SetWizardButtons(PSWIZB_BACK | PSWIZB_DISABLEDFINISH); + + // Clear the chat log. + ////////////////////// + m_chatWindow.ResetContent(); + + // Are we joining? + ////////////////// + if(!Wizard->m_hosting) + { + // Make sure something was selected. + //////////////////////////////////// + int nIndex = GroupPage->m_games.GetSelectionMark(); + if(nIndex == -1) + { + MessageBox("You must have a game selected."); + return 1; + } + + // Get the data. + //////////////// + CListedGame * game = (CListedGame *)GroupPage->m_games.GetItemData(nIndex); + +//PEERSTART + // Join the room. + ///////////////// + Wizard->StartHourglass(); + peerJoinStagingRoom(Wizard->m_peer, game->server, NULL, JoinStagingRoomCallback, Wizard, PEERTrue); + Wizard->StopHourglass(); + if(!joinStagingSuccess) + { + MessageBox("Error joining the staging room."); + return FALSE; + } + + // Stop listing. + //////////////// + peerStopListingGames(Wizard->m_peer); + } + + // Fill the player list. + //////////////////////// + peerEnumPlayers(Wizard->m_peer, StagingRoom, EnumStagingPlayersCallback, Wizard); +//PEERSTOP + + // Default to not ready. + //////////////////////// + m_ready = 0; + + return CPropertyPage::OnSetActive(); +} + +// Leaving this page. +///////////////////// +BOOL CStagingPage::OnKillActive() +{ + // Clear the players. + ///////////////////// + m_players.DeleteAllItems(); + + return CPropertyPage::OnKillActive(); +} + +// Going to the previous page. +////////////////////////////// +LRESULT CStagingPage::OnWizardBack() +{ +//PEERSTART + // Leave the room. + ////////////////// + peerLeaveRoom(Wizard->m_peer, StagingRoom, NULL); +//PEERSTOP + + // Do stuff based on hosting. + ///////////////////////////// + if(Wizard->m_hosting) + { + // Goto the create page. + //////////////////////// + return IDD_CREATE_PAGE; + } + else + { + // Goto the lobby room. + /////////////////////// + return IDD_GROUP_PAGE; + } + + //return CPropertyPage::OnWizardBack(); +} + +// The game is being launched. +////////////////////////////// +BOOL CStagingPage::OnWizardFinish() +{ +//PEERSTART + // Start the game. + ////////////////// + peerStartGame(Wizard->m_peer, "", PEER_KEEP_REPORTING); + + // This is where the host would start up. + ///////////////////////////////////////// + MessageBox("You are now playing!\nHit enter when you are done."); + + // Stop the game. + // This should be called when the host is ready to return to the staging room. + ////////////////////////////////////////////////////////////////////////////// + peerStopGame(Wizard->m_peer); +//PEERSTOP + + return FALSE; +} + +// Init the page. +///////////////// +BOOL CStagingPage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + // Change "Finish". + /////////////////// + HWND hWnd = ::FindWindowEx(GetParent()->m_hWnd, NULL, "Button", "Finish"); + if(hWnd) + ::SetWindowText(hWnd, "&Start Playing"); + + // Set the players columns. + /////////////////////////// + m_players.InsertColumn(COL_NAME, "Player", LVCFMT_LEFT, 70); + m_players.InsertColumn(COL_PING, "Ping", LVCFMT_LEFT, 50); + + // Image list setup. + //////////////////// + m_players.SetImageList(&Wizard->m_imageList, LVSIL_SMALL); + + return TRUE; +} + +// The player's ready. +////////////////////// +void CStagingPage::OnReady() +{ +//PEERSTART + // Set ready to true. + ///////////////////// + peerSetReady(Wizard->m_peer, PEERTrue); +//PEERSTOP +} + +// The player's not ready. +////////////////////////// +void CStagingPage::OnNotReady() +{ +//PEERSTART + // Set ready to false. + ////////////////////// + peerSetReady(Wizard->m_peer, PEERFalse); +//PEERSTOP +} + +// Find the index of a player in the list ny its nick. +////////////////////////////////////////////////////// +int CStagingPage::FindPlayer(const char * nick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Look for this player. + //////////////////////// + LVFINDINFO findInfo; + findInfo.flags = LVFI_STRING; + findInfo.psz = nick; + + // Find the player. + /////////////////// + int nIndex = m_players.FindItem(&findInfo); + + return nIndex; +} + +// Update this player's ping in the list, and add the player if +// not already on the list. +/////////////////////////////////////////////////////////////// +void CStagingPage::UpdatePlayerPing(const char * nick, int ping) +{ + LVITEM item; + + // Is this us? + ////////////// + if(strcasecmp(nick, ConnectPage->m_nick) == 0) + ping = 0; + + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Check for a new nick. + //////////////////////// + if(nIndex == -1) + { + item.iItem = 0; + item.iSubItem = 0; + item.mask = LVIF_TEXT | LVIF_IMAGE; + item.pszText = (char *)nick; + item.iImage = Wizard->m_redSmileyIndex; + + nIndex = m_players.InsertItem(&item); + if(nIndex == -1) + return; + } + + // Add the ping. + //////////////// + char intValue[16]; + sprintf(intValue, "%d", ping); + item.iItem = nIndex; + item.iSubItem = 1; + item.mask = LVIF_TEXT; + item.pszText = intValue; + m_players.SetItem(&item); +} + +// Update the player's ready state, and add the player if +// not alreayd on the list. +///////////////////////////////////////////////////////// +void CStagingPage::UpdatePlayerReady(const char * nick, BOOL ready) +{ + LVITEM item; + + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Check for a new nick. + //////////////////////// + if(nIndex != -1) + { + // Update the image. + //////////////////// + item.iItem = nIndex; + item.iSubItem = 0; + item.mask = LVIF_IMAGE; + if(ready) + item.iImage = Wizard->m_greenSmileyIndex; + else + item.iImage = Wizard->m_redSmileyIndex; + m_players.SetItem(&item); + } + else + { + // Add it. + ////////// + item.iItem = 0; + item.iSubItem = 0; + item.mask = LVIF_TEXT | LVIF_IMAGE; + item.pszText = (char *)nick; + if(ready) + item.iImage = Wizard->m_greenSmileyIndex; + else + item.iImage = Wizard->m_redSmileyIndex; + + nIndex = m_players.InsertItem(&item); + if(nIndex == -1) + return; + + // Set a ping. + ////////////// + item.iItem = nIndex; + item.iSubItem = 1; + item.mask = LVIF_TEXT; + item.pszText = "9999"; + m_players.SetItem(&item); + } +} + +// Remove a player from the list. +///////////////////////////////// +void CStagingPage::RemovePlayer(const char * nick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Remove it. + ///////////// + m_players.DeleteItem(nIndex); +} + +// Change a player's nick on the list. +////////////////////////////////////// +void CStagingPage::ChangePlayerNick(const char * oldNick, const char * newNick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = oldNick; + loweredNick.MakeLower(); + oldNick = loweredNick; + loweredNick = newNick; + loweredNick.MakeLower(); + newNick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(oldNick); + + // Update the nick. + /////////////////// + LVITEM item; + item.iItem = nIndex; + item.iSubItem = 0; + item.mask = LVIF_TEXT; + item.pszText = (char *)newNick; + m_players.SetItem(&item); +} + +// Does the actual chat message sending. +//////////////////////////////////////// +void CStagingPage::SendMessage() +{ + UpdateData(); + + // Ignore blank message. + //////////////////////// + if(m_message == "") + return; + +//PEERSTART + // Send it. + /////////// + peerMessageRoom(Wizard->m_peer, StagingRoom, m_message, NormalMessage); +//PEERSTOP + + // Clear it. + //////////// + m_message = ""; + + UpdateData(FALSE); +} + +// Either enables or disables the finish button based on if +// all the players in the room are ready or not. +/////////////////////////////////////////////////////////// +void CStagingPage::CheckEnableFinish() +{ +//PEERSTART + // Check if all the player's in the room are ready. + /////////////////////////////////////////////////// + PEERBool allReady = peerAreAllReady(Wizard->m_peer); +//PEERSTOP + + // Only enable the finish button if we're hosting and everyone's ready. + /////////////////////////////////////////////////////////////////////// + if(Wizard->m_hosting && allReady) + Wizard->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH); + else + Wizard->SetWizardButtons(PSWIZB_BACK | PSWIZB_DISABLEDFINISH); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/StagingPage.h b/xrGameSpy/gamespy/Peer/PeerLobby/StagingPage.h new file mode 100644 index 00000000000..275b492ab66 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/StagingPage.h @@ -0,0 +1,70 @@ +#if !defined(AFX_STAGINGPAGE_H__E66D2915_B2B7_4A43_B875_D0C905FA1395__INCLUDED_) +#define AFX_STAGINGPAGE_H__E66D2915_B2B7_4A43_B875_D0C905FA1395__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// StagingPage.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CStagingPage dialog + +class CStagingPage : public CPropertyPage +{ + DECLARE_DYNCREATE(CStagingPage) + +// Construction +public: + CStagingPage(); + ~CStagingPage(); + +// Dialog Data + //{{AFX_DATA(CStagingPage) + enum { IDD = IDD_STAGING_PAGE }; + CListCtrl m_players; + CListBox m_chatWindow; + CString m_message; + int m_ready; + //}}AFX_DATA + + int FindPlayer(const char * nick); + void UpdatePlayerPing(const char * nick, int ping); + void UpdatePlayerReady(const char * nick, BOOL ready); + void RemovePlayer(const char * nick); + void ChangePlayerNick(const char * oldNick, const char * newNick); + + void SendMessage(); + + void CheckEnableFinish(); + +// Overrides + // ClassWizard generate virtual function overrides + //{{AFX_VIRTUAL(CStagingPage) + public: + virtual BOOL OnSetActive(); + virtual LRESULT OnWizardBack(); + virtual BOOL OnWizardFinish(); + virtual BOOL OnKillActive(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CStagingPage) + afx_msg void OnReady(); + afx_msg void OnNotReady(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +extern CStagingPage * StagingPage; + +#endif // !defined(AFX_STAGINGPAGE_H__E66D2915_B2B7_4A43_B875_D0C905FA1395__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/StdAfx.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/StdAfx.cpp new file mode 100644 index 00000000000..52d6678489e --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// PeerLobby.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/StdAfx.h b/xrGameSpy/gamespy/Peer/PeerLobby/StdAfx.h new file mode 100644 index 00000000000..4e7087148ba --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/StdAfx.h @@ -0,0 +1,31 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A460F6D9_024E_4B08_A827_B0B0D48AB46D__INCLUDED_) +#define AFX_STDAFX_H__A460F6D9_024E_4B08_A827_B0B0D48AB46D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC socket extensions + +#include "../peer.h" +#include "../../common/gsAvailable.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A460F6D9_024E_4B08_A827_B0B0D48AB46D__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/TitlePage.cpp b/xrGameSpy/gamespy/Peer/PeerLobby/TitlePage.cpp new file mode 100644 index 00000000000..dcccec8dafc --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/TitlePage.cpp @@ -0,0 +1,502 @@ +// TitlePage.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerLobby.h" +#include "TitlePage.h" +#include "LobbyWizard.h" +#include "ConnectPage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CTitlePage * TitlePage; + +#define COL_NAME 0 +#define COL_NUM_WAITING 1 +#define COL_MAX_WAITING 2 +#define COL_NUM_GAMES 3 +#define COL_NUM_PLAYING 4 + +///////////////////////////////////////////////////////////////////////////// +// CTitlePage property page + +IMPLEMENT_DYNCREATE(CTitlePage, CPropertyPage) + +CTitlePage::CTitlePage() : CPropertyPage(CTitlePage::IDD) +{ + //{{AFX_DATA_INIT(CTitlePage) + m_message = _T(""); + //}}AFX_DATA_INIT +} + +CTitlePage::~CTitlePage() +{ +} + +void CTitlePage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTitlePage) + DDX_Control(pDX, IDC_GROUPS, m_groups); + DDX_Control(pDX, IDC_PLAYERS, m_players); + DDX_Control(pDX, IDC_CHAT_WINDOW, m_chatWindow); + DDX_Text(pDX, IDC_MESSAGE, m_message); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTitlePage, CPropertyPage) + //{{AFX_MSG_MAP(CTitlePage) + ON_NOTIFY(NM_CLICK, IDC_GROUPS, OnClickGroups) + ON_NOTIFY(NM_DBLCLK, IDC_GROUPS, OnDblclkGroups) + ON_NOTIFY(LVN_BEGINDRAG, IDC_GROUPS, OnBegindragGroups) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTitlePage message handlers + +// Used to list the players in the title room. +////////////////////////////////////////////// +static void EnumTitlePlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const char * nick, + int flags, + void * param +) +{ + if(!success) + { + Wizard->MessageBox("Error listing title-room players."); + return; + } + + if(index == -1) + return; + + TitlePage->UpdatePlayerPing(nick, 9999); + GSI_UNUSED(peer); + GSI_UNUSED(flags); + GSI_UNUSED(roomType); + GSI_UNUSED(param); +} + +// Called when the join is complete (successful or unsuccessful). +///////////////////////////////////////////////////////////////// +static PEERBool joinSuccess; +static void JoinTitleRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + joinSuccess = success; + + if(success) + { +//PEERSTART + // List the players in the room. + //////////////////////////////// + peerEnumPlayers(Wizard->m_peer, TitleRoom, EnumTitlePlayersCallback, NULL); +//PEERSTOP + } + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(roomType); + GSI_UNUSED(result); +} + +static void ListGroupRoomsCallback +( + PEER peer, + PEERBool success, + int groupID, + SBServer server, + const char * name, + int numWaiting, + int maxWaiting, + int numGames, + int numPlaying, + void * param +) +{ + // Check for failure. + ///////////////////// + if(!success) + { + Wizard->MessageBox("Listing groups failed!"); + Wizard->EndDialog(IDOK); + return; + } + + // Check for done. + ////////////////// + if(groupID == 0) + return; + + CListCtrl * groups = &TitlePage->m_groups; + int nIndex = groups->InsertItem(LVIF_TEXT | LVIF_PARAM, + 0, + name, + 0, 0, + 0, + (LPARAM)groupID); + if(nIndex == -1) + return; + + LV_ITEM item; + CString str; + item.mask = LVIF_TEXT; + item.iItem = nIndex; + item.iSubItem = COL_NUM_WAITING; + str.Format("%d", numWaiting); + item.pszText = (LPSTR)(LPCSTR)str; + groups->SetItem(&item); + item.iSubItem = COL_MAX_WAITING; + str.Format("%d", maxWaiting); + item.pszText = (LPSTR)(LPCSTR)str; + groups->SetItem(&item); + item.iSubItem = COL_NUM_GAMES; + str.Format("%d", numGames); + item.pszText = (LPSTR)(LPCSTR)str; + groups->SetItem(&item); + item.iSubItem = COL_NUM_PLAYING; + str.Format("%d", numPlaying); + item.pszText = (LPSTR)(LPCSTR)str; + groups->SetItem(&item); + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(server); +} + +BOOL CTitlePage::OnSetActive() +{ + // Show the back and next buttons. + ////////////////////////////////// + Wizard->SetWizardButtons(PSWIZB_BACK); + + // Rename the next button. + ////////////////////////// + ::SetWindowText(Wizard->m_nextButtonWnd, "&Join >"); + + // Clear the groups list. + ///////////////////////// + m_groups.DeleteAllItems(); + + // Clear the chat log. + ////////////////////// + m_chatWindow.ResetContent(); + +//PEERSTART + // Join the title room. + /////////////////////// + Wizard->StartHourglass(); + peerJoinTitleRoom(Wizard->m_peer, NULL, JoinTitleRoomCallback, NULL, PEERTrue); + Wizard->StopHourglass(); + if(!joinSuccess) + { + MessageBox("Error joining the title room."); + return FALSE; + } + + // Start listing group rooms. + ///////////////////////////// + peerListGroupRooms(Wizard->m_peer, "", ListGroupRoomsCallback, NULL, PEERFalse); +//PEERSTOP + + return CPropertyPage::OnSetActive(); +} + +BOOL CTitlePage::OnKillActive() +{ + // Reset the "next" button's name. + ////////////////////////////////// + ::SetWindowText(Wizard->m_nextButtonWnd, "&Next >"); + + // Clear the player's. + ///////////////////// + m_players.DeleteAllItems(); + +//PEERSTART + // Leave the title room. + //////////////////////// + if(Wizard->m_peer) + peerLeaveRoom(Wizard->m_peer, TitleRoom, NULL); +//PEERSTOP + + return CPropertyPage::OnKillActive(); +} + +LRESULT CTitlePage::OnWizardNext() +{ + // Update vars. + /////////////// + UpdateData(); + + // Make sure something was selected. + //////////////////////////////////// + int nIndex = m_groups.GetSelectionMark(); + if(nIndex == -1) + { + MessageBox("You must have a group selected."); + return -1; + } + + // Join the group. + ////////////////// + JoinGroup(nIndex); + + return (LRESULT)GROUP_PAGE; +} + +BOOL CTitlePage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + // Set the groups columns. + ////////////////////////// + m_groups.InsertColumn(COL_NAME, "Group", LVCFMT_LEFT, 90); + m_groups.InsertColumn(COL_NUM_WAITING, "Num Waiting", LVCFMT_LEFT, 75); + m_groups.InsertColumn(COL_MAX_WAITING, "Max Waiting", LVCFMT_LEFT, 75); + m_groups.InsertColumn(COL_NUM_GAMES, "Num Games", LVCFMT_LEFT, 75); + m_groups.InsertColumn(COL_NUM_PLAYING, "Num Playing", LVCFMT_LEFT, 75); + ListView_SetExtendedListViewStyle(m_groups.m_hWnd,LVS_EX_FULLROWSELECT); + + // Set the players columns. + /////////////////////////// + m_players.InsertColumn(COL_NAME, "Player", LVCFMT_LEFT, 120); + + return TRUE; +} + +// Find the index of a player in the list by its nick. +////////////////////////////////////////////////////// +int CTitlePage::FindPlayer(const char *nick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Look for this player. + //////////////////////// + LVFINDINFO findInfo; + findInfo.flags = LVFI_STRING; + findInfo.psz = nick; + + // Find the player. + /////////////////// + int nIndex = m_players.FindItem(&findInfo); + + return nIndex; +} + +// Updates the player's ping in the player list, and adds the player +// if its not on the list. +//////////////////////////////////////////////////////////////////// +void CTitlePage::UpdatePlayerPing(const char *nick, int ping) +{ + LVITEM item; + + // Is this us? + ////////////// + if(strcasecmp(nick, ConnectPage->m_nick) == 0) + ping = 0; + + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Check for a new nick. + //////////////////////// + if(nIndex == -1) + { + item.iItem = 0; + item.iSubItem = 0; + item.mask = LVIF_TEXT; + item.pszText = (char *)nick; + + nIndex = m_players.InsertItem(&item); + if(nIndex == -1) + return; + } + +#if 0 + // Add the ping. + //////////////// + char intValue[16]; + sprintf(intValue, "%d", ping); + item.iItem = nIndex; + item.iSubItem = 1; + item.mask = LVIF_TEXT; + item.pszText = intValue; + m_players.SetItem(&item); +#endif +} + +// Remove the player from the list. +/////////////////////////////////// +void CTitlePage::RemovePlayer(const char * nick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = nick; + loweredNick.MakeLower(); + nick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(nick); + + // Remove it. + ///////////// + m_players.DeleteItem(nIndex); +} + +// Change a nick in the player list. +//////////////////////////////////// +void CTitlePage::ChangePlayerNick(const char * oldNick, const char * newNick) +{ + // Always deal in lower-case. + ///////////////////////////// + CString loweredNick = oldNick; + loweredNick.MakeLower(); + oldNick = loweredNick; + loweredNick = newNick; + loweredNick.MakeLower(); + newNick = loweredNick; + + // Find the player. + /////////////////// + int nIndex = FindPlayer(oldNick); + + // Update the nick. + /////////////////// + LVITEM item; + item.iItem = nIndex; + item.iSubItem = 0; + item.mask = LVIF_TEXT; + item.pszText = (char *)newNick; + m_players.SetItem(&item); +} + +// Does the actual chat message sending. +//////////////////////////////////////// +void CTitlePage::SendMessage() +{ + UpdateData(); + + // Ignore blank message. + //////////////////////// + if(m_message == "") + return; + +//PEERSTART + // Send it. + /////////// + peerMessageRoom(Wizard->m_peer, TitleRoom, m_message, NormalMessage); +//PEERSTOP + + // Clear it. + //////////// + m_message = ""; + + UpdateData(FALSE); +} + +// Join a group. +//////////////// +void CTitlePage::OnDblclkGroups(NMHDR* pNMHDR, LRESULT* pResult) +{ + NMHEADER * header = (NMHEADER *)pNMHDR; + + // If something was double-clicked, join it. + //////////////////////////////////////////// + if(header->iItem != -1) + JoinGroup(header->iItem); + + *pResult = 0; +} + +// Handle group list clicks. +//////////////////////////// +void CTitlePage::OnClickGroups(NMHDR* pNMHDR, LRESULT* pResult) +{ + // Enable/Disable join based on if something is selected. + ///////////////////////////////////////////////////////// + BOOL enable = (m_groups.GetSelectedCount() > 0); + ::EnableWindow(Wizard->m_nextButtonWnd, enable); + + *pResult = 0; + GSI_UNUSED(pNMHDR); +} +void CTitlePage::OnBegindragGroups(NMHDR* pNMHDR, LRESULT* pResult) +{ + // Treat this like a click. + // (OnClick() isn't called for "drags". + /////////////////////////////////////// + OnClickGroups(pNMHDR, pResult); +} + +// Called when the join is complete (successful or unsuccessful). +///////////////////////////////////////////////////////////////// +static void JoinGroupRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + joinSuccess = success; + GSI_UNUSED(roomType); + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(result); +} + +// Join a group based on its index in the groups list. +////////////////////////////////////////////////////// +void CTitlePage::JoinGroup(int nIndex) +{ + // Get the group ID. + ///////////////////////// + int groupID = (int)m_groups.GetItemData(nIndex); + ASSERT(groupID); + +//PEERSTART + // Join the group room. + /////////////////////// + Wizard->StartHourglass(); + peerJoinGroupRoom(Wizard->m_peer, groupID, JoinGroupRoomCallback, NULL, PEERTrue); + Wizard->StopHourglass(); + if(!joinSuccess) + { + MessageBox("Error joining the group room."); + return; + } +//PEERSTOP + + // Goto the group room page. + //////////////////////////// + Wizard->SetActivePage(GROUP_PAGE); +} diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/TitlePage.h b/xrGameSpy/gamespy/Peer/PeerLobby/TitlePage.h new file mode 100644 index 00000000000..0d356d217fe --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/TitlePage.h @@ -0,0 +1,70 @@ +#if !defined(AFX_TITLEPAGE_H__15BC897B_80B2_4DED_8622_568C60F30225__INCLUDED_) +#define AFX_TITLEPAGE_H__15BC897B_80B2_4DED_8622_568C60F30225__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TitlePage.h : header file +// + +#include "../peer.h" + +///////////////////////////////////////////////////////////////////////////// +// CTitlePage dialog + +class CTitlePage : public CPropertyPage +{ + DECLARE_DYNCREATE(CTitlePage) + +// Construction +public: + void JoinGroup(int nIndex); + CTitlePage(); + ~CTitlePage(); + +// Dialog Data + //{{AFX_DATA(CTitlePage) + enum { IDD = IDD_TITLE_PAGE }; + CListCtrl m_groups; + CListCtrl m_players; + CListBox m_chatWindow; + CString m_message; + //}}AFX_DATA + + void UpdatePlayerPing(const char * nick, int ping); + int FindPlayer(const char * nick); + void RemovePlayer(const char * nick); + void ChangePlayerNick(const char * oldNick, const char * newNick); + + void SendMessage(); + +// Overrides + // ClassWizard generate virtual function overrides + //{{AFX_VIRTUAL(CTitlePage) + public: + virtual BOOL OnSetActive(); + virtual BOOL OnKillActive(); + virtual LRESULT OnWizardNext(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CTitlePage) + virtual BOOL OnInitDialog(); + afx_msg void OnClickGroups(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDblclkGroups(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBegindragGroups(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +extern CTitlePage * TitlePage; + +#endif // !defined(AFX_TITLEPAGE_H__15BC897B_80B2_4DED_8622_568C60F30225__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/PeerLobby.ico b/xrGameSpy/gamespy/Peer/PeerLobby/res/PeerLobby.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerLobby/res/PeerLobby.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/PeerLobby.rc2 b/xrGameSpy/gamespy/Peer/PeerLobby/res/PeerLobby.rc2 new file mode 100644 index 00000000000..9fb0ea686f7 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/res/PeerLobby.rc2 @@ -0,0 +1,13 @@ +// +// PEERLOBBY.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00001.ico b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00001.ico new file mode 100644 index 00000000000..4d3d729a698 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00001.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00002.ico b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00002.ico new file mode 100644 index 00000000000..f988b937374 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00002.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00003.ico b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00003.ico new file mode 100644 index 00000000000..dc5c8127c3d Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00003.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00004.ico b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00004.ico new file mode 100644 index 00000000000..771d4e14370 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerLobby/res/ico00004.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/res/icon1.ico b/xrGameSpy/gamespy/Peer/PeerLobby/res/icon1.ico new file mode 100644 index 00000000000..d07fb145d39 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerLobby/res/icon1.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerLobby/resource.h b/xrGameSpy/gamespy/Peer/PeerLobby/resource.h new file mode 100644 index 00000000000..3bfc18765c4 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerLobby/resource.h @@ -0,0 +1,45 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by PeerLobby.rc +// +#define IDD_PEERLOBBY_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDD_TITLE_PAGE 106 +#define IDD_CONNECT_PAGE 107 +#define IDD_GROUP_PAGE 108 +#define IDD_CREATE_PAGE 109 +#define IDD_STAGING_PAGE 110 +#define IDR_MAINFRAME 128 +#define IDI_YELLOW_SMILEY 130 +#define IDI_RED_SMILEY 131 +#define IDI_RUNNING_GAME 132 +#define IDI_STAGING_ROOM 133 +#define IDI_GREEN_SMILEY 134 +#define IDC_NICK 1000 +#define IDC_NAME 1001 +#define IDC_MAX_PLAYERS 1002 +#define IDC_CREATE_GAME 1004 +#define IDC_JOIN_GAME 1005 +#define IDC_GAMES 1006 +#define IDC_CHAT_WINDOW 1007 +#define IDC_PLAYERS 1008 +#define IDC_MESSAGE 1009 +#define IDC_NOT_READY 1017 +#define IDC_READY 1018 +#define IDC_CREATE 1020 +#define IDC_TITLE 1021 +#define IDC_KEY 1022 +#define IDC_GROUPS 1029 +#define IDC_GROUP_ROOMS 1030 +#define IDC_PROGRESS 10126 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1031 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.cpp b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.cpp new file mode 100644 index 00000000000..479dfa61d51 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.cpp @@ -0,0 +1,80 @@ +// PeerTest.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "PeerTest.h" +#include "PeerTestDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestApp + +BEGIN_MESSAGE_MAP(CPeerTestApp, CWinApp) + //{{AFX_MSG_MAP(CPeerTestApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestApp construction + +CPeerTestApp::CPeerTestApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CPeerTestApp object + +CPeerTestApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestApp initialization + +BOOL CPeerTestApp::InitInstance() +{ + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CPeerTestDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.dsp b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.dsp new file mode 100644 index 00000000000..fffdc91da5f --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.dsp @@ -0,0 +1,561 @@ +# Microsoft Developer Studio Project File - Name="PeerTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=PeerTest - 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 "PeerTest.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 "PeerTest.mak" CFG="PeerTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PeerTest - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "PeerTest - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Peer/PeerTest", EBOAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PeerTest - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "PeerTest - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "IRC_LOG" /FR /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "PeerTest - Win32 Release" +# Name "PeerTest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\PeerTest.cpp +# End Source File +# Begin Source File + +SOURCE=.\PeerTest.rc +# End Source File +# Begin Source File + +SOURCE=.\PeerTestDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\PeerTest.h +# End Source File +# Begin Source File + +SOURCE=.\PeerTestDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\PeerTest.ico +# End Source File +# Begin Source File + +SOURCE=.\res\PeerTest.rc2 +# End Source File +# End Group +# Begin Group "PeerSDK" + +# PROP Default_Filter "" +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_crypt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_queryengine.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_server.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverbrowsing.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverlist.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "ChatSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\chat\chat.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatChannel.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCrypt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatHandlers.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatSocket.h +# End Source File +# End Group +# Begin Group "Pinger" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\pinger\pinger.h +# End Source File +# Begin Source File + +SOURCE=..\..\pinger\pingerMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\peer.h +# End Source File +# Begin Source File + +SOURCE=..\peerAutoMatch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerAutoMatch.h +# End Source File +# Begin Source File + +SOURCE=..\peerCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\peerGlobalCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerGlobalCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\peerHost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerHost.h +# End Source File +# Begin Source File + +SOURCE=..\peerKeys.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerKeys.h +# End Source File +# Begin Source File + +SOURCE=..\peerMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerMain.h +# End Source File +# Begin Source File + +SOURCE=..\peerMangle.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerMangle.h +# End Source File +# Begin Source File + +SOURCE=..\peerOperations.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerOperations.h +# End Source File +# Begin Source File + +SOURCE=..\peerPing.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerPing.h +# End Source File +# Begin Source File + +SOURCE=..\peerPlayers.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerPlayers.h +# End Source File +# Begin Source File + +SOURCE=..\peerQR.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerQR.h +# End Source File +# Begin Source File + +SOURCE=..\peerRooms.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerRooms.h +# End Source File +# Begin Source File + +SOURCE=..\peerSB.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\peerSB.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c + +!IF "$(CFG)" == "PeerTest - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "PeerTest - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.h b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.h new file mode 100644 index 00000000000..3128d103fb9 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.h @@ -0,0 +1,49 @@ +// PeerTest.h : main header file for the PEERTEST application +// + +#if !defined(AFX_PEERTEST_H__2F625A3C_93C3_4689_9749_3B9FCBE53594__INCLUDED_) +#define AFX_PEERTEST_H__2F625A3C_93C3_4689_9749_3B9FCBE53594__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestApp: +// See PeerTest.cpp for the implementation of this class +// + +class CPeerTestApp : public CWinApp +{ +public: + CPeerTestApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPeerTestApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CPeerTestApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PEERTEST_H__2F625A3C_93C3_4689_9749_3B9FCBE53594__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.rc b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.rc new file mode 100644 index 00000000000..e4795400712 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest.rc @@ -0,0 +1,341 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\PeerTest.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\PeerTest.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About PeerTest" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "PeerTest Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2000",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP +END + +IDD_PEERTEST_DIALOG DIALOGEX 0, 0, 377, 369 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "PeerTest" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Initialize",IDC_BUTTON7,12,17,55,11 + PUSHBUTTON "Set Title",IDC_BUTTON24,12,30,55,11 + PUSHBUTTON "gmtest",IDC_BUTTON45,12,42,55,11 + PUSHBUTTON "Connect",IDC_BUTTON1,12,55,55,11 + PUSHBUTTON "ConnectProfile",IDC_BUTTON36,12,67,55,11 + PUSHBUTTON "ConnectUnique",IDC_BUTTON50,12,80,55,11 + PUSHBUTTON "ConnectPreAuth",IDC_BUTTON49,12,92,55,11 + PUSHBUTTON "Disconnect",IDC_BUTTON5,12,105,55,11 + PUSHBUTTON "Shutdown",IDC_BUTTON21,74,17,55,11 + DEFPUSHBUTTON "Quit",IDOK,137,17,55,11 + EDITTEXT IDC_TITLE,91,30,45,12,ES_AUTOHSCROLL + EDITTEXT IDC_SECRET_KEY,91,42,45,12,ES_AUTOHSCROLL + CONTROL "Blocking",IDC_BLOCKING,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,143,32,43,10 + CONTROL "Quiet",IDC_QUIET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 143,42,33,10 + EDITTEXT IDC_NICK,91,55,45,12,ES_AUTOHSCROLL + PUSHBUTTON "Fix",IDC_FIX_NICK,142,54,20,12 + PUSHBUTTON "Change",IDC_CHANGE_NICK,162,54,30,12 + EDITTEXT IDC_EMAIL,91,67,101,12,ES_AUTOHSCROLL + EDITTEXT IDC_LOGIN_PASSWORD,91,80,39,12,ES_PASSWORD | + ES_AUTOHSCROLL + EDITTEXT IDC_NAMESPACE,173,80,19,12,ES_AUTOHSCROLL + EDITTEXT IDC_AUTH_TOKEN,113,92,79,12,ES_AUTOHSCROLL + EDITTEXT IDC_PARTNER_CHALLENGE,131,105,61,12,ES_AUTOHSCROLL + EDITTEXT IDC_RAW,41,120,96,12,ES_AUTOHSCROLL + PUSHBUTTON "Send",IDC_BUTTON39,142,120,50,11 + EDITTEXT IDC_CDKEY,41,132,96,12,ES_AUTOHSCROLL + PUSHBUTTON "Authenticate",IDC_BUTTON46,142,133,50,11 + EDITTEXT IDC_PASSWORD,49,158,87,12,ES_AUTOHSCROLL + PUSHBUTTON "Set Password",IDC_BUTTON34,141,158,50,11 + EDITTEXT IDC_NAME,49,172,87,12,ES_AUTOHSCROLL + PUSHBUTTON "Set Name",IDC_BUTTON35,141,172,50,11 + PUSHBUTTON "Join",IDC_BUTTON22,12,201,50,11 + PUSHBUTTON "Leave",IDC_BUTTON23,12,213,50,11 + PUSHBUTTON "Enum Players",IDC_BUTTON8,12,225,50,11 + PUSHBUTTON "Stay",IDC_BUTTON40,12,237,50,11 + PUSHBUTTON "Get Info",IDC_BUTTON26,12,249,50,11 + PUSHBUTTON "Message",IDC_BUTTON25,12,261,50,11 + LISTBOX IDC_TITLE_PLAYERS,13,287,50,70,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Join",IDC_BUTTON17,77,201,50,11 + PUSHBUTTON "Leave",IDC_BUTTON18,77,213,50,11 + PUSHBUTTON "Enum Players",IDC_BUTTON9,77,225,50,11 + PUSHBUTTON "Enum Rooms",IDC_BUTTON6,77,237,50,11 + PUSHBUTTON "Get Info",IDC_BUTTON27,77,249,50,11 + PUSHBUTTON "Message",IDC_BUTTON20,77,261,50,11 + LISTBOX IDC_GROUP_PLAYERS,77,287,50,70,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Join",IDC_BUTTON3,142,201,50,11 + PUSHBUTTON "Create",IDC_BUTTON2,142,213,50,11 + PUSHBUTTON "Leave",IDC_BUTTON4,142,225,50,11 + PUSHBUTTON "Enum Players",IDC_BUTTON10,142,237,50,11 + PUSHBUTTON "Get Info",IDC_BUTTON28,142,249,50,11 + PUSHBUTTON "Message",IDC_BUTTON13,142,261,50,11 + LISTBOX IDC_STAGING_PLAYERS,142,287,50,70,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_ROOMS,207,17,95,88,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Start",IDC_BUTTON29,205,119,21,11 + PUSHBUTTON "Stop",IDC_BUTTON30,226,119,21,11 + PUSHBUTTON "Info",IDC_BUTTON44,251,119,21,11 + PUSHBUTTON "Update",IDC_BUTTON48,272,119,30,11 + EDITTEXT IDC_FILTER,227,133,76,12,ES_AUTOHSCROLL + PUSHBUTTON "Start",IDC_START_AUTO_MATCH,205,158,30,11 + PUSHBUTTON "Stop",IDC_STOP_AUTO_MATCH,205,170,30,11 + EDITTEXT IDC_MAX_PLAYERS,283,157,19,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_AWAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,212, + 200,16,8 + EDITTEXT IDC_AWAY_REASON,232,197,70,14,ES_AUTOHSCROLL + CONTROL "Not Ready",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,317,17,50,14 + PUSHBUTTON "Start Game",IDC_BUTTON15,317,32,50,14 + PUSHBUTTON "Stop Game",IDC_BUTTON31,317,47,50,14 + PUSHBUTTON "Start Playing",IDC_BUTTON42,317,62,50,14,WS_GROUP + PUSHBUTTON "Is Playing?",IDC_BUTTON43,317,77,50,14,WS_GROUP + PUSHBUTTON "Start Reporting",IDC_BUTTON32,317,92,50,14 + PUSHBUTTON "State Changed",IDC_BUTTON33,317,107,50,14 + PUSHBUTTON "Get Info",IDC_BUTTON12,317,148,50,14 + PUSHBUTTON "Get Ready",IDC_BUTTON14,317,164,50,14 + PUSHBUTTON "Get Ping",IDC_BUTTON16,317,180,50,14 + PUSHBUTTON "Kick",IDC_BUTTON47,317,196,50,14 + EDITTEXT IDC_KEY,232,229,50,12,ES_AUTOHSCROLL + EDITTEXT IDC_VALUE,232,244,50,12,ES_AUTOHSCROLL + EDITTEXT IDC_PLAYER,232,259,50,12,ES_AUTOHSCROLL + CONTROL "Global",IDC_KEY_TYPE,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,287,239,36,10 + CONTROL "Room",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,287,254,35, + 10 + PUSHBUTTON "Set",IDC_BUTTON37,332,234,35,14,WS_GROUP + PUSHBUTTON "Get",IDC_BUTTON38,332,254,35,14 + CONTROL "Title",IDC_KEY_ROOM,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,242,279,29,10 + CONTROL "Group",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON,282,279, + 35,10 + CONTROL "Staging",IDC_RADIO8,"Button",BS_AUTORADIOBUTTON,327,279, + 40,10 + EDITTEXT IDC_MESSAGE,207,307,160,12,ES_AUTOHSCROLL | WS_GROUP + LISTBOX IDC_CHAT_LIST,207,322,160,35,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Server",IDC_STATIC,7,7,190,141 + LTEXT "Nick:",IDC_STATIC,71,56,18,8 + GROUPBOX "Players:",IDC_PLAYERS_BOX,137,276,60,86 + GROUPBOX "Rooms:",IDC_ROOMS_BOX,202,7,105,142 + GROUPBOX "Staging Room",IDC_STATIC,137,191,60,84 + GROUPBOX "Game",IDC_STATIC,312,7,60,122 + GROUPBOX "Player Info",IDC_STATIC,312,134,60,83 + GROUPBOX "Group Room",IDC_STATIC,72,191,60,84 + GROUPBOX "Title Room",IDC_STATIC,7,191,60,84 + GROUPBOX "Chat",IDC_STATIC,202,297,170,65 + GROUPBOX "Players:",IDC_PLAYERS_BOX2,72,276,60,86 + GROUPBOX "Players:",IDC_PLAYERS_BOX3,7,276,60,86 + LTEXT "Title:",IDC_STATIC,71,31,16,8 + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER, + 207,107,95,9 + LTEXT "Password:",IDC_STATIC,13,159,34,8 + LTEXT "Name:",IDC_STATIC,13,173,22,8 + GROUPBOX "Rooms",IDC_STATIC,7,148,190,41 + GROUPBOX "Keys",IDC_STATIC,202,219,170,75 + LTEXT "Key:",IDC_STATIC,207,231,15,8 + LTEXT "Value:",IDC_STATIC,207,246,21,8 + LTEXT "Room:",IDC_STATIC,207,279,22,8 + LTEXT "Player:",IDC_STATIC,207,262,22,8 + GROUPBOX "Away",IDC_STATIC,202,187,105,30 + LTEXT "Raw:",IDC_STATIC,12,121,18,8 + LTEXT "Filter:",IDC_STATIC,205,135,18,8 + LTEXT "Key:",IDC_STATIC,71,43,15,8 + LTEXT "CD Key:",IDC_STATIC,11,133,27,8 + GROUPBOX "AutoMatch",IDC_STATIC,202,149,105,37 + LTEXT "Max Players:",IDC_STATIC,239,159,41,8 + LTEXT "Status:",IDC_STATIC,239,172,23,8 + LTEXT "",IDC_AUTO_MATCH_STATUS,265,172,39,8 + LTEXT "Email:",IDC_STATIC,71,68,20,8 + LTEXT "Pass:",IDC_STATIC,71,81,18,8 + LTEXT "Namespace:",IDC_STATIC,132,81,41,8 + LTEXT "Auth Token:",IDC_STATIC,71,93,40,8 + LTEXT "Partner Challenge:",IDC_STATIC,71,106,59,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "PeerTest MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "PeerTest\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "PeerTest.EXE\0" + VALUE "ProductName", "PeerTest Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_PEERTEST_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 370 + TOPMARGIN, 7 + BOTTOMMARGIN, 362 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ABOUTBOX "&About PeerTest..." + IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\PeerTest.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTestDlg.cpp b/xrGameSpy/gamespy/Peer/PeerTest/PeerTestDlg.cpp new file mode 100644 index 00000000000..9b3d0373f00 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTestDlg.cpp @@ -0,0 +1,2863 @@ +// PeerTestDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "PeerTest.h" +#include "PeerTestDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define VERBOSE 0 + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +CPeerTestDlg * dlg; + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// Dialog Data + //{{AFX_DATA(CAboutDlg) + enum { IDD = IDD_ABOUTBOX }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CAboutDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestDlg dialog + +CPeerTestDlg::CPeerTestDlg(CWnd* pParent /*=NULL*/) + : CDialog(CPeerTestDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPeerTestDlg) + m_blocking = FALSE; + m_nick = _T("PeerPants"); + m_title = _T("gmtest"); + m_ready = FALSE; + m_message = _T(""); + m_password = _T(""); + m_name = _T("My Game"); + m_quiet = FALSE; + m_key = _T(""); + m_player = _T(""); + m_keyType = 0; + m_keyRoom = 0; + m_value = _T(""); + m_away = FALSE; + m_awayReason = _T(""); + m_raw = _T(""); + m_filter = _T(""); + m_secretKey = _T("HA6zkS"); + m_cdKey = _T(""); + m_autoMatchStatus = _T(""); + m_maxPlayers = 2; + m_email = _T(""); + m_loginPassword = _T(""); + m_namespace = _T("1"); + m_authToken = _T(""); + m_partnerChallenge = _T(""); + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + + // Check for cfg's. + /////////////////// + FILE * file; + gsi_char buffer[256]; + int rcode; + char dummy; + file = _tfopen(_T("peertest.cfg"), _T("rt")); + if(file) + { + rcode = _ftscanf(file, _T("%[^\n]%c"), buffer, &dummy); + if((rcode >= 1) && buffer[0]) + m_title = buffer; + rcode = _ftscanf(file, _T("%[^\n]%c"), buffer, &dummy); + if((rcode >= 1) && buffer[0]) + m_secretKey = buffer; + rcode = _ftscanf(file, _T("%[^\n]%c"), buffer, &dummy); + if((rcode >= 1) && buffer[0]) + m_nick = buffer; + rcode = _ftscanf(file, _T("%[^\n]%c"), buffer, &dummy); + if((rcode >= 1) && buffer[0]) + m_email = buffer; + rcode = _ftscanf(file, _T("%[^\n]%c"), buffer, &dummy); + if((rcode >= 1) && buffer[0]) + m_loginPassword = buffer; + rcode = _ftscanf(file, _T("%[^\n]%c"), buffer, &dummy); + if((rcode >= 1) && buffer[0]) + m_namespace = buffer; + fclose(file); + } + + // Set the nick if it was passed on the command line. + ///////////////////////////////////////////////////// + if(__argc == 2) + m_nick = __argv[1]; + + m_selectedNick = _T("PleaseSelectANick"); + m_selectedRoom = TitleRoom; +} + +void CPeerTestDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPeerTestDlg) + DDX_Control(pDX, IDC_PROGRESS, m_progress); + DDX_Control(pDX, IDC_TITLE_PLAYERS, m_playersT); + DDX_Control(pDX, IDC_GROUP_PLAYERS, m_playersG); + DDX_Control(pDX, IDC_STAGING_PLAYERS, m_playersS); + DDX_Control(pDX, IDC_PLAYERS_BOX3, m_playersBoxT); + DDX_Control(pDX, IDC_PLAYERS_BOX2, m_playersBoxG); + DDX_Control(pDX, IDC_PLAYERS_BOX, m_playersBoxS); + DDX_Control(pDX, IDC_CHAT_LIST, m_chatList); + DDX_Control(pDX, IDC_ROOMS, m_rooms); + DDX_Control(pDX, IDC_ROOMS_BOX, m_roomsBox); + DDX_Control(pDX, IDC_CHECK1, m_readyCtl); + DDX_Check(pDX, IDC_BLOCKING, m_blocking); + DDX_Text(pDX, IDC_NICK, m_nick); + DDV_MaxChars(pDX, m_nick, 127); + DDX_Text(pDX, IDC_TITLE, m_title); + DDX_Check(pDX, IDC_CHECK1, m_ready); + DDX_Text(pDX, IDC_MESSAGE, m_message); + DDX_Text(pDX, IDC_PASSWORD, m_password); + DDV_MaxChars(pDX, m_password, 23); + DDX_Text(pDX, IDC_NAME, m_name); + DDX_Check(pDX, IDC_QUIET, m_quiet); + DDX_Text(pDX, IDC_KEY, m_key); + DDX_Text(pDX, IDC_PLAYER, m_player); + DDX_Radio(pDX, IDC_KEY_TYPE, m_keyType); + DDX_Radio(pDX, IDC_KEY_ROOM, m_keyRoom); + DDX_Text(pDX, IDC_VALUE, m_value); + DDX_Check(pDX, IDC_AWAY, m_away); + DDX_Text(pDX, IDC_AWAY_REASON, m_awayReason); + DDX_Text(pDX, IDC_RAW, m_raw); + DDX_Text(pDX, IDC_FILTER, m_filter); + DDX_Text(pDX, IDC_SECRET_KEY, m_secretKey); + DDX_Text(pDX, IDC_CDKEY, m_cdKey); + DDX_Text(pDX, IDC_AUTO_MATCH_STATUS, m_autoMatchStatus); + DDX_Text(pDX, IDC_MAX_PLAYERS, m_maxPlayers); + DDX_Text(pDX, IDC_EMAIL, m_email); + DDX_Text(pDX, IDC_LOGIN_PASSWORD, m_loginPassword); + DDX_Text(pDX, IDC_NAMESPACE, m_namespace); + DDX_Text(pDX, IDC_AUTH_TOKEN, m_authToken); + DDX_Text(pDX, IDC_PARTNER_CHALLENGE, m_partnerChallenge); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CPeerTestDlg, CDialog) + //{{AFX_MSG_MAP(CPeerTestDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_BUTTON1, OnButton1) + ON_WM_TIMER() + ON_BN_CLICKED(IDC_BUTTON2, OnButton2) + ON_BN_CLICKED(IDC_BUTTON3, OnButton3) + ON_BN_CLICKED(IDC_BUTTON4, OnButton4) + ON_BN_CLICKED(IDC_BUTTON5, OnButton5) + ON_BN_CLICKED(IDC_BUTTON8, OnButton8) + ON_BN_CLICKED(IDC_BUTTON9, OnButton9) + ON_BN_CLICKED(IDC_BUTTON10, OnButton10) + ON_BN_CLICKED(IDC_BUTTON12, OnButton12) + ON_BN_CLICKED(IDC_BUTTON14, OnButton14) + ON_BN_CLICKED(IDC_CHECK1, OnCheck1) + ON_BN_CLICKED(IDC_BUTTON15, OnButton15) + ON_BN_CLICKED(IDC_BUTTON13, OnButton13) + ON_BN_CLICKED(IDC_BUTTON20, OnButton20) + ON_BN_CLICKED(IDC_BUTTON25, OnButton25) + ON_BN_CLICKED(IDC_BUTTON17, OnButton17) + ON_BN_CLICKED(IDC_BUTTON22, OnButton22) + ON_BN_CLICKED(IDC_BUTTON18, OnButton18) + ON_BN_CLICKED(IDC_BUTTON23, OnButton23) + ON_BN_CLICKED(IDC_BUTTON26, OnButton26) + ON_BN_CLICKED(IDC_BUTTON27, OnButton27) + ON_BN_CLICKED(IDC_BUTTON28, OnButton28) + ON_BN_CLICKED(IDC_BUTTON16, OnButton16) + ON_BN_CLICKED(IDC_BUTTON29, OnButton29) + ON_BN_CLICKED(IDC_BUTTON30, OnButton30) + ON_LBN_SELCHANGE(IDC_TITLE_PLAYERS, OnSelchangeTitlePlayers) + ON_LBN_SELCHANGE(IDC_GROUP_PLAYERS, OnSelchangeGroupPlayers) + ON_LBN_SELCHANGE(IDC_STAGING_PLAYERS, OnSelchangeStagingPlayers) + ON_BN_CLICKED(IDC_BUTTON6, OnButton6) + ON_BN_CLICKED(IDC_BUTTON7, OnButton7) + ON_BN_CLICKED(IDC_BUTTON21, OnButton21) + ON_BN_CLICKED(IDC_BUTTON24, OnButton24) + ON_BN_CLICKED(IDC_BUTTON31, OnButton31) + ON_BN_CLICKED(IDC_BUTTON32, OnButton32) + ON_BN_CLICKED(IDC_BUTTON33, OnButton33) + ON_BN_CLICKED(IDC_BUTTON34, OnButton34) + ON_BN_CLICKED(IDC_BUTTON35, OnButton35) + ON_BN_CLICKED(IDC_CHANGE_NICK, OnChangeNick) + ON_BN_CLICKED(IDC_QUIET, OnQuiet) + ON_BN_CLICKED(IDC_BUTTON37, OnButton37) + ON_BN_CLICKED(IDC_BUTTON38, OnButton38) + ON_LBN_SETFOCUS(IDC_TITLE_PLAYERS, OnSetfocusTitlePlayers) + ON_LBN_SETFOCUS(IDC_GROUP_PLAYERS, OnSetfocusGroupPlayers) + ON_LBN_SETFOCUS(IDC_STAGING_PLAYERS, OnSetfocusStagingPlayers) + ON_BN_CLICKED(IDC_AWAY, OnAway) + ON_BN_CLICKED(IDC_BUTTON39, OnButton39) + ON_BN_CLICKED(IDC_BUTTON40, OnButton40) + ON_BN_CLICKED(IDC_FIX_NICK, OnFixNick) + ON_BN_CLICKED(IDC_BUTTON11, OnButton11) + ON_BN_CLICKED(IDC_BUTTON42, OnButton42) + ON_BN_CLICKED(IDC_BUTTON43, OnButton43) + ON_BN_CLICKED(IDC_BUTTON44, OnButton44) + ON_BN_CLICKED(IDC_BUTTON45, OnButton45) + ON_BN_CLICKED(IDC_BUTTON46, OnButton46) + ON_LBN_DBLCLK(IDC_ROOMS, OnDblclkRooms) + ON_BN_CLICKED(IDC_BUTTON47, OnButton47) + ON_BN_CLICKED(IDC_BUTTON48, OnButton48) + ON_BN_CLICKED(IDC_START_AUTO_MATCH, OnStartAutoMatch) + ON_BN_CLICKED(IDC_STOP_AUTO_MATCH, OnStopAutoMatch) + ON_BN_CLICKED(IDC_BUTTON36, OnButton36) + ON_BN_CLICKED(IDC_BUTTON49, OnButton49) + ON_BN_CLICKED(IDC_BUTTON50, OnButton50) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestDlg message handlers + +BOOL CPeerTestDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Add "About..." menu item to system menu. + + // IDM_ABOUTBOX must be in the system command range. + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // TODO: Add extra initialization here + dlg = this; + SetTimer(100, 10, NULL); + m_peer = NULL; + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CPeerTestDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CPeerTestDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CPeerTestDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +static const gsi_char * RoomToString +( + RoomType roomType +) +{ + if(roomType == TitleRoom) + return _T("Title"); + + if(roomType == GroupRoom) + return _T("Group"); + + if(roomType == StagingRoom) + return _T("Staging"); + + return _T("?"); +} + +static void ClearPlayersList(CListBox & list) +{ + CString * str; + for(int i = 0 ; i < list.GetCount() ; i++) + { + str = (CString *)list.GetItemData(i); + if(str) + delete str; + } + list.ResetContent(); +} + +static void ClearRoomsList(CListBox & list) +{ + list.ResetContent(); +} + +static CListBox & m_players(RoomType roomType) +{ + switch(roomType) + { + case TitleRoom: + return dlg->m_playersT; + case GroupRoom: + return dlg->m_playersG; + case StagingRoom: + return dlg->m_playersS; + default: + ASSERT(0); + } + + static CListBox dummy; + return dummy; +} + +static CButton & m_playersBox(RoomType roomType) +{ + switch(roomType) + { + case TitleRoom: + return dlg->m_playersBoxT; + case GroupRoom: + return dlg->m_playersBoxG; + case StagingRoom: + return dlg->m_playersBoxS; + default: + ASSERT(0); + } + + static CButton dummy; + return dummy; +} + +static void DisconnectedCallback +( + PEER peer, + const gsi_char * reason, + void * param +) +{ + CString message = "Disconnected: "; + message += reason; + dlg->MessageBox(message); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void RoomMessageCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * message, + MessageType messageType, + void * param +) +{ + int c; + + c = *RoomToString(roomType); + + gsi_char buffer[2048]; + if(messageType == NormalMessage) + { + _stprintf(buffer, _T("%c]%s: %s"), + c, + nick, + message); + } + else if(messageType == ActionMessage) + { + _stprintf(buffer, _T("%c]%s %s"), + c, + nick, + message); + } + else + { + _stprintf(buffer, _T("%c]*%s*: %s"), + c, + nick, + message); + } + int index = dlg->m_chatList.InsertString(-1, buffer); + +#if VERBOSE + OutputDebugString(buffer); + OutputDebugString("\n"); +#endif + + dlg->m_chatList.SetCurSel(index); + dlg->m_chatList.SetCurSel(-1); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void RoomUTMCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * command, + const gsi_char * parameters, + PEERBool authenticated, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T(" UTM %s| %s | %s | %s | %s\n"), + authenticated?"(authenticated) ":"", + RoomToString(roomType), + nick, + command, + parameters); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(authenticated); + GSI_UNUSED(parameters); + GSI_UNUSED(command); + GSI_UNUSED(nick); + GSI_UNUSED(roomType); + GSI_UNUSED(peer); +} + +static void RoomNameChangedCallback +( + PEER peer, + RoomType roomType, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T(" NAME | %s | %s\n"), + RoomToString(roomType), + peerGetRoomName(peer, roomType)); + + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(peer); + GSI_UNUSED(roomType); +} + +const gsi_char * ModeToString +( + CHATChannelMode * mode +) +{ + static gsi_char buffer[256]; + buffer[0] = '\0'; + + if(mode->InviteOnly) + _tcscat(buffer,_T("InviteOnly+")); + if(mode->Private) + _tcscat(buffer,_T("Private+")); + if(mode->Secret) + _tcscat(buffer,_T("Secret+")); + if(mode->Moderated) + _tcscat(buffer,_T("Moderated+")); + if(mode->NoExternalMessages) + _tcscat(buffer,_T("NoExternalMessages+")); + if(mode->OnlyOpsChangeTopic) + _tcscat(buffer,_T("OnlyOpsChangeTopic+")); + + if(buffer[0]) + buffer[_tcslen(buffer) - 1] = '\0'; + + return buffer; +} + +static void RoomModeChangedCallback +( + PEER peer, + RoomType roomType, + CHATChannelMode * mode, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T(" MODE | %s | %s\n"), + RoomToString(roomType), + ModeToString(mode)); + + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(mode); + GSI_UNUSED(roomType); + GSI_UNUSED(peer); +} + +static void PlayerMessageCallback +( + PEER peer, + const gsi_char * nick, + const gsi_char * message, + MessageType messageType, + void * param +) +{ + gsi_char buffer[2048]; + if(messageType == NormalMessage) + { + _stprintf(buffer, _T("%s: %s"), + nick, + message); + } + else if(messageType == ActionMessage) + { + _stprintf(buffer, _T("%s %s"), + nick, + message); + } + else + { + _stprintf(buffer, _T("*%s*: %s"), + nick, + message); + } + int index = dlg->m_chatList.InsertString(-1, buffer); + +#if VERBOSE + OutputDebugString(buffer); + OutputDebugString("\n"); +#endif + + dlg->m_chatList.SetCurSel(index); + dlg->m_chatList.SetCurSel(-1); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void PlayerUTMCallback +( + PEER peer, + const gsi_char * nick, + const gsi_char * command, + const gsi_char * parameters, + PEERBool authenticated, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T(" UTM %s| %s | %s | %s\n"), + authenticated?"(authenticated) ":"", + nick, + command, + parameters); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(authenticated); + GSI_UNUSED(parameters); + GSI_UNUSED(command); + GSI_UNUSED(nick); + GSI_UNUSED(peer); +} + +static void ReadyChangedCallback +( + PEER peer, + const gsi_char * nick, + PEERBool ready, + void * param +) +{ + gsi_char buffer[256]; + if(ready) + _stprintf(buffer, _T("%s is ready\n"), nick); + else + _stprintf(buffer, _T("%s is not ready\n"), nick); + OutputDebugString(buffer); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void GameStartedCallback +( + PEER peer, + SBServer server, + const gsi_char * message, + void * param +) +{ + gsi_char buffer[256]; + _stprintf(buffer, _T("The game is starting: %s:%d %s"), + SBServerGetPublicAddress(server), SBServerGetIntValue(server, _T("hostport"), 0), message); + dlg->MessageBox(buffer); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void PlayerJoinedCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + void * param +) +{ + dlg->FillPlayerList(roomType); + + GSI_UNUSED(param); + GSI_UNUSED(nick); + GSI_UNUSED(peer); +} + +static void PlayerLeftCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * reason, + void * param +) +{ + dlg->FillPlayerList(roomType); + + GSI_UNUSED(param); + GSI_UNUSED(reason); + GSI_UNUSED(nick); + GSI_UNUSED(peer); +} + +static void KickedCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * reason, + void * param +) +{ + CString str; + str.Format(_T("Kicked from %s by %s: \"%s\""), RoomToString(roomType), nick, reason); + dlg->MessageBox(str); + ClearPlayersList(m_players(roomType)); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void NewPlayerListCallback +( + PEER peer, + RoomType roomType, + void * param +) +{ + dlg->FillPlayerList(roomType); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void PlayerChangedNickCallback +( + PEER peer, + RoomType roomType, + const gsi_char * oldNick, + const gsi_char * newNick, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T(" NICK | %s | %s\n"), oldNick, newNick); + OutputDebugString(buffer); +#endif + + // Update the player list for this room. + //////////////////////////////////////// + dlg->FillPlayerList(roomType); + + GSI_UNUSED(param); + GSI_UNUSED(newNick); + GSI_UNUSED(oldNick); + GSI_UNUSED(peer); +} + +static void PlayerInfoCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + unsigned int IP, + int profileID, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + IN_ADDR addr; + addr.s_addr = IP; + _stprintf(buffer, _T(" INFO | %s | %s | %s | %d\n"), RoomToString(roomType), nick?nick:"(END)", inet_ntoa(addr), profileID); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(profileID); + GSI_UNUSED(IP); + GSI_UNUSED(nick); + GSI_UNUSED(roomType); + GSI_UNUSED(peer); +} + +static void FlagsToString +( + int flags, + CString & str +) +{ + if(!flags) + { + str = "(none)"; + return; + } + + str = ""; + + if(flags & PEER_FLAG_STAGING) + str += "staging+"; + if(flags & PEER_FLAG_READY) + str += "ready+"; + if(flags & PEER_FLAG_PLAYING) + str += "playing+"; + if(flags & PEER_FLAG_AWAY) + str += "away+"; + if(flags & PEER_FLAG_HOST) + str += "host+"; + if(flags & PEER_FLAG_OP) + str += "op+"; + if(flags & PEER_FLAG_VOICE) + str += "voice+"; + + if(!str.IsEmpty()) + str.Delete(str.GetLength() - 1); +} + +static void PlayerFlagsChangedCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + int oldFlags, + int newFlags, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + CString strOldFlags; + CString strNewFlags; + + FlagsToString(oldFlags, strOldFlags); + FlagsToString(newFlags, strNewFlags); + + _stprintf(buffer, _T(" FLAGS | %s | %s | %s=>%s\n"), RoomToString(roomType), nick, strOldFlags, strNewFlags); + OutputDebugString(buffer); +#endif + + // If the host flag changed, refresh the room. + ////////////////////////////////////////////// + if((oldFlags ^ newFlags) & PEER_FLAG_HOST) + dlg->FillPlayerList(roomType); + + GSI_UNUSED(param); + GSI_UNUSED(nick); + GSI_UNUSED(peer); +} + +static int FindPingPlayersNick +( + const gsi_char * nick +) +{ + CListBox & list = dlg->m_pingPlayers; + int count; + int i; + CString text; + int start; + + count = list.GetCount(); + for(i = 0 ; i < count ; i++) + { + list.GetText(i, text); + + start = text.Find('-'); + ASSERT(start != -1); + + if(text.Mid(start + 1).CompareNoCase(nick) == 0) + return i; + } + + return -1; +} + +static void PingCallback +( + PEER peer, + const gsi_char * nick, + int ping, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T(" PING | %s | %d\n"), nick, ping); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(ping); + GSI_UNUSED(nick); + GSI_UNUSED(peer); +} + +static void CrossPingCallback +( + PEER peer, + const gsi_char * nick1, + const gsi_char * nick2, + int crossPing, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T("XPING | %s<->%s | %d\n"), nick1, nick2, crossPing); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(crossPing); + GSI_UNUSED(nick2); + GSI_UNUSED(nick1); + GSI_UNUSED(peer); +} + +static void GlobalKeyChangedCallback +( + PEER peer, + const gsi_char * nick, + const gsi_char * key, + const gsi_char * value, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T("KEY | %s | %s = %s\n"), nick, key, value); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(value); + GSI_UNUSED(key); + GSI_UNUSED(nick); + GSI_UNUSED(peer); +} + +static void RoomKeyChangedCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * key, + const gsi_char * value, + void * param +) +{ +#if VERBOSE + gsi_char buffer[256]; + _stprintf(buffer, _T("KEY | %s | %s | %s = %s\n"), nick, RoomToString(roomType), key, value); + OutputDebugString(buffer); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(value); + GSI_UNUSED(key); + GSI_UNUSED(nick); + GSI_UNUSED(roomType); + GSI_UNUSED(peer); +} + +static const gsi_char * KeyTypeToString(qr2_key_type type) +{ + switch(type) + { + case key_server: + return _T("server"); + case key_player: + return _T("player"); + case key_team: + return _T("team"); + } + + ASSERT(0); + return _T("Unkown key type"); +} + +static const gsi_char * ErrorTypeToString(qr2_error_t error) +{ + switch(error) + { + case e_qrnoerror: + return _T("noerror"); + case e_qrwsockerror: + return _T("wsockerror"); + case e_qrbinderror: + return _T("rbinderror"); + case e_qrdnserror: + return _T("dnserror"); + case e_qrconnerror: + return _T("connerror"); + case e_qrnochallengeerror: + return _T("nochallengeerror"); + } + + ASSERT(0); + return _T("Unknown error type"); +} + +static void QRServerKeyCallback +( + PEER peer, + int key, + qr2_buffer_t buffer, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, "QR_SERVER_KEY | %d\n", key); + OutputDebugString(verbose); +#endif + + switch(key) + { + case HOSTNAME_KEY: + qr2_buffer_add(buffer, _T("My Game")); + break; + case NUMPLAYERS_KEY: + qr2_buffer_add_int(buffer, 1); + break; + case MAXPLAYERS_KEY: + qr2_buffer_add_int(buffer, 4); + break; + case GAMEMODE_KEY: + qr2_buffer_add(buffer, _T("openplaying")); + break; + case HOSTPORT_KEY: + qr2_buffer_add_int(buffer, 15151); + break; + case MAPNAME_KEY: + qr2_buffer_add(buffer, _T("Big Crate Room")); + break; + case GAMETYPE_KEY: + qr2_buffer_add(buffer, _T("Friendly")); + break; + case TIMELIMIT_KEY: + qr2_buffer_add_int(buffer, 100); + break; + case FRAGLIMIT_KEY: + qr2_buffer_add_int(buffer, 0); + break; + case TEAMPLAY_KEY: + qr2_buffer_add_int(buffer, 0); + break; + default: + qr2_buffer_add(buffer, _T("")); + break; + } + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void QRPlayerKeyCallback +( + PEER peer, + int key, + int index, + qr2_buffer_t buffer, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, "QR_PLAYER_KEY | %d | %d\n", key, index); + OutputDebugString(verbose); +#endif + + switch(key) + { + case PLAYER__KEY: + qr2_buffer_add(buffer, _T("Johnny McJohnson")); + break; + case PING__KEY: + qr2_buffer_add_int(buffer, 17); + break; + default: + qr2_buffer_add(buffer, _T("")); + break; + } + + GSI_UNUSED(param); + GSI_UNUSED(index); + GSI_UNUSED(peer); +} + +static void QRTeamKeyCallback +( + PEER peer, + int key, + int index, + qr2_buffer_t buffer, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, "QR_TEAM_KEY | %d | %d\n", key, index); + OutputDebugString(verbose); +#endif + + // we don't report teams, so this shouldn't get called + qr2_buffer_add(buffer, _T("")); + + GSI_UNUSED(param); + GSI_UNUSED(key); + GSI_UNUSED(index); + GSI_UNUSED(peer); +} + +static void QRKeyListCallback +( + PEER peer, + qr2_key_type type, + qr2_keybuffer_t keyBuffer, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, "QR_KEY_LIST | %s\n", KeyTypeToString(type)); + OutputDebugString(verbose); +#endif + + // register the keys we use + switch(type) + { + case key_server: + if(!peerIsAutoMatching(peer)) + { + qr2_keybuffer_add(keyBuffer, HOSTPORT_KEY); + qr2_keybuffer_add(keyBuffer, MAPNAME_KEY); + qr2_keybuffer_add(keyBuffer, GAMETYPE_KEY); + qr2_keybuffer_add(keyBuffer, TIMELIMIT_KEY); + qr2_keybuffer_add(keyBuffer, FRAGLIMIT_KEY); + qr2_keybuffer_add(keyBuffer, TEAMPLAY_KEY); + } + break; + case key_player: + // no custom player keys + break; + case key_team: + // no custom team keys + break; + } + + GSI_UNUSED(param); +} + +static int QRCountCallback +( + PEER peer, + qr2_key_type type, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, "QR_COUNT | %s\n", KeyTypeToString(type)); + OutputDebugString(verbose); +#endif + + if(type == key_player) + return 1; + else if(type == key_team) + return 0; + + return 0; + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void QRAddErrorCallback +( + PEER peer, + qr2_error_t error, + gsi_char * errorString, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, "QR_ADD_ERROR | %s | %s\n", ErrorTypeToString(error), errorString); + OutputDebugString(verbose); +#endif + + CString str; + str.Format(_T("Reporting error: %s (%s)"), ErrorTypeToString(error), errorString); + dlg->MessageBox(str); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void QRNatNegotiateCallback +( + PEER peer, + int cookie, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, _T("QR_NAT_NEGOTIATE | 0x%08X\n"), cookie); + OutputDebugString(verbose); +#endif + + CString str; + str.Format(_T("Received Nat Negotiate Cookie: 0x%08X"), cookie); + dlg->MessageBox(str); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void QRPublicAddressCallback +( + PEER peer, + unsigned int ip, + unsigned short port, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + struct in_addr addr; + addr.s_addr = ip; + _stprintf(verbose, _T("QR_PUBLIC_ADDRESS | %s:%d\n"), inet_ntoa(addr), port); + OutputDebugString(verbose); +#endif + + GSI_UNUSED(param); + GSI_UNUSED(port); + GSI_UNUSED(ip); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnButton7() +{ + if(!m_peer) + { + GSIStartAvailableCheck("gmtest"); + GSIACResult result; + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(10); + + if(result == GSIACUnavailable) + MessageBox("This game's backend services are unavailable."); + else if(result == GSIACTemporarilyUnavailable) + MessageBox("This game's backend services are temporarily unavailable.\nPlease try again later."); + else + { + PEERCallbacks callbacks; + memset(&callbacks, 0, sizeof(PEERCallbacks)); + callbacks.disconnected = DisconnectedCallback; + callbacks.readyChanged = ReadyChangedCallback; + callbacks.roomMessage = RoomMessageCallback; + callbacks.roomUTM = RoomUTMCallback; + callbacks.roomNameChanged = RoomNameChangedCallback; + callbacks.roomModeChanged = RoomModeChangedCallback; + callbacks.playerMessage = PlayerMessageCallback; + callbacks.playerUTM = PlayerUTMCallback; + callbacks.gameStarted = GameStartedCallback; + callbacks.playerJoined = PlayerJoinedCallback; + callbacks.playerLeft = PlayerLeftCallback; + callbacks.kicked = KickedCallback; + callbacks.newPlayerList = NewPlayerListCallback; + callbacks.playerChangedNick = PlayerChangedNickCallback; + callbacks.playerInfo = PlayerInfoCallback; + callbacks.playerFlagsChanged = PlayerFlagsChangedCallback; + callbacks.ping = PingCallback; + callbacks.crossPing = CrossPingCallback; + callbacks.globalKeyChanged = GlobalKeyChangedCallback; + callbacks.roomKeyChanged = RoomKeyChangedCallback; + callbacks.qrServerKey = QRServerKeyCallback; + callbacks.qrPlayerKey = QRPlayerKeyCallback; + callbacks.qrTeamKey = QRTeamKeyCallback; + callbacks.qrKeyList = QRKeyListCallback; + callbacks.qrCount = QRCountCallback; + callbacks.qrAddError = QRAddErrorCallback; + callbacks.qrNatNegotiateCallback = QRNatNegotiateCallback; + callbacks.qrPublicAddressCallback = QRPublicAddressCallback; + callbacks.param = NULL; + + m_peer = peerInitialize(&callbacks); + if(!m_peer) + dlg->MessageBox(_T("Init: failure")); + } + } +} + +static void ConnectCallback +( + PEER peer, + PEERBool success, + int failureReason, + void * param +) +{ + CString str; + if(success) + str.Format(_T("Connect: success")); + else + { + CString reason; + if(failureReason == PEER_DISCONNECTED) + reason = "disconnected"; + else if(failureReason == PEER_NICK_ERROR) + reason = "nick error"; + else if(failureReason == PEER_LOGIN_FAILED) + reason = "login failed"; + else + reason = "unknown"; + str.Format(_T("Connect: failure (%s)"), reason); + } + dlg->MessageBox(str); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void NickErrorCallback +( + PEER peer, + int type, + const gsi_char * nick, + int numSuggestedNicks, + const char ** suggestedNicks, + void * param +) +{ + CString str; + gsi_char retryNick[64]; + int rcode; + + if(type == PEER_IN_USE) + { + _stprintf(retryNick, "PeerTest%d", rand() % 100); + str.Format("Nick '%s' in use.\nRetry with random nick '%s'?", nick, retryNick); + rcode = dlg->MessageBox(str, NULL, MB_YESNO); + peerRetryWithNick(peer, (rcode == IDYES)?retryNick:NULL); + return; + } + + if(type == PEER_NICK_TOO_LONG) + { + _stprintf(retryNick, "PeerTest%d", rand() % 100); + str.Format("Nick '%s' too long.\nRetry with random nick '%s'?", nick, retryNick); + rcode = dlg->MessageBox(str, NULL, MB_YESNO); + peerRetryWithNick(peer, (rcode == IDYES)?retryNick:NULL); + return; + } + if(type == PEER_INVALID) + { + peerFixNick(retryNick, nick); + str.Format(_T("Invalid nick '%s'.\nRetry with fixed nick '%s'?"), nick, retryNick); + rcode = dlg->MessageBox(str, NULL, MB_YESNO); + peerRetryWithNick(peer, (rcode == IDYES)?retryNick:NULL); + return; + } + + if(type == PEER_UNIQUENICK_EXPIRED) + { + dlg->UpdateData(); + str.Format(_T("This account's unique nick has expired.\nRegister '%s'?"), dlg->m_nick); + rcode = dlg->MessageBox(str, NULL, MB_YESNO); + peerRegisterUniqueNick(peer, atoi(dlg->m_namespace), (rcode == IDYES)?((LPCSTR)dlg->m_nick):NULL, NULL); + return; + } + + if(type == PEER_NO_UNIQUENICK) + { + dlg->UpdateData(); + str.Format(_T("This account has no unique nick.\nRegister '%s'?"), dlg->m_nick); + rcode = dlg->MessageBox(str, NULL, MB_YESNO); + peerRegisterUniqueNick(peer, atoi(dlg->m_namespace), (rcode == IDYES)?((LPCSTR)dlg->m_nick):NULL, NULL); + return; + } + + if(type == PEER_INVALID_UNIQUENICK) + { + if(numSuggestedNicks <= 0) + { + dlg->MessageBox(_T("Invalid unique nick with no suggestions!")); + peerRegisterUniqueNick(peer, 0, NULL, NULL); + return; + } + + dlg->UpdateData(); + + for(int i = 0 ; i < numSuggestedNicks ; i++) + { + str.Format(_T("The unique nick you attempted to register is either invalid or already in use.\nWould you like to register '%s'?"), suggestedNicks[i]); + rcode = dlg->MessageBox(str, NULL, MB_YESNOCANCEL); + if(rcode == IDCANCEL) + break; + if(rcode == IDYES) + { + peerRegisterUniqueNick(peer, atoi(dlg->m_namespace), suggestedNicks[i], NULL); + return; + } + } + peerRegisterUniqueNick(peer, 0, NULL, NULL); + return; + } + + GSI_UNUSED(param); +} + +void CPeerTestDlg::OnButton1() +{ + if(m_peer) + { + if(peerIsConnected(m_peer)) + { + MessageBox("Already connected"); + return; + } + + UpdateData(); + + peerConnect( + m_peer, + m_nick, + 0, + NickErrorCallback, + ConnectCallback, + this, + (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnButton36() +{ + if(m_peer) + { + if(peerIsConnected(m_peer)) + { + MessageBox("Already connected"); + return; + } + + UpdateData(); + + if(m_namespace.IsEmpty() || !isdigit(m_namespace.GetAt(0))) + { + MessageBox("Enter a namespace of 0 or greater"); + return; + } + + peerConnectLogin( + m_peer, + atoi(m_namespace), + m_email, + m_nick, + NULL, + m_loginPassword, + NickErrorCallback, + ConnectCallback, + this, + (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnButton50() +{ + if(m_peer) + { + if(peerIsConnected(m_peer)) + { + MessageBox("Already connected"); + return; + } + + UpdateData(); + + if(m_namespace.IsEmpty() || !isdigit(m_namespace.GetAt(0))) + { + MessageBox("Enter a namespace of 0 or greater"); + return; + } + + peerConnectLogin( + m_peer, + atoi(m_namespace), + NULL, + NULL, + m_nick, + m_loginPassword, + NickErrorCallback, + ConnectCallback, + this, + (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnButton49() +{ + if(m_peer) + { + if(peerIsConnected(m_peer)) + { + MessageBox("Already connected"); + return; + } + + UpdateData(); + + peerConnectPreAuth( + m_peer, + m_authToken, + m_partnerChallenge, + NickErrorCallback, + ConnectCallback, + this, + (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnButton21() +{ + if(m_peer) + { + peerShutdown(m_peer); + m_peer = NULL; + } +} + +void CPeerTestDlg::OnTimer(UINT nIDEvent) +{ + if(nIDEvent == 100) + { + if(m_peer) + { + peerThink(m_peer); + } + } + + CDialog::OnTimer(nIDEvent); +} + +void EnumPlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const gsi_char * nick, + int flags, + void * param +) +{ + if(!success) + { + dlg->MessageBox(_T("EnumPlayers failed")); + return; + } + + if(index == -1) + return; + + dlg->m_count++; + if(flags & PEER_FLAG_HOST) + { + gsi_char buffer[128]; + _stprintf(buffer, _T("HOST: %s"), nick); + m_players(roomType).AddString(buffer); + } + else + m_players(roomType).AddString(nick); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::FillPlayerList +( + RoomType roomType +) +{ + UpdateData(); + ClearPlayersList(m_players(roomType)); + m_count = 0; + if(peerInRoom(m_peer, roomType)) + peerEnumPlayers(m_peer, roomType, EnumPlayersCallback, NULL); + + gsi_char buffer[128]; + _stprintf(buffer, _T("Players: %d"), dlg->m_count); + m_playersBox(roomType).SetWindowText(buffer); +} + +static const gsi_char * ResultToString +( + PEERJoinResult result +) +{ + switch(result) + { + case PEERJoinSuccess: + return _T("Success"); + case PEERFullRoom: + return _T("Full"); + case PEERInviteOnlyRoom: + return _T("Invite Only"); + case PEERBannedFromRoom: + return _T("Banned"); + case PEERBadPassword: + return _T("Bad Password"); + case PEERAlreadyInRoom: + return _T("Already in room"); + case PEERNoTitleSet: + return _T("No Title"); + case PEERNoConnection: + return _T("No Connection"); + case PEERAutoMatching: + return _T("Auto Matching"); + case PEERJoinFailed: + return _T("Join Failed"); + } + + ASSERT(0); + return _T(""); +} + +static void JoinRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + if(!success) + { + CString msg; + msg.Format(_T("Join failure: %s"), ResultToString(result)); + dlg->MessageBox(msg); + } + else + { + dlg->FillPlayerList(roomType); + if(roomType == StagingRoom) + { + dlg->m_name = peerGetRoomName(peer, StagingRoom); + dlg->UpdateData(FALSE); + } + } + + GSI_UNUSED(param); +} + +void CPeerTestDlg::OnButton2() +{ + if(m_peer) + { + UpdateData(); + peerCreateStagingRoom(m_peer, m_name, 6, m_password, JoinRoomCallback, NULL, (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnButton3() +{ + if(m_peer) + { + UpdateData(); + SBServer server = GetCurrentServer(); + if(server) + { + if(SBServerGetIntValue(server, _T("password"), 0) && !m_password.GetLength()) + dlg->MessageBox(_T("This server requires a password")); + peerJoinStagingRoom(m_peer, server, m_password, JoinRoomCallback, NULL, (PEERBool)m_blocking); + } + } +} + +void CPeerTestDlg::OnButton17() +{ + if(m_peer) + { + SBServer server = GetCurrentServer(); + if(server) + { + int groupID = ntohl(SBServerGetPublicInetAddress(server)); + if(groupID != 0) + peerJoinGroupRoom(m_peer, groupID, JoinRoomCallback, NULL, (PEERBool)m_blocking); + } + } +} + +void CPeerTestDlg::OnButton22() +{ + if(m_peer) + { + peerJoinTitleRoom(m_peer, NULL, JoinRoomCallback, NULL, (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::PostNcDestroy() +{ + if(m_peer) + { + peerShutdown(m_peer); + m_peer = NULL; + } + + CDialog::PostNcDestroy(); +} + +void CPeerTestDlg::OnButton4() +{ + if(m_peer) + { + UpdateData(); + m_ready = FALSE; + UpdateData(FALSE); + peerLeaveRoom(m_peer, StagingRoom, NULL); + ClearPlayersList(m_players(StagingRoom)); + } +} + +void CPeerTestDlg::OnButton18() +{ + if(m_peer) + { + peerLeaveRoom(m_peer, GroupRoom, NULL); + ClearPlayersList(m_players(GroupRoom)); + } +} + +void CPeerTestDlg::OnButton23() +{ + if(m_peer) + { + peerLeaveRoom(m_peer, TitleRoom, NULL); + ClearPlayersList(m_players(TitleRoom)); + } +} + +void CPeerTestDlg::OnButton5() +{ + if(m_peer) + { + peerDisconnect(m_peer); + } +} + +void ListGroupRoomsCallback +( + PEER peer, + PEERBool success, + int groupID, + SBServer server, + const gsi_char * name, + int numWaiting, + int maxWaiting, + int numGames, + int numPlaying, + void * param +) +{ + if(!success) + { + dlg->MessageBox(_T("Failed to list the group rooms")); + return; + } + + if(groupID == 0) + { + gsi_char buffer[128]; + _stprintf(buffer, _T("Rooms: %d"), dlg->m_count); + dlg->m_roomsBox.SetWindowText(buffer); + return; + } + + int nIndex = dlg->m_rooms.AddString(name); + if(nIndex >= 0) + { + dlg->m_rooms.SetItemDataPtr(nIndex, server); + dlg->m_count++; + gsi_char buffer[32]; + _stprintf(buffer, _T("Rooms: %d"), dlg->m_count); + dlg->m_roomsBox.SetWindowText(buffer); + } + + GSI_UNUSED(param); + GSI_UNUSED(numPlaying); + GSI_UNUSED(numGames); + GSI_UNUSED(maxWaiting); + GSI_UNUSED(numWaiting); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnButton6() +{ + if(m_peer) + { + UpdateData(); + + ClearRoomsList(m_rooms); + m_count = 0; + peerListGroupRooms(m_peer, _T(""), ListGroupRoomsCallback, NULL, (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnButton8() +{ + if(m_peer) + { + FillPlayerList(TitleRoom); + } +} + +void CPeerTestDlg::OnButton9() +{ + if(m_peer) + { + FillPlayerList(GroupRoom); + } +} + +void CPeerTestDlg::OnButton10() +{ + if(m_peer) + { + FillPlayerList(StagingRoom); + } +} + +void GetPlayerIPCallback +( + PEER peer, + PEERBool success, + const gsi_char * nick, + unsigned int IP, + void * param +) +{ + gsi_char buffer[128]; + + if(success) + { + IN_ADDR inAddr; + inAddr.S_un.S_addr = IP; + _stprintf(buffer, _T("%s's IP is %s"), nick, inet_ntoa(inAddr)); + } + else + _stprintf(buffer, _T("failed to get %s's IP"), nick); + + dlg->MessageBox(buffer); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnButton12() +{ + if(m_peer) + { + gsi_char buffer[512]; + unsigned int IP; + int profileID; + + if(!peerGetPlayerInfoNoWait(m_peer, m_selectedNick, &IP, &profileID)) + _stprintf(buffer, _T("Info Not Available")); + else + { + IN_ADDR addr; + addr.s_addr = IP; + + _stprintf(buffer, _T("IP = %s\npid = %d"), inet_ntoa(addr), profileID); + + CString strFlags; + int nFlags; + RoomType roomType; + int i; + for(i = 0 ; i < (int)NumRooms ; i++) + { + roomType = (RoomType)i; + + if(peerInRoom(m_peer, roomType)) + { + if(peerGetPlayerFlags(m_peer, m_selectedNick, roomType, &nFlags)) + { + if(roomType == TitleRoom) + _tcscat(buffer,_T("\ntitle room flags = ")); + else if(roomType == GroupRoom) + _tcscat(buffer,_T("\ngroup room flags = ")); + else if(roomType == StagingRoom) + _tcscat(buffer,_T("\nstaging room flags = ")); + + if(!nFlags) + _tcscat(buffer,_T("N/A")); + else + { + if(nFlags & PEER_FLAG_STAGING) + _tcscat(buffer,_T("staging+")); + if(nFlags & PEER_FLAG_READY) + _tcscat(buffer,_T("ready+")); + if(nFlags & PEER_FLAG_PLAYING) + _tcscat(buffer,_T("playing+")); + if(nFlags & PEER_FLAG_AWAY) + _tcscat(buffer,_T("away+")); + if(nFlags & PEER_FLAG_HOST) + _tcscat(buffer, _T("host+")); + if(nFlags & PEER_FLAG_OP) + _tcscat(buffer,_T("op+")); + if(nFlags & PEER_FLAG_VOICE) + _tcscat(buffer,_T("voice+")); + buffer[_tcslen(buffer) - 1] = '\0'; + } + } + } + } + } + + CString caption; + caption.Format(_T("Info for %s"), m_selectedNick); + MessageBox(buffer, caption); + } +} + +void CPeerTestDlg::OnButton14() +{ + if(m_peer) + { + UpdateData(); + + PEERBool ready; + if(peerGetReady(m_peer, m_selectedNick, &ready)) + { + if(ready) + MessageBox(_T("Ready")); + else + MessageBox(_T("Not Ready")); + } + else + { + MessageBox(_T("Ready failed")); + } + } +} + +void CPeerTestDlg::OnCheck1() +{ + if(m_peer) + { + UpdateData(); + + peerSetReady(m_peer, (PEERBool)m_ready); + + if(m_ready) + m_readyCtl.SetWindowText(_T("Ready")); + else + m_readyCtl.SetWindowText(_T("Not Ready")); + } +} + +void CPeerTestDlg::OnButton15() +{ + if(m_peer) + { + UpdateData(); + peerStartGame(m_peer, NULL, PEER_KEEP_REPORTING); + } +} + +void CPeerTestDlg::OnButton13() +{ + if(m_peer) + { + UpdateData(); + peerMessageRoom(m_peer, StagingRoom, m_message, NormalMessage); + m_message = _T(""); + UpdateData(FALSE); + } +} + +void CPeerTestDlg::OnButton20() +{ + if(m_peer) + { + UpdateData(); + peerMessageRoom(m_peer, GroupRoom, m_message, NormalMessage); + m_message = _T(""); + UpdateData(FALSE); + } +} + +void CPeerTestDlg::OnButton25() +{ + if(m_peer) + { + UpdateData(); + peerMessageRoom(m_peer, TitleRoom, m_message, NormalMessage); + m_message = _T(""); + UpdateData(FALSE); + } +} + +void CPeerTestDlg::OnButton26() +{ + if(m_peer) + { + const gsi_char * name = peerGetRoomName(m_peer, TitleRoom); + const gsi_char * channel = peerGetRoomChannel(m_peer, TitleRoom); + if(!name || !channel) + dlg->MessageBox(_T("Failed to get room info.")); + else + { + gsi_char buffer[256]; + _stprintf(buffer, _T("Name: %s\nChannel: %s\nUsers: %d"), name, channel, chatGetChannelNumUsers(peerGetChat(m_peer), channel)); + dlg->MessageBox(buffer); + } + } +} + +void CPeerTestDlg::OnButton27() +{ + if(m_peer) + { + const gsi_char * name = peerGetRoomName(m_peer, GroupRoom); + const gsi_char * channel = peerGetRoomChannel(m_peer, GroupRoom); + if(!name) + dlg->MessageBox(_T("Failed to get room info.")); + else + { + gsi_char buffer[256]; + _stprintf(buffer, _T("Name: %s\nChannel: %s\nUsers: %d"), name, channel, chatGetChannelNumUsers(peerGetChat(m_peer), channel)); + dlg->MessageBox(buffer); + } + } +} + +void CPeerTestDlg::OnButton28() +{ + if(m_peer) + { + const gsi_char * name = peerGetRoomName(m_peer, StagingRoom); + const gsi_char * channel = peerGetRoomChannel(m_peer, StagingRoom); + if(!name) + dlg->MessageBox(_T("Failed to get room info.")); + else + { + gsi_char buffer[256]; + _stprintf(buffer, _T("Name: %s\nChannel: %s\nUsers: %d"), name, channel, chatGetChannelNumUsers(peerGetChat(m_peer), channel)); + dlg->MessageBox(buffer); + } + } +} + +BOOL CPeerTestDlg::DestroyWindow() +{ + ClearRoomsList(m_rooms); + + // Save some info. + ////////////////// + FILE * file; + file = _tfopen(_T("peertest.cfg"), _T("wt")); + if(file) + { + _ftprintf(file, _T("%s\n%s\n%s\n%s\n%s\n%s\n"), + m_title, m_secretKey, m_nick, m_email, m_loginPassword, m_namespace); + fclose(file); + } + + return CDialog::DestroyWindow(); +} + + +void CPeerTestDlg::OnButton16() +{ + if(m_peer) + { + int ping; + gsi_char buffer[256]; + + if(peerGetPlayerPing(m_peer, m_selectedNick, &ping)) + _stprintf(buffer, _T("%s has a %dms ping"), m_selectedNick, ping); + else + _stprintf(buffer, _T("Failed to get a ping for %s"), m_selectedNick); + + MessageBox(buffer); + } +} + +void OnSelchangePlayers(RoomType roomType) +{ + dlg->UpdateData(); + dlg->m_selectedRoom = roomType; + int cur = m_players(roomType).GetCurSel(); + if(cur == -1) + return; + m_players(roomType).GetText(cur, dlg->m_selectedNick); + if(_tcscmp(dlg->m_selectedNick.Left(6), _T("HOST: ")) == 0) + dlg->m_selectedNick = dlg->m_selectedNick.Mid(6); + dlg->m_player = dlg->m_selectedNick; + dlg->UpdateData(FALSE); +} + +void CPeerTestDlg::OnSelchangeTitlePlayers() +{ + if(m_peer) + { + OnSelchangePlayers(TitleRoom); + } +} + +void CPeerTestDlg::OnSelchangeGroupPlayers() +{ + if(m_peer) + { + OnSelchangePlayers(GroupRoom); + } +} + +void CPeerTestDlg::OnSelchangeStagingPlayers() +{ + if(m_peer) + { + OnSelchangePlayers(StagingRoom); + } +} + +void ListingGamesCallback +( + PEER peer, + PEERBool success, + const gsi_char * name, + SBServer server, + PEERBool staging, + int msg, + int progress, + void * param +) +{ + int nIndex; + + if(!success) + { + dlg->MessageBox(_T("ListingGames failed")); + return; + } + + dlg->m_progress.SetPos(progress); + + if(msg == PEER_CLEAR) + { + ClearRoomsList(dlg->m_rooms); + return; + } + + // If updating or removing, find then remove it. + //////////////////////////////////////////////// + if((msg == PEER_UPDATE) || (msg == PEER_REMOVE)) + { + int count = dlg->m_rooms.GetCount(); + for(nIndex = 0 ; nIndex < count ; nIndex++) + { + if((SBServer)dlg->m_rooms.GetItemDataPtr(nIndex) == server) + { + dlg->m_rooms.DeleteString(nIndex); + break; + } + } + ASSERT(nIndex < count); + } + + if((msg == PEER_ADD) || (msg == PEER_UPDATE)) + { + CString str; + if(staging) + str = _T("Staging: "); + else + str = _T("Playing: "); + str += name; + + // Add it. + ////////// + nIndex = dlg->m_rooms.AddString(str); + if(nIndex >= 0) + dlg->m_rooms.SetItemDataPtr(nIndex, server); + } + + gsi_char buffer[32]; + _stprintf(buffer, _T("Rooms: %d"), dlg->m_rooms.GetCount()); + dlg->m_roomsBox.SetWindowText(buffer); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnButton29() +{ + if(m_peer) + { + UpdateData(); + + m_roomsBox.SetWindowText(_T("Rooms:")); + ClearRoomsList(m_rooms); + m_progress.SetPos(0); + + const unsigned char keys[] = + { + NUMPLAYERS_KEY, + MAXPLAYERS_KEY, + HOSTPORT_KEY, + MAPNAME_KEY, + PASSWORD_KEY + }; + peerStartListingGames(m_peer, keys, sizeof(keys), m_filter, ListingGamesCallback, NULL); + } +} + +void CPeerTestDlg::OnButton30() +{ + if(m_peer) + { + peerStopListingGames(m_peer); + } +} + +void CPeerTestDlg::OnButton24() +{ + if(m_peer) + { + UpdateData(); + + PEERBool pingRooms[NumRooms]; + PEERBool crossPingRooms[NumRooms]; + pingRooms[TitleRoom] = PEERTrue; + pingRooms[GroupRoom] = PEERTrue; + pingRooms[StagingRoom] = PEERTrue; + crossPingRooms[TitleRoom] = PEERFalse; + crossPingRooms[GroupRoom] = PEERFalse; + crossPingRooms[StagingRoom] = PEERTrue; + + PEERBool result = peerSetTitle(m_peer, + m_title, + m_secretKey, + m_title, + m_secretKey, + 0, + 30, + PEERTrue, + pingRooms, + crossPingRooms); + + if(!result) + MessageBox(_T("Failed to set the title")); + } +} + +void CPeerTestDlg::OnButton31() +{ + if(m_peer) + { + peerStopGame(m_peer); + } +} + +void CPeerTestDlg::OnButton32() +{ + if(m_peer) + { + peerStartReporting(m_peer); + } +} + +void CPeerTestDlg::OnButton33() +{ + if(m_peer) + { + peerStateChanged(m_peer); + } +} + +void CPeerTestDlg::OnButton34() +{ + if(m_peer) + { + UpdateData(); + peerSetPassword(m_peer, StagingRoom, m_password); + } +} + +void CPeerTestDlg::OnButton35() +{ + if(m_peer) + { + UpdateData(); + peerSetRoomName(m_peer, StagingRoom, m_name); + } +} + +BOOL CPeerTestDlg::PreTranslateMessage(MSG* pMsg) +{ + // Check for enter. + /////////////////// + if(m_peer) + { + if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == 0x0d)) + { + CWnd * focus; + focus = GetFocus(); + if(focus->m_hWnd == GetDlgItem(IDC_MESSAGE)->m_hWnd) + { + UpdateData(); + if(m_message) + { + int i; + for(i = 0 ; i < NumRooms ; i++) + if(peerInRoom(m_peer, (RoomType)i)) + peerMessageRoom(m_peer, (RoomType)i, m_message, NormalMessage); + + m_message = _T(""); + UpdateData(FALSE); + } + + return TRUE; + } + } + } + + return CDialog::PreTranslateMessage(pMsg); +} + +static void ChangeNickCallback +( + PEER peer, + PEERBool success, + const gsi_char * oldNick, + const gsi_char * newNick, + void * param +) +{ + gsi_char buffer[128]; + + if(success) + _stprintf(buffer, _T("Nick changed from %s to %s\n"), oldNick, newNick); + else + _stprintf(buffer, _T("Failed to change nick from %s to %s\n"), oldNick, newNick); + + dlg->MessageBox(buffer); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnChangeNick() +{ + if(m_peer) + { + UpdateData(); + if(m_nick) + { + peerChangeNick(m_peer, m_nick, ChangeNickCallback, NULL, (PEERBool)m_blocking); + } + } +} + +void CPeerTestDlg::OnQuiet() +{ + if(m_peer) + { + UpdateData(); + peerSetQuietMode(m_peer, (PEERBool)m_quiet); + } +} + +void CPeerTestDlg::OnButton37() +{ + const gsi_char * key; + const gsi_char * value; + if(m_peer) + { + UpdateData(); + if(m_key.IsEmpty()) + return; + + key = m_key; + value = m_value; + + if(m_keyType == 0) + peerSetGlobalKeys(m_peer, 1, &key, &value); + else + peerSetRoomKeys(m_peer, (RoomType)m_keyRoom, m_player, 1, &key, &value); + } +} + +static void GetGlobalKeysCallback +( + PEER peer, + PEERBool success, + const gsi_char * nick, + int num, + const gsi_char ** keys, + const gsi_char ** values, + void * param +) +{ + int i; + if(success && nick) + { + OutputDebugString(nick); + OutputDebugString(_T("[Global]: ")); + for(i = 0 ; i < num ; i++) + { + OutputDebugString(_T("\\")); + OutputDebugString(keys[i]); + OutputDebugString(_T("\\")); + OutputDebugString(values[i]); + } + OutputDebugString(_T("\n")); + } + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +static void GetRoomKeysCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + const gsi_char * nick, + int num, + gsi_char ** keys, + gsi_char ** values, + void * param +) +{ + int i; + if(success) + { + if(nick) + OutputDebugString(nick); + if(roomType == TitleRoom) + OutputDebugString(_T("[Title]: ")); + else if(roomType == GroupRoom) + OutputDebugString(_T("[Group]: ")); + else + OutputDebugString(_T("[Staging]: ")); + for(i = 0 ; i < num ; i++) + { + OutputDebugString(_T("\\")); + OutputDebugString(keys[i]); + OutputDebugString(_T("\\")); + if(values) + OutputDebugString(values[i]); + } + OutputDebugString(_T("\n")); + } + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnButton38() +{ + const gsi_char * key; + if(m_peer) + { + UpdateData(); + + key = m_key; + + if(m_keyType == 0) + { + if(m_key.IsEmpty()) + return; + + if(m_player.IsEmpty()) + peerGetRoomGlobalKeys(m_peer, (RoomType)m_keyRoom, 1, &key, GetGlobalKeysCallback, NULL, (PEERBool)m_blocking); + else + peerGetPlayerGlobalKeys(m_peer, m_player, 1, &key, GetGlobalKeysCallback, NULL, (PEERBool)m_blocking); + } + else + { + peerGetRoomKeys(m_peer, (RoomType)m_keyRoom, m_player, key[0]?1:0, &key, GetRoomKeysCallback, NULL, (PEERBool)m_blocking); + } + } +} + +void OnSetfocusRoom(RoomType roomType) +{ + dlg->UpdateData(); + dlg->m_keyRoom = roomType; + dlg->UpdateData(FALSE); +} + +void CPeerTestDlg::OnSetfocusTitlePlayers() +{ + if(m_peer) + { + OnSetfocusRoom(TitleRoom); + } +} + +void CPeerTestDlg::OnSetfocusGroupPlayers() +{ + if(m_peer) + { + OnSetfocusRoom(GroupRoom); + } +} + +void CPeerTestDlg::OnSetfocusStagingPlayers() +{ + if(m_peer) + { + OnSetfocusRoom(StagingRoom); + } +} + +void CPeerTestDlg::OnAway() +{ + if(m_peer) + { + UpdateData(); + + if(m_away) + peerSetAwayMode(m_peer, m_awayReason); + else + peerSetAwayMode(m_peer, NULL); + } +} + +void CPeerTestDlg::OnButton39() +{ + if(m_peer) + { + UpdateData(); + chatSendRaw(peerGetChat(m_peer), m_raw); + } +} + +void CPeerTestDlg::OnButton40() +{ + if(m_peer) + { + peerStayInRoom(m_peer, TitleRoom); + MessageBox(_T("Will stay in the title room when the title is cleared/changed")); + } +} + +void CPeerTestDlg::OnFixNick() +{ + gsi_char newNick[128]; + + UpdateData(); + + chatFixNick(newNick, m_nick); + + m_nick = newNick; + + UpdateData(FALSE); +} + +void CPeerTestDlg::OnButton11() +{ + m_pingPlayers.ResetContent(); +} + +void CPeerTestDlg::OnButton42() +{ + if(m_peer) + { + peerStartPlaying(m_peer); + } +} + +void CPeerTestDlg::OnButton43() +{ + if(m_peer) + { + CString message; + + if(peerIsPlaying(m_peer)) + message = _T("Yes"); + else + message = _T("No"); + + MessageBox(message); + } +} + +void ServerEnumKeysCallback(gsi_char * key, gsi_char * value, void * instance) +{ + CString * keyValues = (CString *)instance; + *keyValues += key; + *keyValues += _T(" = "); + *keyValues += value; + *keyValues += '\n'; +} + +void CPeerTestDlg::OnButton44() +{ + if(m_peer) + { + UpdateData(); + SBServer server = GetCurrentServer(); + if(server) + { + CString keyValues; + CString info; + + // get the flags + int flags = SBServerGetFlags(server); + + // get the state + int state = SBServerGetState(server); + + // add the public address + info.Format(_T("public address = %s:%d\n"), SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server)); + keyValues += info; + + // add the private address + if(flags & PRIVATE_IP_FLAG) + { + info.Format(_T("private address = %s:%d\n"), SBServerGetPrivateAddress(server), SBServerGetPrivateQueryPort(server)); + keyValues += info; + } + + // add the ping + info.Format(_T("ping = %d\n"), SBServerGetPing(server)); + keyValues += info; + + // add the flags + info = _T("flags = "); + if(flags & UNSOLICITED_UDP_FLAG) + info += _T("UNSOLICITED_UDP_FLAG|"); + if(flags & PRIVATE_IP_FLAG) + info += _T("PRIVATE_IP_FLAG|"); + if(flags & CONNECT_NEGOTIATE_FLAG) + info += _T("CONNECT_NEGOTIATE_FLAG|"); + if(flags & ICMP_IP_FLAG) + info += _T("ICMP_IP_FLAG|"); + if(flags & NONSTANDARD_PORT_FLAG) + info += _T("NONSTANDARD_PORT_FLAG|"); + if(flags & NONSTANDARD_PRIVATE_PORT_FLAG) + info += _T("NONSTANDARD_PRIVATE_PORT_FLAG|"); + if(flags & HAS_KEYS_FLAG) + info += _T("HAS_KEYS_FLAG|"); + if(flags & HAS_FULL_RULES_FLAG) + info += _T("HAS_FULL_RULES_FLAG|"); + info.SetAt(info.GetLength() - 1, '\n'); + keyValues += info; + + // add the state + info = _T("state = "); + if(state & STATE_BASICKEYS) + info += _T("STATE_BASICKEYS|"); + if(state & STATE_FULLKEYS) + info += _T("STATE_FULLKEYS|"); + if(state & STATE_PENDINGBASICQUERY) + info += _T("STATE_PENDINGBASICQUERY|"); + if(state & STATE_PENDINGFULLQUERY) + info += _T("STATE_PENDINGFULLQUERY|"); + if(state & STATE_QUERYFAILED) + info += _T("STATE_QUERYFAILED|"); + info.SetAt(info.GetLength() - 1, '\n'); + keyValues += info; + + SBServerEnumKeys(server, ServerEnumKeysCallback, &keyValues); + MessageBox(keyValues); + } + } +} + +void CPeerTestDlg::OnButton45() +{ + UpdateData(); + + m_title = _T("gmtest"); + m_secretKey = _T("HA6zkS"); + + UpdateData(FALSE); +} + +void AuthenticateCDKeyCallback +( + PEER peer, + int result, + const gsi_char * message, + void * param +) +{ + CString str; + str.Format(_T("CD Key Result: %s (%d)"), message, result); + dlg->MessageBox(str); + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnButton46() +{ + if(m_peer) + { + UpdateData(); + peerAuthenticateCDKey(m_peer, m_cdKey, AuthenticateCDKeyCallback, NULL, (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnDblclkRooms() +{ + if(m_peer) + { + UpdateData(); + SBServer server = GetCurrentServer(); + if(server) + { + } + } +} + +SBServer CPeerTestDlg::GetCurrentServer() +{ + int index = m_rooms.GetCurSel(); + if(index == -1) + return NULL; + return (SBServer)m_rooms.GetItemDataPtr(index); +} + +void CPeerTestDlg::OnButton47() +{ + if(m_peer) + { + peerKickPlayer(m_peer, m_selectedRoom, m_selectedNick, _T("You've been kicked")); + } +} + +void CPeerTestDlg::OnButton48() +{ + if(m_peer) + { + UpdateData(); + SBServer server = GetCurrentServer(); + if(server) + { + peerUpdateGame(m_peer, server, PEERTrue); + } + } +} + +void AutoMatchStatusCallback +( + PEER peer, + PEERAutoMatchStatus status, + void * param +) +{ + const gsi_char * StatusNames[] = + { + _T("Failed"), + _T("Searching"), + _T("Waiting"), + _T("Staging"), + _T("Ready"), + _T("Complete") + }; + + CString str; + str.Format(_T("AM Status: %-10s\n"), StatusNames[status]); + OutputDebugString(str); + + dlg->UpdateData(); + + if(peerInRoom(peer, StagingRoom)) + dlg->FillPlayerList(StagingRoom); + else + ClearPlayersList(m_players(StagingRoom)); + + switch(status) + { + case PEERFailed: + dlg->MessageBox(_T("The AutoMatch attempt has failed")); + dlg->m_autoMatchStatus = _T(""); + break; + + case PEERSearching: + case PEERWaiting: + case PEERStaging: + case PEERReady: + case PEERComplete: + dlg->m_autoMatchStatus = StatusNames[status]; + break; + } + + dlg->UpdateData(FALSE); + + GSI_UNUSED(param); +} + +int AutoMatchRateCallback +( + PEER peer, + SBServer match, + void * param +) +{ + dlg->UpdateData(); + + // we only want exact maxplayers matches + if(SBServerGetIntValue(match, _T("maxplayers"), 0) != dlg->m_maxPlayers) + return 0; + + // this match is acceptable + return 1; + + GSI_UNUSED(param); + GSI_UNUSED(peer); +} + +void CPeerTestDlg::OnStartAutoMatch() +{ + if(m_peer) + { + UpdateData(); + if(m_maxPlayers < 2) + { + MessageBox(_T("Max Players must be at least 2")); + return; + } + + OutputDebugString(_T("AM Starting\n")); + + peerStartAutoMatch(m_peer, m_maxPlayers, _T(""), AutoMatchStatusCallback, AutoMatchRateCallback, NULL, (PEERBool)m_blocking); + } +} + +void CPeerTestDlg::OnStopAutoMatch() +{ + if(m_peer) + { + peerStopAutoMatch(m_peer); + + OutputDebugString(_T("AM Stopped\n")); + + UpdateData(); + m_autoMatchStatus = _T(""); + UpdateData(FALSE); + } +} diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTestDlg.h b/xrGameSpy/gamespy/Peer/PeerTest/PeerTestDlg.h new file mode 100644 index 00000000000..a460bf5f9be --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTestDlg.h @@ -0,0 +1,163 @@ +// PeerTestDlg.h : header file +// + +#if !defined(AFX_PEERTESTDLG_H__3043C7C9_6FE5_433F_83A6_8186F9E145A8__INCLUDED_) +#define AFX_PEERTESTDLG_H__3043C7C9_6FE5_433F_83A6_8186F9E145A8__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CPeerTestDlg dialog + +class CPeerTestDlg : public CDialog +{ +// Construction +public: + CPeerTestDlg(CWnd* pParent = NULL); // standard constructor + + void FillPlayerList(RoomType roomType); + SBServer GetCurrentServer(); + + PEER m_peer; + int m_count; + CString m_selectedNick; + RoomType m_selectedRoom; + +// Dialog Data + //{{AFX_DATA(CPeerTestDlg) + enum { IDD = IDD_PEERTEST_DIALOG }; + CListBox m_pingPlayers; + CProgressCtrl m_progress; + CListBox m_playersT; + CListBox m_playersG; + CListBox m_playersS; + CButton m_playersBoxT; + CButton m_playersBoxG; + CButton m_playersBoxS; + CListBox m_chatList; + CListBox m_rooms; + CButton m_roomsBox; + CButton m_readyCtl; + BOOL m_blocking; + CString m_nick; + CString m_title; + BOOL m_ready; + CString m_message; + CString m_password; + CString m_name; + BOOL m_quiet; + CString m_key; + CString m_player; + int m_keyType; + int m_keyRoom; + CString m_value; + BOOL m_away; + CString m_awayReason; + CString m_raw; + CString m_filter; + CString m_secretKey; + CString m_cdKey; + CString m_autoMatchStatus; + int m_maxPlayers; + CString m_email; + CString m_loginPassword; + CString m_namespace; + CString m_authToken; + CString m_partnerChallenge; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPeerTestDlg) + public: + virtual BOOL DestroyWindow(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CPeerTestDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnButton1(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnButton2(); + afx_msg void OnButton3(); + afx_msg void OnButton4(); + afx_msg void OnButton5(); + afx_msg void OnButton8(); + afx_msg void OnButton9(); + afx_msg void OnButton10(); + afx_msg void OnButton12(); + afx_msg void OnButton14(); + afx_msg void OnCheck1(); + afx_msg void OnButton15(); + afx_msg void OnButton13(); + afx_msg void OnButton20(); + afx_msg void OnButton25(); + afx_msg void OnButton17(); + afx_msg void OnButton22(); + afx_msg void OnButton18(); + afx_msg void OnButton23(); + afx_msg void OnButton26(); + afx_msg void OnButton27(); + afx_msg void OnButton28(); + afx_msg void OnButton16(); + afx_msg void OnButton29(); + afx_msg void OnButton30(); + afx_msg void OnSelchangeTitlePlayers(); + afx_msg void OnSelchangeGroupPlayers(); + afx_msg void OnSelchangeStagingPlayers(); + afx_msg void OnButton6(); + afx_msg void OnButton7(); + afx_msg void OnButton21(); + afx_msg void OnButton24(); + afx_msg void OnButton31(); + afx_msg void OnButton32(); + afx_msg void OnButton33(); + afx_msg void OnButton34(); + afx_msg void OnButton35(); + afx_msg void OnChangeNick(); + afx_msg void OnQuiet(); + afx_msg void OnButton37(); + afx_msg void OnButton38(); + afx_msg void OnSetfocusTitlePlayers(); + afx_msg void OnSetfocusGroupPlayers(); + afx_msg void OnSetfocusStagingPlayers(); + afx_msg void OnAway(); + afx_msg void OnButton39(); + afx_msg void OnButton40(); + afx_msg void OnFixNick(); + afx_msg void OnButton11(); + afx_msg void OnButton42(); + afx_msg void OnButton43(); + afx_msg void OnButton44(); + afx_msg void OnButton45(); + afx_msg void OnButton46(); + afx_msg void OnDblclkRooms(); + afx_msg void OnButton47(); + afx_msg void OnButton48(); + afx_msg void OnStartAutoMatch(); + afx_msg void OnStopAutoMatch(); + afx_msg void OnButton36(); + afx_msg void OnButton49(); + afx_msg void OnButton50(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +extern CPeerTestDlg * dlg; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PEERTESTDLG_H__3043C7C9_6FE5_433F_83A6_8186F9E145A8__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTest_vs2005.vcproj b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest_vs2005.vcproj new file mode 100644 index 00000000000..1a44bc833de --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest_vs2005.vcproj @@ -0,0 +1,1005 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Peer/PeerTest/PeerTest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/PeerTest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Peer/PeerTest/ReadMe.txt b/xrGameSpy/gamespy/Peer/PeerTest/ReadMe.txt new file mode 100644 index 00000000000..aecd223ed5c --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/ReadMe.txt @@ -0,0 +1,88 @@ +======================================================================== + MICROSOFT FOUNDATION CLASS LIBRARY : PeerTest +======================================================================== + + +AppWizard has created this PeerTest application for you. This application +not only demonstrates the basics of using the Microsoft Foundation classes +but is also a starting point for writing your application. + +This file contains a summary of what you will find in each of the files that +make up your PeerTest application. + +PeerTest.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +PeerTest.h + This is the main header file for the application. It includes other + project specific headers (including Resource.h) and declares the + CPeerTestApp application class. + +PeerTest.cpp + This is the main application source file that contains the application + class CPeerTestApp. + +PeerTest.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +PeerTest.clw + This file contains information used by ClassWizard to edit existing + classes or add new classes. ClassWizard also uses this file to store + information needed to create and edit message maps and dialog data + maps and to create prototype member functions. + +res\PeerTest.ico + This is an icon file, which is used as the application's icon. This + icon is included by the main resource file PeerTest.rc. + +res\PeerTest.rc2 + This file contains resources that are not edited by Microsoft + Visual C++. You should place all resources not editable by + the resource editor in this file. + + + + +///////////////////////////////////////////////////////////////////////////// + +AppWizard creates one dialog class: + +PeerTestDlg.h, PeerTestDlg.cpp - the dialog + These files contain your CPeerTestDlg class. This class defines + the behavior of your application's main dialog. The dialog's + template is in PeerTest.rc, which can be edited in Microsoft + Visual C++. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named PeerTest.pch and a precompiled types file named StdAfx.obj. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +If your application uses MFC in a shared DLL, and your application is +in a language other than the operating system's current language, you +will need to copy the corresponding localized resources MFC42XXX.DLL +from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, +and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. +For example, MFC42DEU.DLL contains resources translated to German.) If you +don't do this, some of the UI elements of your application will remain in the +language of the operating system. + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Peer/PeerTest/StdAfx.cpp b/xrGameSpy/gamespy/Peer/PeerTest/StdAfx.cpp new file mode 100644 index 00000000000..bc76de009ed --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// PeerTest.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/Peer/PeerTest/StdAfx.h b/xrGameSpy/gamespy/Peer/PeerTest/StdAfx.h new file mode 100644 index 00000000000..d9a5b2ed922 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/StdAfx.h @@ -0,0 +1,31 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__9A024154_8456_4946_B347_66A283043236__INCLUDED_) +#define AFX_STDAFX_H__9A024154_8456_4946_B347_66A283043236__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC socket extensions + +#include "../peer.h" +#include "../../common/gsAvailable.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__9A024154_8456_4946_B347_66A283043236__INCLUDED_) diff --git a/xrGameSpy/gamespy/Peer/PeerTest/res/PeerTest.ico b/xrGameSpy/gamespy/Peer/PeerTest/res/PeerTest.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/PeerTest/res/PeerTest.ico differ diff --git a/xrGameSpy/gamespy/Peer/PeerTest/res/PeerTest.rc2 b/xrGameSpy/gamespy/Peer/PeerTest/res/PeerTest.rc2 new file mode 100644 index 00000000000..29656722f4f --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/res/PeerTest.rc2 @@ -0,0 +1,13 @@ +// +// PEERTEST.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Peer/PeerTest/resource.h b/xrGameSpy/gamespy/Peer/PeerTest/resource.h new file mode 100644 index 00000000000..a96665a908b --- /dev/null +++ b/xrGameSpy/gamespy/Peer/PeerTest/resource.h @@ -0,0 +1,131 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by PeerTest.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_PEERTEST_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON1 1000 +#define IDC_BUTTON2 1001 +#define IDC_BUTTON3 1002 +#define IDC_BUTTON4 1003 +#define IDC_BUTTON5 1004 +#define IDC_BUTTON6 1005 +#define IDC_BUTTON7 1006 +#define IDC_BUTTON8 1007 +#define IDC_BLOCKING 1008 +#define IDC_BUTTON21 1009 +#define IDC_BUTTON9 1010 +#define IDC_BUTTON10 1011 +#define IDC_QUIET 1012 +#define IDC_RADIO2 1013 +#define IDC_BUTTON36 1013 +#define IDC_RADIO3 1014 +#define IDC_BUTTON49 1014 +#define IDC_RADIO4 1015 +#define IDC_BUTTON50 1015 +#define IDC_OTHER 1016 +#define IDC_BUTTON11 1017 +#define IDC_LIST 1018 +#define IDC_TOTAL 1019 +#define IDC_NICK 1020 +#define IDC_CHANNEL 1021 +#define IDC_EMAIL 1021 +#define IDC_BUTTON12 1022 +#define IDC_BUTTON14 1023 +#define IDC_CHECK1 1024 +#define IDC_BUTTON15 1025 +#define IDC_ROOMS 1026 +#define IDC_BUTTON13 1027 +#define IDC_MESSAGE 1028 +#define IDC_PLAYERS_BOX 1029 +#define IDC_ROOMS_BOX 1030 +#define IDC_BUTTON16 1031 +#define IDC_CHAT_LIST 1032 +#define IDC_TITLE_PLAYERS 1033 +#define IDC_PLAYERS_BOX2 1034 +#define IDC_PING_HISTORY 1035 +#define IDC_EDIT1 1036 +#define IDC_EDIT2 1037 +#define IDC_LOGIN_PASSWORD 1037 +#define IDC_EDIT3 1038 +#define IDC_NAMESPACE 1038 +#define IDC_EDIT4 1039 +#define IDC_AUTH_TOKEN 1039 +#define IDC_EDIT5 1040 +#define IDC_PARTNER_CHALLENGE 1040 +#define IDC_EDIT6 1041 +#define IDC_EDIT7 1042 +#define IDC_BUTTON37 1043 +#define IDC_RAW 1044 +#define IDC_BUTTON17 1045 +#define IDC_BUTTON18 1046 +#define IDC_PLAYERS_BOX3 1047 +#define IDC_BUTTON20 1048 +#define IDC_TITLE 1049 +#define IDC_BUTTON22 1050 +#define IDC_BUTTON23 1051 +#define IDC_BUTTON32 1052 +#define IDC_BUTTON25 1053 +#define IDC_BUTTON26 1054 +#define IDC_BUTTON27 1055 +#define IDC_BUTTON28 1056 +#define IDC_BUTTON29 1057 +#define IDC_BUTTON30 1058 +#define IDC_PROGRESS 1059 +#define IDC_BUTTON33 1060 +#define IDC_BUTTON34 1061 +#define IDC_BUTTON35 1062 +#define IDC_BUTTON38 1063 +#define IDC_KEY_TYPE 1064 +#define IDC_RADIO5 1065 +#define IDC_BUTTON39 1066 +#define IDC_PLAYER 1067 +#define IDC_KEY_ROOM 1068 +#define IDC_RADIO7 1069 +#define IDC_RADIO8 1070 +#define IDC_AWAY 1072 +#define IDC_AWAY_REASON 1073 +#define IDC_FILTER 1074 +#define IDC_FIX_NICK 1075 +#define IDC_SECRET_KEY 1076 +#define IDC_BUTTON42 1077 +#define IDC_BUTTON43 1078 +#define IDC_SERVER2 1079 +#define IDC_BUTTON45 1080 +#define IDC_CDKEY 1081 +#define IDC_BUTTON46 1082 +#define IDC_BUTTON47 1083 +#define IDC_BUTTON48 1084 +#define IDC_MAX_PLAYERS 1088 +#define IDC_AUTO_MATCH_STATUS 1089 +#define IDC_LOCAL_INFO 1100 +#define IDC_BUTTON40 1101 +#define IDC_START_AUTO_MATCH 1102 +#define IDC_STAGING_PLAYERS 1103 +#define IDC_GROUP_PLAYERS 1104 +#define IDC_BUTTON24 1105 +#define IDC_BUTTON31 1107 +#define IDC_PASSWORD 1108 +#define IDC_NAME 1109 +#define IDC_CHANGE_NICK 1111 +#define IDC_INFO_KEY 1112 +#define IDC_STOP_AUTO_MATCH 1112 +#define IDC_KEY 1113 +#define IDC_VALUE 1114 +#define IDC_SERVER 1115 +#define IDC_BUTTON44 1116 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 134 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1090 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/Peer/Peer_vs2005.sln b/xrGameSpy/gamespy/Peer/Peer_vs2005.sln new file mode 100644 index 00000000000..4eddc59d005 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/Peer_vs2005.sln @@ -0,0 +1,81 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F3E8E322-A3FE-46C1-85E0-AD7A65C01086}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(SolutionItems) = preProject + changelog.txt = changelog.txt + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peerc_vs2005", "peerc\peerc_vs2005.vcproj", "{67830B22-E992-45F4-B1A0-768E7D1F17CC}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PeerLobby_vs2005", "PeerLobby\PeerLobby_vs2005.vcproj", "{A42D144D-87D8-4E0A-B91E-1E34D2622119}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PeerTest_vs2005", "PeerTest\PeerTest_vs2005.vcproj", "{4B95C508-48A3-43A1-9901-00D7AADDC025}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = PeerTest\\PeerTest_vs2005.vcproj + SccProjectName1 = PeerTest + SccLocalPath1 = PeerTest + SccProjectUniqueName2 = PeerLobby\\PeerLobby_vs2005.vcproj + SccProjectName2 = PeerLobby + SccLocalPath2 = PeerLobby + SccProjectUniqueName3 = peerc\\peerc_vs2005.vcproj + SccProjectName3 = peerc + SccLocalPath3 = peerc + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Debug|Win32.ActiveCfg = Debug|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Debug|Win32.Build.0 = Debug|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Release|Win32.ActiveCfg = Release|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Release|Win32.Build.0 = Release|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {67830B22-E992-45F4-B1A0-768E7D1F17CC}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Debug|Win32.ActiveCfg = Debug|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Debug|Win32.Build.0 = Debug|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Release|Win32.ActiveCfg = Release|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Release|Win32.Build.0 = Release|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {A42D144D-87D8-4E0A-B91E-1E34D2622119}.Unicode Release|Win32.Build.0 = Release|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Debug|Win32.ActiveCfg = Debug|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Debug|Win32.Build.0 = Debug|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Release|Win32.ActiveCfg = Release|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Release|Win32.Build.0 = Release|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {4B95C508-48A3-43A1-9901-00D7AADDC025}.Unicode Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Peer/Peer_vs2005.vssscc b/xrGameSpy/gamespy/Peer/Peer_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/Peer_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Peer/changelog.txt b/xrGameSpy/gamespy/Peer/changelog.txt new file mode 100644 index 00000000000..34fce00d210 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/changelog.txt @@ -0,0 +1,255 @@ +Changelog for: GameSpy Peer SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.07.00 RMV RELEASE Released to Developer Site +12-11-2007 2.06.03 SAH OTHER Added NatNeg to projects to remove compiler errors +11-27-2007 2.06.01 SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +08-06-2007 2.06.00 RMV RELEASE Released to Developer Site +07-10-2007 2.05.02 RMV FIX Fixed peerc Project files to get rid of Unicode warnings and fixed other compiler warnings +02-16-2006 2.05.01 SAH FIX Fixed bug where room name for UNICODE version was not being set +12-15-2006 2.05.00 MJW RELEASE Released to Developer Site +12-07-2006 2.04.66 SAH FIX Fixed bug where pending IMCP queries were not removed from gameEngine in piSBGamesListCallback +10-10-2006 2.04.65 SN FIX Stop automatch now automatically has the player leave the room. +10-05-2006 2.04.65 SAH FIX Updated MacOSX Makefile +09-28-2006 2.04.64 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-02-2006 2.04.63 SAH RELEASE Releasing to developer site +07-31-2006 2.04.63 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 2.04.62 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-06-2006 2.04.61 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +07-06-2006 2.04.60 SAH FIX Fixed Linux makefile to work with pthreads (for http asynch DNS lookup) + SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) +06-05-2006 2.04.59 SN FIX Modified the start listing groups to use correct function for stopping the listing of groups +06-02-2006 2.04.58 SAH FIX Added GS_STATIC_CALLBACK on comparator functions for __fastcall support +05-31-2006 2.04.57 SAH RELEASE Releasing to developer site +05-30-2006 2.04.56 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) +05-25-2006 2.04.55 SAH FIX Added GSI_UNUSED calls to get rid of PSP warnings + SAH FIX Changed PSP project warning levels +05-23-2006 2.04.54 SAH FIX added GSI_UNUSED calls to get rid of PS3 warnings +05-19-2006 2.04.53 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-15-2006 2.04.52 SAH FIX Added "PS3 Release" configuration to project +04-25-2006 2.04.51 SAH RELEASE Releasing to developer site +04-24-2006 2.04.51 SAH FIX Fixed some compile errors with UNICODE build, mainly typecasts +04-24-2006 2.04.50 SAH FIX Fixed Nitro project files to work on build machine +04-20-2006 2.04.49 SAH FIX Commented out unused variables, Moved GSI_UNUSED above return calls + SAH FIX Removed uncessary check (if unsigned int > 0) + SAH FIX Removed uncessary break; statements +04-18-2006 2.04.48 SAH FIX Added || defined(_PS3) to peerc.c for PS3 support +04-14-2006 2.04.47 SAH FIX Got rid of GsCore in the project files, added compile errors +04-10-2006 2.04.46 SAH FEATURE Multiple sorts will retain previous sorting arrangement when values are equal +02-10-2006 2.02.45 SN FIX peerParseQueryW was redundant since qr2_parse_query simply needs an char stream + As encountered by a developer. +02-07-2006 2.02.44 SN FIX peerSetStagingRoomMaxPlayers sets the channel limit in addition to the state change +01-27-2006 2.02.43 SN RELEASE Releasing to developer site +01-26-2006 2.02.43 SN OTHER Added psp prodg project and solution to sgv +12-22-2005 2.02.42 SN OTHER Cleaned up vc6 projects and added latest common code if missing +12-16-2005 2.02.41 SN OTHER Added a solution for the SDK to vault and fixed bindings on vcproj files +12-13-2005 2.02.40 SN FIX Cleaned up .vcproj files to have latest common code + Fixed a compiler issue that would not get caught on VC6 +11-17-2005 2.02.39 DES FEATURE Added ability to send client messages to servers. + DES FIX Updated Nitro Makefile. + DES FIX Made peerc printf Unicode compatible. +11-14-2005 2.02.38 DES FIX Updated the OSX Makefile. + DES FEATURE Added GSI_DOMAIN_NAME support. +10-13-2005 2.02.37 BED FEATURE peerSB now supports QR2 query challenge. + BED FIX Function pointers now cast to int to prevent strict ANSI warnings +09-21-2005 2.02.36 DES FEATURE Updated DS support +08-16-2005 2.02.35 SN FIX Added support for NatNeg in automatch. +07-28-2005 2.02.34 SN RELEASE Releasing to developer site. +07-28-2005 2.02.34 SN FIX Fixed code causing warning in peerc test app +06-03-2004 2.02.33 SN RELEASE Releasing to developer site. +06-03-2005 2.02.33 SN FIX Fixed issue where people behind same firewall as host could join full staging rooms. +05-13-2005 2.02.32 SN FIX Fixed issue where group room internal data was being incompletely cleared, causing crashes. +05-05-2005 2.02.31 BED FIX Update header files for new common code. +05-05-2005 2.02.30 SN OTHER Created Visual Studio .NET project +04-28-2005 2.02.30 SN RELEASE Releasing to developer site. +04-27-2005 2.02.30 DES RELEASE Limited release to Nintendo DS developers. +04-27-2005 2.02.30 DES FEATURE Updates to make peerc more friendly. + DES FIX On Nitro only, Ping the chat server ever 20 seconds to stay connected. +04-27-2005 2.02.29 SN FEATURE Made changes to allow developers to override default chat ping time. +04-25-2005 2.02.28 DES CLEANUP Disable Win32 linker warning. +04-04-2005 2.02.27 SN RELEASE Releasing to developer site. +04-01-2005 2.02.27 SN FIX Fixed and handled case where getting automatch channel modes failed +03-14-2005 2.02.26 DES FEATURE Nintendo DS support +01-27-2005 2.02.25 DES FIX Fixed custom SN sendto and moved it to nonport +11-06-2004 2.02.24 SN FIX Fixed hashing algorithm to minimize collisions +11-04-2004 2.02.23 SN FIX Fixed calls to SB Interal calls +10-15-2004 2.02.22 SN FEATURE Added SDK side nickname checking +09-27-2004 2.02.21 SN RELEASE Releasing with Qr2 fix to developer site +09-17-2004 2.02.21 JED FIX Added robustness to piConnectFillInUserCallback & PEER_CONNECTION_OP, Arcade reported some null pointer crashes +09-16-2004 2.02.20 SN RELEASE Releasing to developer site. +08-27-2004 2.02.20 DES CLEANUP Fixed warnings under OSX + DES CLEANUP Removed peerc.dsp's dependency on peer.dsp + DES CLEANUP General Unicode cleanup + DES CLEANUP Removed MacOS style includes + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Removed headers already included in nonport.h + DES CLEANUP Updated OSX Makefile +08-26-2004 2.02.19 SN FEATURE Added peerUpdateServerByMaster function to update a server through the master server +08-26-2004 2.02.18 DES CLEANUP Removed MacOS stlye includes +08-16-2004 2.02.18 BED FIX Fixed case where players would become stuck in automatch searching phase +08-05-2004 2.02.17 SN RELEASE Releasing to developer site. +08-05-2004 2.02.17 SN FIX Added a parameter missing in a prototype (BAD, compiler could not catch it!!!). +07-19-2004 2.02.17 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +06-21-2004 2.02.16 BED FIX Fixed bug with peerc sample's handling of NickErrorCallback +06-18-2004 2.02.15 BED RELEASE Releasing to developer site. +06-17-2004 2.02.15 BED FIX Fixed bug where piListingGamesCall was prematurely showing 100% progress. + BED FEATURE Added PS2 Insock support +05-21-2004 2.02.14 DDW FEATURE Minor change to accomodate Peer/VEngine compatibility +03-04-2004 2.02.13 BED FIX Fixed bug in Unicode wrapper when retrieving keys for user "*" +12-03-2003 2.02.12 BED FIX Fixed bug where duplicate key change callbacks were called for broadcast keys in staging rooms +12-02-2003 2.02.11 BED FIX Fixed parameter mismatch when using cached player info. +11-10-2003 2.02.10 DES RELEASE Releasing to developer site. +11-07-2003 2.02.10 BED FIX Updated CodeWarrior project files. +11-07-2003 2.02.09 DES FIX Updated linux and PS2 makefiles. + FIX Fixed a case mismatch for a chat include. + FIX Took some debug code out of peerc.c. + FIX Wrapped some internal unicode functions in GSI_UNICODE ifdefs. + FIX Commented out functions in peerc.c that were no longer being used. +11-04-2003 2.02.08 DES FEATURE Added availability check code. +10-29-2003 2.02.07 DES FEATURE Added code to PeerTest for doing the available check. + DES FIX Removed SN compiler options from PeerTest's project. +10-21-2003 2.02.06 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) + BED FIX Removed misc compiler warnings on strict settings. +10-21-2003 2.02.05 DES FEATURE Updated PeerTest to handle new connect methods. +10-16-2003 2.02.04 BED FIX Changed from UCS2ToUTF8String to UCS2ToAsciiString when dealing with nicknames. + FEATURE Added peerSetStagingRoomMaxPlayers. Developer request to allow host to update this. + DES FIX peerPingPlayer no longer returns PEERFalse if there is an outstanding ping for the player. + FIX Correctly handle peerConnectLogin with a 0 namespaceID. +10-09-2003 2.02.03 BED FIX Switched to gsi_time type instead of unsinged long for PS2 compatibility +10-08-2003 2.02.02 DES FEATURE Added peerPingPlayer for doing one-time pings in non-ping rooms. +10-01-2003 2.02.01 DES FEATURE Added a reason code for failed connect attempts. + FEATURE Added suggested nicks for a CHAT_INVALID_UNIQUENICK nick errors. +09-30-2003 2.02.00 DES FEATURE Uniquenick support. +09-08-2003 2.01.27 BED FEATURE Added UTF-8 wrapper for UNICODE support. +08-29-2003 2.01.26 DES RELEASE Released to Stainless Steel for Empires: DotMW. + FIX Compatible AM's that start at the same time will now get matched. + FIX No longer queries an AM server if a query is already pending. +08-18-2003 2.01.25 DES FEATURE Added a callback for getting your public reporting address. +07-24-2003 2.01.24 DES RELEASE Releasing to developer site. +07-24-2003 2.01.24 DES CLEANUP Removed unused roomType parameter from piPingPlayerLeftRoom. +07-23-2003 2.01.23 BED FEATURE Added Linux sample Makefile. +07-18-2003 2.01.22 BED FEATURE Added CodeWarrior (PS2) sample project file. + CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 2.01.21 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 2.01.20 DES FIX Changed a __mips64 check to a _PS2 check. + BED FEATURE Added ProDG sample project files. +07-10-2003 2.01.19 DES FIX Fixed unused value warning in pinger. +06-26-2003 2.01.18 DES FEATURE Added peerGetRoomHost to get the SBServer for the staging room host. +06-26-2003 2.01.17 DES RELEASE Releasing to developer site. + FEATURE peerJoinStagingRoomByChannel added for joining a staging room based on channel name. + FIX Fixed peerShutdown to disconnect before clearing the title. + FIX PeerTest now uses PEER_FLAG_HOST instead of PEER_FLAG_OP to determine the room host. + FIX Fixed PeerTest to refresh a room's players when a player's host flag changes. +06-24-2003 2.01.16 DES FIX Fixed peerStopAutoMatch comment to say it will not leave a staging room. +06-11-2003 2.01.15 DES RELEASE Releasing to developer site. +06-04-2003 2.01.15 DDW FIX Fixed binding to private IP when both private and public are present +05-11-2003 2.01.14 DDW CLEANUP Compatibility with SB internal API changes +05-09-2003 2.01.13 DES CLEANUP Removed Dreamcast support. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +05-07-2003 2.01.12 DES RELEASE Releasing to developer site. + FIX Updated PS2 Makefile for AutoMatch. +05-07-2003 2.01.12 JED CLEANUP Replaced refrences in comments to the dyslexic peerGameStart() with the proper peerStartGame() +05-03-2003 2.01.11 DES FIX Was unable to join an AutoMatch room if the host was behind a firewall. +04-25-2003 2.01.10 DES FIX Flipped peerGetPlayerInfo IP and profileID paramters to match the NoWait version. + FIX peerParseQuery wasn't handling queries correctly during an AutoMatch attempt. + CLEANUP peerStartAutoMatch[WithSocket] now returns void. If it fails to start the + attempt, it calls the statusCallback with PEERFailed. + FIX peerStartAutoMatch[WithSocket] wasn't doing blocking correctly. +04-24-2003 2.01.09 DES FEATURE Added peerGetPlayerInfo to replace peerGetPlayerProfileID and peerGetPlayerIP. + Both old functions are now deprecated and will be removed in a future version. +04-23-2003 2.01.08 DES FEATURE peerGameStartedCallback is now passed the host's SBServer instead of IP. + FEATURE peerGetLocalIP has been replaced by peerGetPublicIP and peerGetPrivateIP. + FIX AutoMatch now correctly checks if a listed match is the local player or not. +04-03-2003 2.01.07 DES FIX If maxPlayers was set to 0 in peerCreateStagingRoom[WithSocket], + the qrServerKey callback was not being called for MAXPLAYERS_KEY. +03-27-2003 2.01.06 DES FIX piGetPrivateIP now returns the IP instead of true/false. +03-26-2003 2.01.05 DES FEATURE Added peerSetGroupID and peerGetGroupID, which allows for getting a list + of games in a group room and reporting a game as being in a group, + without having to actually be in that group room. + CLEANUP Removed piListingGamesGroupID method of setting group ID. + OTHER Updated to pass the new extra parameter to SBServerListConnectAndQuery(). +03-24-2003 2.01.04 DES FIX piStartHosting and piStartReportingWithSocket will now correctly return + PEERFalse if piStartReporting fails. + FIX Updated the PS2 Makefile to compile files recently added to Peer. + OTHER Changed interal IP code to use the common code's IsPrivateIP. +03-21-2003 2.01.03 DES FEATURE Added the ability to join a passworded title room. + FEATURE Added a global (piListingGamesGroupID) to control what group ID to use + when listing games. Use -1 for games that aren't in a group. + OTHER Doesn't initialize pinger if there are no ping rooms. + OTHER During initial server listing, don't query server that already have keys. +03-19-2003 2.01.02 DES FEATURE Added a player flag PEER_FLAG_HOST to identify a staging room host. + FIX Switched to a new set of crypt characters for encoding IPs, the old set + had both 'F' and 'f', which could cause conflicting staging room names. + FIX No longer need to pass a list of fields to peerStartAutoMatch[WithSocket](). + FIX General AutoMatch fixes. +03-13-2003 2.01.01 DES OTHER Shortened the length of the new staging room names. + OTHER If peerIsPlayerHost() is called for the local player, return Peer's hosting flag. + CLEANUP Changed code that used internal members of in_addr (not always fully supported). +03-12-2003 2.01.00 DES FEATURE Full AutoMatch support. + FEATURE Added peerAlwaysGetPlayerInfo(), which is used to tell Peer to always + get players' IPs and Profile IDs whether rooms are ping rooms or not. + FEATURE Added the ability to host multiple staging rooms behind the same public IP. + The staging room name is now based on public IP, private IP, and private queryport. + FEATURE Peer now sets limits on staging rooms to allow no more than the maxPlayers. + This behavior can be turned off by defining PI_NO_STAGING_ROOM_LIMIT. + If maxPlayers is 0, no limit is set, and maxPlayers is not reported. + FEATURE If 0 keys are requested on a room or a player, all of the keys will be returned. + FEATURE Added piSBQueryVersion global flag to set the type of server queries to send. + FIX If a server is removed, clear any pending add/update calls for the same server. + CLEANUP Changed _strdup() calls to goastrdup(). + CLEANUP Added some explicit casts to remove compiler warnings. + CLEANUP Removed peerJoinStagingRoomByIP(). + CLEANUP Peer no longer stores passwords, it only stores whether or not one has been set. + CLEANUP Improved the process of cancelling a join that is already in progress. +02-10-2003 2.00.19 DES CLEANUP Better seperation between hosting (hosting a staging room) + and reporting (reporting a staging room or running game). + FEATURE First steps for AutoMatch support. +02-28-2003 2.00.18 DES RELEASE Releasing to developer site with updated QR2. +02-05-2003 2.00.18 DES RELEASE Releasing to developer site. +02-05-2003 2.00.18 DES CLEANUP Switched to use CanReceiveOnSocket instead of select. +02-04-2003 2.00.17 DES RELEASE Releasing to developer site. +01-23-2003 2.00.17 DES FIX Replaced several calls to free with gsifree. +01-08-2003 2.00.16 DES FIX Fixed passing the incorrect param value to the peerListGroupRooms callback. +12-19-2002 2.00.15 DES RELEASE Releasing to developer site. +12-19-2002 2.00.15 DES CLEANUP Removed assert.h includes. +12-16-2002 2.00.14 DES CLEANUP Removed call to GOAClearSocketError in pinger. +12-13-2002 2.00.13 DES FEATURE Added PS2 eenet stack support. +12-06-2002 2.00.12 DES RELEASE Releasing to developer site with updated QR2. +12-05-2002 2.00.12 DES CLEANUP Removed an extraneous assert. + CLEANUP Changes to remove warnings. +12-03-2002 2.00.11 DES RELEASE Releasing to developer site. +12-03-2002 2.00.11 DES FIX Fixed PeerTest to correctly show server state flags. + FEATURE Added Update button to PeerTest, uses peerUpdateGame to get a server's full keys. +11-25-2002 2.00.10 DES FIX Fixed PeerTest to handle e_qrnochallengeerror. +11-22-2002 2.00.09 DES RELEASE Releasing to developer site. +11-20-2002 2.00.09 DES CLEANUP Cleaned up to remove compiler warings on the PS2. +11-20-2002 2.00.08 DES FIX Fixed bug which caused blocking functions to lockup if disconnected while blocking. +11-14-2002 2.00.07 DES FEATURE Added peerKickPlayer function to SDK and to PeerTest +11-07-2002 2.00.06 DES RELEASE Limited release on developer site and to EAPAC for Generals + Incorporates serverbrowsing change to fix invalid SBServer in listing games callback. +11-07-2002 2.00.06 DES FIX Fixed negative hash due to high-ascii characters in hashed string. +10-28-2002 2.00.05 DES RELEASE Limited release on developer site and to EAPAC for Generals +10-28-2002 2.00.05 DES FIX Correctly passing request fields to SB when starting listing. + Changed peerStartListingGames API to pass in keys by id instead of name. + Changed tests/samples to use new API. + SB callbacks debugging code now also shows the server address or group id. +10-22-2002 2.00.04 DES RELEASE Limited release on developer site and to EAPAC for Generals +10-22-2002 2.00.04 DES FIX Updated SB querying to use QR2 style instead of old GOA style + Update PeerTest to always check for no currently selected server +10-22-2002 2.00.03 DDW FIX Clears query engine when stopping listing of games + Correctly removes servers from query engine when deleted message arrives +10-17-2002 2.00.02 DES RELEASE Limited release on developer site and to EAPAC for Generals + Incorporates fix to Chat SDK +10-10-2002 2.00.02 DES RELEASE Limited release on developer site and to EAPAC for Generals +10-10-2002 2.00.02 DES FIX SBQueryEngineSetPublicIP is now called when the serverlist + determines the public IP (slc_publicipdetermined). +09-26-2002 2.00.01 DES RELEASE Limited release on developer site +09-25-2002 2.00.01 DDW OTHER Changelog started +09-23-2002 2.00.01 DES RELEASE Release to EAPAC for Generals +09-23-2002 2.00.01 DES FEATURE Added peerUpdateGame function +09-06-2002 2.00.00 DDW RELEASE Release to EAPAC for Generals +09-06-2002 2.00.00 DES FEATURE Replaces CEngine/QR with ServerBrowsing/QR2 +06-25-2002 1.20.00 DES RELEASE Release on deveoper site \ No newline at end of file diff --git a/xrGameSpy/gamespy/Peer/peer.h b/xrGameSpy/gamespy/Peer/peer.h new file mode 100644 index 00000000000..1b0978ac94b --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peer.h @@ -0,0 +1,1866 @@ + /* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEER_H_ +#define _PEER_H_ + +/************* +** INCLUDES ** +*************/ +#include "../common/gsCommon.h" +#include "../Chat/chat.h" +#include "../qr2/qr2.h" +#include "../serverbrowsing/sb_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************ +** DEFINES ** +************/ +// Defines for the msg param that's passed into peerListingGamesCallback(). +// PANTS-04.20.00-changed from PI_* to PEER_* +// PANTS-09.26.02-added PEER_COMPLETE +/////////////////////////////////////////////////////////////////////////// +#define PEER_ADD 0 // a server is being added +#define PEER_UPDATE 1 // a server has been updated +#define PEER_REMOVE 2 // a server has been removed +#define PEER_CLEAR 3 // all the servers have been cleared +#define PEER_COMPLETE 4 // the initial listing of servers is complete + +// Nick errors, for peerNickErrorCallback. +////////////////////////////////////////// +#define PEER_NICK_OK 0 +#define PEER_IN_USE 1 // the nick is already being used +#define PEER_INVALID 2 // the nick contains invalid characters +#define PEER_UNIQUENICK_EXPIRED 3 // the uniquenick for this account has expired +#define PEER_NO_UNIQUENICK 4 // there is no uniquenick for this account +#define PEER_INVALID_UNIQUENICK 5 // the uniquenick to associate with the account is invalid or in use +#define PEER_NICK_TOO_LONG 6 // the nick was too long + +// Possible values for the failureReason passed to the peerConnectCallback. +/////////////////////////////////////////////////////////////////////////// +#define PEER_DISCONNECTED 0 // disconnected from, or unable to connect to, the server +#define PEER_NICK_ERROR 1 // a nick error was either ignored or not handled +#define PEER_LOGIN_FAILED 2 // the login info passed to peerConnectLogin was not valid + +// Maximum length of a room password, including the terminating NUL. +//////////////////////////////////////////////////////////////////// +#define PEER_PASSWORD_LEN 24 + +// Each player can have various flags set for each room they are in. +//////////////////////////////////////////////////////////////////// +#define PEER_FLAG_STAGING 0x01 // s +#define PEER_FLAG_READY 0x02 // r +#define PEER_FLAG_PLAYING 0x04 // g +#define PEER_FLAG_AWAY 0x08 // a +#define PEER_FLAG_HOST 0x10 // h +#define PEER_FLAG_OP 0x20 +#define PEER_FLAG_VOICE 0x40 + +// Bitfield reporting options for peerStartGame. +//////////////////////////////////////////////// +#define PEER_KEEP_REPORTING 0 // Continue reporting. +#define PEER_STOP_REPORTING 1 // Stop reporting. Cannot be used with other options. +#define PEER_REPORT_INFO 2 // Continue reporting server keys (as if it were not playing). +#define PEER_REPORT_PLAYERS 4 // Continue reporting player keys (as if it were not playing). + +/********** +** TYPES ** +**********/ +// The peer object. +/////////////////// +typedef void * PEER; + +// Boolean. +/////////// +typedef enum +{ + PEERFalse, + PEERTrue +} PEERBool; + +// Types of rooms. +////////////////// +typedef enum +{ + TitleRoom, // The main room for a game. + GroupRoom, // A room which is, in general, for a particular type of gameplay (team, dm, etc.). + StagingRoom, // A room where players meet before starting a game. + NumRooms +} RoomType; + +// Types of messages. These have the same +// values as their CHAT SDK counterparts. +// PANTS-01.08.01 +///////////////////////////////////////// +typedef enum +{ + NormalMessage, + ActionMessage, + NoticeMessage +} MessageType; + +// Possible results when attempting to join a room. +// Passed into peerJoinRoomCallback(). +/////////////////////////////////////////////////// +typedef enum +{ + PEERJoinSuccess, // The room was joined. + + PEERFullRoom, // The room is full. + PEERInviteOnlyRoom, // The room is invite only. + PEERBannedFromRoom, // The local user is banned from the room. + PEERBadPassword, // An incorrect password (or none) was given for a passworded room. + + PEERAlreadyInRoom, // The local user is already in or entering a room of the same type. + PEERNoTitleSet, // Can't join a room if no title is set. + PEERNoConnection, // Can't join a room if there's no chat connection. + PEERAutoMatching, // The user can't join a staging room during an auto match attempt. + + PEERJoinFailed // Generic failure. +} PEERJoinResult; + +// Possible status values passed to the peerAutoMatchStatusCallback. +// If PEERFailed, the match failed, otherwise this is the current status +// of the automatch attempt. +//////////////////////////////////////////////////////////////////////// +typedef enum +{ + PEERFailed, // The automatch attempt failed. + + PEERSearching, // Searching for a match (active). + PEERWaiting, // Waiting for a match (passive). + PEERStaging, // In a staging room with at least one other player, possibly waiting for more. + PEERReady, // All players are in the staging room, the game is ready to be launched. + PEERComplete // The game is launching, the automatch attempt is now complete. + // The player is still in the staging room. +} PEERAutoMatchStatus; + +/************** +** CALLBACKS ** +**************/ +// Called when the connection to the server gets disconnected. +////////////////////////////////////////////////////////////// +typedef void (* peerDisconnectedCallback) +( + PEER peer, // The peer object. + const gsi_char * reason, // The reason for the disconnection. + void * param // User-data. +); + +// Called when a message is sent to a room the local player is in. +////////////////////////////////////////////////////////////////// +typedef void (* peerRoomMessageCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the message was in. + const gsi_char * nick, // The nick of the player who sent the message. + const gsi_char * message, // The text of the message. + MessageType messageType, // The type of message. + void * param // User-data. +); + +// Called when a UTM is sent to a room the local player is in. +////////////////////////////////////////////////////////////// +typedef void (* peerRoomUTMCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the UTM was in. + const gsi_char * nick, // The nick of the player who sent the UTM. + const gsi_char * command, // The UTM command for this message. + const gsi_char * parameters, // Any parameters for this UTM. + PEERBool authenticated, // True if this has been authenticated by the server. + void * param // User-data. +); + +// Called when the name of a room the player is in changes. +// The new name can be checked with peerGetRoomName. +// PANTS|09.11.00 +/////////////////////////////////////////////////////////// +typedef void (* peerRoomNameChangedCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the name changed in. + void * param // User-data +); + +// Called when a room's mode changes. +// PANTS|04.17.00 +/////////////////////////////////////////////////////////// +typedef void (* peerRoomModeChangedCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the name changed in. + CHATChannelMode * mode, // The current mode for this room. + void * param // User-data +); + +// Called when a private message is received from another player. +///////////////////////////////////////////////////////////////// +typedef void (* peerPlayerMessageCallback) +( + PEER peer, // The peer object. + const gsi_char * nick, // The nick of the player who sent the message. + const gsi_char * message, // The text of the message. + MessageType messageType, // The type of message. + void * param // User-data +); + +// Called when a private UTM is received from another player. +///////////////////////////////////////////////////////////// +typedef void (* peerPlayerUTMCallback) +( + PEER peer, // The peer object. + const gsi_char * nick, // The nick of the player who sent the UTM. + const gsi_char * command, // The UTM command for this message. + const gsi_char * parameters, // Any parameters for this UTM. + PEERBool authenticated, // True if this has been authenticated by the server. + void * param // User-data +); + +// Called when a player's ready state changes, +// from a call to peerSetReady(). +////////////////////////////////////////////// +typedef void (* peerReadyChangedCallback) +( + PEER peer, // The peer object. + const gsi_char * nick, // The nick of the player who's ready state changed. + PEERBool ready, // The player's new ready state. + void * param // User-data. +); + +// Called when the host of a staging room launches the game, +// with a call to peerStartGame(). +// The public and private IPs and ports of the server can +// be obtained from the server object. +//////////////////////////////////////////////////////////// +typedef void (* peerGameStartedCallback) +( + PEER peer, // The peer object. + SBServer server, // A server object representing this host. + const gsi_char * message, // A message that was passed into peerStartGame(). + void * param // User-data. +); + +// A player joined a room. +////////////////////////// +typedef void (* peerPlayerJoinedCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the player joined. + const gsi_char * nick, // The nick of the player that joined. + void * param // User-data. +); + +// A player left a room. +//////////////////////// +typedef void (* peerPlayerLeftCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the player left. + const gsi_char * nick, // The nick of the player that left. + const gsi_char * reason, // The reason the player left. + void * param // User-data. +); + +// The local player was kicked from a room. +/////////////////////////////////////////// +typedef void (* peerKickedCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room that the player was kicked from. + const gsi_char * nick, // The nick of the player that did the kicking. + const gsi_char * reason, // An optional reason for the kick. + void * param // User-data. +); + +// The entire player list for this room has been updated. +///////////////////////////////////////////////////////// +typedef void (* peerNewPlayerListCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of room. + void * param // User-data +); + +// A player in one of the rooms changed his nick. +///////////////////////////////////////////////// +typedef void (* peerPlayerChangedNickCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The type of the room the nick changed was in. + const gsi_char * oldNick, // The player's old nick. + const gsi_char * newNick, // The player's new nick. + void * param // User-data. +); + +// The IP and ProfileID for this player has just been received. +// PANTS|01.08.01 +// This gets called for all players (who are using peer) in a room +// shortly after joining. It will be called with nick==NULL after +// getting info for all the players. +////////////////////////////////////////////////////////////////// +typedef void (* peerPlayerInfoCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The room the info was gotten in. + const gsi_char * nick, // The nick of the player the info is for. + unsigned int IP, // The player's IP. + int profileID, // The player's profile ID. + void * param // User-data. +); + +// This gets called when a player's flags have changed. +/////////////////////////////////////////////////////// +typedef void (* peerPlayerFlagsChangedCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The room the flags were changed in. + const gsi_char * nick, // The player whose flags have changed. + int oldFlags, // The player's old flags. + int newFlags, // The player's new flags. + void * param // User-data +); + +// An updated ping for a player, who may be in any room(s). +/////////////////////////////////////////////////////////// +typedef void (* peerPingCallback) +( + PEER peer, // The peer object. + const gsi_char * nick, // The other player's nick. + int ping, // The ping. + void * param // User-data. +); + +// An updated cross-ping between two players in the staging room. +///////////////////////////////////////////////////////////////// +typedef void (* peerCrossPingCallback) +( + PEER peer, // The peer object. + const gsi_char * nick1, // The first player's nick. + const gsi_char * nick2, // The second player's nick. + int crossPing, // The cross-ping. + void * param // User-data. +); + +// This is called for watch keys when a room is joined, for +// watch keys when another player joins, and for any newly +// set watch keys. +/////////////////////////////////////////////////////////// +typedef void (* peerGlobalKeyChangedCallback) +( + PEER peer, // The peer object. + const gsi_char * nick, // The player whose key changed. + const gsi_char * key, // The key. + const gsi_char * value, // The value. + void * param // User-data. +); + +// This is called for watch keys when a room is joined, for +// watch keys when another player joins, for any newly +// set watch keys, and when a broadcast key is changed. +/////////////////////////////////////////////////////////// +typedef void (* peerRoomKeyChangedCallback) +( + PEER peer, // The peer object. + RoomType roomType, // The room the player is in. + const gsi_char * nick, // The player whose key changed. + const gsi_char * key, // The key. + const gsi_char * value, // The value. + void * param // User-data. +); + +// Called to report QR server keys. +// Use qr2_buffer_add or qr2_buffer_add_int to +// add this key's information to the buffer. +////////////////////////////////////////////// +typedef void (* peerQRServerKeyCallback) +( + PEER peer, // The peer object. + int key, // The key for which to report information. + qr2_buffer_t buffer, // Fill in the information using this buffer. + void * param // User-data. +); + +// Called to report QR player keys. +// Use qr2_buffer_add or qr2_buffer_add_int to +// add this key's information to the buffer. +////////////////////////////////////////////// +typedef void (* peerQRPlayerKeyCallback) +( + PEER peer, // The peer object. + int key, // The key for which to report information. + int index, // The index of the player for which to report info. + qr2_buffer_t buffer, // Fill in the information using this buffer. + void * param // User-data. +); + +// Called to report QR team keys. +// Use qr2_buffer_add or qr2_buffer_add_int to +// add this key's information to the buffer. +////////////////////////////////////////////// +typedef void (* peerQRTeamKeyCallback) +( + PEER peer, // The peer object. + int key, // The key for which to report information. + int index, // The index of the team for which to report info. + qr2_buffer_t buffer, // Fill in the information using this buffer. + void * param // User-data. +); + +// Called to get a list of keys to be reported. +// Use qr2_keybuffer_add() to add keys. +// The following keys do not need to be added, as peer already adds them: +// GAMENAME_KEY, HOSTNAME_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY, +// GAMEMODE_KEY, PASSWORD_KEY, GROUPID_KEY, PLAYER__KEY, PING__KEY. +///////////////////////////////////////////////////////////////////////// +typedef void (* peerQRKeyListCallback) +( + PEER peer, // The peer object. + qr2_key_type type, // The type of keys being asked for (key_server, key_player, or key_team). + qr2_keybuffer_t keyBuffer, // Fill in the keys using this buffer. + void * param // User-data. +); + +// Called to get a count of the number of players or teams. +/////////////////////////////////////////////////////////// +typedef int (* peerQRCountCallback) +( + PEER peer, // The peer object. + qr2_key_type type, // The type of count to return (key_player or key_team). + void * param // User-data. +); + +// Called when there is an error reporting the server. +////////////////////////////////////////////////////// +typedef void (* peerQRAddErrorCallback) +( + PEER peer, // The peer object. + qr2_error_t error, // The type of error. + gsi_char * errorString, // A text string containing the error. + void * param // User-data. +); + +// Called when hosting a server and a nat-negotiate cookie is received. +/////////////////////////////////////////////////////////////////////// +typedef void (* peerQRNatNegotiateCallback) +( + PEER peer, // The peer object. + int cookie, // A cookie sent from a potential client. + void * param // User-data. +); + +// Called when hosting a server with the server's public reporting address. +/////////////////////////////////////////////////////////////////////////// +typedef void (* peerQRPublicAddressCallback) +( + PEER peer, // The peer object. + unsigned int ip, // The public reporting IP + unsigned short port, // The public reporting port + void * param // User-data. +); + +// This struct gets passed into peerInitialize(). +// param will be passed as the last parameter to each of the callbacks. +/////////////////////////////////////////////////////////////////////// +typedef struct PEERCallbacks +{ + peerDisconnectedCallback disconnected; + peerRoomMessageCallback roomMessage; + peerRoomUTMCallback roomUTM; + peerRoomNameChangedCallback roomNameChanged; // PANTS|09.11.00 + peerRoomModeChangedCallback roomModeChanged; // PANTS|04.17.01 + peerPlayerMessageCallback playerMessage; + peerPlayerUTMCallback playerUTM; + peerReadyChangedCallback readyChanged; + peerGameStartedCallback gameStarted; + peerPlayerJoinedCallback playerJoined; + peerPlayerLeftCallback playerLeft; + peerKickedCallback kicked; + peerNewPlayerListCallback newPlayerList; + peerPlayerChangedNickCallback playerChangedNick; + peerPlayerInfoCallback playerInfo; // PANTS|01.08.01 + peerPlayerFlagsChangedCallback playerFlagsChanged; // PANTS|03.12.01 + peerPingCallback ping; + peerCrossPingCallback crossPing; + peerGlobalKeyChangedCallback globalKeyChanged; + peerRoomKeyChangedCallback roomKeyChanged; + peerQRServerKeyCallback qrServerKey; + peerQRPlayerKeyCallback qrPlayerKey; + peerQRTeamKeyCallback qrTeamKey; + peerQRKeyListCallback qrKeyList; + peerQRCountCallback qrCount; + peerQRAddErrorCallback qrAddError; + peerQRNatNegotiateCallback qrNatNegotiateCallback; + peerQRPublicAddressCallback qrPublicAddressCallback; + void * param; +} PEERCallbacks; + +/************ +** UNICODE ** +************/ +#ifndef GSI_UNICODE +#define peerConnect peerConnectA +#define peerConnectLogin peerConnectLoginA +#define peerConnectPreAuth peerConnectPreAuthA +#define peerRetryWithNick peerRetryWithNickA +#define peerRegisterUniqueNick peerRegisterUniqueNickA +#define peerSetTitle peerSetTitleA +#define peerGetTitle peerGetTitleA +#define peerGetNick peerGetNickA +#define peerFixNick peerFixNickA +#define peerTranslateNick peerTranslateNickA +#define peerChangeNick peerChangeNickA +#define peerSetAwayMode peerSetAwayModeA +#define peerParseQuery peerParseQueryA +#define peerAuthenticateCDKey peerAuthenticateCDKeyA +#define peerJoinTitleRoom peerJoinTitleRoomA +#define peerJoinStagingRoom peerJoinStagingRoomA +#define peerJoinStagingRoomByChannel peerJoinStagingRoomByChannelA +#define peerCreateStagingRoom peerCreateStagingRoomA +#define peerCreateStagingRoomWithSocket peerCreateStagingRoomWithSocketA +#define peerLeaveRoom peerLeaveRoomA +#define peerListGroupRooms peerListGroupRoomsA +#define peerStartListingGames peerStartListingGamesA +#define peerMessageRoom peerMessageRoomA +#define peerUTMRoom peerUTMRoomA +#define peerSetPassword peerSetPasswordA +#define peerSetRoomName peerSetRoomNameA +#define peerGetRoomName peerGetRoomNameA +#define peerGetRoomChannel peerGetRoomChannelA +#define peerSetTitleRoomChannel peerSetTitleRoomChannelA +#define peerMessagePlayer peerMessagePlayerA +#define peerUTMPlayer peerUTMPlayerA +#define peerKickPlayer peerKickPlayerA +#define peerGetPlayerPing peerGetPlayerPingA +#define peerGetPlayersCrossPing peerGetPlayersCrossPingA +#define peerPingPlayer peerPingPlayerA +#define peerGetPlayerInfoNoWait peerGetPlayerInfoNoWaitA +#define peerGetPlayerInfo peerGetPlayerInfoA +#define peerGetPlayerProfileID peerGetPlayerProfileIDA +#define peerGetPlayerIP peerGetPlayerIPA +#define peerIsPlayerHost peerIsPlayerHostA +#define peerGetPlayerFlags peerGetPlayerFlagsA +#define peerGetReady peerGetReadyA +#define peerStartGame peerStartGameA +#define peerSetGlobalKeys peerSetGlobalKeysA +#define peerGetPlayerGlobalKeys peerGetPlayerGlobalKeysA +#define peerGetRoomGlobalKeys peerGetRoomGlobalKeysA +#define peerSetRoomKeys peerSetRoomKeysA +#define peerGetRoomKeys peerGetRoomKeysA +#define peerSetGlobalWatchKeys peerSetGlobalWatchKeysA +#define peerSetRoomWatchKeys peerSetRoomWatchKeysA +#define peerGetGlobalWatchKey peerGetGlobalWatchKeyA +#define peerGetRoomWatchKey peerGetRoomWatchKeyA +#define peerStartAutoMatch peerStartAutoMatchA +#define peerStartAutoMatchWithSocket peerStartAutoMatchWithSocketA +#else +#define peerConnect peerConnectW +#define peerConnectLogin peerConnectLoginW +#define peerConnectPreAuth peerConnectPreAuthW +#define peerRetryWithNick peerRetryWithNickW +#define peerRegisterUniqueNick peerRegisterUniqueNickW +#define peerSetTitle peerSetTitleW +#define peerGetTitle peerGetTitleW +#define peerGetNick peerGetNickW +#define peerFixNick peerFixNickW +#define peerTranslateNick peerTranslateNickW +#define peerChangeNick peerChangeNickW +#define peerSetAwayMode peerSetAwayModeW +#define peerParseQuery peerParseQueryA +#define peerAuthenticateCDKey peerAuthenticateCDKeyW +#define peerJoinTitleRoom peerJoinTitleRoomW +#define peerJoinStagingRoom peerJoinStagingRoomW +#define peerJoinStagingRoomByChannel peerJoinStagingRoomByChannelW +#define peerCreateStagingRoom peerCreateStagingRoomW +#define peerCreateStagingRoomWithSocket peerCreateStagingRoomWithSocketW +#define peerLeaveRoom peerLeaveRoomW +#define peerListGroupRooms peerListGroupRoomsW +#define peerStartListingGames peerStartListingGamesW +#define peerMessageRoom peerMessageRoomW +#define peerUTMRoom peerUTMRoomW +#define peerSetPassword peerSetPasswordW +#define peerSetRoomName peerSetRoomNameW +#define peerGetRoomName peerGetRoomNameW +#define peerGetRoomChannel peerGetRoomChannelW +#define peerSetTitleRoomChannel peerSetTitleRoomChannelW +#define peerMessagePlayer peerMessagePlayerW +#define peerUTMPlayer peerUTMPlayerW +#define peerKickPlayer peerKickPlayerW +#define peerGetPlayerPing peerGetPlayerPingW +#define peerGetPlayersCrossPing peerGetPlayersCrossPingW +#define peerPingPlayer peerPingPlayerW +#define peerGetPlayerInfoNoWait peerGetPlayerInfoNoWaitW +#define peerGetPlayerInfo peerGetPlayerInfoW +#define peerGetPlayerProfileID peerGetPlayerProfileIDW +#define peerGetPlayerIP peerGetPlayerIPW +#define peerIsPlayerHost peerIsPlayerHostW +#define peerGetPlayerFlags peerGetPlayerFlagsW +#define peerGetReady peerGetReadyW +#define peerStartGame peerStartGameW +#define peerSetGlobalKeys peerSetGlobalKeysW +#define peerGetPlayerGlobalKeys peerGetPlayerGlobalKeysW +#define peerGetRoomGlobalKeys peerGetRoomGlobalKeysW +#define peerSetRoomKeys peerSetRoomKeysW +#define peerGetRoomKeys peerGetRoomKeysW +#define peerSetGlobalWatchKeys peerSetGlobalWatchKeysW +#define peerSetRoomWatchKeys peerSetRoomWatchKeysW +#define peerGetGlobalWatchKey peerGetGlobalWatchKeyW +#define peerGetRoomWatchKey peerGetRoomWatchKeyW +#define peerStartAutoMatch peerStartAutoMatchW +#define peerStartAutoMatchWithSocket peerStartAutoMatchWithSocketW +#endif + +/************ +** GENERAL ** +************/ +// This creates and intializes a peer object. +// NULL is returned in case of an error, otherwise a peer +// object is returned. +// If a peer object is returned, peerShutdown() must be called +// to cleanup the object +/////////////////////////////////////////////////////////////// +PEER peerInitialize +( + PEERCallbacks * callbacks // Global callbacks. +); + +// This gets called when the connection attempt finishes. +///////////////////////////////////////////////////////// +typedef void (* peerConnectCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + int failureReason, // If failure, the reason for it (PEER_DISCONNECTED, etc.) + void * param // User-data. +); + +// This gets called if there is an error with +// the nickname while connecting. +// Call peerRetryWithNick() to try another nick. If it +// is called with a NULL nick, then the connect will be +// stopped, and peerConnectCallback will be called with +// failure. +// The suggested nicks are only provided if type +// is PEER_INVALID_UNIQUENICK. +///////////////////////////////////////////////////////// +typedef void (* peerNickErrorCallback) +( + PEER peer, // The peer object. + int type, // The type of nick error (PEER_IN_USE, PEER_INVALID, etc.) + const gsi_char * nick, // The bad nick. + int numSuggestedNicks, // The number of suggested nicks. + const gsi_char ** suggestedNicks, // The array of nicks. + void * param // User-data. +); + +// This connects a peer object to a chat server. +// Call peerDisconnect() to close the connection. +// A title must be set with peerSetTitle before connecting. +/////////////////////////////////////////////////////////// +void peerConnect +( + PEER peer, // The peer object. + const gsi_char * nick, // The nick to connect with. + int profileID, // The profileID, or 0 if no profileID. + peerNickErrorCallback nickErrorCallback, // Called if nick error. + peerConnectCallback connectCallback, // Called on complete. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerConnect, but also authenticates using a uniquenick +// and password or an email, profilenick, and password. +///////////////////////////////////////////////////////////////// +void peerConnectLogin +( + PEER peer, // The peer object. + int namespaceID, // The namespace in which to login. + const gsi_char * email, // The email to login with. + const gsi_char * profilenick, // The profile to login with. + const gsi_char * uniquenick, // The uniquenick to login with. + const gsi_char * password, // The password for the login account. + peerNickErrorCallback nickErrorCallback, // Called if nick error. + peerConnectCallback connectCallback, // Called on complete. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerConnect, but also authenticates using an authtoken +// and partnerchallenge from a partner account system. +///////////////////////////////////////////////////////////////// +void peerConnectPreAuth +( + PEER peer, // The peer object. + const gsi_char * authtoken, // The authtoken for this login. + const gsi_char * partnerchallenge, // The partner challenge for this login. + peerNickErrorCallback nickErrorCallback, // Called if nick error. + peerConnectCallback connectCallback, // Called on complete. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// If peerNickErrorCallback is called, call this to +// try and continue the connection with a new nickname. +// If there is an error with this nick, the +// peerNickErrCallback will be called again. +/////////////////////////////////////////////////////// +void peerRetryWithNick +( + PEER peer, + const gsi_char * nick +); + +// Register a uniquenick. +// Should be called in response to the peerNickErrorCallback being called +// with a type of PEER_UNIQUENICK_EXPIRED or PEER_NO_UNIQUENICK. +// If the uniquenick cannot be registered, the peerNickErrorCallback will +// be called again with a type of PEER_IN_USE or PEER_INVALID. +///////////////////////////////////////////////////////////////////////// +void peerRegisterUniqueNick +( + PEER peer, + int namespaceID, + const gsi_char * uniquenick, + const gsi_char * cdkey +); + +// Returns true if peer is connected. +// PANTS|09.11.00 +///////////////////////////////////// +PEERBool peerIsConnected(PEER peer); + +// Sets the current title. +// A title must be set before connecting. +// Returns PEERFalse if an error, or PEERTrue if success. +// For most games the title/qrSecretKey and +// sbName/sbSecretKey pairs will be the same. +///////////////////////////////////////////////////////// +PEERBool peerSetTitle +( + PEER peer, // The peer object. + const gsi_char * title, // The title to make current (ie., ut, gmtest). + const gsi_char * qrSecretKey, // The queryreporting secret key. + const gsi_char * sbName, // The serverbrowsing name. + const gsi_char * sbSecretKey, // The serverbrowsing secret key. + int sbGameVersion, // The version of the game doing the browsing. + int sbMaxUpdates, // The maximum number of concurent updates (10-15 for modem users, 20-30 for high-bandwidth). + PEERBool natNegotiate, // PEERTrue if the title supports GameSpy's NAT-negotiation technology (or another similar technology). + PEERBool pingRooms[NumRooms], // To do pings int a room, set it to PEERTrue. + PEERBool crossPingRooms[NumRooms] // To do cross-pings in a room, set it to PEERTrue. +); + +// Resets peer to no title. +/////////////////////////// +void peerClearTitle(PEER peer); + +// Gets the currently set title. +// Returns NULL if no title is set. +/////////////////////////////////// +const gsi_char * peerGetTitle(PEER peer); + +// Disconnect peer from the chat server. +//////////////////////////////////////// +void peerDisconnect(PEER peer); + +// Shutdown peer. +// The peer object should not be used again after this call. +//////////////////////////////////////////////////////////// +void peerShutdown(PEER peer); + +// Let's peer think. +// This should be called at least every ~10ms, +// typically, within the program's main loop. +////////////////////////////////////////////// +void peerThink(PEER peer); + +// Get the chat object associated with this peer object. +// This returns NULL if peer isn't connected. +//////////////////////////////////////////////////////// +CHAT peerGetChat(PEER peer); + +// Get the local user's nickname. +///////////////////////////////// +const gsi_char * peerGetNick(PEER peer); + +// Replaces any invalid characters in nick with underscores. +//////////////////////////////////////////////////////////// +void peerFixNick +( + gsi_char * newNick, + const gsi_char * oldNick +); + +// Removes the namespace extension from a chat unique nick. +// Returns the nick if it ended with the extension. +// Otherwise returns NULL. +/////////////////////////////////////////////////////////// +const gsi_char * peerTranslateNick +( + gsi_char * nick, // The nick to translate + const gsi_char * extension // The extension to be removed. +); + +// Gets the local IP address. If called before +// the peer object is connected, will return 0. +// DEPRECATED - Use peerGetPublicIP. +/////////////////////////////////////////////// +#define peerGetLocalIP peerGetPublicIP + +// Gets the local public IP address. If called before +// the peer object is connected, will return 0. +////////////////////////////////////////////////////// +unsigned int peerGetPublicIP(PEER peer); + +// Gets the local private IP address. +///////////////////////////////////// +unsigned int peerGetPrivateIP(PEER peer); + +// Gets the local userID. +// Only valid if connected with peerConnectLogin or peerConnectPreAuth. +/////////////////////////////////////////////////////////////////////// +int peerGetUserID(PEER peer); + +// Gets the local profileID. +// Only valid if connected with peerConnectLogin or peerConnectPreAuth. +/////////////////////////////////////////////////////////////////////// +int peerGetProfileID(PEER peer); + +// This gets called when an attempt to change nicks is finished. +//////////////////////////////////////////////////////////////// +typedef void (* peerChangeNickCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + const gsi_char * oldNick, // The old nickname. + const gsi_char * newNick, // The new nickname. + void * param // User-data. +); + +// Changes the user's nickname. +/////////////////////////////// +void peerChangeNick +( + PEER peer, // The peer object. + const gsi_char * newNick, // The nickname to which to change. + peerChangeNickCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Causes Peer to not automatically leave the +// room the next time peerSetTitle or peerClearTitle +// is called. No effect if a title isn't set. When +// the next title is set, the flag is cleared. +// Only TitleRoom is currently supported. +// This function is normally not needed. +//////////////////////////////////////////////////// +void peerStayInRoom +( + PEER peer, // The peer object. + RoomType roomType // Only TitleRoom is currently supproted. +); + +// Turns quiet mode on/off. +/////////////////////////// +void peerSetQuietMode +( + PEER peer, // The peer object. + PEERBool quiet // If PEERTrue, enable quiet mode. +); + +// Sets the away mode. +// If an empty string or NULL, away mode is off. +// If a valid string, away mode is on. +//////////////////////////////////////////////// +void peerSetAwayMode +( + PEER peer, // The peer object. + const gsi_char * reason // The away reason. If NULL or "", not away. +); + +// When using peerStartReportingWithSocket or peerCreateStagingRoomWithSocket, +// any qureries received on the sockets need to be passed to the SDK. Pass +// the data using this function. +////////////////////////////////////////////////////////////////////////////// +void peerParseQuery +( + PEER peer, // The peer object. + char * query, // String of query data. + int len, // The length of the string, not including the NUL. + struct sockaddr * sender // The address the query was received from. +); + +// This gets called when an attempt to authenticate a CD key is finished. +// If the result is 1, the CD key was authenticated. Otherwise, the CD +// key was not authenticated. +///////////////////////////////////////////////////////////////////////// +typedef void (* peerAuthenticateCDKeyCallback) +( + PEER peer, // The peer object. + int result, // 1 if authenticated, otherwise not authenticated. + const gsi_char * message, // A string representing the result. + void * param // User-data. +); + +// Sends a CD Key to the chat server for authentication. +// The callback gets called when the chat server responds. +// This call is required by some games to enter chat rooms. +// It must be called after connecting to the chat server, but +// before entering a room. +///////////////////////////////////////////////////////////// +void peerAuthenticateCDKey +( + PEER peer, // The peer object. + const gsi_char * cdkey, // The CD key to authenticate. + peerAuthenticateCDKeyCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Sends a nat-negotiate cookie to a server. +//////////////////////////////////////////// +void peerSendNatNegotiateCookie +( + PEER peer, // The peer object. + unsigned int ip, // IP (network byte order) of the server to send the cookie to. + unsigned short port, // Port (host byte order) of the server to send the cookie to. + int cookie // The cookie to send. +); + +// Sends a client message to a QR2 server. +////////////////////////////////////////// +void peerSendMessageToServer +( + PEER peer, + unsigned int ip, + unsigned short port, + const char * data, + int len +); + +// If always is PEERTrue, then players' IP and profile ID will +// always be requested when joining a room. This info is normally +// only requested if pings are set in a room. Use this function +// to always request the information. +////////////////////////////////////////////////////////////////// +void peerAlwaysGetPlayerInfo +( + PEER peer, // The peer object. + PEERBool always // If true, always get player info. +); + +/********** +** ROOMS ** +**********/ +// This gets called when an attempt to join or create a room has finished. +////////////////////////////////////////////////////////////////////////// +typedef void (* peerJoinRoomCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + PEERJoinResult result, // The result of the attempt. + RoomType roomType, // The type of room joined/created. + void * param // User-data. +); + +// Joins the currently selected title's title room. +/////////////////////////////////////////////////// +void peerJoinTitleRoom +( + PEER peer, // The peer object. + const gsi_char password[PEER_PASSWORD_LEN], // An optional password, normally NULL. + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Joins a group room. +// The groupID comes from the peerListGroupRoomsCallback. +///////////////////////////////////////////////////////// +void peerJoinGroupRoom +( + PEER peer, // The peer object. + int groupID, // The ID for the group to join. + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Sets the group ID. +// Used to get a list of games in a group room and/or report or create a game +// in a particular group, without actually being in that group room. This is +// not needed if already using peerJoinGroupRoom. +// Setting a group ID of 0 is equivalent to leaving the group room. +///////////////////////////////////////////////////////////////////////////// +void peerSetGroupID +( + PEER peer, // The peer object. + int groupID // The group ID to set +); + +// Returns the current group ID. +// The group ID is set with either peerJoinGroupRoom or peerSetGroupID. +/////////////////////////////////////////////////////////////////////// +int peerGetGroupID +( + PEER peer // The peer object. +); + +// Joins a staging room. +// server is one of the server objects passed to peerListingGamesCallback(). +// This call will only work if staging==PEERTrue for the server. +// PANTS|09.11.00 - The password is only needed for passworded rooms. +// PANTS|03.15.01 - No longer requires you to be actively listing games. +//////////////////////////////////////////////////////////////////////////// +void peerJoinStagingRoom +( + PEER peer, // The peer object. + SBServer server, // The server passed into peerlistingGamesCallback(). + const gsi_char password[PEER_PASSWORD_LEN], // The password of the room being joined. Can be NULL or "". + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Joins a staging room by its channel name. +// Same as peerJoinStagingRoom, except it takes the staging room's +// channel name instead of an SBServer object. Also, when the +// peerGameStartedCallback is called, the server paramter passed to +// it will be NULL. +/////////////////////////////////////////////////////////////////// +void peerJoinStagingRoomByChannel +( + PEER peer, // The peer object. + const gsi_char * channel, // The channel to join. + const gsi_char password[PEER_PASSWORD_LEN], // The password of the room being joined. Can be NULL or "". + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Creates a new staging room, with the local player hosting. +// PANTS|09.11.00 - If the password parameter is not NULL +// or "", this will create a passworded room. The same +// case-sensitive password needs to be passed into +// peerJoinStagingRoom() for other player's to join the room. +// PANTS|09.11.00 - The staging room will be reported as part +// of whatever group room the local player was in when the +// room was created. Leaving the group room will not affect +// what group the staging room is reported as part of. +///////////////////////////////////////////////////////////// +void peerCreateStagingRoom +( + PEER peer, // The peer object. + const gsi_char * name, // The name of the room. + int maxPlayers, // The max number of players allowed in the room. + const gsi_char password[PEER_PASSWORD_LEN], // An optional password for the staging room + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerCreateStagingRoom, but uses the provided socket for +// sending heartbeats and query replies. This allows the game +// to share a socket with the peer SDK, which can make hosting +// games behind a NAT proxy possible. +////////////////////////////////////////////////////////////////// +void peerCreateStagingRoomWithSocket +( + PEER peer, // The peer object. + const gsi_char * name, // The name of the room. + int maxPlayers, // The max number of players allowed in the room. + const gsi_char password[PEER_PASSWORD_LEN], // An optional password for the staging room + SOCKET socket, // The socket to be used for reporting. + unsigned short port, // The local port to which the socket is bound. + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Leave a room. +// PANTS|09.11.00 - You can now leave a group room +// without being forcibly removed from a staging room. +////////////////////////////////////////////////////// +void peerLeaveRoom +( + PEER peer, // The peer object. + RoomType roomType, // The room you want to leave (TitleRoom, GroupRoom, or StagingRoom). + const gsi_char * reason // The reason the player is leaving (can be NULL). PANTS|03.13.01 +); + +// Gets called once for each group room when listing group rooms. +// After this has been called for each group room, it will be +// called one more time with groupID==0 and name==NULL. +///////////////////////////////////////////////////////////////// +typedef void (* peerListGroupRoomsCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + int groupID, // A unique ID for this group. + SBServer server, // The server object for this group room. + const gsi_char * name, // The group room's name. + int numWaiting, // The number of players in the room. + int maxWaiting, // The maximum number of players allowed in the room. + int numGames, // The number of games either staging or running in the group. + int numPlaying, // The total number of players in games in the group. + void * param // User-data. +); + +// List all the groups rooms for the currently set title. +// The fields parameter allows you to request extra info +// on each group room. +///////////////////////////////////////////////////////// +void peerListGroupRooms +( + PEER peer, // The peer object. + const gsi_char * fields, // A backslash delimited list of fields. + peerListGroupRoomsCallback callback, // Called for each group room. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Called with info on games being listed. +// Used to maintain a list of running games and staging rooms. +// The server object is a unique way of identifying each game. +// It can also be used with the calls in the "SBServer Object Functions" section +// of sb_serverbrowsing.h to find out more info about the server. +// If staging==PEERTrue, the game hasn't started yet, it's still in the staging room +// use peerJoinStagingRoom() to join the staging room, or if staging==peerfalse +// use the server object to get the game's IP and port to join with. +// During the _intial_ listing of games, progress is the percentage (0-100) of the +// games that have been added. Once the initial listing is completed, +// progress will always be 100. +// PANTS|09.11.00 - The "password" key will be set to 1 for games that are +// passworded. This can be checked with ServerGetIntValue(server, "password", 0). +///////////////////////////////////////////////////////////////////////////////////// +typedef void (* peerListingGamesCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + const gsi_char * name, // The name of the game being listed. + SBServer server, // The server object for this game. + PEERBool staging, // If PEERTrue, this is a staging room and not a running game. + int msg, // The type of message this is. + // PEER_CLEAR: + // Clear the list. This has the same effect as if this was called + // with PEER_REMOVE for every server listed. + // PEER_ADD: + // This is a new server. Add it to the list. + // PEER_UPDATE: + // This server is already on the list, and its been updated. + // PEER_REMOVE: + // Remove this server from the list. The server object for this server + // should not be used again after this callback returns. + int progress, // The percent of servers that have been added. + void * param // User-data. +); + +// Start listing the currently running games and staging rooms. +// This is used to maintain a list that can presented to the user, +// so they can pick a game (or staging room) to join. +// Games and staging rooms are filtered based on what group the local +// user is in. If the local user isn't in a group, then only games +// and staging rooms that aren't part of any group are listed. +// The fields determine which info to request from the server. These +// must be registered QR2 keys (see qr2regkeys.h). HOSTNAME_KEY and +// GAMEMODE_KEY are automatically requested by Peer, so do not need +// to included. +///////////////////////////////////////////////////////////////////// +void peerStartListingGames +( + PEER peer, // The peer object. + const unsigned char * fields, // An array of registered QR2 keys to request from servers. + int numFields, // The number of keys in the fields array. + const gsi_char * filter, // A SQL-like rule filter. + peerListingGamesCallback callback, // Called when finished. + void * param // Passed to the callback. +); + +// Stop games from being listed. This does NOT clear the games list. +// So all games listed are still considered valid. They stay valid +// until either another call to peerStartListingGames or until the +// title is cleared (or a new one set). +//////////////////////////////////////////////////////////////////// +void peerStopListingGames +( + PEER peer // The peer object. +); + +// Queries the game server for the latest information. +// If fullUpdate is PEERTrue, all of the keys will be requested. +// If fullUpdate is PEERFalse, only the keys passed to +// peerStartListingGames as the fields parameter will be requested. +/////////////////////////////////////////////////////////////////// +void peerUpdateGame +( + PEER peer, // The peer object. + SBServer server, // The server object for the game to update. + PEERBool fullUpdate // If true, get all of the game's keys. +); + +// 08-26-2004 Added by Saad Nader +// Queries the game server for the latest information via the master +// server. +// If fullUpdate is PEERTrue, all of the keys will be requested. +// If fullUpdate is PEERFalse, only the keys passed to +// peerStartListingGames as the fields parameter will be requested. +/////////////////////////////////////////////////////////////////// +void peerUpdateGameByMaster +( + PEER peer, // The peer object. + SBServer server, // The server object for the game to update. + PEERBool fullUpdate // If true, get all of the game's keys. +); + +// Send a ping to the server +// ICMP echo reply will be sent as response. The firewall +// or NAT between server and internet does not have to accept +// ICMP echo requests. +/////////////////////////////////////////////////////////////////// +void peerUpdateGamePing(PEER peer, SBServer server); + +// Send a message to a room. +//////////////////////////// +void peerMessageRoom +( + PEER peer, // The peer object. + RoomType roomType, // The room to send the message to. + const gsi_char * message, // The message. + MessageType messageType // The type of message. +); + +// Send a UTM to a room. +//////////////////////// +void peerUTMRoom +( + PEER peer, // The peer object. + RoomType roomType, // The room to send the UTM to. + const gsi_char * command, // The command. + const gsi_char * parameters, // The UTM's parameters. + PEERBool authenticate // If true, the server will authenticate this UTM (should normally be false). +); + +// Set a password in a room you're hosting. +// The only roomType currently supported is StagingRoom. +// This will only work if the player is hosting the room. +// If password is NULL or "", the password will be cleared. +/////////////////////////////////////////////////////////// +void peerSetPassword +( + PEER peer, // The peer object. + RoomType roomType, // The room in which to set the password. + const gsi_char password[PEER_PASSWORD_LEN] // The password to set. +); + +// Set the name of a room you're hosting. +// The only roomType currently supported is StagingRoom. +// PANTS|09.11.00 +//////////////////////////////////////////////////////// +void peerSetRoomName +( + PEER peer, // The peer object. + RoomType roomType, // The room in which to set the name. + const gsi_char * name // The new name +); + +// Get a room's name (the channel's title). +// Returns NULL if not in the room. +/////////////////////////////////////////// +const gsi_char * peerGetRoomName +( + PEER peer, // The peer object. + RoomType roomType // The room to get the name for. +); + +// Get's the chat channel associated with the room. +// Returns NULL if not in the room. +/////////////////////////////////////////////////// +const gsi_char * peerGetRoomChannel +( + PEER peer, // The peer object. + RoomType roomType // The room to get the channel for. +); + +// Returns PEERTrue if in the room. +/////////////////////////////////// +PEERBool peerInRoom +( + PEER peer, // The peer object. + RoomType roomType // The room to check for. +); + +// Use this channel for the title room for the currently set title. +// This function is normally not needed. +/////////////////////////////////////////////////////////////////// +void peerSetTitleRoomChannel +( + PEER peer, // The peer object. + const gsi_char * channel // The channel to use for the title room. +); + +// Use this to get the SBServer object for the staging room host. +// This will return NULL if the local player is not in a staging room, +// is the staging room host, or joined using peerJoinStagingRoomByChannel. +////////////////////////////////////////////////////////////////////////// +SBServer peerGetHostServer(PEER peer); + +// Update the maximum number of players for a staging room +///////////////////////////////////////////////////////// +void peerSetStagingRoomMaxPlayers +( + PEER peer, + int maxPlayers +); + +/************ +** PLAYERS ** +************/ +// Called for each player in a room being enumerated, and once +// when finished, with index==-1 and nick==NULL. +////////////////////////////////////////////////////////////// +typedef void (* peerEnumPlayersCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + RoomType roomType, // The room whose players are being enumerated. + int index, // The index of the player (0 to (N - 1)). -1 when finished. + const gsi_char * nick, // The nick of the player. + int flags, // This player's flags (see #define's above). PANTS|03.12.01 + void * param // User-data. +); + +// Enumerates through the players in a room. +//////////////////////////////////////////// +void peerEnumPlayers +( + PEER peer, // The peer object. + RoomType roomType, // The room to enum the players in. + peerEnumPlayersCallback callback, // Called when finished. + void * param // Passed to callback. +); + +// Send a message to a player. +////////////////////////////// +void peerMessagePlayer +( + PEER peer, // The peer object. + const gsi_char * nick, // The nick of the player to send the message to. + const gsi_char * message, // The message to send. + MessageType messageType // The type of message. +); + +// Send a UTM to a player. +////////////////////////// +void peerUTMPlayer +( + PEER peer, // The peer object. + const gsi_char * nick, // The nick of the player to send the UTM to. + const gsi_char * command, // The command. + const gsi_char * parameters, // The UTM's parameters. + PEERBool authenticate // If true, the server will authenticate this UTM (should normally be false). +); + +// Kick a player from a room. +// Can only be called by a player with host privileges. +/////////////////////////////////////////////////////// +void peerKickPlayer +( + PEER peer, // The peer object. + RoomType roomType, // The room to kick the player from. + const gsi_char * nick, // The nick of the player to kick. + const gsi_char * reason // An optional reason for kicking the player +); + +// Gets a player's ping (between the local machine and the player's machine). +// Returns PEERFalse if we don't have or can't get the player's ping. +///////////////////////////////////////////////////////////////////////////// +PEERBool peerGetPlayerPing +( + PEER peer, // The peer object. + const gsi_char * nick, // The player to get the ping for. + int * ping // The player's ping is stored here, if we have it. +); + +// Gets the cross-ping between 2 players. +// Returns PEERFalse if we don't have or can't get the player's cross-ping. +/////////////////////////////////////////////////////////////////////////// +PEERBool peerGetPlayersCrossPing +( + PEER peer, // The peer object. + const gsi_char * nick1, // The first player. + const gsi_char * nick2, // The second player. + int * crossPing // The cross-ping is stored here, if we have it. +); + +// Peer already automatically pings all players that are in ping rooms. +// This function does a one-time ping of a remote player in a non-ping room. +// However pings must be enabled in at least one room for this to work, +// otherwise Peer will not open the UDP ping socket. +// Also, peerAlwaysGetPlayerInfo() must be enabled so that Peer has IPs for +// players that are only in non-ping rooms. +//////////////////////////////////////////////////////////////////////////// +PEERBool peerPingPlayer +( + PEER peer, // The peer object. + const gsi_char * nick // The player to ping. +); + +// Gets a player's info immediately. +// Returns PEERFalse if the info is no available. +///////////////////////////////////////////////// +PEERBool peerGetPlayerInfoNoWait +( + PEER peer, + const gsi_char * nick, + unsigned int * IP, + int * profileID +); + +// Called as a result of a call to peerGetPlayerInfo(). +/////////////////////////////////////////////////////// +typedef void (* peerGetPlayerInfoCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + const gsi_char * nick, // The player's nick. + unsigned int IP, // The player's IP, in network byte order. + int profileID, // The player's profile ID. + void * param // User-data. +); + +// Called to get a player's IP and profile ID. +////////////////////////////////////////////// +void peerGetPlayerInfo +( + PEER peer, // The peer object. + const gsi_char * nick, // The player's nick. + peerGetPlayerInfoCallback callback, // Called when finished. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Called as a result of a call to peerGetPlayerProfileID(). +//////////////////////////////////////////////////////////// +typedef void (* peerGetPlayerProfileIDCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + const gsi_char * nick, // The player's nick. + int profileID, // The player's profile ID. + void * param // User-data. +); + +// Called to get a player's profile ID. +// DEPRECATED - Use peerGetPlayerInfo. +/////////////////////////////////////// +void peerGetPlayerProfileID +( + PEER peer, // The peer object. + const gsi_char * nick, // The player's nick. + peerGetPlayerProfileIDCallback callback, // Called when finished. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Called as a result of a call to peerGetPlayerIP(). +///////////////////////////////////////////////////// +typedef void (* peerGetPlayerIPCallback) +( + PEER peer, // The peer object. + PEERBool success, // PEERTrue if success, PEERFalse if failure. + const gsi_char * nick, // The player's nick. + unsigned int IP, // The player's IP, in network byte order. PANTS|09.11.00 - was unsigned long + void * param // User-data. +); + +// Called to get a player's IP. +// DEPRECATED - Use peerGetPlayerInfo. +////////////////////////////////////// +void peerGetPlayerIP +( + PEER peer, // The peer object. + const gsi_char * nick, // The player's nick. + peerGetPlayerIPCallback callback, // Called when finished. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Checks if a player is a host (has ops). +// Returns PEERTrue if yes, PEERFalse if no. +//////////////////////////////////////////// +PEERBool peerIsPlayerHost +( + PEER peer, // The peer object. + const gsi_char * nick, // The player's nick. + RoomType roomType // The room to check in. +); + +// Gets a player's flags in a room. Returns PEERFalse if +// the local player or this player is not in the room. +///////////////////////////////////////////////////////// +PEERBool peerGetPlayerFlags +( + PEER peer, + const gsi_char * nick, + RoomType roomType, + int * flags +); + +/********* +** GAME ** +*********/ +/**************** Disabled *************************/ +// Returns the qr2 record used to report +// Primarily used for CD Key integration to prevent +// game intrusion and and post staging hacks +//////////////////////////////////////////////////// +//qr2_t peerGetReportingRecord(PEER peer); + +// Sets the local player's ready state. +// PEERTrue if ready, PEERFalse if not ready. +///////////////////////////////////////////// +void peerSetReady +( + PEER peer, // The peer object. + PEERBool ready // Ready or not. +); + +// Gets a player's ready state. +/////////////////////////////// +PEERBool peerGetReady +( + PEER peer, // The peer object. + const gsi_char * nick, // The player's nick. + PEERBool * ready // The player's ready state gets stored in here. +); + +// Checks if all the player's in the staging room are ready. +//////////////////////////////////////////////////////////// +PEERBool peerAreAllReady +( + PEER peer // The peer object. +); + +// Called only by a staging room host to start the game. +// All the other people in the staging room will have their +// peerGameStartedCallback() called. +// The message gets passed to everyone in the peerGameStartedCallback(), and +// can be used to pass information such as a special port or password. +// If (reportingOptions & PEER_STOP_REPORTING), Peer will stop game reporting, +// so the program is responsible for any server reporting. +// If !(reportingOptions & PEER_STOP_REPORTING), Peer will continue doing +// game reporting, and calling the program-supplied callbacks. If +// (reportingOptions & PEER_REPORT_INFO), all server keys will still be +// reported. If (reportingOptions & PEER_REPORT_PLAYERS), all player keys +// will still be reported. +///////////////////////////////////////////////////////////////////////////// +void peerStartGame +( + PEER peer, // The peer object. + const gsi_char * message, // A message to send to everyone. + int reportingOptions // Bitfield flags used to set reporting options. +); + +// Starts server reporting, without creating a staging room. +// Call peerStopGame() to stop reporting. +//////////////////////////////////////////////////////////////// +PEERBool peerStartReporting +( + PEER peer // The peer object. +); + +// Same as peerStartReporting, but uses the provided socket for +// sending heartbeats and query replies. This allows the game +// to share a socket with the peer SDK, , which can make hosting +// games behind a NAT proxy possible. +//////////////////////////////////////////////////////////////// +PEERBool peerStartReportingWithSocket +( + PEER peer, // The peer object. + SOCKET socket, // The socket to be used for reporting. + unsigned short port // The local port to which the socket is bound. +); + +// Mark the local player as playing. +// Use this if the player is in a game not +// started by peer, but he should be marked as playing. +/////////////////////////////////////////////////////// +void peerStartPlaying +( + PEER peer // The peer object. +); + +// Check to see if the local player is playing. +/////////////////////////////////////////////// +PEERBool peerIsPlaying +( + PEER peer // The peer object. +); + +// Needs to be called by the host when the game has stopped. +//////////////////////////////////////////////////////////// +void peerStopGame +( + PEER peer // The peer object. +); + +// Call this when hosting a staging room or a game to force peer +// to report the game again. An example of when to call this is +// when a player joins or leaves a game. +// PANTS|09.11.00 +/////////////////////////////////////////////////////////////////// +void peerStateChanged +( + PEER peer // The peer object. +); + +/********* +** KEYS ** +*********/ +// Set global keys on the local player. +/////////////////////////////////////// +void peerSetGlobalKeys +( + PEER peer, // The peer object. + int num, // The number of keys to set. + const gsi_char ** keys, // The keys to set. + const gsi_char ** values // The values for the keys. +); + +// Called with a player's global keys. +////////////////////////////////////// +typedef void (* peerGetGlobalKeysCallback) +( + PEER peer, // The peer object. + PEERBool success, // If PEERFalse, unable to get the keys. + const gsi_char * nick, // The player the keys are for. + int num, // The number of keys. + const gsi_char ** keys, // The keys got. + const gsi_char ** values, // The values for the keys. + void * param // User-data. +); + +// Get a player's global keys. +////////////////////////////// +void peerGetPlayerGlobalKeys +( + PEER peer, // The peer object. + const gsi_char * nick, // The player to get the keys for. + int num, // The number of keys. + const gsi_char ** keys, // The keys to get. + peerGetGlobalKeysCallback callback, // Called with the keys. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Get the global keys for all players in a room we're in. +////////////////////////////////////////////////////////// +void peerGetRoomGlobalKeys +( + PEER peer, // The peer object. + RoomType roomType, // The room to get the keys in. + int num, // The number of keys. + const gsi_char ** keys, // The keys to get. + peerGetGlobalKeysCallback callback, // Called with the keys. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Set the room keys for a player. +// Use NULL or "" to set keys on the room itself. +///////////////////////////////////////////////// +void peerSetRoomKeys +( + PEER peer, // The peer object. + RoomType roomType, // The room to set the keys in. + const gsi_char * nick, // The player to set the keys on (NULL or "" for the room). + int num, // The number of keys. + const gsi_char ** keys, // The keys to set. + const gsi_char ** values // The values to set. +); + +// Called with a player's room keys. +//////////////////////////////////// +typedef void (* peerGetRoomKeysCallback) +( + PEER peer, // The peer object. + PEERBool success, // If PEERFalse, unable to get the keys. + RoomType roomType, // The room the keys are in. + const gsi_char * nick, // The player the keys are for, or NULL for the room. + int num, // The number of keys. + gsi_char ** keys, // The keys. + gsi_char ** values, // The values for the keys. + void * param // User-data. +); + +// Get the room keys for either a single player of an entire room. +// Use "*" for the player to get the keys for the entire room. +// Use NULL or "" for the player to get keys on the room itself. +////////////////////////////////////////////////////////////////// +void peerGetRoomKeys +( + PEER peer, // The peer object. + RoomType roomType, // The room to get the keys in. + const gsi_char * nick, // The player to get the keys for. + int num, // The number of keys. + const gsi_char ** keys, // The keys to get. + peerGetRoomKeysCallback callback, // Called with the keys. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Set the global watch keys for a room type. +// If addKeys is set to PEERTrue, the keys will be +// added to the current global watch keys for this room. +// If addKeys is PEERFalse, these will replace any existing +// global watch keys for this room. +// When entering a room of the given type, peer will get and +// cache these keys for all players in the room. +//////////////////////////////////////////////////////////// +void peerSetGlobalWatchKeys +( + PEER peer, // The peer object. + RoomType roomType, // The type of room to set the watch keys for. + int num, // The number of keys. + const gsi_char ** keys, // The keys to watch for. + PEERBool addKeys // If PEERTrue, add these keys to the existing global watch keys for this room. +); + +// Set the room watch keys for a room type. +// If addKeys is set to PEERTrue, the keys will be +// added to the current room watch keys for this room. +// If addKeys is PEERFalse, these will replace any existing +// room watch keys for this room. +// When entering a room of the given type, peer will get and +// cache these keys for all players in the room. +//////////////////////////////////////////////////////////// +void peerSetRoomWatchKeys +( + PEER peer, // The peer object. + RoomType roomType, // The type of room to set the watch keys for. + int num, // The number of keys. + const gsi_char ** keys, // The keys to watch for. + PEERBool addKeys // If PEERTrue, add these keys to the existing room watch keys for this room. +); + +// Get the global watch key for a particular player. +// If the key isn't cached locally (either because it isn't +// a watch key or just isn't yet known), NULL will be returned. +// If the key is empty, "" will be returned. +/////////////////////////////////////////////////////////////// +const gsi_char * peerGetGlobalWatchKey +( + PEER peer, // The peer object. + const gsi_char * nick, // The player to get the key for. + const gsi_char * key // The key to get. +); + +// Get the room watch key for a particular player in a room. +// If the key isn't cached locally (either because it isn't +// a watch key or just isn't yet known), NULL will be returned. +// If the key is empty, "" will be returned. +/////////////////////////////////////////////////////////////// +const gsi_char * peerGetRoomWatchKey +( + PEER peer, // The peer object. + RoomType roomType, // The room to get the key in. + const gsi_char * nick, // The player to get the key for. + const gsi_char * key // The key to get. +); + +/************** +** AUTOMATCH ** +**************/ + +// Called during a automatch attempt to inform the app of the status. +///////////////////////////////////////////////////////////////////// +typedef void (* peerAutoMatchStatusCallback) +( + PEER peer, // The peer object. + PEERAutoMatchStatus status, // The current status. + void * param // User-data. +); + +// This callback may be called during the automatch attempt. +// Peer uses the callback to ask the application how well a particular +// match fits what the user is looking for. The application checks the match +// and then returns a rating for it. If the rating is <=0 the match is +// considered unsuitable and Peer will not attempt that match. If the rating +// is >0 this match is considered suitable. The higher the rating, up to a +// maximum of INT_MAX, the more suitable the match. The exact scheme used +// to generate a rating is entirely up to the application. The match ratings +// are used by Peer both to check if a particular match meets the user's wishes +// and to compare matches to each other. Peer will first try to match with the +// highest rated possible match, then the second highest, etc. +/////////////////////////////////////////////////////////////////////////////// +typedef int (* peerAutoMatchRateCallback) +( + PEER peer, // The peer object. + SBServer match, // Possible match to rate. + void * param // User-data. +); + +// Used to start a automatch attempt. +// The filter contains any hard criteria. This is used to narrow down the list +// of possible matches to those the user might consider. +// The status callback will be called as the attempt progresses, and the rate +// callback will be used to sort possible matches. +///////////////////////////////////////////////////////////////////////////////// +void peerStartAutoMatch +( + PEER peer, // The peer object. + int maxPlayers, // The total number of players to match (including the local player). + const gsi_char * filter, // Hard criteria - filters out servers. + peerAutoMatchStatusCallback statusCallback, // Called as the attempt status changes. + peerAutoMatchRateCallback rateCallback, // Used to rate possible matches. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerStartAutoMatch, but uses the provided socket for +// sending heartbeats and query replies. This allows the game +// to share a socket with the peer SDK, which can make hosting +// games behind a NAT proxy possible. +//////////////////////////////////////////////////////////////// +void peerStartAutoMatchWithSocket +( + PEER peer, // The peer object. + int maxPlayers, // The total number of players to match (including the local player). + const gsi_char * filter, // Hard criteria - filters out servers. + SOCKET socket, // The socket to be used for reporting. + unsigned short port, // The local port to which the socket is bound. + peerAutoMatchStatusCallback statusCallback, // Called as the attempt status changes. + peerAutoMatchRateCallback rateCallback, // Used to rate possible matches. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Stops an automatch attempt in progress. +// The user will not automatically be removed from any staging room he is in. +///////////////////////////////////////////////////////////////////////////// +void peerStopAutoMatch(PEER peer); + +// Checks if a automatch attempt is in progress. +//////////////////////////////////////////////// +PEERBool peerIsAutoMatching(PEER peer); + +// Gets the current status of the automatch attempt. +// If no attempt is in progress, PEERFailed will be returned. +///////////////////////////////////////////////////////////// +PEERAutoMatchStatus peerGetAutoMatchStatus(PEER peer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerAscii.h b/xrGameSpy/gamespy/Peer/peerAscii.h new file mode 100644 index 00000000000..8ed2352e873 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerAscii.h @@ -0,0 +1,734 @@ + /* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERASCII_H_ +#define _PEERASCII_H_ + +// PROTOTYPES OF ASCII FUNCTIONS +// The only purpose of this file is to silence the CodeWarrior +// "function not prototyped" warnings when using GSI_UNICODE mode + +#ifdef __cplusplus +extern "C" { +#endif + + +/************ +** GENERAL ** +************/ +// This connects a peer object to a chat server. +// Call peerDisconnect() to close the connection. +// A title must be set with peerSetTitle before connecting. +/////////////////////////////////////////////////////////// +void peerConnectA +( + PEER peer, // The peer object. + const char * nick, // The nick to connect with. + int profileID, // The profileID, or 0 if no profileID. + peerNickErrorCallback nickErrorCallback, // Called if nick error. + peerConnectCallback connectCallback, // Called on complete. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerConnect, but also authenticates using a uniquenick +// and password or an email, profilenick, and password. +///////////////////////////////////////////////////////////////// +void peerConnectLoginA +( + PEER peer, // The peer object. + int namespaceID, // The namespace in which to login. + const char * email, // The email to login with. + const char * profilenick, // The profile to login with. + const char * uniquenick, // The uniquenick to login with. + const char * password, // The password for the login account. + peerNickErrorCallback nickErrorCallback, // Called if nick error. + peerConnectCallback connectCallback, // Called on complete. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerConnect, but also authenticates using an authtoken +// and partnerchallenge from a partner account system. +///////////////////////////////////////////////////////////////// +void peerConnectPreAuthA +( + PEER peer, // The peer object. + const char * authtoken, // The authtoken for this login. + const char * partnerchallenge, // The partner challenge for this login. + peerNickErrorCallback nickErrorCallback, // Called if nick error. + peerConnectCallback connectCallback, // Called on complete. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// If peerNickErrorCallback is called, call this to +// try and continue the connection with a new nickname. +// If there is an error with this nick, the +// peerNickErrCallback will be called again. +/////////////////////////////////////////////////////// +void peerRetryWithNickA +( + PEER peer, + const char * nick +); + +// Register a uniquenick. +// Should be called in response to the peerNickErrorCallback being called +// with a type of PEER_UNIQUENICK_EXPIRED or PEER_NO_UNIQUENICK. +// If the uniquenick cannot be registered, the peerNickErrorCallback will +// be called again with a type of PEER_IN_USE or PEER_INVALID. +///////////////////////////////////////////////////////////////////////// +void peerRegisterUniqueNickA +( + PEER peer, + int namespaceID, + const char * uniquenick, + const char * cdkey +); + +// Sets the current title. +// A title must be set before connecting. +// Returns PEERFalse if an error, or PEERTrue if success. +// For most games the title/qrSecretKey and +// sbName/sbSecretKey pairs will be the same. +///////////////////////////////////////////////////////// +PEERBool peerSetTitleA +( + PEER peer, // The peer object. + const char * title, // The title to make current (ie., ut, gmtest). + const char * qrSecretKey, // The queryreporting secret key. + const char * sbName, // The serverbrowsing name. + const char * sbSecretKey, // The serverbrowsing secret key. + int sbGameVersion, // The version of the game doing the browsing. + int sbMaxUpdates, // The maximum number of concurent updates (10-15 for modem users, 20-30 for high-bandwidth). + PEERBool natNegotiate, // PEERTrue if the title supports GameSpy's NAT-negotiation technology (or another similar technology). + PEERBool pingRooms[NumRooms], // To do pings int a room, set it to PEERTrue. + PEERBool crossPingRooms[NumRooms] // To do cross-pings in a room, set it to PEERTrue. +); + +// Gets the currently set title. +// Returns NULL if no title is set. +/////////////////////////////////// +const char * peerGetTitleA(PEER peer); + +// Get the local user's nickname. +///////////////////////////////// +const char * peerGetNickA(PEER peer); + +// Replaces any invalid characters in nick with underscores. +//////////////////////////////////////////////////////////// +void peerFixNickA +( + char * newNick, + const char * oldNick +); + +// Removes the namespace extension from a chat unique nick. +// Returns the nick if it ended with the extension. +// Otherwise returns NULL. +/////////////////////////////////////////////////////////// +const char * peerTranslateNickA +( + char * nick, // The nick to translate + const char * extension // The extension to be removed. +); + +// Changes the user's nickname. +/////////////////////////////// +void peerChangeNickA +( + PEER peer, // The peer object. + const char * newNick, // The nickname to which to change. + peerChangeNickCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Sets the away mode. +// If an empty string or NULL, away mode is off. +// If a valid string, away mode is on. +//////////////////////////////////////////////// +void peerSetAwayModeA +( + PEER peer, // The peer object. + const char * reason // The away reason. If NULL or "", not away. +); + +// When using peerStartReportingWithSocket or peerCreateStagingRoomWithSocket, +// any qureries received on the sockets need to be passed to the SDK. Pass +// the data using this function. +////////////////////////////////////////////////////////////////////////////// +void peerParseQueryA +( + PEER peer, // The peer object. + char * query, // String of query data. + int len, // The length of the string, not including the NUL. + struct sockaddr * sender // The address the query was received from. +); + +// Sends a CD Key to the chat server for authentication. +// The callback gets called when the chat server responds. +// This call is required by some games to enter chat rooms. +// It must be called after connecting to the chat server, but +// before entering a room. +///////////////////////////////////////////////////////////// +void peerAuthenticateCDKeyA +( + PEER peer, // The peer object. + const char * cdkey, // The CD key to authenticate. + peerAuthenticateCDKeyCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +/********** +** ROOMS ** +**********/ +// Joins the currently selected title's title room. +/////////////////////////////////////////////////// +void peerJoinTitleRoomA +( + PEER peer, // The peer object. + const char password[PEER_PASSWORD_LEN], // An optional password, normally NULL. + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Joins a staging room. +// server is one of the server objects passed to peerListingGamesCallback(). +// This call will only work if staging==PEERTrue for the server. +// PANTS|09.11.00 - The password is only needed for passworded rooms. +// PANTS|03.15.01 - No longer requires you to be actively listing games. +//////////////////////////////////////////////////////////////////////////// +void peerJoinStagingRoomA +( + PEER peer, // The peer object. + SBServer server, // The server passed into peerlistingGamesCallback(). + const char password[PEER_PASSWORD_LEN], // The password of the room being joined. Can be NULL or "". + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Joins a staging room by its channel name. +// Same as peerJoinStagingRoom, except it takes the staging room's +// channel name instead of an SBServer object. Also, when the +// peerGameStartedCallback is called, the server paramter passed to +// it will be NULL. +/////////////////////////////////////////////////////////////////// +void peerJoinStagingRoomByChannelA +( + PEER peer, // The peer object. + const char * channel, // The channel to join. + const char password[PEER_PASSWORD_LEN], // The password of the room being joined. Can be NULL or "". + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Creates a new staging room, with the local player hosting. +// PANTS|09.11.00 - If the password parameter is not NULL +// or "", this will create a passworded room. The same +// case-sensitive password needs to be passed into +// peerJoinStagingRoom() for other player's to join the room. +// PANTS|09.11.00 - The staging room will be reported as part +// of whatever group room the local player was in when the +// room was created. Leaving the group room will not affect +// what group the staging room is reported as part of. +///////////////////////////////////////////////////////////// +void peerCreateStagingRoomA +( + PEER peer, // The peer object. + const char * name, // The name of the room. + int maxPlayers, // The max number of players allowed in the room. + const char password[PEER_PASSWORD_LEN], // An optional password for the staging room + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerCreateStagingRoom, but uses the provided socket for +// sending heartbeats and query replies. This allows the game +// to share a socket with the peer SDK, which can make hosting +// games behind a NAT proxy possible. +////////////////////////////////////////////////////////////////// +void peerCreateStagingRoomWithSocketA +( + PEER peer, // The peer object. + const char * name, // The name of the room. + int maxPlayers, // The max number of players allowed in the room. + const char password[PEER_PASSWORD_LEN], // An optional password for the staging room + SOCKET socket, // The socket to be used for reporting. + unsigned short port, // The local port to which the socket is bound. + peerJoinRoomCallback callback, // Called when finished. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Leave a room. +// PANTS|09.11.00 - You can now leave a group room +// without being forcibly removed from a staging room. +////////////////////////////////////////////////////// +void peerLeaveRoomA +( + PEER peer, // The peer object. + RoomType roomType, // The room you want to leave (TitleRoom, GroupRoom, or StagingRoom). + const char * reason // The reason the player is leaving (can be NULL). PANTS|03.13.01 +); + +// List all the groups rooms for the currently set title. +// The fields parameter allows you to request extra info +// on each group room. +///////////////////////////////////////////////////////// +void peerListGroupRoomsA +( + PEER peer, // The peer object. + const char * fields, // A backslash delimited list of fields. + peerListGroupRoomsCallback callback, // Called for each group room. + void * param, // Passed to the callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Start listing the currently running games and staging rooms. +// This is used to maintain a list that can presented to the user, +// so they can pick a game (or staging room) to join. +// Games and staging rooms are filtered based on what group the local +// user is in. If the local user isn't in a group, then only games +// and staging rooms that aren't part of any group are listed. +// The fields determine which info to request from the server. These +// must be registered QR2 keys (see qr2regkeys.h). HOSTNAME_KEY and +// GAMEMODE_KEY are automatically requested by Peer, so do not need +// to included. +///////////////////////////////////////////////////////////////////// +void peerStartListingGamesA +( + PEER peer, // The peer object. + const unsigned char * fields, // An array of registered QR2 keys to request from servers. + int numFields, // The number of keys in the fields array. + const char * filter, // A SQL-like rule filter. + peerListingGamesCallback callback, // Called when finished. + void * param // Passed to the callback. +); + +// Send a message to a room. +//////////////////////////// +void peerMessageRoomA +( + PEER peer, // The peer object. + RoomType roomType, // The room to send the message to. + const char * message, // The message. + MessageType messageType // The type of message. +); + +// Send a UTM to a room. +//////////////////////// +void peerUTMRoomA +( + PEER peer, // The peer object. + RoomType roomType, // The room to send the UTM to. + const char * command, // The command. + const char * parameters, // The UTM's parameters. + PEERBool authenticate // If true, the server will authenticate this UTM (should normally be false). +); + +// Set a password in a room you're hosting. +// The only roomType currently supported is StagingRoom. +// This will only work if the player is hosting the room. +// If password is NULL or "", the password will be cleared. +/////////////////////////////////////////////////////////// +void peerSetPasswordA +( + PEER peer, // The peer object. + RoomType roomType, // The room in which to set the password. + const char password[PEER_PASSWORD_LEN] // The password to set. +); + +// Set the name of a room you're hosting. +// The only roomType currently supported is StagingRoom. +// PANTS|09.11.00 +//////////////////////////////////////////////////////// +void peerSetRoomNameA +( + PEER peer, // The peer object. + RoomType roomType, // The room in which to set the name. + const char * name // The new name +); + +// Get a room's name (the channel's title). +// Returns NULL if not in the room. +/////////////////////////////////////////// +const char * peerGetRoomNameA +( + PEER peer, // The peer object. + RoomType roomType // The room to get the name for. +); + +// Get's the chat channel associated with the room. +// Returns NULL if not in the room. +/////////////////////////////////////////////////// +const char * peerGetRoomChannelA +( + PEER peer, // The peer object. + RoomType roomType // The room to get the channel for. +); + +// Use this channel for the title room for the currently set title. +// This function is normally not needed. +/////////////////////////////////////////////////////////////////// +void peerSetTitleRoomChannelA +( + PEER peer, // The peer object. + const char * channel // The channel to use for the title room. +); + + +/************ +** PLAYERS ** +************/ +// Send a message to a player. +////////////////////////////// +void peerMessagePlayerA +( + PEER peer, // The peer object. + const char * nick, // The nick of the player to send the message to. + const char * message, // The message to send. + MessageType messageType // The type of message. +); + +// Send a UTM to a player. +////////////////////////// +void peerUTMPlayerA +( + PEER peer, // The peer object. + const char * nick, // The nick of the player to send the UTM to. + const char * command, // The command. + const char * parameters, // The UTM's parameters. + PEERBool authenticate // If true, the server will authenticate this UTM (should normally be false). +); + +// Kick a player from a room. +// Can only be called by a player with host privileges. +/////////////////////////////////////////////////////// +void peerKickPlayerA +( + PEER peer, // The peer object. + RoomType roomType, // The room to kick the player from. + const char * nick, // The nick of the player to kick. + const char * reason // An optional reason for kicking the player +); + +// Gets a player's ping (between the local machine and the player's machine). +// Returns PEERFalse if we don't have or can't get the player's ping. +///////////////////////////////////////////////////////////////////////////// +PEERBool peerGetPlayerPingA +( + PEER peer, // The peer object. + const char * nick, // The player to get the ping for. + int * ping // The player's ping is stored here, if we have it. +); + +// Gets the cross-ping between 2 players. +// Returns PEERFalse if we don't have or can't get the player's cross-ping. +/////////////////////////////////////////////////////////////////////////// +PEERBool peerGetPlayersCrossPingA +( + PEER peer, // The peer object. + const char * nick1, // The first player. + const char * nick2, // The second player. + int * crossPing // The cross-ping is stored here, if we have it. +); + +// Peer already automatically pings all players that are in ping rooms. +// This function does a one-time ping of a remote player in a non-ping room. +// However pings must be enabled in at least one room for this to work, +// otherwise Peer will not open the UDP ping socket. +// Also, peerAlwaysGetPlayerInfo() must be enabled so that Peer has IPs for +// players that are only in non-ping rooms. +//////////////////////////////////////////////////////////////////////////// +PEERBool peerPingPlayerA +( + PEER peer, // The peer object. + const char * nick // The player to ping. +); + +// Gets a player's info immediately. +// Returns PEERFalse if the info is no available. +///////////////////////////////////////////////// +PEERBool peerGetPlayerInfoNoWaitA +( + PEER peer, + const char * nick, + unsigned int * IP, + int * profileID +); + +// Called to get a player's IP and profile ID. +////////////////////////////////////////////// +void peerGetPlayerInfoA +( + PEER peer, // The peer object. + const char * nick, // The player's nick. + peerGetPlayerInfoCallback callback, // Called when finished. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Called to get a player's profile ID. +// DEPRECATED - Use peerGetPlayerInfo. +/////////////////////////////////////// +void peerGetPlayerProfileIDA +( + PEER peer, // The peer object. + const char * nick, // The player's nick. + peerGetPlayerProfileIDCallback callback, // Called when finished. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Called to get a player's IP. +// DEPRECATED - Use peerGetPlayerInfo. +////////////////////////////////////// +void peerGetPlayerIPA +( + PEER peer, // The peer object. + const char * nick, // The player's nick. + peerGetPlayerIPCallback callback, // Called when finished. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Checks if a player is a host (has ops). +// Returns PEERTrue if yes, PEERFalse if no. +//////////////////////////////////////////// +PEERBool peerIsPlayerHostA +( + PEER peer, // The peer object. + const char * nick, // The player's nick. + RoomType roomType // The room to check in. +); + +// Gets a player's flags in a room. Returns PEERFalse if +// the local player or this player is not in the room. +///////////////////////////////////////////////////////// +PEERBool peerGetPlayerFlagsA +( + PEER peer, + const char * nick, + RoomType roomType, + int * flags +); + +/********* +** GAME ** +*********/ +// Gets a player's ready state. +/////////////////////////////// +PEERBool peerGetReadyA +( + PEER peer, // The peer object. + const char * nick, // The player's nick. + PEERBool * ready // The player's ready state gets stored in here. +); + +// Called only by a staging room host to start the game. +// All the other people in the staging room will have their +// peerGameStartedCallback() called. +// The message gets passed to everyone in the peerGameStartedCallback(), and +// can be used to pass information such as a special port or password. +// If (reportingOptions & PEER_STOP_REPORTING), Peer will stop game reporting, +// so the program is responsible for any server reporting. +// If !(reportingOptions & PEER_STOP_REPORTING), Peer will continue doing +// game reporting, and calling the program-supplied callbacks. If +// (reportingOptions & PEER_REPORT_INFO), all server keys will still be +// reported. If (reportingOptions & PEER_REPORT_PLAYERS), all player keys +// will still be reported. +///////////////////////////////////////////////////////////////////////////// +void peerStartGameA +( + PEER peer, // The peer object. + const char * message, // A message to send to everyone. + int reportingOptions // Bitfield flags used to set reporting options. +); + +/********* +** KEYS ** +*********/ +// Set global keys on the local player. +/////////////////////////////////////// +void peerSetGlobalKeysA +( + PEER peer, // The peer object. + int num, // The number of keys to set. + const char ** keys, // The keys to set. + const char ** values // The values for the keys. +); + + +// Get a player's global keys. +////////////////////////////// +void peerGetPlayerGlobalKeysA +( + PEER peer, // The peer object. + const char * nick, // The player to get the keys for. + int num, // The number of keys. + const char ** keys, // The keys to get. + peerGetGlobalKeysCallback callback, // Called with the keys. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Get the global keys for all players in a room we're in. +////////////////////////////////////////////////////////// +void peerGetRoomGlobalKeysA +( + PEER peer, // The peer object. + RoomType roomType, // The room to get the keys in. + int num, // The number of keys. + const char ** keys, // The keys to get. + peerGetGlobalKeysCallback callback, // Called with the keys. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Set the room keys for a player. +// Use NULL or "" to set keys on the room itself. +///////////////////////////////////////////////// +void peerSetRoomKeysA +( + PEER peer, // The peer object. + RoomType roomType, // The room to set the keys in. + const char * nick, // The player to set the keys on (NULL or "" for the room). + int num, // The number of keys. + const char ** keys, // The keys to set. + const char ** values // The values to set. +); + +// Get the room keys for either a single player of an entire room. +// Use "*" for the player to get the keys for the entire room. +// Use NULL or "" for the player to get keys on the room itself. +////////////////////////////////////////////////////////////////// +void peerGetRoomKeysA +( + PEER peer, // The peer object. + RoomType roomType, // The room to get the keys in. + const char * nick, // The player to get the keys for. + int num, // The number of keys. + const char ** keys, // The keys to get. + peerGetRoomKeysCallback callback, // Called with the keys. + void * param, // Passed to callback. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Set the global watch keys for a room type. +// If addKeys is set to PEERTrue, the keys will be +// added to the current global watch keys for this room. +// If addKeys is PEERFalse, these will replace any existing +// global watch keys for this room. +// When entering a room of the given type, peer will get and +// cache these keys for all players in the room. +//////////////////////////////////////////////////////////// +void peerSetGlobalWatchKeysA +( + PEER peer, // The peer object. + RoomType roomType, // The type of room to set the watch keys for. + int num, // The number of keys. + const char ** keys, // The keys to watch for. + PEERBool addKeys // If PEERTrue, add these keys to the existing global watch keys for this room. +); + +// Set the room watch keys for a room type. +// If addKeys is set to PEERTrue, the keys will be +// added to the current room watch keys for this room. +// If addKeys is PEERFalse, these will replace any existing +// room watch keys for this room. +// When entering a room of the given type, peer will get and +// cache these keys for all players in the room. +//////////////////////////////////////////////////////////// +void peerSetRoomWatchKeysA +( + PEER peer, // The peer object. + RoomType roomType, // The type of room to set the watch keys for. + int num, // The number of keys. + const char ** keys, // The keys to watch for. + PEERBool addKeys // If PEERTrue, add these keys to the existing room watch keys for this room. +); + +// Get the global watch key for a particular player. +// If the key isn't cached locally (either because it isn't +// a watch key or just isn't yet known), NULL will be returned. +// If the key is empty, "" will be returned. +/////////////////////////////////////////////////////////////// +const char * peerGetGlobalWatchKeyA +( + PEER peer, // The peer object. + const char * nick, // The player to get the key for. + const char * key // The key to get. +); + +// Get the room watch key for a particular player in a room. +// If the key isn't cached locally (either because it isn't +// a watch key or just isn't yet known), NULL will be returned. +// If the key is empty, "" will be returned. +/////////////////////////////////////////////////////////////// +const char * peerGetRoomWatchKeyA +( + PEER peer, // The peer object. + RoomType roomType, // The room to get the key in. + const char * nick, // The player to get the key for. + const char * key // The key to get. +); + +/************** +** AUTOMATCH ** +**************/ + +// Used to start a automatch attempt. +// The filter contains any hard criteria. This is used to narrow down the list +// of possible matches to those the user might consider. +// The status callback will be called as the attempt progresses, and the rate +// callback will be used to sort possible matches. +///////////////////////////////////////////////////////////////////////////////// +void peerStartAutoMatchA +( + PEER peer, // The peer object. + int maxPlayers, // The total number of players to match (including the local player). + const char * filter, // Hard criteria - filters out servers. + peerAutoMatchStatusCallback statusCallback, // Called as the attempt status changes. + peerAutoMatchRateCallback rateCallback, // Used to rate possible matches. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + +// Same as peerStartAutoMatch, but uses the provided socket for +// sending heartbeats and query replies. This allows the game +// to share a socket with the peer SDK, which can make hosting +// games behind a NAT proxy possible. +//////////////////////////////////////////////////////////////// +void peerStartAutoMatchWithSocketA +( + PEER peer, // The peer object. + int maxPlayers, // The total number of players to match (including the local player). + const char * filter, // Hard criteria - filters out servers. + SOCKET socket, // The socket to be used for reporting. + unsigned short port, // The local port to which the socket is bound. + peerAutoMatchStatusCallback statusCallback, // Called as the attempt status changes. + peerAutoMatchRateCallback rateCallback, // Used to rate possible matches. + void * param, // User-data. + PEERBool blocking // If PEERTrue, don't return until finished. +); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerAutoMatch.c b/xrGameSpy/gamespy/Peer/peerAutoMatch.c new file mode 100644 index 00000000000..9a8c8fd9f74 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerAutoMatch.c @@ -0,0 +1,334 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include "peerAutoMatch.h" +#include "peerMangle.h" +#include "peerOperations.h" +#include "peerSB.h" +#include "peerQR.h" +#include "peerCallbacks.h" +#include "peerPlayers.h" +#include "peerRooms.h" + +/************** +** FUNCTIONS ** +**************/ +static PEERBool piCreateAutoMatchRoom(PEER peer); + +static void piCleanAutoMatch(PEER peer) +{ + PEER_CONNECTION; + + // free memory + gsifree(connection->autoMatchFilter); + + // remove the operation + piRemoveOperation(peer, connection->autoMatchOperation); + + connection->autoMatchOperation = NULL; +} + +void piSetAutoMatchStatus(PEER peer, PEERAutoMatchStatus status) +{ + piOperation * operation; + PEER_CONNECTION; + + // make sure there is an operation + operation = connection->autoMatchOperation; + assert(operation); + if(!operation) + return; + + // we need to create a room before we can really switch to PEERWaiting + if((status == PEERWaiting) && !connection->inRoom[StagingRoom]) + { + if(!piCreateAutoMatchRoom(peer)) + piSetAutoMatchStatus(peer, connection->autoMatchSBFailed?PEERFailed:PEERSearching); + return; + } + + // check if this is already the current status + if(connection->autoMatchStatus != status) + { + // set the new status + connection->autoMatchStatus = status; + + // add the callback + piAddAutoMatchStatusCallback(peer); + } + + // handle the status + switch(status) + { + case PEERFailed: + // stop + piSBStopListingAutoMatches(peer); + piStopAutoMatchReporting(peer); + piLeaveRoom(peer, StagingRoom, ""); + + // clean + piCleanAutoMatch(peer); + break; + + case PEERSearching: + // stop + piStopAutoMatchReporting(peer); + piLeaveRoom(peer, StagingRoom, ""); + + // start + if(!connection->autoMatchBrowsing) + { + if(!piSBStartListingAutoMatches(peer)) + { + piSetAutoMatchStatus(peer, connection->autoMatchQRFailed?PEERFailed:PEERWaiting); + return; + } + } + break; + + case PEERWaiting: + // start + assert(connection->inRoom[StagingRoom]); + if(!connection->autoMatchBrowsing && !connection->autoMatchSBFailed) + piSBStartListingAutoMatches(peer); + + if(!connection->autoMatchReporting) + { + if(!piStartAutoMatchReporting(peer)) + { + piSetAutoMatchStatus(peer, connection->autoMatchSBFailed?PEERFailed:PEERSearching); + return; + } + } + break; + + case PEERStaging: + // stop + if(!connection->hosting) + { + piStopAutoMatchReporting(peer); + } + piSBStopListingAutoMatches(peer); + + // start + if(connection->hosting && !connection->autoMatchReporting) + { + if(!piStartAutoMatchReporting(peer)) + { + piSetAutoMatchStatus(peer, PEERSearching); + return; + } + } + break; + + case PEERReady: + // start + if (connection->hosting && !connection->autoMatchReporting) + piStartAutoMatchReporting(peer); + + break; + case PEERComplete: + // stop + piSBStopListingAutoMatches(peer); + piStopAutoMatchReporting(peer); + + // clean + piCleanAutoMatch(peer); + break; + } +} + +void piStopAutoMatch(PEER peer) +{ + //PEERBool inRoom; + + PEER_CONNECTION; + + // make sure we're AutoMatching + if(peerIsAutoMatching(peer)) + { + // we don't want the status callback called + if(connection->autoMatchOperation) + connection->autoMatchOperation->callback = (PEERCBType)NULL; + + // trick it into thinking it's not in a staging room (if it is) + //inRoom = connection->inRoom[StagingRoom]; + //connection->inRoom[StagingRoom] = PEERFalse; + + // cleanup + piSetAutoMatchStatus(peer, PEERFailed); + + // reset the inRoom flag + //connection->inRoom[StagingRoom] = inRoom; + } +} + +static void piJoinAutoMatchRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + PEER_CONNECTION; + + // if we're the only one, or if there's no host, leave + if(success && ((connection->numPlayers[StagingRoom] <= 1) || !piCountRoomOps(peer, StagingRoom, connection->nick))) + { + piLeaveRoom(peer, StagingRoom, ""); + success = PEERFalse; + } + + // check if it succeeded + if(success) + { + // we're now staging + piSetAutoMatchStatus(peer, PEERStaging); + + // if we've got maxplayers, we're now Ready + if((connection->autoMatchStatus == PEERStaging) && (connection->numPlayers[StagingRoom] >= connection->maxPlayers)) + piSetAutoMatchStatus(peer, PEERReady); + } + + // if we were waiting, and this failed, restart waiting + if(!success && (connection->autoMatchStatus == PEERWaiting)) + piSetAutoMatchStatus(peer, PEERWaiting); + + GSI_UNUSED(result); + GSI_UNUSED(roomType); + GSI_UNUSED(param); +} + +PEERBool piJoinAutoMatchRoom(PEER peer, SBServer server) +{ + unsigned int publicIP; + unsigned int privateIP; + unsigned short privatePort; + char room[PI_ROOM_MAX_LEN]; + + PEER_CONNECTION; + + // Get the public and private IPs and ports. + publicIP = SBServerGetPublicInetAddress(server); + privateIP = SBServerGetPrivateInetAddress(server); + if(SBServerHasPrivateAddress(server)) + privatePort = SBServerGetPrivateQueryPort(server); + else + privatePort = SBServerGetPublicQueryPort(server); + + if(!publicIP) + return PEERFalse; + + // get the staging room. + piMangleStagingRoom(room, connection->title, publicIP, privateIP, privatePort); + + // start the operation. + if(!piNewJoinRoomOperation(peer, StagingRoom, room, NULL, piJoinAutoMatchRoomCallback, NULL, piGetNextID(peer))) + return PEERFalse; + + // clone the server + connection->hostServer = piSBCloneServer(server); + + return PEERTrue; +} + +// GetChannelModeCallback used to get the channel modes +// and fix the modes: Limit and OpsObeyChannelLimit +static void piAutoMatchGetChannelCallback(CHAT chat, CHATBool success, const gsi_char *channel, CHATChannelMode *mode, void *param) +{ + piConnection *connection = (piConnection *)param; + if (success) + { + + mode->Limit = connection->maxPlayers; + mode->OpsObeyChannelLimit = CHATTrue; + + // Don't let ops bypass channel limit on the number of players in room + chatSetChannelMode(chat, channel, mode); + } + else + { + // handle the failure + connection->autoMatchQRFailed = PEERTrue; + piSetAutoMatchStatus((PEER *)&connection, connection->autoMatchSBFailed?PEERFailed:PEERSearching); + } +} + +static void piCreateAutoMatchRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + PEERAutoMatchStatus status; + + PEER_CONNECTION; + + if(success) + { + // set the status based on the number of people in the room + if(connection->numPlayers[StagingRoom] <= 1) + { + status = PEERWaiting; + + // get the channel modes so we can set the limits on our staging channel + chatGetChannelMode(connection->chat, peerGetRoomChannel(peer, StagingRoom), piAutoMatchGetChannelCallback, + (void *)connection, CHATFalse); + } + else if(connection->numPlayers[StagingRoom] >= connection->maxPlayers) + { + status = PEERReady; + } + else + { + status = PEERStaging; + } + + // set the Waiting status + piSetAutoMatchStatus(peer, status); + } + else + { + // handle the failure + connection->autoMatchQRFailed = PEERTrue; + piSetAutoMatchStatus(peer, connection->autoMatchSBFailed?PEERFailed:PEERSearching); + } + + GSI_UNUSED(result); + GSI_UNUSED(roomType); + GSI_UNUSED(param); +} + +static PEERBool piCreateAutoMatchRoom(PEER peer) +{ + piOperation * operation; + + PEER_CONNECTION; + + // get the AutoMatch operation + operation = connection->autoMatchOperation; + + // start the operations + if(!piNewCreateStagingRoomOperation(peer, connection->nick, "", connection->maxPlayers, operation->socket, operation->port, piCreateAutoMatchRoomCallback, NULL, piGetNextID(peer))) + { + connection->autoMatchQRFailed = PEERTrue; + return PEERFalse; + } + + return PEERTrue; +} diff --git a/xrGameSpy/gamespy/Peer/peerAutoMatch.h b/xrGameSpy/gamespy/Peer/peerAutoMatch.h new file mode 100644 index 00000000000..73234a49ee3 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerAutoMatch.h @@ -0,0 +1,39 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERAUTOMATCH_H_ +#define _PEERAUTOMATCH_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************ +** DEFINES ** +************/ +#define PI_AUTOMATCH_RATING_KEY "gsi_am_rating" + +/************** +** FUNCTIONS ** +**************/ +void piSetAutoMatchStatus(PEER peer, PEERAutoMatchStatus status); +void piStopAutoMatch(PEER peer); +PEERBool piJoinAutoMatchRoom(PEER peer, SBServer server); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerCallbacks.c b/xrGameSpy/gamespy/Peer/peerCallbacks.c new file mode 100644 index 00000000000..87d1997a4ea --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerCallbacks.c @@ -0,0 +1,3695 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include "peer.h" +#include "peerMain.h" +#include "peerCallbacks.h" +#include "peerOperations.h" + +/************ +** DEFINES ** +************/ +#define ASSERT_DATA(data) assert(data->type >= 0);\ + assert(data->callback);\ + assert(data->params); + +/********** +** TYPES ** +**********/ +typedef struct piCallbackData +{ + piCallbackType type; // PI__CALLBACK + PEERBool success; // operation success + PEERCBType callback; // the function callback -- int type for ANSI compatability + void * callbackParam; // user-data for the callback + void * params; // extra callback params + int ID; // unique ID for this callback + PEERBool inCall; // set to true immediately before callback is called, then to false +} piCallbackData; + +typedef struct piCallbackFuncs +{ + piCallbackType type; + PEERBool (* copy) + ( + void * paramsOut, + void * paramsIn + ); + void (* gsifree) + ( + void * params + ); + void (* call) + ( + PEER peer, + piCallbackData * data + ); +} piCallbackFuncs; + +/************** +** CALLBACKS ** +**************/ +static int piAddCallback +( + PEER peer, + PEERBool success, + PEERCBType callback, + void * param, + piCallbackType type, + void * paramsIn, + size_t paramsSize, + int opID +); + +/* Connect. +**********/ +typedef struct piConnectParams +{ + int failureReason; +} piConnectParams; +static PEERBool piConnectCopy(void * paramsOut_, void * paramsIn_) +{ + piConnectParams * paramsOut = (piConnectParams *)paramsOut_; + piConnectParams * paramsIn = (piConnectParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->failureReason = paramsIn->failureReason; + + return PEERTrue; +} +static void piConnectFree(void * params_) +{ + piConnectParams * params = (piConnectParams *)params_; + + assert(params); + GSI_UNUSED(params); +} +static void piConnectCall(PEER peer, piCallbackData * data) +{ + piConnectParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_CONNECT_CALLBACK); + + params = data->params; + ((peerConnectCallback)data->callback)(peer, data->success, params->failureReason, data->callbackParam); +} +void piAddConnectCallback +( + PEER peer, + PEERBool success, + int failureReason, + peerConnectCallback callback, + void * param, + int opID +) +{ + piConnectParams params; + + params.failureReason = failureReason; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_CONNECT_CALLBACK, ¶ms, sizeof(piConnectParams), opID); +} + +/* JoinRoom. +***********/ +typedef struct piJoinRoomParams +{ + PEERJoinResult result; + RoomType roomType; +} piJoinRoomParams; +static PEERBool piJoinRoomCopy(void * paramsOut_, void * paramsIn_) +{ + piJoinRoomParams * paramsOut = (piJoinRoomParams *)paramsOut_; + piJoinRoomParams * paramsIn = (piJoinRoomParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->result = paramsIn->result; + paramsOut->roomType = paramsIn->roomType; + + return PEERTrue; +} +static void piJoinRoomFree(void * params_) +{ + piJoinRoomParams * params = (piJoinRoomParams *)params_; + + assert(params); + GSI_UNUSED(params); +} +static void piJoinRoomCall(PEER peer, piCallbackData * data) +{ + piJoinRoomParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_JOIN_ROOM_CALLBACK); + + params = data->params; + ((peerJoinRoomCallback)(PEERCBType)data->callback)(peer, data->success, params->result, params->roomType, data->callbackParam); +} +void piAddJoinRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + peerJoinRoomCallback callback, + void * param, + int opID +) +{ + piJoinRoomParams params; + + // if this was called as part of an AutoMatch attempt, call the callback directly + // this is safe because we're only calling into Peer code + if(peerIsAutoMatching(peer) && (roomType == StagingRoom)) + { + callback(peer, success, result, roomType, param); + return; + } + + params.result = result; + params.roomType = roomType; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_JOIN_ROOM_CALLBACK, ¶ms, sizeof(piJoinRoomParams), opID); +} + +/* ListGroupsRooms. +******************/ +typedef struct piListGroupRoomsParams +{ + int groupID; + SBServer server; + char * name; + int numWaiting; + int maxWaiting; + int numGames; + int numPlaying; +} piListGroupRoomsParams; +static PEERBool piListGroupRoomsCopy(void * paramsOut_, void * paramsIn_) +{ + piListGroupRoomsParams * paramsOut = (piListGroupRoomsParams *)paramsOut_; + piListGroupRoomsParams * paramsIn = (piListGroupRoomsParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->groupID = paramsIn->groupID; + paramsOut->server = paramsIn->server; + paramsOut->numWaiting = paramsIn->numWaiting; + paramsOut->maxWaiting = paramsIn->maxWaiting; + paramsOut->numGames = paramsIn->numGames; + paramsOut->numPlaying = paramsIn->numPlaying; + if(paramsIn->name) + { + paramsOut->name = goastrdup(paramsIn->name); + if(paramsIn->name && !paramsOut->name) + return PEERFalse; + } + else + paramsOut->name = NULL; + + return PEERTrue; +} +static void piListGroupRoomsFree(void * params_) +{ + piListGroupRoomsParams * params = (piListGroupRoomsParams *)params_; + + assert(params); + + gsifree(params->name); +} +static void piListGroupRoomsCall(PEER peer, piCallbackData * data) +{ + piListGroupRoomsParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_LIST_GROUP_ROOMS_CALLBACK); + + params = data->params; + +#ifndef GSI_UNICODE + ((peerListGroupRoomsCallback)(PEERCBType)data->callback)(peer, data->success, params->groupID, params->server, params->name, params->numWaiting, params->maxWaiting, params->numGames, params->numPlaying, data->callbackParam); +#else + { + unsigned short* name_W = NULL; + if (params->name != NULL) + name_W = UTF8ToUCS2StringAlloc(params->name); + ((peerListGroupRoomsCallback)(int)data->callback)(peer, data->success, params->groupID, params->server, name_W, params->numWaiting, params->maxWaiting, params->numGames, params->numPlaying, data->callbackParam); + gsifree(name_W); + } +#endif +} +void piAddListGroupRoomsCallback +( + PEER peer, + PEERBool success, + int groupID, + SBServer server, + const char * name, + int numWaiting, + int maxWaiting, + int numGames, + int numPlaying, + peerListGroupRoomsCallback callback, + void * param, + int opID +) +{ + piListGroupRoomsParams params; + params.groupID = groupID; + params.server = server; + params.name = (char *)name; + params.numWaiting = numWaiting; + params.maxWaiting = maxWaiting; + params.numGames = numGames; + params.numPlaying = numPlaying; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_LIST_GROUP_ROOMS_CALLBACK, ¶ms, sizeof(piListGroupRoomsParams), opID); +} + +/* ListingGames. +***************/ +typedef struct piListingGamesParams +{ + char * name; + SBServer server; + PEERBool staging; + int msg; + int progress; +} piListingGamesParams; +static PEERBool piListingGamesCopy(void * paramsOut_, void * paramsIn_) +{ + piListingGamesParams * paramsOut = (piListingGamesParams *)paramsOut_; + piListingGamesParams * paramsIn = (piListingGamesParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + if(paramsIn->name) + { + paramsOut->name = goastrdup(paramsIn->name); + if(paramsIn->name && !paramsOut->name) + return PEERFalse; + } + else + paramsOut->name = NULL; + paramsOut->staging = paramsIn->staging; + paramsOut->server = paramsIn->server; + paramsOut->msg = paramsIn->msg; + paramsOut->progress = paramsIn->progress; + + return PEERTrue; +} +static void piListingGamesFree(void * params_) +{ + piListingGamesParams * params = (piListingGamesParams *)params_; + + assert(params); + + gsifree(params->name); +} +static void piListingGamesCall(PEER peer, piCallbackData * data) +{ + piListingGamesParams * params; + int len; + int i; + + PEER_CONNECTION; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_LISTING_GAMES_CALLBACK); + + params = data->params; + + // This is a bit of a hack. We don't want the server browser progess to show + // 100% until the last callback is being called. + if (params->progress == 100) + { + len = ArrayLength(connection->callbackList); + for(i = 0; i < len; i++) + { + // look for a listing games callback + piCallbackData* anotherData = (piCallbackData *)ArrayNth(connection->callbackList, i); + if(anotherData != data && anotherData->type == PI_LISTING_GAMES_CALLBACK) + { + piListingGamesParams* anotherParams = (piListingGamesParams *)anotherData->params; + if(anotherParams->msg == PEER_UPDATE) + { + // Another update callback will follow this one, + // limit the current callback's progress to 99% + params->progress = 99; + break; + } + } + } + } + +#ifndef GSI_UNICODE + ((peerListingGamesCallback)(PEERCBType)data->callback)(peer, data->success, params->name, params->server, params->staging, params->msg, params->progress, data->callbackParam); +#else + { + unsigned short* name_W = NULL; + if (params->name != NULL) + name_W = UTF8ToUCS2StringAlloc(params->name); + ((peerListingGamesCallback)(int)data->callback)(peer, data->success, name_W, params->server, params->staging, params->msg, params->progress, data->callbackParam); + gsifree(name_W); + } +#endif +} + +void piAddListingGamesCallback +( + PEER peer, + PEERBool success, + SBServer server, + int msg +) +{ + piListingGamesParams params; + const char * name; + const char * gamemode; + PEERBool staging; + int count; + int pendingCount; + int progress; + PEER_CONNECTION; + + // if this is a remove, remove any queued adds or updates + if(msg == PEER_REMOVE) + piClearListingGameServerCallbacks(peer, server); + + // get info from the server object + if(server) + { + name = SBServerGetStringValueA(server, "hostname", "(No Name)"); + gamemode = SBServerGetStringValueA(server, "gamemode", ""); + staging = (PEERBool)(strcasecmp(gamemode, "openstaging") == 0); + } + else + { + name = NULL; + staging = PEERFalse; + } + + // set the progress + if(connection->initialGameList) + { + count = SBServerListCount(&connection->gameList); + if(count) + { + pendingCount = (connection->gameEngine.querylist.count + connection->gameEngine.pendinglist.count); + progress = (((count - pendingCount) * 100) / count); + } + else + { + progress = 0; + } + } + else + { + progress = 100; + } + + params.name = (char *)name; + params.server = server; + params.staging = staging; + params.msg = msg; + params.progress = progress; + piAddCallback(peer, success, (PEERCBType)connection->gameListCallback, connection->gameListParam, PI_LISTING_GAMES_CALLBACK, ¶ms, sizeof(piListingGamesParams), -1); +} + +/* NickError. +*************/ +typedef struct piNickErrorParams +{ + int type; + char * nick; + int numSuggestedNicks; + char ** suggestedNicks; +} piNickErrorParams; +static PEERBool piNickErrorCopy(void * paramsOut_, void * paramsIn_) +{ + int i; + int num; + PEERBool success = PEERTrue; + piNickErrorParams * paramsOut = (piNickErrorParams *)paramsOut_; + piNickErrorParams * paramsIn = (piNickErrorParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + memset(paramsOut, 0, sizeof(piNickErrorParams)); + num = paramsOut->numSuggestedNicks = paramsIn->numSuggestedNicks; + + paramsOut->type = paramsIn->type; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + success = PEERFalse; + } + else + paramsOut->nick = NULL; + + if(success && num && paramsIn->suggestedNicks) + { + paramsOut->suggestedNicks = (char **)gsimalloc(sizeof(char *) * num); + if(!paramsOut->suggestedNicks) + success = PEERFalse; + else + memset(paramsOut->suggestedNicks, 0, sizeof(char *) * num); + + for(i = 0 ; success && (i < num) ; i++) + { + paramsOut->suggestedNicks[i] = goastrdup(paramsIn->suggestedNicks[i]); + if(!paramsOut->suggestedNicks[i]) + success = PEERFalse; + } + } + + if(!success) + { + gsifree(paramsOut->nick); + for(i = 0 ; i < num ; i++) + { + if(paramsOut->suggestedNicks) + gsifree(paramsOut->suggestedNicks[i]); + } + gsifree(paramsOut->suggestedNicks); + } + + return success; +} +static void piNickErrorFree(void * params_) +{ + int i; + piNickErrorParams * params = (piNickErrorParams *)params_; + + assert(params); + + gsifree(params->nick); + for(i = 0 ; i < params->numSuggestedNicks ; i++) + { + if(params->suggestedNicks) + gsifree(params->suggestedNicks[i]); + } + gsifree(params->suggestedNicks); +} +static void piNickErrorCall(PEER peer, piCallbackData * data) +{ + piNickErrorParams * params; + + //PEER_CONNECTION; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_NICK_ERROR_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerNickErrorCallback)(PEERCBType)data->callback)(peer, params->type, params->nick, params->numSuggestedNicks, (const char **)params->suggestedNicks, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short** suggestedNicks_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)params->suggestedNicks, params->numSuggestedNicks); + int i; + ((peerNickErrorCallback)data->callback)(peer, params->type, nick_W, params->numSuggestedNicks, (const unsigned short**)suggestedNicks_W, data->callbackParam); + gsifree(nick_W); + for (i=0; i < params->numSuggestedNicks; i++) + { + gsifree(suggestedNicks_W[i]); + } + gsifree(suggestedNicks_W); + } +#endif +} + +void piAddNickErrorCallback +( + PEER peer, + int type, + const char * nick, + int numSuggestedNicks, + const char ** suggestedNicks, + void * param, + int opID +) +{ + piNickErrorParams params; + + PEER_CONNECTION; + + params.type = type; + params.nick = (char *)nick; + params.numSuggestedNicks = numSuggestedNicks; + params.suggestedNicks = (char **)suggestedNicks; + piAddCallback(peer, PEERFalse, (PEERCBType)connection->nickErrorCallback, param, PI_NICK_ERROR_CALLBACK, ¶ms, sizeof(piNickErrorParams), opID); +} + +/* EnumPlayers. +**************/ +typedef struct piEnumPlayersParams +{ + RoomType roomType; + int index; + char * nick; + int flags; +} piEnumPlayersParams; +static PEERBool piEnumPlayersCopy(void * paramsOut_, void * paramsIn_) +{ + piEnumPlayersParams * paramsOut = (piEnumPlayersParams *)paramsOut_; + piEnumPlayersParams * paramsIn = (piEnumPlayersParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + paramsOut->index = paramsIn->index; + paramsOut->flags = paramsIn->flags; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(paramsIn->nick && !paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + + return PEERTrue; +} +static void piEnumPlayersFree(void * params_) +{ + piEnumPlayersParams * params = (piEnumPlayersParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piEnumPlayersCall(PEER peer, piCallbackData * data) +{ + piEnumPlayersParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_ENUM_PLAYERS_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerEnumPlayersCallback)data->callback)(peer, data->success, params->roomType, params->index, params->nick, params->flags, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerEnumPlayersCallback)data->callback)(peer, data->success, params->roomType, params->index, nick_W, params->flags, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddEnumPlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const char * nick, + int flags, + peerEnumPlayersCallback callback, + void * param, + int opID +) +{ + piEnumPlayersParams params; + params.roomType = roomType; + params.index = index; + params.nick = (char *)nick; + params.flags = flags; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_ENUM_PLAYERS_CALLBACK, ¶ms, sizeof(piEnumPlayersParams), opID); +} + +/* GetPlayerInfo. +****************/ +typedef struct piGetPlayerInfoParams +{ + char * nick; + unsigned int IP; + int profileID; +} piGetPlayerInfoParams; +static PEERBool piGetPlayerInfoCopy(void * paramsOut_, void * paramsIn_) +{ + piGetPlayerInfoParams * paramsOut = (piGetPlayerInfoParams *)paramsOut_; + piGetPlayerInfoParams * paramsIn = (piGetPlayerInfoParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + paramsOut->IP = paramsIn->IP; + paramsOut->profileID = paramsIn->profileID; + + return PEERTrue; +} +static void piGetPlayerInfoFree(void * params_) +{ + piGetPlayerInfoParams * params = (piGetPlayerInfoParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piGetPlayerInfoCall(PEER peer, piCallbackData * data) +{ + piGetPlayerInfoParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GET_PLAYER_INFO_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGetPlayerInfoCallback)data->callback)(peer, data->success, params->nick, params->IP, params->profileID, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerGetPlayerInfoCallback)data->callback)(peer, data->success, nick_W, params->IP, params->profileID, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddGetPlayerInfoCallback +( + PEER peer, + PEERBool success, + const char * nick, + unsigned int IP, + int profileID, + peerGetPlayerInfoCallback callback, + void * param, + int opID +) +{ + piGetPlayerInfoParams params; + params.nick = (char *)nick; + params.IP = IP; + params.profileID = profileID; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_GET_PLAYER_INFO_CALLBACK, ¶ms, sizeof(piGetPlayerInfoParams), opID); +} + +/* GetPlayerProfileID. +*********************/ +typedef struct piGetPlayerProfileIDParams +{ + char * nick; + int profileID; +} piGetPlayerProfileIDParams; +static PEERBool piGetPlayerProfileIDCopy(void * paramsOut_, void * paramsIn_) +{ + piGetPlayerProfileIDParams * paramsOut = (piGetPlayerProfileIDParams *)paramsOut_; + piGetPlayerProfileIDParams * paramsIn = (piGetPlayerProfileIDParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + paramsOut->profileID = paramsIn->profileID; + + return PEERTrue; +} +static void piGetPlayerProfileIDFree(void * params_) +{ + piGetPlayerProfileIDParams * params = (piGetPlayerProfileIDParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piGetPlayerProfileIDCall(PEER peer, piCallbackData * data) +{ + piGetPlayerProfileIDParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GET_PLAYER_PROFILE_ID_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGetPlayerProfileIDCallback)data->callback)(peer, data->success, params->nick, params->profileID, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerGetPlayerProfileIDCallback)data->callback)(peer, data->success, nick_W, params->profileID, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddGetPlayerProfileIDCallback +( + PEER peer, + PEERBool success, + const char * nick, + int profileID, + peerGetPlayerProfileIDCallback callback, + void * param, + int opID +) +{ + piGetPlayerProfileIDParams params; + params.nick = (char *)nick; + params.profileID = profileID; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_GET_PLAYER_PROFILE_ID_CALLBACK, ¶ms, sizeof(piGetPlayerProfileIDParams), opID); +} + +/* GetPlayerIP. +**************/ +typedef struct piGetPlayerIPParams +{ + char * nick; + unsigned int IP; +} piGetPlayerIPParams; +static PEERBool piGetPlayerIPCopy(void * paramsOut_, void * paramsIn_) +{ + piGetPlayerIPParams * paramsOut = (piGetPlayerIPParams *)paramsOut_; + piGetPlayerIPParams * paramsIn = (piGetPlayerIPParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->IP = paramsIn->IP; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + + return PEERTrue; +} +static void piGetPlayerIPFree(void * params_) +{ + piGetPlayerIPParams * params = (piGetPlayerIPParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piGetPlayerIPCall(PEER peer, piCallbackData * data) +{ + piGetPlayerIPParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GET_PLAYER_IP_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGetPlayerIPCallback)data->callback)(peer, data->success, params->nick, params->IP, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerGetPlayerIPCallback)data->callback)(peer, data->success, nick_W, params->IP, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddGetPlayerIPCallback +( + PEER peer, + PEERBool success, + const char * nick, + unsigned int IP, + peerGetPlayerIPCallback callback, + void * param, + int opID +) +{ + piGetPlayerIPParams params; + params.nick = (char *)nick; + params.IP = IP; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_GET_PLAYER_IP_CALLBACK, ¶ms, sizeof(piGetPlayerIPParams), opID); +} + +/* Room Message. +***************/ +typedef struct piRoomMessageParams +{ + RoomType roomType; + char * nick; + char * message; + MessageType messageType; +} piRoomMessageParams; +static PEERBool piRoomMessageCopy(void * paramsOut_, void * paramsIn_) +{ + piRoomMessageParams * paramsOut = (piRoomMessageParams *)paramsOut_; + piRoomMessageParams * paramsIn = (piRoomMessageParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + paramsOut->messageType = paramsIn->messageType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->message) + { + paramsOut->message = goastrdup(paramsIn->message); + if(!paramsOut->message) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->message = NULL; + + return PEERTrue; +} +static void piRoomMessageFree(void * params_) +{ + piRoomMessageParams * params = (piRoomMessageParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->message); +} +static void piRoomMessageCall(PEER peer, piCallbackData * data) +{ + piRoomMessageParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_ROOM_MESSAGE_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerRoomMessageCallback)data->callback)(peer, params->roomType, params->nick, params->message, params->messageType, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* message_W = UTF8ToUCS2StringAlloc(params->message); + + ((peerRoomMessageCallback)data->callback)(peer, params->roomType, nick_W, message_W, params->messageType, data->callbackParam); + gsifree(nick_W); + gsifree(message_W); + } +#endif +} +void piAddRoomMessageCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * message, + MessageType messageType +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->roomMessage) + { + piRoomMessageParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.message = (char *)message; + params.messageType = messageType; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->roomMessage, callbacks->param, PI_ROOM_MESSAGE_CALLBACK, ¶ms, sizeof(piRoomMessageParams), -1); + } +} + +/* Room UTM. +***********/ +typedef struct piRoomUTMParams +{ + RoomType roomType; + char * nick; + char * command; + char * parameters; + PEERBool authenticated; +} piRoomUTMParams; +static PEERBool piRoomUTMCopy(void * paramsOut_, void * paramsIn_) +{ + piRoomUTMParams * paramsOut = (piRoomUTMParams *)paramsOut_; + piRoomUTMParams * paramsIn = (piRoomUTMParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->authenticated = paramsIn->authenticated; + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->command) + { + paramsOut->command = goastrdup(paramsIn->command); + if(!paramsOut->command) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->command = NULL; + if(paramsIn->parameters) + { + paramsOut->parameters = goastrdup(paramsIn->parameters); + if(!paramsOut->parameters) + { + gsifree(paramsOut->nick); + gsifree(paramsOut->command); + return PEERFalse; + } + } + else + paramsOut->parameters = NULL; + + return PEERTrue; +} +static void piRoomUTMFree(void * params_) +{ + piRoomUTMParams * params = (piRoomUTMParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->command); + gsifree(params->parameters); +} +static void piRoomUTMCall(PEER peer, piCallbackData * data) +{ + piRoomUTMParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_ROOM_UTM_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerRoomUTMCallback)data->callback)(peer, params->roomType, params->nick, params->command, params->parameters, params->authenticated, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* command_W = UTF8ToUCS2StringAlloc(params->command); + unsigned short* parameters_W = UTF8ToUCS2StringAlloc(params->parameters); + ((peerRoomUTMCallback)data->callback)(peer, params->roomType, nick_W, command_W, parameters_W, params->authenticated, data->callbackParam); + gsifree(nick_W); + gsifree(command_W); + gsifree(parameters_W); + } +#endif +} +void piAddRoomUTMCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * command, + const char * parameters, + PEERBool authenticated +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->roomUTM) + { + piRoomUTMParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.command = (char *)command; + params.parameters = (char *)parameters; + params.authenticated = authenticated; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->roomUTM, callbacks->param, PI_ROOM_UTM_CALLBACK, ¶ms, sizeof(piRoomUTMParams), -1); + } +} + +/* Room Name Changed. +********************/ +typedef struct piRoomNameChangedParams +{ + RoomType roomType; +} piRoomNameChangedParams; +static PEERBool piRoomNameChangedCopy(void * paramsOut_, void * paramsIn_) +{ + piRoomNameChangedParams * paramsOut = (piRoomNameChangedParams *)paramsOut_; + piRoomNameChangedParams * paramsIn = (piRoomNameChangedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + + return PEERTrue; +} +static void piRoomNameChangedFree(void * params_) +{ + piRoomNameChangedParams * params = (piRoomNameChangedParams *)params_; + + assert(params); + GSI_UNUSED(params); +} +static void piRoomNameChangedCall(PEER peer, piCallbackData * data) +{ + piRoomNameChangedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_ROOM_NAME_CHANGED_CALLBACK); + + params = data->params; + ((peerRoomNameChangedCallback)data->callback)(peer, params->roomType, data->callbackParam); +} +void piAddRoomNameChangedCallback +( + PEER peer, + RoomType roomType +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->roomNameChanged) + { + piRoomNameChangedParams params; + params.roomType = roomType; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->roomNameChanged, callbacks->param, PI_ROOM_NAME_CHANGED_CALLBACK, ¶ms, sizeof(piRoomNameChangedParams), -1); + } +} + +/* Room Mode Changed. +********************/ +typedef struct piRoomModeChangedParams +{ + RoomType roomType; + CHATChannelMode mode; +} piRoomModeChangedParams; +static PEERBool piRoomModeChangedCopy(void * paramsOut_, void * paramsIn_) +{ + piRoomModeChangedParams * paramsOut = (piRoomModeChangedParams *)paramsOut_; + piRoomModeChangedParams * paramsIn = (piRoomModeChangedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + paramsOut->mode = paramsIn->mode; + + return PEERTrue; +} +static void piRoomModeChangedFree(void * params_) +{ + piRoomModeChangedParams * params = (piRoomModeChangedParams *)params_; + + assert(params); + GSI_UNUSED(params); +} +static void piRoomModeChangedCall(PEER peer, piCallbackData * data) +{ + piRoomModeChangedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_ROOM_MODE_CHANGED_CALLBACK); + + params = data->params; + ((peerRoomModeChangedCallback)data->callback)(peer, params->roomType, ¶ms->mode, data->callbackParam); +} +void piAddRoomModeChangedCallback +( + PEER peer, + RoomType roomType, + CHATChannelMode * mode +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->roomModeChanged) + { + piRoomModeChangedParams params; + params.roomType = roomType; + params.mode = *mode; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->roomModeChanged, callbacks->param, PI_ROOM_MODE_CHANGED_CALLBACK, ¶ms, sizeof(piRoomModeChangedParams), -1); + } +} + +/* Player Message. +*****************/ +typedef struct piPlayerMessageParams +{ + char * nick; + char * message; + MessageType messageType; +} piPlayerMessageParams; +static PEERBool piPlayerMessageCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerMessageParams * paramsOut = (piPlayerMessageParams *)paramsOut_; + piPlayerMessageParams * paramsIn = (piPlayerMessageParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->messageType = paramsIn->messageType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->message) + { + paramsOut->message = goastrdup(paramsIn->message); + if(!paramsOut->message) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->message = NULL; + + return PEERTrue; +} +static void piPlayerMessageFree(void * params_) +{ + piPlayerMessageParams * params = (piPlayerMessageParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->message); +} +static void piPlayerMessageCall(PEER peer, piCallbackData * data) +{ + piPlayerMessageParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_MESSAGE_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPlayerMessageCallback)data->callback)(peer, params->nick, params->message, params->messageType, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* message_W = UTF8ToUCS2StringAlloc(params->message); + ((peerPlayerMessageCallback)data->callback)(peer, nick_W, message_W, params->messageType, data->callbackParam); + gsifree(nick_W); + gsifree(message_W); + } +#endif +} +void piAddPlayerMessageCallback +( + PEER peer, + const char * nick, + const char * message, + MessageType messageType +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerMessage) + { + piPlayerMessageParams params; + params.nick = (char *)nick; + params.message = (char *)message; + params.messageType = messageType; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerMessage, callbacks->param, PI_PLAYER_MESSAGE_CALLBACK, ¶ms, sizeof(piPlayerMessageParams), -1); + } +} + +/* Player UTM. +*************/ +typedef struct piPlayerUTMParams +{ + char * nick; + char * command; + char * parameters; + PEERBool authenticated; +} piPlayerUTMParams; +static PEERBool piPlayerUTMCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerUTMParams * paramsOut = (piPlayerUTMParams *)paramsOut_; + piPlayerUTMParams * paramsIn = (piPlayerUTMParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->authenticated = paramsIn->authenticated; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->command) + { + paramsOut->command = goastrdup(paramsIn->command); + if(!paramsOut->command) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->command = NULL; + if(paramsIn->parameters) + { + paramsOut->parameters = goastrdup(paramsIn->parameters); + if(!paramsOut->parameters) + { + gsifree(paramsOut->nick); + gsifree(paramsOut->command); + return PEERFalse; + } + } + else + paramsOut->parameters = NULL; + + return PEERTrue; +} +static void piPlayerUTMFree(void * params_) +{ + piPlayerUTMParams * params = (piPlayerUTMParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->command); + gsifree(params->parameters); +} +static void piPlayerUTMCall(PEER peer, piCallbackData * data) +{ + piPlayerUTMParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_UTM_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPlayerUTMCallback)data->callback)(peer, params->nick, params->command, params->parameters, params->authenticated, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* command_W = UTF8ToUCS2StringAlloc(params->command); + unsigned short* parameters_W = UTF8ToUCS2StringAlloc(params->parameters); + ((peerPlayerUTMCallback)data->callback)(peer, nick_W, command_W, parameters_W, params->authenticated, data->callbackParam); + gsifree(nick_W); + gsifree(command_W); + gsifree(parameters_W); + } +#endif +} +void piAddPlayerUTMCallback +( + PEER peer, + const char * nick, + const char * command, + const char * parameters, + PEERBool authenticated +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerUTM) + { + piPlayerUTMParams params; + params.nick = (char *)nick; + params.command = (char *)command; + params.parameters = (char *)parameters; + params.authenticated = authenticated; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerUTM, callbacks->param, PI_PLAYER_UTM_CALLBACK, ¶ms, sizeof(piPlayerUTMParams), -1); + } +} + +/* Ready Changed. +****************/ +typedef struct piReadyChangedParams +{ + char * nick; + PEERBool ready; +} piReadyChangedParams; +static PEERBool piReadyChangedCopy(void * paramsOut_, void * paramsIn_) +{ + piReadyChangedParams * paramsOut = (piReadyChangedParams *)paramsOut_; + piReadyChangedParams * paramsIn = (piReadyChangedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + paramsOut->ready = paramsIn->ready; + + return PEERTrue; +} +static void piReadyChangedFree(void * params_) +{ + piReadyChangedParams * params = (piReadyChangedParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piReadyChangedCall(PEER peer, piCallbackData * data) +{ + piReadyChangedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_READY_CHANGED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerReadyChangedCallback)data->callback)(peer, params->nick, params->ready, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerReadyChangedCallback)data->callback)(peer, nick_W, params->ready, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddReadyChangedCallback +( + PEER peer, + const char * nick, + PEERBool ready +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->readyChanged) + { + piReadyChangedParams params; + params.nick = (char *)nick; + params.ready = ready; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->readyChanged, callbacks->param, PI_READY_CHANGED_CALLBACK, ¶ms, sizeof(piReadyChangedParams), -1); + } +} + +/* GameStarted. +**************/ +typedef struct piGameStartedParams +{ + SBServer server; + char * message; +} piGameStartedParams; +static PEERBool piGameStartedCopy(void * paramsOut_, void * paramsIn_) +{ + piGameStartedParams * paramsOut = (piGameStartedParams *)paramsOut_; + piGameStartedParams * paramsIn = (piGameStartedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->server = paramsIn->server; + if(paramsIn->message) + { + paramsOut->message = goastrdup(paramsIn->message); + if(!paramsOut->message) + return PEERFalse; + } + else + paramsOut->message = NULL; + + return PEERTrue; +} +static void piGameStartedFree(void * params_) +{ + piGameStartedParams * params = (piGameStartedParams *)params_; + + assert(params); + + gsifree(params->message); +} +static void piGameStartedCall(PEER peer, piCallbackData * data) +{ + piGameStartedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GAME_STARTED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGameStartedCallback)data->callback)(peer, params->server, params->message, data->callbackParam); +#else + { + unsigned short* message_W = UTF8ToUCS2StringAlloc(params->message); + ((peerGameStartedCallback)data->callback)(peer, params->server, message_W, data->callbackParam); + gsifree(message_W); + } +#endif +} +void piAddGameStartedCallback +( + PEER peer, + SBServer server, + const char * message +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->gameStarted) + { + piGameStartedParams params; + params.server = server; + params.message = (char *)message; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->gameStarted, callbacks->param, PI_GAME_STARTED_CALLBACK, ¶ms, sizeof(piGameStartedParams), -1); + } +} + +/* Player Joined. +****************/ +typedef struct piPlayerJoinedParams +{ + RoomType roomType; + char * nick; +} piPlayerJoinedParams; +static PEERBool piPlayerJoinedCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerJoinedParams * paramsOut = (piPlayerJoinedParams *)paramsOut_; + piPlayerJoinedParams * paramsIn = (piPlayerJoinedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + + return PEERTrue; +} +static void piPlayerJoinedFree(void * params_) +{ + piPlayerJoinedParams * params = (piPlayerJoinedParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piPlayerJoinedCall(PEER peer, piCallbackData * data) +{ + piPlayerJoinedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_JOINED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPlayerJoinedCallback)data->callback)(peer, params->roomType, params->nick, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerPlayerJoinedCallback)data->callback)(peer, params->roomType, nick_W, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddPlayerJoinedCallback +( + PEER peer, + RoomType roomType, + const char * nick +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerJoined) + { + piPlayerJoinedParams params; + params.roomType = roomType; + params.nick = (char *)nick; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerJoined, callbacks->param, PI_PLAYER_JOINED_CALLBACK, ¶ms, sizeof(piPlayerJoinedParams), -1); + } +} + +/* Player Left. +**************/ +typedef struct piPlayerLeftParams +{ + RoomType roomType; + char * nick; + char * reason; +} piPlayerLeftParams; +static PEERBool piPlayerLeftCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerLeftParams * paramsOut = (piPlayerLeftParams *)paramsOut_; + piPlayerLeftParams * paramsIn = (piPlayerLeftParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->reason) + { + paramsOut->reason = goastrdup(paramsIn->reason); + if(!paramsOut->reason) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->reason = NULL; + + return PEERTrue; +} +static void piPlayerLeftFree(void * params_) +{ + piPlayerLeftParams * params = (piPlayerLeftParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->reason); +} +static void piPlayerLeftCall(PEER peer, piCallbackData * data) +{ + piPlayerLeftParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_LEFT_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPlayerLeftCallback)data->callback)(peer, params->roomType, params->nick, params->reason, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* reason_W = UTF8ToUCS2StringAlloc(params->reason); + ((peerPlayerLeftCallback)data->callback)(peer, params->roomType, nick_W, reason_W, data->callbackParam); + gsifree(nick_W); + gsifree(reason_W); + } +#endif +} +void piAddPlayerLeftCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * reason +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerLeft) + { + piPlayerLeftParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.reason = (char *)reason; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerLeft, callbacks->param, PI_PLAYER_LEFT_CALLBACK, ¶ms, sizeof(piPlayerLeftParams), -1); + } +} + +/* Kicked. +*********/ +typedef struct piKickedParams +{ + RoomType roomType; + char * nick; + char * reason; +} piKickedParams; +static PEERBool piKickedCopy(void * paramsOut_, void * paramsIn_) +{ + piKickedParams * paramsOut = (piKickedParams *)paramsOut_; + piKickedParams * paramsIn = (piKickedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->reason) + { + paramsOut->reason = goastrdup(paramsIn->reason); + if(!paramsOut->reason) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->reason = NULL; + + return PEERTrue; +} +static void piKickedFree(void * params_) +{ + piKickedParams * params = (piKickedParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->reason); +} +static void piKickedCall(PEER peer, piCallbackData * data) +{ + piKickedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_KICKED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerKickedCallback)data->callback)(peer, params->roomType, params->nick, params->reason, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* reason_W = UTF8ToUCS2StringAlloc(params->reason); + ((peerKickedCallback)data->callback)(peer, params->roomType, nick_W, reason_W, data->callbackParam); + gsifree(nick_W); + gsifree(reason_W); + } +#endif +} +void piAddKickedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * reason +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->kicked) + { + piKickedParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.reason = (char *)reason; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->kicked, callbacks->param, PI_KICKED_CALLBACK, ¶ms, sizeof(piKickedParams), -1); + } +} + +/* New Player List. +******************/ +typedef struct piNewPlayerListParams +{ + RoomType roomType; +} piNewPlayerListParams; +static PEERBool piNewPlayerListCopy(void * paramsOut_, void * paramsIn_) +{ + piNewPlayerListParams * paramsOut = (piNewPlayerListParams *)paramsOut_; + piNewPlayerListParams * paramsIn = (piNewPlayerListParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + + return PEERTrue; +} +static void piNewPlayerListFree(void * params_) +{ + piNewPlayerListParams * params = (piNewPlayerListParams *)params_; + + assert(params); + GSI_UNUSED(params); +} +static void piNewPlayerListCall(PEER peer, piCallbackData * data) +{ + piNewPlayerListParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_NEW_PLAYER_LIST_CALLBACK); + + params = data->params; + ((peerNewPlayerListCallback)data->callback)(peer, params->roomType, data->callbackParam); +} +void piAddNewPlayerListCallback +( + PEER peer, + RoomType roomType +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->newPlayerList) + { + piNewPlayerListParams params; + params.roomType = roomType; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->newPlayerList, callbacks->param, PI_NEW_PLAYER_LIST_CALLBACK, ¶ms, sizeof(piNewPlayerListParams), -1); + } +} + +/* Player Changed Nick. +**********************/ +typedef struct piPlayerChangedNickParams +{ + RoomType roomType; + char * oldNick; + char * newNick; +} piPlayerChangedNickParams; +static PEERBool piPlayerChangedNickCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerChangedNickParams * paramsOut = (piPlayerChangedNickParams *)paramsOut_; + piPlayerChangedNickParams * paramsIn = (piPlayerChangedNickParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->oldNick) + { + paramsOut->oldNick = goastrdup(paramsIn->oldNick); + if(!paramsOut->oldNick) + return PEERFalse; + } + else + paramsOut->oldNick = NULL; + if(paramsIn->newNick) + { + paramsOut->newNick = goastrdup(paramsIn->newNick); + if(!paramsOut->newNick) + { + gsifree(paramsOut->oldNick); + return PEERFalse; + } + } + else + paramsOut->newNick = NULL; + + return PEERTrue; +} +static void piPlayerChangedNickFree(void * params_) +{ + piPlayerChangedNickParams * params = (piPlayerChangedNickParams *)params_; + + assert(params); + + gsifree(params->oldNick); + gsifree(params->newNick); +} +static void piPlayerChangedNickCall(PEER peer, piCallbackData * data) +{ + piPlayerChangedNickParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_CHANGED_NICK_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPlayerChangedNickCallback)data->callback)(peer, params->roomType, params->oldNick, params->newNick, data->callbackParam); +#else + { + unsigned short* oldNick_W = UTF8ToUCS2StringAlloc(params->oldNick); + unsigned short* newNick_W = UTF8ToUCS2StringAlloc(params->newNick); + ((peerPlayerChangedNickCallback)data->callback)(peer, params->roomType, oldNick_W, newNick_W, data->callbackParam); + gsifree(oldNick_W); + gsifree(newNick_W); + } +#endif +} +void piAddPlayerChangedNickCallback +( + PEER peer, + RoomType roomType, + const char * oldNick, + const char * newNick +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerChangedNick) + { + piPlayerChangedNickParams params; + params.roomType = roomType; + params.oldNick = (char *)oldNick; + params.newNick = (char *)newNick; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerChangedNick, callbacks->param, PI_PLAYER_CHANGED_NICK_CALLBACK, ¶ms, sizeof(piPlayerChangedNickParams), -1); + } +} + +/* Player Info. +**************/ +typedef struct piPlayerInfoParams +{ + RoomType roomType; + char * nick; + unsigned int IP; + int profileID; +} piPlayerInfoParams; +static PEERBool piPlayerInfoCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerInfoParams * paramsOut = (piPlayerInfoParams *)paramsOut_; + piPlayerInfoParams * paramsIn = (piPlayerInfoParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + paramsOut->IP = paramsIn->IP; + paramsOut->profileID = paramsIn->profileID; + + return PEERTrue; +} +static void piPlayerInfoFree(void * params_) +{ + piPlayerInfoParams * params = (piPlayerInfoParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piPlayerInfoCall(PEER peer, piCallbackData * data) +{ + piPlayerInfoParams * params; + PEER_CONNECTION; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_INFO_CALLBACK); + + params = data->params; + + // Don't call this if we're not in the room anymore. + //////////////////////////////////////////////////// + if(!connection->inRoom[params->roomType]) + return; + +#ifndef GSI_UNICODE + ((peerPlayerInfoCallback)data->callback)(peer, params->roomType, params->nick, params->IP, params->profileID, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerPlayerInfoCallback)data->callback)(peer, params->roomType, nick_W, params->IP, params->profileID, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddPlayerInfoCallback +( + PEER peer, + RoomType roomType, + const char * nick, + unsigned int IP, + int profileID +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerInfo) + { + piPlayerInfoParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.IP = IP; + params.profileID = profileID; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerInfo, callbacks->param, PI_PLAYER_INFO_CALLBACK, ¶ms, sizeof(piPlayerInfoParams), -1); + } +} + +/* Disconnected. +***************/ +typedef struct piDisconnectedParams +{ + char * reason; +} piDisconnectedParams; +static PEERBool piDisconnectedCopy(void * paramsOut_, void * paramsIn_) +{ + piDisconnectedParams * paramsOut = (piDisconnectedParams *)paramsOut_; + piDisconnectedParams * paramsIn = (piDisconnectedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + if(paramsIn->reason) + { + paramsOut->reason = goastrdup(paramsIn->reason); + if(!paramsOut->reason) + return PEERFalse; + } + else + paramsOut->reason = NULL; + + return PEERTrue; +} +static void piDisconnectedFree(void * params_) +{ + piDisconnectedParams * params = (piDisconnectedParams *)params_; + + assert(params); + + gsifree(params->reason); +} +static void piDisconnectedCall(PEER peer, piCallbackData * data) +{ + piDisconnectedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_DISCONNECTED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerDisconnectedCallback)data->callback)(peer, params->reason, data->callbackParam); +#else + { + unsigned short* reason_W = UTF8ToUCS2StringAlloc(params->reason); + ((peerDisconnectedCallback)data->callback)(peer, reason_W, data->callbackParam); + gsifree(reason_W); + } +#endif +} +void piAddDisconnectedCallback +( + PEER peer, + const char * reason +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->disconnected) + { + piDisconnectedParams params; + params.reason = (char *)reason; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->disconnected, callbacks->param, PI_DISCONNECTED_CALLBACK, ¶ms, sizeof(piDisconnectedParams), -1); + } +} + +/* Ping. +*******/ +typedef struct piPingParams +{ + char * nick; + int ping; +} piPingParams; +static PEERBool piPingCopy(void * paramsOut_, void * paramsIn_) +{ + piPingParams * paramsOut = (piPingParams *)paramsOut_; + piPingParams * paramsIn = (piPingParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->ping = paramsIn->ping; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + + return PEERTrue; +} +static void piPingFree(void * params_) +{ + piPingParams * params = (piPingParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piPingCall(PEER peer, piCallbackData * data) +{ + piPingParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PING_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPingCallback)data->callback)(peer, params->nick, params->ping, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerPingCallback)data->callback)(peer, nick_W, params->ping, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddPingCallback +( + PEER peer, + const char * nick, + int ping +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->ping) + { + piPingParams params; + params.nick = (char *)nick; + params.ping = ping; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->ping, callbacks->param, PI_PING_CALLBACK, ¶ms, sizeof(piPingParams), -1); + } +} + +/* CrossPing. +************/ +typedef struct piCrossPingParams +{ + char * nick1; + char * nick2; + int crossPing; +} piCrossPingParams; +static PEERBool piCrossPingCopy(void * paramsOut_, void * paramsIn_) +{ + piCrossPingParams * paramsOut = (piCrossPingParams *)paramsOut_; + piCrossPingParams * paramsIn = (piCrossPingParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->crossPing = paramsIn->crossPing; + if(paramsIn->nick1) + { + paramsOut->nick1 = goastrdup(paramsIn->nick1); + if(!paramsOut->nick1) + return PEERFalse; + } + else + paramsOut->nick1 = NULL; + if(paramsIn->nick2) + { + paramsOut->nick2 = goastrdup(paramsIn->nick2); + if(!paramsOut->nick2) + { + gsifree(paramsOut->nick1); + return PEERFalse; + } + } + else + paramsOut->nick2 = NULL; + + return PEERTrue; +} +static void piCrossPingFree(void * params_) +{ + piCrossPingParams * params = (piCrossPingParams *)params_; + + assert(params); + + gsifree(params->nick1); + gsifree(params->nick2); +} +static void piCrossPingCall(PEER peer, piCallbackData * data) +{ + piCrossPingParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_CROSS_PING_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerCrossPingCallback)data->callback)(peer, params->nick1, params->nick2, params->crossPing, data->callbackParam); +#else + { + unsigned short* nick1_W = UTF8ToUCS2StringAlloc(params->nick1); + unsigned short* nick2_W = UTF8ToUCS2StringAlloc(params->nick2); + ((peerCrossPingCallback)data->callback)(peer, nick1_W, nick2_W, params->crossPing, data->callbackParam); + gsifree(nick1_W); + gsifree(nick2_W); + } +#endif +} +void piAddCrossPingCallback +( + PEER peer, + const char * nick1, + const char * nick2, + int crossPing +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->crossPing) + { + piCrossPingParams params; + params.nick1 = (char *)nick1; + params.nick2 = (char *)nick2; + params.crossPing = crossPing; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->crossPing, callbacks->param, PI_CROSS_PING_CALLBACK, ¶ms, sizeof(piCrossPingParams), -1); + } +} + +/* Change Nick. +**************/ +typedef struct piChangeNickParams +{ + char * oldNick; + char * newNick; +} piChangeNickParams; +static PEERBool piChangeNickCopy(void * paramsOut_, void * paramsIn_) +{ + piChangeNickParams * paramsOut = (piChangeNickParams *)paramsOut_; + piChangeNickParams * paramsIn = (piChangeNickParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + if(paramsIn->newNick) + { + paramsOut->newNick = goastrdup(paramsIn->newNick); + if(!paramsOut->newNick) + return PEERFalse; + } + else + paramsOut->newNick = NULL; + if(paramsIn->oldNick) + { + paramsOut->oldNick = goastrdup(paramsIn->oldNick); + if(!paramsOut->oldNick) + { + gsifree(paramsOut->newNick); + return PEERFalse; + } + } + else + paramsOut->oldNick = NULL; + + return PEERTrue; +} +static void piChangeNickFree(void * params_) +{ + piChangeNickParams * params = (piChangeNickParams *)params_; + + assert(params); + + gsifree(params->newNick); + gsifree(params->oldNick); +} +static void piChangeNickCall(PEER peer, piCallbackData * data) +{ + piChangeNickParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_CHANGE_NICK_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerChangeNickCallback)data->callback)(peer, data->success, params->oldNick, params->newNick, data->callbackParam); +#else + { + unsigned short* oldNick_W = UTF8ToUCS2StringAlloc(params->oldNick); + unsigned short* newNick_W = UTF8ToUCS2StringAlloc(params->newNick); + ((peerChangeNickCallback)data->callback)(peer, data->success, oldNick_W, newNick_W, data->callbackParam); + gsifree(oldNick_W); + gsifree(newNick_W); + } +#endif +} +void piAddChangeNickCallback +( + PEER peer, + PEERBool success, + const char * oldNick, + const char * newNick, + peerChangeNickCallback callback, + void * param, + int opID +) +{ + piChangeNickParams params; + params.newNick = (char *)newNick; + params.oldNick = (char *)oldNick; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_CHANGE_NICK_CALLBACK, ¶ms, sizeof(piChangeNickParams), opID); +} + +/* GlobalKeyChanged. +*******************/ +typedef struct piGlobalGlobalKeyChangedParams +{ + RoomType roomType; + char * nick; + char * key; + char * value; +} piGlobalKeyChangedParams; +static PEERBool piGlobalKeyChangedCopy(void * paramsOut_, void * paramsIn_) +{ + piGlobalKeyChangedParams * paramsOut = (piGlobalKeyChangedParams *)paramsOut_; + piGlobalKeyChangedParams * paramsIn = (piGlobalKeyChangedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->key) + { + paramsOut->key = goastrdup(paramsIn->key); + if(!paramsOut->key) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->key = NULL; + if(paramsIn->value) + { + paramsOut->value = goastrdup(paramsIn->value); + if(!paramsOut->value) + { + gsifree(paramsOut->nick); + gsifree(paramsOut->key); + return PEERFalse; + } + } + else + paramsOut->value = NULL; + + return PEERTrue; +} +static void piGlobalKeyChangedFree(void * params_) +{ + piGlobalKeyChangedParams * params = (piGlobalKeyChangedParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->key); + gsifree(params->value); +} +static void piGlobalKeyChangedCall(PEER peer, piCallbackData * data) +{ + piGlobalKeyChangedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GLOBAL_KEY_CHANGED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGlobalKeyChangedCallback)data->callback)(peer, params->nick, params->key, params->value, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* key_W = UTF8ToUCS2StringAlloc(params->key); + unsigned short* value_W = UTF8ToUCS2StringAlloc(params->value); + ((peerGlobalKeyChangedCallback)data->callback)(peer, nick_W, key_W, value_W, data->callbackParam); + gsifree(nick_W); + gsifree(key_W); + gsifree(value_W); + } +#endif +} +void piAddGlobalKeyChangedCallback +( + PEER peer, + const char * nick, + const char * key, + const char * value +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->globalKeyChanged) + { + piGlobalKeyChangedParams params; + params.nick = (char *)nick; + params.key = (char *)key; + params.value = (char *)value; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->globalKeyChanged, callbacks->param, PI_GLOBAL_KEY_CHANGED_CALLBACK, ¶ms, sizeof(piGlobalKeyChangedParams), -1); + } +} + +/* RoomKeyChanged. +*****************/ +typedef struct piRoomKeyChangedParams +{ + RoomType roomType; + char * nick; + char * key; + char * value; +} piRoomKeyChangedParams; +static PEERBool piRoomKeyChangedCopy(void * paramsOut_, void * paramsIn_) +{ + piRoomKeyChangedParams * paramsOut = (piRoomKeyChangedParams *)paramsOut_; + piRoomKeyChangedParams * paramsIn = (piRoomKeyChangedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + if(paramsIn->key) + { + paramsOut->key = goastrdup(paramsIn->key); + if(!paramsOut->key) + { + gsifree(paramsOut->nick); + return PEERFalse; + } + } + else + paramsOut->key = NULL; + if(paramsIn->value) + { + paramsOut->value = goastrdup(paramsIn->value); + if(!paramsOut->value) + { + gsifree(paramsOut->nick); + gsifree(paramsOut->key); + return PEERFalse; + } + } + else + paramsOut->value = NULL; + + return PEERTrue; +} +static void piRoomKeyChangedFree(void * params_) +{ + piRoomKeyChangedParams * params = (piRoomKeyChangedParams *)params_; + + assert(params); + + gsifree(params->nick); + gsifree(params->key); + gsifree(params->value); +} +static void piRoomKeyChangedCall(PEER peer, piCallbackData * data) +{ + piRoomKeyChangedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_ROOM_KEY_CHANGED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerRoomKeyChangedCallback)data->callback)(peer, params->roomType, params->nick, params->key, params->value, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short* key_W = UTF8ToUCS2StringAlloc(params->key); + unsigned short* value_W = UTF8ToUCS2StringAlloc(params->value); + ((peerRoomKeyChangedCallback)data->callback)(peer, params->roomType, nick_W, key_W, value_W, data->callbackParam); + gsifree(nick_W); + gsifree(key_W); + gsifree(value_W); + } +#endif +} +void piAddRoomKeyChangedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * key, + const char * value +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->roomKeyChanged) + { + piRoomKeyChangedParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.key = (char *)key; + params.value = (char *)value; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->roomKeyChanged, callbacks->param, PI_ROOM_KEY_CHANGED_CALLBACK, ¶ms, sizeof(piRoomKeyChangedParams), -1); + } +} + +/* GetGlobalKeys. +****************/ +typedef struct piGetGlobalKeysParams +{ + char * nick; + int num; + char ** keys; + char ** values; +} piGetGlobalKeysParams; +static PEERBool piGetGlobalKeysCopy(void * paramsOut_, void * paramsIn_) +{ + int i; + int num; + PEERBool success = PEERTrue; + piGetGlobalKeysParams * paramsOut = (piGetGlobalKeysParams *)paramsOut_; + piGetGlobalKeysParams * paramsIn = (piGetGlobalKeysParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + memset(paramsOut, 0, sizeof(piGetGlobalKeysParams)); + num = paramsOut->num = paramsIn->num; + + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + success = PEERFalse; + } + else + paramsOut->nick = NULL; + + if(success && num) + { + paramsOut->keys = (char **)gsimalloc(sizeof(char *) * num); + if(!paramsOut->keys) + success = PEERFalse; + else + memset(paramsOut->keys, 0, sizeof(char *) * num); + } + + if(success && num && paramsIn->values) + { + paramsOut->values = (char **)gsimalloc(sizeof(char *) * num); + if(!paramsOut->values) + success = PEERFalse; + else + memset(paramsOut->values, 0, sizeof(char *) * num); + } + + if(success && num && paramsIn->values) + { + for(i = 0 ; success && (i < num) ; i++) + { + paramsOut->keys[i] = goastrdup(paramsIn->keys[i]); + if(!paramsOut->keys[i]) + success = PEERFalse; + else + { + paramsOut->values[i] = goastrdup(paramsIn->values[i]); + if(!paramsOut->values[i]) + success = PEERFalse; + } + } + } + + if(!success) + { + gsifree(paramsOut->nick); + for(i = 0 ; i < num ; i++) + { + if(paramsOut->keys) + gsifree(paramsOut->keys[i]); + if(paramsOut->values) + gsifree(paramsOut->values[i]); + } + gsifree(paramsOut->keys); + gsifree(paramsOut->values); + } + + return success; +} +static void piGetGlobalKeysFree(void * params_) +{ + int i; + piGetGlobalKeysParams * params = (piGetGlobalKeysParams *)params_; + + assert(params); + + gsifree(params->nick); + for(i = 0 ; i < params->num ; i++) + { + gsifree(params->keys[i]); + if(params->values) + gsifree(params->values[i]); + } + gsifree(params->keys); + gsifree(params->values); +} +static void piGetGlobalKeysCall(PEER peer, piCallbackData * data) +{ + piGetGlobalKeysParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GET_GLOBAL_KEYS_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGetGlobalKeysCallback)data->callback)(peer, data->success, params->nick, params->num, (const char **)params->keys, (const char **)params->values, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short** keys_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)params->keys, params->num); + unsigned short** values_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)params->values, params->num); + int i; + ((peerGetGlobalKeysCallback)data->callback)(peer, data->success, nick_W, params->num, (const unsigned short**)keys_W, (const unsigned short**)values_W, data->callbackParam); + gsifree(nick_W); + for (i=0; i < params->num; i++) + { + gsifree(keys_W[i]); + if (values_W != NULL) // may be a NULL when getting keys for "*" + gsifree(values_W[i]); + } + gsifree(keys_W); + gsifree(values_W); + } +#endif +} +void piAddGetGlobalKeysCallback +( + PEER peer, + PEERBool success, + const char * nick, + int num, + const char ** keys, + const char ** values, + peerGetGlobalKeysCallback callback, + void * param, + int opID +) +{ + piGetGlobalKeysParams params; + params.nick = (char *)nick; + params.num = num; + params.keys = (char **)keys; + params.values = (char **)values; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_GET_GLOBAL_KEYS_CALLBACK, ¶ms, sizeof(piGetGlobalKeysParams), opID); +} + +/* GetRoomKeys. +****************/ +typedef struct piGetRoomKeysParams +{ + RoomType roomType; + char * nick; + int num; + char ** keys; + char ** values; +} piGetRoomKeysParams; +static PEERBool piGetRoomKeysCopy(void * paramsOut_, void * paramsIn_) +{ + int i; + int num; + PEERBool success = PEERTrue; + piGetRoomKeysParams * paramsOut = (piGetRoomKeysParams *)paramsOut_; + piGetRoomKeysParams * paramsIn = (piGetRoomKeysParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + memset(paramsOut, 0, sizeof(piGetRoomKeysParams)); + num = paramsOut->num = paramsIn->num; + + paramsOut->roomType = paramsIn->roomType; + + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + success = PEERFalse; + } + else + paramsOut->nick = NULL; + + if(success && num) + { + paramsOut->keys = (char **)gsimalloc(sizeof(char *) * num); + if(!paramsOut->keys) + success = PEERFalse; + else + memset(paramsOut->keys, 0, sizeof(char *) * num); + } + + if(success && num && paramsIn->values) + { + paramsOut->values = (char **)gsimalloc(sizeof(char *) * num); + if(!paramsOut->values) + success = PEERFalse; + else + memset(paramsOut->values, 0, sizeof(char *) * num); + } + + if(success && num && paramsIn->values) + { + for(i = 0 ; success && (i < num) ; i++) + { + paramsOut->keys[i] = goastrdup(paramsIn->keys[i]); + if(!paramsOut->keys[i]) + success = PEERFalse; + else if(paramsOut->values) + { + paramsOut->values[i] = goastrdup(paramsIn->values[i]); + if(!paramsOut->values[i]) + success = PEERFalse; + } + } + } + + if(!success) + { + gsifree(paramsOut->nick); + for(i = 0 ; i < num ; i++) + { + if(paramsOut->keys) + gsifree(paramsOut->keys[i]); + if(paramsOut->values) + gsifree(paramsOut->values[i]); + } + gsifree(paramsOut->keys); + gsifree(paramsOut->values); + } + + return success; +} +static void piGetRoomKeysFree(void * params_) +{ + int i; + piGetRoomKeysParams * params = (piGetRoomKeysParams *)params_; + + assert(params); + + gsifree(params->nick); + for(i = 0 ; i < params->num ; i++) + { + gsifree(params->keys[i]); + if(params->values) + gsifree(params->values[i]); + } + gsifree(params->keys); + gsifree(params->values); +} +static void piGetRoomKeysCall(PEER peer, piCallbackData * data) +{ + piGetRoomKeysParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_GET_ROOM_KEYS_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerGetRoomKeysCallback)data->callback)(peer, data->success, params->roomType, params->nick, params->num, params->keys, params->values, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + unsigned short** keys_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)params->keys, params->num); + unsigned short** values_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)params->values, params->num); + int i; + ((peerGetRoomKeysCallback)data->callback)(peer, data->success, params->roomType, nick_W, params->num, keys_W, values_W, data->callbackParam); + gsifree(nick_W); + for (i=0; i < params->num; i++) + { + gsifree(keys_W[i]); + if (values_W != NULL) // may be a NULL when getting keys for "*" + gsifree(values_W[i]); + } + gsifree(keys_W); + gsifree(values_W); + } +#endif +} +void piAddGetRoomKeysCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + const char * nick, + int num, + const char ** keys, + const char ** values, + peerGetRoomKeysCallback callback, + void * param, + int opID +) +{ + piGetRoomKeysParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.num = num; + params.keys = (char **)keys; + params.values = (char **)values; + + piAddCallback(peer, success, (PEERCBType)callback, param, PI_GET_ROOM_KEYS_CALLBACK, ¶ms, sizeof(piGetRoomKeysParams), opID); +} + +/* PlayerFlagsChanged. +*********************/ +typedef struct piPlayerFlagsChangedParams +{ + RoomType roomType; + char * nick; + int oldFlags; + int newFlags; +} piPlayerFlagsChangedParams; +static PEERBool piPlayerFlagsChangedCopy(void * paramsOut_, void * paramsIn_) +{ + piPlayerFlagsChangedParams * paramsOut = (piPlayerFlagsChangedParams *)paramsOut_; + piPlayerFlagsChangedParams * paramsIn = (piPlayerFlagsChangedParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->roomType = paramsIn->roomType; + paramsOut->newFlags = paramsIn->newFlags; + paramsOut->oldFlags = paramsIn->oldFlags; + if(paramsIn->nick) + { + paramsOut->nick = goastrdup(paramsIn->nick); + if(!paramsOut->nick) + return PEERFalse; + } + else + paramsOut->nick = NULL; + + return PEERTrue; +} +static void piPlayerFlagsChangedFree(void * params_) +{ + piPlayerFlagsChangedParams * params = (piPlayerFlagsChangedParams *)params_; + + assert(params); + + gsifree(params->nick); +} +static void piPlayerFlagsChangedCall(PEER peer, piCallbackData * data) +{ + piPlayerFlagsChangedParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_PLAYER_FLAGS_CHANGED_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerPlayerFlagsChangedCallback)data->callback)(peer, params->roomType, params->nick, params->oldFlags, params->newFlags, data->callbackParam); +#else + { + unsigned short* nick_W = UTF8ToUCS2StringAlloc(params->nick); + ((peerPlayerFlagsChangedCallback)data->callback)(peer, params->roomType, nick_W, params->oldFlags, params->newFlags, data->callbackParam); + gsifree(nick_W); + } +#endif +} +void piAddPlayerFlagsChangedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + int oldFlags, + int newFlags +) +{ + PEERCallbacks * callbacks; + + PEER_CONNECTION; + + callbacks = &connection->callbacks; + if(callbacks->playerFlagsChanged) + { + piPlayerFlagsChangedParams params; + params.roomType = roomType; + params.nick = (char *)nick; + params.oldFlags = oldFlags; + params.newFlags = newFlags; + + piAddCallback(peer, PEERTrue, (PEERCBType)callbacks->playerFlagsChanged, callbacks->param, PI_PLAYER_FLAGS_CHANGED_CALLBACK, ¶ms, sizeof(piPlayerFlagsChangedParams), -1); + } +} + +/* Authenticate CD Key. +**********************/ +typedef struct piAuthenticateCDKeyParams +{ + int result; + char * message; +} piAuthenticateCDKeyParams; +static PEERBool piAuthenticateCDKeyCopy(void * paramsOut_, void * paramsIn_) +{ + piAuthenticateCDKeyParams * paramsOut = (piAuthenticateCDKeyParams *)paramsOut_; + piAuthenticateCDKeyParams * paramsIn = (piAuthenticateCDKeyParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->result = paramsIn->result; + if(paramsIn->message) + { + paramsOut->message = goastrdup(paramsIn->message); + if(!paramsOut->message) + return PEERFalse; + } + else + paramsOut->message = NULL; + + return PEERTrue; +} +static void piAuthenticateCDKeyFree(void * params_) +{ + piAuthenticateCDKeyParams * params = (piAuthenticateCDKeyParams *)params_; + + assert(params); + + gsifree(params->message); +} +static void piAuthenticateCDKeyCall(PEER peer, piCallbackData * data) +{ + piAuthenticateCDKeyParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_AUTHENTICATE_CDKEY_CALLBACK); + + params = data->params; +#ifndef GSI_UNICODE + ((peerAuthenticateCDKeyCallback)data->callback)(peer, params->result, params->message, data->callbackParam); +#else + { + unsigned short* message_W = UTF8ToUCS2StringAlloc(params->message); + ((peerAuthenticateCDKeyCallback)data->callback)(peer, params->result, message_W, data->callbackParam); + gsifree(message_W); + } +#endif +} +void piAddAuthenticateCDKeyCallback +( + PEER peer, + int result, + const char * message, + peerAuthenticateCDKeyCallback callback, + void * param, + int opID +) +{ + piAuthenticateCDKeyParams params; + params.result = result; + params.message = (char *)message; + + piAddCallback(peer, PEERTrue, (PEERCBType)callback, param, PI_AUTHENTICATE_CDKEY_CALLBACK, ¶ms, sizeof(piAuthenticateCDKeyParams), opID); +} + +/* AutoMatch Status. +*******************/ +typedef struct piAutoMatchStatusParams +{ + PEERAutoMatchStatus status; +} piAutoMatchStatusParams; +static PEERBool piAutoMatchStatusCopy(void * paramsOut_, void * paramsIn_) +{ + piAutoMatchStatusParams * paramsOut = (piAutoMatchStatusParams *)paramsOut_; + piAutoMatchStatusParams * paramsIn = (piAutoMatchStatusParams *)paramsIn_; + + assert(paramsOut); + assert(paramsIn); + + paramsOut->status = paramsIn->status; + + return PEERTrue; +} +static void piAutoMatchStatusFree(void * params_) +{ + piAutoMatchStatusParams * params = (piAutoMatchStatusParams *)params_; + + assert(params); + GSI_UNUSED(params); +} +static void piAutoMatchStatusCall(PEER peer, piCallbackData * data) +{ + piAutoMatchStatusParams * params; + + assert(data); + assert(data->callback); + assert(data->params); + assert(data->type == PI_AUTO_MATCH_STATUS_CALLBACK); + + params = data->params; + ((peerAutoMatchStatusCallback)data->callback)(peer, params->status, data->callbackParam); +} +void piAddAutoMatchStatusCallback +( + PEER peer +) +{ + piAutoMatchStatusParams params; + piOperation * operation; + + PEER_CONNECTION; + + operation = connection->autoMatchOperation; + if(!operation || !operation->callback) + return; + + params.status = connection->autoMatchStatus; + + piAddCallback(peer, PEERTrue, operation->callback, operation->callbackParam, PI_AUTO_MATCH_STATUS_CALLBACK, ¶ms, sizeof(piAutoMatchStatusParams), operation->ID); +} + +/* AutoMatch Rate. +*****************/ +int piCallAutoMatchRateCallback +( + PEER peer, + SBServer server +) +{ + piOperation * operation; + + PEER_CONNECTION; + + operation = connection->autoMatchOperation; + if(!operation || !operation->callback2) + return 0; + + return ((peerAutoMatchRateCallback)connection->autoMatchOperation->callback2)(peer, server, operation->callbackParam); +} + +/************ +** GLOBALS ** +************/ +static const piCallbackFuncs callbackFuncs[] = +{ + { + PI_CONNECT_CALLBACK, + piConnectCopy, + piConnectFree, + piConnectCall + }, + { + PI_JOIN_ROOM_CALLBACK, + piJoinRoomCopy, + piJoinRoomFree, + piJoinRoomCall + }, + { + PI_LIST_GROUP_ROOMS_CALLBACK, + piListGroupRoomsCopy, + piListGroupRoomsFree, + piListGroupRoomsCall + }, + { + PI_LISTING_GAMES_CALLBACK, + piListingGamesCopy, + piListingGamesFree, + piListingGamesCall + }, + { + PI_NICK_ERROR_CALLBACK, + piNickErrorCopy, + piNickErrorFree, + piNickErrorCall + }, + { + PI_ENUM_PLAYERS_CALLBACK, + piEnumPlayersCopy, + piEnumPlayersFree, + piEnumPlayersCall + }, + { + PI_GET_PLAYER_INFO_CALLBACK, + piGetPlayerInfoCopy, + piGetPlayerInfoFree, + piGetPlayerInfoCall + }, + { + PI_GET_PLAYER_PROFILE_ID_CALLBACK, + piGetPlayerProfileIDCopy, + piGetPlayerProfileIDFree, + piGetPlayerProfileIDCall + }, + { + PI_GET_PLAYER_IP_CALLBACK, + piGetPlayerIPCopy, + piGetPlayerIPFree, + piGetPlayerIPCall + }, + { + PI_ROOM_MESSAGE_CALLBACK, + piRoomMessageCopy, + piRoomMessageFree, + piRoomMessageCall + }, + { + PI_ROOM_UTM_CALLBACK, + piRoomUTMCopy, + piRoomUTMFree, + piRoomUTMCall + }, + { + PI_ROOM_NAME_CHANGED_CALLBACK, + piRoomNameChangedCopy, + piRoomNameChangedFree, + piRoomNameChangedCall + }, + { + PI_ROOM_MODE_CHANGED_CALLBACK, + piRoomModeChangedCopy, + piRoomModeChangedFree, + piRoomModeChangedCall + }, + { + PI_PLAYER_MESSAGE_CALLBACK, + piPlayerMessageCopy, + piPlayerMessageFree, + piPlayerMessageCall + }, + { + PI_PLAYER_UTM_CALLBACK, + piPlayerUTMCopy, + piPlayerUTMFree, + piPlayerUTMCall + }, + { + PI_READY_CHANGED_CALLBACK, + piReadyChangedCopy, + piReadyChangedFree, + piReadyChangedCall + }, + { + PI_GAME_STARTED_CALLBACK, + piGameStartedCopy, + piGameStartedFree, + piGameStartedCall + }, + { + PI_PLAYER_JOINED_CALLBACK, + piPlayerJoinedCopy, + piPlayerJoinedFree, + piPlayerJoinedCall + }, + { + PI_PLAYER_LEFT_CALLBACK, + piPlayerLeftCopy, + piPlayerLeftFree, + piPlayerLeftCall + }, + { + PI_KICKED_CALLBACK, + piKickedCopy, + piKickedFree, + piKickedCall + }, + { + PI_NEW_PLAYER_LIST_CALLBACK, + piNewPlayerListCopy, + piNewPlayerListFree, + piNewPlayerListCall + }, + { + PI_PLAYER_CHANGED_NICK_CALLBACK, + piPlayerChangedNickCopy, + piPlayerChangedNickFree, + piPlayerChangedNickCall + }, + { + PI_PLAYER_INFO_CALLBACK, + piPlayerInfoCopy, + piPlayerInfoFree, + piPlayerInfoCall + }, + { + PI_DISCONNECTED_CALLBACK, + piDisconnectedCopy, + piDisconnectedFree, + piDisconnectedCall + }, + { + PI_PING_CALLBACK, + piPingCopy, + piPingFree, + piPingCall + }, + { + PI_CROSS_PING_CALLBACK, + piCrossPingCopy, + piCrossPingFree, + piCrossPingCall + }, + { + PI_CHANGE_NICK_CALLBACK, + piChangeNickCopy, + piChangeNickFree, + piChangeNickCall + }, + { + PI_GLOBAL_KEY_CHANGED_CALLBACK, + piGlobalKeyChangedCopy, + piGlobalKeyChangedFree, + piGlobalKeyChangedCall + }, + { + PI_ROOM_KEY_CHANGED_CALLBACK, + piRoomKeyChangedCopy, + piRoomKeyChangedFree, + piRoomKeyChangedCall + }, + { + PI_GET_GLOBAL_KEYS_CALLBACK, + piGetGlobalKeysCopy, + piGetGlobalKeysFree, + piGetGlobalKeysCall + }, + { + PI_GET_ROOM_KEYS_CALLBACK, + piGetRoomKeysCopy, + piGetRoomKeysFree, + piGetRoomKeysCall + }, + { + PI_PLAYER_FLAGS_CHANGED_CALLBACK, + piPlayerFlagsChangedCopy, + piPlayerFlagsChangedFree, + piPlayerFlagsChangedCall + }, + { + PI_AUTHENTICATE_CDKEY_CALLBACK, + piAuthenticateCDKeyCopy, + piAuthenticateCDKeyFree, + piAuthenticateCDKeyCall + }, + { + PI_AUTO_MATCH_STATUS_CALLBACK, + piAutoMatchStatusCopy, + piAutoMatchStatusFree, + piAutoMatchStatusCall + }, + { + PI_NUM_CALLBACK_TYPES, + NULL, + NULL, + NULL + } +}; + +/************** +** FUNCTIONS ** +**************/ +static void piCallbackListFree(void *elem1) +{ + piCallbackData * data = (piCallbackData *)elem1; + //ASSERT_DATA(data); + + // Call the gsifree func. + ////////////////////// + callbackFuncs[data->type].gsifree(data->params); + + // Cleanup the callback data. + ///////////////////////////// +#ifdef GSI_MANIC_DEBUG + // Set the data to a fill value so we catch the overwrite + memset(data->params, 0xea, sizeof(data->params)); +#endif + gsifree(data->params); + +} + +PEERBool piCallbacksInit +( + PEER peer +) +{ + PEER_CONNECTION; + +#ifdef _DEBUG +{ + // Consistency check. + ///////////////////// + int i; + for(i = 0 ; i <= PI_NUM_CALLBACK_TYPES ; i++) + assert(callbackFuncs[i].type == i); +} +#endif + + // No callbacks yet. + //////////////////// + connection->callbacksQueued = 0; + connection->callbacksCalled = 0; + connection->callbackDepth = 0; + + // Init the list. + ///////////////// + connection->callbackList = ArrayNew(sizeof(piCallbackData), 0, piCallbackListFree); + if(!connection->callbackList) + return PEERFalse; + + return PEERTrue; +} + +void piCallbacksCleanup +( + PEER peer +) +{ + PEER_CONNECTION; + + // gsifree the callback list. + ////////////////////////// + if(connection->callbackList) + ArrayFree(connection->callbackList); +} + +#ifdef GSI_MANIC_DEBUG +#include "stdio.h" +#endif +static void piCallCallback(PEER peer, piCallbackData * data, int index) +{ + PEER_CONNECTION; + + // In the call. + /////////////// + data->inCall = PEERTrue; + connection->callbackDepth++; + + // Call it. + /////////// + callbackFuncs[data->type].call(peer, data); + + // Out of the call. + /////////////////// + data->inCall = PEERFalse; + connection->callbackDepth--; + + // One more called. + /////////////////// + connection->callbacksCalled++; + + // gsifree it. + /////////// + ArrayDeleteAt(connection->callbackList, index); +} + +void piCallbacksThink +( + PEER peer, + int blockingID +) +{ + int index; + int len; + piCallbackData * data; + + PEER_CONNECTION; + + assert(blockingID >= -1); + + // Blocking call? + ///////////////// + if(blockingID != -1) + { + // How many? + //////////// + len = ArrayLength(connection->callbackList); + assert(len >= 0); + + // Check if this callback is finished. + ////////////////////////////////////// + for(index = 0 ; index < len ; index++) + { + // Get the nth element. + /////////////////////// + data = (piCallbackData *)ArrayNth(connection->callbackList, index); + assert(data); + + // Check the ID and specifically for disconnect. + //////////////////////////////////////////////// + if((data->ID == blockingID) || (data->type == PI_DISCONNECTED_CALLBACK)) + { + // Call it. + /////////// + piCallCallback(peer, data, index); + + break; + } + } + } + else + { + int numInCalls = 0; + while(ArrayLength(connection->callbackList) > numInCalls) + { + // Get the callback data. + ///////////////////////// + data = (piCallbackData *)ArrayNth(connection->callbackList, numInCalls); + assert(data); + + // Are we already in this call? (how philosophical) + /////////////////////////////////////////////////// + if(data->inCall) + { + numInCalls++; + } + else + { + // Call it. + /////////// + piCallCallback(peer, data, numInCalls); + } + } + } +} + +static int piAddCallback +( + PEER peer, + PEERBool success, + PEERCBType callback, + void * param, + piCallbackType type, + void * paramsIn, + size_t paramsSize, + int opID +) +{ + piCallbackData data; + void * paramsOut; + + PEER_CONNECTION; + + assert(callback); + //assert(type >= 0); + assert(type < PI_NUM_CALLBACK_TYPES); + assert(paramsIn); + assert(paramsSize > 0); + + // If no callback, nothing to do. + ///////////////////////////////// + if(!callback) + return -1; + + // Allocate the output struct. + ////////////////////////////// + paramsOut = gsimalloc(paramsSize); + if(!paramsOut) + return -1; + + // Zero it. + /////////// + memset(paramsOut, 0, paramsSize); + + // Copy the input to the output. + //////////////////////////////// + if(!callbackFuncs[type].copy(paramsOut, paramsIn)) + { + assert(0); + gsifree(paramsOut); + return -1; + } + + // Fill in the data. + //////////////////// + data.type = type; + data.success = success; + data.callback = callback; + data.callbackParam = param; + data.params = paramsOut; + data.ID = opID; + data.inCall = PEERFalse; + + // Add it to the list. + ////////////////////// + ArrayAppend(connection->callbackList, &data); + connection->callbacksQueued++; + + return data.ID; +} + +static int GS_STATIC_CALLBACK piIsCallbackFinishedCompareCallback +( + const void *elem1, + const void *elem2 +) +{ + piCallbackData * data1 = (piCallbackData *)elem1; + piCallbackData * data2 = (piCallbackData *)elem2; + assert(data1); + assert(data2); + + return (data1->ID - data2->ID); +} + +PEERBool piIsCallbackFinished +( + PEER peer, + int opID +) +{ + int index; + piCallbackData data; + + PEER_CONNECTION; + + // Search for it. + ///////////////// + data.ID = opID; + index = ArraySearch(connection->callbackList, &data, piIsCallbackFinishedCompareCallback, 0, 0); + + return (index == NOT_FOUND)?PEERTrue:PEERFalse; +} + +void piClearCallbacks +( + PEER peer, + piCallbackType type +) +{ + piCallbackData * data; + int len; + int i; + + PEER_CONNECTION; + + len = ArrayLength(connection->callbackList); + for(i = (len - 1) ; i >= 0 ; i--) + { + data = (piCallbackData *)ArrayNth(connection->callbackList, i); + if(data->type == type) + ArrayDeleteAt(connection->callbackList, i); + } +} + +void piClearListingGameServerCallbacks(PEER peer, SBServer server) +{ + piCallbackData * data; + piListingGamesParams * params; + int len; + int i; + + PEER_CONNECTION; + + len = ArrayLength(connection->callbackList); + for(i = (len - 1) ; i >= 0 ; i--) + { + data = (piCallbackData *)ArrayNth(connection->callbackList, i); + if(data->type == PI_LISTING_GAMES_CALLBACK) + { + params = (piListingGamesParams *)data->params; + if(params->server == server) + ArrayDeleteAt(connection->callbackList, i); + } + } +} diff --git a/xrGameSpy/gamespy/Peer/peerCallbacks.h b/xrGameSpy/gamespy/Peer/peerCallbacks.h new file mode 100644 index 00000000000..db8475d9704 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerCallbacks.h @@ -0,0 +1,401 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERCALLBACKS_H_ +#define _PEERCALLBACKS_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/********** +** TYPES ** +**********/ +typedef enum piCallbackType +{ + PI_CONNECT_CALLBACK, + PI_JOIN_ROOM_CALLBACK, + PI_LIST_GROUP_ROOMS_CALLBACK, + PI_LISTING_GAMES_CALLBACK, + PI_NICK_ERROR_CALLBACK, + PI_ENUM_PLAYERS_CALLBACK, + PI_GET_PLAYER_INFO_CALLBACK, + PI_GET_PLAYER_PROFILE_ID_CALLBACK, + PI_GET_PLAYER_IP_CALLBACK, + PI_ROOM_MESSAGE_CALLBACK, + PI_ROOM_UTM_CALLBACK, + PI_ROOM_NAME_CHANGED_CALLBACK, + PI_ROOM_MODE_CHANGED_CALLBACK, + PI_PLAYER_MESSAGE_CALLBACK, + PI_PLAYER_UTM_CALLBACK, + PI_READY_CHANGED_CALLBACK, + PI_GAME_STARTED_CALLBACK, + PI_PLAYER_JOINED_CALLBACK, + PI_PLAYER_LEFT_CALLBACK, + PI_KICKED_CALLBACK, + PI_NEW_PLAYER_LIST_CALLBACK, + PI_PLAYER_CHANGED_NICK_CALLBACK, + PI_PLAYER_INFO_CALLBACK, + PI_DISCONNECTED_CALLBACK, + PI_PING_CALLBACK, + PI_CROSS_PING_CALLBACK, + PI_CHANGE_NICK_CALLBACK, + PI_GLOBAL_KEY_CHANGED_CALLBACK, + PI_ROOM_KEY_CHANGED_CALLBACK, + PI_GET_GLOBAL_KEYS_CALLBACK, + PI_GET_ROOM_KEYS_CALLBACK, + PI_PLAYER_FLAGS_CHANGED_CALLBACK, + PI_AUTHENTICATE_CDKEY_CALLBACK, + PI_AUTO_MATCH_STATUS_CALLBACK, + PI_NUM_CALLBACK_TYPES +} piCallbackType; + +/************** +** FUNCTIONS ** +**************/ +PEERBool piCallbacksInit(PEER peer); +void piCallbacksCleanup(PEER peer); +void piCallbacksThink(PEER peer, int blockingID); +PEERBool piIsCallbackFinished(PEER peer, int opID); +void piClearCallbacks(PEER peer, piCallbackType type); +void piClearListingGameServerCallbacks(PEER peer, SBServer server); + +/************** +** CALLBACKS ** +**************/ + +void piAddConnectCallback +( + PEER peer, + PEERBool success, + int failureReason, + peerConnectCallback callback, + void * param, + int opID +); + +void piAddJoinRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + peerJoinRoomCallback callback, + void * param, + int opID +); + +void piAddListGroupRoomsCallback +( + PEER peer, + PEERBool success, + int groupID, + SBServer server, + const char * name, + int numWaiting, + int maxWaiting, + int numGames, + int numPlaying, + peerListGroupRoomsCallback callback, + void * param, + int opID +); + +void piAddListingGamesCallback +( + PEER peer, + PEERBool success, + SBServer server, + int msg +); + +void piAddEnumPlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const char * nick, + int flags, + peerEnumPlayersCallback callback, + void * param, + int opID +); + +void piAddGetPlayerInfoCallback +( + PEER peer, + PEERBool success, + const char * nick, + unsigned int IP, + int profileID, + peerGetPlayerInfoCallback callback, + void * param, + int opID +); + +void piAddGetPlayerProfileIDCallback +( + PEER peer, + PEERBool success, + const char * nick, + int profileID, + peerGetPlayerProfileIDCallback callback, + void * param, + int opID +); + +void piAddGetPlayerIPCallback +( + PEER peer, + PEERBool success, + const char * nick, + unsigned int IP, + peerGetPlayerIPCallback callback, + void * param, + int opID +); + +void piAddRoomMessageCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * message, + MessageType messageType +); + +void piAddRoomUTMCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * command, + const char * parameters, + PEERBool authenticated +); + +void piAddRoomNameChangedCallback +( + PEER peer, + RoomType roomType +); + +void piAddRoomModeChangedCallback +( + PEER peer, + RoomType roomType, + CHATChannelMode * mode +); + +void piAddPlayerMessageCallback +( + PEER peer, + const char * nick, + const char * message, + MessageType messageType +); + +void piAddPlayerUTMCallback +( + PEER peer, + const char * nick, + const char * command, + const char * parameters, + PEERBool authenticated +); + +void piAddReadyChangedCallback +( + PEER peer, + const char * nick, + PEERBool ready +); + +void piAddGameStartedCallback +( + PEER peer, + SBServer server, + const char * message +); + +void piAddPlayerJoinedCallback +( + PEER peer, + RoomType roomType, + const char * nick +); + +void piAddPlayerLeftCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * reason +); + +void piAddKickedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * reason +); + +void piAddNewPlayerListCallback +( + PEER peer, + RoomType roomType +); + +void piAddPlayerChangedNickCallback +( + PEER peer, + RoomType roomType, + const char * oldNick, + const char * newNick +); + +void piAddPlayerInfoCallback +( + PEER peer, + RoomType roomType, + const char * nick, + unsigned int IP, + int profileID +); + +void piAddDisconnectedCallback +( + PEER peer, + const char * reason +); + +void piAddPingCallback +( + PEER peer, + const char * nick, + int ping +); + +void piAddCrossPingCallback +( + PEER peer, + const char * nick1, + const char * nick2, + int crossPing +); + +void piAddNickErrorCallback +( + PEER peer, + int type, + const char * nick, + int numSuggestedNicks, + const char ** suggestedNicks, + void * param, + int opID +); + +void piAddChangeNickCallback +( + PEER peer, + PEERBool success, + const char * oldNick, + const char * newNick, + peerChangeNickCallback callback, + void * param, + int opID +); + +void piAddGlobalKeyChangedCallback +( + PEER peer, + const char * nick, + const char * key, + const char * value +); + +void piAddRoomKeyChangedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + const char * key, + const char * value +); + +void piAddGetGlobalKeysCallback +( + PEER peer, + PEERBool success, + const char * nick, + int num, + const char ** keys, + const char ** values, + peerGetGlobalKeysCallback callback, + void * param, + int opID +); + +void piAddGetRoomKeysCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + const char * nick, + int num, + const char ** keys, + const char ** values, + peerGetRoomKeysCallback callback, + void * param, + int opID +); + +void piAddPlayerFlagsChangedCallback +( + PEER peer, + RoomType roomType, + const char * nick, + int oldFlags, + int newFlags +); + +void piAddAuthenticateCDKeyCallback +( + PEER peer, + int result, + const char * message, + peerAuthenticateCDKeyCallback callback, + void * param, + int opID +); + +void piAddAutoMatchStatusCallback +( + PEER peer +); + +int piCallAutoMatchRateCallback +( + PEER peer, + SBServer server +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerGlobalCallbacks.c b/xrGameSpy/gamespy/Peer/peerGlobalCallbacks.c new file mode 100644 index 00000000000..781d8503d9f --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerGlobalCallbacks.c @@ -0,0 +1,1081 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include "peer.h" +#include "peerAscii.h" +#include "peerMain.h" +#include "peerGlobalCallbacks.h" +#include "peerRooms.h" +#include "peerPlayers.h" +#include "peerCallbacks.h" +#include "peerOperations.h" +#include "peerPing.h" +#include "peerMangle.h" +#include "peerKeys.h" +#include "peerAutoMatch.h" + +/************ +** DEFINES ** +************/ +#define PI_UTM_MATCH(utm) (strncmp(piUTMCommand, utm, strlen(utm) - 1) == 0) + +#define PI_UTM_COMMAND_LEN 8 +#define PI_UTM_PARAMATERS_LEN 512 + +/************ +** GLOBALS ** +************/ +static char piUTMCommand[PI_UTM_COMMAND_LEN]; +static char piUTMParameters[PI_UTM_PARAMATERS_LEN]; + +/************** +** FUNCTIONS ** +**************/ +// Prototype the ASCII versions that are needed even in unicode mode +void peerMessagePlayerA(PEER peer, const char * nick, const char * message, MessageType messageType); + + +/* Chat. +*******/ +static PEERBool piIsOldUTM +( + const char * message +) +{ + // Check for no message. + //////////////////////// + assert(message); + if(!message) + return PEERFalse; + + // Check for too short for prefix + 1 char. + /////////////////////////////////////////// + if(strlen(message) < 4) + return PEERFalse; + + // Check for no prefix. + /////////////////////// + if((message[0] != '@') || + (message[1] != '@') || + (message[2] != '@') || + (message[3] == ' ')) + { + return PEERFalse; + } + + return PEERTrue; +} + +// Returns PEERTrue if a UTM. +///////////////////////////// +static PEERBool piParseUTM +( + const char * message +) +{ + int len; + + // Check for no message. + //////////////////////// + assert(message); + if(!message) + return PEERFalse; + + // Find the end of the command. + /////////////////////////////// + len = (int)strcspn(message, "/ "); + if(len >= PI_UTM_COMMAND_LEN) + return PEERFalse; + memcpy(piUTMCommand, message, (unsigned int)len); + piUTMCommand[len] = '\0'; + + // Copy off the parameters. + /////////////////////////// + message += len; + if(message[0]) + { + message++; + if(strlen(message) >= PI_UTM_PARAMATERS_LEN) + return PEERFalse; + strcpy(piUTMParameters, message); + } + else + { + piUTMParameters[0] = '\0'; + } + + return PEERTrue; +} + +static void piProcessUTM +( + PEER peer, + piPlayer * player, + PEERBool inRoom, + RoomType roomType +) +{ + char * params = piUTMParameters; + + PEER_CONNECTION; + + assert(piUTMCommand[0]); + assert(player); + + if(PI_UTM_MATCH(PI_UTM_LAUNCH)) + { +#ifdef _DEBUG + assert(connection->inRoom[StagingRoom]); + if(inRoom) + assert(roomType == StagingRoom); + else + assert(player->inRoom[StagingRoom]); +#endif + if(!connection->inRoom[StagingRoom]) + return; + if(inRoom && (roomType != StagingRoom)) + return; + if(!inRoom && !player->inRoom[StagingRoom]) + return; + + // Ignore if we're hosting. + /////////////////////////// + if(connection->hosting) + return; + + // Only accept launch from ops. + /////////////////////////////// + if(!piIsPlayerOp(player)) + return; + + // We're playing. + ///////////////// + connection->playing = PEERTrue; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + + // Add the callback. + //////////////////// + piAddGameStartedCallback(peer, connection->hostServer, params); + + // If we're AutoMatching, we're now done. + ///////////////////////////////////////// + if(peerIsAutoMatching(peer)) + piSetAutoMatchStatus(peer, PEERComplete); + } + else if(PI_UTM_MATCH(PI_UTM_XPING)) + { + piPlayer * other; + int ping; + unsigned int IP; + +#ifdef _DEBUG +// if(inRoom) +// assert(connection->xpingRoom[roomType]); +#endif + if(inRoom && !connection->xpingRoom[roomType]) + return; + + // Check for no params. + /////////////////////// + if(!params[0]) + return; + + // Get the IP. + ////////////// + IP = piDemangleIP(params); + + // Get the ping. + //////////////// + params += 11; + ping = atoi(params); + + // Figure out who this ping is to. + ////////////////////////////////// + other = piFindPlayerByIP(peer, IP); + if(!other) + return; + if(strcasecmp(player->nick, other->nick) == 0) + return; + if(inRoom && !player->inRoom[roomType]) + return; + if(!inRoom) + { + int i; + PEERBool success = PEERFalse; + + // Check that the three of us are in a room with xping enabled. + /////////////////////////////////////////////////////////////// + for(i = 0 ; i < NumRooms ; i++) + { + if(connection->xpingRoom[i] && connection->inRoom[i] && player->inRoom[i] && other->inRoom[i]) + success = PEERTrue; + } + if(!success) + return; + } + + // Update. + ////////// + piUpdateXping(peer, player->nick, other->nick, ping); + + // Add a xping callback. + //////////////////////// + piAddCrossPingCallback(peer, player->nick, other->nick, ping); + } +} + +void piChatDisconnectedA +( + CHAT chat, + const char * reason, + PEER peer +) +{ + PEER_CONNECTION; + + // We're disconnected. + ////////////////////// + connection->disconnect = PEERTrue; + + // Add the disconnected callback. + ///////////////////////////////// + piAddDisconnectedCallback(peer, reason); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +void piChatDisconnectedW +( + CHAT chat, + const unsigned short * reason, + PEER peer +) +{ + char* reason_A = UCS2ToUTF8StringAlloc(reason); + piChatDisconnectedA(chat, reason_A, peer); + gsifree(reason_A); +} +#endif + +static void piHandleOldNFO +( + PEER peer, + piPlayer * player, + const char * message +) +{ + // Ignore old NFOs from new clients. + //////////////////////////////////// + if(strncmp(message + strlen(message) - 2, "X\\", 2) != 0) + { + const char * str; + + if(!player->inRoom[StagingRoom]) + return; + + str = strstr(message, "\\$flags$\\"); + if(str) + { + PEERBool ready = PEERFalse; + str += 9; + while(*str && (*str != '\\')) + { + if(*str++ == 'r') + { + ready = PEERTrue; + break; + } + } + + if(ready) + player->flags[StagingRoom] |= PEER_FLAG_READY; + else + player->flags[StagingRoom] &= ~PEER_FLAG_READY; + } + } + + GSI_UNUSED(peer); +} + +void piChatPrivateMessageA +( + CHAT chat, + const char * user, + const char * message, + int type, + PEER peer +) +{ + assert(message); + + if(!user || !user[0]) + return; + + // Check for old-style UTMs. + //////////////////////////// + if(piIsOldUTM(message)) + { + // Check for ready. + /////////////////// + if(strncasecmp(message, "@@@NFO", 6) == 0) + { + piPlayer * player; + + player = piGetPlayer(peer, user); + if(player) + piHandleOldNFO(peer, player, message); + } + + return; + } + + // Check if it's a UTM. + /////////////////////// + if((type == CHAT_UTM) || (type == CHAT_ATM)) + { + if(piParseUTM(message)) + { + piPlayer * player; + + // Get the player it's from. + //////////////////////////// + player = piGetPlayer(peer, user); + if(player) + { + // Process it. + ////////////// + piProcessUTM(peer, player, PEERFalse, (RoomType)0); + } + + // Pass it along. + ///////////////// + piAddPlayerUTMCallback(peer, user, piUTMCommand, piUTMParameters, (PEERBool)(type == CHAT_ATM)); + } + + return; + } + + // It's a regular message, deliver it. + ////////////////////////////////////// + piAddPlayerMessageCallback(peer, user, message, (MessageType)type); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +void piChatPrivateMessageW +( + CHAT chat, + const unsigned short * user, + const unsigned short * message, + int type, + PEER peer +) +{ + char* user_A = UCS2ToUTF8StringAlloc(user); + char* message_A = UCS2ToUTF8StringAlloc(message); + piChatPrivateMessageA(chat, user_A, message_A, type, peer); + gsifree(user_A); + gsifree(message_A); +} +#endif + +static void piChannelMessageA +( + CHAT chat, + const char * channel, + const char * user, + const char * message, + int type, + PEER peer +) +{ + piPlayer * player; + RoomType roomType; + + //PEER_CONNECTION; + + assert(message); + + // Check the room type. + /////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Get the player. + ////////////////// + player = piGetPlayer(peer, user); + + // Check for old-style UTMs. + //////////////////////////// + if(player && piIsOldUTM(message)) + { + // Only take stuff in staging rooms. + //////////////////////////////////// + if(roomType != StagingRoom) + return; + + // Check for a launch. + ////////////////////// + if(strncasecmp(message, "@@@GML", 6) == 0) + { + // Ignore old launches from new clients. + //////////////////////////////////////// + if(strncmp(message + strlen(message) - 4, "/OLD", 4) == 0) + return; + + // Convert this into its modern equivalent. + /////////////////////////////////////////// + type = CHAT_UTM; + message = "GML"; + } + // Check for ready. + /////////////////// + else if(strncasecmp(message, "@@@NFO", 6) == 0) + { + piHandleOldNFO(peer, player, message); + + return; + } + else + { + return; + } + } + + // Check if it's a UTM. + /////////////////////// + if((type == CHAT_UTM) || (type == CHAT_ATM)) + { + if(piParseUTM(message)) + { + // Process it. + ////////////// + if(player) + piProcessUTM(peer, player, PEERTrue, roomType); + + // Pass it along. + ///////////////// + piAddRoomUTMCallback(peer, roomType, user, piUTMCommand, piUTMParameters, (type == CHAT_ATM)?PEERTrue:PEERFalse); + } + + return; + } + + // Add the callback. + //////////////////// + piAddRoomMessageCallback(peer, roomType, user, message, (MessageType)type); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChannelMessageW +( + CHAT chat, + const unsigned short * channel, + const unsigned short * user, + const unsigned short * message, + int type, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* user_A = UCS2ToUTF8StringAlloc(user); + char* message_A = UCS2ToUTF8StringAlloc(message); + piChannelMessageA(chat, channel_A, user_A, message_A, type, peer); + gsifree(channel_A); + gsifree(user_A); + gsifree(message_A); +} +#endif + +static void piChannelKickedA +( + CHAT chat, + const char * channel, + const char * user, + const char * reason, + PEER peer +) +{ + RoomType roomType; + + //PEER_CONNECTION; + + // Figure out the room type. + //////////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Leave the room. + ////////////////// + piLeaveRoom(peer, roomType, NULL); + + // Add the callback. + //////////////////// + piAddKickedCallback(peer, roomType, user, reason); + + // If we were kicked from an AutoMatch room, start searching. + ///////////////////////////////////////////////////////////// + if((roomType == StagingRoom) && peerIsAutoMatching(peer)) + piSetAutoMatchStatus(peer, PEERSearching); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChannelKickedW +( + CHAT chat, + const unsigned short * channel, + const unsigned short * user, + const unsigned short * reason, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* user_A = UCS2ToUTF8StringAlloc(user); + char* reason_A = UCS2ToUTF8StringAlloc(reason); + piChannelKickedA(chat, channel_A, user_A, reason_A, peer); + gsifree(channel_A); + gsifree(user_A); + gsifree(reason_A); +} +#endif + +static void piChannelUserJoinedA +( + CHAT chat, + const char * channel, + const char * user, + int mode, + PEER peer +) +{ + RoomType roomType; + piPlayer * player; + + PEER_CONNECTION; + + // Figure out the room type. + //////////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Add this player to the room. + /////////////////////////////// + player = piPlayerJoinedRoom(peer, user, roomType, mode); + if(!player) + return; + + // Get IP and profile ID if we don't already have it. + ///////////////////////////////////////////////////// + if(!player->gotIPAndProfileID) + { + const char * info; + unsigned int IP; + int profileID; + + if(chatGetBasicUserInfoNoWaitA(connection->chat, user, &info, NULL) && piDemangleUser(info, &IP, &profileID)) + { + piSetPlayerIPAndProfileID(peer, user, IP, profileID); + } + } + + // Refresh this player's watch keys. + //////////////////////////////////// + piKeyCacheRefreshPlayer(peer, roomType, user); + + // Add the callback. + //////////////////// + piAddPlayerJoinedCallback(peer, roomType, user); + +#if 1 + // If this is the staging room, send our ready state. + ///////////////////////////////////////////////////// + if((roomType == StagingRoom) && connection->ready) + peerMessagePlayerA(peer, user, "@@@NFO \\$flags$\\rX\\", NormalMessage); +#endif + + // Check if this is an AutoMatch room. + ////////////////////////////////////// + if((roomType == StagingRoom) && peerIsAutoMatching(peer)) + { + // If we are Waiting, we're now Staging. + //////////////////////////////////////// + if(connection->autoMatchStatus == PEERWaiting) + piSetAutoMatchStatus(peer, PEERStaging); + + // If we've got maxplayers, we're now Ready. + //////////////////////////////////////////// + if((connection->autoMatchStatus == PEERStaging) && (connection->numPlayers[StagingRoom] >= connection->maxPlayers)) + piSetAutoMatchStatus(peer, PEERReady); + } + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChannelUserJoinedW +( + CHAT chat, + const unsigned short * channel, + const unsigned short * user, + int mode, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* user_A = UCS2ToUTF8StringAlloc(user); + piChannelUserJoinedA(chat, channel_A, user_A, mode, peer); + gsifree(channel_A); + gsifree(user_A); +} +#endif + +static void piChannelUserPartedA +( + CHAT chat, + const char * channel, + const char * user, + int why, + const char * reason, + const char * kicker, + PEER peer +) +{ + RoomType roomType; + PEERAutoMatchStatus status = PEERFailed; + PEERBool newStatus = PEERFalse; + PEERBool autoMatchRoom; + + PEER_CONNECTION; + + // Figure out the room type. + //////////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Check if this is an AutoMatch room. + ////////////////////////////////////// + autoMatchRoom = ((roomType == StagingRoom) && peerIsAutoMatching(peer))?PEERTrue:PEERFalse; + if(autoMatchRoom) + { + piPlayer * player; + + // Get the players. + /////////////////// + player = piGetPlayer(peer, user); + + // Check if he was the last op. + /////////////////////////////// + if(!connection->hosting && piIsPlayerHost(player)) + { + status = PEERSearching; + newStatus = PEERTrue; + } + // Check for host and everyone left. + //////////////////////////////////// + else if(connection->hosting && connection->numPlayers[StagingRoom] == 2) + { + status = PEERWaiting; + newStatus = PEERTrue; + } + // Check for no longer at maxplayers. + ///////////////////////////////////// + else if(connection->numPlayers[StagingRoom] == connection->maxPlayers) + { + status = PEERStaging; + newStatus = PEERTrue; + } + } + + // Remove this player from the room. + //////////////////////////////////// + piPlayerLeftRoom(peer, user, roomType); + + // Figure out the reason. + ///////////////////////// + if((why == CHAT_KICKED) || (why == CHAT_KILLED)) + reason = "Kicked"; + else if(!reason) + reason = ""; + + // Add the callback. + //////////////////// + piAddPlayerLeftCallback(peer, roomType, user, reason); + + // Set status if needed. + //////////////////////// + if(newStatus) + piSetAutoMatchStatus(peer, status); + + GSI_UNUSED(chat); + GSI_UNUSED(kicker); +} +#ifdef GSI_UNICODE +static void piChannelUserPartedW +( + CHAT chat, + const unsigned short * channel, + const unsigned short * user, + int why, + const unsigned short * reason, + const unsigned short * kicker, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* user_A = UCS2ToUTF8StringAlloc(user); + char* reason_A = UCS2ToUTF8StringAlloc(reason); + char* kicker_A = UCS2ToUTF8StringAlloc(kicker); + piChannelUserPartedA(chat, channel_A, user_A, why, reason_A, kicker_A, peer); + gsifree(channel_A); + gsifree(user_A); + gsifree(reason_A); + gsifree(kicker_A); +} +#endif + +static void piChannelUserChangedNickA +( + CHAT chat, + const char * channel, + const char * oldNick, + const char * newNick, + PEER peer +) +{ + RoomType roomType; + + // Figure out the room type. + //////////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Change the nick locally. + /////////////////////////// + piPlayerChangedNick(peer, oldNick, newNick); + + // Add the callback. + //////////////////// + piAddPlayerChangedNickCallback(peer, roomType, oldNick, newNick); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChannelUserChangedNickW +( + CHAT chat, + const unsigned short * channel, + const unsigned short * oldNick, + const unsigned short * newNick, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* oldNick_A = UCS2ToUTF8StringAlloc(oldNick); + char* newNick_A = UCS2ToUTF8StringAlloc(newNick); + piChannelUserChangedNickA(chat, channel_A, oldNick_A, newNick_A, peer); + gsifree(channel_A); + gsifree(oldNick_A); + gsifree(newNick_A); +} +#endif + +static void piChannelTopicChangedA +( + CHAT chat, + const char * channel, + const char * topic, + PEER peer +) +{ + RoomType roomType; + + PEER_CONNECTION; + + // Figure out the room type. + //////////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Don't allow blank names. + /////////////////////////// + if(!topic[0]) + return; + + // Is it the same as the old name? + ////////////////////////////////// + //if(strcmp(NAME, topic) == 0) + // return; + + // Copy the new name. + ///////////////////// + strzcpy(NAME, topic, PI_NAME_MAX_LEN); + + // Add a callback. + ////////////////// + if(IN_ROOM) + piAddRoomNameChangedCallback(peer, roomType); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChannelTopicChangedW +( + CHAT chat, + const unsigned short * channel, + const unsigned short * topic, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* topic_A = UCS2ToUTF8StringAlloc(topic); + piChannelTopicChangedA(chat, channel_A, topic_A, peer); + gsifree(channel_A); + gsifree(topic_A); +} +#endif + +static void piChannelNewUserListA +( + CHAT chat, + const char * channel, + int num, + const char ** users, + int * modes, + PEER peer +) +{ + int i; + RoomType roomType; + + //PEER_CONNECTION; + + // Figure out the room type. + //////////////////////////// + if(!piRoomToType(peer, channel, &roomType)) + return; + + // Clear all the players out of this room. + ////////////////////////////////////////// + piClearRoomPlayers(peer, roomType); + + // Add all the new ones. + //////////////////////// + for(i = 0 ; i < num ; i++) + piPlayerJoinedRoom(peer, users[i], roomType, modes[i]); + + // Refresh keys. + //////////////// + piKeyCacheRefreshRoom(peer, roomType); + + // Call the callback. + ///////////////////// + piAddNewPlayerListCallback(peer, roomType); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChannelNewUserListW +( + CHAT chat, + const unsigned short * channel, + int num, + const unsigned short ** users, + int * modes, + PEER peer +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char** users_A = UCS2ToUTF8StringArrayAlloc(users, num); + int i; + piChannelNewUserListA(chat, channel_A, num, (const char**)users_A, modes, peer); + gsifree(channel_A); + for (i=0; iparam = peer; +#ifndef GSI_UNICODE // NOT GSI_PEER_UNICODE + channelCallbacks->channelMessage = piChannelMessageA; + channelCallbacks->kicked = piChannelKickedA; + channelCallbacks->userJoined = piChannelUserJoinedA; + channelCallbacks->userParted = piChannelUserPartedA; + channelCallbacks->userChangedNick = piChannelUserChangedNickA; + channelCallbacks->topicChanged = piChannelTopicChangedA; + channelCallbacks->newUserList = piChannelNewUserListA; + channelCallbacks->broadcastKeyChanged = piBroadcastKeyChangedA; + channelCallbacks->userModeChanged = piUserModeChangedA; + channelCallbacks->channelModeChanged = piChannelModeChangedA; +#else + channelCallbacks->channelMessage = piChannelMessageW; + channelCallbacks->kicked = piChannelKickedW; + channelCallbacks->userJoined = piChannelUserJoinedW; + channelCallbacks->userParted = piChannelUserPartedW; + channelCallbacks->userChangedNick = piChannelUserChangedNickW; + channelCallbacks->topicChanged = piChannelTopicChangedW; + channelCallbacks->newUserList = piChannelNewUserListW; + channelCallbacks->broadcastKeyChanged = piBroadcastKeyChangedW; + channelCallbacks->userModeChanged = piUserModeChangedW; + channelCallbacks->channelModeChanged = piChannelModeChangedW; +#endif +} + diff --git a/xrGameSpy/gamespy/Peer/peerGlobalCallbacks.h b/xrGameSpy/gamespy/Peer/peerGlobalCallbacks.h new file mode 100644 index 00000000000..290278c2469 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerGlobalCallbacks.h @@ -0,0 +1,56 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERGLOBALCALLBACKS_H_ +#define _PEERGLOBALCALLBACKS_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************ +** DEFINES ** +************/ +#define PI_UTM_LAUNCH "GML" +#define PI_UTM_XPING "PNG" + +/************** +** FUNCTIONS ** +**************/ + +/* Chat. +*******/ +#ifndef GSI_UNICODE +#define piChatDisconnected piChatDisconnectedA +#define piChatPrivateMessage piChatPrivateMessageA +#else +#define piChatDisconnected piChatDisconnectedW +#define piChatPrivateMessage piChatPrivateMessageW +#endif + +// Include both forms here so CodeWarrior will have it's happy prototypes +void piChatDisconnectedA(CHAT chat, const char * reason, PEER peer); +void piChatDisconnectedW(CHAT chat, const unsigned short * reason, PEER peer); + +void piChatPrivateMessageA(CHAT chat, const char * user, const char * message, int type, PEER peer); +void piChatPrivateMessageW(CHAT chat, const unsigned short * user, const unsigned short * message, int type, PEER peer); + +void piSetChannelCallbacks(PEER peer, chatChannelCallbacks * channelCallbacks); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerHost.c b/xrGameSpy/gamespy/Peer/peerHost.c new file mode 100644 index 00000000000..f21c2c27b8d --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerHost.c @@ -0,0 +1,79 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include "peerQR.h" +#include "peerRooms.h" + +/************** +** FUNCTIONS ** +**************/ +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped +PEERBool piStartHosting (PEER peer, SOCKET socket, unsigned short port); // peerOperations.c +void piStopHosting(PEER peer, PEERBool stopReporting); // peerOperations.c +#endif + +PEERBool piStartHosting +( + PEER peer, + SOCKET socket, + unsigned short port +) +{ + PEER_CONNECTION; + + // Check that we're not hosting. + //////////////////////////////// + assert(!connection->hosting); + if(connection->hosting) + return PEERFalse; + + // Now we're hosting. + ///////////////////// + connection->hosting = PEERTrue; + + // Start reporting. + /////////////////// + if(!piStartReporting(peer, socket, port)) + return PEERFalse; + + return PEERTrue; +} + +void piStopHosting +( + PEER peer, + PEERBool stopReporting +) +{ + PEER_CONNECTION; + + // Stop reporting. + ////////////////// + if(stopReporting) + piStopReporting(peer); + + // Check that we're hosting. + //////////////////////////// + if(!connection->hosting) + return; + + // Reset states. + //////////////// + connection->hosting = PEERFalse; + connection->playing = PEERFalse; + connection->ready = PEERFalse; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); +} diff --git a/xrGameSpy/gamespy/Peer/peerHost.h b/xrGameSpy/gamespy/Peer/peerHost.h new file mode 100644 index 00000000000..4fe94df328d --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerHost.h @@ -0,0 +1,34 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERHOST_H_ +#define _PEERHOST_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/************** +** FUNCTIONS ** +**************/ +PEERBool piStartHosting(PEER peer, SOCKET socket, unsigned short port); +void piStopHosting(PEER peer, PEERBool stopReporting); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerKeys.c b/xrGameSpy/gamespy/Peer/peerKeys.c new file mode 100644 index 00000000000..d96ff7cee62 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerKeys.c @@ -0,0 +1,999 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include "peerKeys.h" +#include "peerCallbacks.h" +#include "peerRooms.h" +#include "peerGlobalCallbacks.h" +#include "peerMangle.h" + +/************ +** DEFINES ** +************/ +#define PI_WATCH_KEYS_NUM_BUCKETS 16 +#define PI_WATCH_CACHE_NUM_BUCKETS 128 + +/********** +** TYPES ** +**********/ +// Stored in the *WatckKey tables. +////////////////////////////////// +typedef struct piWatchKey +{ + char * key; +} piWatchKey; + +// Stored in the *WatchCache tables. +//////////////////////////////////// +typedef struct piCacheKey +{ + char * nick; + char * key; + char * value; +#ifdef GSI_UNICODE + unsigned short * value_W; +#endif +} piCacheKey; + +typedef struct piClearWatchKeyCacheData +{ + const char * key; + HashTable watchCache; +} piClearWatchKeyCacheData; + +typedef struct piRemoveExistingKeysData +{ + int num; + const char ** keys; + HashTable watchKeys; +} piRemoveExistingKeysData; + +typedef struct piPlayerChangedNickMapData +{ + const char * oldNick; + const char * newNick; +} piPlayerChangedNickMapData; + +typedef struct piSetupKeysMapData +{ + int next; + char ** keys; +} piSetupKeysMapData; + +typedef struct piCleanseRoomCacheMapData +{ + PEER peer; + RoomType roomType; +} piCleanseRoomCacheMapData; + +/************** +** FUNCTIONS ** +**************/ +#ifndef GSI_UNICODE // NOT GSI_UNICODE, these have to coincide with the chatsdk build +#define piGetRoomKeysCallback piGetRoomKeysCallbackA +#define piGetGlobalKeysCallback piGetGlobalKeysCallbackA +#else +#define piGetRoomKeysCallback piGetRoomKeysCallbackW +#define piGetGlobalKeysCallback piGetGlobalKeysCallbackW +#endif + + +static int WatchKeysHash +( + const void * elem, + int numBuckets +) +{ + piWatchKey * key = (piWatchKey *)elem; + int c; + const char * str; + unsigned int hash; + + assert(key->key && key->key[0]); + + // Get the hash. + //////////////// + str = key->key; + hash = 0; + while((c = *str++) != '\0') + hash += (unsigned int)tolower(c); + hash %= (unsigned int)numBuckets; + + return (int)hash; +} + +static int GS_STATIC_CALLBACK WatchKeysCompare +( + const void * elem1, + const void * elem2 +) +{ + piWatchKey * key1 = (piWatchKey *)elem1; + piWatchKey * key2 = (piWatchKey *)elem2; + + assert(key1->key && key1->key[0] && key2->key && key2->key[0]); + + return strcasecmp(key1->key, key2->key); +} + +static void WatchKeysFree +( + void * elem +) +{ + piWatchKey * key = (piWatchKey *)elem; + + gsifree(key->key); +} + +static int WatchCacheHash +( + const void * elem, + int numBuckets +) +{ + piCacheKey * key = (piCacheKey *)elem; + int c; + const char * str; + unsigned int hash; + + assert(key); + assert(key->nick[0]); + + // Get the hash. + //////////////// + str = key->key; + hash = 0; + while((c = *str++) != '\0') + hash += (unsigned int)tolower(c); + hash %= (unsigned int)numBuckets; + + return (int)hash; +} + +static int GS_STATIC_CALLBACK WatchCacheCompare +( + const void * elem1, + const void * elem2 +) +{ + int rcode; + + piCacheKey * key1 = (piCacheKey *)elem1; + piCacheKey * key2 = (piCacheKey *)elem2; + + rcode = strcasecmp(key1->nick, key2->nick); + if(rcode) + return rcode; + + return strcasecmp(key1->key, key2->key); +} + +static void WatchCacheFree +( + void * elem +) +{ + piCacheKey * key = (piCacheKey *)elem; + + gsifree(key->nick); + gsifree(key->key); + gsifree(key->value); +#ifdef GSI_UNICODE + gsifree(key->value_W); +#endif +} + +PEERBool piKeysInit +( + PEER peer +) +{ + int roomType; + PEER_CONNECTION; + + memset(connection->globalWatchKeys, 0, sizeof(HashTable) * NumRooms); + memset(connection->roomWatchKeys, 0, sizeof(HashTable) * NumRooms); + memset(connection->roomWatchCache, 0, sizeof(HashTable) * NumRooms); + + // Create all the tables. + ///////////////////////// + connection->globalWatchCache = TableNew(sizeof(piCacheKey), PI_WATCH_CACHE_NUM_BUCKETS, + WatchCacheHash, WatchCacheCompare, WatchCacheFree); + if(!connection->globalWatchCache) + return PEERFalse; + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + connection->globalWatchKeys[roomType] = TableNew(sizeof(piWatchKey), PI_WATCH_KEYS_NUM_BUCKETS, + WatchKeysHash, WatchKeysCompare, WatchKeysFree); + connection->roomWatchKeys[roomType] = TableNew(sizeof(piWatchKey), PI_WATCH_KEYS_NUM_BUCKETS, + WatchKeysHash, WatchKeysCompare, WatchKeysFree); + connection->roomWatchCache[roomType] = TableNew(sizeof(piCacheKey), PI_WATCH_CACHE_NUM_BUCKETS, + WatchCacheHash, WatchCacheCompare, WatchCacheFree); + + if(!connection->globalWatchKeys[roomType] || !connection->roomWatchKeys[roomType] || + !connection->roomWatchCache[roomType]) + { + return PEERFalse; + } + } + + return PEERTrue; +} + +void piKeysCleanup +( + PEER peer +) +{ + int roomType; + + PEER_CONNECTION; + + if(connection->globalWatchCache) + TableFree(connection->globalWatchCache); + + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + if(connection->globalWatchKeys[roomType]) + TableFree(connection->globalWatchKeys[roomType]); + if(connection->roomWatchKeys[roomType]) + TableFree(connection->roomWatchKeys[roomType]); + if(connection->roomWatchCache[roomType]) + TableFree(connection->roomWatchCache[roomType]); + } +} + +static const char * piGetWatchKeyA +( + const char * nick, + const char * key, + HashTable watchCache +) +{ + piCacheKey keyTemp; + piCacheKey * cacheKey; + + keyTemp.nick = (char *)nick; + keyTemp.key = (char *)key; + cacheKey = (piCacheKey *)TableLookup(watchCache, &keyTemp); + + if(!cacheKey) + return NULL; + + if(cacheKey->value) + return cacheKey->value; + return ""; +} +static const unsigned short * piGetWatchKeyW +( + const unsigned short * nick, + const unsigned short * key, + HashTable watchCache +) +{ +#ifndef GSI_UNICODE + GSI_UNUSED(nick); + GSI_UNUSED(key); + GSI_UNUSED(watchCache); + return NULL; // can't use this function unless in GSI_UNICODE mode +#else + piCacheKey keyTemp; + piCacheKey * cacheKey; + + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char* key_A = UCS2ToUTF8StringAlloc(key); + + keyTemp.nick = (char *)nick_A; + keyTemp.key = (char *)key_A; + cacheKey = (piCacheKey *)TableLookup(watchCache, &keyTemp); + + gsifree(nick_A); + gsifree(key_A); + + if (!cacheKey) + return NULL; + + if(cacheKey->value_W) + return cacheKey->value_W; + return L""; +#endif +} + +const char * piGetGlobalWatchKeyA +( + PEER peer, + const char * nick, + const char * key +) +{ + PEER_CONNECTION; + + return piGetWatchKeyA(nick, key, connection->globalWatchCache); +} +const unsigned short * piGetGlobalWatchKeyW +( + PEER peer, + const unsigned short * nick, + const unsigned short * key +) +{ + PEER_CONNECTION; + + return piGetWatchKeyW(nick, key, connection->globalWatchCache); +} + +const char * piGetRoomWatchKeyA +( + PEER peer, + RoomType roomType, + const char * nick, + const char * key +) +{ + PEER_CONNECTION; + + return piGetWatchKeyA(nick, key, connection->roomWatchCache[roomType]); +} +const unsigned short * piGetRoomWatchKeyW +( + PEER peer, + RoomType roomType, + const unsigned short * nick, + const unsigned short * key +) +{ + PEER_CONNECTION; + + return piGetWatchKeyW(nick, key, connection->roomWatchCache[roomType]); +} + +static void piCleanseGlobalCacheMap +( + void * elem, + void * clientData +) +{ + piPlayer * player; + int roomType; + piCacheKey * cacheKey = (piCacheKey *)elem; + PEER peer = (PEER)clientData; + piConnection * connection = (piConnection *)peer; + piWatchKey watchKeyTemp; + + watchKeyTemp.key = cacheKey->key; + + player = piGetPlayer(peer, cacheKey->nick); + if(player) + { + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + if(player->inRoom[roomType]) + { + if(TableLookup(connection->globalWatchKeys[roomType], &watchKeyTemp)) + return; + } + } + } + + TableRemove(connection->globalWatchCache, cacheKey); +} + +static void piCleanseRoomCacheMap +( + void * elem, + void * clientData +) +{ + piPlayer * player; + piCacheKey * cacheKey = (piCacheKey *)elem; + piCleanseRoomCacheMapData * data = (piCleanseRoomCacheMapData *)clientData; + piConnection * connection = (piConnection *)data->peer; + piWatchKey watchKeyTemp; + + watchKeyTemp.key = cacheKey->key; + + player = piGetPlayer(data->peer, cacheKey->nick); + if(player && player->inRoom[data->roomType]) + { + if(TableLookup(connection->roomWatchKeys[data->roomType], &watchKeyTemp)) + return; + } + + TableRemove(connection->globalWatchCache, cacheKey); +} + +void piKeyCacheCleanse +( + PEER peer +) +{ + int roomType; + piCleanseRoomCacheMapData data; + + PEER_CONNECTION; + + TableMapSafe(connection->globalWatchCache, piCleanseGlobalCacheMap, peer); + + data.peer = peer; + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + if(IN_ROOM || ENTERING_ROOM) + { + data.roomType = (RoomType)roomType; + TableMapSafe(connection->roomWatchCache[roomType], piCleanseRoomCacheMap, &data); + } + else + { + TableClear(connection->roomWatchCache[roomType]); + } + } +} + +static void piGetGlobalKeysCallbackA +( + CHAT chat, + CHATBool success, + const char * user, + int num, + const char ** keys, + const char ** values, + void * param +) +{ + PEER peer = (PEER)param; + + if(success && user) + { + int i; + + for(i = 0 ; i < num ; i++) + piGlobalKeyChanged(peer, user, keys[i], values[i]); + } + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piGetGlobalKeysCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * user, + int num, + const unsigned short ** keys, + const unsigned short ** values, + void * param +) +{ + char* user_A = UCS2ToUTF8StringAlloc(user); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = UCS2ToUTF8StringArrayAlloc(values, num); + int i; + piGetGlobalKeysCallbackA(chat, success, user_A, num, (const char**)keys_A, (const char**)values_A, param); + gsifree(user_A); + for (i=0; i is NULL, then this has been called by the + // GETCKEY list-end handler (ciRplEndGetCKeyHandler), + // and the PlayerInfo callback should be called one final + // time with NULL as the user. + // + // Alter the username and proceed so that all of the + // subsequent handlers and callbacks have a real name to + // work with. Note "(END)" is illegal as an IRC nickname + // (09mar01/bgw). + // + int i; + RoomType roomType; + static const char * szEndName = "(END)"; + + if(!piRoomToType(peer, channel, &roomType)) + return; + + for(i = 0 ; i < num ; i++) + piRoomKeyChanged(peer, roomType, szEndName, keys[i], NULL); + return; + } + + if(success /*&& user*/) + { + int i; + RoomType roomType; + + if(!piRoomToType(peer, channel, &roomType)) + return; + + for(i = 0 ; i < num ; i++) + piRoomKeyChanged(peer, roomType, user, keys[i], values[i]); + } + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piGetRoomKeysCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * channel, + const unsigned short * user, + int num, + const unsigned short ** keys, + const unsigned short ** values, + void * param +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* user_A = UCS2ToUTF8StringAlloc(user); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = UCS2ToUTF8StringArrayAlloc(values, num); + int i; + piGetRoomKeysCallbackA(chat, success, channel_A, user_A, num, (const char**)keys_A, (const char**)values_A, param); + gsifree(channel_A); + gsifree(user_A); + for(i=0; inum ; i++) + if(strcasecmp(key->key, data->keys[i]) == 0) + return; + + TableRemove(data->watchKeys, key); +} + +void piSetGlobalWatchKeys +( + PEER peer, + RoomType roomType, + int num, + const char ** keys, + PEERBool addKeys +) +{ + piWatchKey watchKey; + int i; + + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + assert(num >= 0); + + // If no keys. + ////////////// + if(num == 0) + { + // Nothing to add. + ////////////////// + if(addKeys) + return; + + // Clear the list and cache. + //////////////////////////// + TableClear(connection->globalWatchKeys[roomType]); + piKeyCacheCleanse(peer); + + return; + } + + assert(keys); + + if(!addKeys) + { + piRemoveExistingKeysData data; + data.num = num; + data.keys = keys; + data.watchKeys = connection->globalWatchKeys[roomType]; + TableMapSafe(connection->globalWatchKeys[roomType], piRemoveExistingKeysMap, &data); + } + + for(i = 0 ; i < num ; i++) + { + watchKey.key = goastrdup(keys[i]); + TableEnter(connection->globalWatchKeys[roomType], &watchKey); + } + + // Update them all. + /////////////////// + if(ENTERING_ROOM || IN_ROOM) + chatGetGlobalKeysA(connection->chat, ROOM, num, keys, piGetGlobalKeysCallback, peer, CHATFalse); +} + +void piSetRoomWatchKeys +( + PEER peer, + RoomType roomType, + int num, + const char ** keys, + PEERBool addKeys +) +{ + piWatchKey watchKey; + int i; + + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + assert(num >= 0); + + // If no keys. + ////////////// + if(num == 0) + { + // Nothing to add. + ////////////////// + if(addKeys) + return; + + // Clear the list and cache. + //////////////////////////// + TableClear(connection->roomWatchKeys[roomType]); + TableClear(connection->roomWatchCache[roomType]); + + return; + } + + assert(keys); + + if(!addKeys) + { + piRemoveExistingKeysData data; + data.num = num; + data.keys = keys; + data.watchKeys = connection->roomWatchKeys[roomType]; + TableMapSafe(connection->roomWatchKeys[roomType], piRemoveExistingKeysMap, &data); + } + + for(i = 0 ; i < num ; i++) + { + watchKey.key = goastrdup(keys[i]); + TableEnter(connection->roomWatchKeys[roomType], &watchKey); + } + + // Update them all. + /////////////////// + if(ENTERING_ROOM || IN_ROOM) + chatGetChannelKeysA(connection->chat, ROOM, "*", num, keys, piGetRoomKeysCallback, peer, CHATFalse); +} + +static PEERBool piKeyChanged +( + PEER peer, + const char * nick, + const char * key, + const char * value, + HashTable watchKeys, + HashTable watchCache, + PEERBool inRoom, + RoomType roomType +) +{ + piWatchKey watchKeyTemp; + piCacheKey cacheKey; + + assert(key && key[0]); + + // We don't track anything for rooms. + ///////////////////////////////////// + if(!nick || !nick[0]) + return PEERTrue; + + // No NULL values. + ////////////////// + if(!value) + value = ""; + + // Is this a username (IP and Profile ID)? + ////////////////////////////////////////// + if(strcasecmp(key, "username") == 0) + { + piPlayer * player; + + if(strcmp(nick, "(END)") == 0) + { + // + // If is "(END)", this is the final message from + // a GETCKEYS list. Call straight into the PlayerInfo + // callback with zeroed arguments (09mar01/bgw). + // + assert(inRoom); + piAddPlayerInfoCallback(peer, roomType, NULL, 0, 0); + return PEERFalse; + } + + // Get the player. + ////////////////// + player = piGetPlayer(peer, nick); + if(player && !player->gotIPAndProfileID) + { + int profileID; + unsigned int IP; + + // Get the info. + //////////////// + if(piDemangleUser(value, &IP, &profileID)) + { + // Cache the info. + ////////////////// + piSetPlayerIPAndProfileID(peer, nick, IP, profileID); + } + } + + // If this was in a room, call the callback. + //////////////////////////////////////////// + if(inRoom) + { + if(player && player->gotIPAndProfileID) + piAddPlayerInfoCallback(peer, roomType, nick, player->IP, player->profileID); + else + piAddPlayerInfoCallback(peer, roomType, nick, 0, 0); + } + } + + // Is this flags? + ///////////////// + if(inRoom && strcasecmp(key, "b_flags") == 0) + piSetPlayerRoomFlags(peer, nick, roomType, value); + + // Check if this is a watch key. + //////////////////////////////// + watchKeyTemp.key = (char *)key; + if(!TableLookup(watchKeys, &watchKeyTemp)) + { + // Is it a broadcast key? + ///////////////////////// + if(inRoom && (strncmp(key, "b_", 2) == 0)) + return PEERTrue; + return PEERFalse; + } + + // Cache it. + //////////// + memset(&cacheKey, 0, sizeof(piCacheKey)); + cacheKey.nick = goastrdup(nick); + cacheKey.key = goastrdup(key); + cacheKey.value = goastrdup(value); +#ifdef GSI_UNICODE + cacheKey.value_W = UTF8ToUCS2StringAlloc(cacheKey.value); +#endif + TableEnter(watchCache, &cacheKey); + + return PEERTrue; +} + +void piGlobalKeyChanged +( + PEER peer, + const char * nick, + const char * key, + const char * value +) +{ + PEER_CONNECTION; + + if(piKeyChanged(peer, nick, key, value, connection->globalWatchKeys[TitleRoom], connection->globalWatchCache, PEERFalse, (RoomType)0) || + piKeyChanged(peer, nick, key, value, connection->globalWatchKeys[GroupRoom], connection->globalWatchCache, PEERFalse, (RoomType)0) || + piKeyChanged(peer, nick, key, value, connection->globalWatchKeys[StagingRoom], connection->globalWatchCache, PEERFalse, (RoomType)0)) + piAddGlobalKeyChangedCallback(peer, nick, key, value); +} + +void piRoomKeyChanged +( + PEER peer, + RoomType roomType, + const char * nick, + const char * key, + const char * value +) +{ + PEER_CONNECTION; + + if(piKeyChanged(peer, nick, key, value, connection->roomWatchKeys[roomType], connection->roomWatchCache[roomType], PEERTrue, roomType)) + piAddRoomKeyChangedCallback(peer, roomType, nick, key, value); +} + +static void piPlayerChangedNickMap +( + void * elem, + void * clientData +) +{ + piCacheKey * key = (piCacheKey *)elem; + piPlayerChangedNickMapData * data = (piPlayerChangedNickMapData *)clientData; + + if(strcasecmp(key->nick, data->oldNick) == 0) + { + gsifree(key->nick); + key->nick = goastrdup(data->newNick); + } +} + +void piKeyCachePlayerChangedNick +( + PEER peer, + const char * oldNick, + const char * newNick +) +{ + piPlayerChangedNickMapData data; + + PEER_CONNECTION; + + data.oldNick = oldNick; + data.newNick = newNick; + + TableMap(connection->globalWatchCache, piPlayerChangedNickMap, &data); + TableMap(connection->roomWatchCache[0], piPlayerChangedNickMap, &data); + TableMap(connection->roomWatchCache[1], piPlayerChangedNickMap, &data); + TableMap(connection->roomWatchCache[2], piPlayerChangedNickMap, &data); +} + +static void piSetupKeysMap +( + void * elem, + void * clientData +) +{ + piWatchKey * key = (piWatchKey *)elem; + piSetupKeysMapData * data = (piSetupKeysMapData *)clientData; + + // Add the key to the list. + /////////////////////////// + data->keys[data->next++] = key->key; +} + +static void piKeyCacheRefresh +( + PEER peer, + RoomType roomType, + const char * nick +) +{ + int num; + piSetupKeysMapData data; + PEERBool getIP; + PEERBool getFlags; + piWatchKey watchKey; + + PEER_CONNECTION; + + assert(IN_ROOM || ENTERING_ROOM); + if(!IN_ROOM && !ENTERING_ROOM) + return; + + // Get the IP if we're pinging this room. + ///////////////////////////////////////// + if(!nick) + getIP = (connection->pingRoom[roomType] || connection->alwaysRequestPlayerInfo)?PEERTrue:PEERFalse; + else + getIP = PEERFalse; + + // Check if we're already getting the IP. + ///////////////////////////////////////// + if(getIP) + { + watchKey.key = "username"; + getIP = (PEERBool)(!TableLookup(connection->roomWatchKeys[roomType], &watchKey)); + } + + // Don't get flags on a player - he just joined, and will set them. + /////////////////////////////////////////////////////////////////// + getFlags = (PEERBool)(nick == NULL); + + // Check for a b_flags watch key. + ///////////////////////////////// + if(getFlags) + { + watchKey.key = "b_flags"; + getFlags = (PEERBool)(!(TableLookup(connection->globalWatchKeys[roomType], &watchKey) || + TableLookup(connection->roomWatchKeys[roomType], &watchKey))); + } + + data.next = 0; + num = TableCount(connection->globalWatchKeys[roomType]); + if(num) + { + data.keys = (char **)gsimalloc(sizeof(char *) * num); + if(!data.keys) + return; + TableMap(connection->globalWatchKeys[roomType], piSetupKeysMap, &data); + assert(data.next == num); + chatGetGlobalKeysA(connection->chat, nick?nick:ROOM, num, (const char **)data.keys, piGetGlobalKeysCallback, peer, CHATFalse); + gsifree(data.keys); + } + + if(!nick) + { + data.next = 0; + num = TableCount(connection->roomWatchKeys[roomType]); + if(getIP) + num++; + if(getFlags) + num++; + if(num) + { + data.keys = (char **)gsimalloc(sizeof(char *) * num); + if(!data.keys) + return; + TableMap(connection->roomWatchKeys[roomType], piSetupKeysMap, &data); + if(getIP) + data.keys[data.next++] = "username"; + if(getFlags) + data.keys[data.next++] = "b_flags"; + assert(data.next == num); + chatGetChannelKeysA(connection->chat, ROOM, nick?nick:"*", num, (const char **)data.keys, piGetRoomKeysCallback, peer, CHATFalse); + gsifree(data.keys); + } + } +} + +void piKeyCacheRefreshPlayer +( + PEER peer, + RoomType roomType, + const char * nick +) +{ + piKeyCacheRefresh(peer, roomType, nick); +} + +void piKeyCacheRefreshRoom +( + PEER peer, + RoomType roomType +) +{ + piKeyCacheRefresh(peer, roomType, NULL); +} diff --git a/xrGameSpy/gamespy/Peer/peerKeys.h b/xrGameSpy/gamespy/Peer/peerKeys.h new file mode 100644 index 00000000000..f27333d2aba --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerKeys.h @@ -0,0 +1,49 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERKEYS_H_ +#define _PEERKEYS_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" +#include "peerPlayers.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/************** +** FUNCTIONS ** +**************/ +PEERBool piKeysInit(PEER peer); +void piKeysCleanup(PEER peer); +const char * piGetGlobalWatchKeyA(PEER peer, const char * nick, const char * key); +const char * piGetRoomWatchKeyA(PEER peer, RoomType roomType, const char * nick, const char * key); +const unsigned short * piGetGlobalWatchKeyW(PEER peer, const unsigned short * nick, const unsigned short * key); +const unsigned short * piGetRoomWatchKeyW(PEER peer, RoomType roomType, const unsigned short * nick, const unsigned short * key); +void piSetGlobalWatchKeys(PEER peer, RoomType roomType, int num, const char ** keys, PEERBool addKeys); +void piSetRoomWatchKeys(PEER peer, RoomType roomType, int num, const char ** keys, PEERBool addKeys); +void piGlobalKeyChanged(PEER peer, const char * nick, const char * key, const char * value); +void piRoomKeyChanged(PEER peer, RoomType roomType, const char * nick, const char * key, const char * value); +void piKeyCachePlayerChangedNick(PEER peer, const char * oldNick, const char * newNick); +void piKeyCachePlayerLeftRoom(PEER peer, RoomType roomType, piPlayer * player); +void piKeyCacheLeftRoom(PEER peer, RoomType roomType); +void piKeyCacheRefreshPlayer(PEER peer, RoomType roomType, const char * nick); +void piKeyCacheRefreshRoom(PEER peer, RoomType roomType); +void piKeyCacheCleanse(PEER peer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerMain.c b/xrGameSpy/gamespy/Peer/peerMain.c new file mode 100644 index 00000000000..c40c98be928 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerMain.c @@ -0,0 +1,4409 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include "peer.h" +#include "peerAscii.h" +#include "peerMain.h" +#include "peerCallbacks.h" +#include "peerGlobalCallbacks.h" +#include "peerOperations.h" +#include "peerPlayers.h" +#include "peerRooms.h" +#include "peerPing.h" +#include "peerSB.h" +#include "peerMangle.h" +#include "peerKeys.h" +#include "peerQR.h" +#include "peerHost.h" +#include "peerAutoMatch.h" +#include "../common/gsAvailable.h" + +/************ +** DEFINES ** +************/ +#define PEER_CONNECTED assert(connection->connected); + +#define PI_CHECK_SHUTDOWN if(connection->shutdown && (connection->callbackDepth == 0))\ + {\ + peerShutdown(peer);\ + } + +#define PI_INIT_FAILED {\ + piShutdownCleanup(peer);\ + return NULL;\ + } + +#define PI_DO_BLOCKING if(blocking)\ + {\ + do\ + {\ + msleep(1);\ + piThink(peer, opID);\ + }\ + while(!piCheckBlockingID(peer, opID));\ + PI_CHECK_SHUTDOWN\ + } + +#define PI_OP_ID int opID = piGetNextID(peer) +#if 0 +int opID; // for visual assist +#endif + +/*************** +** PROTOTYPES ** +***************/ +static void piShutdownCleanup(PEER peer); +static void piDisconnectCleanup(PEER peer); +static void piThink(PEER peer,int ID); + +void peerCreateStagingRoomWithSocketA(PEER peer, const char * name, int maxPlayers, const char password[PEER_PASSWORD_LEN], SOCKET socket, unsigned short port, peerJoinRoomCallback callback, void * param, PEERBool blocking); +void peerStartAutoMatchWithSocketA(PEER peer, int maxPlayers, const char * filter, SOCKET socket, unsigned short port, peerAutoMatchStatusCallback statusCallback, peerAutoMatchRateCallback rateCallback, void * param, PEERBool blocking); + +/************ +** GENERAL ** +************/ +static PEERBool piCheckBlockingID +( + PEER peer, + int ID +) +{ + return (PEERBool)(piIsOperationFinished(peer, ID) && piIsCallbackFinished(peer, ID)); +} + +static unsigned int piGetPrivateIP(void) +{ + HOSTENT * host; + IN_ADDR * addr; + int i; + + host = getlocalhost(); + if(!host) + return 0; + + for(i = 0 ; host->h_addr_list[i] ; i++) + { + addr = (IN_ADDR *)host->h_addr_list[i]; + if(IsPrivateIP(addr)) + return addr->s_addr; + } + + return 0; +} + +PEER peerInitialize +( + PEERCallbacks * callbacks +) +{ + PEER peer; + piConnection * connection; + + assert(callbacks); + + // Check if the backend is available. + ///////////////////////////////////// + if(__GSIACResult != GSIACAvailable) + return NULL; + + // Init sockets. + //////////////// + SocketStartUp(); + + // Create an object. + //////////////////// + connection = (piConnection *)gsimalloc(sizeof(piConnection)); + if(!connection) + return NULL; + memset(connection, 0, sizeof(piConnection)); + peer = (PEER)connection; + + // Chat. + //////// + connection->chat = NULL; + connection->nick[0] = '\0'; + connection->connecting = PEERFalse; + connection->connected = PEERFalse; + + // Game. + //////// + connection->privateIP = piGetPrivateIP(); + connection->title[0] = '\0'; + +#ifdef GSI_UNICODE + connection->title_W[0] = '\0'; + connection->nick_W[0] = '\0'; +#endif + + // ID. + ////// + connection->nextID = 0; + + // Operations. + ////////////// + if(!piOperationsInit(peer)) + PI_INIT_FAILED + + // Callbacks. + ///////////// + connection->callbacks = *callbacks; + if(!piCallbacksInit(peer)) + PI_INIT_FAILED + + // Keys. + //////// + if(!piKeysInit(peer)) + PI_INIT_FAILED + + // Misc. + //////// + connection->shutdown = PEERFalse; + + return peer; +} + +void peerConnectA +( + PEER peer, + const char * nick, + int profileID, + peerNickErrorCallback nickErrorCallback, + peerConnectCallback connectCallback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + + PI_OP_ID; + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + assert(profileID >= 0); + assert(connectCallback); + assert(strlen(nick) < PI_NICK_MAX_LEN); + + // Are we already connecting or connected? + ////////////////////////////////////////// + if(connection->connected || connection->connecting) + success = PEERFalse; + + // We must have a title set to connect. + /////////////////////////////////////// + if(success && !connection->title[0]) + success = PEERFalse; + + if(success) + { + // Chat. + //////// + connection->chat = NULL; + strzcpy(connection->nick, nick, PI_NICK_MAX_LEN); + connection->connected = PEERFalse; + connection->connecting = PEERTrue; + connection->nickErrorCallback = nickErrorCallback; + +#ifdef GSI_UNICODE + UTF8ToUCS2String(connection->nick, connection->nick_W); +#endif + // Misc. + //////// + connection->profileID = profileID; + connection->disconnect = PEERFalse; + + // Start connecting. + //////////////////// + if(!piNewConnectOperation(peer, PI_CONNECT, nick, 0, NULL, NULL, NULL, NULL, NULL, NULL, connectCallback, param, opID)) + { + success = PEERFalse; + piDisconnectCleanup(peer); + } + } + + if(!success) + piAddConnectCallback(peer, PEERFalse, PEER_DISCONNECTED, connectCallback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerConnectW +( + PEER peer, + const unsigned short * nick, + int profileID, + peerNickErrorCallback nickErrorCallback, + peerConnectCallback connectCallback, + void * param, + PEERBool blocking +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + peerConnectA(peer, nick_A, profileID, nickErrorCallback, connectCallback, param, blocking); + gsifree(nick_A); +} +#endif + +void peerConnectLoginA +( + PEER peer, + int namespaceID, + const char * email, + const char * profilenick, + const char * uniquenick, + const char * password, + peerNickErrorCallback nickErrorCallback, + peerConnectCallback connectCallback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + + PI_OP_ID; + PEER_CONNECTION; + + assert(connectCallback); + + // Are we already connecting or connected? + ////////////////////////////////////////// + if(connection->connected || connection->connecting) + success = PEERFalse; + + // We must have a title set to connect. + /////////////////////////////////////// + if(success && !connection->title[0]) + success = PEERFalse; + + if(success) + { + // Chat. + //////// + connection->chat = NULL; + connection->nick[0] = '\0'; + connection->connected = PEERFalse; + connection->connecting = PEERTrue; + connection->nickErrorCallback = nickErrorCallback; + +#ifdef GSI_UNICODE + UTF8ToUCS2String(connection->nick, connection->nick_W); +#endif + // Misc. + //////// + connection->profileID = 0; + connection->disconnect = PEERFalse; + + // Start connecting. + //////////////////// + if(!piNewConnectOperation(peer, (uniquenick && uniquenick[0])?PI_CONNECT_UNIQUENICK_LOGIN:PI_CONNECT_PROFILENICK_LOGIN, NULL, namespaceID, email, profilenick, uniquenick, password, NULL, NULL, connectCallback, param, opID)) + { + success = PEERFalse; + piDisconnectCleanup(peer); + } + } + + if(!success) + piAddConnectCallback(peer, PEERFalse, PEER_DISCONNECTED, connectCallback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerConnectLoginW +( + PEER peer, + int namespaceID, + const unsigned short * email, + const unsigned short * profilenick, + const unsigned short * uniquenick, + const unsigned short * password, + peerNickErrorCallback nickErrorCallback, + peerConnectCallback connectCallback, + void * param, + PEERBool blocking +) +{ + char* email_A = UCS2ToUTF8StringAlloc(email); + char* profilenick_A = UCS2ToUTF8StringAlloc(profilenick); + char* uniquenick_A = UCS2ToUTF8StringAlloc(uniquenick); + char* password_A = UCS2ToUTF8StringAlloc(password); + peerConnectLoginA(peer, namespaceID, email_A, profilenick_A, uniquenick_A, password_A, nickErrorCallback, connectCallback, param, blocking); + gsifree(email_A); + gsifree(profilenick_A); + gsifree(uniquenick_A); + gsifree(password_A); +} +#endif + +void peerConnectPreAuthA +( + PEER peer, + const char * authtoken, + const char * partnerchallenge, + peerNickErrorCallback nickErrorCallback, + peerConnectCallback connectCallback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + + PI_OP_ID; + PEER_CONNECTION; + + assert(authtoken && authtoken[0]); + assert(partnerchallenge && partnerchallenge[0]); + assert(connectCallback); + + // Are we already connecting or connected? + ////////////////////////////////////////// + if(connection->connected || connection->connecting) + success = PEERFalse; + + // We must have a title set to connect. + /////////////////////////////////////// + if(success && !connection->title[0]) + success = PEERFalse; + + if(success) + { + // Chat. + //////// + connection->chat = NULL; + connection->nick[0] = '\0'; + connection->connected = PEERFalse; + connection->connecting = PEERTrue; + connection->nickErrorCallback = nickErrorCallback; + +#ifdef GSI_UNICODE + UTF8ToUCS2String(connection->nick, connection->nick_W); +#endif + // Misc. + //////// + connection->profileID = 0; + connection->disconnect = PEERFalse; + + // Start connecting. + //////////////////// + if(!piNewConnectOperation(peer, PI_CONNECT_PREAUTH, NULL, 0, NULL, NULL, NULL, NULL, authtoken, partnerchallenge, connectCallback, param, opID)) + { + success = PEERFalse; + piDisconnectCleanup(peer); + } + } + + if(!success) + piAddConnectCallback(peer, PEERFalse, PEER_DISCONNECTED, connectCallback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerConnectPreAuthW +( + PEER peer, + const unsigned short * authtoken, + const unsigned short * partnerchallenge, + peerNickErrorCallback nickErrorCallback, + peerConnectCallback connectCallback, + void * param, + PEERBool blocking +) +{ + char* authtoken_A = UCS2ToUTF8StringAlloc(authtoken); + char* partnerchallenge_A = UCS2ToUTF8StringAlloc(partnerchallenge); + peerConnectPreAuthA(peer, authtoken_A, partnerchallenge_A, nickErrorCallback, connectCallback, param, blocking); + gsifree(authtoken_A); + gsifree(partnerchallenge_A); +} +#endif + +void peerRetryWithNickA +( + PEER peer, + const char * nick +) +{ + PEER_CONNECTION; + + // Check that we're connecting. + /////////////////////////////// + assert(connection->connecting); + if(!connection->connecting) + return; + + // Set the new nick we're using. + //////////////////////////////// + if(nick && nick[0]) + { + strzcpy(connection->nick, nick, PI_NICK_MAX_LEN); + +#ifdef GSI_UNICODE + UTF8ToUCS2String(connection->nick, connection->nick_W); +#endif + } + + // Retry with the new nick. + /////////////////////////// + chatRetryWithNickA(connection->chat, nick); +} +#ifdef GSI_UNICODE +void peerRetryWithNickW +( + PEER peer, + const unsigned short * nick +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + peerRetryWithNickA(peer, nick_A); + gsifree(nick_A); +} +#endif + +void peerRegisterUniqueNickA +( + PEER peer, + int namespaceID, + const char * uniquenick, + const char * cdkey) +{ + PEER_CONNECTION; + + // Check that we're connecting. + /////////////////////////////// + assert(connection->connecting); + if(!connection->connecting) + return; + + // Register the nick. + ///////////////////// + chatRegisterUniqueNickA(connection->chat, namespaceID, uniquenick, cdkey); +} +#ifdef GSI_UNICODE +void peerRegisterUniqueNickW +( + PEER peer, + int namespaceID, + const unsigned short * uniquenick, + const unsigned short * cdkey +) +{ + char* uniquenick_A = UCS2ToUTF8StringAlloc(uniquenick); + char* cdkey_A = UCS2ToUTF8StringAlloc(cdkey); + peerRegisterUniqueNickA(peer, namespaceID, uniquenick_A, cdkey_A); + gsifree(uniquenick_A); + gsifree(cdkey_A); +} +#endif + +PEERBool peerIsConnected(PEER peer) +{ + PEER_CONNECTION; + + return connection->connected; +} + +PEERBool piConnectTitle(PEER peer) +{ + // Rooms. + ///////// + if(!piRoomsInit(peer)) + return PEERFalse; + + // Players. + /////////// + if(!piPlayersInit(peer)) + return PEERFalse; + + // Ping. + // If it fails, keep going. + /////////////////////////// + piPingInit(peer); + + return PEERTrue; +} + +void piDisconnectTitle(PEER peer) +{ + // Rooms. + ///////// + piRoomsCleanup(peer); + + // Players. + /////////// + piPlayersCleanup(peer); + + // Ping. + //////// + piPingCleanup(peer); + + // AutoMatch. + ///////////// + piStopAutoMatch(peer); +} + +PEERBool peerSetTitleA +( + PEER peer, + const char * title, + const char * qrSecretKey, + const char * sbName, + const char * sbSecretKey, + int sbGameVersion, + int sbMaxUpdates, + PEERBool natNegotiate, + PEERBool pingRooms[NumRooms], + PEERBool crossPingRooms[NumRooms] +) +{ + static PEERBool noPings[NumRooms]; + PEERBool pingTitleRoom = PEERFalse; + PEERBool xpingTitleRoom = PEERFalse; + + PEER_CONNECTION; + + assert(title); + assert(title[0]); + assert(strlen(title) < PI_TITLE_MAX_LEN); + assert(qrSecretKey); + assert(sbName); + assert(sbName[0]); + assert(sbSecretKey); + + // Check if a title is set. + /////////////////////////// + if(connection->title[0]) + peerClearTitle(peer); + + // Game. + //////// + strcpy(connection->title, title); + +#ifdef GSI_UNICODE + AsciiToUCS2String(title, connection->title_W); +#endif + + // Null pings means don't do pings. + /////////////////////////////////// + if(!pingRooms) + pingRooms = noPings; + if(!crossPingRooms) + crossPingRooms = noPings; + + // If staying in the title room, leave the room's ping setting alone. + ///////////////////////////////////////////////////////////////////// + if(connection->stayInTitleRoom) + { + pingTitleRoom = connection->pingRoom[TitleRoom]; + xpingTitleRoom = connection->xpingRoom[TitleRoom]; + } + + // Save our ping settings. + ////////////////////////// + memcpy(connection->pingRoom, pingRooms, sizeof(PEERBool) * NumRooms); + memcpy(connection->xpingRoom, crossPingRooms, sizeof(PEERBool) * NumRooms); + + // If staying in the title room, leave the room's ping setting alone. + ///////////////////////////////////////////////////////////////////// + if(connection->stayInTitleRoom) + { + connection->pingRoom[TitleRoom] = pingTitleRoom; + connection->xpingRoom[TitleRoom] = xpingTitleRoom; + } + + // Save SB settings. + //////////////////// + strzcpy(connection->sbName, sbName, PI_SB_LEN); + strzcpy(connection->sbSecretKey, sbSecretKey, PI_SB_LEN); + connection->sbGameVersion = sbGameVersion; + connection->sbMaxUpdates = sbMaxUpdates; + + // Init SB. + /////////// + if(!piSBInit(peer)) + return PEERFalse; + + // If we're already connected, do the connect stuff. + //////////////////////////////////////////////////// + if(connection->connected) + { + if(!piConnectTitle(peer)) + { + peerClearTitle(peer); + return PEERFalse; + } + } + + // Hosting. + /////////// + strcpy(connection->qrSecretKey, qrSecretKey); + piStopHosting(peer, PEERTrue); + connection->hosting = PEERFalse; + connection->playing = PEERFalse; + connection->natNegotiate = natNegotiate; + + // Game states. + /////////////// + connection->ready = PEERFalse; + + // Make sure the "stay in title room" setting is cleared. + ///////////////////////////////////////////////////////// + connection->stayInTitleRoom = PEERFalse; + + return PEERTrue; +} +#ifdef GSI_UNICODE +PEERBool peerSetTitleW +( + PEER peer, + const unsigned short * title, + const unsigned short * qrSecretKey, + const unsigned short * sbName, + const unsigned short * sbSecretKey, + int sbGameVersion, + int sbMaxUpdates, + PEERBool natNegotiate, + PEERBool pingRooms[NumRooms], + PEERBool crossPingRooms[NumRooms] +) +{ + char* title_A = UCS2ToUTF8StringAlloc(title); + char* qrSecretKey_A = UCS2ToUTF8StringAlloc(qrSecretKey); + char* sbName_A = UCS2ToUTF8StringAlloc(sbName); + char* sbSecretKey_A = UCS2ToUTF8StringAlloc(sbSecretKey); + PEERBool result = peerSetTitleA(peer, title_A, qrSecretKey_A, sbName_A, sbSecretKey_A, sbGameVersion, sbMaxUpdates, natNegotiate, pingRooms, crossPingRooms); + gsifree(title_A); + gsifree(qrSecretKey_A); + gsifree(sbName_A); + gsifree(sbSecretKey_A); + return result; +} +#endif + +void peerClearTitle(PEER peer) +{ + PEER_CONNECTION; + + // Stop hosting if we are. + ////////////////////////// + piStopHosting(peer, PEERTrue); + + // Cleanup SB. + ////////////// + piSBCleanup(peer); + + // Cleanup title stuff. + /////////////////////// + piDisconnectTitle(peer); + + // Cleanup game. + //////////////// + connection->title[0] = '\0'; + +#ifdef GSI_UNICODE + connection->title_W[0] = '\0'; +#endif + + // Cleanup qr secret key. + ///////////////////////// + connection->qrSecretKey[0] = '\0'; +} + +const char* peerGetTitleA(PEER peer) +{ + PEER_CONNECTION; + + if(!connection->title[0]) + return NULL; + + return connection->title; +} +#ifdef GSI_UNICODE +const unsigned short* peerGetTitleW(PEER peer) +{ + PEER_CONNECTION; + + if(!connection->title_W[0]) + return NULL; + + return connection->title_W; +} +#endif + +static void piDisconnectCleanup(PEER peer) +{ + PEER_CONNECTION; + + // Chat. + //////// + if(connection->chat) + chatDisconnect(connection->chat); + connection->chat = NULL; + connection->nick[0] = '\0'; + connection->connecting = PEERFalse; + connection->connected = PEERFalse; + +#ifdef GSI_UNICODE + connection->nick_W[0] = '\0'; +#endif + + // Operations. + ////////////// + piOperationsReset(peer); + + // Title. + ///////// + piDisconnectTitle(peer); + + // Away. + //////// + connection->away = PEERFalse; + connection->awayReason[0] = '\0'; + + // We're not trying to disconnect. + ////////////////////////////////// + connection->disconnect = PEERFalse; +} + +static void piDisconnect(PEER peer) +{ + PEER_CONNECTION; + + // Are we within a callback? + //////////////////////////// + if(connection->callbackDepth > 0) + { + // Flag for disconnect later. + ///////////////////////////// + connection->disconnect = PEERTrue; + + return; + } + + // Can't stay in the title room if we're disconnecting. + /////////////////////////////////////////////////////// + connection->stayInTitleRoom = PEERFalse; + + // Cleanup the connection. + ////////////////////////// + piDisconnectCleanup(peer); + + // Think to make sure the disconnected callback gets called. + //////////////////////////////////////////////////////////// + piThink(peer, -1); +} + +void peerDisconnect(PEER peer) +{ + PEER_CONNECTION; + + // Do the disconnect. + ///////////////////// + piDisconnect(peer); + + // Check if we got shutdown in the disconnect callback. + /////////////////////////////////////////////////////// + PI_CHECK_SHUTDOWN +} + +static void piShutdownCleanup(PEER peer) +{ + PEER_CONNECTION; + + // Operations. + ////////////// + piOperationsCleanup(peer); + + // Callbacks. + ///////////// + piCallbacksCleanup(peer); + + // Shut down sockets. + ///////////////////// + SocketShutDown(); + + // Keys. + //////// + piKeysCleanup(peer); + + // gsifree the connection. + /////////////////////// + gsifree(connection); +} + +void peerShutdown(PEER peer) +{ + PEER_CONNECTION; + + // Cleanup the connection? + ////////////////////////// + if(connection->connected || connection->connecting) + { + peerDisconnectedCallback callback; + + // We don't want the disconnected callback + // called if we're being explicitly shutdown. + ///////////////////////////////////////////// + callback = connection->callbacks.disconnected; + connection->callbacks.disconnected = NULL; + piDisconnect(peer); + connection->callbacks.disconnected = callback; + } + + // Cleanup title if needed. + /////////////////////////// + if(connection->title[0]) + peerClearTitle(peer); + + // Are we within a callback? + //////////////////////////// + if(connection->callbackDepth > 0) + { + // Flag for shutdown later. + /////////////////////////// + connection->shutdown = PEERTrue; + + return; + } + + // Cleanup. + /////////// + piShutdownCleanup(peer); +} + +#ifdef _DEBUG +static void piNumPlayersConsistencyCheckMap +( + piPlayer * player, + int count[NumRooms] +) +{ + int i; + + assert(player); + assert(count); + + for(i = 0 ; i < NumRooms ; i++) + { + if(player->inRoom[i]) + count[i]++; + } +} +#endif + +static void piThink +( + PEER peer, + int opID +) +{ + gsi_time now; + PEER_CONNECTION; + +#ifdef _DEBUG + if(connection->players) + { + // Consistency check number of players in each room. + //////////////////////////////////////////////////// + { + int count[NumRooms]; + int i; + + // Init the counts to 0. + //////////////////////// + for(i = 0 ; i < NumRooms ; i++) + count[i] = 0; + + // Map through the players checking the count. + ////////////////////////////////////////////// + TableMap(connection->players, (TableMapFn)piNumPlayersConsistencyCheckMap, count); + + // Check the counts. + //////////////////// + for(i = 0 ; i < NumRooms ; i++) + assert(count[i] == connection->numPlayers[i]); + } + } +#endif + +#if 0 + // Show info. + ///////////// + { + char buffer[1024]; + static int counter = -1; + + counter++; + counter %= 20; + if(counter == 0) + { + sprintf(buffer, + "---------------------\n" + "operationsStarted: %d\n" + "operationsFinished: %d\n" + "callbacksQueued: %d\n" + "callbacksCalled: %d\n" + "callbackDepth: %d\n" + "titleRoomPlayers: %d\n" + "groupRoomPlayers: %d\n" + "stagingRoomPlayers: %d\n", + connection->operationsStarted, + connection->operationsFinished, + connection->callbacksQueued, + connection->callbacksCalled, + connection->callbackDepth, + connection->numPlayers[TitleRoom], + connection->numPlayers[GroupRoom], + connection->numPlayers[StagingRoom]); + OutputDebugString(buffer); + } + } +#endif + + // Let chat think. + ////////////////// + if(connection->connected || connection->connecting) + { + chatThink(connection->chat); + + // Only do this if we weren't disconnected. + /////////////////////////////////////////// + if(!connection->disconnect) + { + // Is a title set? + ////////////////// + if(connection->title[0]) + { + // Do ping stuff. + ///////////////// + piPingThink(peer); + } + + // Are we connected? + //////////////////// + if(connection->connected) + { + // Ge the current time. + /////////////////////// + now = current_time(); + + // Check if we need to ping the chat server. + //////////////////////////////////////////// + if((now - connection->lastChatPing) > PI_CHAT_PING_TIME) + { + // Send the ping. + ///////////////// + chatSendRawA(connection->chat, "PING"); + + // Store the current time. + ////////////////////////// + connection->lastChatPing = now; + } + } + } + } + + // Let SB think. + //////////////// + piSBThink(peer); + + // Let query-reporting think. + ///////////////////////////// + piQRThink(peer); + + // If we got disconnected from chat, do the cleanup before calling the callback. + //////////////////////////////////////////////////////////////////////////////// + if(connection->disconnect && (connection->callbackDepth == 0)) + piDisconnect(peer); + + // Let the callbacks think. + /////////////////////////// + piCallbacksThink(peer, opID); +} + +void peerThink(PEER peer) +{ + PEER_CONNECTION; + + // Think. + ///////// + piThink(peer, -1); + + PI_CHECK_SHUTDOWN +} + +CHAT peerGetChat(PEER peer) +{ + PEER_CONNECTION; + + // Return it. + ///////////// + return connection->chat; +} + +const char * peerGetNickA(PEER peer) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check if connected. + ////////////////////// + if(!connection->connected) + return NULL; + + // Return it. + ///////////// + return connection->nick; +} +#ifdef GSI_UNICODE +const unsigned short * peerGetNickW(PEER peer) +{ + PEER_CONNECTION; + PEER_CONNECTED; + if (!connection->connected) + return NULL; + return connection->nick_W; +} +#endif + +#ifndef GSI_UNICODE +void peerFixNickA +( + char * newNick, + const char * oldNick +) +{ + chatFixNickA(newNick, oldNick); +} +const char * peerTranslateNickA +( + char * nick, + const char * extension +) +{ + return chatTranslateNickA(nick, extension); +} +#else +void peerFixNickW +( + unsigned short * newNick, + const unsigned short * oldNick +) +{ + chatFixNickW(newNick, oldNick); +} +const unsigned short * peerTranslateNickW +( + unsigned short * nick, + const unsigned short * extension +) +{ + return chatTranslateNickW(nick, extension); +} +#endif + +unsigned int peerGetPublicIP(PEER peer) +{ + PEER_CONNECTION; + + // Return it. + ///////////// + return connection->publicIP; +} + +unsigned int peerGetPrivateIP(PEER peer) +{ + PEER_CONNECTION; + + // Return it. + ///////////// + return connection->privateIP; +} + +int peerGetUserID(PEER peer) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + if(!connection->connected) + return 0; + + return chatGetUserID(connection->chat); +} + +int peerGetProfileID(PEER peer) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + if(!connection->connected) + return 0; + + return chatGetProfileID(connection->chat); +} + +void peerChangeNickA +( + PEER peer, + const char * newNick, + peerChangeNickCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + + PI_OP_ID; + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + + // Start the operation. + /////////////////////// + if(!piNewChangeNickOperation(peer, newNick, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddChangeNickCallback(peer, PEERFalse, connection->nick, newNick, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerChangeNickW +( + PEER peer, + const unsigned short * newNick, + peerChangeNickCallback callback, + void * param, + PEERBool blocking +) +{ + char* newNick_A = UCS2ToUTF8StringAlloc(newNick); + peerChangeNickA(peer, newNick_A, callback, param, blocking); + gsifree(newNick_A); +} +#endif + +void peerStayInRoom +( + PEER peer, + RoomType roomType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + assert(roomType == TitleRoom); + if(roomType != TitleRoom) + return; + + if(!connection->title[0]) + return; + + connection->stayInTitleRoom = PEERTrue; +} + +void peerSetQuietMode +( + PEER peer, + PEERBool quiet +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + chatSetQuietMode(connection->chat, (CHATBool)quiet); +} + +void peerSetAwayModeA +( + PEER peer, + const char * reason +) +{ + char buffer[PI_AWAY_MAX_LEN + 6]; + PEER_CONNECTION; + PEER_CONNECTED; + + if(!reason) + reason = ""; + + // Store the setting. + ///////////////////// + connection->away = (PEERBool)(reason[0] != '\0'); + strzcpy(connection->awayReason, reason, PI_AWAY_MAX_LEN); + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + + // Send the chat command. + ///////////////////////// + sprintf(buffer, "AWAY :%s", connection->awayReason); + chatSendRawA(connection->chat, buffer); +} +#ifdef GSI_UNICODE +void peerSetAwayModeW +( + PEER peer, + const unsigned short* reason +) +{ + char* reason_A = UCS2ToUTF8StringAlloc(reason); + peerSetAwayModeA(peer, reason_A); + gsifree(reason_A); +} +#endif + +void peerParseQueryA +( + PEER peer, + char * query, + int len, + struct sockaddr * sender +) +{ + PEER_CONNECTION; + + assert(query); + assert(sender); + + // Handle the query based on what type of reporting we're doing. + //////////////////////////////////////////////////////////////// + if(connection->queryReporting) + qr2_parse_queryA(connection->queryReporting, query, len, sender); + else if(connection->autoMatchReporting) + qr2_parse_queryA(connection->autoMatchReporting, query, len, sender); +} +/* NOT necessary since qr2_parse_query uses char not unsigned short +#ifdef GSI_UNICODE +void peerParseQueryW +( + PEER peer, + unsigned short * query, + int len, + struct sockaddr * sender +) +{ + char* query_A = UCS2ToUTF8StringAlloc(query); + peerParseQueryA(peer, query_A, len, sender); + gsifree(query_A); +} +#endif +*/ +void peerAuthenticateCDKeyA +( + PEER peer, + const char * cdkey, + peerAuthenticateCDKeyCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + + PI_OP_ID; + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + + // Start the operation. + /////////////////////// + if(!piNewAuthenticateCDKeyOperation(peer, cdkey, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddAuthenticateCDKeyCallback(peer, 0, "Error starting CD Key check", callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerAuthenticateCDKeyW +( + PEER peer, + const unsigned short* cdkey, + peerAuthenticateCDKeyCallback callback, + void * param, + PEERBool blocking +) +{ + char* cdkey_A = UCS2ToUTF8StringAlloc(cdkey); + peerAuthenticateCDKeyA(peer, cdkey_A, callback, param, blocking); + gsifree(cdkey_A); +} +#endif + +void peerSendNatNegotiateCookie +( + PEER peer, + unsigned int ip, + unsigned short port, + int cookie +) +{ + piSendNatNegotiateCookie(peer, ip, port, cookie); +} + +void peerSendMessageToServer +( + PEER peer, + unsigned int ip, + unsigned short port, + const char * data, + int len +) +{ + piSendMessageToServer(peer, ip, port, data, len); +} + +void peerAlwaysGetPlayerInfo +( + PEER peer, + PEERBool always +) +{ + PEER_CONNECTION; + + connection->alwaysRequestPlayerInfo = always; +} + +/********** +** ROOMS ** +**********/ +void peerJoinTitleRoomA +( + PEER peer, + const char password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + PEERJoinResult result = PEERJoinFailed; + char buffer[PI_ROOM_MAX_LEN]; + + PI_OP_ID; + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + + // NULL password is the same as empty password. + /////////////////////////////////////////////// + if(!password) + password = ""; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + { + success = PEERFalse; + result = PEERNoTitleSet; + } + + // Check for a connection. + ////////////////////////// + if(success && !connection->connected) + { + success = PEERFalse; + result = PEERNoConnection; + } + + // Check if we're in the title room. + //////////////////////////////////// + assert(!connection->enteringRoom[TitleRoom] && !connection->inRoom[TitleRoom]); + if((success && connection->enteringRoom[TitleRoom]) || connection->inRoom[TitleRoom]) + { + success = PEERFalse; + result = PEERAlreadyInRoom; + } + + // Check if we're AutoMatching. + /////////////////////////////// + assert(!peerIsAutoMatching(peer)); + if(success && peerIsAutoMatching(peer)) + { + success = PEERFalse; + result = PEERAutoMatching; + } + + // Get the room name. + ///////////////////// + if(success) + { + if(connection->titleRoomChannel[0]) + strcpy(buffer, connection->titleRoomChannel); + else + piMangleTitleRoom(buffer, connection->title); + } + + // Start the operation. + /////////////////////// + if(success && !piNewJoinRoomOperation(peer, TitleRoom, buffer, password, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddJoinRoomCallback(peer, PEERFalse, result, TitleRoom, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerJoinTitleRoomW +( + PEER peer, + const unsigned short password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + char* password_A = NULL; + if (password != NULL) + password_A = UCS2ToUTF8StringAlloc(password); + peerJoinTitleRoomA(peer, password_A, callback, param, blocking); + gsifree(password_A); +} +#endif + +void peerJoinGroupRoom +( + PEER peer, + int groupID, + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + PEERJoinResult result = PEERJoinFailed; + char room[PI_ROOM_MAX_LEN]; + + PI_OP_ID; + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + { + success = PEERFalse; + result = PEERNoTitleSet; + } + + // Check for a connection. + ////////////////////////// + if(success && !connection->connected) + { + success = PEERFalse; + result = PEERNoConnection; + } + + // Check if we're AutoMatching. + /////////////////////////////// + assert(!peerIsAutoMatching(peer)); + if(success && peerIsAutoMatching(peer)) + { + success = PEERFalse; + result = PEERAutoMatching; + } + + // Check the ID. + //////////////// + assert(groupID); + if(success && !groupID) + success = PEERFalse; + + // Check if we're in a group room. + ////////////////////////////////// + if(success && (connection->enteringRoom[GroupRoom] || connection->inRoom[GroupRoom])) + { + success = PEERFalse; + result = PEERAlreadyInRoom; + } + + // Create the name. + /////////////////// + piMangleGroupRoom(room, groupID); + + // Save off the group id. + ///////////////////////// + connection->groupID = groupID; + + // Start the operation. + /////////////////////// + if(success && !piNewJoinRoomOperation(peer, GroupRoom, room, NULL, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddJoinRoomCallback(peer, PEERFalse, result, GroupRoom, callback, param, opID); + + PI_DO_BLOCKING; +} + +void peerSetGroupID +( + PEER peer, + int groupID +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Save off the group id. + ///////////////////////// + connection->groupID = groupID; +} + +int peerGetGroupID +( + PEER peer +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return 0; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return 0; + + // Get the group id. + //////////////////// + return connection->groupID; +} + +static void piJoinStagingRoom +( + PEER peer, + SBServer server, + const char * channel, + const char password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + unsigned int publicIP = 0; + unsigned int privateIP = 0; + unsigned short privatePort = 0; + char room[PI_ROOM_MAX_LEN]; + PEERBool success = PEERTrue; + PEERJoinResult result = PEERJoinFailed; + + PI_OP_ID; + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + + // NULL password is the same as empty password. + /////////////////////////////////////////////// + if(!password) + password = ""; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + { + success = PEERFalse; + result = PEERNoTitleSet; + } + + // Check for a connection. + ////////////////////////// + if(success && !connection->connected) + { + success = PEERFalse; + result = PEERNoConnection; + } + + // Check if we're in a staging room. + //////////////////////////////////// + if(success && (connection->enteringRoom[StagingRoom] || connection->inRoom[StagingRoom])) + { + success = PEERFalse; + result = PEERAlreadyInRoom; + } + + // Check if we're AutoMatching. + /////////////////////////////// + assert(!peerIsAutoMatching(peer)); + if(success && peerIsAutoMatching(peer)) + { + success = PEERFalse; + result = PEERAutoMatching; + } + + // If we have a server, get the public and private IPs and ports. + ///////////////////////////////////////////////////////////////// + if(success && server) + { + publicIP = SBServerGetPublicInetAddress(server); + privateIP = SBServerGetPrivateInetAddress(server); + if(SBServerHasPrivateAddress(server)) + privatePort = SBServerGetPrivateQueryPort(server); + else + privatePort = SBServerGetPublicQueryPort(server); + + if(!publicIP) + success = PEERFalse; + } + + // If we have a channel, check it. + ////////////////////////////////// + if(success && !server) + { + assert(channel); + assert(channel[0]); + if(!channel || !channel[0]) + success = PEERFalse; + } + + // Stop hosting. + //////////////// + if(success) + piStopHosting(peer, PEERTrue); + + // If we have a server, get the staging room. + ///////////////////////////////////////////// + if(success && server) + piMangleStagingRoom(room, connection->title, publicIP, privateIP, privatePort); + + // Start the operation. + /////////////////////// + if(success && !piNewJoinRoomOperation(peer, StagingRoom, server?room:channel, password, callback, param, opID)) + success = PEERFalse; + + // If we have a server, clone it. + ///////////////////////////////// + if(success && server) + connection->hostServer = piSBCloneServer(server); + + // Check for failure. + ///////////////////// + if(!success) + piAddJoinRoomCallback(peer, PEERFalse, result, StagingRoom, callback, param, opID); + + PI_DO_BLOCKING; +} + +void peerJoinStagingRoomA +( + PEER peer, + SBServer server, + const char password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + piJoinStagingRoom(peer, server, NULL, password, callback, param, blocking); +} +#ifdef GSI_UNICODE +void peerJoinStagingRoomW +( + PEER peer, + SBServer server, + const unsigned short password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + char* password_A = UCS2ToUTF8StringAlloc(password); + peerJoinStagingRoomA(peer, server, password_A, callback, param, blocking); + gsifree(password_A); +} +#endif + +void peerJoinStagingRoomByChannelA +( + PEER peer, + const char * channel, + const char password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + piJoinStagingRoom(peer, NULL, channel, password, callback, param, blocking); +} +#ifdef GSI_UNICODE +void peerJoinStagingRoomByChannelW +( + PEER peer, + const unsigned short * channel, + const unsigned short password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* password_A = UCS2ToUTF8StringAlloc(password); + peerJoinStagingRoomByChannelA(peer, channel_A, password_A, callback, param, blocking); + gsifree(password_A); + gsifree(channel_A); +} +#endif + +void peerCreateStagingRoomA +( + PEER peer, + const char * name, + int maxPlayers, + const char password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + peerCreateStagingRoomWithSocketA(peer, name, maxPlayers, password, INVALID_SOCKET, 0, callback, param, blocking); +} +#ifdef GSI_UNICODE +void peerCreateStagingRoomW +( + PEER peer, + const unsigned short * name, + int maxPlayers, + const unsigned short password[PEER_PASSWORD_LEN], + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + char* name_A = UCS2ToUTF8StringAlloc(name); + char* password_A = UCS2ToUTF8StringAlloc(password); + peerCreateStagingRoomA(peer, name_A, maxPlayers, password_A, callback, param, blocking); + gsifree(password_A); + gsifree(name_A); +} +#endif + +void peerCreateStagingRoomWithSocketA +( + PEER peer, + const char * name, + int maxPlayers, + const char password[PEER_PASSWORD_LEN], + SOCKET socket, + unsigned short port, + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + PEERJoinResult result = PEERJoinFailed; + PI_OP_ID; + + PEER_CONNECTION; + + assert(name); + assert(connection->title[0]); + assert(callback); + assert(maxPlayers >= 0); + + // NULL password is the same as empty password. + /////////////////////////////////////////////// + if(!password) + password = ""; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + { + success = PEERFalse; + result = PEERNoTitleSet; + } + + // Check for a connection. + ////////////////////////// + if(success && !connection->connected) + { + success = PEERFalse; + result = PEERNoConnection; + } + + // Check if we're in a staging room. + //////////////////////////////////// + if(success && (connection->enteringRoom[StagingRoom] || connection->inRoom[StagingRoom])) + { + success = PEERFalse; + result = PEERAlreadyInRoom; + } + + // Check if we're AutoMatching. + /////////////////////////////// + assert(!peerIsAutoMatching(peer)); + if(success && peerIsAutoMatching(peer)) + { + success = PEERFalse; + result = PEERAutoMatching; + } + + // Stop hosting. + //////////////// + if(success) + piStopHosting(peer, PEERTrue); + + // Start the operation. + /////////////////////// + if(success && !piNewCreateStagingRoomOperation(peer, name, password, maxPlayers, socket, port, callback, param, opID)) + success = PEERFalse; + + // Add callback if error. + ///////////////////////// + if(!success) + piAddJoinRoomCallback(peer, PEERFalse, result, StagingRoom, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerCreateStagingRoomWithSocketW +( + PEER peer, + const unsigned short * name, + int maxPlayers, + const unsigned short password[PEER_PASSWORD_LEN], + SOCKET socket, + unsigned short port, + peerJoinRoomCallback callback, + void * param, + PEERBool blocking +) +{ + char* name_A = UCS2ToUTF8StringAlloc(name); + char* password_A = UCS2ToUTF8StringAlloc(password); + peerCreateStagingRoomWithSocketA(peer, name_A, maxPlayers, password_A, socket, port, callback, param, blocking); + gsifree(password_A); + gsifree(name_A); +} +#endif + +// Should only be called when a game report is already in progress +// Always call after creating staging room, starting reporting, +// starting automatch +////////////////////////////////////////////////////////////////////////// +/* +qr2_t peerGetReportingRecord(PEER peer) +{ + PEER_CONNECTION; + if (!connection->title[0]) + return NULL; + + if (!connection->connected) + return NULL; + + assert(connection->queryReporting || connection->autoMatchReporting); + // When we are reporting normal games, the normal qr2 record + // is returned. + if (connection->queryReporting) + { + return connection->queryReporting; + } + + + // When we are reporting automatch games, the automatch qr2 record + // is returned. + if (peerIsAutoMatching(peer) && connection->autoMatchReporting) + { + return connection->autoMatchReporting; + } + + return NULL; +} +*/ + +void peerLeaveRoomA +( + PEER peer, + RoomType roomType, + const char * reason +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Check if we're in or entering. + ///////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + // Leave. + ///////// + piLeaveRoom(peer, roomType, reason); + + // Is this an AutoMatch room? + ///////////////////////////// + if((roomType == StagingRoom) && peerIsAutoMatching(peer)) + { + // Go back to searching. + //////////////////////// + piSetAutoMatchStatus(peer, PEERSearching); + } +} +#ifdef GSI_UNICODE +void peerLeaveRoomW +( + PEER peer, + RoomType roomType, + const unsigned short* reason +) +{ + if (reason != NULL) + { + char* reason_A = UCS2ToUTF8StringAlloc(reason); + peerLeaveRoomA(peer, roomType, reason_A); + gsifree(reason_A); + } + else + peerLeaveRoomA(peer, roomType, NULL); +} +#endif + +void peerListGroupRoomsA +( + PEER peer, + const char * fields, + peerListGroupRoomsCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + PI_OP_ID; + PEER_CONNECTION; + + assert(callback); + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + success = PEERFalse; + + // Can't have a NULL fields. + //////////////////////////// + if(!fields) + fields = ""; + + // Start the listing. + ///////////////////// + if(success && !piNewListGroupRoomsOperation(peer, fields, callback, param, opID)) + success = PEERFalse; + + // Call the callback if failed. + /////////////////////////////// + if(!success) + piAddListGroupRoomsCallback(peer, PEERFalse, 0, NULL, NULL, 0, 0, 0, 0, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerListGroupRoomsW +( + PEER peer, + const unsigned short * fields, + peerListGroupRoomsCallback callback, + void * param, + PEERBool blocking +) +{ + char* fields_A = UCS2ToUTF8StringAlloc(fields); + peerListGroupRoomsA(peer, fields_A, callback, param, blocking); + gsifree(fields_A); +} +#endif + +void peerStartListingGamesA +( + PEER peer, + const unsigned char * fields, + int numFields, + const char * filter, + peerListingGamesCallback callback, + void * param +) +{ + PEERBool success; + + PEER_CONNECTION; + + assert(callback); + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Can't have an empty filter. + ////////////////////////////// + if(filter && !filter[0]) + filter = NULL; + + // Check the fields. + //////////////////// + if(!fields || (numFields <= 0)) + numFields = 0; + + // Save the callback info. + ////////////////////////// + connection->gameListCallback = callback; + connection->gameListParam = param; + + // Start the listing. + ///////////////////// + success = piSBStartListingGames(peer, fields, numFields, filter); + + // Call the callback if failed. + /////////////////////////////// + if(!success) + piAddListingGamesCallback(peer, PEERFalse, NULL, 0); +} +#ifdef GSI_UNICODE +void peerStartListingGamesW +( + PEER peer, + const unsigned char * fields, + int numFields, + const unsigned short * filter, + peerListingGamesCallback callback, + void * param +) +{ + char* filter_A = UCS2ToUTF8StringAlloc(filter); + peerStartListingGamesA(peer, fields, numFields, filter_A, callback, param); + gsifree(filter_A); +} +#endif + +void peerStopListingGames +( + PEER peer +) +{ + PEER_CONNECTION; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Stop the listing. + //////////////////// + piSBStopListingGames(peer); +} + +void peerUpdateGame +( + PEER peer, + SBServer server, + PEERBool fullUpdate +) +{ + PEER_CONNECTION; + + assert(server); + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Update the server. + // Changed 08-26-2004 + // Saad Nader + // Added force update by master server parameter + // for internal update function + ///////////////////// + piSBUpdateGame(peer, server, fullUpdate, PEERFalse, PEERFalse); +} + +// Added 08-26-2004 +// By Saad Nader +// per request of developer +//////////////////////////////////////////////////////////////////////////// +void peerUpdateGameByMaster(PEER peer, SBServer server, PEERBool fullUpdate) +{ + // obtain and check the peer connection object + PEER_CONNECTION; + + // validate server for sanity check + assert(server); + + // Check that we have set a title + if(!connection->title[0]) + return; + + // Let internal update take place via the master server + piSBUpdateGame(peer, server, fullUpdate, PEERTrue, PEERFalse); +} + +void peerUpdateGamePing(PEER peer, SBServer server) +{ + // obtain and check the peer connection object + PEER_CONNECTION; + + // validate server for sanity check + assert(server); + + // Check that we have set a title + if(!connection->title[0]) + return; + + // Let internal update take place via the master server + piSBUpdateGame(peer, server, PEERFalse, PEERFalse, PEERTrue); +} + +void peerMessageRoomA +( + PEER peer, + RoomType roomType, + const char * message, + MessageType messageType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + ASSERT_MESSAGETYPE(messageType); + + // Check for no message. + //////////////////////// + if(!message || !message[0]) + return; + + // Check that we're in this room. + ///////////////////////////////// + assert(IN_ROOM); + if(!IN_ROOM) + return; + + // Send the message. + //////////////////// + chatSendChannelMessageA(connection->chat, ROOM, message, (int)messageType); +} +#ifdef GSI_UNICODE +void peerMessageRoomW +( + PEER peer, + RoomType roomType, + const unsigned short * message, + MessageType messageType +) +{ + char* message_A = UCS2ToUTF8StringAlloc(message); + peerMessageRoomA(peer, roomType, message_A, messageType); + gsifree(message_A); +} +#endif + +void peerUTMRoomA +( + PEER peer, + RoomType roomType, + const char * command, + const char * parameters, + PEERBool authenticate +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + + // Check that we're in this room. + ///////////////////////////////// + assert(IN_ROOM); + if(!IN_ROOM) + return; + + // Send it. + /////////// + piSendChannelUTM(peer, ROOM, command, parameters, authenticate); +} +#ifdef GSI_UNICODE +void peerUTMRoomW +( + PEER peer, + RoomType roomType, + const unsigned short * command, + const unsigned short * parameters, + PEERBool authenticate +) +{ + char* command_A = UCS2ToUTF8StringAlloc(command); + char* parameters_A = UCS2ToUTF8StringAlloc(parameters); + peerUTMRoomA(peer, roomType, command_A, parameters_A, authenticate); + gsifree(parameters_A); + gsifree(command_A); +} +#endif + +void peerSetPasswordA +( + PEER peer, + RoomType roomType, + const char password[PEER_PASSWORD_LEN] +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + + // Check room type. + //////////////////// + assert(roomType == StagingRoom); + if(roomType != StagingRoom) + return; + + // NULL password is the same as empty password. + /////////////////////////////////////////////// + if(!password) + password = ""; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Check if we're in or entering. + ///////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + // Make sure we're hosting. + /////////////////////////// + assert(connection->hosting); + if(!connection->hosting) + return; + + // Set/clear the password. + ////////////////////////// + if(password[0]) + chatSetChannelPasswordA(connection->chat, ROOM, CHATTrue, password); + else + chatSetChannelPasswordA(connection->chat, ROOM, CHATFalse, "x"); + + // Set the passworded flag. + /////////////////////////// + connection->passwordedRoom = password[0]?PEERTrue:PEERFalse; + + // Send a state-changed. + //////////////////////// + piSendStateChanged(peer); +} +#ifdef GSI_UNICODE +void peerSetPasswordW +( + PEER peer, + RoomType roomType, + const unsigned short password[PEER_PASSWORD_LEN] +) +{ + char* password_A = UCS2ToUTF8StringAlloc(password); + peerSetPasswordA(peer, roomType, password_A); + gsifree(password_A); +} +#endif + +void peerSetRoomNameA +( + PEER peer, + RoomType roomType, + const char * name +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + + assert(roomType == StagingRoom); + + // NULL name is the same as empty name. + /////////////////////////////////////// + if(!name) + name = ""; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Check if we're in or entering. + ///////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + // Make sure we're hosting. + /////////////////////////// + assert(connection->hosting); + if(!connection->hosting) + return; + + // Set it. + ////////// + chatSetChannelTopicA(connection->chat, ROOM, name); +} +#ifdef GSI_UNICODE +void peerSetRoomNameW +( + PEER peer, + RoomType roomType, + const unsigned short * name +) +{ + char* name_A = UCS2ToUTF8StringAlloc(name); + peerSetRoomNameA(peer, roomType, name_A); + gsifree(name_A); +} +#endif + +const char * peerGetRoomNameA +( + PEER peer, + RoomType roomType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + assert(IN_ROOM); + if(!IN_ROOM) + return NULL; + + return NAME; +} +#ifdef GSI_UNICODE +const unsigned short * peerGetRoomNameW +( + PEER peer, + RoomType roomType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + assert(IN_ROOM); + if(!IN_ROOM) + return NULL; + + return NAME_W; +} +#endif + +const char * peerGetRoomChannelA +( + PEER peer, + RoomType roomType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + assert(IN_ROOM || ENTERING_ROOM); + if(!IN_ROOM && ! ENTERING_ROOM) + return NULL; + + return ROOM; +} +#ifdef GSI_UNICODE +const unsigned short * peerGetRoomChannelW +( + PEER peer, + RoomType roomType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + assert(IN_ROOM || ENTERING_ROOM); + if(!IN_ROOM && ! ENTERING_ROOM) + return NULL; + + return ROOM_W; +} +#endif + +PEERBool peerInRoom +( + PEER peer, + RoomType roomType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + + return IN_ROOM; +} + +void peerSetTitleRoomChannelA +( + PEER peer, + const char * channel +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Check for no channel. + //////////////////////// + if(!channel) + channel = ""; + + // Copy it. + /////////// + strzcpy(connection->titleRoomChannel, channel, PI_ROOM_MAX_LEN); +} +#ifdef GSI_UNICODE +void peerSetTitleRoomChannelW +( + PEER peer, + const unsigned short * channel +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + peerSetTitleRoomChannelA(peer, channel_A); + gsifree(channel_A); +} +#endif + +SBServer peerGetHostServer(PEER peer) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + return connection->hostServer; +} + +/************ +** PLAYERS ** +************/ +typedef struct piEnumPlayersData +{ + peerEnumPlayersCallback callback; + void * param; +} piEnumPlayersData; + +static void piEnumPlayersEnumRoomPlayersCallback +( + PEER peer, + RoomType roomType, + piPlayer * player, + int index, + void *param +) +{ + piEnumPlayersData * data = (piEnumPlayersData *)param; + const char * nick; + + int flags; + + if(player) + { + nick = player->nick; + flags = player->flags[roomType]; + } + else + { + nick = NULL; + flags = 0; + } + + // Call the callback. + ///////////////////// +#ifndef GSI_UNICODE + data->callback(peer, PEERTrue, roomType, index, nick, flags, data->param); +#else + if (nick == NULL) + data->callback(peer, PEERTrue, roomType, index, NULL, flags, data->param); + else + { + unsigned short nick_W[512]; + UTF8ToUCS2String(nick, nick_W); + data->callback(peer, PEERTrue, roomType, index, nick_W, flags, data->param); + } +#endif +} + +void peerEnumPlayers +( + PEER peer, + RoomType roomType, + peerEnumPlayersCallback callback, + void * param +) +{ + PEERBool success = PEERTrue; + piEnumPlayersData data; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + ASSERT_ROOMTYPE(roomType); + + // Check that we're in this room. + ///////////////////////////////// + assert(IN_ROOM); + if(success && !IN_ROOM) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + { + // Call the callback. + ///////////////////// + callback(peer, PEERFalse, roomType, -1, NULL, PEERFalse, param); + return; + } + + // Enumerate through the players, using a local copy. + ///////////////////////////////////////////////////// + data.callback = callback; + data.param = param; + piEnumRoomPlayers(peer, roomType, piEnumPlayersEnumRoomPlayersCallback, &data); +} + +void peerMessagePlayerA +( + PEER peer, + const char * nick, + const char * message, + MessageType messageType +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_MESSAGETYPE(messageType); + assert(nick); + assert(nick[0]); + + // Check for connection succeeded. + ////////////////////////////////// + if(!connection->connected) + return; + + // Check for no message. + //////////////////////// + if(!message || !message[0]) + return; + + // Send the message to this player. + /////////////////////////////////// + chatSendUserMessageA(connection->chat, nick, message, (int)messageType); +} +#ifdef GSI_UNICODE +void peerMessagePlayerW +( + PEER peer, + const unsigned short * nick, + const unsigned short * message, + MessageType messageType +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char* message_A = UCS2ToUTF8StringAlloc(message); + peerMessagePlayerA(peer, nick_A, message_A, messageType); + gsifree(nick_A); + gsifree(message_A); +} +#endif + +void peerUTMPlayerA +( + PEER peer, + const char * nick, + const char * command, + const char * parameters, + PEERBool authenticate +) +{ + // Send it. + /////////// + piSendPlayerUTM(peer, nick, command, parameters, authenticate); +} +#ifdef GSI_UNICODE +void peerUTMPlayerW +( + PEER peer, + const unsigned short * nick, + const unsigned short * command, + const unsigned short * parameters, + PEERBool authenticate +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char* command_A = UCS2ToUTF8StringAlloc(command); + char* parameters_A = UCS2ToUTF8StringAlloc(parameters); + peerUTMPlayerA(peer, nick_A, command_A, parameters_A, authenticate); + gsifree(parameters_A); + gsifree(command_A); + gsifree(nick_A); +} +#endif + +void peerKickPlayerA +( + PEER peer, + RoomType roomType, + const char * nick, + const char * reason +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + ASSERT_ROOMTYPE(roomType); + assert(IN_ROOM || ENTERING_ROOM); + assert(nick); + assert(nick[0]); + + // Check for connection succeeded. + ////////////////////////////////// + if(!connection->connected) + return; + + // Kick the player. + /////////////////// + chatKickUserA(connection->chat, ROOM, nick, reason); +} +#ifdef GSI_UNICODE +void peerKickPlayerW +( + PEER peer, + RoomType roomType, + const unsigned short * nick, + const unsigned short * reason +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char* reason_A = UCS2ToUTF8StringAlloc(reason); + peerKickPlayerA(peer, roomType, nick_A, reason_A); + gsifree(reason_A); + gsifree(nick_A); +} +#endif + +PEERBool peerGetPlayerPingA +( + PEER peer, + const char * nick, + int * ping +) +{ + piPlayer * player; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(nick); + assert(nick[0]); + assert(ping); + + // Get the player. + ////////////////// + player = piGetPlayer(peer, nick); + if(!player) + return PEERFalse; + + // Is it the local player? + ////////////////////////// + if(player->local) + { + *ping = 0; + } + else + { + // Check if there's a ping. + /////////////////////////// + if(!player->numPings) + return PEERFalse; + + *ping = player->pingAverage; + } + + return PEERTrue; +} +#ifdef GSI_UNICODE +PEERBool peerGetPlayerPingW +( + PEER peer, + const unsigned short * nick, + int * ping +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PEERBool result = peerGetPlayerPingA(peer, nick_A, ping); + gsifree(nick_A); + return result; +} +#endif + +PEERBool peerGetPlayersCrossPingA +( + PEER peer, + const char * nick1, + const char * nick2, + int * crossPing +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + assert(nick1); + assert(nick1[0]); + assert(nick2); + assert(nick2[0]); + assert(crossPing); + + // Do it. + ///////// + return piGetXping(peer, nick1, nick2, crossPing); +} +#ifdef GSI_UNICODE +PEERBool peerGetPlayersCrossPingW +( + PEER peer, + const unsigned short * nick1, + const unsigned short * nick2, + int * crossPing +) +{ + char* nick1_A = UCS2ToUTF8StringAlloc(nick1); + char* nick2_A = UCS2ToUTF8StringAlloc(nick2); + PEERBool result = peerGetPlayersCrossPingA(peer, nick1_A, nick2_A, crossPing); + gsifree(nick2_A); + gsifree(nick1_A); + return result; +} +#endif + +PEERBool peerPingPlayerA +( + PEER peer, + const char * nick +) +{ + piPlayer * player; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(nick); + assert(nick[0]); + + // Get the player. + ////////////////// + player = piGetPlayer(peer, nick); + if(!player) + return PEERFalse; + + // Is it the local player? + ////////////////////////// + if(player->local) + return PEERFalse; + + // Do we have the IP? + ///////////////////// + if(!player->gotIPAndProfileID) + return PEERFalse; + + // Is the player already being pinged? + ////////////////////////////////////// + if(player->waitingForPing) + return PEERTrue; + + // Set this player as a must ping. + ////////////////////////////////// + player->mustPing = PEERTrue; + + // Set this player as a one-time ping. + ////////////////////////////////////// + if(!player->inPingRoom) + player->pingOnce = PEERTrue; + + return PEERTrue; +} +#ifdef GSI_UNICODE +PEERBool peerPingPlayerW +( + PEER peer, + const unsigned short * nick +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PEERBool result = peerPingPlayerA(peer, nick_A); + gsifree(nick_A); + return result; +} +#endif + +PEERBool peerGetPlayerInfoNoWaitA +( + PEER peer, + const char * nick, + unsigned int * IP, + int * profileID +) +{ + piPlayer * player; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(nick); + + player = piGetPlayer(peer, nick); + if(!player || !player->gotIPAndProfileID) + { + const char * info; + unsigned int locIP; + int locProfileID; + + // Can we get it from chat? + /////////////////////////// + if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &locIP, &locProfileID)) + { + if(player) + piSetPlayerIPAndProfileID(peer, nick, locIP, locProfileID); + + if(IP) + *IP = locIP; + if(profileID) + *profileID = locProfileID; + + return PEERTrue; + } + return PEERFalse; + } + + if(IP) + *IP = player->IP; + if(profileID) + *profileID = player->profileID; + + return PEERTrue; +} +#ifdef GSI_UNICODE +PEERBool peerGetPlayerInfoNoWaitW +( + PEER peer, + const unsigned short * nick, + unsigned int * IP, + int * profileID +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PEERBool result = peerGetPlayerInfoNoWaitA(peer, nick_A, IP, profileID); + gsifree(nick_A); + return result; +} +#endif + +void peerGetPlayerInfoA +( + PEER peer, + const char * nick, + peerGetPlayerInfoCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + piPlayer * player; + PI_OP_ID; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + assert(nick); + assert(nick[0]); + assert(callback); + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + + // Check if chat has it. + //////////////////////// + if(player && !player->gotIPAndProfileID) + { + const char * info; + unsigned int IP; + int profileID; + + if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &IP, &profileID)) + { + piSetPlayerIPAndProfileID(peer, nick, IP, profileID); + } + } + + // See if we already have it. + ///////////////////////////// + if(player && player->gotIPAndProfileID) + { + piAddGetPlayerInfoCallback(peer, PEERTrue, nick, player->IP, player->profileID, callback, param, opID); + } + else + { + // Start an op to get it. + ///////////////////////// + if(!piNewGetPlayerInfoOperation(peer, nick, callback, param, opID)) + success = PEERFalse; + } + + // If failed, add the callback. + /////////////////////////////// + if(!success) + piAddGetPlayerInfoCallback(peer, PEERFalse, nick, 0, 0, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerGetPlayerInfoW +( + PEER peer, + const unsigned short * nick, + peerGetPlayerInfoCallback callback, + void * param, + PEERBool blocking +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + peerGetPlayerInfoA(peer, nick_A, callback, param, blocking); + gsifree(nick_A); +} +#endif + +void peerGetPlayerProfileIDA +( + PEER peer, + const char * nick, + peerGetPlayerProfileIDCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + piPlayer * player; + PI_OP_ID; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + assert(nick); + assert(nick[0]); + assert(callback); + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + + // Check if chat has it. + //////////////////////// + if(player && !player->gotIPAndProfileID) + { + const char * info; + unsigned int IP; + int profileID; + + if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &IP, &profileID)) + { + piSetPlayerIPAndProfileID(peer, nick, IP, profileID); + } + } + + // See if we already have it. + ///////////////////////////// + if(player && player->gotIPAndProfileID) + { + piAddGetPlayerProfileIDCallback(peer, PEERTrue, nick, player->profileID, callback, param, opID); + } + else + { + // Start an op to get it. + ///////////////////////// + if(!piNewGetProfileIDOperation(peer, nick, callback, param, opID)) + success = PEERFalse; + } + + // If failed, add the callback. + /////////////////////////////// + if(!success) + piAddGetPlayerProfileIDCallback(peer, PEERFalse, nick, 0, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerGetPlayerProfileIDW +( + PEER peer, + const unsigned short * nick, + peerGetPlayerProfileIDCallback callback, + void * param, + PEERBool blocking +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + peerGetPlayerProfileIDA(peer, nick_A, callback, param, blocking); + gsifree(nick_A); +} +#endif + +void peerGetPlayerIPA +( + PEER peer, + const char * nick, + peerGetPlayerIPCallback callback, + void * param, + PEERBool blocking +) +{ + PEERBool success = PEERTrue; + piPlayer * player; + PI_OP_ID; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(callback); + assert(nick); + assert(nick[0]); + assert(callback); + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + + // Check if chat has it. + //////////////////////// + if(player && !player->gotIPAndProfileID) + { + const char * info; + unsigned int IP; + int profileID; + + if(chatGetBasicUserInfoNoWaitA(connection->chat, nick, &info, NULL) && piDemangleUser(info, &IP, &profileID)) + { + piSetPlayerIPAndProfileID(peer, nick, IP, profileID); + } + } + + // Check if we already have it. + /////////////////////////////// + if(player && player->gotIPAndProfileID) + { + piAddGetPlayerIPCallback(peer, PEERTrue, nick, player->IP, callback, param, opID); + } + else + { + // Start an op to get it. + ///////////////////////// + if(!piNewGetIPOperation(peer, nick, callback, param, opID)) + success = PEERFalse; + } + + // If failed, add the callback. + /////////////////////////////// + if(!success) + piAddGetPlayerIPCallback(peer, PEERFalse, nick, 0, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerGetPlayerIPW +( + PEER peer, + const unsigned short * nick, + peerGetPlayerIPCallback callback, + void * param, + PEERBool blocking +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + peerGetPlayerIPA(peer, nick_A, callback, param, blocking); + gsifree(nick_A); +} +#endif + +PEERBool peerIsPlayerHostA +( + PEER peer, + const char * nick, + RoomType roomType +) +{ + piPlayer * player; + + PEER_CONNECTION; + PEER_CONNECTED; + + // Are we in this type of room? + /////////////////////////////// + assert(IN_ROOM); + if(!IN_ROOM) + return PEERFalse; + + // Get the player. + ////////////////// + player = piGetPlayer(peer, nick); + if(!player) + return PEERFalse; + + // If it's the local player, return the value we store. + /////////////////////////////////////////////////////// + if(player->local) + return connection->hosting; + + // Is he host? + ////////////// + return piIsPlayerHost(player); +} +#ifdef GSI_UNICODE +PEERBool peerIsPlayerHostW +( + PEER peer, + const unsigned short * nick, + RoomType roomType +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PEERBool result = peerIsPlayerHostA(peer, nick_A, roomType); + gsifree(nick_A); + return result; +} +#endif + +PEERBool peerGetPlayerFlagsA +( + PEER peer, + const char * nick, + RoomType roomType, + int * flags +) +{ + piPlayer * player; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(flags); + if(!flags) + return PEERFalse; + + // Are we in this type of room? + /////////////////////////////// + assert(IN_ROOM); + if(!IN_ROOM) + return PEERFalse; + + // Get the player. + ////////////////// + player = piGetPlayer(peer, nick); + if(!player) + return PEERFalse; + + // Is he in? + //////////// + if(!player->inRoom[roomType]) + return PEERFalse; + + // Get the flags. + ///////////////// + *flags = player->flags[roomType]; + + return PEERTrue; +} +#ifdef GSI_UNICODE +PEERBool peerGetPlayerFlagsW +( + PEER peer, + const unsigned short * nick, + RoomType roomType, + int * flags +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PEERBool result = peerGetPlayerFlagsA(peer, nick_A, roomType, flags); + gsifree(nick_A); + return result; +} +#endif + +/********* +** GAME ** +*********/ +void peerSetReady +( + PEER peer, + PEERBool ready +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Are we in a staging room? + //////////////////////////// + assert(connection->inRoom[StagingRoom]); + if(!connection->inRoom[StagingRoom]) + return; + + // Don't do anything if the state isn't changing. + ///////////////////////////////////////////////// + if(connection->ready == ready) + return; + + // Set it. + ////////// + connection->ready = ready; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + +#if 1 + // Send an old-style ready notice. + // THIS IS ONLY NEEDED FOR BACKWARDS COMPATIBILITY AND SHOULD BE REMOVED AT SOME POINT IN THE FUTURE. + //////////////////////////////////////////////////////////////////////////////////////////////////// + { + char buffer[32]; + //IN_ADDR addr; + //addr.s_addr = connection->publicIP; + strcpy(buffer, "@@@NFO \\$flags$\\"); + if(ready) + strcat(buffer, "r"); + strcat(buffer, "X\\"); // Flag to indicate this was sent by a new client. + peerMessageRoomA(peer, StagingRoom, buffer, NormalMessage); + } +#endif +} + +PEERBool peerGetReadyA +( + PEER peer, + const char * nick, + PEERBool * ready +) +{ + piPlayer * player; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(nick); + assert(nick[0]); + assert(ready); + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return PEERFalse; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return PEERFalse; + + // Are we in a staging room? + //////////////////////////// + assert(connection->inRoom[StagingRoom]); + if(!connection->inRoom[StagingRoom]) + return PEERFalse; + + // Get the player. + ////////////////// + player = piGetPlayer(peer, nick); + if(!player || !player->inRoom[StagingRoom]) + return PEERFalse; + + *ready = (PEERBool)((player->flags[StagingRoom] & PEER_FLAG_READY) != 0); + + return PEERTrue; +} +#ifdef GSI_UNICODE +PEERBool peerGetReadyW +( + PEER peer, + const unsigned short * nick, + PEERBool * ready +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PEERBool result = peerGetReadyA(peer, nick_A, ready); + gsifree(nick_A); + return result; +} +#endif + +static void piAreAllReadyEnumRoomPlayersCallback +( + PEER peer, + RoomType roomType, + piPlayer * player, + int index, + void *param +) +{ + if(player) + { + PEERBool * allReadyPtr = (PEERBool *)param; + + // If this player's not ready, set the flag. + //////////////////////////////////////////// + if(!(player->flags[StagingRoom] & PEER_FLAG_READY)) + *allReadyPtr = PEERFalse; + } + + GSI_UNUSED(peer); + GSI_UNUSED(roomType); + GSI_UNUSED(index); +} + +PEERBool peerAreAllReady +( + PEER peer +) +{ + PEERBool allReady; + + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return PEERFalse; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return PEERFalse; + + // Are we in a staging room? + //////////////////////////// + assert(connection->inRoom[StagingRoom]); + if(!connection->inRoom[StagingRoom]) + return PEERFalse; + + // Enum through all the room's players. + /////////////////////////////////////// + allReady = PEERTrue; + piEnumRoomPlayers(peer, StagingRoom, piAreAllReadyEnumRoomPlayersCallback, &allReady); + + return allReady; +} + +void peerStartGameA +( + PEER peer, + const char * message, + int reportingOptions +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Check that we're in a staging room. + ////////////////////////////////////// + assert(connection->inRoom[StagingRoom]); + if(!connection->inRoom[StagingRoom]) + return; + + // Make sure we're the host. + //////////////////////////// + assert(connection->hosting); + if(!connection->hosting) + return; + + // Change NULL messages to empty messages. + ////////////////////////////////////////// + if(!message) + message = ""; + + // Send the launch UTM. + /////////////////////// + piSendChannelUTM(peer, connection->rooms[StagingRoom], PI_UTM_LAUNCH, message, PEERFalse); + +#if 1 + // Send an old-style launch command. + // THIS IS ONLY NEEDED FOR BACKWARDS COMPATIBILITY AND SHOULD BE REMOVED AT SOME POINT IN THE FUTURE. + //////////////////////////////////////////////////////////////////////////////////////////////////// + { + char buffer[32]; + IN_ADDR addr; + addr.s_addr = connection->publicIP; + sprintf(buffer, "@@@GML %s/OLD", inet_ntoa(addr)); + peerMessageRoomA(peer, StagingRoom, buffer, NormalMessage); + } +#endif + + // We're playing. + ///////////////// + connection->playing = PEERTrue; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + + // If we're AutoMatching, we're now done. + ///////////////////////////////////////// + if(peerIsAutoMatching(peer)) + { + piSetAutoMatchStatus(peer, PEERComplete); + } + else if(connection->queryReporting) + { + // Check if we should stop GOA reporting. + ///////////////////////////////////////// + if(reportingOptions & PEER_STOP_REPORTING) + { + // Stop. + //////// + piStopReporting(peer); + } + else + { + // Set the options. + /////////////////// + connection->reportingOptions = reportingOptions; + + // Send a state-changed. + //////////////////////// + piSendStateChanged(peer); + } + } +} +#ifdef GSI_UNICODE +void peerStartGameW +( + PEER peer, + const unsigned short * message, + int reportingOptions +) +{ + char* message_A = UCS2ToUTF8StringAlloc(message); + peerStartGameA(peer, message_A, reportingOptions); + gsifree(message_A); +} +#endif + +PEERBool peerStartReporting +( + PEER peer +) +{ + return peerStartReportingWithSocket(peer, INVALID_SOCKET, 0); +} + +PEERBool peerStartReportingWithSocket +( + PEER peer, + SOCKET socket, + unsigned short port +) +{ + PEER_CONNECTION; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return PEERFalse; + + // Start. + ///////// + if(!piStartReporting(peer, socket, port)) + return PEERFalse; + + return PEERTrue; +} + +void peerStartPlaying +( + PEER peer +) +{ + PEER_CONNECTION; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Mark us as playing. + ////////////////////// + connection->playing = PEERTrue; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); +} + +PEERBool peerIsPlaying +( + PEER peer +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return PEERFalse; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return PEERFalse; + + return connection->playing; +} + +void peerStopGame +( + PEER peer +) +{ + PEER_CONNECTION; + + // We're done playing. + ////////////////////// + connection->playing = PEERFalse; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + + // Are we reporting? + //////////////////// + if(connection->queryReporting) + { + // Are we still in the staging room? + //////////////////////////////////// + if(connection->inRoom[StagingRoom]) + piSendStateChanged(peer); + else + piStopReporting(peer); + } +} + +void peerStateChanged +( + PEER peer +) +{ + PEER_CONNECTION; + + // We should be reporting. + ////////////////////////// + assert(connection->queryReporting); + + // Send a state-changed. + //////////////////////// + piSendStateChanged(peer); +} + +void piSendChannelUTM +( + PEER peer, + const char * channel, + const char * command, + const char * parameters, + PEERBool authenticate +) +{ + char buffer[512]; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(channel && channel[0]); + assert(command && command[0]); + assert(parameters); + + // Check for connection succeeded. + ////////////////////////////////// + if(!connection->connected) + return; + + // Check for no channel. + //////////////////////// + if(!channel || !channel[0]) + return; + + // Check for no command. + //////////////////////// + if(!command || !command[0]) + return; + + // Check for no parameters. + /////////////////////////// + if(!parameters) + parameters = ""; + + // Make sure this UTM isn't too long. + ///////////////////////////////////// + if((strlen(command) + strlen(parameters) + 5) > sizeof(buffer)) + return; + + // Form the message. + //////////////////// + sprintf(buffer, "%s %s", command, parameters); + + // Send it. + /////////// + chatSendChannelMessageA(connection->chat, channel, buffer, authenticate?CHAT_ATM:CHAT_UTM); +} + +void piSendPlayerUTM +( + PEER peer, + const char * nick, + const char * command, + const char * parameters, + PEERBool authenticate +) +{ + char buffer[512]; + + PEER_CONNECTION; + PEER_CONNECTED; + + assert(nick && nick[0]); + assert(command && command[0]); + assert(parameters); + + // Check for connection succeeded. + ////////////////////////////////// + if(!connection->connected) + return; + + // Check for no nick. + ///////////////////// + if(!nick || !nick[0]) + return; + + // Check for no command. + //////////////////////// + if(!command || !command[0]) + return; + + // Check for no parameters. + /////////////////////////// + if(!parameters) + parameters = ""; + + // Make sure this UTM isn't too long. + ///////////////////////////////////// + if((strlen(command) + strlen(parameters) + 5) > sizeof(buffer)) + return; + + // Form the message. + //////////////////// + sprintf(buffer, "%s %s", command, parameters); + + // Send it. + /////////// + chatSendUserMessageA(connection->chat, nick, buffer, authenticate?CHAT_ATM:CHAT_UTM); +} + +/********* +** KEYS ** +*********/ +void peerSetGlobalKeysA +( + PEER peer, + int num, + const char ** keys, + const char ** values +) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + assert(keys); + assert(values); + assert(num > 0); + + // Check for connection succeeded. + ////////////////////////////////// + if(!connection->connected) + return; + + // Set the keys. + //////////////// + chatSetGlobalKeysA(connection->chat, num, keys, values); +} +#ifdef GSI_UNICODE +void peerSetGlobalKeysW +( + PEER peer, + int num, + const unsigned short ** keys, + const unsigned short ** values +) +{ + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = UCS2ToUTF8StringArrayAlloc(values, num); + int i; + peerSetGlobalKeysA(peer, num, (const char**)keys_A, (const char**)values_A); + for (i=0; iconnected) + return; + + if(!nick || !nick[0]) + nick = connection->nick; + + assert(callback); + + // Start the operation. + /////////////////////// + if(!piNewGetGlobalKeysOperation(peer, nick, num, keys, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddGetGlobalKeysCallback(peer, PEERFalse, nick, 0, NULL, NULL, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerGetPlayerGlobalKeysW +( + PEER peer, + const unsigned short * nick, + int num, + const unsigned short ** keys, + peerGetGlobalKeysCallback callback, + void * param, + PEERBool blocking +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + int i; + peerGetPlayerGlobalKeysA(peer, nick_A, num, (const char**)keys_A, callback, param, blocking); + gsifree(nick_A); + for (i=0; iconnected) + return; + + ASSERT_ROOMTYPE(roomType); + assert(callback); + + // Check that we're in or entering this room. + ///////////////////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + // Start the operation. + /////////////////////// + if(!piNewGetGlobalKeysOperation(peer, ROOM, num, keys, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddGetGlobalKeysCallback(peer, PEERFalse, "", 0, NULL, NULL, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerGetRoomGlobalKeysW +( + PEER peer, + RoomType roomType, + int num, + const unsigned short ** keys, + peerGetGlobalKeysCallback callback, + void * param, + PEERBool blocking +) +{ + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + int i; + peerGetRoomGlobalKeysA(peer, roomType, num, (const char**)keys_A, callback, param, blocking); + for (i=0; i 0); + ASSERT_ROOMTYPE(roomType); + + // Check for connection succeeded. + ////////////////////////////////// + if(!connection->connected) + return; + + // Check that we're in or entering this room. + ///////////////////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + // Set the keys. + //////////////// + chatSetChannelKeysA(connection->chat, ROOM, nick, num, keys, values); +} +#ifdef GSI_UNICODE +void peerSetRoomKeysW +( + PEER peer, + RoomType roomType, + const unsigned short * nick, + int num, + const unsigned short ** keys, + const unsigned short ** values +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = UCS2ToUTF8StringArrayAlloc(values, num); + int i; + peerSetRoomKeysA(peer, roomType, nick_A, num, (const char**)keys_A, (const char**)values_A); + gsifree(nick_A); + for (i=0; iconnected) + return; + + ASSERT_ROOMTYPE(roomType); + assert(callback); + + // Check that we're in or entering this room. + ///////////////////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + // Start the operation. + /////////////////////// + if(!piNewGetRoomKeysOperation(peer, roomType, nick, num, keys, callback, param, opID)) + success = PEERFalse; + + // Check for failure. + ///////////////////// + if(!success) + piAddGetRoomKeysCallback(peer, PEERFalse, roomType, nick, 0, NULL, NULL, callback, param, opID); + + PI_DO_BLOCKING; +} +#ifdef GSI_UNICODE +void peerGetRoomKeysW +( + PEER peer, + RoomType roomType, + const unsigned short * nick, + int num, + const unsigned short ** keys, + peerGetRoomKeysCallback callback, + void * param, + PEERBool blocking +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + int i; + peerGetRoomKeysA(peer, roomType, nick_A, num, (const char**)keys_A, callback, param, blocking); + gsifree(nick_A); + for (i=0; i= 2); + + // Check the params. + //////////////////// + if(!filter) + filter = ""; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + goto failed; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + goto failed; + + // Check for an AutoMatch in progress. + ////////////////////////////////////// + assert(!peerIsAutoMatching(peer)); + if(peerIsAutoMatching(peer)) + goto failed; + + // If entering a staging room, leave. + ///////////////////////////////////// + if(connection->enteringRoom[StagingRoom]) + piLeaveRoom(peer, StagingRoom, ""); + + // Stop any reporting. + ////////////////////// + piStopReporting(peer); + + // Stop any game listing. + ///////////////////////// + piSBStopListingGames(peer); + + // Store some parameters. + ///////////////////////// + connection->maxPlayers = maxPlayers; + connection->autoMatchFilter = goastrdup(filter); + if(!connection->autoMatchFilter) + goto failed; + + // Initialize the AutoMatch status. + /////////////////////////////////// + connection->autoMatchStatus = PEERFailed; + + // Clear the SB and QR failed flags. + //////////////////////////////////// + connection->autoMatchSBFailed = PEERFalse; + connection->autoMatchQRFailed = PEERFalse; + + // Start the AutoMatch. + /////////////////////// + if(!piNewAutoMatchOperation(peer, socket, port, statusCallback, rateCallback, param, opID)) + { + gsifree(connection->autoMatchFilter); + goto failed; + } + + PI_DO_BLOCKING; + + return; + +failed: + // Failed to start the attempt. + /////////////////////////////// + connection->autoMatchStatus = PEERFailed; + piAddAutoMatchStatusCallback(peer); +} +#ifdef GSI_UNICODE +void peerStartAutoMatchWithSocketW +( + PEER peer, + int maxPlayers, + const unsigned short * filter, + SOCKET socket, + unsigned short port, + peerAutoMatchStatusCallback statusCallback, + peerAutoMatchRateCallback rateCallback, + void * param, + PEERBool blocking +) +{ + char* filter_A = UCS2ToUTF8StringAlloc(filter); + peerStartAutoMatchWithSocketA(peer, maxPlayers, filter_A, socket, port, statusCallback, rateCallback, param, blocking); + gsifree(filter_A); +} +#endif + +void peerStopAutoMatch(PEER peer) +{ + PEER_CONNECTION; + PEER_CONNECTED; + + // Check for a title. + ///////////////////// + if(!connection->title[0]) + return; + + // Check for a connection. + ////////////////////////// + if(!connection->connected) + return; + + // Stop the AutoMatch. + ////////////////////// + piStopAutoMatch(peer); +} + +PEERBool peerIsAutoMatching(PEER peer) +{ + PEER_CONNECTION; + + // If the status is Failed or Done, then we're not matching. + //////////////////////////////////////////////////////////// + if(connection->autoMatchStatus == PEERFailed) + return PEERFalse; + if(connection->autoMatchStatus == PEERComplete) + return PEERFalse; + + return PEERTrue; +} + +PEERAutoMatchStatus peerGetAutoMatchStatus(PEER peer) +{ + PEER_CONNECTION; + + return connection->autoMatchStatus; +} + +void peerSetStagingRoomMaxPlayers(PEER peer, int maxPlayers) +{ + PEER_CONNECTION; + GS_ASSERT(connection->inRoom[StagingRoom]); + if (connection->inRoom[StagingRoom]) + { + // Let QR2 report the new max players, and set the new chat channel limit + connection->maxPlayers = maxPlayers; + piSendStateChanged(peer); + + chatSetChannelLimitA(connection->chat, connection->rooms[StagingRoom], maxPlayers); + } +} diff --git a/xrGameSpy/gamespy/Peer/peerMain.h b/xrGameSpy/gamespy/Peer/peerMain.h new file mode 100644 index 00000000000..5b459f8148b --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerMain.h @@ -0,0 +1,223 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERMAIN_H_ +#define _PEERMAIN_H_ + +/************* +** INCLUDES ** +*************/ +#include "peer.h" +#include "../darray.h" +#include "../hashtable.h" +#include "../pinger/pinger.h" +#include "../Chat/chatASCII.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +#if 0 +piConnection * connection; // This is to fool Visual Assist. +#endif + +/************ +** DEFINES ** +************/ +#define PI_ROOM_MAX_LEN 257 +#define PI_NICK_MAX_LEN 64 +#define PI_NAME_MAX_LEN 512 +#define PI_TITLE_MAX_LEN 32 +#define PI_AWAY_MAX_LEN 128 +#define PI_SB_LEN 32 // from sb_internal.h + +#ifndef PI_CHAT_PING_TIME + #ifndef _NITRO + #define PI_CHAT_PING_TIME (5 * 60000) + #else + #define PI_CHAT_PING_TIME (20000) + #endif +#endif + +#define PEER_CONNECTION piConnection * connection;\ + assert(peer);\ + connection = (piConnection *)peer;\ + GSI_UNUSED(connection); + +#define ASSERT_ROOMTYPE(type) assert((type == TitleRoom) || (type == GroupRoom) || (type == StagingRoom)) +#define ASSERT_MESSAGETYPE(type) assert((type == NormalMessage) || (type == ActionMessage) || (type == NoticeMessage)) + +#define ROOM (connection->rooms[roomType]) +#define ROOM_W (connection->rooms_W[roomType]) +#define ROOMS (connection->rooms) +#define NAME (connection->names[roomType]) +#define NAME_W (connection->names_W[roomType]) +#define NAMES (connection->names) +#define IN_ROOM (connection->inRoom[roomType]) +#define ENTERING_ROOM (connection->enteringRoom[roomType]) + +#define strzcpy(dest, src, len) { strncpy(dest, src, (len)); (dest)[(len) - 1] = '\0'; } +#define strzcat(dest, src, len) { strncat(dest, src, (len) - strlen(dest)); (dest)[(len) - 1] = '\0'; } + +#if defined(_PS3) +#define PEERCBType void* // Note: ANSI function pointers should int rather than void* +#else +#define PEERCBType int // Note: ANSI function pointers should int rather than void* +#endif + +/********** +** TYPES ** +**********/ +typedef struct piConnection +{ + // Chat. + //////// + CHAT chat; // The chat connection. + char nick[PI_NICK_MAX_LEN]; // The local nick. + PEERBool connecting; + PEERBool connected; + peerNickErrorCallback nickErrorCallback; + gsi_time lastChatPing; + + // Game. + //////// + unsigned int publicIP; + unsigned int privateIP; + int profileID; + char title[PI_TITLE_MAX_LEN]; + +#ifdef GSI_UNICODE + unsigned short title_W[PI_TITLE_MAX_LEN]; + unsigned short nick_W[PI_NICK_MAX_LEN]; + unsigned short names_W[NumRooms][PI_NAME_MAX_LEN]; + unsigned short rooms_W[NumRooms][PI_ROOM_MAX_LEN]; +#endif + + // Rooms. + ///////// + char rooms[NumRooms][PI_ROOM_MAX_LEN]; + PEERBool enteringRoom[NumRooms]; + PEERBool inRoom[NumRooms]; + char names[NumRooms][PI_NAME_MAX_LEN]; + int oldFlags[NumRooms]; + int groupID; + char titleRoomChannel[PI_ROOM_MAX_LEN]; + PEERBool stayInTitleRoom; + + // Players. + /////////// + HashTable players; + int numPlayers[NumRooms]; + PEERBool alwaysRequestPlayerInfo; + + // Ping. + //////// + PEERBool doPings; + int lastPingTimeMod; + PEERBool pingRoom[NumRooms]; + PEERBool xpingRoom[NumRooms]; + HashTable xpings; + unsigned int lastXpingSend; + + // Reporting. + ///////////// + qr2_t queryReporting; + char qrSecretKey[64]; // i ripped the length from qr2.c + PEERBool natNegotiate; + int reportingOptions; + int reportingGroupID; // might be different than groupID if left group room after started reporting + + // Hosting. + /////////// + PEERBool hosting; + PEERBool playing; + int maxPlayers; + PEERBool passwordedRoom; + + // Staging room. + //////////////// + SBServer hostServer; + PEERBool ready; + + // SB. + ////// + char sbName[PI_SB_LEN]; + char sbSecretKey[PI_SB_LEN]; + int sbGameVersion; + int sbMaxUpdates; + PEERBool sbInitialized; + SBServerList gameList; + SBServerList groupList; + SBQueryEngine gameEngine; + peerListingGamesCallback gameListCallback; + void * gameListParam; + PEERBool initialGameList; + struct piOperation * listingGroupsOperation; + + // ID. + ////// + int nextID; + + // Operations. + ////////////// + DArray operationList; + int operationsStarted; + int operationsFinished; + + // Callbacks. + ///////////// + PEERCallbacks callbacks; + DArray callbackList; + int callbacksQueued; + int callbacksCalled; + int callbackDepth; + + // Away. + //////// + PEERBool away; + char awayReason[PI_AWAY_MAX_LEN]; + + // Keys. + //////// + HashTable globalWatchKeys[NumRooms]; + HashTable roomWatchKeys[NumRooms]; + HashTable globalWatchCache; + HashTable roomWatchCache[NumRooms]; + + // AutoMatch. + ///////////// + PEERAutoMatchStatus autoMatchStatus; + SBServerList autoMatchList; + SBQueryEngine autoMatchEngine; + PEERBool autoMatchBrowsing; + struct piOperation * autoMatchOperation; + qr2_t autoMatchReporting; + char * autoMatchFilter; + PEERBool autoMatchSBFailed; + PEERBool autoMatchQRFailed; + + // Misc. + //////// + PEERBool disconnect; + PEERBool shutdown; +} piConnection; + +void piSendChannelUTM(PEER peer, const char * channel, const char * command, const char * parameters, PEERBool authenticate); +void piSendPlayerUTM(PEER peer, const char * nick, const char * command, const char * parameters, PEERBool authenticate); +PEERBool piConnectTitle(PEER peer); +void piDisconnectTitle(PEER peer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerMangle.c b/xrGameSpy/gamespy/Peer/peerMangle.c new file mode 100644 index 00000000000..dbe02426de1 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerMangle.c @@ -0,0 +1,292 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/* +** +** Title Room +** #GSP! +** +** Group Room +** #GPG! +** +** Staging Room +** #GSP!!XX +** +** User +** XX| +** +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include "peerMain.h" +#include "peerMangle.h" + +/************ +** DEFINES ** +************/ +#define PI_SEPERATOR "!" + +/************ +** GLOBALS ** +************/ +PEERBool piOldMangleStagingRooms; +static const char digits_hex[] = "0123456789abcdef"; +static const char digits_crypt[] = "aFl4uOD9sfWq1vGp"; +static const char new_digits_crypt[] = "qJ1h4N9cP3lzD0Ka"; +static const unsigned int ip_xormask = 0xc3801dc7; +static char cryptbuffer[32]; + +/************** +** FUNCTIONS ** +**************/ +//originally ripped from Aphex's ipencode.h +static const char * EncodeIP(unsigned int ip, char * buffer, PEERBool newCrypt) +{ + const char * crypt = newCrypt?new_digits_crypt:digits_crypt; + int i; + char * str; + int digit_idx; + + // XOR the IP address. + ip ^= ip_xormask; + + // Print out the ip addr in hex form. + sprintf(cryptbuffer, "%08x", ip); + + // Translate chars in positions 0 through 7 from hex digits to "crypt" digits. + for(i = 0 ; i < 8 ; i++) + { + str = strchr(digits_hex, cryptbuffer[i]); + digit_idx = (str - digits_hex); + + if((digit_idx < 0) || (digit_idx > 15)) // sanity check + { + strcpy(cryptbuffer, "14saFv19"); // equivalent to 0.0.0.0 + break; + } + + cryptbuffer[i] = crypt[digit_idx]; + } + + if(buffer) + { + strcpy(buffer, cryptbuffer); + return buffer; + } + + return cryptbuffer; +} + +//originally ripped from Aphex's ipencode.h +static unsigned int DecodeIP(const char * buffer, PEERBool newCrypt) +{ + const char * crypt = newCrypt?new_digits_crypt:digits_crypt; + unsigned int ip; + char * str; + int digit_idx; + int i; + + if(!buffer) + return 0; + + // Translate chars from hex digits to "crypt" digits. + for(i = 0 ; i < 8 ; i++) + { + str = strchr(crypt, buffer[i]); + digit_idx = (str - crypt); + + if((digit_idx < 0) || (digit_idx > 15)) + return 0; + + cryptbuffer[i] = digits_hex[digit_idx]; + } + + // Cap the buffer. + cryptbuffer[i] = '\0'; + + // Convert the string to an unsigned long (the XORd ip addr). + sscanf(cryptbuffer, "%x", &ip); + + // re-XOR the IP address. + ip ^= ip_xormask; + + return ip; +} + +static const char * piStagingRoomHash(unsigned int publicIP, unsigned int privateIP, unsigned short port, char * buffer) +{ + unsigned int result; + + publicIP = ntohl(publicIP); + privateIP = ntohl(privateIP); + + result = (((privateIP >> 24) & 0xFF) | ((privateIP >> 8) & 0xFF00) | ((privateIP << 8) & 0xFF0000) | ((privateIP << 24) & 0xFF000000)); + result ^= publicIP; + result ^= (port | (port << 16)); + + return EncodeIP(result, buffer, PEERTrue); +} + +void piMangleTitleRoom +( + char buffer[PI_ROOM_MAX_LEN], + const char * title +) +{ + assert(buffer); + assert(title); + assert(title[0]); + + sprintf(buffer, "#GSP" PI_SEPERATOR "%s", + title); +} + +void piMangleGroupRoom +( + char buffer[PI_ROOM_MAX_LEN], + int groupID +) +{ + assert(buffer); + assert(groupID); + + sprintf(buffer, "#GPG" PI_SEPERATOR "%d", groupID); +} + +void piMangleStagingRoom +( + char buffer[PI_ROOM_MAX_LEN], + const char * title, + unsigned int publicIP, + unsigned int privateIP, + unsigned short privatePort +) +{ + char encodeBuffer[9]; + int borderChar; + + assert(buffer); + assert(title); + assert(title[0]); + + if(piOldMangleStagingRooms) + { + EncodeIP(publicIP, encodeBuffer, PEERFalse); + borderChar = 'X'; + } + else + { + piStagingRoomHash(publicIP, privateIP, privatePort, encodeBuffer); + borderChar = 'M'; + } + + sprintf(buffer, "#GSP" PI_SEPERATOR "%s" PI_SEPERATOR "%c%s%c", title, borderChar, encodeBuffer, borderChar); +} + +void piMangleUser +( + char buffer[PI_USER_MAX_LEN], + unsigned int IP, + int profileID +) +{ + assert(buffer); + assert(IP != 0); + assert(profileID >= 0); + + sprintf(buffer, "X%sX|%d", + EncodeIP(IP, NULL, PEERFalse), + profileID); +} + +PEERBool piDemangleUser +( + const char buffer[PI_USER_MAX_LEN], + unsigned int * IP, + int * profileID +) +{ + unsigned int decodedIP; + int scannedProfileID; + + assert(buffer); + if(buffer == NULL) + return PEERFalse; + + // Check the length. + //////////////////// + if(strlen(buffer) < 12) + return PEERFalse; + + // Check for the Xs. + //////////////////// + if((buffer[0] != 'X') && (buffer[9] != 'X')) + return PEERFalse; + + // Get the IP. + ////////////// + decodedIP = DecodeIP(buffer + 1, PEERFalse); + if(!decodedIP) + return PEERFalse; + + // Check the profile ID. + //////////////////////// + if(!isdigit(buffer[11])) + return PEERFalse; + + // Get the pid. + /////////////// + scannedProfileID = atoi(buffer + 11); + + // Check what is wanted. + //////////////////////// + if(IP) + *IP = decodedIP; + if(profileID) + *profileID = scannedProfileID; + + + return PEERTrue; +} + +void piMangleIP +( + char buffer[11], + unsigned int IP +) +{ + assert(buffer); + assert(IP != 0); + + EncodeIP(IP, buffer + 1, PEERFalse); + buffer[0] = 'X'; + buffer[9] = 'X'; + buffer[10] = '\0'; +} + +unsigned int piDemangleIP +( + const char buffer[11] +) +{ + assert(buffer); + if(!buffer) + return 0; + + // Check for the Xs. + //////////////////// + if((buffer[0] != 'X') && (buffer[9] != 'X')) + return 0; + + return DecodeIP(buffer + 1, PEERFalse); +} diff --git a/xrGameSpy/gamespy/Peer/peerMangle.h b/xrGameSpy/gamespy/Peer/peerMangle.h new file mode 100644 index 00000000000..4d826b60712 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerMangle.h @@ -0,0 +1,46 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERMANGLE_H_ +#define _PEERMANGLE_H_ + +/************* +** INCLUDES ** +*************/ +#include "peer.h" +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/************ +** DEFINES ** +************/ +#define PI_USER_MAX_LEN 128 + +/************** +** FUNCTIONS ** +**************/ +void piMangleTitleRoom(char buffer[PI_ROOM_MAX_LEN], const char * title); +void piMangleGroupRoom(char buffer[PI_ROOM_MAX_LEN], int groupID); +void piMangleStagingRoom(char buffer[PI_ROOM_MAX_LEN], const char * title, + unsigned int publicIP, unsigned int privateIP, unsigned short privatePort); +void piMangleUser(char buffer[PI_USER_MAX_LEN], unsigned int IP, int profileID); +PEERBool piDemangleUser(const char buffer[PI_USER_MAX_LEN], unsigned int * IP, int * profileID); +void piMangleIP(char buffer[11], unsigned int IP); +unsigned int piDemangleIP(const char buffer[11]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerOperations.c b/xrGameSpy/gamespy/Peer/peerOperations.c new file mode 100644 index 00000000000..975e09d60e3 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerOperations.c @@ -0,0 +1,1844 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include +#include "peerOperations.h" +#include "peerCallbacks.h" +#include "peerGlobalCallbacks.h" +#include "peerMangle.h" +#include "peerRooms.h" +#include "peerPlayers.h" +#include "peerKeys.h" +#include "peerSB.h" +#include "peerHost.h" +#include "peerAutoMatch.h" +#include "peerQR.h" +#include "../md5.h" + +/************ +** DEFINES ** +************/ +#define PI_CHAT_SERVER_ADDRESS "peerchat." GSI_DOMAIN_NAME +#define PI_CHAT_SERVER_PORT 6667 + +#define PEER_CONNECTION_OP piOperation * operation = (piOperation *)param;\ + piConnection * connection = NULL;\ + PEER peer = NULL;\ + assert(operation && operation->peer);\ + if(operation && operation->peer)\ + peer = operation->peer;\ + connection = (piConnection *)peer;\ + GSI_UNUSED(connection); +#if 0 +// for Visual Assist +PEER peer; +piOperation * operation; +#endif + +/********** +** TYPES ** +**********/ +typedef struct piOperationContainer +{ + piOperation * operation; +} piOperationContainer; + +/************** +** FUNCTIONS ** +**************/ +#ifndef GSI_UNICODE +#define piGetGlobalKeysCallback piGetGlobalKeysCallbackA +#define piGetChannelKeysCallback piGetChannelKeysCallbackA +#define piGetPlayerInfoCallback piGetPlayerInfoCallbackA +#define piConnectNickErrorCallback piConnectNickErrorCallbackA +#define piConnectFillInUserCallback piConnectFillInUserCallbackA +#define piCreateStagingRoomEnumUsersCallback piCreateStagingRoomEnumUsersCallbackA +#define piCreateStagingRoomEnterChannelCallback piCreateStagingRoomEnterChannelCallbackA +#define piJoinRoomEnumUsersCallback piJoinRoomEnumUsersCallbackA +#define piJoinRoomEnterChannelCallback piJoinRoomEnterChannelCallbackA +#define piChangeNickCallback piChangeNickCallbackA +#define piAuthenticateCDKeyCallback piAuthenticateCDKeyCallbackA +#else +#define piGetGlobalKeysCallback piGetGlobalKeysCallbackW +#define piGetChannelKeysCallback piGetChannelKeysCallbackW +#define piGetPlayerInfoCallback piGetPlayerInfoCallbackW +#define piConnectNickErrorCallback piConnectNickErrorCallbackW +#define piConnectFillInUserCallback piConnectFillInUserCallbackW +#define piCreateStagingRoomEnumUsersCallback piCreateStagingRoomEnumUsersCallbackW +#define piCreateStagingRoomEnterChannelCallback piCreateStagingRoomEnterChannelCallbackW +#define piJoinRoomEnumUsersCallback piJoinRoomEnumUsersCallbackW +#define piJoinRoomEnterChannelCallback piJoinRoomEnterChannelCallbackW +#define piChangeNickCallback piChangeNickCallbackW +#define piAuthenticateCDKeyCallback piAuthenticateCDKeyCallbackW +#endif + +static void piOperationsListFree(void *elem1) +{ + piOperationContainer * container = (piOperationContainer *)elem1; + piOperation * operation; + + assert(container); + assert(container->operation); + + operation = container->operation; + + // Free the name. + ///////////////// + gsifree(operation->name); + + // Free the password. + ///////////////////// + gsifree(operation->password); + + // Free the user data. + ////////////////////// + gsifree(operation->data); + + // Close the socket if needed. + ////////////////////////////// + if(operation->socketClose) + { + closesocket(operation->socket); + SocketShutDown(); + } + + // Free the operation. + ////////////////////// + gsifree(operation); +} + +PEERBool piOperationsInit(PEER peer) +{ + PEER_CONNECTION; + + assert(!connection->operationList); + + // Init data. + ///////////// + connection->operationsStarted = 0; + connection->operationsFinished = 0; + + // Init the list. + ///////////////// + connection->operationList = ArrayNew(sizeof(piOperationContainer), 0, piOperationsListFree); + if(!connection->operationList) + return PEERFalse; + + return PEERTrue; +} + +void piOperationsReset(PEER peer) +{ + PEER_CONNECTION; + + // Clear the list. + ////////////////// + if(connection->operationList) + ArrayClear(connection->operationList); + + // Clear the listingGroupsOperation + if (connection->listingGroupsOperation) + connection->listingGroupsOperation = NULL; +} + +void piOperationsCleanup(PEER peer) +{ + PEER_CONNECTION; + + // Cleanup the list. + //////////////////// + if(connection->operationList) + ArrayFree(connection->operationList); + connection->operationList = NULL; +} + +void piRemoveOperation(PEER peer, piOperation * operation) +{ + piOperationContainer * container; + piOperation * op; + int i; + int count; + + PEER_CONNECTION; + + // Make sure there is a list. + ///////////////////////////// + if(!connection->operationList) + return; + + // Loop through the operations. + /////////////////////////////// + count = ArrayLength(connection->operationList); + for(i = 0 ; i < count ; i++) + { + // Get the operation. + ///////////////////// + container = (piOperationContainer *)ArrayNth(connection->operationList, i); + op = container->operation; + + // Check the op. + //////////////// + if(op == operation) + { + // Remove it. + ///////////// + ArrayDeleteAt(connection->operationList, i); + + // One more finished. + ///////////////////// + connection->operationsFinished++; + + return; + } + } +} + +PEERBool piIsOperationFinished(PEER peer, int opID) +{ + piOperationContainer * container; + piOperation * op; + int i; + int count; + + PEER_CONNECTION; + + // Make sure there is a list. + ///////////////////////////// + if(!connection->operationList) + return PEERTrue; + + // Loop through the operations. + /////////////////////////////// + count = ArrayLength(connection->operationList); + for(i = 0 ; i < count ; i++) + { + // Get the operation. + ///////////////////// + container = (piOperationContainer *)ArrayNth(connection->operationList, i); + op = container->operation; + + // Check the ID. + //////////////// + if(op->ID == opID) + return PEERFalse; + } + + return PEERTrue; +} + +void piCancelJoinOperation(PEER peer, RoomType roomType) +{ + piOperationContainer * container; + piOperation * operation; + int i; + int count; + + PEER_CONNECTION; + + // Make sure there is a list. + ///////////////////////////// + if(!connection->operationList) + return; + + // Loop through the operations. + /////////////////////////////// + count = ArrayLength(connection->operationList); + for(i = 0 ; i < count ; i++) + { + // Get the operation. + ///////////////////// + container = (piOperationContainer *)ArrayNth(connection->operationList, i); + operation = container->operation; + + // Is it a join or create? + ////////////////////////// + if((operation->type == PI_JOIN_ROOM_OPERATION) || (operation->type == PI_CREATE_ROOM_OPERATION)) + { + // Is it the same room? + /////////////////////// + if(operation->roomType == roomType) + { + // Cancel the operation. + //////////////////////// + operation->cancel = PEERTrue; + + return; + } + } + } +} + +int piGetNextID(PEER peer) +{ + int ID; + + PEER_CONNECTION; + + // Get the ID. + ////////////// + ID = connection->nextID; + + // Increment. + ///////////// + connection->nextID++; + if(connection->nextID < 0) + connection->nextID = 0; + + return ID; +} + +static piOperation * piAddOperation +( + PEER peer, + piOperationType type, + void * data, + PEERCBType callback, + void * callbackParam, + int opID +) +{ + piOperation * operation; + piOperationContainer container; + + PEER_CONNECTION; + + //assert(type >= 0); + assert(type < PI_NUM_OPERATION_TYPES); + + // Make sure there is a list. + ///////////////////////////// + if(!connection->operationList) + return NULL; + + // Alloc the operaiton. + /////////////////////// + operation = (piOperation *)gsimalloc(sizeof(piOperation)); + if(!operation) + return NULL; + + // Fill in the operation. + ///////////////////////// + memset(operation, 0, sizeof(piOperation)); + operation->peer = peer; + operation->type = type; + operation->data = data; + operation->ID = opID; + operation->callback = callback; + operation->callbackParam = callbackParam; + operation->name = NULL; + operation->cancel = PEERFalse; + + // Add the operation to the list. + ///////////////////////////////// + container.operation = operation; + ArrayAppend(connection->operationList, &container); + + // One more op. + /////////////// + connection->operationsStarted++; + + return operation; +} + +/*************** +** OPERATIONS ** +***************/ + +/* Connect. +**********/ +static void piConnectConnectCallback +( + CHAT chat, + CHATBool success, + int failureReason, + void *param +) +{ + PEER_CONNECTION_OP; + + // If successful, try and do the connect title stuff. + ///////////////////////////////////////////////////// + if(success) + { + if(!piConnectTitle(peer)) + { + piDisconnectTitle(peer); + success = CHATFalse; + } + } + + // Connection attempt finished. + /////////////////////////////// + connection->connecting = PEERFalse; + connection->connected = (PEERBool)success; + + if(success) + { + const char * nick; + + // Setup server pinging. + //////////////////////// + connection->lastChatPing = current_time(); + + // Check the nick. + ////////////////// + nick = chatGetNickA(chat); + if(strcasecmp(connection->nick, nick) != 0) + { + strcpy(connection->nick, nick); + +#ifdef GSI_UNICODE + UTF8ToUCS2String(connection->nick, connection->nick_W); +#endif + } + } + else + { + // Set the disconnect flag. + /////////////////////////// + connection->disconnect = PEERTrue; + } + + // Add the callback. + //////////////////// + piAddConnectCallback(peer, (PEERBool)success, failureReason, (peerConnectCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); +} + +static void piConnectNickErrorCallbackA +( + CHAT chat, + int type, + const char * nick, + int numSuggestedNicks, + const char ** suggestedNicks, + void *param +) +{ + PEER_CONNECTION_OP; + + // Add the peer callback. + ///////////////////////// + piAddNickErrorCallback(peer, type, nick, numSuggestedNicks, suggestedNicks, operation->callbackParam, operation->ID); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piConnectNickErrorCallbackW +( + CHAT chat, + int type, + const unsigned short * nick, + int numSuggestedNicks, + const unsigned short ** suggestedNicks, + void *param +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char** suggestedNicks_A = UCS2ToUTF8StringArrayAlloc(suggestedNicks, numSuggestedNicks); + int i; + piConnectNickErrorCallbackA(chat, type, nick_A, numSuggestedNicks, (const char**)suggestedNicks_A, param); + gsifree(nick_A); + if(suggestedNicks_A) + { + for (i=0; ipublicIP = IP; + + // If chat has a pid, override ours. + //////////////////////////////////// + pid = chatGetProfileID(connection->chat); + if(pid) + connection->profileID = pid; + + // Mangle the IP and pid into the user. + /////////////////////////////////////// + piMangleUser(user, connection->publicIP, connection->profileID); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piConnectFillInUserCallbackW +( + CHAT chat, + unsigned int IP, + unsigned short user[128], // OUT parameter!! + void * param +) +{ + // This one is reversed! Call the callback, THEN convert + char user_A[256]; + piConnectFillInUserCallbackA(chat, IP, user_A, param); + UTF8ToUCS2String(user_A, user); +} +#endif + +PEERBool piNewConnectOperation +( + PEER peer, + piConnectType connectType, + const char * nick, + int namespaceID, + const char * email, + const char * profilenick, + const char * uniquenick, + const char * password, + const char * authtoken, + const char * partnerchallenge, + peerConnectCallback callback, + void * callbackParam, + int opID +) +{ + piOperation * operation; + chatGlobalCallbacks globalCallbacks; + const char * uniqueID; + char encodedUniqueID[33]; + peerNickErrorCallback nickErrorCallback; + + PEER_CONNECTION; + + assert(callback); + +#ifdef _DEBUG + if(connectType == PI_CONNECT) + { + assert(nick && nick[0]); + } + else if(connectType == PI_CONNECT_UNIQUENICK_LOGIN) + { + assert(namespaceID > 0); + assert(uniquenick && uniquenick[0]); + assert(password && password[0]); + } + else if(connectType == PI_CONNECT_PROFILENICK_LOGIN) + { + assert(namespaceID >= 0); + assert(email && email[0]); + assert(profilenick && profilenick[0]); + assert(password && password[0]); + } + else if(connectType == PI_CONNECT_PREAUTH) + { + assert(authtoken && authtoken[0]); + assert(partnerchallenge && partnerchallenge[0]); + } +#endif + + // Add an operation. + //////////////////// + operation = piAddOperation(peer, PI_CONNECT_OPERATION, NULL, (PEERCBType)callback, callbackParam, opID); + if(!operation) + return PEERFalse; + + // Setup the global callbacks. + ////////////////////////////// + memset(&globalCallbacks, 0, sizeof(chatGlobalCallbacks)); + globalCallbacks.disconnected = piChatDisconnected; + globalCallbacks.privateMessage = piChatPrivateMessage; + globalCallbacks.param = peer; + + // Encode the unique ID. + //////////////////////// + uniqueID = GOAGetUniqueID(); + MD5Digest((unsigned char *)uniqueID, strlen(uniqueID), encodedUniqueID); + + // Connect to chat. + /////////////////// + nickErrorCallback = (connection->nickErrorCallback ? piConnectNickErrorCallback : NULL); + if(connectType == PI_CONNECT) + { + connection->chat = chatConnectSecureA( + PI_CHAT_SERVER_ADDRESS, + PI_CHAT_SERVER_PORT, + nick, + encodedUniqueID, + connection->sbName, + connection->sbSecretKey, + &globalCallbacks, + nickErrorCallback, + piConnectFillInUserCallback, + piConnectConnectCallback, + operation, + CHATFalse); + } + else if((connectType == PI_CONNECT_UNIQUENICK_LOGIN) || (connectType == PI_CONNECT_PROFILENICK_LOGIN)) + { + connection->chat = chatConnectLoginA( + PI_CHAT_SERVER_ADDRESS, + PI_CHAT_SERVER_PORT, + namespaceID, + email, + profilenick, + uniquenick, + password, + encodedUniqueID, + connection->sbName, + connection->sbSecretKey, + &globalCallbacks, + nickErrorCallback, + piConnectFillInUserCallback, + piConnectConnectCallback, + operation, + CHATFalse); + } + else if(connectType == PI_CONNECT_PREAUTH) + { + connection->chat = chatConnectPreAuthA( + PI_CHAT_SERVER_ADDRESS, + PI_CHAT_SERVER_PORT, + authtoken, + partnerchallenge, + encodedUniqueID, + connection->sbName, + connection->sbSecretKey, + &globalCallbacks, + nickErrorCallback, + piConnectFillInUserCallback, + piConnectConnectCallback, + operation, + CHATFalse); + } + if(!connection->chat) + { + piRemoveOperation(peer, operation); + return PEERFalse; + } + + return PEERTrue; +} + +/* Create Staging Room. +**********************/ +static PEERJoinResult piEnterResultToJoinResult +( + CHATEnterResult result +) +{ + switch(result) + { + case CHATEnterSuccess: + return PEERJoinSuccess; + case CHATChannelIsFull: + return PEERFullRoom; + case CHATInviteOnlyChannel: + return PEERInviteOnlyRoom; + case CHATBannedFromChannel: + return PEERBannedFromRoom; + case CHATBadChannelPassword: + return PEERBadPassword; + default: + break; + } + + return PEERJoinFailed; +} + +static void piCreateStagingRoomEnumUsersCallbackA +( + CHAT chat, + CHATBool success, + const char * channel, + int numUsers, + const char ** users, + int * modes, + void *param +) +{ + PEER_CONNECTION_OP; + + // Check if this was cancelled. + /////////////////////////////// + if(operation->cancel) + { + piRemoveOperation(peer, operation); + return; + } + + // Start hosting/reporting. + /////////////////////////// + if(success) + { + if(!peerIsAutoMatching(peer)) + { + if(!piStartHosting(peer, operation->socket, operation->port)) + success = CHATFalse; + else + { + // If we created the socket, hand over responsibility for it to qr2. + //////////////////////////////////////////////////////////////////// + if(operation->socketClose) + { + operation->socketClose = PEERFalse; + connection->queryReporting->read_socket = 1; + } + } + } + else + { + connection->hosting = PEERTrue; + } + } + + // Do stuff based on success. + ///////////////////////////// + if(success) + { + int i; + + // Done entering. + ///////////////// + piFinishedEnteringRoom(peer, StagingRoom, operation->name); + + // Add everyone to the room. + //////////////////////////// + for(i = 0 ; i < numUsers ; i++) + piPlayerJoinedRoom(peer, users[i], StagingRoom, modes[i]); + + // Set the name. + //////////////// + chatSetChannelTopicA(connection->chat, channel, operation->name); + + // Set a limit on the room. + /////////////////////////// +#ifndef PI_NO_STAGING_ROOM_LIMIT + if(connection->maxPlayers) + chatSetChannelLimitA(connection->chat, channel, connection->maxPlayers); +#endif + + // If this is AutoMatch, and we created a socket, hand it over. + /////////////////////////////////////////////////////////////// + if(operation->socketClose && peerIsAutoMatching(peer)) + { + connection->autoMatchOperation->socket = operation->socket; + connection->autoMatchOperation->port = operation->port; + connection->autoMatchOperation->socketClose = PEERTrue; + operation->socketClose = PEERFalse; + } + } + else + { + // Leave the room. + ////////////////// + piLeaveRoom(peer, StagingRoom, NULL); + } + + // Add the callback. + //////////////////// + piAddJoinRoomCallback(peer, (PEERBool)success, success?PEERJoinSuccess:PEERJoinFailed, StagingRoom, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piCreateStagingRoomEnumUsersCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * channel, + int numUsers, + const unsigned short ** users, + int * modes, + void *param +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char** users_A = UCS2ToUTF8StringArrayAlloc(users, numUsers); + int i; + piCreateStagingRoomEnumUsersCallbackA(chat, success, channel_A, numUsers, (const char**)users_A, modes, param); + gsifree(channel_A); + for (i=0; iLimit = connection->maxPlayers; + mode->OpsObeyChannelLimit = CHATTrue; + + // Don't let ops bypass channel limit on the number of players in room + chatSetChannelMode(chat, channel, mode); + } + +} + + +static void piCreateStagingRoomEnterChannelCallbackA +( + CHAT chat, + CHATBool success, + CHATEnterResult result, + const char * channel, + void *param +) +{ + PEER_CONNECTION_OP; + + assert(channel); + assert(channel[0]); + + // Check if this was cancelled. + /////////////////////////////// + if(operation->cancel) + { + piRemoveOperation(peer, operation); + return; + } + + if(success) + { + // If passworded, set it. + ///////////////////////// + if(operation->password) + chatSetChannelPasswordA(connection->chat, channel, CHATTrue, operation->password); + + + // get the channel modes so we can set the limits on our staging channel + chatGetChannelMode(connection->chat, peerGetRoomChannel(peer, StagingRoom), piCreateStagingRoomGetChannelModeCallback, + (void *)connection, CHATFalse); + + + // How many users? + ////////////////// + chatEnumUsersA(chat, channel, piCreateStagingRoomEnumUsersCallback, operation, CHATFalse); + } + else + { + PEERJoinResult joinResult; + + // Not entering. + //////////////// + piLeaveRoom(peer, StagingRoom, NULL); + + // Get the peer result. + /////////////////////// + if(result == CHATEnterSuccess) + joinResult = PEERJoinFailed; + else + joinResult = piEnterResultToJoinResult(result); + + // Add the callback. + //////////////////// + piAddJoinRoomCallback(peer, PEERFalse, joinResult, StagingRoom, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + } +} +#ifdef GSI_UNICODE +static void piCreateStagingRoomEnterChannelCallbackW +( + CHAT chat, + CHATBool success, + CHATEnterResult result, + const unsigned short * channel, + void *param +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + piCreateStagingRoomEnterChannelCallbackA(chat, success, result, channel_A, param); + gsifree(channel_A); +} +#endif + +// internal QR2 function +qr2_error_t qr2_create_socket(/*[out]*/SOCKET *sock, const char *ip, /*[in/out]*/int * port); + +PEERBool piNewCreateStagingRoomOperation +( + PEER peer, + const char * name, + const char * password, + int maxPlayers, + SOCKET socket, + unsigned short port, + peerJoinRoomCallback callback, + void * callbackParam, + int opID +) +{ + piOperation * operation; + chatChannelCallbacks channelCallbacks; + char room[PI_ROOM_MAX_LEN]; + PEERBool createdSocket = PEERFalse; + + PEER_CONNECTION; + + assert(name); + if(!name) + name = ""; + + assert(callback); + if(!callback) + return PEERFalse; + + // Save off the maxplayers. + /////////////////////////// + connection->maxPlayers = maxPlayers; + + // If we don't have a socket, create one to use. + //////////////////////////////////////////////// + if(socket == INVALID_SOCKET) + { + IN_ADDR addr; + qr2_error_t rcode; + int privatePort; + + addr.s_addr = 0;//crt -- don't bind to privateIP (for clients that have both public and private) connection->privateIP; + if(port) + privatePort = port; + else + privatePort = PI_QUERYPORT; + + rcode = qr2_create_socket(&socket, inet_ntoa(addr), &privatePort); + if(rcode != e_qrnoerror) + return PEERFalse; + + port = (unsigned short)privatePort; + createdSocket = PEERTrue; + } + + // Get the room name. + ///////////////////// + piMangleStagingRoom(room, connection->title, connection->publicIP, connection->privateIP, port); + assert(room[0]); + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_CREATE_ROOM_OPERATION, NULL, (PEERCBType)callback, callbackParam, opID); + if(!operation) + return PEERFalse; + operation->socketClose = createdSocket; + operation->name = goastrdup(name); + if(!operation->name) + { + piRemoveOperation(peer, operation); + return PEERFalse; + } + operation->socket = socket; + operation->port = port; + operation->roomType = StagingRoom; + if(password[0]) + operation->password = goastrdup(password); + + // Set the callbacks. + ///////////////////// + piSetChannelCallbacks(peer, &channelCallbacks); + + // Create the room. + /////////////////// + piStartedEnteringRoom(peer, StagingRoom, room); + chatEnterChannelA(connection->chat, room, NULL, &channelCallbacks, piCreateStagingRoomEnterChannelCallback, operation, CHATFalse); + + // Store passworded flag if needed. + /////////////////////////////////// + if(password[0]) + connection->passwordedRoom = PEERTrue; + + return PEERTrue; +} + +/* Join Room. +************/ +static void piJoinRoomEnumUsersCallbackA +( + CHAT chat, + CHATBool success, + const char * channel, + int numUsers, + const char ** users, + int * modes, + void * param +) +{ + PEER_CONNECTION_OP; + + // Check if this was cancelled. + /////////////////////////////// + if(operation->cancel) + { + piRemoveOperation(peer, operation); + return; + } + + // Check for success. + ///////////////////// + if(success) + { + int i; + + // Finished entering the room. + ////////////////////////////// + piFinishedEnteringRoom(peer, operation->roomType, ""); + + // Add all these people to the room. + //////////////////////////////////// + for(i = 0 ; i < numUsers ; i++) + piPlayerJoinedRoom(peer, users[i], operation->roomType, modes[i]); + } + else + { + // Leave the room. + ////////////////// + piLeaveRoom(peer, operation->roomType, NULL); + } + + // Add the callback. + //////////////////// + piAddJoinRoomCallback(peer, (PEERBool)success, success?PEERJoinSuccess:PEERJoinFailed, operation->roomType, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); + GSI_UNUSED(channel); +} +#ifdef GSI_UNICODE +static void piJoinRoomEnumUsersCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * channel, + int numUsers, + const unsigned short ** users, + int * modes, + void * param +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char** users_A = UCS2ToUTF8StringArrayAlloc(users, numUsers); + int i; + piJoinRoomEnumUsersCallbackA(chat, success, channel_A, numUsers, (const char**)users_A, modes, param); + gsifree(channel_A); + for (i=0; icancel) + { + piSBFreeHostServer(peer); + piRemoveOperation(peer, operation); + return; + } + + if(success) + { + // How many users? + ////////////////// + chatEnumUsersA(chat, channel, piJoinRoomEnumUsersCallback, operation, CHATFalse); + } + else + { + PEERJoinResult joinResult; + + // Not entering. + //////////////// + piLeaveRoom(peer, operation->roomType, NULL); + + // Get the peer result. + /////////////////////// + if(result == CHATEnterSuccess) + joinResult = PEERJoinFailed; + else + joinResult = piEnterResultToJoinResult(result); + + // Add the callback. + //////////////////// + piAddJoinRoomCallback(peer, PEERFalse, joinResult, operation->roomType, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + } +} +#ifdef GSI_UNICODE +static void piJoinRoomEnterChannelCallbackW +( + CHAT chat, + CHATBool success, + CHATEnterResult result, + const unsigned short * channel, + void *param +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + piJoinRoomEnterChannelCallbackA(chat, success, result, channel_A, param); + gsifree(channel_A); +} +#endif + +PEERBool piNewJoinRoomOperation +( + PEER peer, + RoomType roomType, + const char * channel, + const char * password, + peerJoinRoomCallback callback, + void * callbackParam, + int opID +) +{ + piOperation * operation; + chatChannelCallbacks channelCallbacks; + + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + assert(callback); + + // Check the name. + ////////////////// + assert(channel); + assert(channel[0]); + if(!channel || !channel[0]) + return PEERFalse; + + // Check password. + ////////////////// + if(!password) + password = ""; + + // Check that the name isn't too long. + ////////////////////////////////////// + assert(strlen(channel) < PI_ROOM_MAX_LEN); + if(strlen(channel) >= PI_ROOM_MAX_LEN) + return PEERFalse; + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_JOIN_ROOM_OPERATION, NULL, (PEERCBType)callback, callbackParam, opID); + if(!operation) + return PEERFalse; + operation->roomType = roomType; + + // Set the callbacks. + ///////////////////// + piSetChannelCallbacks(peer, &channelCallbacks); + + // Join the room. + ///////////////// + piStartedEnteringRoom(peer, roomType, channel); + chatEnterChannelA(connection->chat, channel, password, &channelCallbacks, piJoinRoomEnterChannelCallback, operation, CHATFalse); + + return PEERTrue; +} + +/* List Group Rooms. +*******************/ +PEERBool piNewListGroupRoomsOperation +( + PEER peer, + const char * fields, + peerListGroupRoomsCallback callback, + void * param, + int opID +) +{ + piOperation * operation; + + PEER_CONNECTION; + + assert(callback); + + // Add the operation. + ///////////////////// + operation = connection->listingGroupsOperation = piAddOperation(peer, PI_LIST_GROUP_ROOMS_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Start the listing. + ///////////////////// + return piSBStartListingGroups(peer, fields); +} + +/* Get Player Info. +*******************/ +static void piGetPlayerInfoCallbackA +( + CHAT chat, + CHATBool success, + const char * nick, + const char * user, + const char * address, + void * param +) +{ + int profileID = 0; + unsigned int IP = 0; + + PEER_CONNECTION_OP; + + assert(nick); + assert(nick[0]); + + // Check for success. + ///////////////////// + if(success) + { + assert(user); + assert(user[0]); + + // Get the info. + //////////////// + if(!piDemangleUser(user, &IP, &profileID)) + success = CHATFalse; + + // Cache the info. + ////////////////// + if(success) + piSetPlayerIPAndProfileID(peer, nick, IP, profileID); + } + if(!success) + { + profileID = 0; + IP = 0; + } + + // Add the callback. + //////////////////// + if(operation->callback) + { + if(operation->type == PI_GET_PLAYER_INFO_OPERATION) + piAddGetPlayerInfoCallback(peer, (PEERBool)success, nick, IP, profileID, (peerGetPlayerInfoCallback)operation->callback, operation->callbackParam, operation->ID); + else if(operation->type == PI_GET_PROFILE_ID_OPERATION) + piAddGetPlayerProfileIDCallback(peer, (PEERBool)success, nick, profileID, (peerGetPlayerProfileIDCallback)operation->callback, operation->callbackParam, operation->ID); + else if(operation->type == PI_GET_IP_OPERATION) + piAddGetPlayerIPCallback(peer, (PEERBool)success, nick, IP, (peerGetPlayerIPCallback)operation->callback, operation->callbackParam, operation->ID); + else + assert(0); + } + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); + GSI_UNUSED(address); +} +#ifdef GSI_UNICODE +static void piGetPlayerInfoCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * nick, + const unsigned short * user, + const unsigned short * address, + void * param +) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + char* user_A = UCS2ToUTF8StringAlloc(user); + char* address_A = UCS2ToUTF8StringAlloc(address); + piGetPlayerInfoCallbackA(chat, success, nick_A, user_A, address_A, param); + gsifree(nick_A); + gsifree(user_A); + gsifree(address_A); +} +#endif + +PEERBool piNewGetPlayerInfoOperation +( + PEER peer, + const char * nick, + peerGetPlayerInfoCallback callback, + void * param, + int opID +) +{ + piOperation * operation; + + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_GET_PLAYER_INFO_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Get the user's info. + /////////////////////// + chatGetBasicUserInfoA(connection->chat, nick, piGetPlayerInfoCallback, operation, CHATFalse); + + return PEERTrue; +} + +PEERBool piNewGetProfileIDOperation +( + PEER peer, + const char * nick, + peerGetPlayerProfileIDCallback callback, + void * param, + int opID +) +{ + piOperation * operation; + + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_GET_PROFILE_ID_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Get the user's info. + /////////////////////// + chatGetBasicUserInfoA(connection->chat, nick, piGetPlayerInfoCallback, operation, CHATFalse); + + return PEERTrue; +} + +PEERBool piNewGetIPOperation +( + PEER peer, + const char * nick, + peerGetPlayerIPCallback callback, + void * param, + int opID +) +{ + piOperation * operation; + + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_GET_IP_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Get the user's info. + /////////////////////// + chatGetBasicUserInfoA(connection->chat, nick, piGetPlayerInfoCallback, operation, CHATFalse); + + return PEERTrue; +} + +/* Change Nick. +**************/ +static void piChangeNickCallbackA +( + CHAT chat, + CHATBool success, + const char * oldNick, + const char * newNick, + void * param +) +{ + PEER_CONNECTION_OP; + + // Check for success. + ///////////////////// + if(success) + { + // Update the nick locally. + /////////////////////////// + strcpy(connection->nick, newNick); + +#ifdef GSI_UNICODE + UTF8ToUCS2String(connection->nick, connection->nick_W); +#endif + } + + // Add the callback. + //////////////////// + if(operation->callback) + piAddChangeNickCallback(peer, (PEERBool)success, oldNick, newNick, (peerChangeNickCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piChangeNickCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * oldNick, + const unsigned short * newNick, + void * param +) +{ + char* oldNick_A = UCS2ToUTF8StringAlloc(oldNick); + char* newNick_A = UCS2ToUTF8StringAlloc(newNick); + piChangeNickCallbackA(chat, success, oldNick_A, newNick_A, param); + gsifree(oldNick_A); + gsifree(newNick_A); +} +#endif + +PEERBool piNewChangeNickOperation +( + PEER peer, + const char * newNick, + peerChangeNickCallback callback, + void * param, + int opID +) +{ + piOperation * operation; + + PEER_CONNECTION; + + assert(newNick); + assert(newNick[0]); + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_CHANGE_NICK_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Change the nick. + /////////////////// + chatChangeNickA(connection->chat, newNick, piChangeNickCallback, operation, CHATFalse); + + return PEERTrue; +} + +/* Get Global Keys. +******************/ +static void piGetGlobalKeysCallbackA +( + CHAT chat, + CHATBool success, + const char * user, + int num, + const char ** keys, + const char ** values, + void * param +) +{ + int i; + + PEER_CONNECTION_OP; + + // Update the watch keys. + ///////////////////////// + if(success && user) + { + for(i = 0 ; i < num ; i++) + piGlobalKeyChanged(peer, user, keys[i], values[i]); + } + + // Add the callback. + //////////////////// + if(operation->callback) + piAddGetGlobalKeysCallback(peer, (PEERBool)success, user, num, keys, values, (peerGetGlobalKeysCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + if(!success || !user || !operation->num) + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piGetGlobalKeysCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * user, + int num, + const unsigned short ** keys, + const unsigned short ** values, + void * param +) +{ + char* user_A = UCS2ToUTF8StringAlloc(user); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = UCS2ToUTF8StringArrayAlloc(values, num); + int i; + piGetGlobalKeysCallbackA(chat, success, user_A, num, (const char**)keys_A, (const char**)values_A, param); + gsifree(user_A); + for (i=0; i 0); + assert(keys); + + if(!target || !target[0]) + return PEERFalse; + if(num <= 0) + return PEERFalse; + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_GET_GLOBAL_KEYS_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Use num as a flag for getting a whole channel. + ///////////////////////////////////////////////// + operation->num = (target[0] == '#'); + + // Get the keys. + //////////////// + chatGetGlobalKeysA(connection->chat, target, num, keys, piGetGlobalKeysCallback, operation, CHATFalse); + + return PEERTrue; +} + +/* Get Room Keys. +****************/ +static void piGetChannelKeysCallbackA +( + CHAT chat, + CHATBool success, + const char * channel, + const char * user, + int num, + const char ** keys, + const char ** values, + void * param +) +{ + int i; + + PEER_CONNECTION_OP; + + // Update the watch keys. + ///////////////////////// + if(success && user) + { + for(i = 0 ; i < num ; i++) + piRoomKeyChanged(peer, operation->roomType, user, keys[i], values[i]); + } + + // Add the callback. + //////////////////// + if(operation->callback) + piAddGetRoomKeysCallback(peer, (PEERBool)success, operation->roomType, user, num, keys, values, (peerGetRoomKeysCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + if(!success || !user || !operation->num) + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); + GSI_UNUSED(channel); +} +#ifdef GSI_UNICODE +static void piGetChannelKeysCallbackW +( + CHAT chat, + CHATBool success, + const unsigned short * channel, + const unsigned short * user, + int num, + const unsigned short ** keys, + const unsigned short ** values, + void * param +) +{ + char* channel_A = UCS2ToUTF8StringAlloc(channel); + char* user_A = UCS2ToUTF8StringAlloc(user); + char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num); + char** values_A = UCS2ToUTF8StringArrayAlloc(values, num); + int i; + piGetChannelKeysCallbackA(chat, success, channel_A, user_A, num, (const char**)keys_A, (const char**)values_A, param); + gsifree(channel_A); + gsifree(user_A); + for (i=0; i= 0); + assert(!num || keys); + + if(num < 0) + return PEERFalse; + if((num > 0) && !keys) + return PEERFalse; + + if(!ENTERING_ROOM && !IN_ROOM) + return PEERFalse; + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_GET_ROOM_KEYS_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + operation->roomType = roomType; + + // Use num as a flag for getting a whole channel. + ///////////////////////////////////////////////// + if(nick) + operation->num = (strcmp(nick, "*") == 0); + else + operation->num = 0; + + // Get the keys. + //////////////// + chatGetChannelKeysA(connection->chat, ROOM, nick, num, keys, piGetChannelKeysCallback, operation, CHATFalse); + + return PEERTrue; +} + +/* Authenticate CD Key +*********************/ +static void piAuthenticateCDKeyCallbackA +( + CHAT chat, + int result, + const char * message, + void * param +) +{ + + PEER_CONNECTION_OP; + + // Add the callback. + //////////////////// + if(operation->callback) + piAddAuthenticateCDKeyCallback(peer, result, message, (peerAuthenticateCDKeyCallback)operation->callback, operation->callbackParam, operation->ID); + + // Remove the operation. + //////////////////////// + piRemoveOperation(peer, operation); + + GSI_UNUSED(chat); +} +#ifdef GSI_UNICODE +static void piAuthenticateCDKeyCallbackW +( + CHAT chat, + int result, + const unsigned short * message, + void * param +) +{ + char* message_A = UCS2ToUTF8StringAlloc(message); + piAuthenticateCDKeyCallbackA(chat, result, message_A, param); + gsifree(message_A); +} +#endif + +PEERBool piNewAuthenticateCDKeyOperation +( + PEER peer, + const char * cdkey, + peerAuthenticateCDKeyCallback callback, + void * param, + int opID +) +{ + piOperation * operation; + + PEER_CONNECTION; + + assert(cdkey); + assert(cdkey[0]); + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_AUTHENTICATE_CDKEY_OPERATION, NULL, (PEERCBType)callback, param, opID); + if(!operation) + return PEERFalse; + + // Check the CD key. + //////////////////// + chatAuthenticateCDKeyA(connection->chat, cdkey, piAuthenticateCDKeyCallback, operation, CHATFalse); + + return PEERTrue; +} + +/* AutoMatch +***********/ +PEERBool piNewAutoMatchOperation +( + PEER peer, + SOCKET socket, + unsigned short port, + peerAutoMatchStatusCallback statusCallback, + peerAutoMatchRateCallback rateCallback, + void * param, + int opID +) +{ + piOperation * operation; + PEERAutoMatchStatus status; + + PEER_CONNECTION; + + // Add the operation. + ///////////////////// + operation = piAddOperation(peer, PI_AUTO_MATCH_OPERATION, NULL, (PEERCBType)statusCallback, param, opID); + if(!operation) + return PEERFalse; + + // Store the second callback. + ///////////////////////////// + operation->callback2 = (PEERCBType)rateCallback; + + // Store the socket and port. + ///////////////////////////// + operation->socket = socket; + operation->port = port; + + // Track this op. + ///////////////// + connection->autoMatchOperation = operation; + + // Figure out which status to use. + ////////////////////////////////// +/* if(connection->inRoom[StagingRoom]) + { + if(connection->numPlayers[StagingRoom] <= 1) + { + if(connection->hosting) + status = PEERWaiting; + else + status = PEERStaging; + } + else if(connection->numPlayers[StagingRoom] >= connection->maxPlayers) + { + status = PEERReady; + } + else + { + status = PEERStaging; + } + } + else*/ + { + status = PEERSearching; + } + + // Set the status. + ////////////////// + piSetAutoMatchStatus(peer, status); + + return PEERTrue; +} diff --git a/xrGameSpy/gamespy/Peer/peerOperations.h b/xrGameSpy/gamespy/Peer/peerOperations.h new file mode 100644 index 00000000000..b0675ccda86 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerOperations.h @@ -0,0 +1,221 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEEROPERATIONS_H_ +#define _PEEROPERATIONS_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/********** +** TYPES ** +**********/ +typedef enum piOperationType +{ + PI_CONNECT_OPERATION, + PI_CREATE_ROOM_OPERATION, + PI_JOIN_ROOM_OPERATION, + PI_ENUM_PLAYERS_OPERATION, + PI_LIST_GROUP_ROOMS_OPERATION, + PI_LIST_STAGING_ROOMS_OPERATION, + PI_GET_PLAYER_INFO_OPERATION, + PI_GET_PROFILE_ID_OPERATION, + PI_GET_IP_OPERATION, + PI_CHANGE_NICK_OPERATION, + PI_GET_GLOBAL_KEYS_OPERATION, + PI_GET_ROOM_KEYS_OPERATION, + PI_AUTHENTICATE_CDKEY_OPERATION, + PI_AUTO_MATCH_OPERATION, + PI_NUM_OPERATION_TYPES +} piOperationType; + +typedef enum piConnectType +{ + PI_CONNECT, + PI_CONNECT_UNIQUENICK_LOGIN, + PI_CONNECT_PROFILENICK_LOGIN, + PI_CONNECT_PREAUTH +} piConnectType; + +typedef struct piOperation +{ + PEER peer; // the peer object + piOperationType type; // PI__OPERATION + void * data; // operation-specific data + int ID; // unique ID for this operation + PEERCBType callback; // the callback for this operation + PEERCBType callback2; // second callback if needed + void * callbackParam; // user-data for the callback + RoomType roomType; // lots of operations need this + char * name; // general purpose name + char * password; // general purpose password + int num; // general purpose integer + SOCKET socket; // general purpose socket + unsigned short port; // general purpose port + PEERBool socketClose; // close the socket when done + PEERBool cancel; // this op has been cancelled +} piOperation; + +/************** +** FUNCTIONS ** +**************/ +PEERBool piOperationsInit(PEER peer); +void piOperationsReset(PEER peer); +void piOperationsCleanup(PEER peer); +PEERBool piIsOperationFinished(PEER peer, int opID); +void piRemoveOperation(PEER peer, piOperation * operation); +void piCancelJoinOperation(PEER peer, RoomType roomType); +piOperation * piGetOperation(PEER peer, int opID); +int piGetNextID(PEER peer); + +/*************** +** OPERATIONS ** +***************/ +PEERBool piNewConnectOperation +( + PEER peer, + piConnectType connectType, + const char * nick, + int namespaceID, + const char * email, + const char * profilenick, + const char * uniquenick, + const char * password, + const char * authtoken, + const char * partnerchallenge, + peerConnectCallback callback, + void * callbackParam, + int opID +); + +PEERBool piNewCreateStagingRoomOperation +( + PEER peer, + const char * name, + const char * password, + int maxPlayers, + SOCKET socket, + unsigned short port, + peerJoinRoomCallback callback, + void * callbackParam, + int opID +); + +PEERBool piNewJoinRoomOperation +( + PEER peer, + RoomType roomType, + const char * channel, + const char * password, + peerJoinRoomCallback callback, + void * callbackParam, + int opID +); + +PEERBool piNewListGroupRoomsOperation +( + PEER peer, + const char * fields, + peerListGroupRoomsCallback callback, + void * param, + int opID +); + +PEERBool piNewGetPlayerInfoOperation +( + PEER peer, + const char * nick, + peerGetPlayerInfoCallback callback, + void * param, + int opID +); + +PEERBool piNewGetProfileIDOperation +( + PEER peer, + const char * nick, + peerGetPlayerProfileIDCallback callback, + void * param, + int opID +); + +PEERBool piNewGetIPOperation +( + PEER peer, + const char * nick, + peerGetPlayerIPCallback callback, + void * param, + int opID +); + +PEERBool piNewChangeNickOperation +( + PEER peer, + const char * newNick, + peerChangeNickCallback callback, + void * param, + int opID +); + +PEERBool piNewGetGlobalKeysOperation +( + PEER peer, + const char * target, + int num, + const char ** keys, + peerGetGlobalKeysCallback callback, + void * param, + int opID +); + +PEERBool piNewGetRoomKeysOperation +( + PEER peer, + RoomType roomType, + const char * nick, + int num, + const char ** keys, + peerGetRoomKeysCallback callback, + void * param, + int opID +); + +PEERBool piNewAuthenticateCDKeyOperation +( + PEER peer, + const char * cdkey, + peerAuthenticateCDKeyCallback callback, + void * param, + int opID +); + +PEERBool piNewAutoMatchOperation +( + PEER peer, + SOCKET socket, + unsigned short port, + peerAutoMatchStatusCallback statusCallback, + peerAutoMatchRateCallback rateCallback, + void * param, + int opID +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerPing.c b/xrGameSpy/gamespy/Peer/peerPing.c new file mode 100644 index 00000000000..65330e79b5e --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerPing.c @@ -0,0 +1,1118 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include "peerPlayers.h" +#include "peerPing.h" +#include "peerGlobalCallbacks.h" +#include "peerCallbacks.h" +#include "peerMangle.h" + +/************ +** DEFINES ** +************/ +#define PI_PING_TIMEOUT 5000 +#define PI_PINGS_PER_SEC 25 +#define PI_PING_INTERVAL (1000 / PI_PINGS_PER_SEC) +#define PI_XPING_INTERVAL 2000 +#define PI_XPING_PLAYER_INTERVAL 5000 +#define PI_PINGER_PORT 13139 +#define PI_MAX_PING_PLAYERS 12 +#define PI_XPING_NUM_BUCKETS 32 +#define PI_DONT_PING_FLAGS (PEER_FLAG_PLAYING | PEER_FLAG_AWAY) +#define PI_MAX_XPING_NUM_PLAYERS 32 + +#define PEER_CONNECTION_DATA piConnection * connection;\ + assert(data);\ + assert(data->peer);\ + connection = (piConnection *)data->peer;\ + GSI_UNUSED(connection); + + +/********** +** TYPES ** +**********/ +typedef struct piXping +{ + char nicks[2][PI_NICK_MAX_LEN]; + int ping; +} piXping; + +/************** +** FUNCTIONS ** +**************/ +static int piXpingTableHashFn +( + const void *param, + int numBuckets +) +{ + piXping * xping = (piXping *)param; + int i; + int c; + const char * str; + unsigned int hash = 0; + const char * nicks[2]; + + assert(xping); + assert(xping->nicks[0][0]); + assert(xping->nicks[1][0]); + + nicks[0] = xping->nicks[0]; + nicks[1] = xping->nicks[1]; + + // Reverse the order if the second is smaller. + ////////////////////////////////////////////// + if(strcmp(nicks[1], nicks[0]) < 0) + { + const char * temp = nicks[0]; + nicks[0] = nicks[1]; + nicks[1] = temp; + } + + // Get the hash. + //////////////// + for(i = 0 ; i < 2 ; i++) + { + str = nicks[i]; + while((c = *str++) != '\0') + hash += (unsigned int)tolower(c); + hash %= (unsigned int)numBuckets; + } + + return (int)hash; +} + +static int GS_STATIC_CALLBACK piXpingTableCompareFn +( + const void *param1, + const void *param2 +) +{ + piXping * xping1 = (piXping *)param1; + piXping * xping2 = (piXping *)param2; + + int i; + int rcode; + const char * nicks[2][2]; + + assert(xping1); + assert(xping1->nicks[0][0]); + assert(xping1->nicks[1][0]); + assert(xping2); + assert(xping2->nicks[0][0]); + assert(xping2->nicks[1][0]); + + nicks[0][0] = xping1->nicks[0]; + nicks[0][1] = xping1->nicks[1]; + nicks[1][0] = xping2->nicks[0]; + nicks[1][1] = xping2->nicks[1]; + + // Reverse the order if the second is smaller. + ////////////////////////////////////////////// + for(i = 0 ; i < 2 ; i++) + { + if(strcmp(nicks[i][1], nicks[i][0]) < 0) + { + const char * temp = nicks[i][0]; + nicks[i][0] = nicks[i][1]; + nicks[i][1] = temp; + } + } + + for(i = 0 ; i < 2 ; i++) + { + rcode = strcasecmp(nicks[0][i], nicks[1][i]); + if(rcode != 0) + return rcode; + } + + return 0; +} + +static void piXpingTableElementFreeFn +( + void *param +) +{ + piXping * xping = (piXping *)param; + assert(xping); + assert(xping->nicks[0][0]); + assert(xping->nicks[1][0]); + GSI_UNUSED(xping); +} + +static void piProcessPing +( + PEER peer, + piPlayer * player, + int ping +) +{ + int i; + int total; + + //PEER_CONNECTION; + + // One more returned. + ///////////////////// + player->pingsReturned++; + player->pingsLostConsecutive = 0; + + // We have one more ping for this player. + ///////////////////////////////////////// + player->numPings++; + + //Update last ping received. + //////////////////////////// + player->lastPingRecv = current_time(); + + // Update the ping history. + /////////////////////////// + if(player->pingHistoryNum > 0) + memmove(player->pingHistory + 1, player->pingHistory, min(player->pingHistoryNum, PI_PING_HISTORY_LEN - 1) * sizeof(int)); + player->pingHistory[0] = ping; + if(player->pingHistoryNum < PI_PING_HISTORY_LEN) + player->pingHistoryNum++; + + // Recompute the ping average. + ////////////////////////////// + total = 0; + for(i = 0 ; i < player->pingHistoryNum ; i++) + total += player->pingHistory[i]; + player->pingAverage = (total / player->pingHistoryNum); + + // Add a ping callback. + /////////////////////// + piAddPingCallback(peer, player->nick, ping); + + // New ping, no xping yet. + ////////////////////////// + player->xpingSent = PEERFalse; + + // If this is a one-timer, stop pinging. + //////////////////////////////////////// + if(player->pingOnce) + player->pingOnce = PEERFalse; +} + +static void piPinged +( + unsigned int IP, + unsigned short port, + int ping, + const char * data, + int len, + PEER peer +) +{ + piPlayer * player; + + // Find the player. + /////////////////// + player = piFindPlayerByIP(peer, IP); + if(!player) + return; + + // Process the ping. + //////////////////// + piProcessPing(peer, player, ping); + + GSI_UNUSED(port); + GSI_UNUSED(data); + GSI_UNUSED(len); +} + +PEERBool piPingInit +( + PEER peer +) +{ + static PEERBool noPings[NumRooms]; + + PEER_CONNECTION; + + // If there are no ping rooms, skip this. + ///////////////////////////////////////// + if(memcmp(connection->pingRoom, noPings, sizeof(noPings)) == 0) + return PEERTrue; + + // Init the xping table. + //////////////////////// + connection->xpings = TableNew(sizeof(piXping), PI_XPING_NUM_BUCKETS, piXpingTableHashFn, piXpingTableCompareFn, piXpingTableElementFreeFn); + if(!connection->xpings) + return PEERFalse; + + // Init pinger. + /////////////// + if(!pingerInit(NULL, PI_PINGER_PORT, piPinged, peer, NULL, NULL)) + return PEERFalse; + + // No pings yet. + //////////////// + connection->lastPingTimeMod = 0; + connection->lastXpingSend = 0; + + // Init the random number generator. + //////////////////////////////////// + srand(current_time()); + + // We're doing pings. + ///////////////////// + connection->doPings = PEERTrue; + + return PEERTrue; +} + +void piPingCleanup +( + PEER peer +) +{ + PEER_CONNECTION; + + // Nothing to do if we weren't pinging. + /////////////////////////////////////// + if(!connection->doPings) + return; + + // If we're staying in the title room, get out. + /////////////////////////////////////////////// + if(connection->stayInTitleRoom) + return; + + // Clear timing stuff. + ////////////////////// + connection->lastPingTimeMod = 0; + connection->lastXpingSend = 0; + + // gsifree the xping table. + //////////////////////// + if(connection->xpings) + TableFree(connection->xpings); + connection->xpings = NULL; + + // Cleanup pinger. + ////////////////// + pingerShutdown(); + + // Not doing pings. + /////////////////// + connection->doPings = PEERFalse; +} + +typedef struct piPingerReplyData +{ + PEER peer; + unsigned int IP; + int ping; +} piPingerReplyData; + +static void piPingerReplyMapFn +( + void *elem, + void *clientdata +) +{ + piPlayer * player = (piPlayer *)elem; + piPingerReplyData * data = (piPingerReplyData *)clientdata; + + PEER_CONNECTION_DATA; + + assert(player); + + // Check if waiting for a ping. + /////////////////////////////// + if(!player->waitingForPing) + return; + + // Check the IP. + //////////////// + if(!player->gotIPAndProfileID || (player->IP != data->IP)) + return; + + // Not waiting anymore. + /////////////////////// + player->waitingForPing = PEERFalse; + + // Check timeout. + ///////////////// + if(data->ping == PINGER_TIMEOUT) + { + // One more lost. + ///////////////// + player->pingsLostConsecutive++; + + // If a one-timer drops three in a row, give up. + //////////////////////////////////////////////// + if(player->pingOnce && (player->pingsLostConsecutive >= 3)) + { + player->pingsLostConsecutive = 0; + player->pingOnce = PEERFalse; + } + } + else + { + // Process the ping. + //////////////////// + piProcessPing(data->peer, player, data->ping); + } +} + +static void piPingerReply +( + unsigned int IP, + unsigned short port, + int ping, + const char * pingData, + int pingDataLen, + PEER peer +) +{ + piPingerReplyData data; + + PEER_CONNECTION; + + // Find who sent the ping. + ////////////////////////// + data.peer = peer; + data.IP = IP; + data.ping = ping; + TableMap(connection->players, piPingerReplyMapFn, &data); + + GSI_UNUSED(port); + GSI_UNUSED(pingData); + GSI_UNUSED(pingDataLen); + +} + +static void piPingPlayer +( + PEER peer, + piPlayer * player +) +{ + assert(player->gotIPAndProfileID); + + // Make sure we're not already waiting. + /////////////////////////////////////// + assert(!player->waitingForPing); + if(player->waitingForPing) + return; + + // Do the ping. + /////////////// + pingerPing(player->IP, PI_PINGER_PORT, piPingerReply, peer, PINGERFalse, PI_PING_TIMEOUT); + + // Waiting for a ping to return. + //////////////////////////////// + player->waitingForPing = PEERTrue; + + // Last ping send time. + /////////////////////// + player->lastPingSend = current_time(); + + // Clear must ping flag. + //////////////////////// + player->mustPing = PEERFalse; +} + +typedef struct piPickPingPlayersData +{ + PEER peer; + piPlayer ** players; + int max; + int num; +} piPickPingPlayersData; + +static void piPickPingPlayersMap +( + void * elem, + void * clientData +) +{ + piPlayer * player = (piPlayer *)elem; + piPickPingPlayersData * data = (piPickPingPlayersData *)clientData; + PEER peer = (PEER)data->peer; + piPlayer * other; + unsigned long now; + unsigned long delay; + int i; + int j; + + PEER_CONNECTION; + + // Not pinging? + /////////////// + if(!player->inPingRoom && !player->pingOnce) + return; + + // Don't have IP? + ///////////////// + if(!player->gotIPAndProfileID) + return; + + // Waiting for a ping? + ////////////////////// + if(player->waitingForPing) + return; + + // Don't ping the local player. + /////////////////////////////// + if(player->local) + return; + + // Don't ping someone who's playing or away. + //////////////////////////////////////////// + if((player->inRoom[TitleRoom] && (player->flags[TitleRoom] & PI_DONT_PING_FLAGS)) || + (player->inRoom[GroupRoom] && (player->flags[GroupRoom] & PI_DONT_PING_FLAGS)) || + (player->inRoom[StagingRoom] && (player->flags[StagingRoom] & PI_DONT_PING_FLAGS))) + return; + + // Check if we have to ping this player. + //////////////////////////////////////// + if(!player->mustPing) + { + // Get the current time. + //////////////////////// + now = current_time(); + + // Slow pings for no response. + ////////////////////////////// + if((player->pingsLostConsecutive >= 4) && ((now - player->lastPingSend) < 120000)) + return; + + // Pinged recently? + /////////////////// + if(player->inRoom[StagingRoom]) + delay = 2000; + else if(player->pingsReturned < 3) + delay = 5000; + else + delay = 30000; + if((now - player->lastPingSend) < delay) + return; + if((now - player->lastPingRecv) < (delay + 1500)) + return; + } + + // Go through all the spots. + //////////////////////////// + for(i = (data->max - 1) ; i >= 0 ; i--) + { + // Is it empty? + /////////////// + if(!data->players[i]) + continue; + + // The "other" player. + ////////////////////// + other = data->players[i]; + + // Is this player higher priority than us? + ////////////////////////////////////////// + if((!other->numPings && player->numPings) || // Not pinged. + (other->inRoom[StagingRoom] && !player->inRoom[StagingRoom]) || // In staging room. + (piIsPlayerVIP(other, StagingRoom) && !piIsPlayerVIP(player, StagingRoom)) || // Op or voice in the same staging room. + (strcasecmp(other->nick, player->nick) < 0)) // Alphabetical. + { + break; + } + } + + // Bump it up one, so it's set to our spot. + /////////////////////////////////////////// + i++; + + // Did we not find anything? + //////////////////////////// + if(i == data->max) + return; + + // Bump down the other player and all below. + //////////////////////////////////////////// + for(j = (data->max - 1) ; j > i ; j--) + data->players[j] = data->players[j - 1]; + + // Set this player. + /////////////////// + data->players[i] = player; + + // One more. + //////////// + if(data->num < data->max) + data->num++; +} + +// Returns an array of pointers to players to ping, +// or NULL if there's noone to ping. +// The number of players in the array will be no +// larger than min(PI_MAX_PING_PLAYERS, numPings). +/////////////////////////////////////////////////// +static piPlayer ** piPickPingPlayers +( + PEER peer, + int * numPings +) +{ + static piPlayer * players[PI_MAX_PING_PLAYERS]; + piPickPingPlayersData data; + PEER_CONNECTION; + + // Check for no players. + //////////////////////// + if(!connection->players || !(*numPings) || !TableCount(connection->players)) + { + *numPings = 0; + return NULL; + } + + // Setup a list of players to ping. + /////////////////////////////////// + data.peer = peer; + data.players = players; + data.max = min(PI_MAX_PING_PLAYERS, *numPings); + data.num = 0; + memset(players, 0, sizeof(piPlayer *) * data.max); + TableMap(connection->players, piPickPingPlayersMap, &data); + + // Set number of pings. + /////////////////////// + *numPings = data.num; + + // Check for noone to ping. + /////////////////////////// + if(!data.players[0]) + return NULL; + + return data.players; +} + +static void piXpingPlayer +( + PEER peer, + piPlayer * player +) +{ + int roomType; + char message[(PI_NICK_MAX_LEN * 2) + 32]; + char encodedIP[11]; + + PEER_CONNECTION; + + assert(player->inXpingRoom); + if(!player->inXpingRoom) + return; + + // Setup the message. + ///////////////////// + piMangleIP(encodedIP, player->IP); + sprintf(message, "%s %d", encodedIP, player->pingAverage); + + // Figure out which room to send the xping in. + ////////////////////////////////////////////// + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + if(player->inRoom[roomType] && connection->xpingRoom[roomType]) + { + if(connection->numPlayers[roomType] <= PI_MAX_XPING_NUM_PLAYERS) + { + assert(IN_ROOM || ENTERING_ROOM); + if(IN_ROOM || ENTERING_ROOM) + piSendChannelUTM(peer, ROOM, PI_UTM_XPING, message, PEERFalse); + } + } + } + + // Sent it. + /////////// + player->xpingSent = PEERTrue; + player->lastXping = current_time(); + connection->lastXpingSend = (unsigned int)player->lastXping; +} + +typedef struct piPickXpingPlayerData +{ + PEER peer; + piPlayer * player; +} piPickXpingPlayerData; + +static void piPickXpingPlayerMap +( + void * elem, + void * clientData +) +{ + piPlayer * player = (piPlayer *)elem; + piPickXpingPlayerData * data = (piPickXpingPlayerData *)clientData; + PEER peer = (PEER)data->peer; + unsigned long now; + + PEER_CONNECTION; + + // Not xpinging? + //////////////// + if(!player->inXpingRoom) + return; + + // Don't xping the local player. + //////////////////////////////// + if(player->local) + return; + + // Don't xping if no pings received. + /////////////////////////////////// + if(!player->numPings) + return; + + // Don't xping with the same info. + ////////////////////////////////// + if(player->xpingSent) + return; + + // Don't xping too often. + ///////////////////////// + now = current_time(); + if((now - player->lastXping) < PI_XPING_PLAYER_INTERVAL) + return; + + // First player? + //////////////// + if(!data->player) + { + data->player = player; + } + else if((now - player->lastXping) > (now - data->player->lastXping)) + { + data->player = player; + } +} + +// Returns a player to ping, or NULL if there's noone to ping. +////////////////////////////////////////////////////////////// +static piPlayer * piPickXpingPlayer +( + PEER peer +) +{ + piPickXpingPlayerData data; + PEER_CONNECTION; + + // Check for no players. + //////////////////////// + if(!connection->players || !TableCount(connection->players)) + return NULL; + + // Find someone near the top of the list. + ///////////////////////////////////////// + data.peer = peer; + data.player = NULL; + TableMap(connection->players, piPickXpingPlayerMap, &data); + + return data.player; +} + +void piPingThink +( + PEER peer +) +{ + unsigned long now; + int pingTimeMod; + int numPings; + piPlayer * player; + piPlayer ** players; + int i; + + PEER_CONNECTION; + + // Check if we're not doing pings. + ////////////////////////////////// + if(!connection->doPings) + return; + + // Don't do pings while playing! + //////////////////////////////// + if(connection->playing) + return; + + // Don't do pings while away. + ///////////////////////////// + if(connection->away) + return; + + // Get the current time. + //////////////////////// + now = current_time(); + + // Get the number of pings to send. + /////////////////////////////////// + pingTimeMod = (int)(now / PI_PING_INTERVAL); + if(connection->lastPingTimeMod) + numPings = (pingTimeMod - connection->lastPingTimeMod); + else + numPings = 1; + if(numPings) + connection->lastPingTimeMod = pingTimeMod; + + // Send pings. + ////////////// + players = piPickPingPlayers(peer, &numPings); + if(players) + { + for(i = 0 ; (i < numPings) && players[i] ; i++) + piPingPlayer(peer, players[i]); + } + + // Check for sending a crossping. + ///////////////////////////////// + if((now - connection->lastXpingSend) > PI_XPING_INTERVAL) + { + // Try and pick a player to crossping. + ////////////////////////////////////// + player = piPickXpingPlayer(peer); + if(player) + piXpingPlayer(peer, player); + } + + // Let pinger think. + //////////////////// + pingerThink(); +} + +PEERBool piPingInitPlayer +( + PEER peer, + piPlayer * player +) +{ + int i; + + PEER_CONNECTION; + + assert(player); + + // Check if we're not doing pings. + ////////////////////////////////// + if(!connection->doPings) + return PEERTrue; + + player->lastPingSend = 0; + player->lastPingRecv = 0; + player->lastXping = 0; + player->waitingForPing = PEERFalse; + player->pingsReturned = 0; + player->pingsLostConsecutive = 0; + player->pingAverage = 0; + for(i = 0 ; i < PI_PING_HISTORY_LEN ; i++) + player->pingHistory[i] = 0; + player->pingHistoryNum = 0; + player->numPings = 0; + player->xpingSent = PEERFalse; + player->inPingRoom = PEERFalse; + player->inXpingRoom = PEERFalse; + player->mustPing = PEERFalse; + player->pingOnce = PEERFalse; + + return PEERTrue; +} + +void piPingPlayerJoinedRoom +( + PEER peer, + piPlayer * player, + RoomType roomType +) +{ + PEER_CONNECTION; + + assert(player); + ASSERT_ROOMTYPE(roomType); + + // Check if we're not doing pings. + ////////////////////////////////// + if(!connection->doPings) + return; + + // Is this a ping room? + /////////////////////// + if(connection->pingRoom[roomType]) + player->inPingRoom = PEERTrue; + + // Is this an xping room? + ///////////////////////// + if(connection->xpingRoom[roomType]) + player->inXpingRoom = PEERTrue; + + // Immediately ping players when they join a staging room. + ////////////////////////////////////////////////////////// + if(roomType == StagingRoom) + player->mustPing = PEERTrue; +} + +static void piRemoveXping +( + PEER peer, + piXping * xping +) +{ + PEER_CONNECTION; + + assert(xping); + + TableRemove(connection->xpings, xping); +} + +typedef struct piPingPlayerLeftRoomData +{ + PEER peer; + const char * nick; +} piPingPlayerLeftRoomData; + +static void piPingPlayerLeftRoomTableMapFn +( + void *elem, + void *clientdata +) +{ + piXping * xping = (piXping *)elem; + piPingPlayerLeftRoomData * data = (piPingPlayerLeftRoomData *)clientdata; + assert(xping); + assert(data); + + // Check if this player is part of this xping. + ////////////////////////////////////////////// + if((strcmp(xping->nicks[0], data->nick) == 0) || (strcmp(xping->nicks[1], data->nick) == 0)) + piRemoveXping(data->peer, xping); +} + +void piPingPlayerLeftRoom +( + PEER peer, + piPlayer * player +) +{ + PEER_CONNECTION; + + assert(player); + + // Check if we're not doing pings. + ////////////////////////////////// + if(!connection->doPings) + return; + + // Was this player in a ping room? + ////////////////////////////////// + if(player->inPingRoom) + { + int i; + PEERBool inPingRoom = PEERFalse; + + // Is he still in a ping room? + ////////////////////////////// + for(i = 0 ; i < NumRooms ; i++) + { + if(player->inRoom[i] && connection->pingRoom[i]) + inPingRoom = PEERTrue; + } + player->inPingRoom = inPingRoom; + } + + // Was this player in an xping room? + //////////////////////////////////// + if(player->inXpingRoom) + { + int i; + PEERBool inXpingRoom = PEERFalse; + + // Is he still in a ping room? + ////////////////////////////// + for(i = 0 ; i < NumRooms ; i++) + { + if(player->inRoom[i] && connection->xpingRoom[i]) + inXpingRoom = PEERTrue; + } + player->inXpingRoom = inXpingRoom; + + if(!player->inXpingRoom) + { + piPingPlayerLeftRoomData data; + data.peer = peer; + data.nick = player->nick; + + // Get rid of all this players xpings. + ////////////////////////////////////// + TableMapSafe(connection->xpings, piPingPlayerLeftRoomTableMapFn, &data); + } + } +} + +static piXping * piFindXping +( + PEER peer, + const char * nick1, + const char * nick2 +) +{ + piXping xpingMatch; + + PEER_CONNECTION; + + assert(nick1); + assert(nick1[0]); + assert(piGetPlayer(peer, nick1)); + assert(nick2); + assert(nick2[0]); + assert(piGetPlayer(peer, nick2)); + + // Setup the xping match. + ///////////////////////// + strzcpy(xpingMatch.nicks[0], nick1, PI_NICK_MAX_LEN); + _strlwr(xpingMatch.nicks[0]); + strzcpy(xpingMatch.nicks[1], nick2, PI_NICK_MAX_LEN); + _strlwr(xpingMatch.nicks[0]); + + // Find the xping. + ////////////////// + return (piXping *)TableLookup(connection->xpings, &xpingMatch); +} + +static piXping * piAddXping +( + PEER peer, + const char * nick1, + const char * nick2 +) +{ + piXping xpingMatch; + piXping * xping; + + PEER_CONNECTION; + + assert(nick1); + assert(nick1[0]); + assert(piGetPlayer(peer, nick1)); + assert(nick2); + assert(nick2[0]); + assert(piGetPlayer(peer, nick2)); + + // Setup the one to add. + //////////////////////// + xping = &xpingMatch; + strzcpy(xping->nicks[0], nick1, PI_NICK_MAX_LEN); + _strlwr(xping->nicks[0]); + strzcpy(xping->nicks[1], nick2, PI_NICK_MAX_LEN); + _strlwr(xping->nicks[1]); + + // Add it. + ////////// + TableEnter(connection->xpings, xping); + + // Get it. + ////////// + xping = (piXping *)TableLookup(connection->xpings, &xpingMatch); + + // Return it. + ///////////// + return xping; +} + +void piUpdateXping +( + PEER peer, + const char * nick1, + const char * nick2, + int ping +) +{ + piPlayer * player1; + piPlayer * player2; + piXping * xping; + + PEER_CONNECTION; + + assert(nick1); + assert(nick1[0]); + assert(piGetPlayer(peer, nick1)); + assert(nick2); + assert(nick2[0]); + assert(piGetPlayer(peer, nick2)); + assert(ping >= 0); + + // Check if we're not doing pings. + ////////////////////////////////// + if(!connection->doPings) + return; + + player1 = piGetPlayer(peer, nick1); + if(!player1) + return; + if(!player1->inXpingRoom) + return; + player2 = piGetPlayer(peer, nick2); + if(!player2) + return; + if(!player2->inXpingRoom) + return; + + // Add it. + ////////// + xping = piAddXping(peer, nick1, nick2); + assert(xping); + if(!xping) + return; + + // Update. + ////////// + xping->ping = ping; +} + +PEERBool piGetXping +( + PEER peer, + const char * nick1, + const char * nick2, + int * ping +) +{ + piXping * xping; + + PEER_CONNECTION; + + assert(nick1); + assert(nick1[0]); + assert(piGetPlayer(peer, nick1)); + assert(nick2); + assert(nick2[0]); + assert(piGetPlayer(peer, nick2)); + assert(ping); + + // Check if we're not doing pings. + ////////////////////////////////// + if(!connection->doPings) + return PEERFalse; + + // Get the xping. + ///////////////// + xping = piFindXping(peer, nick1, nick2); + assert(xping); + if(!xping) + return PEERFalse; + + // Return the ping. + /////////////////// + *ping = xping->ping; + + return PEERTrue; +} diff --git a/xrGameSpy/gamespy/Peer/peerPing.h b/xrGameSpy/gamespy/Peer/peerPing.h new file mode 100644 index 00000000000..99757acd18d --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerPing.h @@ -0,0 +1,41 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERPING_H_ +#define _PEERPING_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/************** +** FUNCTIONS ** +**************/ +PEERBool piPingInit(PEER peer); +void piPingCleanup(PEER peer); +void piPingThink(PEER peer); +PEERBool piPingInitPlayer(PEER peer, piPlayer * player); +void piPingPlayerJoinedRoom(PEER peer, piPlayer * player, RoomType roomType); +void piPingPlayerLeftRoom(PEER peer, piPlayer * player); +void piUpdateXping(PEER peer, const char * nick1, const char * nick2, int ping); +PEERBool piGetXping(PEER peer, const char * nick1, const char * nick2, int * ping); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerPlayers.c b/xrGameSpy/gamespy/Peer/peerPlayers.c new file mode 100644 index 00000000000..0d5db95900d --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerPlayers.c @@ -0,0 +1,824 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include "peerPlayers.h" +#include "peerPing.h" +#include "peerCallbacks.h" +#include "peerKeys.h" + +/************ +** DEFINES ** +************/ +#define PI_PLAYERS_NUM_BUCKETS 32 +#define PI_PLAYER_INFO_SIZE (sizeof(piPlayer) - PI_NICK_MAX_LEN) +#define PI_PLAYER_INFO(player) ((char *)(player) + PI_NICK_MAX_LEN) + +/************** +** FUNCTIONS ** +**************/ +static int piPlayersTableHashFn +( + const void *elem, + int numBuckets +) +{ + piPlayer * player = (piPlayer *)elem; + int c; + const char * str; + unsigned int hash; + + assert(player); + assert(player->nick[0]); + + // Get the hash. + //////////////// + str = player->nick; + hash = 0; + while((c = *str++) != '\0') + hash += (unsigned int)tolower(c); + hash %= (unsigned int)numBuckets; + + return (int)hash; +} + +static int GS_STATIC_CALLBACK piPlayersTableCompareFn +( + const void *elem1, + const void *elem2 +) +{ + piPlayer * player1 = (piPlayer *)elem1; + piPlayer * player2 = (piPlayer *)elem2; + assert(player1); + assert(player1->nick[0]); + assert(player2); + assert(player2->nick[0]); + + return strcasecmp(player1->nick, player2->nick); +} + +static void piPlayersTableElementFreeFn +( + void *elem +) +{ + piPlayer * player = (piPlayer *)elem; + assert(player); + assert(player->nick); + GSI_UNUSED(player); +} + +PEERBool piPlayersInit +( + PEER peer +) +{ + int i; + + PEER_CONNECTION; + + if(connection->stayInTitleRoom) + return PEERTrue; + + // Setup the player table. + ////////////////////////// + connection->players = TableNew(sizeof(piPlayer), PI_PLAYERS_NUM_BUCKETS, piPlayersTableHashFn, piPlayersTableCompareFn, piPlayersTableElementFreeFn); + if(!connection->players) + return PEERFalse; + + // No players in any room. + ////////////////////////// + for(i = 0 ; i < NumRooms ; i++) + connection->numPlayers[i] = 0; + + return PEERTrue; +} + +void piPlayersCleanup +( + PEER peer +) +{ + int i; + + PEER_CONNECTION; + + if(connection->stayInTitleRoom) + return; + + // gsifree the player table. + ///////////////////////// + if(connection->players) + TableFree(connection->players); + connection->players = NULL; + for(i = 0 ; i < NumRooms ; i++) + connection->numPlayers[i] = 0; +} + +static piPlayer * piAddPlayer +( + PEER peer, + const char * nick, + PEERBool initialize +) +{ + piPlayer * player; + piPlayer playerMatch; + + PEER_CONNECTION; + + assert(!piGetPlayer(peer, nick)); + + // Setup the player. + //////////////////// + player = &playerMatch; + memset(player, 0, sizeof(piPlayer)); + strzcpy(player->nick, nick, PI_NICK_MAX_LEN); + if(initialize) + { + int roomType; + + player->local = (PEERBool)(strcasecmp(nick, connection->nick) == 0); + + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + player->inRoom[roomType] = PEERFalse; + player->flags[roomType] = 0; + } + + player->IP = 0; + player->profileID = 0; + player->gotIPAndProfileID = PEERFalse; + + if(!piPingInitPlayer(peer, player)) + return NULL; + } + + // Add the player. + ////////////////// + TableEnter(connection->players, player); + + player = piGetPlayer(peer, nick); + assert(player); + + return player; +} + +static void piRemovePlayer +( + PEER peer, + piPlayer * player +) +{ + PEER_CONNECTION; + + assert(player); + + // Remove it. + ///////////// + TableRemove(connection->players, player); +} + +piPlayer * piPlayerJoinedRoom +( + PEER peer, + const char * nick, + RoomType roomType, + int mode +) +{ + piPlayer * player; + + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + ASSERT_ROOMTYPE(roomType); + assert(IN_ROOM || ENTERING_ROOM); + + // Check that we're in/entering this room. + ////////////////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return NULL; + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + + // Is it a new player? + ////////////////////// + if(!player) + { + // Add the player. + ////////////////// + player = piAddPlayer(peer, nick, PEERTrue); + } + + // In this room. + //////////////// + assert(!player->inRoom[roomType]); + player->inRoom[roomType] = PEERTrue; + connection->numPlayers[roomType]++; + player->flags[roomType] = 0; + if(mode & CHAT_OP) + player->flags[roomType] |= PEER_FLAG_OP; + if(mode & CHAT_VOICE) + player->flags[roomType] |= PEER_FLAG_VOICE; + + // Do ping stuff. + ///////////////// + piPingPlayerJoinedRoom(peer, player, roomType); + + return player; +} + +void piPlayerLeftRoom +( + PEER peer, + const char * nick, + RoomType roomType +) +{ + piPlayer * player; + + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + ASSERT_ROOMTYPE(roomType); + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + assert(player); + if(!player) + return; + + // Leave the room. + ////////////////// + assert(player->inRoom[roomType]); + player->inRoom[roomType] = PEERFalse; + connection->numPlayers[roomType]--; + player->flags[roomType] = 0; + + // Do ping stuff. + ///////////////// + piPingPlayerLeftRoom(peer, player); + + // Are we not in any rooms now? + /////////////////////////////// + if(!player->inRoom[0] && !player->inRoom[1] && !player->inRoom[2]) + { + // This player is out. + ////////////////////// + piRemovePlayer(peer, player); + } + + // Cleanse the key cache. + ///////////////////////// + piKeyCacheCleanse(peer); +} + +void piPlayerChangedNick +( + PEER peer, + const char * oldNick, + const char * newNick +) +{ + char playerInfoBuffer[PI_PLAYER_INFO_SIZE]; + piPlayer * player; + + assert(oldNick); + assert(oldNick[0]); + assert(newNick); + assert(newNick[0]); + + // Find the player. + /////////////////// + player = piGetPlayer(peer, oldNick); + + // Check if we can't find this player + // (we could have already done the nick change + // if we're in more than one channel together). + /////////////////////////////////////////////// + if(!player) + return; + + // Save off the player info. + //////////////////////////// + memcpy(playerInfoBuffer, PI_PLAYER_INFO(player), PI_PLAYER_INFO_SIZE); + + // Remove the old nick. + /////////////////////// + piRemovePlayer(peer, player); + + // Add the new one. + /////////////////// + player = piAddPlayer(peer, newNick, PEERFalse); + assert(player); + if(!player) + return; + + // Copy the player info back in. + //////////////////////////////// + memcpy(PI_PLAYER_INFO(player), playerInfoBuffer, PI_PLAYER_INFO_SIZE); + + // Update the key cache. + //////////////////////// + piKeyCachePlayerChangedNick(peer, oldNick, newNick); +} + +typedef struct piLeftRoomData +{ + PEER peer; + RoomType roomType; +} piLeftRoomData; + +static void piLeftRoomMapFn +( + void *elem, + void *clientdata +) +{ + piPlayer * player = (piPlayer *)elem; + piLeftRoomData * data = (piLeftRoomData *)clientdata; + assert(player); + assert(player->nick); + assert(data); + + // Is the player in this room? + ////////////////////////////// + if(player->inRoom[data->roomType]) + { + // Leave the room. + ////////////////// + piPlayerLeftRoom(data->peer, player->nick, data->roomType); + } +} + +void piClearRoomPlayers +( + PEER peer, + RoomType roomType +) +{ + piLeftRoomData data; + + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + + // Go through all the players. + ////////////////////////////// + data.peer = peer; + data.roomType = roomType; + TableMapSafe(connection->players, piLeftRoomMapFn, &data); +} + +piPlayer * piGetPlayer +( + PEER peer, + const char * nick +) +{ + piPlayer playerMatch; + piPlayer * player; + + PEER_CONNECTION; + + assert(nick); + assert(nick[0]); + + // Check for no table. + ////////////////////// + if(!connection->players) + return NULL; + + // Lookup this player. + ////////////////////// + strzcpy(playerMatch.nick, nick, PI_NICK_MAX_LEN); + player = (piPlayer *)TableLookup(connection->players, &playerMatch); + + return player; +} + +typedef struct piEnumRoomPlayersData +{ + PEER peer; + RoomType roomType; + int count; + piEnumRoomPlayersCallback callback; + void * param; +} piEnumRoomPlayersData; + +static void piEnumRoomPlayersMap +( + void *elem, + void *clientdata +) +{ + piPlayer * player = (piPlayer *)elem; + piEnumRoomPlayersData * data = (piEnumRoomPlayersData *)clientdata; + // Is this player in the room? + ////////////////////////////// + if(player->inRoom[data->roomType]) + { + // Call the callback. + ///////////////////// + data->callback(data->peer, data->roomType, player, data->count, data->param); + + // One more player. + /////////////////// + data->count++; + } +} + +void piEnumRoomPlayers +( + PEER peer, + RoomType roomType, + piEnumRoomPlayersCallback callback, + void * param +) +{ + piEnumRoomPlayersData data; + + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + assert(callback); + + // Init the data. + ///////////////// + data.peer = peer; + data.roomType = roomType; + data.count = 0; + data.callback = callback; + data.param = param; + + // Enum through the players. + //////////////////////////// + TableMap(connection->players, piEnumRoomPlayersMap, &data); + + // Call the callback once to terminate the enum. + //////////////////////////////////////////////// + callback(peer, roomType, NULL, -1, param); +} + +static int piFindPlayersByIPMap +( + void * elem, + void * clientdata +) +{ + piPlayer * player = (piPlayer *)elem; + unsigned int IP; + + IP = *(unsigned int *)clientdata; + + // Is this the same IP? + /////////////////////// + if(player->gotIPAndProfileID && (player->IP == IP)) + return 0; + + return 1; +} + +piPlayer * piFindPlayerByIP +( + PEER peer, + unsigned int IP +) +{ + PEER_CONNECTION; + + return (piPlayer *)TableMap2(connection->players, piFindPlayersByIPMap, &IP); +} + +void piSetPlayerIPAndProfileID +( + PEER peer, + const char * nick, + unsigned int IP, + int profileID +) +{ + piPlayer * player; + + assert(nick); + assert(nick[0]); + + if(!nick) + return; + + // Cache the info. + ////////////////// + player = piGetPlayer(peer, nick); + if(player) + { + player->IP = IP; + player->profileID = profileID; + + if(!player->gotIPAndProfileID) + { + player->gotIPAndProfileID = PEERTrue; + + // The IP is now available, send a ping + //////////////////////////////////////// + if(player->inRoom[TitleRoom]) + piPingPlayerJoinedRoom(peer, player, TitleRoom); + if(player->inRoom[GroupRoom]) + piPingPlayerJoinedRoom(peer, player, GroupRoom); + if(player->inRoom[StagingRoom]) + piPingPlayerJoinedRoom(peer, player, StagingRoom); + } + + } +} + +static void piSetNewPlayerFlags +( + PEER peer, + const char * nick, + RoomType roomType, + int flags +) +{ + piPlayer * player; + int oldFlags; + + assert(nick); + assert(nick[0]); + + if(!nick) + return; + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + if(!player || !player->inRoom[roomType]) + return; + + // Copy off the old flags. + ////////////////////////// + oldFlags = player->flags[roomType]; + + // Check for no change. + /////////////////////// + if(flags == oldFlags) + return; + + // Set the new flags. + ///////////////////// + player->flags[roomType] = flags; + + // If ready changed in the staging room, call a callback. + ///////////////////////////////////////////////////////// + if((roomType == StagingRoom) && ((oldFlags & PEER_FLAG_READY) != (flags & PEER_FLAG_READY))) + piAddReadyChangedCallback(peer, player->nick, (PEERBool)((player->flags[roomType] & PEER_FLAG_READY) != 0)); + + // Call the flags changed callback. + /////////////////////////////////// + piAddPlayerFlagsChangedCallback(peer, roomType, nick, oldFlags, flags); +} + +int piParseFlags +( + const char * flags +) +{ + int nFlags = 0; + + if(strchr(flags, 's')) + nFlags |= PEER_FLAG_STAGING; + if(strchr(flags, 'r')) + nFlags |= PEER_FLAG_READY; + if(strchr(flags, 'g')) + nFlags |= PEER_FLAG_PLAYING; + if(strchr(flags, 'a')) + nFlags |= PEER_FLAG_AWAY; + if(strchr(flags, 'h')) + nFlags |= PEER_FLAG_HOST; + + return nFlags; +} + +void piSetPlayerRoomFlags +( + PEER peer, + const char * nick, + RoomType roomType, + const char * flags +) +{ + piPlayer * player; + int nFlags; + + assert(nick); + assert(nick[0]); + + if(!nick) + return; + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + if(!player || !player->inRoom[roomType]) + return; + + // Get the mode. + //////////////// + nFlags = (player->flags[roomType] & (PEER_FLAG_OP | PEER_FLAG_VOICE)); + + // Add the new flags. + ///////////////////// + nFlags |= piParseFlags(flags); + + // Set them. + //////////// + piSetNewPlayerFlags(peer, nick, roomType, nFlags); +} + +void piSetPlayerModeFlags +( + PEER peer, + const char * nick, + RoomType roomType, + int mode +) +{ + piPlayer * player; + int nFlags; + + assert(nick); + assert(nick[0]); + + if(!nick) + return; + + // Find the player. + /////////////////// + player = piGetPlayer(peer, nick); + if(!player || !player->inRoom[roomType]) + return; + + // Get the non-mode flags. + ////////////////////////// + nFlags = (player->flags[roomType] & (~(PEER_FLAG_OP | PEER_FLAG_VOICE))); + + // Add the new flags. + ///////////////////// + if(mode & CHAT_OP) + nFlags |= PEER_FLAG_OP; + if(mode & CHAT_VOICE) + nFlags |= PEER_FLAG_VOICE; + + // Set them. + //////////// + piSetNewPlayerFlags(peer, nick, roomType, nFlags); +} + +PEERBool piIsPlayerVIP +( + piPlayer * player, + RoomType roomType +) +{ + if(!player) + return PEERFalse; + + if(!player->inRoom[roomType]) + return PEERFalse; + + return (PEERBool)((player->flags[roomType] & (PEER_FLAG_OP | PEER_FLAG_VOICE)) != 0); +} + +PEERBool piIsPlayerHost(piPlayer * player) +{ + if(!player) + return PEERFalse; + + if(!player->inRoom[StagingRoom]) + return PEERFalse; + + return (PEERBool)((player->flags[StagingRoom] & (PEER_FLAG_OP | PEER_FLAG_HOST)) == (PEER_FLAG_OP | PEER_FLAG_HOST)); +} + +PEERBool piIsPlayerOp(piPlayer * player) +{ + if(!player) + return PEERFalse; + + if(!player->inRoom[StagingRoom]) + return PEERFalse; + + return (PEERBool)(player->flags[StagingRoom] & PEER_FLAG_OP); +} + +typedef struct piFindPlayerByIndexData +{ + int index; + int count; + RoomType roomType; +} piFindPlayerByIndexData; + +static int piFindPlayerByIndexMap +( + void * elem, + void * clientdata +) +{ + piPlayer * player = (piPlayer *)elem; + piFindPlayerByIndexData * data = (piFindPlayerByIndexData *)clientdata; + + // check if the player is in the room + if(player->inRoom[data->roomType]) + { + // check if this is the one we're looking for + if(data->index == data->count) + return 0; + + // one more player found + data->count++; + } + + return 1; +} + +piPlayer * piFindPlayerByIndex +( + PEER peer, + RoomType roomType, + int index +) +{ + piFindPlayerByIndexData data; + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + + // setup the data + data.index = index; + data.count = 0; + data.roomType = roomType; + + // enum through the players + return TableMap2(connection->players, piFindPlayerByIndexMap, &data); +} + +typedef struct piCountRoomOpsMapData +{ + int count; + RoomType roomType; + const char * exclude; +} piCountRoomOpsMapData; + +static void piCountRoomOpsMap +( + void * elem, + void * clientdata +) +{ + piPlayer * player = (piPlayer *)elem; + piCountRoomOpsMapData * data = (piCountRoomOpsMapData *)clientdata; + + // check the exlude nick + if(data->exclude && (strcasecmp(data->exclude, player->nick) == 0)) + return; + + // is this player an op? + if(player->flags[data->roomType] & PEER_FLAG_OP) + data->count++; +} + +int piCountRoomOps(PEER peer, RoomType roomType, const char * exclude) +{ + piCountRoomOpsMapData data; + + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + + // setup the data struct + data.count = 0; + data.roomType = roomType; + data.exclude = exclude; + + // enum through the players + TableMap(connection->players, piCountRoomOpsMap, &data); + + // return the count + return data.count; +} diff --git a/xrGameSpy/gamespy/Peer/peerPlayers.h b/xrGameSpy/gamespy/Peer/peerPlayers.h new file mode 100644 index 00000000000..9820e8219a8 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerPlayers.h @@ -0,0 +1,92 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERPLAYERS_H_ +#define _PEERPLAYERS_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/************ +** DEFINES ** +************/ +#define PI_PING_HISTORY_LEN 4 + +/********** +** TYPES ** +**********/ +typedef struct piPlayer +{ + char nick[PI_NICK_MAX_LEN]; // this has to be first + PEERBool inRoom[NumRooms]; // true if in the room + PEERBool local; // true for the local player + + unsigned int IP; // the IP in network byte order + int profileID; // gp profile id + PEERBool gotIPAndProfileID; // true if we have the IP and profile ID + + int flags[NumRooms]; // player's room flags + + // Ping stuff + unsigned long lastPingSend; // last time a ping was sent + unsigned long lastPingRecv; // last time a ping was received + unsigned long lastXping; // last time a xping was sent + PEERBool waitingForPing; // if true we're waiting for a ping to return + int pingsReturned; // number of pings returned + int pingsLostConsecutive; // number of pings lost in a row + int pingAverage; // the average ping time + int pingHistory[PI_PING_HISTORY_LEN]; // history of pings + int pingHistoryNum; // the number of pings in the ping history + int numPings; // number of pings for this player + PEERBool xpingSent; // if true, we already sent a xping with the current average + PEERBool inPingRoom; // true if the player is in a room getting pinged + PEERBool inXpingRoom; // true if the player is in a room getting xpinged + PEERBool mustPing; // if true, ping this player as soon as possible + PEERBool pingOnce; // a one-time ping has been triggered with peerPingPlayer +} piPlayer; + +/************** +** FUNCTIONS ** +**************/ +PEERBool piPlayersInit(PEER peer); +void piPlayersCleanup(PEER peer); +piPlayer * piPlayerJoinedRoom(PEER peer, const char * nick, RoomType roomType, int mode); +void piPlayerLeftRoom(PEER peer, const char * nick, RoomType roomType); +void piPlayerChangedNick(PEER peer, const char * oldNick, const char * newNick); +void piClearRoomPlayers(PEER peer, RoomType roomType); +piPlayer * piGetPlayer(PEER peer, const char * nick); +typedef void (* piEnumRoomPlayersCallback)(PEER peer, RoomType roomType, piPlayer * player, int index, void * param); +void piEnumRoomPlayers(PEER peer, RoomType roomType, piEnumRoomPlayersCallback callback, void * param); +piPlayer * piFindPlayerByIP(PEER peer, unsigned int IP); +void piSetPlayerIPAndProfileID(PEER peer, const char * nick, unsigned int IP, int profileID); +int piParseFlags(const char * flags); +void piSetPlayerRoomFlags(PEER peer, const char * nick, RoomType roomType, const char * flags); +void piSetPlayerModeFlags(PEER peer, const char * nick, RoomType roomType, int mode); +PEERBool piIsPlayerVIP(piPlayer * player, RoomType roomType); +PEERBool piIsPlayerHost(piPlayer * player); +PEERBool piIsPlayerOp(piPlayer * player); +piPlayer * piFindPlayerByIndex(PEER peer, RoomType roomType, int index); +piPlayer * piFindRoomHost(PEER peer, RoomType roomType); +piPlayer * piFindRoomOp(PEER peer, RoomType roomType); +int piCountRoomOps(PEER peer, RoomType roomType, const char * exclude); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerQR.c b/xrGameSpy/gamespy/Peer/peerQR.c new file mode 100644 index 00000000000..d70ab916b9a --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerQR.c @@ -0,0 +1,494 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include "peerQR.h" +#include "peerGlobalCallbacks.h" +#include "peerPlayers.h" +#include "peerAutoMatch.h" +#include "peerOperations.h" + +/************** +** CALLBACKS ** +**************/ +#ifndef GSI_UNICODE +#define piQRAddErrorCallback piQRAddErrorCallbackA +#else +#define piQRAddErrorCallback piQRAddErrorCallbackW +#endif + +static void piQRServerKeyCallback +( + int key, + qr2_buffer_t buffer, + PEER peer +) +{ + PEER_CONNECTION; + + // check if we should report it + if(connection->inRoom[StagingRoom] && (!connection->playing || (connection->reportingOptions & PEER_REPORT_INFO))) + { + // check if it's one of our keys + switch(key) + { + case HOSTNAME_KEY: + qr2_buffer_addA(buffer, NAMES[StagingRoom]); + return; + case NUMPLAYERS_KEY: + qr2_buffer_add_int(buffer, connection->numPlayers[StagingRoom]); + return; + case MAXPLAYERS_KEY: + if(!connection->maxPlayers) + break; + qr2_buffer_add_int(buffer, connection->maxPlayers); + return; + case GAMEMODE_KEY: + if(connection->playing) + break; + qr2_buffer_addA(buffer, "openstaging"); + return; + case PASSWORD_KEY: + qr2_buffer_add_int(buffer, connection->passwordedRoom?1:0); + return; + } + } + + // we always report groupid + if(key == GROUPID_KEY) + { + qr2_buffer_add_int(buffer, connection->reportingGroupID); + return; + } + + // pass it to the app + if(connection->callbacks.qrServerKey) + connection->callbacks.qrServerKey(peer, key, buffer, connection->callbacks.param); +} + +static void piQRPlayerKeyCallback +( + int key, + int index, + qr2_buffer_t buffer, + PEER peer +) +{ + piPlayer * player; + PEER_CONNECTION; + + // check if we should report it + if(connection->inRoom[StagingRoom] && (!connection->playing || (connection->reportingOptions & PEER_REPORT_PLAYERS))) + { + // check if it's a key we report + if((key == PLAYER__KEY) || (key == PING__KEY)) + { + // convert the index to a player + player = piFindPlayerByIndex(peer, StagingRoom, index); + if(!player) + qr2_buffer_addA(buffer, ""); + else if(key == PLAYER__KEY) + qr2_buffer_addA(buffer, player->nick); + else if(key == PING__KEY) + qr2_buffer_add_int(buffer, player->pingAverage); + + return; + } + } + + // pass it to the app + if(connection->callbacks.qrPlayerKey) + connection->callbacks.qrPlayerKey(peer, key, index, buffer, connection->callbacks.param); +} + +static void piQRTeamKeyCallback +( + int key, + int index, + qr2_buffer_t buffer, + PEER peer +) +{ + PEER_CONNECTION; + + // pass it to the app + if(connection->callbacks.qrTeamKey) + connection->callbacks.qrTeamKey(peer, key, index, buffer, connection->callbacks.param); +} + +static void piQRKeyListCallback +( + qr2_key_type type, + qr2_keybuffer_t keyBuffer, + PEER peer +) +{ + PEER_CONNECTION; + + // add our own keys + switch(type) + { + case key_server: + if(!connection->autoMatchReporting) + { + qr2_keybuffer_add(keyBuffer, HOSTNAME_KEY); + qr2_keybuffer_add(keyBuffer, GAMEMODE_KEY); + if(connection->passwordedRoom) + qr2_keybuffer_add(keyBuffer, PASSWORD_KEY); + if(connection->reportingGroupID) + qr2_keybuffer_add(keyBuffer, GROUPID_KEY); + } + qr2_keybuffer_add(keyBuffer, NUMPLAYERS_KEY); + if(connection->maxPlayers) + qr2_keybuffer_add(keyBuffer, MAXPLAYERS_KEY); + break; + case key_player: + qr2_keybuffer_add(keyBuffer, PLAYER__KEY); + qr2_keybuffer_add(keyBuffer, PING__KEY); + break; + default: + break; + } + + // pass it to the app + if(connection->callbacks.qrKeyList) + connection->callbacks.qrKeyList(peer, type, keyBuffer, connection->callbacks.param); +} + +static int piQRCountCallback +( + qr2_key_type type, + PEER peer +) +{ + PEER_CONNECTION; + + // we only handle player counts + if(type == key_player) + { + // check if we should report it + if(connection->inRoom[StagingRoom] && (!connection->playing || (connection->reportingOptions & PEER_REPORT_PLAYERS))) + return connection->numPlayers[StagingRoom]; + } + + // pass it to the app + if(connection->callbacks.qrCount) + return connection->callbacks.qrCount(peer, type, connection->callbacks.param); + + // app's not handling it + return 0; +} + +static void piQRAddErrorCallbackA +( + qr2_error_t error, + char * errorString, + PEER peer +) +{ + PEER_CONNECTION; + + // handle this if automatching + if(peerIsAutoMatching(peer)) + { + PEERAutoMatchStatus status; + + // track the error + connection->autoMatchQRFailed = PEERTrue; + + // switch to a new state + if(connection->autoMatchSBFailed && (connection->autoMatchStatus != PEERStaging)) + status = PEERFailed; + else + status = PEERSearching; + piSetAutoMatchStatus(peer, status); + + return; + } + + // pass it to the app + if(connection->callbacks.qrAddError) + { +#ifndef GSI_UNICODE + connection->callbacks.qrAddError(peer, error, errorString, connection->callbacks.param); +#else + unsigned short* errorString_W = UTF8ToUCS2StringAlloc(errorString); + connection->callbacks.qrAddError(peer, error, errorString_W, connection->callbacks.param); + gsifree(errorString_W); +#endif + } +} +#ifdef GSI_UNICODE +static void piQRAddErrorCallbackW +( + qr2_error_t error, + unsigned short * errorString, + PEER peer +) +{ + char* errorString_A = UCS2ToUTF8StringAlloc(errorString); + piQRAddErrorCallbackA(error, errorString_A, peer); + gsifree(errorString_A); +} +#endif + +static void piQRNatNegotiateCallback +( + int cookie, + PEER peer +) +{ + PEER_CONNECTION; + + // pass it to the app + if(connection->callbacks.qrNatNegotiateCallback) + connection->callbacks.qrNatNegotiateCallback(peer, cookie, connection->callbacks.param); +} + +static void piQRPublicAddressCallback +( + unsigned int ip, + unsigned short port, + PEER peer +) +{ + PEER_CONNECTION; + + // pass it to the app + if(connection->callbacks.qrPublicAddressCallback) + connection->callbacks.qrPublicAddressCallback(peer, ip, port, connection->callbacks.param); +} + +/************** +** FUNCTIONS ** +**************/ +PEERBool piStartReporting +( + PEER peer, + SOCKET socket, + unsigned short port +) +{ + int rcode; + + PEER_CONNECTION; + + // Check that we're not reporting. + ////////////////////////////////// + assert(!connection->queryReporting); + if(connection->queryReporting) + piStopReporting(peer); + + // Init qr2. + //////////// + if(socket == INVALID_SOCKET) + { + rcode = qr2_initA(&connection->queryReporting, NULL, PI_QUERYPORT, connection->title, connection->qrSecretKey, + 1, connection->natNegotiate, + piQRServerKeyCallback, + piQRPlayerKeyCallback, + piQRTeamKeyCallback, + piQRKeyListCallback, + piQRCountCallback, + piQRAddErrorCallback, + peer); + } + else + { + rcode = qr2_init_socketA(&connection->queryReporting, socket, port, connection->title, connection->qrSecretKey, + 1, connection->natNegotiate, + piQRServerKeyCallback, + piQRPlayerKeyCallback, + piQRTeamKeyCallback, + piQRKeyListCallback, + piQRCountCallback, + piQRAddErrorCallback, + peer); + } + + if(rcode != 0) + return PEERFalse; + + // Store the ID of the group room we're in. + /////////////////////////////////////////// + connection->reportingGroupID = connection->groupID; + + // Setup the nat-negotiate callback. + //////////////////////////////////// + qr2_register_natneg_callback(connection->queryReporting, piQRNatNegotiateCallback); + + // Set the public address callback. + /////////////////////////////////// + qr2_register_publicaddress_callback(connection->queryReporting, piQRPublicAddressCallback); + + // No options. + ////////////// + connection->reportingOptions = 0; + + return PEERTrue; +} + +void piStopReporting +( + PEER peer +) +{ + PEER_CONNECTION; + + // Check that we're reporting. + ////////////////////////////// + if(!connection->queryReporting) + return; + + // Clean up query-reporting. + //////////////////////////// + qr2_shutdown(connection->queryReporting); + connection->queryReporting = NULL; +} + +void piSendStateChanged +( + PEER peer +) +{ + PEER_CONNECTION; + + // Check that we're reporting. + ////////////////////////////// + if(!connection->queryReporting) + return; + + // Send the statechanged. + ///////////////////////// + qr2_send_statechanged(connection->queryReporting); +} + +void piQRThink +( + PEER peer +) +{ + PEER_CONNECTION; + + if(connection->queryReporting) + qr2_think(connection->queryReporting); + if(connection->autoMatchReporting) + qr2_think(connection->autoMatchReporting); +} + +PEERBool piStartAutoMatchReporting +( + PEER peer +) +{ + piOperation * operation; + char autoMatchTitle[PI_TITLE_MAX_LEN]; + int rcode; + + PEER_CONNECTION; + + // Check that we're not reporting. + ////////////////////////////////// + assert(!connection->autoMatchReporting); + if(connection->autoMatchReporting) + piStopAutoMatchReporting(peer); + + // Get the operation. + ///////////////////// + operation = connection->autoMatchOperation; + assert(operation); + + // Setup the AutoMatch gamename. + //////////////////////////////// + strzcpy(autoMatchTitle, connection->title, sizeof(autoMatchTitle)); + strzcat(autoMatchTitle, "am", sizeof(autoMatchTitle)); + + // Init qr2. + //////////// + if(operation->socket == INVALID_SOCKET) + { + rcode = qr2_initA(&connection->autoMatchReporting, NULL, PI_QUERYPORT, autoMatchTitle, connection->qrSecretKey, + 1, connection->natNegotiate, + piQRServerKeyCallback, + piQRPlayerKeyCallback, + piQRTeamKeyCallback, + piQRKeyListCallback, + piQRCountCallback, + piQRAddErrorCallback, + peer); + } + else + { + rcode = qr2_init_socketA(&connection->autoMatchReporting, operation->socket, operation->port, autoMatchTitle, connection->qrSecretKey, + 1, connection->natNegotiate, + piQRServerKeyCallback, + piQRPlayerKeyCallback, + piQRTeamKeyCallback, + piQRKeyListCallback, + piQRCountCallback, + piQRAddErrorCallback, + peer); + + // If we created the socket, hand over responsibility for it to qr2. + //////////////////////////////////////////////////////////////////// + if(operation->socketClose) + { + operation->socketClose = PEERFalse; + connection->autoMatchReporting->read_socket = 1; + } + } + + // Set the error flag. + ////////////////////// + connection->autoMatchQRFailed = (rcode == 0)?PEERTrue:PEERFalse; + + // Return false if there was an error. + ////////////////////////////////////// + if(rcode != 0) + return PEERFalse; + + // Setup the nat-negotiate callback. + //////////////////////////////////// + qr2_register_natneg_callback(connection->autoMatchReporting, piQRNatNegotiateCallback); + + // Set the public address callback. + /////////////////////////////////// + qr2_register_publicaddress_callback(connection->autoMatchReporting, piQRPublicAddressCallback); + + return PEERTrue; +} + +void piStopAutoMatchReporting +( + PEER peer +) +{ + PEER_CONNECTION; + + // Check that we're reporting. + ////////////////////////////// + if(!connection->autoMatchReporting) + return; + + // Clean up query-reporting. + //////////////////////////// + qr2_shutdown(connection->autoMatchReporting); + connection->autoMatchReporting = NULL; + + // This socket should have been cleared after qr2_shutdown + // but it's a copy of connection->autoMatchReporting->hbsock + // Thus it needs to be cleared if it hasn't been already + if (connection->autoMatchOperation->socket != INVALID_SOCKET) + { + connection->autoMatchOperation->socket = INVALID_SOCKET; + } +} diff --git a/xrGameSpy/gamespy/Peer/peerQR.h b/xrGameSpy/gamespy/Peer/peerQR.h new file mode 100644 index 00000000000..0805a6565bc --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerQR.h @@ -0,0 +1,44 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERQR_H_ +#define _PEERQR_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/************ +** DEFINES ** +************/ +#define PI_QUERYPORT 6500 + +/************** +** FUNCTIONS ** +**************/ +PEERBool piStartReporting(PEER peer, SOCKET socket, unsigned short port); +void piStopReporting(PEER peer); +void piSendStateChanged(PEER peer); +void piQRThink(PEER peer); +PEERBool piStartAutoMatchReporting(PEER peer); +void piStopAutoMatchReporting(PEER peer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerRooms.c b/xrGameSpy/gamespy/Peer/peerRooms.c new file mode 100644 index 00000000000..d7128e8ddfb --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerRooms.c @@ -0,0 +1,416 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include "peerRooms.h" +#include "peerPlayers.h" +#include "peerMangle.h" +#include "peerCallbacks.h" +#include "peerKeys.h" +#include "peerQR.h" +#include "peerHost.h" +#include "peerOperations.h" +#include "peerSB.h" + +/************** +** FUNCTIONS ** +**************/ +PEERBool piRoomsInit +( + PEER peer +) +{ + int roomType; + + PEER_CONNECTION; + + // Init rooms. + ////////////// + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + if(connection->stayInTitleRoom && ((RoomType)roomType == TitleRoom)) + continue; + + ROOM[0] = '\0'; + NAME[0] = '\0'; + ENTERING_ROOM = PEERFalse; + IN_ROOM = PEERFalse; + connection->oldFlags[roomType] = 0; + +#ifdef GSI_UNICODE + ROOM_W[0] = '\0'; +#endif + } + connection->groupID = 0; + connection->titleRoomChannel[0] = '\0'; + + return PEERTrue; +} + +void piRoomsCleanup +( + PEER peer +) +{ + int roomType; + + PEER_CONNECTION; + + // Check all the rooms. + /////////////////////// + for(roomType = 0 ; roomType < NumRooms ; roomType++) + { + if(connection->stayInTitleRoom && ((RoomType)roomType == TitleRoom)) + continue; + + // Are we in or entering the room? + ////////////////////////////////// + if(IN_ROOM || ENTERING_ROOM) + { + // Leave it. + //////////// + piLeaveRoom(peer, (RoomType)roomType, NULL); + } + ROOM[0] = '\0'; + NAME[0] = '\0'; + ENTERING_ROOM = PEERFalse; + IN_ROOM = PEERFalse; + } + connection->titleRoomChannel[0] = '\0'; +} + +void piStartedEnteringRoom +( + PEER peer, + RoomType roomType, + const char * room +) +{ + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + assert(room); + assert(room[0]); + assert(strlen(room) < PI_ROOM_MAX_LEN); + if(strlen(room) >= PI_ROOM_MAX_LEN) + return; + + // Check that we're not entering, or in, this room. + /////////////////////////////////////////////////// + assert(!ROOM[0]); + assert(!ENTERING_ROOM); + assert(!IN_ROOM); + + // Start entering. + ////////////////// + strcpy(ROOM, room); + ENTERING_ROOM = PEERTrue; + connection->oldFlags[roomType] = 0; + +#ifdef GSI_UNICODE + UTF8ToUCS2String(ROOM, ROOM_W); +#endif +} + + +void piFinishedEnteringRoom +( + PEER peer, + RoomType roomType, + const char * name +) +{ + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + + if(!name) + name = ""; + + // Check that we're entering. + ///////////////////////////// + assert(ROOM[0]); + assert(ENTERING_ROOM); + assert(!IN_ROOM); + assert(strlen(name) < PI_ROOM_MAX_LEN); + + // We're in. + //////////// + IN_ROOM = PEERTrue; + ENTERING_ROOM = PEERFalse; + strzcpy(NAME, name, PI_NAME_MAX_LEN); + +#ifdef GSI_UNICODE + UTF8ToUCS2String(NAME, NAME_W); +#endif + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + + // Refresh the watch keys for this room. + //////////////////////////////////////// + piKeyCacheRefreshRoom(peer, roomType); +} + +void piLeaveRoom +( + PEER peer, + RoomType roomType, + const char * reason +) +{ + PEER_CONNECTION; + + ASSERT_ROOMTYPE(roomType); + + // Check that we're in/entering this room. + ////////////////////////////////////////// + if(!ENTERING_ROOM && !IN_ROOM) + return; + + assert(ROOM[0]); + + // Are we entering? + /////////////////// + if(ENTERING_ROOM) + { + // Cancel the operation. + //////////////////////// + piCancelJoinOperation(peer, roomType); + } + + // Leave the channel. + ///////////////////// + if(connection->connected) + chatLeaveChannelA(connection->chat, ROOM, reason); + + // Clear all the players out of this room. + ////////////////////////////////////////// + piClearRoomPlayers(peer, roomType); + + // Reset in/entering states. + //////////////////////////// + if(IN_ROOM) + { + assert(!ENTERING_ROOM); + IN_ROOM = PEERFalse; + } + else + { + assert(ENTERING_ROOM); + ENTERING_ROOM = PEERFalse; + } + + // Clear the room/name. + /////////////////////// + ROOM[0] = '\0'; + NAME[0] = '\0'; + +#ifdef GSI_UNICODE + ROOM_W[0] = '\0'; +#endif + + // Clear the flags. + /////////////////// + connection->oldFlags[roomType] = 0; + + // Do roomtype specific stuff. + ////////////////////////////// + if(roomType == StagingRoom) + { + // Stop hosting. + //////////////// + piStopHosting(peer, PEERFalse); + + // Stop reporting as long as we're not playing. + /////////////////////////////////////////////// + if(!connection->playing) + piStopReporting(peer); + + // No host server. + ////////////////// + piSBFreeHostServer(peer); + + // Turn ready off. + ////////////////// + connection->ready = PEERFalse; + + // Clear passworded flag. + ///////////////////////// + connection->passwordedRoom = PEERFalse; + + // Set the flags. + ///////////////// + piSetLocalFlags(peer); + } + else if(roomType == GroupRoom) + { + // Clear the group ID. + ////////////////////// + connection->groupID = 0; + } + + // Cleanse the key cache. + ///////////////////////// + piKeyCacheCleanse(peer); +} + +PEERBool piRoomToType +( + PEER peer, + const char * room, + RoomType * roomType +) +{ + int i; + + PEER_CONNECTION; + + for(i = 0 ; i < NumRooms ; i++) + { + if(strcasecmp(room, ROOMS[i]) == 0) + { + *roomType = (RoomType)i; + return PEERTrue; + } + } + + return PEERFalse; +} + +void piSetLocalFlags +( + PEER peer +) +{ + char buffer[NumRooms][128]; + char * titleRoom; + char * groupRoom; + char * stagingRoom; + const char * key = "b_flags"; + int nFlags; + + PEER_CONNECTION; + + if(!connection->connected) + return; + + if(connection->inRoom[TitleRoom] || connection->enteringRoom[TitleRoom]) + titleRoom = buffer[TitleRoom]; + else + titleRoom = NULL; + if(connection->inRoom[GroupRoom] || connection->enteringRoom[GroupRoom]) + groupRoom = buffer[GroupRoom]; + else + groupRoom = NULL; + if(connection->inRoom[StagingRoom] || connection->enteringRoom[StagingRoom]) + stagingRoom = buffer[StagingRoom]; + else + stagingRoom = NULL; + + // Check for staging room. + ////////////////////////// + if(connection->inRoom[StagingRoom]) + { + if(titleRoom) + *titleRoom++ = 's'; + if(groupRoom) + *groupRoom++ = 's'; + *stagingRoom++ = 's'; + + // Check for ready. + /////////////////// + if(connection->ready) + *stagingRoom++ = 'r'; + + // Check for hosting. + ///////////////////// + if(connection->hosting) + *stagingRoom++ = 'h'; + } + + // Check for playing. + ///////////////////// + if(connection->playing) + { + if(titleRoom) + *titleRoom++ = 'g'; + if(groupRoom) + *groupRoom++ = 'g'; + if(stagingRoom) + *stagingRoom++ = 'g'; + } + + // Check for away. + ////////////////// + if(connection->away) + { + if(titleRoom) + *titleRoom++ = 'a'; + if(groupRoom) + *groupRoom++ = 'a'; + if(stagingRoom) + *stagingRoom++ = 'a'; + } + + // Cap it off. + ////////////// + if(titleRoom) + { + *titleRoom = '\0'; + titleRoom = buffer[TitleRoom]; + } + if(groupRoom) + { + *groupRoom = '\0'; + groupRoom = buffer[GroupRoom]; + } + if(stagingRoom) + { + *stagingRoom = '\0'; + stagingRoom = buffer[StagingRoom]; + } + + // Set the keys. + //////////////// + if(titleRoom) + { + nFlags = piParseFlags(titleRoom); + if(nFlags != connection->oldFlags[TitleRoom]) + { + chatSetChannelKeysA(connection->chat, connection->rooms[TitleRoom], connection->nick, 1, &key, (const char **)&titleRoom); + connection->oldFlags[TitleRoom] = nFlags; + } + } + if(groupRoom) + { + nFlags = piParseFlags(groupRoom); + if(nFlags != connection->oldFlags[GroupRoom]) + { + chatSetChannelKeysA(connection->chat, connection->rooms[GroupRoom], connection->nick, 1, &key, (const char **)&groupRoom); + connection->oldFlags[GroupRoom] = nFlags; + } + } + if(stagingRoom) + { + nFlags = piParseFlags(stagingRoom); + if(nFlags != connection->oldFlags[StagingRoom]) + { + chatSetChannelKeysA(connection->chat, connection->rooms[StagingRoom], connection->nick, 1, &key, (const char **)&stagingRoom); + connection->oldFlags[StagingRoom] = nFlags; + } + } +} diff --git a/xrGameSpy/gamespy/Peer/peerRooms.h b/xrGameSpy/gamespy/Peer/peerRooms.h new file mode 100644 index 00000000000..cc6388b4292 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerRooms.h @@ -0,0 +1,40 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERROOMS_H_ +#define _PEERROOMS_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/************** +** FUNCTIONS ** +**************/ +PEERBool piRoomsInit(PEER peer); +void piRoomsCleanup(PEER peer); +void piStartedEnteringRoom(PEER peer, RoomType roomType, const char * room); +void piFinishedEnteringRoom(PEER peer, RoomType roomType, const char * name); +void piLeaveRoom(PEER peer, RoomType roomType, const char * reason); +PEERBool piRoomToType(PEER peer, const char * room, RoomType * roomType); +void piSetLocalFlags(PEER peer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerSB.c b/xrGameSpy/gamespy/Peer/peerSB.c new file mode 100644 index 00000000000..cb5a1b75d8f --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerSB.c @@ -0,0 +1,1112 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include +#include +#include "peerMain.h" +#include "peerOperations.h" +#include "peerSB.h" +#include "peerCallbacks.h" +#include "peerMangle.h" +#include "peerRooms.h" +#include "peerAutoMatch.h" +#include "peerQR.h" + +/************ +** GLOBALS ** +************/ +int piSBQueryVersion = QVERSION_QR2; + +/********** +** GAMES ** +**********/ +static void piSBGamesListCallback +( + SBServerListPtr serverlist, + SBListCallbackReason reason, + SBServer server, + void * instance +) +{ + PEER peer = (PEER)instance; + PEER_CONNECTION; + +#if 0 + { + static const char reasonStrings[][32] = + { + "serveradded", + "serverupdated", + "serverdeleted", + "initiallistcomplete", + "disconnected", + "queryerror", + "publicipdetermined" + }; + char buffer[256]; + sprintf(buffer, "GAMES | LIST | %s", reasonStrings[reason]); + if(server) + sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server)); + strcat(buffer, "\n"); + OutputDebugString(buffer); + } +#endif + + // handle based on the callback reason + switch(reason) + { + case slc_serveradded: + // if it's added call the callback and get it updated + piAddListingGamesCallback(peer, PEERTrue, server, PEER_ADD); + if(!SBServerHasBasicKeys(server)) + { + SBBool usequerychallenge = SBFalse; + if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE) + usequerychallenge = SBTrue; + SBQueryEngineUpdateServer(&connection->gameEngine, server, 0, QTYPE_BASIC, usequerychallenge); + } + break; + + case slc_serverupdated: + // if it's updated let the app know + piAddListingGamesCallback(peer, PEERTrue, server, PEER_UPDATE); + break; + + case slc_serverdeleted: + // if it's deleted, call the callback + if ((server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY)) != 0) + SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server); + piAddListingGamesCallback(peer, PEERTrue, server, PEER_REMOVE); + break; + + case slc_initiallistcomplete: + // done with the initial list + connection->initialGameList = PEERFalse; + + // let the app know + piAddListingGamesCallback(peer, PEERTrue, NULL, PEER_COMPLETE); + + break; + + case slc_queryerror: + // call the failed callback + piAddListingGamesCallback(peer, PEERFalse, NULL, 0); + break; + + case slc_publicipdetermined: + // let the engine know the IP + connection->publicIP = serverlist->mypublicip; + SBQueryEngineSetPublicIP(&connection->gameEngine, serverlist->mypublicip); + break; + + default: + break; + } +} + +static void piSBGamesEngineCallback +( + SBQueryEnginePtr engine, + SBQueryEngineCallbackReason reason, + SBServer server, + void * instance +) +{ + PEER peer = (PEER)instance; + //PEER_CONNECTION; + +#if 0 + { + static const char reasonStrings[][32] = + { + "updatesuccess", + "updatefailed", + "engineidle" + }; + char buffer[256]; + sprintf(buffer, "GAMES | ENGINE | %s", reasonStrings[reason]); + if(server) + sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server)); + strcat(buffer, "\n"); + OutputDebugString(buffer); + } +#endif + + // if this is an updated server, call the callback + if(reason == qe_updatesuccess) + piAddListingGamesCallback(peer, PEERTrue, server, PEER_UPDATE); + + GSI_UNUSED(engine); +} + +PEERBool piSBStartListingGames +( + PEER peer, + const unsigned char * fields, + int numFields, + const char * filter +) +{ + char groupFilter[32]; + char smartSpyFilter[MAX_FILTER_LEN]; + char fullFields[MAX_FIELD_LIST_LEN]; + int listLen; + int keyLen; + int i; + + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + if(!connection->sbInitialized) + return PEERFalse; + + // Stop it if it's going. + ///////////////////////// + piSBStopListingGames(peer); + + // Clear the list. + ////////////////// + SBServerListClear(&connection->gameList); + + // Filter by group if in one. + ///////////////////////////// + if(connection->groupID) + sprintf(groupFilter, "groupid=%d", connection->groupID); + else + strcpy(groupFilter, "groupid is null"); + + // Setup the actual filter. + /////////////////////////// + if(filter) + { + sprintf(smartSpyFilter, "(%s) AND (", groupFilter); + strzcat(smartSpyFilter, filter, sizeof(smartSpyFilter) - 1); + strcat(smartSpyFilter, ")"); + } + else + { + strcpy(smartSpyFilter, groupFilter); + } + + // Clear this in case it was set. + ///////////////////////////////// + connection->gameEngine.numserverkeys = 0; + + // We always set these keys. + //////////////////////////// + strcpy(fullFields, "\\hostname\\gamemode"); + listLen = (int)strlen(fullFields); + SBQueryEngineAddQueryKey(&connection->gameEngine, HOSTNAME_KEY); + SBQueryEngineAddQueryKey(&connection->gameEngine, GAMEMODE_KEY); + + // Build the key list. + ////////////////////// + for(i = 0 ; i < numFields ; i++) + { + // Check that we have the space to add the key. + /////////////////////////////////////////////// + keyLen = (int)strlen(qr2_registered_key_list[fields[i]]); + if((listLen + keyLen + 1) >= MAX_FIELD_LIST_LEN) + break; + + // Add the key. + /////////////// + listLen += sprintf(fullFields + listLen, "\\%s", qr2_registered_key_list[fields[i]]); + + // Add to the engine query list. + //////////////////////////////// + SBQueryEngineAddQueryKey(&connection->gameEngine, fields[i]); + } + + // Start updating the list. + /////////////////////////// + if(SBServerListConnectAndQuery(&connection->gameList, fullFields, smartSpyFilter, PUSH_UPDATES, 0) != sbe_noerror) + { + piSBStopListingGames(peer); + return PEERFalse; + } + + // Doing the initial listing. + ///////////////////////////// + connection->initialGameList = PEERTrue; + + // Clear the list before they start getting servers. + //////////////////////////////////////////////////// + piAddListingGamesCallback(peer, PEERTrue, NULL, PEER_CLEAR); + + return PEERTrue; +} + +void piSBStopListingGames +( + PEER peer +) +{ + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + if(!connection->sbInitialized) + return; + + // Stop the listing. + //////////////////// + SBServerListDisconnect(&connection->gameList); + + // Stop the engine. + /////////////////// + SBEngineHaltUpdates(&connection->gameEngine); + + // Remove all pending game list callbacks. + ////////////////////////////////////////// + piClearCallbacks(peer, PI_LISTING_GAMES_CALLBACK); +} + +/*********** +** GROUPS ** +***********/ +static void piSBGroupsListCallback +( + SBServerListPtr serverlist, + SBListCallbackReason reason, + SBServer server, + void * instance +) +{ + piOperation * operation; + PEER peer = (PEER)instance; + PEER_CONNECTION; + + operation = connection->listingGroupsOperation; + +#if 0 + { + static const char reasonStrings[][32] = + { + "serveradded", + "serverupdated", + "serverdeleted", + "initiallistcomplete", + "disconnected", + "queryerror", + "publicipdetermined" + }; + char buffer[256]; + sprintf(buffer, "GROUPS | LIST | %s", reasonStrings[reason]); + if(server) + sprintf(buffer + strlen(buffer), " | %d", ntohl(SBServerGetPublicInetAddress(server))); + strcat(buffer, "\n"); + OutputDebugString(buffer); + } +#endif + + // handle based on the callback reason + switch(reason) + { + // if it's added call the callback + case slc_serveradded: + { + int groupID = (int)ntohl(SBServerGetPublicInetAddress(server)); +//#ifndef GSI_PEER_UNICODE + const char * name = SBServerGetStringValueA(server, "hostname", "(No Name)"); + int numWaiting = SBServerGetIntValueA(server, "numwaiting", 0); + int maxWaiting = SBServerGetIntValueA(server, "maxwaiting", 0); + int numGames = SBServerGetIntValueA(server, "numservers", 0); + int numPlaying = SBServerGetIntValueA(server, "numplayers", 0); +//#else +// const unsigned short * name = SBServerGetStringValue(server, L"hostname", L"(No Name)"); +// int numWaiting = SBServerGetIntValue(server, L"numwaiting", 0); +// int maxWaiting = SBServerGetIntValue(server, L"maxwaiting", 0); +// int numGames = SBServerGetIntValue(server, L"numservers", 0); +// int numPlaying = SBServerGetIntValue(server, L"numplayers", 0); +//#endif + piAddListGroupRoomsCallback(peer, PEERTrue, groupID, server, name, numWaiting, maxWaiting, numGames, numPlaying, (peerListGroupRoomsCallback)operation->callback, operation->callbackParam, operation->ID); + break; + } + + // initial list completion + case slc_initiallistcomplete: + // calling the terminating callback + piAddListGroupRoomsCallback(peer, PEERTrue, 0, NULL, NULL, 0, 0, 0, 0, (peerListGroupRoomsCallback)operation->callback, operation->callbackParam, operation->ID); + piRemoveOperation(peer, operation); + connection->listingGroupsOperation = NULL; + break; + + // check for a query error + case slc_queryerror: + // call the failed callback + piAddListGroupRoomsCallback(peer, PEERFalse, 0, NULL, NULL, 0, 0, 0, 0, (peerListGroupRoomsCallback)operation->callback, operation->callbackParam, operation->ID); + piRemoveOperation(peer, operation); + connection->listingGroupsOperation = NULL; + break; + + default: + break; + } + + GSI_UNUSED(serverlist); +} + +PEERBool piSBStartListingGroups +( + PEER peer, + const char * fields +) +{ + char fullFields[MAX_FIELD_LIST_LEN + 1]; + int len; + + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + if(!connection->sbInitialized) + return PEERFalse; + + // Stop it if it's going. + ///////////////////////// + piSBStopListingGroups(peer); + + // Clear the list. + ////////////////// + SBServerListClear(&connection->groupList); + + // Setup the fields list. + ///////////////////////// + strcpy(fullFields, "\\hostname\\numwaiting\\maxwaiting\\numservers\\numplayers"); + len = (int)strlen(fullFields); + strzcpy(fullFields + len, fields, (unsigned int)MAX_FIELD_LIST_LEN - len); + + // Start updating the list. + /////////////////////////// + if(SBServerListConnectAndQuery(&connection->groupList, fullFields, "", SEND_GROUPS, 0) != sbe_noerror) + { + piSBStopListingGroups(peer); + return PEERFalse; + } + + return PEERTrue; +} + +void piSBStopListingGroups +( + PEER peer +) +{ + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + if(!connection->sbInitialized) + return; + + // Stop the listing. + //////////////////// + SBServerListDisconnect(&connection->groupList); +} + +/************** +** AUTOMATCH ** +**************/ +static PEERBool piIsLocalServer(PEER peer, SBServer server) +{ + PEER_CONNECTION; + + // check the public ip + if(SBServerGetPublicInetAddress(server) != connection->publicIP) + return PEERFalse; + + // check the private ip and port + if(SBServerHasPrivateAddress(server)) + { + if(SBServerGetPrivateInetAddress(server) != connection->privateIP) + return PEERFalse; + + if(SBServerGetPrivateQueryPort(server) != connection->autoMatchOperation->port) + return PEERFalse; + } + // check the public port + else + { + if(SBServerGetPublicQueryPort(server) != connection->autoMatchOperation->port) + return PEERFalse; + } + + return PEERTrue; +} + +static int piSBAutoMatchGetServerRating(PEER peer, SBServer server) +{ + PEER_CONNECTION; + + // ignore the local machine + if(connection->autoMatchReporting && piIsLocalServer(peer, server)) + return 0; + + // check if it got the keys. + if(!SBServerHasFullKeys(server)) + return 0; + + // ignore full servers +#ifndef GSI_UNICODE + if(SBServerGetIntValue(server, "numplayers", 0) >= SBServerGetIntValue(server, "maxplayers", 0)) + return 0; +#else + if(SBServerGetIntValue(server, L"numplayers", 0) >= SBServerGetIntValue(server, L"maxplayers", 0)) + return 0; +#endif + + // return the rating for this server + return piCallAutoMatchRateCallback(peer, server); +} + +static void piSBAutoMatchCheckUpdatedServer(PEER peer, SBServer server) +{ + int rating; + + PEER_CONNECTION; + + // only do this if we're waiting + if(connection->autoMatchStatus != PEERWaiting) + return; + + // if we're already joining a staging room, ignore this + if(connection->enteringRoom[StagingRoom]) + return; + + // get the rating for this server + rating = piSBAutoMatchGetServerRating(peer, server); + + // if it's not acceptable, ignore + if(rating <= 0) + return; + + // stop reporting and leave the room + piStopAutoMatchReporting(peer); + piLeaveRoom(peer, StagingRoom, ""); + + // join the match + if(!piJoinAutoMatchRoom(peer, server)) + { + // it's bad news if it failed to start the op + piSetAutoMatchStatus(peer, PEERFailed); + } +} + +static void piSBAutoMatchCheckPushedServer(PEER peer, SBServer server) +{ + SortInfo info; + int aRating; + PEER_CONNECTION; + + // We must be in the waiting or searching phase to rate a server this way + if(connection->autoMatchStatus != PEERWaiting && connection->autoMatchStatus != PEERSearching) + return; + + // if we're already joining a staging room, ignore this + if(connection->enteringRoom[StagingRoom]) + return; + + // Check if this is the only server in our list + if (SBServerListCount(&connection->autoMatchList) == 1) + { + // get the rating for this server + aRating = piSBAutoMatchGetServerRating(peer, server); + + // if it's not acceptable, ignore + if(aRating <= 0) + return; + + // stop reporting and leave the room + piStopAutoMatchReporting(peer); + piLeaveRoom(peer, StagingRoom, ""); + + // join the match + if(!piJoinAutoMatchRoom(peer, server)) + { + // it's bad news if it failed to start the op + piSetAutoMatchStatus(peer, PEERFailed); + } + } + + // otherwise we'll need to run through all the servers + // rate each of them and join the one with the highest rating. + else if (SBServerListCount(&connection->autoMatchList) > 1) + { + int count, i; + SBServer aServer; + + // loop through all the servers. + count = SBServerListCount(&connection->autoMatchList); + for(i = (count - 1) ; i >= 0 ; i--) + { + // get the server. + aServer = SBServerListNth(&connection->autoMatchList, i); + + // get the rating for this server + aRating = piSBAutoMatchGetServerRating(peer, aServer); + if(aRating <= 0) + { + SBServerListRemoveAt(&connection->autoMatchList, i); + continue; + } + + // store this server's rating + SBServerAddIntKeyValue(aServer, PI_AUTOMATCH_RATING_KEY, aRating); + } + + // recount + count = SBServerListCount(&connection->autoMatchList); + + // no matches? + if(!count) + { + piSetAutoMatchStatus(peer, PEERWaiting); + return; + } + + // sort by rating +#ifdef GSI_UNICODE + _tcscpy(info.sortkey, (const unsigned short *)PI_AUTOMATCH_RATING_KEY); +#else + _tcscpy(info.sortkey, PI_AUTOMATCH_RATING_KEY); +#endif + info.comparemode = sbcm_int; + SBServerListSort(&connection->autoMatchList, SBTrue, info); + + piStopAutoMatchReporting(peer); + piLeaveRoom(peer, StagingRoom, ""); + + // join the top rated match + if(!piJoinAutoMatchRoom(peer, SBServerListNth(&connection->autoMatchList, 0))) + { + // it's bad news if it failed to start the op + piSetAutoMatchStatus(peer, PEERFailed); + } + } + +} + +static void piSBAutoMatchListCallback +( + SBServerListPtr serverlist, + SBListCallbackReason reason, + SBServer server, + void * instance +) +{ + PEER peer = (PEER)instance; + PEER_CONNECTION; + +#if 0 + { + static const char reasonStrings[][32] = + { + "serveradded", + "serverupdated", + "serverdeleted", + "initiallistcomplete", + "disconnected", + "queryerror", + "publicipdetermined" + }; + char buffer[256]; + sprintf(buffer, "AUTOMATCH | LIST | %s", reasonStrings[reason]); + if(server) + sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server)); + strcat(buffer, "\n"); + OutputDebugString(buffer); + } +#endif + + // handle based on the callback reason + switch(reason) + { + case slc_serveradded: + // If we have the server info, or we already requested it + // just bail + if(server->state & (STATE_FULLKEYS|STATE_PENDINGFULLQUERY)) + break; + + // If it's behind a firewall, get the keys from the master + if (!SBServerDirectConnect(server)) + SBGetServerRulesFromMaster(&connection->autoMatchList, SBServerGetPublicInetAddress(server), SBServerGetPublicQueryPortNBO(server)); + else // send normal update + { + SBBool usequerychallenge = SBFalse; + if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE) + usequerychallenge = SBTrue; + SBQueryEngineUpdateServer(&connection->autoMatchEngine, server, 0, QTYPE_FULL, usequerychallenge); + } + break; + + case slc_serverupdated: + // If we don't have the full keys, request them + if(!SBServerHasFullKeys(server) && SBServerDirectConnect(server) && !(server->state & STATE_PENDINGFULLQUERY)) + { + // Send a normal query, if the server is firewalled we wouldn't be here + // assert(SBServerDirectConnect(server)) + SBBool usequerychallenge = SBFalse; + if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE) + usequerychallenge = SBTrue; + SBQueryEngineUpdateServer(&connection->autoMatchEngine, server, 0, QTYPE_FULL, usequerychallenge); + } + else if(!SBServerHasFullKeys(server) && !SBServerDirectConnect(server)) + { + SBGetServerRulesFromMaster(&connection->autoMatchList, SBServerGetPublicInetAddress(server), SBServerGetPublicQueryPortNBO(server)); + } + else + piSBAutoMatchCheckPushedServer(peer, server); + break; + + case slc_serverdeleted: + // make sure it's not in the update queue + if ((server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY)) != 0) + SBQueryEngineRemoveServerFromFIFOs(&connection->autoMatchEngine, server); + break; + + case slc_initiallistcomplete: + // if no servers were found, start Waiting + // or if servers were found but all were behind a firewall, start Waiting + if(!SBServerListCount(&connection->autoMatchList) || + (0==connection->autoMatchEngine.querylist.count)) + { + piSetAutoMatchStatus(peer, PEERWaiting); + } + break; + case slc_queryerror: + // browsing failed + connection->autoMatchSBFailed = PEERTrue; + if(connection->autoMatchStatus == PEERSearching) + piSetAutoMatchStatus(peer, connection->autoMatchQRFailed?PEERFailed:PEERWaiting); + break; + + case slc_publicipdetermined: + // let the engine know the IP + connection->publicIP = serverlist->mypublicip; + SBQueryEngineSetPublicIP(&connection->gameEngine, serverlist->mypublicip); + break; + + default: + break; + } +} + +static void piSBAutoMatchEngineCallback +( + SBQueryEnginePtr engine, + SBQueryEngineCallbackReason reason, + SBServer server, + void * instance +) +{ + PEER peer = (PEER)instance; + int i; + int count; + int rating; + SortInfo info; + + PEER_CONNECTION; + +#if 0 + { + static const char reasonStrings[][32] = + { + "updatesuccess", + "updatefailed", + "engineidle" + }; + char buffer[256]; + sprintf(buffer, "AUTOMATCH | ENGINE | %s", reasonStrings[reason]); + if(server) + sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server)); + strcat(buffer, "\n"); + OutputDebugString(buffer); + } +#endif + + // handle based on the callback reason + switch(reason) + { + case qe_updatesuccess: + // check the server + piSBAutoMatchCheckUpdatedServer(peer, server); + break; + + case qe_updatefailed: + if(!SBServerListCount(&connection->autoMatchList)) + piSetAutoMatchStatus(peer, PEERWaiting); + break; + + // check if the querying is complete. + case qe_engineidle: + // make sure we're searching + if(connection->autoMatchStatus != PEERSearching) + return; + + // if we're already in or joining a staging room, ignore this + if(connection->inRoom[StagingRoom] || connection->enteringRoom[StagingRoom]) + return; + + // loop through all the servers. + count = SBServerListCount(&connection->autoMatchList); + for(i = (count - 1) ; i >= 0 ; i--) + { + // get the server. + server = SBServerListNth(&connection->autoMatchList, i); + + // get the rating for this server + rating = piSBAutoMatchGetServerRating(peer, server); + if(rating <= 0) + { + SBServerListRemoveAt(&connection->autoMatchList, i); + continue; + } + + // store this server's rating + SBServerAddIntKeyValue(server, PI_AUTOMATCH_RATING_KEY, rating); + } + + // recount + count = SBServerListCount(&connection->autoMatchList); + + // no matches? + if(!count) + { + piSetAutoMatchStatus(peer, PEERWaiting); + return; + } + + // sort by rating +#ifdef GSI_UNICODE + _tcscpy(info.sortkey, (const unsigned short *)PI_AUTOMATCH_RATING_KEY); +#else + _tcscpy(info.sortkey, PI_AUTOMATCH_RATING_KEY); +#endif + + info.comparemode = sbcm_int; + SBServerListSort(&connection->autoMatchList, SBTrue, info); + + // join the top rated match + if(!piJoinAutoMatchRoom(peer, SBServerListNth(&connection->autoMatchList, 0))) + { + // it's bad news if it failed to start the op + piSetAutoMatchStatus(peer, PEERFailed); + } + + break; + + default: + break; + } + + GSI_UNUSED(engine); +} + +PEERBool piSBStartListingAutoMatches +( + PEER peer +) +{ + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + if(!connection->sbInitialized) + { + connection->autoMatchSBFailed = PEERTrue; + return PEERFalse; + } + + // stop it if it's going. + piSBStopListingAutoMatches(peer); + + // clear the list. + SBServerListClear(&connection->autoMatchList); + + // start updating the list. + if(SBServerListConnectAndQuery(&connection->autoMatchList, NULL, connection->autoMatchFilter, PUSH_UPDATES, 0) != sbe_noerror) + { + piSBStopListingAutoMatches(peer); + connection->autoMatchSBFailed = PEERTrue; + return PEERFalse; + } + + // clear the error flag + connection->autoMatchSBFailed = PEERFalse; + + // we're browsing + connection->autoMatchBrowsing = PEERTrue; + + return PEERTrue; +} + +void piSBStopListingAutoMatches +( + PEER peer +) +{ + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + if(!connection->sbInitialized) + return; + + // we're done browsing + connection->autoMatchBrowsing = PEERFalse; + + // stop the listing. + SBServerListDisconnect(&connection->autoMatchList); + + // stop the engine. + SBEngineHaltUpdates(&connection->autoMatchEngine); +} + +/************** +** FUNCTIONS ** +**************/ +PEERBool piSBInit +( + PEER peer +) +{ + char autoMatchTitle[PI_TITLE_MAX_LEN]; + + PEER_CONNECTION; + + // init the game list and engine + memset(&connection->gameList, 0, sizeof(connection->gameList)); + SBServerListInit(&connection->gameList, connection->title, connection->sbName, connection->sbSecretKey, connection->sbGameVersion, SBFalse, piSBGamesListCallback, peer); + SBQueryEngineInit(&connection->gameEngine, connection->sbMaxUpdates, piSBQueryVersion, SBFalse, piSBGamesEngineCallback, peer); + + // init the group list + memset(&connection->groupList, 0, sizeof(connection->groupList)); + SBServerListInit(&connection->groupList, connection->title, connection->sbName, connection->sbSecretKey, connection->sbGameVersion, SBFalse, piSBGroupsListCallback, peer); + + // init the AutoMatch list and engine + strzcpy(autoMatchTitle, connection->title, sizeof(autoMatchTitle)); + strzcat(autoMatchTitle, "am", sizeof(autoMatchTitle)); + memset(&connection->autoMatchList, 0, sizeof(connection->autoMatchList)); + SBServerListInit(&connection->autoMatchList, autoMatchTitle, connection->sbName, connection->sbSecretKey, connection->sbGameVersion, SBFalse, piSBAutoMatchListCallback, peer); + SBQueryEngineInit(&connection->autoMatchEngine, connection->sbMaxUpdates, piSBQueryVersion, SBFalse, piSBAutoMatchEngineCallback, peer); + + // no host server yet + connection->hostServer = NULL; + + // initialized + connection->sbInitialized = PEERTrue; + + return PEERTrue; +} + +void piSBCleanup +( + PEER peer +) +{ + PEER_CONNECTION; + + // stop listing + piSBStopListingGames(peer); + piSBStopListingGroups(peer); + + // cleanup the SB + if(connection->sbInitialized) + { + SBServerListCleanup(&connection->gameList); + SBEngineCleanup(&connection->gameEngine); + SBServerListCleanup(&connection->groupList); + SBServerListCleanup(&connection->autoMatchList); + SBEngineCleanup(&connection->autoMatchEngine); + } + + // AutoMatch cleanup + connection->autoMatchBrowsing = PEERFalse; +} + + +void piSBUpdateGame +( + PEER peer, + SBServer server, + PEERBool fullUpdate, + PEERBool forceUpdateByMaster, + PEERBool icmpEcho +) +{ + PEER_CONNECTION; + + // check that we're initialized. + assert(connection->sbInitialized); + + if(!connection->sbInitialized) + return; + + // Changed 08-26-2004 + // Saad Nader + // Added force update by master server parameter + // for internal update function + ///////////////////// + if (forceUpdateByMaster) + { + // remove from the existing update lists if present + if(server->flags & UNSOLICITED_UDP_FLAG) + SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server); + + // Obtain the information via the master server + SBGetServerRulesFromMaster(&connection->gameList, server->publicip, server->publicport); + return; + } + + if (icmpEcho && (server->flags & ICMP_IP_FLAG)) + { + SBBool usequerychallenge = SBFalse; + if (connection->gameList.backendgameflags & QR2_USE_QUERY_CHALLENGE) + usequerychallenge = SBTrue; + + if (server->flags & UNSOLICITED_UDP_FLAG) + SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server); + + SBQueryEngineUpdateServer(&connection->gameEngine, server, 1, QTYPE_ICMP, usequerychallenge); + return; + } + // if the server supports unsolicited UDP, query it directly + if(server->flags & UNSOLICITED_UDP_FLAG) + { + SBBool usequerychallenge = SBFalse; + if (connection->gameList.backendgameflags & QR2_USE_QUERY_CHALLENGE) + usequerychallenge = SBTrue; + + // remove from the existing update lists if present + SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server); + + // query the server + SBQueryEngineUpdateServer(&connection->gameEngine, server, 1, fullUpdate?QTYPE_FULL:QTYPE_BASIC, usequerychallenge); + } + else + { + // get the values from the master server + SBGetServerRulesFromMaster(&connection->gameList, server->publicip, server->publicport); + } +} + +void piSBThink +( + PEER peer +) +{ + PEER_CONNECTION; + + // check that we're initialized. + if(!connection->sbInitialized) + return; + + SBListThink(&connection->gameList); + SBListThink(&connection->groupList); + SBQueryEngineThink(&connection->gameEngine); + SBListThink(&connection->autoMatchList); + SBQueryEngineThink(&connection->autoMatchEngine); +} + +void piSendNatNegotiateCookie +( + PEER peer, + unsigned int ip, + unsigned short port, + int cookie +) +{ + PEER_CONNECTION; + + // check that we're initialized. + if(!connection->sbInitialized) + return; + + // send the cookie + if (peerIsAutoMatching(peer)) + { + SBSendNatNegotiateCookieToServer(&connection->autoMatchList, ip, htons(port), cookie); + } + else + SBSendNatNegotiateCookieToServer(&connection->gameList, ip, htons(port), cookie); +} + +void piSendMessageToServer +( + PEER peer, + unsigned int ip, + unsigned short port, + const char * data, + int len +) +{ + PEER_CONNECTION; + + // check that we're initialized. + if(!connection->sbInitialized) + return; + + // send the message + if(peerIsAutoMatching(peer)) + { + SBSendMessageToServer(&connection->autoMatchList, ip, port, data, len); + } + else + { + SBSendMessageToServer(&connection->gameList, ip, port, data, len); + } +} + +static void piSBCloneServerTableMap(void * elem, void * clientData) +{ + SBKeyValuePair * kvPair = (SBKeyValuePair *)elem; + SBServer clone = (SBServer)clientData; + + SBServerAddKeyValue(clone, kvPair->key, kvPair->value); +} + +SBServer piSBCloneServer(SBServer server) +{ + SBServer clone; + HashTable table; + + // allocate the clone + clone = SBAllocServer(NULL, server->publicip, server->publicport); + + // save off the table + table = clone->keyvals; + + // copy the source server + memcpy(clone, server, sizeof(struct _SBServer)); + clone->keyvals = table; + clone->next = NULL; + + // copy all the values from the original table + TableMap(server->keyvals, piSBCloneServerTableMap, clone); + + return clone; +} + +void piSBFreeHostServer(PEER peer) +{ + PEER_CONNECTION; + + if(!connection->hostServer) + return; + + SBServerFree(&connection->hostServer); + connection->hostServer = NULL; +} diff --git a/xrGameSpy/gamespy/Peer/peerSB.h b/xrGameSpy/gamespy/Peer/peerSB.h new file mode 100644 index 00000000000..ed97057c0d5 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerSB.h @@ -0,0 +1,46 @@ +/* +GameSpy Peer SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PEERSB_H_ +#define _PEERSB_H_ + +/************* +** INCLUDES ** +*************/ +#include "peerMain.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/************** +** FUNCTIONS ** +**************/ +PEERBool piSBInit(PEER peer); +void piSBCleanup(PEER peer); +PEERBool piSBStartListingGames(PEER peer, const unsigned char * fields, int numFields, const char * filter); +void piSBStopListingGames(PEER peer); +void piSBUpdateGame(PEER peer, SBServer server, PEERBool fullUpdate, PEERBool forceUpdateByMaster, PEERBool icmpEcho); +PEERBool piSBStartListingGroups(PEER peer, const char * fields); +void piSBStopListingGroups(PEER peer); +void piSBThink(PEER peer); +void piSendNatNegotiateCookie(PEER peer, unsigned int ip, unsigned short port, int cookie); +void piSendMessageToServer(PEER peer, unsigned int ip, unsigned short port, const char * data, int len); +PEERBool piSBStartListingAutoMatches(PEER peer); +void piSBStopListingAutoMatches(PEER peer); +SBServer piSBCloneServer(SBServer server); +void piSBFreeHostServer(PEER peer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Peer/peerc/peerc.c b/xrGameSpy/gamespy/Peer/peerc/peerc.c new file mode 100644 index 00000000000..46ca28a2467 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerc.c @@ -0,0 +1,773 @@ +// GameSpy Peer SDK C Test App +// Dan "Mr. Pants" Schoenblum +// dan@gamespy.com + +/********* +INCLUDES +*********/ +#include "../peer.h" +#include "../../common/gsStringUtil.h" +#include "../../common/gsAvailable.h" + +/******** +DEFINES +********/ +#define TITLE _T("gmtest") + +// ensure cross-platform compatibility for printf +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define LOOP_SECONDS 60 + +#define NICK_SIZE 32 // size of nick array, below + +/************* +GLOBAL VARS +*************/ +gsi_char nick[NICK_SIZE]; // our nickname for peerConnect + +// RoomType to string +gsi_char RtoS[3][16] = +{ + _T("TitleRoom"), + _T("GroupRoom"), + _T("StagingRoom") +}; + +PEERBool groupRoomCallbackDone = PEERFalse; + + +static const gsi_char * ResultToString (PEERJoinResult result) +{ + switch(result) + { + case PEERJoinSuccess: + return _T("Success"); + case PEERFullRoom: + return _T("Full"); + case PEERInviteOnlyRoom: + return _T("Invite Only"); + case PEERBannedFromRoom: + return _T("Banned"); + case PEERBadPassword: + return _T("Bad Password"); + case PEERAlreadyInRoom: + return _T("Already in room"); + case PEERNoTitleSet: + return _T("No Title"); + case PEERNoConnection: + return _T("No Connection"); + case PEERAutoMatching: + return _T("Auto Matching"); + case PEERJoinFailed: + return _T("Join Failed"); + } + + //ASSERT(0); + return _T(""); +} + +static void JoinRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param + ) +{ + if(!success) + { + _tprintf(_T("Join failure: %s"), ResultToString(result)); + return; + } + else + { + _tprintf(_T("Joined %s.\n"), RtoS[roomType]); + /*dlg->FillPlayerList(roomType); + if(roomType == StagingRoom) + { + dlg->m_name = peerGetRoomName(peer, StagingRoom); + dlg->UpdateData(FALSE); + }*/ + } + + GSI_UNUSED(param); + GSI_UNUSED(roomType); + GSI_UNUSED(peer); +} + +static void CreateStagingRoomCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param + ) +{ + if (success) + _tprintf(_T("Staging Room Created\n")); + + GSI_UNUSED(param); + GSI_UNUSED(roomType); + GSI_UNUSED(result); + GSI_UNUSED(peer); +} + +static void DisconnectedCallback +( + PEER peer, + const gsi_char * reason, + void * param +) +{ + _tprintf(_T("Disconnected: %s\n"), reason); + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void RoomMessageCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * message, + MessageType messageType, + void * param +) +{ + _tprintf(_T(" (%s) %s: %s\n"), RtoS[roomType], nick, message); + //if(strcasecmp(message, _T("quit")) == 0) + // stop = PEERTrue; + //else if((strlen(message) > 5) && (strncasecmp(message, _T("echo"), 4) == 0)) + // peerMessageRoom(peer, roomType, message + 5, messageType); + + GSI_UNUSED(param); + GSI_UNUSED(peer); + GSI_UNUSED(messageType); +} + +static void RoomUTMCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * command, + const gsi_char * parameters, + PEERBool authenticated, + void * param +) +{ + GSI_UNUSED(peer); + GSI_UNUSED(roomType); + GSI_UNUSED(nick); + GSI_UNUSED(command); + GSI_UNUSED(parameters); + GSI_UNUSED(authenticated); + GSI_UNUSED(param); +} + +static void PlayerMessageCallback +( + PEER peer, + const gsi_char * nick, + const gsi_char * message, + MessageType messageType, + void * param +) +{ + _tprintf(_T("(PRIVATE) %s: %s\n"), nick, message); + + GSI_UNUSED(peer); + GSI_UNUSED(messageType); + GSI_UNUSED(param); +} + +static void ReadyChangedCallback +( + PEER peer, + const gsi_char * nick, + PEERBool ready, + void * param +) +{ + if(ready) + _tprintf(_T("%s is ready\n"), nick); + else + _tprintf(_T("%s is not ready\n"), nick); + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void GameStartedCallback +( + PEER peer, + SBServer server, + const gsi_char * message, + void * param +) +{ + _tprintf(_T("The game is starting at %s\n"), SBServerGetPublicAddress(server)); + if(message && message[0]) + _tprintf(_T(": %s\n"), message); + else + _tprintf(_T("\n")); + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void PlayerJoinedCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + void * param +) +{ + _tprintf(_T("%s joined the %s\n"), nick, RtoS[roomType]); + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void PlayerLeftCallback +( + PEER peer, + RoomType roomType, + const gsi_char * nick, + const gsi_char * reason, + void * param +) +{ + _tprintf(_T("%s left the %s\n"), nick, RtoS[roomType]); + + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(reason); +} + +static void PlayerChangedNickCallback +( + PEER peer, + RoomType roomType, + const gsi_char * oldNick, + const gsi_char * newNick, + void * param +) +{ + _tprintf(_T("%s in %s changed nicks to %s\n"), oldNick, RtoS[roomType], newNick); + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +PEERBool connectSuccess; +static void ConnectCallback +( + PEER peer, + PEERBool success, + int failureReason, + void * param +) +{ + connectSuccess = success; + + GSI_UNUSED(peer); + GSI_UNUSED(success); + GSI_UNUSED(failureReason); + GSI_UNUSED(param); +} + +static void EnumPlayersCallback +( + PEER peer, + PEERBool success, + RoomType roomType, + int index, + const gsi_char * nick, + int flags, + void * param +) +{ + if(!success) + { + _tprintf(_T("Enum %s players failed\n"), RtoS[roomType]); + return; + } + + if(index == -1) + { + _tprintf(_T("--------------------\n")); + return; + } + + _tprintf(_T("%d: %s\n"), index, nick); + /*if(flags & PEER_FLAG_OP) + _tprintf(_T(" (host)\n")); + else + _tprintf(_T("\n"));*/ + + + GSI_UNUSED(peer); + GSI_UNUSED(param); + GSI_UNUSED(flags); +} +/* +int gStartListing; +static void ListingGamesCallback +( + PEER peer, + PEERBool success, + const gsi_char * name, + SBServer server, + PEERBool staging, + int msg, + int progress, + void * param +) +{ + if(success) + { + gsi_char *msgname; + switch (msg) + { + case PEER_CLEAR: + msgname = _T("PEER_CLEAR"); + break; + case PEER_ADD: + msgname = _T("PEER_ADD"); + if (SBServerHasBasicKeys(server)) + _tprintf(_T(" firewall server name: %s numplayers: %d ping: %d firewall: %s\n"), SBServerGetStringValue(server,_T("hostname"),_T("UNKNOWN")), SBServerGetIntValue(server,_T("numplayers"),0), SBServerGetPing(server), SBServerDirectConnect(server)==SBTrue?_T("NO"):_T("YES")); + if (SBServerHasFullKeys(server)) + _tprintf(_T(" server gametype: %s \n"), SBServerGetStringValue(server, _T("gametype"), _T("unknown"))); + break; + case PEER_UPDATE: + msgname = _T("PEER_UPDATE"); + if(server) + { + _tprintf(_T(" update server name: %s numplayers: %d ping: %d firewall: %s\n"), SBServerGetStringValue(server,_T("hostname"),_T("UNKNOWN")), SBServerGetIntValue(server,_T("numplayers"),0), SBServerGetPing(server), SBServerDirectConnect(server)==SBTrue?_T("NO"):_T("YES")); + _tprintf(_T(" server gametype: %s \n"), SBServerGetStringValue(server, _T("gametype"), _T("unknown"))); + } + break; + case PEER_REMOVE: + msgname = _T("PEER_REMOVE"); + break; + case PEER_COMPLETE: + msgname = _T("PEER_COMPLETE"); + gStartListing = 1; + break; + default: + msgname = _T("ERROR!"); + } + //_tprintf("game: %s\n", msgname); + //if(server) + // _tprintf(" server name: %s numplayers: %d ping: %d\n", SBServerGetStringValue(server,_T("hostname"),_T("UNKNOWN")), SBServerGetIntValue(server,_T("numplayers"),0), SBServerGetPing(server)); + } + + GSI_UNUSED(peer); + GSI_UNUSED(name); + GSI_UNUSED(staging); + GSI_UNUSED(progress); + GSI_UNUSED(param); +} +*/ +static void ListGroupRoomsCallback +( + PEER peer, + PEERBool success, + int groupID, + SBServer server, + const gsi_char * name, + int numWaiting, + int maxWaiting, + int numGames, + int numPlaying, + void * param +) +{ + if(success && (groupID > 0)) + { + _tprintf(_T(" %s\n"), name); + _tprintf(_T(" Players in room: %d\n"), numWaiting); + _tprintf(_T(" Max players in room: %d\n"), maxWaiting); + _tprintf(_T(" Games: %d\n"), numGames); + _tprintf(_T(" Players in games: %d\n"), numPlaying); + } + else + groupRoomCallbackDone = PEERTrue; // if groupID is set to 0 it means all group rooms have been listed + + GSI_UNUSED(peer); + GSI_UNUSED(server); + GSI_UNUSED(numWaiting); + GSI_UNUSED(maxWaiting); + GSI_UNUSED(numGames); + GSI_UNUSED(numPlaying); + GSI_UNUSED(param); +} + +PEERBool joinSuccess; +static void JoinCallback +( + PEER peer, + PEERBool success, + PEERJoinResult result, + RoomType roomType, + void * param +) +{ + joinSuccess = success; + + GSI_UNUSED(peer); + GSI_UNUSED(result); + GSI_UNUSED(roomType); + GSI_UNUSED(param); +} + +static void NickErrorCallback +( + PEER peer, + int type, + const gsi_char * badNick, + int numSuggestedNicks, + const gsi_char ** suggestedNicks, + void * param +) +{ + static int errCount; + + if(errCount < 20) + { + _tsnprintf(nick,NICK_SIZE,_T("peerc%u"),(unsigned int)current_time()); + nick[NICK_SIZE - 1] = '\0'; + peerRetryWithNick(peer, nick); + } + else + { + //peerDisconnect(peer); + peerRetryWithNick(peer, NULL); + } + errCount++; + + GSI_UNUSED(type); + GSI_UNUSED(badNick); + GSI_UNUSED(suggestedNicks); + GSI_UNUSED(numSuggestedNicks); + GSI_UNUSED(param); +} +/* +static void AutoMatchStatusCallback(PEER thePeer, PEERAutoMatchStatus theStatus, void* theParam) +{ + _tprintf(_T("Automatch status: %d\r\n"), theStatus); + GSI_UNUSED(thePeer); + GSI_UNUSED(theStatus); + GSI_UNUSED(theParam); +} + +static int AutoMatchRateCallback(PEER thePeer, SBServer theServer, void* theParam) +{ + GSI_UNUSED(thePeer); + GSI_UNUSED(theServer); + GSI_UNUSED(theParam); + return 0; +} +*/ +static void RoomKeyChangedCallback(PEER thePeer, RoomType theType, const gsi_char* theNick, const gsi_char* theKey, const gsi_char* theValue, void* theParam) +{ + GSI_UNUSED(thePeer); + GSI_UNUSED(theType); + GSI_UNUSED(theNick); + GSI_UNUSED(theKey); + GSI_UNUSED(theValue); + GSI_UNUSED(theParam); +} + +static void QRServerKeyCallback +( + PEER peer, + int key, + qr2_buffer_t buffer, + void * param +) +{ +#if VERBOSE + gsi_char verbose[256]; + _stprintf(verbose, _T("QR_SERVER_KEY | %d\n"), key); + OutputDebugString(verbose); +#endif + + switch(key) + { + case HOSTNAME_KEY: + _tprintf(_T(" Server Key callback is being called for HOSTNAME_KEY\n")); + qr2_buffer_add(buffer, _T("My Game")); + break; + case NUMPLAYERS_KEY: + _tprintf(_T(" Server Key callback is being called for NUMPLAYERS_KEY\n")); + qr2_buffer_add_int(buffer, 1); + break; + case GAMEMODE_KEY: + _tprintf(_T(" Server Key callback is being called for GAMEMODE_KEY\n")); + qr2_buffer_add(buffer, _T("openplaying")); + break; + case HOSTPORT_KEY: + _tprintf(_T(" Server Key callback is being called for HOSTPORT_KEY\n")); + qr2_buffer_add_int(buffer, 15151); + break; + case MAPNAME_KEY: + _tprintf(_T(" Server Key callback is being called for MAPNAME_KEY\n")); + qr2_buffer_add(buffer, _T("Big Crate Room")); + break; + case GAMETYPE_KEY: + _tprintf(_T(" Server Key callback is being called for GAMETYPE_KEY\n")); + qr2_buffer_add(buffer, _T("Friendly")); + break; + case TIMELIMIT_KEY: + _tprintf(_T(" Server Key callback is being called for TIMELIMIT_KEY\n")); + qr2_buffer_add_int(buffer, 100); + break; + case FRAGLIMIT_KEY: + _tprintf(_T(" Server Key callback is being called for FRAGLIMIT_KEY\n")); + qr2_buffer_add_int(buffer, 0); + break; + case TEAMPLAY_KEY: + _tprintf(_T(" Server Key callback is being called for TEAMPLAY_KEY\n")); + qr2_buffer_add_int(buffer, 0); + break; + default: + qr2_buffer_add(buffer, _T("")); + break; + } + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void QRKeyListCallback +( + PEER peer, + qr2_key_type type, + qr2_keybuffer_t keyBuffer, + void * param +) +{ + // register the keys we use + switch(type) + { + case key_server: + _tprintf(_T(" Key List Callback is being called for server keys\n")); + if(!peerIsAutoMatching(peer)) + { + qr2_keybuffer_add(keyBuffer, HOSTPORT_KEY); + qr2_keybuffer_add(keyBuffer, MAPNAME_KEY); + qr2_keybuffer_add(keyBuffer, GAMETYPE_KEY); + qr2_keybuffer_add(keyBuffer, TIMELIMIT_KEY); + qr2_keybuffer_add(keyBuffer, FRAGLIMIT_KEY); + qr2_keybuffer_add(keyBuffer, TEAMPLAY_KEY); + } + break; + case key_player: + _tprintf(_T(" Key List Callback is being called for player keys\n")); + // no custom player keys + break; + case key_team: + _tprintf(_T(" Key List Callback is being called for team keys\n")); + // no custom team keys + break; + default: break; + } + + GSI_UNUSED(param); +} + + + + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped + int test_main(int argc, char **argv); +#endif + +int test_main(int argc, char **argv) +{ + PEER peer; // peer object (initialized with peerInitialize + + /* peerInitialize */ + PEERCallbacks callbacks; // we will need to add all of the supported callbacks + + /* peerSetTitle parameters */ + gsi_char secret_key[9]; // your title's assigned secret key + int maxUpdates = 10; // max server queries the SDK will send out at a time + PEERBool natNeg = PEERFalse; // nat negotiation will not be supported + PEERBool pingRooms[NumRooms]; + PEERBool crossPingRooms[NumRooms]; + + /* peerConnect parameters */ + int profileID = 0; // we will not be using gp accounts, so this will be ignored + void * userData = NULL; // optional data passed to peerConnectCallback + PEERBool blocking = PEERTrue; // true means function runs synchronously + PEERBool non_blocking = PEERFalse; // false means function runs asynchronously + + int newbiesGroupID = 2; + + gsi_char * serverName = _T("UberNoobServer"); + int maxPlayers = 2; + gsi_char * noPassword = _T(""); + + GSIACResult result; // used for backend availability check + gsi_time startTime; + + // set our nickname to a random string so that we'll have different nicks when running multiple instances of peerc + _tsnprintf(nick,NICK_SIZE,_T("peerc%u"),(unsigned int)current_time()); + nick[NICK_SIZE - 1] = '\0'; + + // set the secret key, in a semi-obfuscated manner + secret_key[0] = 'H'; + secret_key[1] = 'A'; + secret_key[2] = '6'; + secret_key[3] = 'z'; + secret_key[4] = 'k'; + secret_key[5] = 'S'; + secret_key[6] = '\0'; + + // check that the game's backend is available + GSIStartAvailableCheck(_T("gmtest")); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + _tprintf(_T("The backend is not available\n")); + return 1; + } + + // set the callbacks + memset(&callbacks, 0, sizeof(PEERCallbacks)); + callbacks.disconnected = DisconnectedCallback; + //callbacks.qrNatNegotiateCallback + callbacks.gameStarted = GameStartedCallback; + callbacks.playerChangedNick = PlayerChangedNickCallback; + callbacks.playerJoined = PlayerJoinedCallback; + callbacks.playerLeft = PlayerLeftCallback; + callbacks.readyChanged = ReadyChangedCallback; + callbacks.roomMessage = RoomMessageCallback; + callbacks.playerMessage = PlayerMessageCallback; + callbacks.roomUTM = RoomUTMCallback; + callbacks.roomKeyChanged = RoomKeyChangedCallback; + callbacks.qrKeyList = QRKeyListCallback; + callbacks.qrServerKey = QRServerKeyCallback; + callbacks.param = NULL; + + // initialize peer object, specifying the supported callbacks + peer = peerInitialize(&callbacks); + if(!peer) + { + _tprintf(_T("Failed to init\n")); + return 1; + } + + // ping/cross-ping in every room + pingRooms[TitleRoom] = PEERTrue; + pingRooms[GroupRoom] = PEERTrue; + pingRooms[StagingRoom] = PEERTrue; + crossPingRooms[TitleRoom] = PEERTrue; + crossPingRooms[GroupRoom] = PEERTrue; + crossPingRooms[StagingRoom] = PEERTrue; + + // set the title + if(!peerSetTitle(peer, TITLE, secret_key, TITLE, secret_key, 0, maxUpdates, natNeg, pingRooms, crossPingRooms)) + { + peerShutdown(peer); + _tprintf(_T("Failed to set the title\n")); + return 1; + } + + // connect to the chat server + _tprintf(_T("Connecting as %s..."), nick); + peerConnect(peer, nick, profileID, NickErrorCallback, ConnectCallback, userData, blocking); + if(!connectSuccess) + { + peerShutdown(peer); + _tprintf(_T("Failed to connect\n")); + return 1; + } + printf("Connected\n\n"); + + // join the title room + printf("Joining title room..."); + peerJoinTitleRoom(peer, NULL, JoinCallback, NULL, PEERTrue); + if(!joinSuccess) + { + peerDisconnect(peer); + peerShutdown(peer); + _tprintf(_T("Failed to join the title room\n")); + return 1; + } + printf("Joined\n\n"); + + // list the group rooms + printf("Listing group rooms:\n"); + peerListGroupRooms(peer, _T(""), ListGroupRoomsCallback, userData, non_blocking); + + while (!groupRoomCallbackDone) + { + peerThink(peer); + msleep(10); + } + + // send a chat message to the room + printf("\nSending message to the Title Room...\n"); + peerMessageRoom(peer, TitleRoom, _T("Hi everyone in the Title Room!\n"), NormalMessage); + + // Loop for a while + startTime = current_time(); + while((current_time() - startTime) < (1000)) + { + peerThink(peer); + msleep(10); + } + + _tprintf(_T("\nJoining Group Room 'Newbies'...")); + peerJoinGroupRoom(peer, newbiesGroupID, JoinRoomCallback, userData, blocking); + + _tprintf(_T("\nPlayers in Group Room: \n")); + peerEnumPlayers(peer, GroupRoom, EnumPlayersCallback, NULL); + + _tprintf(_T("Hosting Staging Room...\n")); + peerCreateStagingRoom(peer, serverName, maxPlayers, noPassword, CreateStagingRoomCallback, userData, blocking); + + // Loop for a while + startTime = current_time(); + while((current_time() - startTime) < (1000)) + { + peerThink(peer); + msleep(10); + } + + //peerStartAutoMatch(peer, 3, _T(""), AutoMatchStatusCallback, AutoMatchRateCallback, NULL, PEERFalse); + + //peerStopListingGames(peer); + + // Leave the title room + peerLeaveRoom(peer, TitleRoom, NULL); + + // Stop auto match if it's in progress + //peerStopAutoMatch(peer); + + // disconnect local client from chat server (peerShutdown must still be called) + peerDisconnect(peer); + + peerShutdown(peer); // clean up (free internal sdk memory) + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + return 0; +} diff --git a/xrGameSpy/gamespy/Peer/peerc/peerc.dsp b/xrGameSpy/gamespy/Peer/peerc/peerc.dsp new file mode 100644 index 00000000000..1c5db5aeb7d --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerc.dsp @@ -0,0 +1,524 @@ +# Microsoft Developer Studio Project File - Name="peerc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=peerc - Win32 Unicode 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 "peerc.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 "peerc.mak" CFG="peerc - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "peerc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "peerc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "peerc - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "peerc - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Peer/peerc", GSUAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "peerc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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 wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "peerc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "peerc - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "peerc___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "peerc___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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 wsock32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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 wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "peerc - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "peerc___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "peerc___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 wsock32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "peerc - Win32 Release" +# Name "peerc - Win32 Debug" +# Name "peerc - Win32 Unicode Release" +# Name "peerc - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\peerc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "" +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "PeerSDK" + +# PROP Default_Filter "" +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_server.c +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\..\serverbrowsing\sb_serverlist.c +# End Source File +# End Group +# Begin Group "QueryReportingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "ChatSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\chat\chat.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatChannel.c +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatHandlers.c +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\Chat\chatSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\chat\chatSocket.h +# End Source File +# End Group +# Begin Group "Pinger" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\pinger\pinger.h +# End Source File +# Begin Source File + +SOURCE=..\..\pinger\pingerMain.c +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\peer.h +# End Source File +# Begin Source File + +SOURCE=..\peerAutoMatch.c +# End Source File +# Begin Source File + +SOURCE=..\peerAutoMatch.h +# End Source File +# Begin Source File + +SOURCE=..\peerCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\peerCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\peerGlobalCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\peerGlobalCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\peerHost.c +# End Source File +# Begin Source File + +SOURCE=..\peerHost.h +# End Source File +# Begin Source File + +SOURCE=..\peerKeys.c +# End Source File +# Begin Source File + +SOURCE=..\peerKeys.h +# End Source File +# Begin Source File + +SOURCE=..\peerMain.c +# End Source File +# Begin Source File + +SOURCE=..\peerMain.h +# End Source File +# Begin Source File + +SOURCE=..\peerMangle.c +# End Source File +# Begin Source File + +SOURCE=..\peerMangle.h +# End Source File +# Begin Source File + +SOURCE=..\peerOperations.c +# End Source File +# Begin Source File + +SOURCE=..\peerOperations.h +# End Source File +# Begin Source File + +SOURCE=..\peerPing.c +# End Source File +# Begin Source File + +SOURCE=..\peerPing.h +# End Source File +# Begin Source File + +SOURCE=..\peerPlayers.c +# End Source File +# Begin Source File + +SOURCE=..\peerPlayers.h +# End Source File +# Begin Source File + +SOURCE=..\peerQR.c +# End Source File +# Begin Source File + +SOURCE=..\peerQR.h +# End Source File +# Begin Source File + +SOURCE=..\peerRooms.c +# End Source File +# Begin Source File + +SOURCE=..\peerRooms.h +# End Source File +# Begin Source File + +SOURCE=..\peerSB.c +# End Source File +# Begin Source File + +SOURCE=..\peerSB.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Peer/peerc/peerc_vs2005.vcproj b/xrGameSpy/gamespy/Peer/peerc/peerc_vs2005.vcproj new file mode 100644 index 00000000000..d9670017e54 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerc_vs2005.vcproj @@ -0,0 +1,1353 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Peer/peerc/peerc_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Peer/peerc/peerc_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerc_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Peer/peerc/peerlinux/Makefile b/xrGameSpy/gamespy/Peer/peerc/peerlinux/Makefile new file mode 100644 index 00000000000..8c73e559bed --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerlinux/Makefile @@ -0,0 +1,77 @@ +# Peer SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=peersdk + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../darray.o\ + ../../../md5c.o\ + ../../../hashtable.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../../Chat/chatCallbacks.o\ + ../../../Chat/chatChannel.o\ + ../../../Chat/chatCrypt.o\ + ../../../Chat/chatHandlers.o\ + ../../../Chat/chatMain.o\ + ../../../Chat/chatSocket.o\ + ../../../pinger/pingerMain.o\ + ../../../serverbrowsing/sb_crypt.o\ + ../../../serverbrowsing/sb_queryengine.o\ + ../../../serverbrowsing/sb_server.o\ + ../../../serverbrowsing/sb_serverbrowsing.o\ + ../../../serverbrowsing/sb_serverlist.o\ + ../../../qr2/qr2.o\ + ../../../qr2/qr2regkeys.o\ + ../../../natneg/natneg.o\ + ../../../natneg/NATify.o\ + ../../peerAutoMatch.o\ + ../../peerCallbacks.o\ + ../../peerGlobalCallbacks.o\ + ../../peerHost.o\ + ../../peerKeys.o\ + ../../peerMain.o\ + ../../peerMangle.o\ + ../../peerOperations.o\ + ../../peerPing.o\ + ../../peerPlayers.o\ + ../../peerQR.o\ + ../../peerRooms.o\ + ../../peerSB.o\ + ../peerc.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/Peer/peerc/peermacosx/Makefile b/xrGameSpy/gamespy/Peer/peerc/peermacosx/Makefile new file mode 100644 index 00000000000..a91940e64d3 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peermacosx/Makefile @@ -0,0 +1,52 @@ +# Peer SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=peerc + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../Chat/chatCallbacks.o\ + ../../../Chat/chatChannel.o\ + ../../../Chat/chatCrypt.o\ + ../../../Chat/chatHandlers.o\ + ../../../Chat/chatMain.o\ + ../../../Chat/chatSocket.o\ + ../../../pinger/pingerMain.o\ + ../../../serverbrowsing/sb_crypt.o\ + ../../../serverbrowsing/sb_queryengine.o\ + ../../../serverbrowsing/sb_server.o\ + ../../../serverbrowsing/sb_serverbrowsing.o\ + ../../../serverbrowsing/sb_serverlist.o\ + ../../../qr2/qr2.o\ + ../../../qr2/qr2regkeys.o\ + ../../../natneg/natneg.o\ + ../../../natneg/NATify.o\ + ../../peerAutoMatch.o\ + ../../peerCallbacks.o\ + ../../peerGlobalCallbacks.o\ + ../../peerHost.o\ + ../../peerKeys.o\ + ../../peerMain.o\ + ../../peerMangle.o\ + ../../peerOperations.o\ + ../../peerPing.o\ + ../../peerPlayers.o\ + ../../peerQR.o\ + ../../peerRooms.o\ + ../../peerSB.o\ + ../peerc.o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/Peer/peerc/peernitrocw/Nitro.lcf b/xrGameSpy/gamespy/Peer/peerc/peernitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peernitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/Peer/peerc/peernitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/Peer/peerc/peernitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peernitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/Peer/peerc/peernitrocw/peernitrocw.mcp b/xrGameSpy/gamespy/Peer/peerc/peernitrocw/peernitrocw.mcp new file mode 100644 index 00000000000..6a3ee55ca15 Binary files /dev/null and b/xrGameSpy/gamespy/Peer/peerc/peernitrocw/peernitrocw.mcp differ diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps2/Makefile b/xrGameSpy/gamespy/Peer/peerc/peerps2/Makefile new file mode 100644 index 00000000000..37bafd7ed63 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps2/Makefile @@ -0,0 +1,53 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = peerc + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../hashtable.o\ + ../../../available.o\ + ../../../stringutil.o\ + ../../../serverbrowsing/sb_crypt.o\ + ../../../serverbrowsing/sb_queryengine.o\ + ../../../serverbrowsing/sb_server.o\ + ../../../serverbrowsing/sb_serverbrowsing.o\ + ../../../serverbrowsing/sb_serverlist.o\ + ../../../qr2/qr2.o\ + ../../../qr2/qr2regkeys.o\ + ../../../Chat/chatCrypt.o\ + ../../../Chat/chatCallbacks.o\ + ../../../Chat/chatChannel.o\ + ../../../Chat/chatHandlers.o\ + ../../../Chat/chatMain.o\ + ../../../Chat/chatSocket.o\ + ../../../pinger/pingerMain.o\ + ../../peerAutoMatch.o\ + ../../peerCallbacks.o\ + ../../peerGlobalCallbacks.o\ + ../../peerHost.o\ + ../../peerKeys.o\ + ../../peerMain.o\ + ../../peerMangle.o\ + ../../peerOperations.o\ + ../../peerPing.o\ + ../../peerPlayers.o\ + ../../peerQR.o\ + ../../peerRooms.o\ + ../../peerSB.o\ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps2cw/peerps2cw.mcp b/xrGameSpy/gamespy/Peer/peerc/peerps2cw/peerps2cw.mcp new file mode 100644 index 00000000000..ebf2deb04cf Binary files /dev/null and b/xrGameSpy/gamespy/Peer/peerc/peerps2cw/peerps2cw.mcp differ diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.dsp b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.dsp new file mode 100644 index 00000000000..056ed2b69dc --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.dsp @@ -0,0 +1,564 @@ +# Microsoft Developer Studio Project File - Name="peerps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=peerps2prodg - Win32 Release_Insock +!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 "peerps2prodg.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 "peerps2prodg.mak" CFG="peerps2prodg - Win32 Release_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "peerps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "peerps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "peerps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "peerps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "peerps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "peerps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Peer/peerc/peerps2prodg", NTEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "peerps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "_DEBUG" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\peerps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_EENet\peerps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "peerps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "peerps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "peerps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "INSOCK" /D "UNIQUEID" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libc.a sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_SNSystems\peerps2prodg.elf" /D:SN_TARGET_PS2 -fshort-wchar +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_Insock\peerps2prodg.elf" /D:SN_TARGET_PS2 -fshort-wchar + +!ELSEIF "$(CFG)" == "peerps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\peerps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_SNSystems\peerps2prodg.elf" /D:SN_TARGET_PS2 -fshort-wchar + +!ELSEIF "$(CFG)" == "peerps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\peerps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\peerps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "peerps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "peerps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "peerps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /D "UNIQUEID" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\peerps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\peerps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "peerps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\peerps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\peerps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "peerps2prodg - Win32 Debug_EENet" +# Name "peerps2prodg - Win32 Debug_Insock" +# Name "peerps2prodg - Win32 Debug_SNSystems" +# Name "peerps2prodg - Win32 Release_EENet" +# Name "peerps2prodg - Win32 Release_Insock" +# Name "peerps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\peerc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "Peer" + +# PROP Default_Filter "" +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_server.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\serverbrowsing\sb_serverlist.c +# End Source File +# End Group +# Begin Group "QueryReportingSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\qr2\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "ChatSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Chat\chat.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatChannel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatChannel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatHandlers.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatHandlers.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\Chat\chatSocket.h +# End Source File +# End Group +# Begin Group "Pinger" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\pinger\pinger.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\pinger\pingerMain.c +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\peer.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerAutoMatch.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerAutoMatch.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerGlobalCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerGlobalCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerHost.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerHost.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerMangle.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerMangle.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerOperations.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerOperations.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerPing.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerPing.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerPlayers.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerPlayers.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerQR.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerQR.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerRooms.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerRooms.h +# End Source File +# Begin Source File + +SOURCE=..\..\peerSB.c +# End Source File +# Begin Source File + +SOURCE=..\..\peerSB.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.dsw b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.dsw new file mode 100644 index 00000000000..7c1581af70a --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "peerps2prodg"=.\peerps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer/peerc/peerps2prodg", NTEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/gamespy/goa/peer/peerc/peerps2prodg", NTEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.sln b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.sln new file mode 100644 index 00000000000..92c9c7336ad --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.sln @@ -0,0 +1,43 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peerps2prodg", "peerps2prodg.vcproj", "{3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = peerps2prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 INET Release|Win32.Build.0 = PS2 INET Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {3FA7F00E-E8CC-4A64-9E29-40BCD5AFCAF5}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.vcproj b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.vcproj new file mode 100644 index 00000000000..d11c160651a --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps2prodg/peerps2prodg.vcproj @@ -0,0 +1,913 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps3/Makefile b/xrGameSpy/gamespy/Peer/peerc/peerps3/Makefile new file mode 100644 index 00000000000..26c843f1f6a --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps3/Makefile @@ -0,0 +1,58 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = peerc + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsAvailable.o \ + ../../../common/gsDebug.o \ + ../../../common/gsMemory.o \ + ../../../common/gsStringUtil.o \ + ../../../serverbrowsing/sb_crypt.o\ + ../../../serverbrowsing/sb_queryengine.o\ + ../../../serverbrowsing/sb_server.o\ + ../../../serverbrowsing/sb_serverbrowsing.o\ + ../../../serverbrowsing/sb_serverlist.o\ + ../../../qr2/qr2.o\ + ../../../qr2/qr2regkeys.o\ + ../../../Chat/chatCrypt.o\ + ../../../Chat/chatCallbacks.o\ + ../../../Chat/chatChannel.o\ + ../../../Chat/chatHandlers.o\ + ../../../Chat/chatMain.o\ + ../../../Chat/chatSocket.o\ + ../../../pinger/pingerMain.o\ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../peerAutoMatch.o\ + ../../peerCallbacks.o\ + ../../peerGlobalCallbacks.o\ + ../../peerHost.o\ + ../../peerKeys.o\ + ../../peerMain.o\ + ../../peerMangle.o\ + ../../peerOperations.o\ + ../../peerPing.o\ + ../../peerPlayers.o\ + ../../peerQR.o\ + ../../peerRooms.o\ + ../../peerSB.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps3prodg/peerps3prodg.sln b/xrGameSpy/gamespy/Peer/peerc/peerps3prodg/peerps3prodg.sln new file mode 100644 index 00000000000..4b92cf2d9a1 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps3prodg/peerps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peerps3prodg", "peerps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = peerps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Peer/peerc/peerps3prodg/peerps3prodg.vcproj b/xrGameSpy/gamespy/Peer/peerc/peerps3prodg/peerps3prodg.vcproj new file mode 100644 index 00000000000..ec868527493 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerps3prodg/peerps3prodg.vcproj @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Peer/peerc/peerpsp/Makefile b/xrGameSpy/gamespy/Peer/peerc/peerpsp/Makefile new file mode 100644 index 00000000000..54cc2dab1f8 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerpsp/Makefile @@ -0,0 +1,57 @@ +#GameSpy.net PSP Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +#SDK_LIBS = + +#Name of the SDK sample +TARGET = peerc + +#All the object files needed for this SDK +OBJS = ../../../common/psp/pspcommon.o\ + ../../../common/psp/gsUtilPSP.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsDebug.o\ + ../../../common/gsAvailable.o\ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../pinger/pingerMain.o\ + ../../../qr2/qr2.o\ + ../../../qr2/qr2regkeys.o\ + ../../../serverbrowsing/sb_crypt.o\ + ../../../serverbrowsing/sb_queryengine.o\ + ../../../serverbrowsing/sb_server.o\ + ../../../serverbrowsing/sb_serverbrowsing.o\ + ../../../serverbrowsing/sb_serverlist.o\ + ../../../chat/chatCallbacks.o\ + ../../../chat/chatChannel.o\ + ../../../chat/chatCrypt.o\ + ../../../chat/chatHandlers.o\ + ../../../chat/chatMain.o\ + ../../../chat/chatSocket.o\ + ../../peerAutoMatch.o\ + ../../peerCallbacks.o\ + ../../peerGlobalCallbacks.o\ + ../../peerHost.o\ + ../../peerKeys.o\ + ../../peerMain.o\ + ../../peerMangle.o\ + ../../peerOperations.o\ + ../../peerPing.o\ + ../../peerPlayers.o\ + ../../peerQR.o\ + ../../peerRooms.o\ + ../../peerSB.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/psp/Makefile.common + diff --git a/xrGameSpy/gamespy/Peer/peerc/peerpspprodg/peerpspprodg.sln b/xrGameSpy/gamespy/Peer/peerc/peerpspprodg/peerpspprodg.sln new file mode 100644 index 00000000000..a242a288375 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerpspprodg/peerpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peerpspprodg", "peerpspprodg.vcproj", "{95FC1698-2881-45AD-828C-BEF64ADF6A27}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = peerpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {95FC1698-2881-45AD-828C-BEF64ADF6A27}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {95FC1698-2881-45AD-828C-BEF64ADF6A27}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {95FC1698-2881-45AD-828C-BEF64ADF6A27}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {95FC1698-2881-45AD-828C-BEF64ADF6A27}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {95FC1698-2881-45AD-828C-BEF64ADF6A27}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {95FC1698-2881-45AD-828C-BEF64ADF6A27}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Peer/peerc/peerpspprodg/peerpspprodg.vcproj b/xrGameSpy/gamespy/Peer/peerc/peerpspprodg/peerpspprodg.vcproj new file mode 100644 index 00000000000..ddf1336b410 --- /dev/null +++ b/xrGameSpy/gamespy/Peer/peerc/peerpspprodg/peerpspprodg.vcproj @@ -0,0 +1,699 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Peer/peerc/peerrevolutioncw/peerrevolutioncw.mcp b/xrGameSpy/gamespy/Peer/peerc/peerrevolutioncw/peerrevolutioncw.mcp new file mode 100644 index 00000000000..d56ea977d4c Binary files /dev/null and b/xrGameSpy/gamespy/Peer/peerc/peerrevolutioncw/peerrevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2.dsp b/xrGameSpy/gamespy/Voice2/Voice2.dsp new file mode 100644 index 00000000000..6c289cbc37d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2.dsp @@ -0,0 +1,460 @@ +# Microsoft Developer Studio Project File - Name="Voice2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=Voice2 - 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 "Voice2.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 "Voice2.mak" CFG="Voice2 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Voice2 - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "Voice2 - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Voice2", NONDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Voice2 - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "speex-1.0.5\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "Voice2 - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "speex-1.0.5\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "Voice2 - Win32 Release" +# Name "Voice2 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gvCodec.c +# End Source File +# Begin Source File + +SOURCE=.\gvCustomDevice.c +# End Source File +# Begin Source File + +SOURCE=.\gvDevice.c +# End Source File +# Begin Source File + +SOURCE=.\gvDirectSound.c +# End Source File +# Begin Source File + +SOURCE=.\gvFrame.c +# End Source File +# Begin Source File + +SOURCE=.\gvMain.c +# End Source File +# Begin Source File + +SOURCE=.\gvSource.c +# End Source File +# Begin Source File + +SOURCE=.\gvSpeex.c +# End Source File +# Begin Source File + +SOURCE=.\gvUtil.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gv.h +# End Source File +# Begin Source File + +SOURCE=.\gvCodec.h +# End Source File +# Begin Source File + +SOURCE=.\gvCustomDevice.h +# End Source File +# Begin Source File + +SOURCE=.\gvDevice.h +# End Source File +# Begin Source File + +SOURCE=.\gvDirectSound.h +# End Source File +# Begin Source File + +SOURCE=.\gvFrame.h +# End Source File +# Begin Source File + +SOURCE=.\gvMain.h +# End Source File +# Begin Source File + +SOURCE=.\gvSource.h +# End Source File +# Begin Source File + +SOURCE=.\gvSpeex.h +# End Source File +# Begin Source File + +SOURCE=.\gvUtil.h +# End Source File +# Begin Source File + +SOURCE=..\nonport.h +# End Source File +# End Group +# Begin Group "Speex" + +# PROP Default_Filter "" +# Begin Group "Source" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\bits.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\cb_search.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\exc_10_16_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\exc_10_32_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\exc_20_32_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\exc_5_256_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\exc_5_64_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\exc_8_128_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\filters.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\gain_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\gain_table_lbr.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\hexc_10_32_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\hexc_table.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\high_lsp_tables.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\lpc.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\lsp.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\lsp_tables_nb.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\ltp.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\math_approx.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\misc.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\modes.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\nb_celp.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\quant_lsp.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\sb_celp.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\speex_callbacks.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\speex_header.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\stereo.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\vbr.c" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\vq.c" +# End Source File +# End Group +# Begin Group "Headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\cb_search.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\disable_warnings.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\filters.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\filters_sse.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\lpc.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\lsp.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\ltp.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\ltp_sse.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\math_approx.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\misc.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\modes.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\nb_celp.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\quant_lsp.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\sb_celp.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\stack_alloc.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\vbr.h" +# End Source File +# Begin Source File + +SOURCE=".\speex-1.0.5\libspeex\vq.h" +# End Source File +# End Group +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/Voice2.dsw b/xrGameSpy/gamespy/Voice2/Voice2.dsw new file mode 100644 index 00000000000..2dc933ada4d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2.dsw @@ -0,0 +1,93 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Voice2BuddyMFC"=.\Voice2BuddyMFC\Voice2BuddyMFC.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/IGNCP/Gamespy/GOA/Voice2/voice2buddymfc + .\voice2buddymfc + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libspeex + End Project Dependency +}}} + +############################################################################### + +Project: "Voice2Test"=.\Voice2Test\Voice2Test.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/IGNCP/Gamespy/GOA/Voice2/Voice2Test + .\Voice2Test + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libspeex + End Project Dependency +}}} + +############################################################################### + +Project: "libspeex"=.\libspeex\libspeex.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/IGNCP/Gamespy/GOA/Voice2/libspeex + .\libspeex + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "voice2bench"=.\voice2bench\voice2bench.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/IGNCP/Gamespy/GOA/Voice2/voice2bench + .\voice2bench + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libgsm + End Project Dependency + Begin Project Dependency + Project_Dep_Name libspeex + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/LoginDlg.cpp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/LoginDlg.cpp new file mode 100644 index 00000000000..4938f0839c6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/LoginDlg.cpp @@ -0,0 +1,107 @@ +// LoginDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "Voice2BuddyMFC.h" +#include "LoginDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + + +CLoginDlg::CLoginDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLoginDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoginDlg) + m_Email = _T(""); + m_Nickname = _T(""); + m_Password = _T(""); + //}}AFX_DATA_INIT +} + + +void CLoginDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoginDlg) + DDX_Text(pDX, IDC_EMAIL, m_Email); + DDX_Text(pDX, IDC_NICKNAME, m_Nickname); + DDX_Text(pDX, IDC_PASSWORD, m_Password); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoginDlg, CDialog) + //{{AFX_MSG_MAP(CLoginDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg message handlers + +void CLoginDlg::OnOK() +{ + // Retrieve settings from the view + UpdateData(TRUE); + + // Save settings to the registry + HKEY aRegKey = NULL; + LONG aResult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\GameSpy\\Voice2BuddyMFC", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &aRegKey, NULL); + if (aResult == ERROR_SUCCESS) + { + RegSetValue(aRegKey, "LastLoginNickname", REG_SZ, m_Nickname, m_Nickname.GetLength()); + RegSetValue(aRegKey, "LastLoginEmail", REG_SZ, m_Email, m_Email.GetLength()); + RegCloseKey(aRegKey); + } + + + CDialog::OnOK(); +} + +void CLoginDlg::OnCancel() +{ + + CDialog::OnCancel(); +} + +BOOL CLoginDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Load settings from the registry + char aStringBuf[255]; + LONG aLongBuf; + + HKEY aRegKey = NULL; + LONG aResult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\GameSpy\\Voice2BuddyMFC", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &aRegKey, NULL); + if (aResult == ERROR_SUCCESS) + { + // Load last session username + aLongBuf = 255; + aResult = RegQueryValue(aRegKey, "LastLoginNickname", aStringBuf, &aLongBuf); + if (aResult == ERROR_SUCCESS) + m_Nickname = aStringBuf; + + // Load last session email + aLongBuf = 255; + aResult = RegQueryValue(aRegKey, "LastLoginEmail", aStringBuf, &aLongBuf); + if (aResult == ERROR_SUCCESS) + m_Email = aStringBuf; + + RegCloseKey(aRegKey); + } + + // Reflect new settings into the view + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/LoginDlg.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/LoginDlg.h new file mode 100644 index 00000000000..dd0d249047c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/LoginDlg.h @@ -0,0 +1,50 @@ +#if !defined(AFX_LOGINDLG_H__0E2CE143_57CF_4FE7_9DFB_9C63388C0680__INCLUDED_) +#define AFX_LOGINDLG_H__0E2CE143_57CF_4FE7_9DFB_9C63388C0680__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LoginDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + +class CLoginDlg : public CDialog +{ +// Construction +public: + CLoginDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoginDlg) + enum { IDD = IDD_LOGIN }; + CString m_Email; + CString m_Nickname; + CString m_Password; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoginDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoginDlg) + virtual void OnOK(); + virtual void OnCancel(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOGINDLG_H__0E2CE143_57CF_4FE7_9DFB_9C63388C0680__INCLUDED_) diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/SetupDlg.cpp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/SetupDlg.cpp new file mode 100644 index 00000000000..bf54bc68187 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/SetupDlg.cpp @@ -0,0 +1,236 @@ +// SetupDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "Voice2BuddyMFC.h" +#include "SetupDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define VOICE_THINK_TIMER_ID 101 +#define VOICE_THINK_TIMER_DELAY 10 + +enum SetupMessage +{ + V2B_STARTDEVICES = 0 +}; + +///////////////////////////////////////////////////////////////////////////// +// CSetupDlg dialog + + +CSetupDlg::CSetupDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSetupDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSetupDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CSetupDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSetupDlg) + DDX_Control(pDX, IDC_ACTIVATELEVEL, m_ActivateLevel); + DDX_Control(pDX, IDC_VOICELEVEL, m_VoiceLevelCtrl); + DDX_Control(pDX, IDC_ISSPEAKING, m_IsSpeakingCtrl); + DDX_Control(pDX, IDC_PLAYBACKCOMBO, m_PlaybackCombo); + DDX_Control(pDX, IDC_CAPTURECOMBO, m_CaptureCombo); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CSetupDlg, CDialog) + //{{AFX_MSG_MAP(CSetupDlg) + ON_CBN_SELCHANGE(IDC_CAPTURECOMBO, OnSelChangeCaptureCombo) + ON_CBN_SELCHANGE(IDC_PLAYBACKCOMBO, OnSelChangePlaybackCombo) + ON_WM_TIMER() + ON_WM_HSCROLL() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSetupDlg message handlers + +BOOL CSetupDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Begin Enumerate devices + int aNumDevices = gvListDevices(m_SetupInfo->m_DeviceInfoArray, MAX_DEVICES, GV_CAPTURE_AND_PLAYBACK); + + // Populate the combo boxes + for (int aDeviceNum = 0; aDeviceNum < aNumDevices; aDeviceNum++) + { + // Add capture devices to display list + if (GV_CAPTURE & m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_deviceType) + { + // Set the item data to the device number (this may differ from the row due to sorting) + m_CaptureCombo.InsertString(0, m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_name); + m_CaptureCombo.SetItemData(0, aDeviceNum); + if (GV_CAPTURE & m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_defaultDevice) + m_CaptureCombo.SetCurSel(0); + } + + // Add playback devices to display list + if (GV_PLAYBACK & m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_deviceType) + { + // Set the item data to the device number (this may differ from the row due to sorting) + m_PlaybackCombo.InsertString(0, m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_name); + m_PlaybackCombo.SetItemData(0, aDeviceNum); + if (GV_PLAYBACK & m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_defaultDevice) + m_PlaybackCombo.SetCurSel(0); + } + } + + // If no device has been set, try setting to the first one + if (m_CaptureCombo.GetCurSel() == -1) + m_CaptureCombo.SetCurSel(0); + if (m_PlaybackCombo.GetCurSel() == -1) + m_PlaybackCombo.SetCurSel(0); + + // Try to start the capture and playback device + StartSelCaptureDevice(); + StartSelPlaybackDevice(); + + UpdateData(FALSE); + + SetTimer(VOICE_THINK_TIMER_ID, VOICE_THINK_TIMER_DELAY, NULL); + + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + + +// Switch the active device +void CSetupDlg::OnSelChangeCaptureCombo() +{ + StartSelCaptureDevice(); +} + +// Switch the active device +void CSetupDlg::OnSelChangePlaybackCombo() +{ + StartSelPlaybackDevice(); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void CSetupDlg::StartSelCaptureDevice() +{ + // Stop the previous device + if (m_SetupInfo->m_CaptureDevice != NULL) + { + gvStopDevice(m_SetupInfo->m_CaptureDevice, GV_CAPTURE); + gvFreeDevice(m_SetupInfo->m_CaptureDevice); + } + + // Get the selected device id + int aSelDevice = m_CaptureCombo.GetCurSel(); + if (aSelDevice == -1) + return; + + int aDeviceNum = m_CaptureCombo.GetItemData(aSelDevice); + if (aDeviceNum == CB_ERR) + return; + + // Create and start the new device + m_SetupInfo->m_CaptureDevice = gvNewDevice(m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_id, GV_CAPTURE); + if (m_SetupInfo->m_CaptureDevice != NULL) + gvStartDevice(m_SetupInfo->m_CaptureDevice, GV_CAPTURE); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void CSetupDlg::StartSelPlaybackDevice() +{ + // Stop the previous device + if (m_SetupInfo->m_PlaybackDevice != NULL) + { + gvStopDevice(m_SetupInfo->m_PlaybackDevice, GV_PLAYBACK); + gvFreeDevice(m_SetupInfo->m_PlaybackDevice); + } + + // Get the selected device id + int aSelDevice = m_PlaybackCombo.GetCurSel(); + if (aSelDevice == -1) + return; + + int aDeviceNum = m_PlaybackCombo.GetItemData(aSelDevice); + if (aDeviceNum == CB_ERR) + return; + + // Create and start the new device + m_SetupInfo->m_PlaybackDevice = gvNewDevice(m_SetupInfo->m_DeviceInfoArray[aDeviceNum].m_id, GV_PLAYBACK); + if (m_SetupInfo->m_PlaybackDevice != NULL) + gvStartDevice(m_SetupInfo->m_PlaybackDevice, GV_PLAYBACK); +} + +static GVBool gMute = GVFalse; + +void CSetupDlg::OnTimer(UINT nIDEvent) +{ + gvThink(); + + // Check for voice data, play as local echo + int aBytesAvailable = gvGetAvailableCaptureBytes(m_SetupInfo->m_CaptureDevice); + if (aBytesAvailable > 0) + { + GVByte aBuffer[1024]; + int aLength = 1024; + GVFrameStamp aFrameStamp; + GVScalar aVolume = 0; + + GVBool gotPacket = gvCapturePacket(m_SetupInfo->m_CaptureDevice, aBuffer, &aLength, &aFrameStamp, &aVolume); + if (gotPacket == GVTrue) + { + gvPlayPacket(m_SetupInfo->m_PlaybackDevice, aBuffer, aLength, 0, aFrameStamp, gMute); + m_IsSpeakingCtrl.ShowWindow(SW_SHOW); + } + else + { + m_IsSpeakingCtrl.ShowWindow(SW_HIDE); + } + + // Display the volume level + m_VoiceLevelCtrl.SetPos( (int)(aVolume*100) ); + } + + + CDialog::OnTimer(nIDEvent); +} + +void CSetupDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + if (pScrollBar == (CScrollBar*)&m_ActivateLevel) + { + double aThreshold = (float)m_ActivateLevel.GetPos()/100; + if (m_SetupInfo->m_CaptureDevice != NULL) + gvSetCaptureThreshold(m_SetupInfo->m_CaptureDevice, aThreshold); + } + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); +} + +BOOL CSetupDlg::DestroyWindow() +{ + // Stop the devices + if (m_SetupInfo->m_CaptureDevice != NULL) + gvStopDevice(m_SetupInfo->m_CaptureDevice, GV_CAPTURE); + if (m_SetupInfo->m_PlaybackDevice != NULL) + gvStopDevice(m_SetupInfo->m_PlaybackDevice, GV_PLAYBACK); + + + // Kill the think timer + KillTimer(VOICE_THINK_TIMER_ID); + + + return CDialog::DestroyWindow(); +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/SetupDlg.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/SetupDlg.h new file mode 100644 index 00000000000..a832760b625 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/SetupDlg.h @@ -0,0 +1,81 @@ +#if !defined(AFX_SETUPDLG_H__36B5B6D7_690D_4628_92E4_96B2CAE34B82__INCLUDED_) +#define AFX_SETUPDLG_H__36B5B6D7_690D_4628_92E4_96B2CAE34B82__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// SetupDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CSetupDlg dialog +#include "../../voice2/gv.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +const unsigned int MAX_DEVICES = 10; + +struct VoiceSetupInfo +{ + GVDevice m_PlaybackDevice; + GVDevice m_CaptureDevice; + GVDeviceInfo m_DeviceInfoArray[MAX_DEVICES]; +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +class CSetupDlg : public CDialog +{ +public: + VoiceSetupInfo* m_SetupInfo; + + void StartSelCaptureDevice(); + void StartSelPlaybackDevice(); + + + // MFC STUFF BELOW + +// Construction +public: + CSetupDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSetupDlg) + enum { IDD = IDD_SETUPDIALOG }; + CSliderCtrl m_ActivateLevel; + CProgressCtrl m_VoiceLevelCtrl; + CStatic m_IsSpeakingCtrl; + CComboBox m_PlaybackCombo; + CComboBox m_CaptureCombo; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSetupDlg) + public: + virtual BOOL DestroyWindow(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CSetupDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSelChangeCaptureCombo(); + afx_msg void OnSelChangePlaybackCombo(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SETUPDLG_H__36B5B6D7_690D_4628_92E4_96B2CAE34B82__INCLUDED_) diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/StdAfx.cpp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/StdAfx.cpp new file mode 100644 index 00000000000..16c74863c30 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// Voice2BuddyMFC.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/StdAfx.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/StdAfx.h new file mode 100644 index 00000000000..19665974cb5 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/StdAfx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__FCEAFCA1_440C_4599_B89A_56952F1DB30C__INCLUDED_) +#define AFX_STDAFX_H__FCEAFCA1_440C_4599_B89A_56952F1DB30C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__FCEAFCA1_440C_4599_B89A_56952F1DB30C__INCLUDED_) diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.cpp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.cpp new file mode 100644 index 00000000000..fca45c6586d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.cpp @@ -0,0 +1,74 @@ +// Voice2BuddyMFC.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "Voice2BuddyMFC.h" +#include "Voice2BuddyMFCDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCApp + +BEGIN_MESSAGE_MAP(CVoice2BuddyMFCApp, CWinApp) + //{{AFX_MSG_MAP(CVoice2BuddyMFCApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCApp construction + +CVoice2BuddyMFCApp::CVoice2BuddyMFCApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CVoice2BuddyMFCApp object + +CVoice2BuddyMFCApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCApp initialization + +BOOL CVoice2BuddyMFCApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CVoice2BuddyMFCDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.dsp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.dsp new file mode 100644 index 00000000000..9a01f2617d9 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.dsp @@ -0,0 +1,623 @@ +# Microsoft Developer Studio Project File - Name="Voice2BuddyMFC" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=Voice2BuddyMFC - 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 "Voice2BuddyMFC.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 "Voice2BuddyMFC.mak" CFG="Voice2BuddyMFC - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Voice2BuddyMFC - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "Voice2BuddyMFC - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 1 +# PROP Scc_ProjName "$/IGNCP/Gamespy/GOA/Voice2/voice2buddymfc" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Voice2BuddyMFC - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /WX /GX /O2 /I "..\speex-1.0.5\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 dsound.lib dxguid.lib libspeex.lib /nologo /subsystem:windows /machine:I386 /libpath:"..\libspeex\Release" + +!ELSEIF "$(CFG)" == "Voice2BuddyMFC - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\speex-1.0.5\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /FD /GZ /c +# SUBTRACT CPP /WX /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 dsound.lib dxguid.lib libspeex.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /libpath:"..\libspeex\Debug" + +!ENDIF + +# Begin Target + +# Name "Voice2BuddyMFC - Win32 Release" +# Name "Voice2BuddyMFC - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\LoginDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\SetupDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# End Source File +# Begin Source File + +SOURCE=.\Voice2BuddyMFC.cpp +# End Source File +# Begin Source File + +SOURCE=.\Voice2BuddyMFC.rc +# End Source File +# Begin Source File + +SOURCE=.\Voice2BuddyMFCDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\VoiceSessionDlg.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\LoginDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\SetupDlg.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\Voice2BuddyMFC.h +# End Source File +# Begin Source File + +SOURCE=.\Voice2BuddyMFCDlg.h +# End Source File +# Begin Source File + +SOURCE=.\VoiceSessionDlg.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\gamespyl.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\logo270x83.bmp +# End Source File +# Begin Source File + +SOURCE=".\res\microsoft-microphone.bmp" +# End Source File +# Begin Source File + +SOURCE=".\res\microsoft-speaker.bmp" +# End Source File +# Begin Source File + +SOURCE=.\res\speaking.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\speaking2.bmp +# End Source File +# Begin Source File + +SOURCE=.\res\Voice2BuddyMFC.ico +# End Source File +# Begin Source File + +SOURCE=.\res\Voice2BuddyMFC.rc2 +# End Source File +# End Group +# Begin Group "VoiceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gv.h +# End Source File +# Begin Source File + +SOURCE=..\gvCodec.c +# End Source File +# Begin Source File + +SOURCE=..\gvCodec.h +# End Source File +# Begin Source File + +SOURCE=..\gvCustomDevice.c +# End Source File +# Begin Source File + +SOURCE=..\gvCustomDevice.h +# End Source File +# Begin Source File + +SOURCE=..\gvDevice.c +# End Source File +# Begin Source File + +SOURCE=..\gvDevice.h +# End Source File +# Begin Source File + +SOURCE=..\gvDirectSound.c +# ADD CPP /W3 +# SUBTRACT CPP /WX +# End Source File +# Begin Source File + +SOURCE=..\gvDirectSound.h +# End Source File +# Begin Source File + +SOURCE=..\gvFrame.c +# End Source File +# Begin Source File + +SOURCE=..\gvFrame.h +# End Source File +# Begin Source File + +SOURCE=..\gvMain.c +# End Source File +# Begin Source File + +SOURCE=..\gvMain.h +# End Source File +# Begin Source File + +SOURCE=..\gvSource.c +# End Source File +# Begin Source File + +SOURCE=..\gvSource.h +# End Source File +# Begin Source File + +SOURCE=..\gvSpeex.c +# End Source File +# Begin Source File + +SOURCE=..\gvSpeex.h +# End Source File +# Begin Source File + +SOURCE=..\gvUtil.c +# End Source File +# Begin Source File + +SOURCE=..\gvUtil.h +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\GP\gp.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpi.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuddy.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiCallback.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiConnect.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiInfo.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiOperation.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiPeer.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiProfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiSearch.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiTransfer.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUtility.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUtility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.h new file mode 100644 index 00000000000..d81962223da --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.h @@ -0,0 +1,49 @@ +// Voice2BuddyMFC.h : main header file for the VOICE2BUDDYMFC application +// + +#if !defined(AFX_VOICE2BUDDYMFC_H__B124CD13_D911_4447_AF83_E1503E9147BF__INCLUDED_) +#define AFX_VOICE2BUDDYMFC_H__B124CD13_D911_4447_AF83_E1503E9147BF__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCApp: +// See Voice2BuddyMFC.cpp for the implementation of this class +// + +class CVoice2BuddyMFCApp : public CWinApp +{ +public: + CVoice2BuddyMFCApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CVoice2BuddyMFCApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CVoice2BuddyMFCApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_VOICE2BUDDYMFC_H__B124CD13_D911_4447_AF83_E1503E9147BF__INCLUDED_) diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.rc b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.rc new file mode 100644 index 00000000000..9feae43566e --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.rc @@ -0,0 +1,300 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\Voice2BuddyMFC.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\Voice2BuddyMFC.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Voice2BuddyMFC" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "Voice2BuddyMFC Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2004",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP +END + +IDD_VOICE2BUDDYMFC_DIALOG DIALOGEX 0, 0, 150, 126 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Voice2 Buddy MFC" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Exit",IDCANCEL,7,105,50,14 + PUSHBUTTON "Setup",ID_SETUP,7,78,50,14,WS_DISABLED + PUSHBUTTON "Voice Chat",ID_VOICECHAT,7,59,50,14,WS_DISABLED + LISTBOX IDC_BUDDYLIST,64,7,79,112,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | + WS_TABSTOP + LTEXT "Select a buddy to chat with --->",IDC_STATIC,7,7,50,46 +END + +IDD_LOGIN DIALOG DISCARDABLE 0, 0, 143, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Login" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,75,74,50,14 + PUSHBUTTON "Cancel",IDCANCEL,18,74,50,14 + EDITTEXT IDC_EMAIL,48,7,88,14,ES_AUTOHSCROLL + EDITTEXT IDC_NICKNAME,48,28,88,14,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,48,49,88,14,ES_PASSWORD | ES_AUTOHSCROLL + RTEXT "Email:",IDC_STATIC,7,7,36,14,SS_CENTERIMAGE + RTEXT "Nickname:",IDC_STATIC,7,28,36,14,SS_CENTERIMAGE + RTEXT "Password:",IDC_STATIC,7,49,36,14,SS_CENTERIMAGE +END + +IDD_SESSION DIALOG DISCARDABLE 0, 0, 121, 79 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Session" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Exit",IDCANCEL,35,58,50,14 + CTEXT "",IDC_DISPLAYTEXT,7,7,107,23 + CONTROL 146,IDC_SPEAKING1,"Static",SS_BITMAP | SS_SUNKEN | NOT + WS_VISIBLE,25,36,28,14 + CONTROL 134,IDC_SPEAKING2,"Static",SS_BITMAP | SS_SUNKEN | NOT + WS_VISIBLE,68,36,28,14 +END + +IDD_SETUPDIALOG DIALOG DISCARDABLE 0, 0, 197, 207 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Voice Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,73,186,50,14 + COMBOBOX IDC_PLAYBACKCOMBO,43,82,136,105,CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_CAPTURECOMBO,43,116,136,96,CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Capture Device:",IDC_STATIC,43,103,98,12 + LTEXT "Playback Device:",IDC_STATIC,43,68,117,12 + CONTROL 136,IDC_SPEAKERBITMAP,"Static",SS_BITMAP,13,74,21,20 + CONTROL 135,IDC_MICROPHONEBITMAP,"Static",SS_BITMAP,13,106,21,20 + GROUPBOX "",IDC_STATIC,7,58,183,82,BS_CENTER + CONTROL "Slider1",IDC_ACTIVATELEVEL,"msctls_trackbar32",TBS_BOTH | + TBS_NOTICKS | WS_TABSTOP,48,146,105,12 + CONTROL "Progress1",IDC_VOICELEVEL,"msctls_progress32",WS_BORDER, + 51,160,97,11 + GROUPBOX "",IDC_STATIC,7,138,183,40 + LTEXT "Activate",IDC_STATIC,155,147,27,10 + LTEXT "Volume",IDC_STATIC,155,161,27,10 + CONTROL 146,IDC_ISSPEAKING,"Static",SS_BITMAP,16,153,27,12 + CONTROL 142,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,7,7,185,52 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "Voice2BuddyMFC MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "Voice2BuddyMFC\0" + VALUE "LegalCopyright", "Copyright (C) 2004\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "Voice2BuddyMFC.EXE\0" + VALUE "ProductName", "Voice2BuddyMFC Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_VOICE2BUDDYMFC_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 143 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + END + + IDD_LOGIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 136 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + IDD_SESSION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 114 + TOPMARGIN, 7 + BOTTOMMARGIN, 72 + END + + IDD_SETUPDIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 190 + TOPMARGIN, 7 + BOTTOMMARGIN, 200 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_SPEAKER BITMAP DISCARDABLE "res\\microsoft-speaker.bmp" +IDB_MICROPHONE BITMAP DISCARDABLE "res\\microsoft-microphone.bmp" +IDB_GAMESPYLOGO BITMAP DISCARDABLE "res\\logo270x83.bmp" +IDB_SPEAKING BITMAP DISCARDABLE "res\\speaking.bmp" +IDB_GAMESPYLOGO1 BITMAP DISCARDABLE "res\\gamespyl.bmp" +IDB_SPEAKING2 BITMAP DISCARDABLE "res\\speaking2.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ABOUTBOX "&About Voice2BuddyMFC..." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\Voice2BuddyMFC.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.vcproj b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.vcproj new file mode 100644 index 00000000000..9d673a5190f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.vcproj @@ -0,0 +1,2107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.vcproj.vspscc b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFCDlg.cpp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFCDlg.cpp new file mode 100644 index 00000000000..54281b3cf6d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFCDlg.cpp @@ -0,0 +1,600 @@ +// Voice2BuddyMFCDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "Voice2BuddyMFC.h" +#include "Voice2BuddyMFCDlg.h" + +#include "LoginDlg.h" +#include "SetupDlg.h" +#include "VoiceSessionDlg.h" + + +#include "../../common/gsAvailable.h" +#include "../../voice2/gv.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +enum V2BuddyMessage +{ + V2B_MSG_DOSETUP, + V2B_MSG_DOLOGIN, + V2B_MSG_DOVOICECHAT, +}; + +#define THINK_TIMER_ID 100 +#define THINK_TIMER_DELAY 10 +#define GAME_NAME "gmtest" +#define NAMESPACE_GAMESPY_SHARED 0 +#define PRODUCTID_GMTEST 1 // can't use 0! + +#define V2B_GP_LOCATION "Voice2BuddyMFC" +#define V2B_GP_STATUS_IDLE "Idle" // free to invite +#define V2B_GP_STATUS_CHATTING "Chatting" // actively chatting +#define V2B_GP_INVITE_DECLINED "Voice invitation declined." +#define V2B_GP_INVITE_ACCEPTED "Voice invitation accepted." + +// Utility to check buddy status and make sure they're running V2B +BOOL IsBuddyUsingV2B(GPConnection* theConnection, GPProfile theProfileId, GPBuddyStatus* theStatus); + + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// Dialog Data + //{{AFX_DATA(CAboutDlg) + enum { IDD = IDD_ABOUTBOX }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CAboutDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCDlg dialog + +CVoice2BuddyMFCDlg::CVoice2BuddyMFCDlg(CWnd* pParent /*=NULL*/) + : CDialog(CVoice2BuddyMFCDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CVoice2BuddyMFCDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CVoice2BuddyMFCDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CVoice2BuddyMFCDlg) + DDX_Control(pDX, ID_SETUP, m_SetupButton); + DDX_Control(pDX, ID_VOICECHAT, m_VoiceChatButton); + DDX_Control(pDX, IDC_BUDDYLIST, m_BuddyList); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CVoice2BuddyMFCDlg, CDialog) + //{{AFX_MSG_MAP(CVoice2BuddyMFCDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(ID_SETUP, OnSetup) + ON_BN_CLICKED(ID_VOICECHAT, OnVoiceChat) + ON_BN_CLICKED(IDCANCEL, OnExit) + ON_WM_TIMER() + ON_WM_DESTROY() + ON_LBN_SELCHANGE(IDC_BUDDYLIST, OnSelchangeBuddylist) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCDlg message handlers + +BOOL CVoice2BuddyMFCDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Add "About..." menu item to system menu. + + // IDM_ABOUTBOX must be in the system command range. + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // We're not connected yet + m_GP = NULL; + m_Initialized = FALSE; + m_Connected = FALSE; + m_InvitedPlayer = 0; + m_MyProfileId = 0; + + // Start network + SocketStartUp(); + + // Init voice SDK (pre-init, do not start devices yet) + GVBool aResult = gvStartup(m_hWnd); + if (aResult != GVTrue) + { + MessageBox("Failed on gvStartup!"); + PostQuitMessage(0); + } + + // Set the codec (this sample hard codes it) + gvSetSampleRate(GVRate_16KHz); + aResult = gvSetCodec(GVCodecSuperHighQuality); + if (aResult != GVTrue) + { + MessageBox("Failed on gvSetCodec!"); + PostQuitMessage(0); + } + + // Disable the "voice chat" button until a buddy is selected + m_VoiceChatButton.EnableWindow(FALSE); + + // Clear the setup info + memset(&m_SetupInfo, 0, sizeof(m_SetupInfo)); + + // Show the setup dialog + PostMessage(WM_USER+1, V2B_MSG_DOSETUP, 0); + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CVoice2BuddyMFCDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CVoice2BuddyMFCDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CVoice2BuddyMFCDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CVoice2BuddyMFCDlg::OnSetup() +{ + // Setup and calibrate the voice hardware + CSetupDlg aSetupDlg; + aSetupDlg.m_SetupInfo = &m_SetupInfo; + aSetupDlg.DoModal(); +} + +void CVoice2BuddyMFCDlg::OnVoiceChat() +{ + // Get the selected buddy + int selIndex = m_BuddyList.GetCurSel(); + if (selIndex == -1) + return; + + // Get the buddy profile + GPProfile aProfile = m_BuddyList.GetItemData(selIndex); + + // Make sure the buddy is using V2B + GPBuddyStatus aStatus; + if (FALSE == IsBuddyUsingV2B(&m_GP, aProfile, &aStatus)) + { + MessageBox("Buddy is not running V2B."); + return; + } + + // Make sure this buddy isn't chatting already + if (strcmp(V2B_GP_STATUS_CHATTING, aStatus.locationString) == 0) + { + MessageBox("Buddy is currently involved in a voice chat."); + return; + } + + // Invite the buddy to voice chat + gpInvitePlayer(&m_GP, aProfile, PRODUCTID_GMTEST, NULL); + m_InvitedPlayer = aProfile; // remember who we invited +} + +void CVoice2BuddyMFCDlg::OnExit() +{ + // TODO: Add your control notification handler code here + CDialog::OnCancel(); +} + +LRESULT CVoice2BuddyMFCDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == (WM_USER+1)) + { + // Process custom message + switch(wParam) + { + case V2B_MSG_DOSETUP: + { + // Show the setup dialog + OnSetup(); + + // Pop up the login dialog + PostMessage(WM_USER+1, V2B_MSG_DOLOGIN, 0); + + // Start the app timer + SetTimer(THINK_TIMER_ID, THINK_TIMER_DELAY, NULL); + return 0; + } + case V2B_MSG_DOLOGIN: + { + // Show the login dialog + CLoginDlg aDlg; + int result = aDlg.DoModal(); + if (result == IDCANCEL) + PostQuitMessage(0); + else + DoLogin(aDlg.m_Email, aDlg.m_Nickname, aDlg.m_Password); + return 0; + } + case V2B_MSG_DOVOICECHAT: + { + // Create the voice session dialog + CVoiceSessionDlg aVoiceSessionDlg; + aVoiceSessionDlg.m_NNCookie = lParam; + aVoiceSessionDlg.m_SetupInfo = m_SetupInfo; + + // We use the profileId of the host as the NNCookie + // now, check to see if we're the host + if (m_MyProfileId == aVoiceSessionDlg.m_NNCookie) + aVoiceSessionDlg.m_IsHost = TRUE; + else + aVoiceSessionDlg.m_IsHost = FALSE; + + // Run the dialog + aVoiceSessionDlg.DoModal(); + return 0; + } + }; + } // end custom messages + return CDialog::WindowProc(message, wParam, lParam); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Utility to check if a buddy is using this app +BOOL IsBuddyUsingV2B(GPConnection* theConnection, GPProfile theProfileId, GPBuddyStatus* theStatus) +{ + GPBuddyStatus aTempStatus; + GPBuddyStatus* aStatus; + if (theStatus != NULL) + aStatus = theStatus; // store location in return value + else + aStatus = &aTempStatus; // store location in temp + + // get the internal buddy index + int aBuddyIndex; + GPResult aResult = gpGetBuddyIndex(theConnection, theProfileId, &aBuddyIndex); + if (aResult != GP_NO_ERROR) + return FALSE; // not a buddy + + // Get the buddy status + aResult = gpGetBuddyStatus(theConnection, aBuddyIndex, aStatus); + if (aResult != GP_NO_ERROR) + return FALSE; // couldn't get status + + // Is the buddy using V2B? + if (strcmp(V2B_GP_LOCATION, aStatus->locationString) != 0) + return FALSE; // no using V2B + + return TRUE; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void OnGPError(GPConnection* theConnection, GPErrorArg* theArg, void* theParam) +{ + CVoice2BuddyMFCDlg* aDialog = (CVoice2BuddyMFCDlg*)theParam; + + char buf[1024]; + sprintf(buf, "GP ERROR: %s", theArg->errorString); + aDialog->MessageBox(buf); + + if (theArg->fatal == GP_FATAL) + aDialog->m_Connected = FALSE; + GSI_UNUSED(theConnection); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void OnGPBuddyInfo(GPConnection* theConnection, GPGetInfoResponseArg* theArg, void* theParam) +{ + CVoice2BuddyMFCDlg* aDialog = (CVoice2BuddyMFCDlg*)theParam; + + // Make sure this name is in the list + int anIndex = aDialog->m_BuddyList.FindString(0, theArg->nick); + if (anIndex == -1) + { + int anIndex = aDialog->m_BuddyList.AddString(theArg->nick); + if (anIndex != -1) + aDialog->m_BuddyList.SetItemData(anIndex, theArg->profile); + } + + GSI_UNUSED(theConnection); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void OnGPBuddyStatus(GPConnection* theConnection, GPRecvBuddyStatusArg* theArg, void* theParam) +{ + CVoice2BuddyMFCDlg* aDialog = (CVoice2BuddyMFCDlg*)theParam; + + // Retrieve info for the buddy (nickname etc.) + // will return with file cache information, if available + gpGetInfo(theConnection, theArg->profile, GP_CHECK_CACHE, GP_NON_BLOCKING, (GPCallback)OnGPBuddyInfo, theParam); + GSI_UNUSED(aDialog); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void OnGPBuddyMessage(GPConnection* theConnection, GPRecvBuddyMessageArg* theArg, void* theParam) +{ + CVoice2BuddyMFCDlg* aDialog = (CVoice2BuddyMFCDlg*)theParam; + + // Ignore messages that are not from V2B + if (FALSE == IsBuddyUsingV2B(theConnection, theArg->profile, NULL)) + return; + + // If this wasn't the guy we invited, ignore it + if (theArg->profile != aDialog->m_InvitedPlayer) + return; + + // Is this an invite accept? + if (strcmp(V2B_GP_INVITE_ACCEPTED, theArg->message)==0) + aDialog->PostMessage(WM_USER+1, V2B_MSG_DOVOICECHAT, aDialog->m_MyProfileId); + + // Is this an invite decline? + if (strcmp(V2B_GP_INVITE_DECLINED, theArg->message)==0) + aDialog->MessageBox(theArg->message); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void OnGPInvite(GPConnection* theConnection, GPRecvGameInviteArg* theArg, void* theParam) +{ + CVoice2BuddyMFCDlg* aDialog = (CVoice2BuddyMFCDlg*)theParam; + + // Make sure the invite is from V2B + if (FALSE == IsBuddyUsingV2B(theConnection, theArg->profile, NULL)) + return; + + // Find the nickname of the buddy, for display + // (may not be the selected buddy) + CString aBuddyName = ""; + int anIndex = 0; + while(anIndex < aDialog->m_BuddyList.GetCount()) + { + // If this is the buddy, store off the name + if (aDialog->m_BuddyList.GetItemData(anIndex) == (unsigned int)theArg->profile) + { + aDialog->m_BuddyList.GetText(anIndex, aBuddyName); + break; + } + anIndex++; + } + if (aBuddyName.IsEmpty()) + return; // buddy not found, ignore the invite + + // Ask the user if they want to accept + char buf[255]; + sprintf(buf, "%s has invited you to voice chat. Accept?", (LPCSTR)aBuddyName); + int aDialogResult = aDialog->MessageBox(buf, "Voice Chat", MB_YESNO); + if (aDialogResult == IDYES) + { + // begin voice session + gpSendBuddyMessage(&aDialog->m_GP, theArg->profile, V2B_GP_INVITE_ACCEPTED); + aDialog->PostMessage(WM_USER+1, V2B_MSG_DOVOICECHAT, theArg->profile); + } + else + { + // send rejection + gpSendBuddyMessage(&aDialog->m_GP, theArg->profile, V2B_GP_INVITE_DECLINED); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void OnGPConnect(GPConnection* theConnection, GPConnectResponseArg* theArg, void* theParam) +{ + CVoice2BuddyMFCDlg* aDialog = (CVoice2BuddyMFCDlg*)theParam; + + if (theArg->result == GP_NO_ERROR) + { + aDialog->m_Connected = TRUE; + aDialog->m_SetupButton.EnableWindow(TRUE); + aDialog->m_MyProfileId = theArg->profile; + } + else + { + aDialog->MessageBox("Failed to connect!"); + PostQuitMessage(0); + } + GSI_UNUSED(theConnection); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void CVoice2BuddyMFCDlg::DoLogin(const CString& theEmail, const CString& theNickname, const CString& thePassword) +{ + // Begin the availability check + GSIACResult aResult = GSIACWaiting; + GSIStartAvailableCheck(GAME_NAME); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + Sleep(20); + } + + // Initialize the Presence SDK + GPResult result = gpInitialize(&m_GP, PRODUCTID_GMTEST, NAMESPACE_GAMESPY_SHARED, GP_PARTNERID_GAMESPY); + if (result != GP_NO_ERROR) + { + MessageBox("Failed on gpInitialize\r\n"); + PostQuitMessage(0); + } + + gpSetCallback(&m_GP, GP_ERROR, (GPCallback)OnGPError, this); + gpSetCallback(&m_GP, GP_RECV_BUDDY_STATUS, (GPCallback)OnGPBuddyStatus, this); + gpSetCallback(&m_GP, GP_RECV_GAME_INVITE, (GPCallback)OnGPInvite, this); + gpSetCallback(&m_GP, GP_RECV_BUDDY_MESSAGE, (GPCallback)OnGPBuddyMessage,this); + m_Initialized = TRUE; + + // Connect to the presence server (goes to callback even though it's blocking) + gpConnect(&m_GP, theNickname, theEmail, thePassword, GP_NO_FIREWALL, GP_BLOCKING, (GPCallback)OnGPConnect, this); + + // Set the think timer if we connected + // (m_Connected is set from the callback function above) + if (m_Connected) + SetTimer(THINK_TIMER_ID, THINK_TIMER_DELAY, NULL); + + // Set our location + gpSetStatus(&m_GP, GP_ONLINE, V2B_GP_STATUS_IDLE, V2B_GP_LOCATION); +} + +void CVoice2BuddyMFCDlg::OnTimer(UINT nIDEvent) +{ + // Win32 timers can be called concurrently by the OS. + // (you can get a second timer callback before the first finishes!) + // CRITICAL_SECTION will not prevent this as Win32 allows concurrent access + static bool inTimer = false; + if (inTimer) + return; + + // Prevent windows from entering the timer again + inTimer = true; + + if (m_Connected) + gpProcess(&m_GP); + + // Allow windows to enter the timer again + inTimer = false; + + CDialog::OnTimer(nIDEvent); +} + +void CVoice2BuddyMFCDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + // Kill the think timer + KillTimer(THINK_TIMER_ID); + + // Disconnect from GP + if (m_Connected) + gpDisconnect(&m_GP); + + // Destruct GP + if (m_Initialized) + gpDestroy(&m_GP); + + gvCleanup(); +} + +void CVoice2BuddyMFCDlg::OnSelchangeBuddylist() +{ + int aSel = m_BuddyList.GetCurSel(); + if (aSel == -1) + m_VoiceChatButton.EnableWindow(FALSE); + else + m_VoiceChatButton.EnableWindow(TRUE); +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFCDlg.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFCDlg.h new file mode 100644 index 00000000000..fdd4d25b2a6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFCDlg.h @@ -0,0 +1,74 @@ +// Voice2BuddyMFCDlg.h : header file +// + +#if !defined(AFX_VOICE2BUDDYMFCDLG_H__F4BA3DE6_2C65_4B7D_A1BC_A9C3BAF53DEE__INCLUDED_) +#define AFX_VOICE2BUDDYMFCDLG_H__F4BA3DE6_2C65_4B7D_A1BC_A9C3BAF53DEE__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CVoice2BuddyMFCDlg dialog +#include "../../gp/gp.h" +#include "SetupDlg.h" + +class CVoice2BuddyMFCDlg : public CDialog +{ + // Non MFC +public: + GPConnection m_GP; + BOOL m_Initialized; + BOOL m_Connected; + unsigned int m_NNCookie; + GPProfile m_InvitedPlayer; // the last player we invited + GPProfile m_MyProfileId; // the local player's profile id + + VoiceSetupInfo m_SetupInfo; + + void DoLogin(const CString& theEmail, const CString& theNickname, const CString& thePassword); + + +// Construction +public: + CVoice2BuddyMFCDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CVoice2BuddyMFCDlg) + enum { IDD = IDD_VOICE2BUDDYMFC_DIALOG }; + CButton m_SetupButton; + CButton m_VoiceChatButton; + CListBox m_BuddyList; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CVoice2BuddyMFCDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CVoice2BuddyMFCDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnSetup(); + afx_msg void OnVoiceChat(); + afx_msg void OnExit(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnDestroy(); + afx_msg void OnSelchangeBuddylist(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_VOICE2BUDDYMFCDLG_H__F4BA3DE6_2C65_4B7D_A1BC_A9C3BAF53DEE__INCLUDED_) diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC_vs2005.vcproj b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC_vs2005.vcproj new file mode 100644 index 00000000000..958eee32948 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC_vs2005.vcproj @@ -0,0 +1,2194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/Voice2BuddyMFC_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/VoiceSessionDlg.cpp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/VoiceSessionDlg.cpp new file mode 100644 index 00000000000..cdbcccc6f9b --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/VoiceSessionDlg.cpp @@ -0,0 +1,397 @@ +// VoiceSessionDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "Voice2BuddyMFC.h" +#include "VoiceSessionDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define THINK_TIMER_ID 100+2 +#define THINK_TIMER_DELAY 20 + + +///////////////////////////////////////////////////////////////////////////// +// CVoiceSessionDlg dialog +struct VoicePacket +{ + GVFrameStamp mFrameStamp; + int mDataLength; + GVByte mBuffer[1024]; // most likely get < 256 bytes +}; +const int gVoicePacketHeaderSize = sizeof(GVFrameStamp)+sizeof(int); + + +CVoiceSessionDlg::CVoiceSessionDlg(CWnd* pParent /*=NULL*/) + : CDialog(CVoiceSessionDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CVoiceSessionDlg) + m_DisplayText = _T(""); + //}}AFX_DATA_INIT +} + + +void CVoiceSessionDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CVoiceSessionDlg) + DDX_Control(pDX, IDC_SPEAKING2, m_RemoteSpeaking); + DDX_Control(pDX, IDC_SPEAKING1, m_LocalSpeaking); + DDX_Text(pDX, IDC_DISPLAYTEXT, m_DisplayText); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CVoiceSessionDlg, CDialog) + //{{AFX_MSG_MAP(CVoiceSessionDlg) + ON_WM_TIMER() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CVoiceSessionDlg message handlers +void CVoiceSessionDlg::OnTimer(UINT nIDEvent) +{ + // Win32 timers can be called concurrently by the OS. + // (you can get a second timer callback before the first finishes!) + // CRITICAL_SECTION will not prevent this as Win32 allows concurrent access + static bool inTimer = false; + if (inTimer) + return; + + // Prevent windows from entering the timer again + inTimer = true; + + // Process voice data + gvThink(); + + // Process NN + NNThink(); + + // Process network traffic + if (m_Socket) + gt2Think(m_Socket); + + // If we're not connected we don't need to do the rest + if (!m_Connection || (gt2GetConnectionState(m_Connection) != GT2Connected)) + { + inTimer = false; + return; + } + + // Show a bitmap if the sources are speaking + static bool wasLocalSpeaking = false; + static bool wasRemoteSpeaking = false; + + bool isLocalSpeaking = (GVTrue == gvIsSourceTalking(m_SetupInfo.m_PlaybackDevice, 0)); + bool isRemoteSpeaking = (GVTrue == gvIsSourceTalking(m_SetupInfo.m_PlaybackDevice, m_RemoteAddr)); + + if (isLocalSpeaking != wasLocalSpeaking) + { + wasLocalSpeaking = isLocalSpeaking; + m_LocalSpeaking.ShowWindow(isLocalSpeaking ? SW_SHOW:SW_HIDE); + } + if (isRemoteSpeaking != wasRemoteSpeaking) + { + wasRemoteSpeaking = isRemoteSpeaking; + m_RemoteSpeaking.ShowWindow(isRemoteSpeaking ? SW_SHOW:SW_HIDE); + } + + // Check for microphone activity + int aBytesAvailable = gvGetAvailableCaptureBytes(m_SetupInfo.m_CaptureDevice); + if (aBytesAvailable > 0) + { + // Voice packet struct, so we don't have to do a buffer copy + // We just record the data directly into the packet + // (the actual packet may be smaller + + VoicePacket aVoicePacket; + memset(&aVoicePacket, 0, sizeof(aVoicePacket)); + aVoicePacket.mDataLength = sizeof(aVoicePacket.mBuffer); + + GVScalar aVolume; // this doesn't need to be sent + + // Read in a voice packet + GVBool gotPacket = gvCapturePacket(m_SetupInfo.m_CaptureDevice, aVoicePacket.mBuffer, &aVoicePacket.mDataLength, &aVoicePacket.mFrameStamp, &aVolume); + if (gotPacket == GVTrue) + { + // Playback for local echo + //gvPlayPacket(m_SetupInfo.m_PlaybackDevice, aVoicePacket.mBuffer, aVoicePacket.mDataLength, 0, aVoicePacket.mFrameStamp); + + // Contruct a message for the buddy + int aTotalPacketSize = gVoicePacketHeaderSize + aVoicePacket.mDataLength; + gt2Send(m_Connection, (GT2Byte*)&aVoicePacket, aTotalPacketSize, GT2False); + } + } + + // Allow new timers to be triggered + inTimer = false; + + CDialog::OnTimer(nIDEvent); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Callbacks for GT2 +void GT2SocketErrorCallback(GT2Socket theSocket) +{ + CVoiceSessionDlg* aDialog = (CVoiceSessionDlg*)gt2GetSocketData(theSocket); + aDialog->m_DisplayText = "GT2SocketErrorCallback. Connection Closed"; + aDialog->UpdateData(FALSE); +} + +void GT2ConnectedCallback(GT2Connection theConnection, GT2Result theResult, unsigned char* theMessage, int theLength) +{ + GT2Socket aSocket = gt2GetConnectionSocket(theConnection); + CVoiceSessionDlg* aDialog = (CVoiceSessionDlg*)gt2GetSocketData(aSocket); + + // Was there an error? + if (theResult != GT2Success) + { + aDialog->MessageBox("GT2ConnectedCallback returned failure!"); + aDialog->PostMessage(WM_CLOSE, 0, 0); + } + else + { + // Remember our connection + aDialog->m_Connection = theConnection; + aDialog->m_DisplayText = "Session established.\r\n(You may begin speaking)"; + aDialog->UpdateData(FALSE); + + // Start the voice devices + if (aDialog->m_SetupInfo.m_CaptureDevice != NULL) + gvStartDevice(aDialog->m_SetupInfo.m_CaptureDevice, GV_CAPTURE); + if (aDialog->m_SetupInfo.m_PlaybackDevice != NULL) + gvStartDevice(aDialog->m_SetupInfo.m_PlaybackDevice, GV_PLAYBACK); + } + GSI_UNUSED(theMessage); + GSI_UNUSED(theLength); + GSI_UNUSED(theResult); +} + +void GT2ReceivedCallback(GT2Connection theConnection, unsigned char* theBuffer, int theLength, int wasReliable) +{ + // Get the ptr to the dialog + CVoiceSessionDlg* aDlg = (CVoiceSessionDlg*)gt2GetSocketData(gt2GetConnectionSocket(theConnection)); + + // Cast to a voice packet so we can extract data + VoicePacket* aVoicePacket = (VoicePacket*)theBuffer; + + // Sanity check the packet + assert(theLength >= gVoicePacketHeaderSize); + assert(theLength == (gVoicePacketHeaderSize + aVoicePacket->mDataLength)); + + // Play the voice data + GVSource aSource = gt2GetRemoteIP(theConnection); + gvPlayPacket(aDlg->m_SetupInfo.m_PlaybackDevice, aVoicePacket->mBuffer, aVoicePacket->mDataLength, aSource, aVoicePacket->mFrameStamp, 0); + OutputDebugString("Playing voice packet\r\n"); + GSI_UNUSED(wasReliable); + GSI_UNUSED(theLength); +} + +GT2Bool GT2UnrecognizedMessageCallback(GT2Socket theSocket, unsigned int theIp, unsigned short thePort, GT2Byte* theData, int theLength) +{ + static unsigned char aNNHeader[NATNEG_MAGIC_LEN] = + { NN_MAGIC_0, NN_MAGIC_1, NN_MAGIC_2, + NN_MAGIC_3, NN_MAGIC_4, NN_MAGIC_5 }; + + // Bail out if it's too short + if (theLength < NATNEG_MAGIC_LEN) + { + OutputDebugString("\tDiscarded message (too small)\r\n"); + return GT2False; + } + + // Check if it matches the NN Magic bytes + if (0==memcmp(theData, aNNHeader,NATNEG_MAGIC_LEN)) + { + // Hand off to the NN SDK + sockaddr_in anAddr; + anAddr.sin_family = AF_INET; + anAddr.sin_port = htons(thePort); + anAddr.sin_addr.s_addr = theIp; + NNProcessData((char*)theData, theLength, &anAddr); + OutputDebugString("\tProcessed NN message\r\n"); + return GT2True; + } + + // Not handled by us + OutputDebugString("\tDiscarded message (not recognized)\r\n"); + GSI_UNUSED(theSocket); + return GT2False; +} + +void GT2ClosedCallback(GT2Connection theConnection, GT2CloseReason theReason) +{ + GT2Socket aSocket = gt2GetConnectionSocket(theConnection); + CVoiceSessionDlg* aDialog = (CVoiceSessionDlg*)gt2GetSocketData(aSocket); + + aDialog->m_DisplayText = "Connection closed. (GT2ClosedCallback)"; + aDialog->UpdateData(FALSE); + GSI_UNUSED(theReason); +} + +void GT2ConnectAttemptCallback(GT2Socket theSocket, GT2Connection theConnection, unsigned int theIp, unsigned short thePort, int theLatency, GT2Byte * theMessage, int theLength) +{ + CVoiceSessionDlg* aDialog = (CVoiceSessionDlg*)gt2GetSocketData(theSocket); + + // Set the callbacks so we can receive data + GT2ConnectionCallbacks aCallbackList; + aCallbackList.received = GT2ReceivedCallback; + aCallbackList.connected = GT2ConnectedCallback; // we're connected + aCallbackList.closed = GT2ClosedCallback; + + // Accept the connection + aDialog->m_Connection = theConnection; + gt2Accept(theConnection, &aCallbackList); + + // Store off the remote addr + aDialog->m_RemoteAddr = gt2GetRemoteIP(theConnection); + + // Start the voice devices + if (aDialog->m_SetupInfo.m_CaptureDevice != NULL) + gvStartDevice(aDialog->m_SetupInfo.m_CaptureDevice, GV_CAPTURE); + if (aDialog->m_SetupInfo.m_PlaybackDevice != NULL) + gvStartDevice(aDialog->m_SetupInfo.m_PlaybackDevice, GV_PLAYBACK); + + aDialog->m_DisplayText = "Session established.\r\n(You may begin speaking)"; + aDialog->UpdateData(FALSE); + GSI_UNUSED(theMessage); + GSI_UNUSED(theLength); + GSI_UNUSED(theIp); + GSI_UNUSED(thePort); + GSI_UNUSED(theLatency); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Callbacks for the NN SDK +void NNProgressCallback(NegotiateState theState, void* theParam) +{ + CVoiceSessionDlg* aDialog = (CVoiceSessionDlg*)theParam; + aDialog->m_DisplayText.Format("NNProgressCallback: %d\r\n", theState); + aDialog->UpdateData(FALSE); +} + +void NNCompletedCallback(NegotiateResult theResult, SOCKET theSocket, sockaddr_in* theAddr, void* theParam) +{ + CVoiceSessionDlg* aDialog = (CVoiceSessionDlg*)theParam; + + // Check the result, are we connected at the socket layer? + if (theResult == nr_success) + { + // Convert sockaddr_in to a string + CString aAddrString; + aAddrString.Format("%s:%d", inet_ntoa(theAddr->sin_addr), ntohs(theAddr->sin_port)); + aDialog->m_DisplayText = "NN Successful"; + + // If hosting, listen for the client... + if (aDialog->m_IsHost) + { + gt2Listen(aDialog->m_Socket, GT2ConnectAttemptCallback); + aDialog->m_DisplayText = "Listening for GT2 connection"; + } + // ...otherwise connect to the host + else + { + // Store off the remote addr + aDialog->m_RemoteAddr = theAddr->sin_addr.s_addr; + + // Set our gt2 callbacks, so we can receive messages + GT2ConnectionCallbacks aCallbackList; + aCallbackList.connected = GT2ConnectedCallback; // we're connected + aCallbackList.received = GT2ReceivedCallback; // we've received data + aCallbackList.closed = GT2ClosedCallback; + + int aTimeout = 0; + GT2Result aResult = gt2Connect(aDialog->m_Socket, &aDialog->m_Connection, aAddrString, NULL, 0, aTimeout, &aCallbackList, GT2False); + if (aResult != GT2Success) + { + // Error, bail out + aDialog->m_DisplayText = "Failed on gt2Connect"; + //aDialog->PostMessage(WM_CLOSE, 0, 0); + } + aDialog->m_DisplayText = "Connecting with GT2"; + } + } + else + { + aDialog->m_DisplayText = "Failed to negotiate a connection."; + } + + // Draw the new display text + aDialog->UpdateData(FALSE); + GSI_UNUSED(theSocket); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// MFC Event handlers +BOOL CVoiceSessionDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Init some variables + m_Socket = NULL; + m_Connection = NULL; + + // Set the gt2Callbacks + // Create our gt2 socket (we'll need it for NN) + // We use NULL for the local addr because we don't care which + // port we're bound to. We could specify one if we wanted by + // using ":5000" as the addr, for example + GT2Result aResult = gt2CreateSocket(&m_Socket, NULL, 0, 0, GT2SocketErrorCallback); + if (aResult != GT2Success) + { + // We're hosed, bail out by closing the dialog + MessageBox("Failed on gt2CreateSocket"); + PostMessage(WM_CLOSE, 0, 0); + return TRUE; + } + + // Set the socket data (the user param) to our dialog + gt2SetSocketData(m_Socket, this); + gt2SetUnrecognizedMessageCallback(m_Socket, GT2UnrecognizedMessageCallback); + + // Begin nat negotiation (use the gt2 socket) + // m_NNCookie and m_IsHost are set before the dialog is run + SOCKET aWinSocket = gt2GetSocketSOCKET(m_Socket); + NNBeginNegotiationWithSocket(aWinSocket, m_NNCookie, m_IsHost, NNProgressCallback, NNCompletedCallback, this); + + m_DisplayText = "Establishing connection..."; + UpdateData(FALSE); + + // Set the think timer + SetTimer(THINK_TIMER_ID, THINK_TIMER_DELAY, NULL); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +BOOL CVoiceSessionDlg::DestroyWindow() +{ + // Clean up NN SDK + NNFreeNegotiateList(); + + // Close the gt2 socket (will close the connection if connected) + if (m_Socket) + gt2CloseSocket(m_Socket); + + // Stop the voice devices + if (m_SetupInfo.m_CaptureDevice != NULL) + gvStopDevice(m_SetupInfo.m_CaptureDevice, GV_CAPTURE); + if (m_SetupInfo.m_PlaybackDevice != NULL) + gvStopDevice(m_SetupInfo.m_PlaybackDevice, GV_PLAYBACK); + + // Kill the timer + KillTimer(THINK_TIMER_ID); + + + return CDialog::DestroyWindow(); +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/VoiceSessionDlg.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/VoiceSessionDlg.h new file mode 100644 index 00000000000..867516710f3 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/VoiceSessionDlg.h @@ -0,0 +1,66 @@ +#if !defined(AFX_VOICESESSIONDLG_H__4D78C45C_9CB3_4F4B_81DF_8BF65316598E__INCLUDED_) +#define AFX_VOICESESSIONDLG_H__4D78C45C_9CB3_4F4B_81DF_8BF65316598E__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// VoiceSessionDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CVoiceSessionDlg dialog +#include "SetupDlg.h" +#include "../../gt2/gt2.h" +#include "../../natneg/natneg.h" + +class CVoiceSessionDlg : public CDialog +{ +public: + int m_NNCookie; // used to connect the two buddies + BOOL m_IsHost; // TRUE = I invited the buddy, FALSE = Buddy invited me + + VoiceSetupInfo m_SetupInfo; // device info + + GT2Socket m_Socket; + GT2Connection m_Connection; + unsigned int m_RemoteAddr; // IP addr of the buddy (used for identification) + + // MFC STUFF BELOW + +// Construction +public: + CVoiceSessionDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CVoiceSessionDlg) + enum { IDD = IDD_SESSION }; + CStatic m_RemoteSpeaking; + CStatic m_LocalSpeaking; + CString m_DisplayText; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CVoiceSessionDlg) + public: + virtual BOOL DestroyWindow(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CVoiceSessionDlg) + afx_msg void OnTimer(UINT nIDEvent); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_VOICESESSIONDLG_H__4D78C45C_9CB3_4F4B_81DF_8BF65316598E__INCLUDED_) diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/Voice2BuddyMFC.ico b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/Voice2BuddyMFC.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/Voice2BuddyMFC.ico differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/Voice2BuddyMFC.rc2 b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/Voice2BuddyMFC.rc2 new file mode 100644 index 00000000000..de338e0643f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/Voice2BuddyMFC.rc2 @@ -0,0 +1,13 @@ +// +// VOICE2BUDDYMFC.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/gamespyl.bmp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/gamespyl.bmp new file mode 100644 index 00000000000..01142a32b94 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/gamespyl.bmp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/logo270x83.bmp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/logo270x83.bmp new file mode 100644 index 00000000000..01142a32b94 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/logo270x83.bmp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/microsoft-microphone.bmp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/microsoft-microphone.bmp new file mode 100644 index 00000000000..71d27583191 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/microsoft-microphone.bmp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/microsoft-speaker.bmp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/microsoft-speaker.bmp new file mode 100644 index 00000000000..b98071f3ca2 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/microsoft-speaker.bmp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/speaking.bmp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/speaking.bmp new file mode 100644 index 00000000000..b42ff519a05 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/speaking.bmp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/speaking2.bmp b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/speaking2.bmp new file mode 100644 index 00000000000..cc274c3dc24 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/res/speaking2.bmp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/resource.h b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/resource.h new file mode 100644 index 00000000000..a4a8a2c56bf --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2BuddyMFC/resource.h @@ -0,0 +1,45 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Voice2BuddyMFC.rc +// +#define ID_SETUP 3 +#define ID_VOICECHAT 4 +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_VOICE2BUDDYMFC_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDD_LOGIN 129 +#define IDD_SESSION 130 +#define IDD_SETUPDIALOG 132 +#define IDB_SPEAKING2 134 +#define IDB_MICROPHONE 135 +#define IDB_SPEAKER 136 +#define IDB_GAMESPYLOGO 142 +#define IDB_SPEAKING 146 +#define IDB_GAMESPYLOGO1 147 +#define IDC_BUDDYLIST 1000 +#define IDC_EMAIL 1001 +#define IDC_NICKNAME 1002 +#define IDC_DISPLAYTEXT 1002 +#define IDC_PASSWORD 1003 +#define IDC_SPEAKING1 1003 +#define IDC_CAPTURECOMBO 1004 +#define IDC_SPEAKING2 1004 +#define IDC_PLAYBACKCOMBO 1005 +#define IDC_SPEAKERBITMAP 1006 +#define IDC_MICROPHONEBITMAP 1007 +#define IDC_VOICELEVEL 1028 +#define IDC_ACTIVATELEVEL 1029 +#define IDC_ISSPEAKING 1031 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 135 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1005 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test.c b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test.c new file mode 100644 index 00000000000..84c77cfe98d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test.c @@ -0,0 +1,1010 @@ +#include "../gv.h" +#include +#include +#if defined(_WIN32) +#include +#elif defined(_PS2) +#include "../../common/ps2/ps2pad.h" +#elif defined(_PS3) +//#define USER_CREATED_SPURS_INSTANCE +#include +#if defined(USER_CREATED_SPURS_INSTANCE) +#include "spursConfiguration.h" +#include +int iReturn, iNumSpus, ppuThreadPriority, spuThreadPriority; +bool exitIfNoWork; +CellSpurs* myCellSpurs; +uint8_t auiLocalPriorities[8]={1,1,1,1,1,1,1,1}; +#endif +#endif + +#define NET_PORT 55123 +#define MAX_DEVICES 10 +#define LOCAL_ECHO 1 +#define SEND_PACKETS 0 +#define CUSTOM_CODEC 0 +#define CUSTOM_CODEC_SAMPLES_PER_FRAME 100 +#define SHOW_TALKERS 0 +#define SHOW_VOLUME 0 +#define SHOW_FRAMESTAMPS 0 +#define CAPTURE_THRESHOLD 0.05 +#define CAPTURE_FILTER 0 +//#define CODEC GVCodecRaw +//#define CODEC GVCodecSuperHighQuality +//#define CODEC GVCodecHighQuality +#define CODEC GVCodecAverage +//#define CODEC GVCodecLowBandwidth +//#define CODEC GVCodecSuperLowBandwidth + +GVDevice capDevice; +GVDevice playDevice; + +SOCKET sock = INVALID_SOCKET; +SOCKADDR_IN sendAddr; +SOCKADDR_IN localSource; + +int SamplesPerFrame; +int BytesPerFrame; +int EncodedFrameSize; +int BitsPerSecond; + +static GVBool CheckInput(void); + +#ifdef _PS3 +gsi_bool controllerConnected = gsi_false; +#endif + +#if CUSTOM_CODEC +static void CustomEncodeCallback(GVByte * out, const GVSample * in) +{ + GVSample * sampleOut = (GVSample *)out; + int i; + + for(i = 0 ; i < SamplesPerFrame ; i++) + sampleOut[i] = htons(in[i]); +} + +static void CustomDecodeAddCallback(GVSample * out, const GVByte * in, GVDecoderData data) +{ + const GVSample * sampleIn = (const GVSample *)in; + int i; + + for(i = 0 ; i < SamplesPerFrame ; i++) + out[i] += ntohs(sampleIn[i]); +} + +static void CustomDecodeSetCallback(GVSample * out, const GVByte * in, GVDecoderData data) +{ + const GVSample * sampleIn = (const GVSample *)in; + int i; + + for(i = 0 ; i < SamplesPerFrame ; i++) + out[i] = ntohs(sampleIn[i]); +} +#endif + +static void PlayPacket(const GVByte * packet, int len, GVSource source) +{ + GVFrameStamp frameStamp; + + if(!playDevice) + return; + + if((len % EncodedFrameSize) != sizeof(GVFrameStamp)) + return; + + // get out the frameStamp + len -= sizeof(GVFrameStamp); + memcpy(&frameStamp, packet + len, sizeof(GVFrameStamp)); + frameStamp = ntohs(frameStamp); +#if SHOW_FRAMESTAMPS + printf("Playing frameStamp %d\n", frameStamp); +#endif + + // queue it + gvPlayPacket(playDevice, packet, len, source, frameStamp, 0); +} + +static void HandleCapturedPacket(const GVByte * packet, int len, GVFrameStamp frameStamp, GVScalar volume) +{ +#if SHOW_VOLUME + printf("%.00f%%\n", (float)(volume * 100)); +#endif + +#if LOCAL_ECHO + PlayPacket(packet, len, localSource); +#endif + +#if SEND_PACKETS + sendto(sock, (char *)packet, len, 0, (SOCKADDR *)&sendAddr, sizeof(SOCKADDR_IN)); +#endif + + GSI_UNUSED(packet); + GSI_UNUSED(len); + GSI_UNUSED(frameStamp); + GSI_UNUSED(volume); +} + +static void UnpluggedCallback(GVDevice device) +{ + printf("Halting - device unplugged\n"); + while(CheckInput()) + msleep(10); + exit(1); + + GSI_UNUSED(device); +} + +static GVBool Initialize(const char * remoteIP) +{ + SOCKADDR_IN localAddr; + GVBool result; +#ifdef _PS3 + int32_t ret; +#endif +#if CUSTOM_CODEC + GVCustomCodecInfo customCodecInfo; +#else + GVCodec codec; +#endif + +#if defined(_PS2) + if(!PadInit()) + { + printf("Failed to initialize the controller\n"); + return GVFalse; + } +#elif defined(_PS3) + // Intialize one controller for testing purposes + ret = cellPadInit(1); + if (ret != CELL_OK) + { + printf ("Failed to initialize cell pad 0x%08x\n", ret); + return(GVFalse); + } +#endif + + SocketStartUp(); + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(sock == INVALID_SOCKET) + { + printf("Failed to create socket\n"); + return GVFalse; + } + if(SetSockBlocking(sock, 0) == 0) + { + printf("Failed to set socket to non-blocking\n"); + return GVFalse; + } + + memset(&localAddr, 0, sizeof(SOCKADDR_IN)); + localAddr.sin_family = AF_INET; + localAddr.sin_port = htons(NET_PORT); + if(gsiSocketIsError(bind(sock, (SOCKADDR *)&localAddr, sizeof(SOCKADDR_IN)))) + { + printf("Failed to bind socket\n"); + return GVFalse; + } + + memset(&sendAddr, 0, sizeof(SOCKADDR_IN)); + sendAddr.sin_family = AF_INET; + sendAddr.sin_addr.s_addr = inet_addr(remoteIP); + sendAddr.sin_port = htons(NET_PORT); + +#if SEND_PACKETS + printf("Sending to %s:%d\n", remoteIP, NET_PORT); +#endif + +#if defined(_PS3) && defined(USER_CREATED_SPURS_INSTANCE) + + iNumSpus = 1; + spuThreadPriority = 200; + ppuThreadPriority = 1000; + exitIfNoWork = false; + myCellSpurs = (CellSpurs*) gsimemalign(128, sizeof(CellSpurs)); + + // initializing spus themselves before using spurs + sys_spu_initialize(iNumSpus,0); + + iReturn=cellSpursInitialize(myCellSpurs, iNumSpus,spuThreadPriority,ppuThreadPriority,exitIfNoWork); + if (iReturn!=CELL_OK) + { + printf("Error initializing spurs\n"); + return GVFalse; + } + spursConfiguration_initWithSpurs(myCellSpurs, iNumSpus,auiLocalPriorities); +#endif + +#if defined(_WIN32) + result = gvStartup(NULL); +#else + result = gvStartup(); +#endif + if(!result) + { + printf("Startup failed\n"); + return GVFalse; + } + printf("Started\n"); + +#if CUSTOM_CODEC + customCodecInfo.m_samplesPerFrame = CUSTOM_CODEC_SAMPLES_PER_FRAME; + customCodecInfo.m_encodedFrameSize = (CUSTOM_CODEC_SAMPLES_PER_FRAME * GV_BYTES_PER_SAMPLE); + customCodecInfo.m_newDecoderCallback = NULL; + customCodecInfo.m_freeDecoderCallback = NULL; + customCodecInfo.m_encodeCallback = CustomEncodeCallback; + customCodecInfo.m_decodeAddCallback = CustomDecodeAddCallback; + customCodecInfo.m_decodeSetCallback = CustomDecodeSetCallback; + gvSetCustomCodec(&customCodecInfo); +#else + codec = CODEC; +#if defined(_PS3) && defined(_WIN32) + gvSetSampleRate(GVRate_16KHz); +#elif defined(_PSP) + gvSetSampleRate(GVRate_11KHz); +#else + gvSetSampleRate(GVRate_8KHz); +#endif + if(!gvSetCodec(codec)) + { + printf("Failed to set the codec\n"); + return GVFalse; + } +#endif + + gvGetCodecInfo(&SamplesPerFrame, &EncodedFrameSize, &BitsPerSecond); + BytesPerFrame = (SamplesPerFrame * GV_BYTES_PER_SAMPLE); + + printf("SamplesPerFrame=%d EncodedFrameSize=%d BitsPerSecond=%d\n", + SamplesPerFrame, EncodedFrameSize, BitsPerSecond); + + return GVTrue; +} + +void Destroy() +{ +#ifdef _PS3 + int32_t ret; + ret = cellPadEnd(); + if (ret != CELL_OK) + { + printf ("Failed to destroy cell pad 0x%08x\n", ret); + } +#endif + playDevice = NULL; + capDevice = NULL; + closesocket(sock); + gvCleanup(); + +#if defined(_PS3) && defined(USER_CREATED_SPURS_INSTANCE) + cellSpursFinalize(myCellSpurs); + gsifree(myCellSpurs); +#endif +} + +#if CAPTURE_FILTER +#define M_2PI 6.283185307179586476925286766559 +static void Filter(GVDevice device, GVSample * audio, GVFrameStamp frameStamp) +{ + int i; + double t; + double v; + for(i = 0 ; i < SamplesPerFrame ; i++) + { + t = ((double)i / SamplesPerFrame); + v = sin(t * M_2PI); + audio[i] = (GVSample)(audio[i] * v); + } +} +#endif + +static void ListChannels(GVDevice device, GVDeviceType type) +{ + gsi_char name[GV_CHANNEL_NAME_LEN]; + int num; + int i; + + num = gvGetNumChannels(device, type); + if(num < 2) + return; + + printf("\tChannels:\n"); + + for(i = 0 ; i < num ; i++) + { + gvGetChannelName(device, type, i, name); + _tprintf(_T("\t\t%d: %s\n"), i, name); + } +} + +#if defined(_PSP) +#include +#define PSP_STEREO 1 +#if PSP_STEREO + #define CHANNELS 2 + #define PSP_WAVE_FORMAT SCE_WAVE_AUDIO_FMT_S16_STEREO +#else + #define CHANNELS 1 + #define PSP_WAVE_FORMAT SCE_WAVE_AUDIO_FMT_S16_MONO +#endif +#define PSP_CHANNEL 0 +#define PSP_BUFFER_SIZE 640 +#define PSP_TEMP_BUFFER_SIZE 160 +#define PSP_NUM_BUFFERS 2 +#define PSP_VOLUME 0x8000 +static int PSPBufferIndex = 0; +static GVSample PSPBuffer[PSP_NUM_BUFFERS][PSP_BUFFER_SIZE * CHANNELS]; +static GVSample PSPTempBuffer[PSP_TEMP_BUFFER_SIZE]; +static SceUID PSPPlaybackThreadID; + +static int PSPPlaybackThread(SceSize args, void * argp) +{ + int rcode; + int i; + + while(1) + { + // get the playback audio + gvGetCustomPlaybackAudio(playDevice, PSPTempBuffer, PSP_TEMP_BUFFER_SIZE); + + // upsample from 11khz to 44khz + // also interleave for stereo + for(i = 0; i < PSP_TEMP_BUFFER_SIZE ; i++) + { + PSPBuffer[PSPBufferIndex][i*4*CHANNELS] = PSPTempBuffer[i]; + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+1] = PSPTempBuffer[i]; + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+2] = PSPTempBuffer[i]; + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+3] = PSPTempBuffer[i]; +#if PSP_STEREO + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+4] = PSPTempBuffer[i]; + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+5] = PSPTempBuffer[i]; + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+6] = PSPTempBuffer[i]; + PSPBuffer[PSPBufferIndex][i*4*CHANNELS+7] = PSPTempBuffer[i]; +#endif + } + + // write it + rcode = sceWaveAudioWriteBlocking(PSP_CHANNEL, PSP_VOLUME, PSP_VOLUME, PSPBuffer[PSPBufferIndex]); + if(rcode < 0) + { + printf("sceWaveAudioWrite Error = %X\n", rcode); + break; + } + + // move the index + PSPBufferIndex++; + PSPBufferIndex %= PSP_NUM_BUFFERS; + } + + // wait for playback to finish + sceWaveAudioWriteBlocking(PSP_CHANNEL, PSP_VOLUME, PSP_VOLUME, NULL); + + sceKernelExitThread(0); + + GSI_UNUSED(args); + GSI_UNUSED(argp); + + return 0; +} + +static GVBool PSPStartup(void) +{ + int rcode; + GVBool result; + + rcode = sceWaveInit(); + if(rcode != SCE_OK) + { + printf("sceWaveInit = %X\n", rcode); + return GVFalse; + } + + rcode = sceWaveAudioSetSample(PSP_CHANNEL, PSP_BUFFER_SIZE); + if(rcode != SCE_OK) + { + printf("sceWaveAudioSetSample = %X\n", rcode); + return GVFalse; + } + + rcode = sceWaveAudioSetFormat(PSP_CHANNEL, PSP_WAVE_FORMAT); + if(rcode != SCE_OK) + { + printf("sceWaveAudioSetFormat = %X\n", rcode); + return GVFalse; + } + + playDevice = gvNewCustomDevice(GV_PLAYBACK); + if(!playDevice) + { + printf("gvNewCustomDevice failed\n"); + return GVFalse; + } + + result = gvStartDevice(playDevice, GV_PLAYBACK); + if(!result) + { + printf("gvStartDevice failed\n"); + return GVFalse; + } + + // create playback thread + PSPPlaybackThreadID = sceKernelCreateThread("playback",PSPPlaybackThread, + SCE_KERNEL_USER_HIGHEST_PRIORITY, 4096, 0, NULL); + if(PSPPlaybackThreadID < 0) + { + printf("Error creating playback thread\n"); + return GVFalse; + } + + // start playback thread + rcode = sceKernelStartThread(PSPPlaybackThreadID, 0, NULL); + if(rcode < 0) + { + printf("Error starting playback thread\n"); + return GVFalse; + } + + return GVTrue; +} +#endif + +static void Startup(void) +{ + int num; + GVDeviceInfo devices[MAX_DEVICES]; + GVDeviceInfo * info; + GVDevice device; + GVBool pd, cd, dpd, dcd; + GVDeviceType types; + const char * typesString; + int i; + GVBool result; + const char * hardwareType; + +#if defined(_PS2) || defined(_PS3) + printf("Waiting for devices to be detected...\n"); + msleep(2000); +#endif + +#if defined(_PSP) + PSPStartup(); +#endif + + printf("Checking for devices...\n"); + do + { + num = gvListDevices(devices, MAX_DEVICES, GV_CAPTURE_AND_PLAYBACK); + msleep(10); + } + while(num == 0); + printf("Found %d devices\n", num); + + for(i = 0 ; i < num ; i++) + { + info = &devices[i]; + pd = (info->m_deviceType & GV_PLAYBACK); + cd = (info->m_deviceType & GV_CAPTURE); + dpd = (info->m_defaultDevice & GV_PLAYBACK); + dcd = (info->m_defaultDevice & GV_CAPTURE); + if(info->m_hardwareType == GVHardwareDirectSound) + hardwareType = "DirectSound"; + else if(info->m_hardwareType == GVHardwarePS2Spu2) + hardwareType = "SPU2"; + else if(info->m_hardwareType == GVHardwarePS2Headset) + hardwareType = "Headset"; + else if(info->m_hardwareType == GVHardwarePS2Microphone) + hardwareType = "Microphone"; + else if(info->m_hardwareType == GVHardwarePS2Speakers) + hardwareType = "Speakers"; + else if(info->m_hardwareType == GVHardwarePS2Eyetoy) + hardwareType = "Eyetoy"; + else if(info->m_hardwareType == GVHardwarePSPHeadset) + hardwareType = "Headset"; + else if(info->m_hardwareType == GVHardwarePS3Headset) + hardwareType = "Headset"; + else if(info->m_hardwareType == GVHardwareMacOSX) + hardwareType = "MacOS X"; + else + hardwareType = "Unknown"; + + _tprintf(_T("%d: %s"), + i, info->m_name); + printf(" (%s)\n\tPlayback: %s\n\tCapture: %s\n", + hardwareType, + pd?(dpd?"Default":"Yes"):"No", + cd?(dcd?"Default":"Yes"):"No"); + +#if defined(_PS2) || defined(_PS3) + + if (!capDevice && cd) + dcd = cd; + if (!playDevice && pd) + dpd = pd; + + if((pd && !playDevice) || (cd && !capDevice)) +#else + if(dpd || dcd) +#endif + { + types = 0; + if(dpd && !playDevice) + types |= GV_PLAYBACK; + if(dcd && !capDevice) + types |= GV_CAPTURE; + + if(types == GV_CAPTURE) + typesString = "capture"; + else if(types == GV_PLAYBACK) + typesString = "playback"; + else + typesString = "capture & playback"; + + printf("\tUsing Types: %s\n", typesString); + + device = gvNewDevice(devices[i].m_id, types); + printf("\tCreation: %s\n", device?"succeeded":"failed"); + if(!device) + continue; + + gvSetUnpluggedCallback(device, UnpluggedCallback); + + if(types & GV_CAPTURE) + { + capDevice = device; + gvSetCaptureThreshold(device, CAPTURE_THRESHOLD); +#if CAPTURE_FILTER + gvSetFilter(capDevice, GV_CAPTURE, Filter); +#endif + ListChannels(device, GV_CAPTURE); + } + if(types & GV_PLAYBACK) + { + playDevice = device; + ListChannels(device, GV_PLAYBACK); + } + + result = gvStartDevice(device, types); + printf("\tStarting: %s\n", result?"succeeded":"failed"); + } + } + +#if defined(_WIN32) + printf("Press Q to quit\n"); +#elif defined(_PS2) + printf("Press X to quit\n"); +#endif +} + +static void ShowInfo(void) +{ +#if SHOW_TALKERS + static gsi_time lastPrintTime; + gsi_time now; + GVSource sources[10]; + int num; + int i; + + if(!playDevice) + return; + + // check if we should show info + now = current_time(); + if((now - lastPrintTime) > 1000) + { + lastPrintTime = now; + + // see who's talking + num = gvListTalkingSources(playDevice, sources, sizeof(sources) / sizeof(sources[0])); + printf("Talking sources:"); + for(i = 0 ; i < num ; i++) + printf(" %s:%d", inet_ntoa(sources[i].sin_addr), ntohs(sources[i].sin_port)); + printf("\n"); + } +#endif +} + +GVByte packet[1024] POST_ALIGN(128); +static void Think(void) +{ + GVBool result; + int rcode; + + int packetLen; + GVFrameStamp frameStamp; + SOCKADDR_IN fromAddr; + int fromLen; + GVScalar volume; + + memset(packet, 0, sizeof(packet)); + + // handle incoming packets + do + { + fromLen = sizeof(SOCKADDR_IN); + + rcode = recvfrom(sock, (char *)packet, sizeof(packet), 0, (SOCKADDR *)&fromAddr, &fromLen); + if(rcode > 0) + PlayPacket(packet, rcode, fromAddr); + else if(rcode < 0) + { + int error = GOAGetLastError(sock); + if(error != WSAEWOULDBLOCK) + printf("recv error: %d\n", error); + } + } + while(rcode > 0); + + // let gv process the packets + gvThink(); + + // check for captured packets + if(gvIsDeviceStarted(capDevice, GV_CAPTURE)) + { + do + { + packetLen = (sizeof(packet) - sizeof(GVFrameStamp)); + memset(packet, 0, sizeof(packet)); + result = gvCapturePacket(capDevice, packet, &packetLen, &frameStamp, &volume); + if(result) + { + // handle the capture packet + frameStamp = htons(frameStamp); + memcpy(packet + packetLen, &frameStamp, sizeof(GVFrameStamp)); + HandleCapturedPacket(packet, packetLen + sizeof(GVFrameStamp), frameStamp, volume); + } + } + while(result); + } +} + +#if defined(_UNIX) +#include +#include +#include +//#include +int _kbhit(void) +{ + static const int STDIN = 0; + static int initialized = 0; + struct timeval timeout; + struct fd_set rdset; + + if (initialized == 0) + { + // Use termios to turn off line buffering + struct termios term; + tcgetattr(STDIN, &term); + term.c_lflag &= ~ICANON; + tcsetattr(STDIN, TCSANOW, &term); + setbuf(stdin, NULL); + initialized = 1; + } + + FD_ZERO(&rdset); + FD_SET(STDIN, &rdset); + timeout.tv_sec = 0; + timeout.tv_usec = 0; + return select(STDIN + 1, &rdset, NULL, NULL, &timeout); +} +#endif + +#if !defined(_PS2) && !defined(_PSP) && !defined(_PS3) +int gsiGetChar(void) +{ + int c; + + if(_kbhit() == 0) + return -1; + +#if defined(_WIN32) + c = _getch(); +#else + c = getchar(); +#endif + + return tolower(c); +} +#endif + +static GVBool CheckInput(void) +{ +#if defined(_PS2) + int events[NumPadEvents]; + memset(events, 0, sizeof(events)); + PadReadInput(events); + if(events[PadX]) + { + return GVFalse; + } + if(events[PadSquare]) + { + if(capDevice && !gvIsDeviceStarted(capDevice, GV_CAPTURE)) + { + gvStartDevice(capDevice, GV_CAPTURE); + puts("Started capture"); + } + } + if(events[PadCircle]) + { + if(capDevice && gvIsDeviceStarted(capDevice, GV_CAPTURE)) + { + gvStopDevice(capDevice, GV_CAPTURE); + puts("Stopped capture"); + } + } + return GVTrue; +#elif defined(_PSP) + return GVTrue; +#elif defined(_PS3) + // On PS3, capture and playback device point to the same device + // i.e. the USB Headset + + int ret; + CellPadData PadData; + CellPadInfo PadInfo; + + ret = cellPadGetInfo (&PadInfo); + if (ret != 0) + { + printf ("Error obtaining cell pad info: (%08X)\n", ret); + return GVFalse; + } + + if (PadInfo.status[0] == CELL_PAD_STATUS_DISCONNECTED) + { + if (controllerConnected) + { + printf("The controller has been disconnected\n"); + controllerConnected = gsi_false; + } + return GVTrue; + } + else + { + if (!controllerConnected) + { + printf("The controller has been connected\n"); + controllerConnected = gsi_true; + } + } + ret = cellPadGetData (0, &PadData); + if (PadData.len > 0) + { + if (PadData.button[CELL_PAD_BTN_OFFSET_DIGITAL2] & CELL_PAD_CTRL_CROSS) + { + return GVFalse; + } + + if (PadData.button[CELL_PAD_BTN_OFFSET_DIGITAL2] & CELL_PAD_CTRL_SQUARE) + { + if ((capDevice && playDevice) && !gvIsDeviceStarted(capDevice, GV_CAPTURE_AND_PLAYBACK)) + { + gvStartDevice(capDevice, GV_CAPTURE_AND_PLAYBACK); + printf("Started USB Headset capture/playback"); + } + } + if (PadData.button[CELL_PAD_BTN_OFFSET_DIGITAL2] & CELL_PAD_CTRL_CIRCLE) + { + if ((capDevice && playDevice) && gvIsDeviceStarted(capDevice, GV_CAPTURE_AND_PLAYBACK)) + { + gvStopDevice(capDevice, GV_CAPTURE_AND_PLAYBACK); + printf("Stopped USB Headset capture/playback\n"); + } + } + } + return GVTrue; + +#else + int c; + GVScalar volume; + int num; + int channel; + gsi_char name[GV_CHANNEL_NAME_LEN]; + + while((c = gsiGetChar()) != -1) + { + switch(c) + { + case'/': + case'?': + puts("q: quit\n"); + puts("c/v: start/stop capture device\n"); + puts("b/n: start/stop playback device\n"); + puts("d/f/g: get/decrease/increase capture volume\n"); + puts("e/r/t: get/decrease/increase playback volume\n"); + puts("-/+: decrease/increase capture channel\n"); + puts("[/]: decrease/increase playback channel\n"); + puts("?: help\n"); + break; + case 'q': + return GVFalse; + case 'c': + if(capDevice && !gvIsDeviceStarted(capDevice, GV_CAPTURE)) + { + gvStartDevice(capDevice, GV_CAPTURE); + puts("Started capture"); + } + break; + case 'b': + if(playDevice && !gvIsDeviceStarted(playDevice, GV_PLAYBACK)) + { + gvStartDevice(playDevice, GV_PLAYBACK); + puts("Started playback"); + } + break; + case 'v': + if(capDevice && gvIsDeviceStarted(capDevice, GV_CAPTURE)) + { + gvStopDevice(capDevice, GV_CAPTURE); + puts("Stopped capture"); + } + break; + case 'n': + if(playDevice && gvIsDeviceStarted(playDevice, GV_PLAYBACK)) + { + gvStopDevice(playDevice, GV_PLAYBACK); + puts("Stopped playback"); + } + break; + case 'd': + if(capDevice) + { + volume = gvGetDeviceVolume(capDevice, GV_CAPTURE); + printf("Capture volume: %.f%%\n", (float)volume * 100); + } + break; + case 'e': + if(playDevice) + { + volume = gvGetDeviceVolume(playDevice, GV_PLAYBACK); + printf("Playback volume: %.f%%\n", (float)volume * 100); + } + break; + case 'f': + if(capDevice) + { + volume = gvGetDeviceVolume(capDevice, GV_CAPTURE); + volume = max(0.0, (volume - 0.2)); + gvSetDeviceVolume(capDevice, GV_CAPTURE, volume); + printf("Capture volume set: %.f%%\n", (float)volume * 100); + } + break; + case 'g': + if(capDevice) + { + volume = gvGetDeviceVolume(capDevice, GV_CAPTURE); + volume = min(1.0, (volume + 0.2)); + gvSetDeviceVolume(capDevice, GV_CAPTURE, volume); + printf("Capture volume set: %.f%%\n", (float)volume * 100); + } + break; + case 'r': + if(playDevice) + { + volume = gvGetDeviceVolume(playDevice, GV_PLAYBACK); + volume = max(0.0, (volume - 0.2)); + gvSetDeviceVolume(playDevice, GV_PLAYBACK, volume); + printf("Playback volume set: %.f%%\n", (float)volume * 100); + } + break; + case 't': + if(playDevice) + { + volume = gvGetDeviceVolume(playDevice, GV_PLAYBACK); + volume = min(1.0, (volume + 0.2)); + gvSetDeviceVolume(playDevice, GV_PLAYBACK, volume); + printf("Playback volume set: %.f%%\n", (float)volume * 100); + } + break; + case '-': + if(capDevice) + { + num = gvGetNumChannels(capDevice, GV_CAPTURE); + if(num == 0) + { + printf("Capture device has no channels\n"); + } + else + { + channel = gvGetChannel(capDevice, GV_CAPTURE); + if(channel > 0) + gvSetChannel(capDevice, GV_CAPTURE, --channel); + gvGetChannelName(capDevice, GV_CAPTURE, channel, name); + _tprintf(_T("Capture channel: %s [%d] (%d total)\n"), name, channel, num); + } + } + break; + case '=': + case '+': + if(capDevice) + { + num = gvGetNumChannels(capDevice, GV_CAPTURE); + if(num == 0) + { + printf("Capture device has no channels\n"); + } + else + { + channel = gvGetChannel(capDevice, GV_CAPTURE); + if(channel < (num - 1)) + gvSetChannel(capDevice, GV_CAPTURE, ++channel); + gvGetChannelName(capDevice, GV_CAPTURE, channel, name); + _tprintf(_T("Capture channel: %s [%d] (%d total)\n"), name, channel, num); + } + } + break; + case '[': + if(playDevice) + { + num = gvGetNumChannels(playDevice, GV_PLAYBACK); + if(num == 0) + { + printf("Playback device has no channels\n"); + } + else + { + channel = gvGetChannel(playDevice, GV_PLAYBACK); + if(channel > 0) + gvSetChannel(playDevice, GV_PLAYBACK, --channel); + gvGetChannelName(playDevice, GV_PLAYBACK, channel, name); + _tprintf(_T("Playback channel: %s [%d] (%d total)\n"), name, channel, num); + } + } + break; + case ']': + if(playDevice) + { + num = gvGetNumChannels(playDevice, GV_PLAYBACK); + if(num == 0) + { + printf("Playback device has no channels\n"); + } + else + { + channel = gvGetChannel(playDevice, GV_PLAYBACK); + if(channel < (num - 1)) + gvSetChannel(playDevice, GV_PLAYBACK, ++channel); + gvGetChannelName(playDevice, GV_PLAYBACK, channel, name); + _tprintf(_T("Playback channel: %s [%d] (%d total)\n"), name, channel, num); + } + } + break; + } + } + return GVTrue; +#endif +} + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped + int test_main(int argc, char **argp); +#endif +int test_main(int argc, char **argp) +{ + char remoteIP[64]; + + if(argc >= 2) + strcpy(remoteIP, argp[1]); + else + { + // Put in your own IP address + strcpy(remoteIP, "192.168.0.100"); + } + if(!Initialize(remoteIP)) + return 1; + + Startup(); + + while(CheckInput()) + { + Think(); + + ShowInfo(); + + msleep(1); + } + + Destroy(); + + return 0; +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test.dsp b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test.dsp new file mode 100644 index 00000000000..11c802e8e88 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test.dsp @@ -0,0 +1,320 @@ +# Microsoft Developer Studio Project File - Name="Voice2Test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Voice2Test - Win32 Debug Unicode +!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 "Voice2Test.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 "Voice2Test.mak" CFG="Voice2Test - Win32 Debug Unicode" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Voice2Test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Voice2Test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "Voice2Test - Win32 Debug Unicode" (based on "Win32 (x86) Console Application") +!MESSAGE "Voice2Test - Win32 Release Unicode" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/IGNCP/Gamespy/GOA/Voice2/Voice2Test" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Voice2Test - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I "..\speex-1.0.5\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /D "HAVE_CONFIG_H" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 libspeex.lib dsound.lib dxguid.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:console /machine:I386 /libpath:"..\libspeex\Release" + +!ELSEIF "$(CFG)" == "Voice2Test - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "..\speex-1.0.5\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /D "HAVE_CONFIG_H" /Fr /FD /GZ /c +# SUBTRACT CPP /YX +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libspeex.lib dsound.lib dxguid.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:console /debug /machine:I386 /pdbtype:sept /libpath:"..\libspeex\Debug" + +!ELSEIF "$(CFG)" == "Voice2Test - Win32 Debug Unicode" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Voice2Test___Win32_Debug_Unicode0" +# PROP BASE Intermediate_Dir "Voice2Test___Win32_Debug_Unicode0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Voice2Test___Win32_Debug_Unicode0" +# PROP Intermediate_Dir "Voice2Test___Win32_Debug_Unicode0" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\speex-1.0.5\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /YX /FD /GZ /c +# SUBTRACT BASE CPP /WX /Fr +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "..\speex-1.0.5\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /D "GSI_UNICODE" /D "HAVE_CONFIG_H" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 dxguid.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libspeex.lib dsound.lib dxguid.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:console /debug /machine:I386 /pdbtype:sept /libpath:"..\libspeex\Debug" + +!ELSEIF "$(CFG)" == "Voice2Test - Win32 Release Unicode" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Voice2Test___Win32_Release_Unicode" +# PROP BASE Intermediate_Dir "Voice2Test___Win32_Release_Unicode" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Voice2Test___Win32_Release_Unicode" +# PROP Intermediate_Dir "Voice2Test___Win32_Release_Unicode" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\speex-1.0.5\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /YX /FD /c +# SUBTRACT BASE CPP /WX /Fr +# ADD CPP /nologo /W3 /WX /GX /O2 /I "..\speex-1.0.5\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /D "GSI_UNICODE" /D "HAVE_CONFIG_H" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 dxguid.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:console /machine:I386 +# ADD LINK32 libspeex.lib dsound.lib dxguid.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:console /machine:I386 /libpath:"..\libspeex\Release" + +!ENDIF + +# Begin Target + +# Name "Voice2Test - Win32 Release" +# Name "Voice2Test - Win32 Debug" +# Name "Voice2Test - Win32 Debug Unicode" +# Name "Voice2Test - Win32 Release Unicode" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Voice2Test.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "VoiceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gv.h +# End Source File +# Begin Source File + +SOURCE=..\gvCodec.c +# End Source File +# Begin Source File + +SOURCE=..\gvCodec.h +# End Source File +# Begin Source File + +SOURCE=..\gvCustomDevice.c +# End Source File +# Begin Source File + +SOURCE=..\gvCustomDevice.h +# End Source File +# Begin Source File + +SOURCE=..\gvDevice.c +# End Source File +# Begin Source File + +SOURCE=..\gvDevice.h +# End Source File +# Begin Source File + +SOURCE=..\gvDirectSound.c +# ADD CPP /W3 +# SUBTRACT CPP /WX +# End Source File +# Begin Source File + +SOURCE=..\gvDirectSound.h +# End Source File +# Begin Source File + +SOURCE=..\gvFrame.c +# End Source File +# Begin Source File + +SOURCE=..\gvFrame.h +# End Source File +# Begin Source File + +SOURCE=..\gvMain.c +# End Source File +# Begin Source File + +SOURCE=..\gvMain.h +# End Source File +# Begin Source File + +SOURCE=..\gvSource.c +# End Source File +# Begin Source File + +SOURCE=..\gvSource.h +# End Source File +# Begin Source File + +SOURCE=..\gvSpeex.c +# End Source File +# Begin Source File + +SOURCE=..\gvSpeex.h +# End Source File +# Begin Source File + +SOURCE=..\gvUtil.c +# End Source File +# Begin Source File + +SOURCE=..\gvUtil.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test_vs2005.vcproj b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test_vs2005.vcproj new file mode 100644 index 00000000000..993dcf1310e --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test_vs2005.vcproj @@ -0,0 +1,1139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/Voice2Test_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvmacosx/Makefile b/xrGameSpy/gamespy/Voice2/Voice2Test/gvmacosx/Makefile new file mode 100644 index 00000000000..b991c44772a --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvmacosx/Makefile @@ -0,0 +1,73 @@ +# Voice2 SDK test app Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=voice2test + +SPEEX=../../speex-1.0.5/ +SPEEX_SRC=$(SPEEX)libspeex/ +SPEEX_INC=$(SPEEX)include/ + +INCLUDES=-I$(SPEEX_INC) + +DEFINES=-DGV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN + +LIBS=-framework CoreAudio -framework AudioToolbox -framework CoreFoundation + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + $(SPEEX_SRC)bits.o\ + $(SPEEX_SRC)cb_search.o\ + $(SPEEX_SRC)exc_10_16_table.o\ + $(SPEEX_SRC)exc_10_32_table.o\ + $(SPEEX_SRC)exc_20_32_table.o\ + $(SPEEX_SRC)exc_5_256_table.o\ + $(SPEEX_SRC)exc_5_64_table.o\ + $(SPEEX_SRC)exc_8_128_table.o\ + $(SPEEX_SRC)filters.o\ + $(SPEEX_SRC)gain_table.o\ + $(SPEEX_SRC)gain_table_lbr.o\ + $(SPEEX_SRC)hexc_10_32_table.o\ + $(SPEEX_SRC)hexc_table.o\ + $(SPEEX_SRC)high_lsp_tables.o\ + $(SPEEX_SRC)lpc.o\ + $(SPEEX_SRC)lsp.o\ + $(SPEEX_SRC)lsp_tables_nb.o\ + $(SPEEX_SRC)ltp.o\ + $(SPEEX_SRC)math_approx.o\ + $(SPEEX_SRC)misc.o\ + $(SPEEX_SRC)modes.o\ + $(SPEEX_SRC)nb_celp.o\ + $(SPEEX_SRC)quant_lsp.o\ + $(SPEEX_SRC)sb_celp.o\ + $(SPEEX_SRC)speex_callbacks.o\ + $(SPEEX_SRC)speex_header.o\ + $(SPEEX_SRC)stereo.o\ + $(SPEEX_SRC)vbr.o\ + $(SPEEX_SRC)vq.o\ + ../../gvCodec.o\ + ../../gvCustomDevice.o\ + ../../gvDevice.o\ + ../../gvFrame.o\ + ../../gvMain.o\ + ../../gvOSXAudio.o\ + ../../gvSource.o\ + ../../gvSpeex.o\ + ../../gvUtil.o\ + ../Voice2Test.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw.mcp b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw.mcp new file mode 100644 index 00000000000..4cdbc3d4386 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw.mcp differ diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_eenet_debug.h b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_eenet_debug.h new file mode 100644 index 00000000000..0c26e218d41 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_eenet_debug.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_eenet_debug.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_eenet_release.h b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_eenet_release.h new file mode 100644 index 00000000000..aca5ec0131c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_eenet_release.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" +#include "cw/cwprefix_eenet_release.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_insock_debug.h b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_insock_debug.h new file mode 100644 index 00000000000..b9b266c1fd7 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_insock_debug.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_insock_debug.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_insock_release.h b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_insock_release.h new file mode 100644 index 00000000000..2a208213376 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_insock_release.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_insock_release.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_snsystems_debug.h b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_snsystems_debug.h new file mode 100644 index 00000000000..6e5f7cbb5a3 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_snsystems_debug.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_snsystems_debug.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_snsystems_release.h b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_snsystems_release.h new file mode 100644 index 00000000000..71936c6e49d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2cw/gvps2cw_prefix_snsystems_release.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" +#include "cw/cwprefix_snsystems_release.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.dsp b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.dsp new file mode 100644 index 00000000000..50171c8ab62 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.dsp @@ -0,0 +1,344 @@ +# Microsoft Developer Studio Project File - Name="gvps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gvps2prodg - Win32 Release_SNSystems +!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 "gvps2prodg.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 "gvps2prodg.mak" CFG="gvps2prodg - Win32 Release_SNSystems" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gvps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gvps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gvps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "gvps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/Voice2/Voice2Test/gvps2prodg", XPODAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gvps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gvps2prodg___Win32_Debug_EENet" +# PROP BASE Intermediate_Dir "gvps2prodg___Win32_Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "_DEBUG" /D "SN_TARGET_PS2" /D "GSI_VOICE" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gvps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libipu.a libsdr.a liblgvid.a liblgaud.a liblgcodec.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gvps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gvps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gvps2prodg___Win32_Release_EENet" +# PROP BASE Intermediate_Dir "gvps2prodg___Win32_Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "GSI_VOICE" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gvps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libipu.a libsdr.a liblgvid.a liblgaud.a liblgcodec.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\gvps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gvps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gvps2prodg___Win32_Debug_SNSystems" +# PROP BASE Intermediate_Dir "gvps2prodg___Win32_Debug_SNSystems" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "GSI_VOICE" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libc.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gvps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a sneetcp.a libsdr.a liblgvid.a liblgaud.a liblgcodec.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a libipu.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\gvps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gvps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gvps2prodg___Win32_Release_SNSystems" +# PROP BASE Intermediate_Dir "gvps2prodg___Win32_Release_SNSystems" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /O2 /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "GSI_VOICE" /D GV_CUSTOM_SOURCE_TYPE=SOCKADDR_IN /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\gvps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libipu.a libsdr.a liblgvid.a liblgaud.a liblgcodec.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\gvps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "gvps2prodg - Win32 Debug_EENet" +# Name "gvps2prodg - Win32 Release_EENet" +# Name "gvps2prodg - Win32 Debug_SNSystems" +# Name "gvps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2pad.c +# End Source File +# Begin Source File + +SOURCE=..\Voice2Test.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2pad.h +# End Source File +# End Group +# Begin Group "GSI" + +# PROP Default_Filter "" +# Begin Group "VoiceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gv.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvCodec.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvCodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvCustomDevice.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvCustomDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvDevice.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvFrame.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvFrame.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvLogitechPS2Codecs.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvLogitechPS2Codecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Audio.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Audio.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Eyetoy.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Eyetoy.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Headset.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Headset.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Spu2.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvPS2Spu2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvSource.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvSource.h +# End Source File +# Begin Source File + +SOURCE=..\..\gvUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\gvUtil.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# End Group +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=..\..\changelog.txt +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.dsw b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.dsw new file mode 100644 index 00000000000..7ed0331742b --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gvps2prodg"=.\gvps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Voice2/Voice2Test/gvps2prodg", XPODAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Voice2/Voice2Test/gvps2prodg", XPODAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.sln b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.sln new file mode 100644 index 00000000000..197c1c2ddc5 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gvps2prodg", "gvps2prodg.vcproj", "{00789DA2-0626-4F5A-9FD6-A4529CB01BC6}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gvps2prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 INET Release|Win32.Build.0 = PS2 INET Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {00789DA2-0626-4F5A-9FD6-A4529CB01BC6}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.vcproj b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.vcproj new file mode 100644 index 00000000000..6366c02f2bb --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps2prodg/gvps2prodg.vcproj @@ -0,0 +1,704 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodg/gvps3prodg.sln b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodg/gvps3prodg.sln new file mode 100644 index 00000000000..dc583f3ff8c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodg/gvps3prodg.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gvps3prodg", "gvps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + PS3 Debug = PS3 Debug + PS3 Release = PS3 Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodg/gvps3prodg.vcproj b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodg/gvps3prodg.vcproj new file mode 100644 index 00000000000..3fbb10b5dcc --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodg/gvps3prodg.vcproj @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.sln b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.sln new file mode 100644 index 00000000000..657c3696841 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeexSpursTaskManager", "..\..\..\common\ps3\SpeexSpursTaskManager\SpeexSpursTaskManager_vs2005.vcproj", "{240177C7-AE7B-48E3-871D-82B7CB809D28}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeexSpursTask", "..\..\..\common\ps3\SpeexSpursTaskManager\SpeexSpursTask\SpeexSpursTask_vs2005.vcproj", "{090CCE44-29BC-436D-A8A3-82398190DE52}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gvps3prodgspeexspu", "gvps3prodgspeexspu.vcproj", "{DBAC0AD7-9994-4B86-9CBD-6F085C58B420}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {090CCE44-29BC-436D-A8A3-82398190DE52} = {090CCE44-29BC-436D-A8A3-82398190DE52} + {240177C7-AE7B-48E3-871D-82B7CB809D28} = {240177C7-AE7B-48E3-871D-82B7CB809D28} + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager\\SpeexSpursTaskManager_vs2005.vcproj + SccProjectName1 = ../../../common/ps3/SpeexSpursTaskManager + SccLocalPath1 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager + SccProjectUniqueName2 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager\\SpeexSpursTask\\SpeexSpursTask_vs2005.vcproj + SccProjectName2 = ../../../common/ps3/SpeexSpursTaskManager/SpeexSpursTask + SccLocalPath2 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager\\SpeexSpursTask + SccProjectUniqueName3 = gvps3prodgspeexspu.vcproj + SccLocalPath3 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + {DBAC0AD7-9994-4B86-9CBD-6F085C58B420}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {DBAC0AD7-9994-4B86-9CBD-6F085C58B420}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {DBAC0AD7-9994-4B86-9CBD-6F085C58B420}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {DBAC0AD7-9994-4B86-9CBD-6F085C58B420}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.vcproj b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.vcproj new file mode 100644 index 00000000000..86533e92ce1 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.vcproj @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.vssscc b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/gvps3prodgspeexspu.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/vsi.nul b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/vsi.nul new file mode 100644 index 00000000000..a7c43ed2506 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvps3prodgspeexspu/vsi.nul @@ -0,0 +1 @@ +IMPORTANT: Do not remove the custom build step for this file \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvpspprodg/gvpspprodg.sln b/xrGameSpy/gamespy/Voice2/Voice2Test/gvpspprodg/gvpspprodg.sln new file mode 100644 index 00000000000..1fefc3a15bf --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvpspprodg/gvpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gvpspprodg", "gvpspprodg.vcproj", "{B42F2BB1-779C-461A-84C7-3CFDFF181113}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gvpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B42F2BB1-779C-461A-84C7-3CFDFF181113}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {B42F2BB1-779C-461A-84C7-3CFDFF181113}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {B42F2BB1-779C-461A-84C7-3CFDFF181113}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {B42F2BB1-779C-461A-84C7-3CFDFF181113}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {B42F2BB1-779C-461A-84C7-3CFDFF181113}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {B42F2BB1-779C-461A-84C7-3CFDFF181113}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Voice2/Voice2Test/gvpspprodg/gvpspprodg.vcproj b/xrGameSpy/gamespy/Voice2/Voice2Test/gvpspprodg/gvpspprodg.vcproj new file mode 100644 index 00000000000..34b1173eb10 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2Test/gvpspprodg/gvpspprodg.vcproj @@ -0,0 +1,780 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/Voice2_vs2005.sln b/xrGameSpy/gamespy/Voice2/Voice2_vs2005.sln new file mode 100644 index 00000000000..8b873856557 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2_vs2005.sln @@ -0,0 +1,46 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "voice2bench_vs2005", "voice2bench\voice2bench_vs2005.vcproj", "{A5DCA80C-34D5-415E-95FA-6FC20333B396}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Voice2BuddyMFC_vs2005", "Voice2BuddyMFC\Voice2BuddyMFC_vs2005.vcproj", "{61C9EEC3-F790-4020-AEDE-3A6916A40B59}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Voice2Test_vs2005", "Voice2Test\Voice2Test_vs2005.vcproj", "{F80C724E-956C-4D7D-A748-3FB30665402D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = Voice2Test\\Voice2Test_vs2005.vcproj + SccProjectName1 = Voice2Test + SccLocalPath1 = Voice2Test + SccProjectUniqueName2 = Voice2BuddyMFC\\Voice2BuddyMFC_vs2005.vcproj + SccProjectName2 = Voice2BuddyMFC + SccLocalPath2 = Voice2BuddyMFC + SccProjectUniqueName3 = voice2bench\\voice2bench_vs2005.vcproj + SccProjectName3 = voice2bench + SccLocalPath3 = voice2bench + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A5DCA80C-34D5-415E-95FA-6FC20333B396}.Debug|Win32.ActiveCfg = Debug|Win32 + {A5DCA80C-34D5-415E-95FA-6FC20333B396}.Debug|Win32.Build.0 = Debug|Win32 + {A5DCA80C-34D5-415E-95FA-6FC20333B396}.Release|Win32.ActiveCfg = Release|Win32 + {A5DCA80C-34D5-415E-95FA-6FC20333B396}.Release|Win32.Build.0 = Release|Win32 + {61C9EEC3-F790-4020-AEDE-3A6916A40B59}.Debug|Win32.ActiveCfg = Debug|Win32 + {61C9EEC3-F790-4020-AEDE-3A6916A40B59}.Debug|Win32.Build.0 = Debug|Win32 + {61C9EEC3-F790-4020-AEDE-3A6916A40B59}.Release|Win32.ActiveCfg = Release|Win32 + {61C9EEC3-F790-4020-AEDE-3A6916A40B59}.Release|Win32.Build.0 = Release|Win32 + {F80C724E-956C-4D7D-A748-3FB30665402D}.Debug|Win32.ActiveCfg = Debug|Win32 + {F80C724E-956C-4D7D-A748-3FB30665402D}.Debug|Win32.Build.0 = Debug|Win32 + {F80C724E-956C-4D7D-A748-3FB30665402D}.Release|Win32.ActiveCfg = Release|Win32 + {F80C724E-956C-4D7D-A748-3FB30665402D}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Voice2/Voice2_vs2005.vssscc b/xrGameSpy/gamespy/Voice2/Voice2_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/Voice2_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Voice2/changelog.txt b/xrGameSpy/gamespy/Voice2/changelog.txt new file mode 100644 index 00000000000..4c58820b325 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/changelog.txt @@ -0,0 +1,105 @@ +Changelog for: GameSpy Voice SDK 2 +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.08.00 RMV RELEASE Released to Developer Site +12-12-2007 2.07.04 SAH FIX Fixed OSX to use mute bool in playing packets +12-11-2007 2.07.03 SN FIX Fixed floating point precision for sample app + SN FIX Cleaned up some compiler errors for PS2 support +12-07-2007 2.07.02 SAH OTHER Fixed all VC6 projects to use Speex 1.0.5 +12-04-2007 2.07.01 SN FIX Removed some test code from PS3 headset listing function + SN FIX Commented out SPURS define from Voice2Test for PS3 PPU testing +11-27-2007 2.07.01 SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +11-08-2007 2.07.00 SN FEATURE Added initial SPU speex support for the PS3 +08-22-2007 2.06.01 SN FIX Fixed support for 16Khz audio on the PS3 + SN FIX Cleaned up some code for VS2005 +08-20-2007 2.06.00 SN FEATURE Added support for 16Khz audio on the PC +08-06-2007 2.05.00 RMV RELEASE Released to Developer Site +06-20-2007 2.04.00 SN FEATURE Added support for PS3 USB Headsets. + SN FEATURE Used speex as a codec for PS3 USB Headsets for now + SN FEATURE Using speex 1.2 beta1 + SN FEATURE Usung GSM 1.0.12 for platforms using GSM codec +06-20-2007 2.03.01 DES FEATURE Speex is now more compatible with other sample rates +12-15-2006 2.03.00 MJW RELEASE Released to Developer Site +12-13-2006 2.02.14 MJW FIX Fixed VC7 projects +10-05-2006 2.02.13 SAH FIX Updated MacOSX Makefile +08-02-2006 2.02.12 SAH RELEASE Releasing to developer site +07-24-2006 2.02.12 SAH FIX Added new NatNeg files to Voice2 MFC app to fix compilation error +07-06-2006 2.02.11 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file + SAH FIX Added PSP solution along with project file +05-31-2006 2.02.10 SAH RELEASE Releasing to developer site +05-20-2006 2.02.09 SAH FIX Added GSI_UNUSED calls to Voice2Test, fixed PSP warning levels +05-15-2006 2.02.08 SAH FIX Added "PS3 Release" configuration to project +04-25-2006 2.02.07 SAH RELEASE Releasing to developer site +04-24-2006 2.02.07 SAH FIX Got rid of unnecessary source files in Voice2Test project +04-20-2006 2.02.06 SAH FIX Added a missing ')' in ps2Headset +04-18-2006 2.02.05 SAH FIX Added || defined(_PS3) in voice2Test.c for PS3 support +04-13-2006 2.02.04 DES FEATURE PSP and GSM support + DES RELEASE Limited developer release +03-21-2006 2.01.03 DES FIX Unicode support + DES RELEASE Limited developer release +03-16-2006 2.01.02 DES FIX Fixed OSX when using a device with more than one channel. + DES FEATURE Added channel API. + DES RELEASE Limited developer release +03-15-2006 2.01.01 DES FEATURE OSX volume is now controlled in software by default. + DES FIX No longer hangs when trying to stop a closed iSight + DES FIX Detects when an OSX USB device is unplugged +03-14-2006 2.01.00 DES RELEASE Limited developer release +03-14-2006 2.01.00 DES FIX Moved OSX encoding and decoding out of the IOProc functions. + DES FEATURE Added raw codec for getting unencoded audio + DES OTHER Changed decodeCallback to decodeAddCallback and decodeSetCallback. +01-27-2006 2.00.25 SN RELEASE Releasing to developer site +12-22-2005 2.00.25 SN OTHER Cleaned up projects and added missing common code if needed +11-14-2005 2.00.24 DES FIX Updated OSX support. +11-11-2005 2.00.23 DES CLEANUP Updated dsp projects to use Speex 1.0.5 +09-21-2005 2.00.22 DES FEATURE Changed DirectSound include from mmreg.h to mmsystem.h + DES FEATURE Voice2Test is now setup to work with Speex 1.0.5 +07-28-2005 2.00.21 SN RELEASE Releasing to developer site. +07-18-2005 2.00.21 DES FIX gvGetCustomPlaybackAudio no longer always returns true. + DES FIX Custom playback devices were trying to write too much audio data. +06-03-2005 2.00.20 SN RELEASE Releasing to developer site. +06-03-2005 2.00.20 SN FIX Fix support for old and new eyetoy library. +05-04-2005 2.00.19 SN OTHER Created Visual Studio .NET project +04-28-2005 2.00.19 SN RELEASE Releasing to developer site. +04-25-2005 2.00.18 DES CLEANUP Disable Win32 linker warning. + DES FEATURE Updated to use Speex 1.0.4. +04-04-2005 2.00.17 SN RELEASE Releasing to developer site. +03-18-2005 2.00.17 DES FIX Added coded to ensure that DirectSound always pairs calls + to init and cleanup COM. +01-27-2005 2.00.16 DES FIX Removed GV_CUSTOM_SOURCE_TYPE define from Voice2Test.c +01-19-2005 2.00.15 DES FIX Fixed bug when checking GVI_DYNAMICALLY_ALLOCATE_FRAMES. +10-04-2004 2.00.14 DES FEATURE Completed OSX hardware support. + DES FIX Packet capturing code no longer assumes voice pointer is valid. + DES FIX Fixed voice2test endian issues. + DES FIX Voice2test no longer assume a capture device was found. +09-16-2004 2.00.13 SN RELEASE Releasing to developer site. +09-02-2004 2.00.13 DES FEATURE Added initial OSX hardware support (not complete yet) + DES CLEANUP Moved code for managing device lists into gvDevice.c/h +08-27-2004 2.00.12 DES CLEANUP Fixed warnings under OSX (no harware support yet) + DES FIX voice2bench will now use Speex on all non-ps2 systems + DES CLEANUP Updated Win32 project configurations + DES FEATURE Added OSX Makefiles + DES FIX Typo in the CORE_INPUT_L CORE0_INPUT_L define. +08-10-2004 2.00.11 DES FIX An lgAud device can now only be used once at a time. +08-05-2004 2.00.10 SN RELEASE Releasing to developer site. +08-05-2004 2.00.10 SN FIX Fixed missing prototype warning for codwarrior +08-04-2004 2.00.09 DES FIX gvGetDeviceVolume was using the wrong formula for getting + the volume from DirectSound devices. +08-03-2004 2.00.08 DES FEATURE Now differentiates between lgAud device types. + Possible types are headset, microphone, and speakers. +07-23-2004 2.00.07 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +07-22-2004 2.00.06 DES FIX Fixed eyetoy device bit + FEATURE Voice2Test now shows what types are being + used for created devices. +07-14-2004 2.00.05 DES FEATURE Added GVHardwareType for checking a device's hardware type + FEATURE SPU2 playback support for PS2. + CLEANUP Split PS2 devices into seperate files. +06-29-2004 2.00.04 SN FIX Changed the ouput path for the object files +06-29-2004 2.00.03 BED RELEASE Releasing to developer site (Beta) +06-28-2004 2.00.03 DES FEATURE Setup lgVid to use the GSI memory functions. +06-23-2004 2.00.02 BED FIX Removed gvSpeex files from PS2 builds +06-22-2004 2.00.01 DES FEATURE Added support for the PS2 EyeToy as an audio capture device. +06-08-2004 2.00.00 DES RELEASE Limited developer release +06-04-2004 2.00.00 DES OTHER Changelog started diff --git a/xrGameSpy/gamespy/Voice2/gv.h b/xrGameSpy/gamespy/Voice2/gv.h new file mode 100644 index 00000000000..ca970462f02 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gv.h @@ -0,0 +1,234 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +/************************ +** GameSpy Voice 2 SDK ** +************************/ + +#ifndef _GV_H_ +#define _GV_H_ + +#include "../common/gsCommon.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +//DEFINES +///////// +#define GV_BYTES_PER_SAMPLE (sizeof(GVSample) / sizeof(GVByte)) +#define GV_BITS_PER_SAMPLE (GV_BYTES_PER_SAMPLE * 8) + +#define GV_DEVICE_NAME_LEN 64 +#define GV_CHANNEL_NAME_LEN 64 + +#define GV_CAPTURE 1 +#define GV_PLAYBACK 2 +#define GV_CAPTURE_AND_PLAYBACK (GV_CAPTURE|GV_PLAYBACK) + +#define GVRate_8KHz 8000 +#define GVRate_16KHz 16000 +//Used by PSP +#define GVRate_11KHz 11025 + +//For backwards compatability +#define GV_SAMPLES_PER_SECOND (gvGetSampleRate()) +#define GV_BYTES_PER_SECOND (gvGetSampleRate() * GV_BYTES_PER_SAMPLE) + +//TYPES +/////// +typedef enum +{ + GVCodecRaw, + GVCodecSuperHighQuality, + GVCodecHighQuality, + GVCodecAverage, + GVCodecLowBandwidth, + GVCodecSuperLowBandwidth +} GVCodec; + +typedef enum +{ + GVHardwareDirectSound, // Win32 + GVHardwarePS2Spu2, // PS2 (System output) + GVHardwarePS2Headset, // PS2 (USB) + GVHardwarePS2Microphone, // PS2 (USB) + GVHardwarePS2Speakers, // PS2 (USB) + GVHardwarePS2Eyetoy, // PS2 (USB) + GVHardwarePS3Headset, // PS3 (USB) + GVHardwarePSPHeadset, // PSP + GVHardwareMacOSX, // MacOSX + GVHardwareCustom // Any +} GVHardwareType; + +typedef enum +{ + GVCaptureModeThreshold, + GVCaptureModePushToTalk +} GVCaptureMode; + +typedef int GVBool; +#define GVFalse 0 +#define GVTrue 1 + +typedef gsi_u8 GVByte; +typedef gsi_i16 GVSample; + +typedef int GVRate; + +#if defined(_PSP) || defined(_PS2) || defined(_PS3) + typedef float GVScalar; // range 0-1 +#else + typedef double GVScalar; // range 0-1 +#endif +typedef gsi_u16 GVFrameStamp; +typedef void * GVDecoderData; +typedef int GVDeviceType; +typedef struct GVIDevice * GVDevice; + +#if defined(GV_CUSTOM_SOURCE_TYPE) +typedef GV_CUSTOM_SOURCE_TYPE GVSource; +#else +typedef int GVSource; +#endif + +#if defined(_WIN32) +typedef GUID GVDeviceID; +#else +typedef int GVDeviceID; +#endif + +typedef struct +{ + GVDeviceID m_id; + gsi_char m_name[GV_DEVICE_NAME_LEN]; + GVDeviceType m_deviceType; + GVDeviceType m_defaultDevice; // not supported on PS2 + GVHardwareType m_hardwareType; +} GVDeviceInfo; + +typedef struct +{ + int m_samplesPerFrame; // number of samples in an unencoded frame + int m_encodedFrameSize; // number of bytes in an encoded frame + + GVBool (* m_newDecoderCallback)(GVDecoderData * data); + void (* m_freeDecoderCallback)(GVDecoderData data); + + void (* m_encodeCallback)(GVByte * out, const GVSample * in); + void (* m_decodeAddCallback)(GVSample * out, const GVByte * in, GVDecoderData data); // adds to output (required) + void (* m_decodeSetCallback)(GVSample * out, const GVByte * in, GVDecoderData data); // sets output (optional) +} GVCustomCodecInfo; + +//GLOBALS +///////// +#if defined(_WIN32) +extern const GVDeviceID GVDefaultCaptureDeviceID; +extern const GVDeviceID GVDefaultPlaybackDeviceID; +#elif defined(_PS2) +extern const GVDeviceID GVPS2Spu2DeviceID; +#endif + +//GENERAL +///////// +#if defined(_WIN32) +GVBool gvStartup(HWND hWnd); +#else +GVBool gvStartup(void); +#endif +void gvCleanup(void); + +void gvThink(void); + +//CODEC +/////// +GVBool gvSetCodec(GVCodec codec); +void gvSetCustomCodec(GVCustomCodecInfo * info); + +void gvGetCodecInfo(int * samplesPerFrame, int * encodedFrameSize, int * bitsPerSecond); + +//SAMPLE RATE +///////////// +void gvSetSampleRate(GVRate sampleRate); +GVRate gvGetSampleRate(void); + +//DEVICES +///////// +int gvListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +#if defined(_WIN32) +GVBool gvRunSetupWizard(GVDeviceID captureDeviceID, GVDeviceID playbackDeviceID); +GVBool gvAreDevicesSetup(GVDeviceID captureDeviceID, GVDeviceID playbackDeviceID); +#endif + +GVDevice gvNewDevice(GVDeviceID deviceID, GVDeviceType type); +void gvFreeDevice(GVDevice device); + +GVBool gvStartDevice(GVDevice device, GVDeviceType type); +void gvStopDevice(GVDevice device, GVDeviceType type); +GVBool gvIsDeviceStarted(GVDevice device, GVDeviceType type); + +void gvSetDeviceVolume(GVDevice device, GVDeviceType type, GVScalar volume); +GVScalar gvGetDeviceVolume(GVDevice device, GVDeviceType type); + +typedef void (* gvUnpluggedCallback)(GVDevice device); +void gvSetUnpluggedCallback(GVDevice device, gvUnpluggedCallback unpluggedCallback); + +typedef void (* gvFilterCallback)(GVDevice device, GVSample * audio, GVFrameStamp frameStamp); +void gvSetFilter(GVDevice device, GVDeviceType type, gvFilterCallback callback); + +//CAPTURE +///////// +// len is both an input and output parameter +GVBool gvCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume); +int gvGetAvailableCaptureBytes(GVDevice device); + +void gvSetCaptureThreshold(GVDevice device, GVScalar threshold); +GVScalar gvGetCaptureThreshold(GVDevice device); + +void gvSetCaptureMode(GVDevice device, GVCaptureMode captureMode); +GVCaptureMode gvGetCaptureMode(GVDevice device); + +void gvSetPushToTalk(GVDevice device, GVBool talkOn); +GVBool gvGetPushToTalk(GVDevice device); + +//PLAYBACK +////////// +void gvPlayPacket(GVDevice device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute); + +GVBool gvIsSourceTalking(GVDevice device, GVSource source); +int gvListTalkingSources(GVDevice device, GVSource sources[], int maxSources); + +void gvSetGlobalMute(GVBool mute); +GVBool gvGetGlobalMute(void); + +//CUSTOM DEVICE +/////////////// +GVDevice gvNewCustomDevice(GVDeviceType type); + +// for both of these, numSamples must be a multiple of the codec's samplesPerFrame +// this ensures that no data needs to be buffered by the SDK +GVBool gvGetCustomPlaybackAudio(GVDevice device, GVSample * audio, int numSamples); +GVBool gvSetCustomCaptureAudio(GVDevice device, const GVSample * audio, int numSamples, + GVByte * packet, int * packetLen, GVFrameStamp * frameStamp, GVScalar * volume); + +//CHANNELS +////////// +int gvGetNumChannels(GVDevice device, GVDeviceType type); +void gvGetChannelName(GVDevice device, GVDeviceType type, int channel, gsi_char name[GV_CHANNEL_NAME_LEN]); +void gvSetChannel(GVDevice device, GVDeviceType type, int channel); +int gvGetChannel(GVDevice device, GVDeviceType type); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvCodec.c b/xrGameSpy/gamespy/Voice2/gvCodec.c new file mode 100644 index 00000000000..f7933b208b5 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvCodec.c @@ -0,0 +1,354 @@ +#include "gvCodec.h" +#include "gvFrame.h" + +#if !defined(GV_NO_DEFAULT_CODEC) + #if defined(_PS2) + #include "gvLogitechPS2Codecs.h" + #elif defined(_PSP) + #include "gvGSM.h" + #else + #include "gvSpeex.h" + #endif +#endif + +/************ +** GLOBALS ** +************/ +#define GVI_RAW_BASE_SAMPLES_PER_FRAME 160 + +/************ +** GLOBALS ** +************/ +int GVISamplesPerFrame; +int GVIBytesPerFrame; +int GVIEncodedFrameSize; +int GVISampleRate; +int GVIBytesPerSecond; +static GVCustomCodecInfo GVICodecInfo; +#if !defined(GV_NO_DEFAULT_CODEC) +static GVBool GVICleanupInternalCodec; +#endif +#ifndef _PSP +static GVBool GVIRawCodec; +#endif + +/************** +** FUNCTIONS ** +**************/ +#if !defined(GV_NO_DEFAULT_CODEC) +static void gviCleanupCodec(void) +{ +#if defined(_PS2) + gviLGCodecCleanup(); +#elif defined(_PSP) + gviGSMCleanup(); +#else + gviSpeexCleanup(); +#endif +} +#endif + +void gviCodecsInitialize(void) +{ + //Set a default sample rate. +#if defined(_PSP) + gviSetSampleRate(GVRate_11KHz); +#else + gviSetSampleRate(GVRate_8KHz); +#endif + +#if !defined(GV_NO_DEFAULT_CODEC) + GVICleanupInternalCodec = GVFalse; +#endif +} + +void gviCodecsCleanup(void) +{ +#if !defined(GV_NO_DEFAULT_CODEC) + if(GVICleanupInternalCodec) + { + gviCleanupCodec(); + GVICleanupInternalCodec = GVFalse; + } +#endif +} + +#if !defined(GV_NO_DEFAULT_CODEC) + +#if defined(_PS2) +static GVBool gviSetInternalCodec(GVCodec codec) +{ + GVCustomCodecInfo info; + const char * name; + + // figure out the name of the codec to use + // goto gvLogitechPS2Codecs.h to see what the quality values mean + if(codec == GVCodecSuperHighQuality) + name = "uLaw"; + else if(codec == GVCodecHighQuality) + name = "G723.24"; + else if(codec == GVCodecAverage) + name = "GSM"; + else if(codec == GVCodecLowBandwidth) + name = "SPEEX"; + else if(codec == GVCodecSuperLowBandwidth) + name = "LPC10"; + else + return GVFalse; + + // init lgCodec + if(!gviLGCodecInitialize(name)) + return GVFalse; + + // setup the info + info.m_samplesPerFrame = gviLGCodecGetSamplesPerFrame(); + info.m_encodedFrameSize = gviLGCodecGetEncodedFrameSize(); + info.m_newDecoderCallback = NULL; + info.m_freeDecoderCallback = NULL; + info.m_encodeCallback = gviLGCodecEncode; + info.m_decodeAddCallback = gviLGCodecDecodeAdd; + info.m_decodeSetCallback = gviLGCodecDecodeSet; + + // set it + gviSetCustomCodec(&info); + + return GVTrue; +} +#elif defined(_PSP) +static GVBool gviSetInternalCodec(GVCodec codec) +{ + GVCustomCodecInfo info; + + // init gsm + if(!gviGSMInitialize()) + return GVFalse; + + // setup the info + info.m_samplesPerFrame = gviGSMGetSamplesPerFrame(); + info.m_encodedFrameSize = gviGSMGetEncodedFrameSize(); + info.m_newDecoderCallback = gviGSMNewDecoder; + info.m_freeDecoderCallback = gviGSMFreeDecoder; + info.m_encodeCallback = gviGSMEncode; + info.m_decodeAddCallback = gviGSMDecodeAdd; + info.m_decodeSetCallback = gviGSMDecodeSet; + + // set it + gviSetCustomCodec(&info); + + GSI_UNUSED(codec); + + return GVTrue; +} +#else +static GVBool gviSetInternalCodec(GVCodec codec) +{ + GVCustomCodecInfo info; + int quality; + + // figure out the quality + // goto gvSpeex.h to see what the quality values mean + if(codec == GVCodecSuperHighQuality) + quality = 10; + else if(codec == GVCodecHighQuality) + quality = 7; + else if(codec == GVCodecAverage) + quality = 4; + else if(codec == GVCodecLowBandwidth) + quality = 2; + else if(codec == GVCodecSuperLowBandwidth) + quality = 1; + else + return GVFalse; + + // init speex + if(!gviSpeexInitialize(quality, GVISampleRate)) + return GVFalse; + + // setup the info + info.m_samplesPerFrame = gviSpeexGetSamplesPerFrame(); + info.m_encodedFrameSize = gviSpeexGetEncodedFrameSize(); + info.m_newDecoderCallback = gviSpeexNewDecoder; + info.m_freeDecoderCallback = gviSpeexFreeDecoder; + info.m_encodeCallback = gviSpeexEncode; + info.m_decodeAddCallback = gviSpeexDecodeAdd; + info.m_decodeSetCallback = gviSpeexDecodeSet; + + // set it + gviSetCustomCodec(&info); + + return GVTrue; +} +#endif + +#endif + +static void gviRawEncode(GVByte * out, const GVSample * in) +{ + GVSample * sampleOut = (GVSample *)out; + int i; + + for(i = 0 ; i < GVISamplesPerFrame; i++) + sampleOut[i] = htons(in[i]); +} + +static void gviRawDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data) +{ + const GVSample * sampleIn = (const GVSample *)in; + int i; + + for(i = 0 ; i < GVISamplesPerFrame; i++) + // Expanded to remove warnings in VS2K5 + out[i] = out[i] + ntohs(sampleIn[i]); + + GSI_UNUSED(data); +} + +static void gviRawDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data) +{ + const GVSample * sampleIn = (const GVSample *)in; + int i; + + for(i = 0 ; i < GVISamplesPerFrame; i++) + out[i] = ntohs(sampleIn[i]); + + GSI_UNUSED(data); +} + +static void gviSetRawCodec(void) +{ + GVCustomCodecInfo info; + memset(&info, 0, sizeof(info)); + // setup the info + if (GVISampleRate == GVRate_8KHz) + info.m_samplesPerFrame = GVI_RAW_BASE_SAMPLES_PER_FRAME; + // need to double the frame size since data has shorter wavelength + else if (GVISampleRate == GVRate_16KHz) + info.m_samplesPerFrame = GVI_RAW_BASE_SAMPLES_PER_FRAME * 2; + + // the samples per frame should be set above + info.m_encodedFrameSize = (info.m_samplesPerFrame * GV_BYTES_PER_SAMPLE); + info.m_newDecoderCallback = NULL; + info.m_freeDecoderCallback = NULL; + info.m_encodeCallback = gviRawEncode; + info.m_decodeAddCallback = gviRawDecodeAdd; + info.m_decodeSetCallback = gviRawDecodeSet; + + // set it + gviSetCustomCodec(&info); +} + +GVBool gviSetCodec(GVCodec codec) +{ +#if !defined(GV_NO_DEFAULT_CODEC) + // cleanup if we need to + if(GVICleanupInternalCodec) + { + gviCleanupCodec(); + GVICleanupInternalCodec = GVFalse; + } +#endif + + // raw codec is handled specially + if(codec == GVCodecRaw) + { + gviSetRawCodec(); + #ifndef _PSP + GVIRawCodec = GVTrue; + #endif + return GVTrue; + } + else + #ifndef _PSP + GVIRawCodec = GVFalse; + #endif + +#if !defined(GV_NO_DEFAULT_CODEC) + // do the actual set (based on which internal codec we are using) + if(!gviSetInternalCodec(codec)) + return GVFalse; + + // clean this up at some point + GVICleanupInternalCodec = GVTrue; + + return GVTrue; +#else + return GVFalse; +#endif +} + +void gviSetCustomCodec(GVCustomCodecInfo * info) +{ + // store the info + memcpy(&GVICodecInfo, info, sizeof(GVCustomCodecInfo)); + GVISamplesPerFrame = info->m_samplesPerFrame; + GVIEncodedFrameSize = info->m_encodedFrameSize; + + // extra info + GVIBytesPerFrame = (GVISamplesPerFrame * (int)GV_BYTES_PER_SAMPLE); + + // frames needs to be initialized with codec info + gviFramesStartup(); +} + +void gviSetSampleRate(GVRate sampleRate) +{ + //Save the sample rate. + GVISampleRate = sampleRate; + GVIBytesPerSecond = GVISampleRate * GV_BYTES_PER_SAMPLE; +} + +GVRate gviGetSampleRate(void) +{ + return GVISampleRate; +} + + +GVBool gviNewDecoder(GVDecoderData * data) +{ + if(!GVICodecInfo.m_newDecoderCallback) + { + *data = NULL; + return GVTrue; + } + + return GVICodecInfo.m_newDecoderCallback(data); +} + +void gviFreeDecoder(GVDecoderData data) +{ + if(GVICodecInfo.m_freeDecoderCallback) + GVICodecInfo.m_freeDecoderCallback(data); +} + +void gviEncode(GVByte * out, const GVSample * in) +{ + GVICodecInfo.m_encodeCallback(out, in); +} + +void gviDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data) +{ + GVICodecInfo.m_decodeAddCallback(out, in, data); +} + +void gviDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data) +{ + if(GVICodecInfo.m_decodeSetCallback) + { + GVICodecInfo.m_decodeSetCallback(out, in, data); + } + else + { + memset(out, 0, GVIBytesPerFrame); + GVICodecInfo.m_decodeAddCallback(out, in, data); + } +} + +void gviResetEncoder(void) +{ +#if !defined(GV_NO_DEFAULT_CODEC) && !defined(_PS2) && !defined(_PSP) + + //If we are using the RawCodec, we have never set up Speex. + if (!GVIRawCodec) + gviSpeexResetEncoder(); +#endif +} diff --git a/xrGameSpy/gamespy/Voice2/gvCodec.h b/xrGameSpy/gamespy/Voice2/gvCodec.h new file mode 100644 index 00000000000..3e9f446a86c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvCodec.h @@ -0,0 +1,47 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_CODEC_H_ +#define _GV_CODEC_H_ + +#include "gvMain.h" + +/************ +** GLOBALS ** +************/ +extern int GVISamplesPerFrame; +extern int GVIBytesPerFrame; +extern int GVIEncodedFrameSize; +extern GVRate GVISampleRate; //In samples per second. +extern int GVIBytesPerSecond; + +/************** +** FUNCTIONS ** +**************/ +void gviCodecsInitialize(void); +void gviCodecsCleanup(void); + +GVBool gviSetCodec(GVCodec codec); +void gviSetCustomCodec(GVCustomCodecInfo * info); + +void gviSetSampleRate(GVRate sampleRate); +GVRate gviGetSampleRate(void); + +GVBool gviNewDecoder(GVDecoderData * data); +void gviFreeDecoder(GVDecoderData data); + +void gviEncode(GVByte * out, const GVSample * in); +void gviDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data); +void gviDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data); + +void gviResetEncoder(void); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvCustomDevice.c b/xrGameSpy/gamespy/Voice2/gvCustomDevice.c new file mode 100644 index 00000000000..b3b869c0cff --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvCustomDevice.c @@ -0,0 +1,385 @@ +#include "gvCustomDevice.h" +#include "gvSource.h" +#include "gvCodec.h" +#include "gvUtil.h" + +#define GVI_DEFAULT_THRESHOLD ((GVScalar)0.0) + +#if defined(_WIN32) +static GVDeviceID GVICustomDeviceID = {0}; +#else +static GVDeviceID GVICustomDeviceID = 0; +#endif + +typedef struct +{ + GVBool m_captureStarted; + GVScalar m_captureThreshold; + GVFrameStamp m_captureClock; + GVFrameStamp m_captureLastCrossedThresholdTime; + GVScalar m_captureVolume; + + GVBool m_playbackStarted; + GVISourceList m_playbackSources; + GVFrameStamp m_playbackClock; + GVScalar m_playbackVolume; +} GVICustomData; + +static void gviCustomFreeDevice(GVIDevice * device) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + if(device->m_types & GV_PLAYBACK) + { + data->m_playbackStarted = GVFalse; + gviFreeSourceList(data->m_playbackSources); + } + if(device->m_types & GV_CAPTURE) + { + data->m_captureStarted = GVFalse; + } + + gviFreeDevice(device); +} + +static GVBool gviCustomStartDevice(GVIDevice * device, GVDeviceType type) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + if(type & GV_PLAYBACK) + { + data->m_playbackStarted = GVTrue; + data->m_playbackClock = 0; + } + if(type & GV_CAPTURE) + { + data->m_captureStarted = GVTrue; + } + return GVTrue; +} + +static void gviCustomStopDevice(GVIDevice * device, GVDeviceType type) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + if(type & GV_PLAYBACK) + { + data->m_playbackStarted = GVFalse; + gviClearSourceList(data->m_playbackSources); + } + if(type & GV_CAPTURE) + { + data->m_captureStarted = GVFalse; + data->m_captureClock++; + } +} + +static GVBool gviCustomIsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + if(type == GV_PLAYBACK) + return data->m_playbackStarted; + else if(type == GV_CAPTURE) + return data->m_captureStarted; + return (data->m_playbackStarted && data->m_captureStarted); +} + +static void gviCustomSetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + if(type & GV_PLAYBACK) + data->m_playbackVolume = volume; + if(type & GV_CAPTURE) + data->m_captureVolume = volume; +} + +static GVScalar gviCustomGetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + if(type & GV_PLAYBACK) + return data->m_playbackVolume; + return data->m_captureVolume; +} + +static void gviCustomSetCaptureThreshold(GVIDevice * device, GVScalar threshold) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + data->m_captureThreshold = threshold; +} + +static GVScalar gviCustomGetCaptureThreshold(GVIDevice * device) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + return data->m_captureThreshold; +} + +static int gviCustomGetAvailableCaptureBytes(GVDevice device) +{ + // not supported with custom devices + assert(0); + GSI_UNUSED(device); + return 0; +} + +static GVBool gviCustomCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + // not supported with custom devices + assert(0); + GSI_UNUSED(device); + GSI_UNUSED(packet); + GSI_UNUSED(len); + GSI_UNUSED(frameStamp); + GSI_UNUSED(volume); + return GVFalse; +} + +static void gviCustomPlayPacket(GVIDevice * device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + // don't do anythying if we're not playing + if(!data->m_playbackStarted) + return; + + gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock); +} + +static GVBool gviCustomIsSourceTalking(GVDevice device, GVSource source) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + // don't do anythying if we're not playing + if(!data->m_playbackStarted) + return GVFalse; + + return gviIsSourceTalking(data->m_playbackSources, source); +} + +static int gviCustomListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + + // don't do anythying if we're not playing + if(!data->m_playbackStarted) + return GVFalse; + + return gviListTalkingSources(data->m_playbackSources, sources, maxSources); +} + +GVDevice gviCustomNewDevice(GVDeviceType type) +{ + GVIDevice * device; + GVICustomData * data; + + // create a new device + device = gviNewDevice(GVICustomDeviceID, GVHardwareCustom, type, sizeof(GVICustomData)); + if(!device) + return NULL; + + // get a pointer to the data + data = (GVICustomData *)device->m_data; + + // store the pointers + device->m_methods.m_freeDevice = gviCustomFreeDevice; + device->m_methods.m_startDevice = gviCustomStartDevice; + device->m_methods.m_stopDevice = gviCustomStopDevice; + device->m_methods.m_isDeviceStarted = gviCustomIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviCustomSetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviCustomGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviCustomSetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviCustomGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviCustomGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviCustomCapturePacket; + device->m_methods.m_playPacket = gviCustomPlayPacket; + device->m_methods.m_isSourceTalking = gviCustomIsSourceTalking; + device->m_methods.m_listTalkingSources = gviCustomListTalkingSources; + + // init the data + if(type & GV_PLAYBACK) + { + // create the array of sources + data->m_playbackSources = gviNewSourceList(); + if(!data->m_playbackSources) + return GVFalse; + + // setup the struct + data->m_playbackStarted = GVFalse; + data->m_playbackClock = 0; + data->m_playbackVolume = 1.0; + } + if(type & GV_CAPTURE) + { + data->m_captureStarted = GVFalse; + data->m_captureThreshold = GVI_DEFAULT_THRESHOLD; + data->m_captureClock = 0; + data->m_captureLastCrossedThresholdTime = (GVFrameStamp)(data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + data->m_captureVolume = 1.0; + } + + return device; +} + +GVBool gviGetCustomPlaybackAudio(GVIDevice * device, GVSample * audio, int numSamples) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + GVBool wroteToBuffer; + int numFrames; + int i; + GVBool result = GVFalse; + + // don't do anythying if we're not playing + if(!data->m_playbackStarted) + return GVFalse; + + // the len must be a multiple of the frame size + assert(!(numSamples % GVISamplesPerFrame)); + + // calc the number of frames + numFrames = (numSamples / GVISamplesPerFrame); + + // fill it + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, + audio, numFrames); + + // check if anything was written + if(!wroteToBuffer) + { + // no, so clear it + memset(audio, 0, numSamples * GV_BYTES_PER_SAMPLE); + } + else + { + // check if we need to adjust the volume + if(data->m_playbackVolume != 1.0) + { + for(i = 0 ; i < numSamples ; i++) + audio[i] = (GVSample)(audio[i] * data->m_playbackVolume); + } + // set the output flag to true because samples were decoded this pass + result = GVTrue; + } + + // filter + if(device->m_playbackFilterCallback) + { + for(i = 0 ; i < numFrames ; i++) + device->m_playbackFilterCallback(device, audio + (GVISamplesPerFrame * i), (GVFrameStamp)(data->m_playbackClock + i)); + } + + // update the clock + // Expanded to remove warnings in VS2K5 + data->m_playbackClock = data->m_playbackClock + (GVFrameStamp)numFrames; + + return result; +} + +GVBool gviSetCustomCaptureAudio(GVDevice device, const GVSample * audio, int numSamples, + GVByte * packet, int * packetLen, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVICustomData * data = (GVICustomData *)device->m_data; + int numBytes; + GVBool overThreshold = GVFalse; + int numFrames; + int i; + int len; + + // store the len + len = *packetLen; + + // clear the len and volume + *packetLen = 0; + if(volume) + *volume = 0; + + // don't do anything if we're not capturing + if(!data->m_captureStarted) + return GVFalse; + + // the len must be a multiple of the frame size + assert(!(numSamples % GVISamplesPerFrame)); + + // set the frameStamp + *frameStamp = data->m_captureClock; + + // figure out the number of frames + numFrames = (numSamples / GVISamplesPerFrame); + + // if audio is NULL, this is simply telling us to advance the clock + if(audio) + { + // get the number of new bytes + numBytes = (int)(numSamples * GV_BYTES_PER_SAMPLE); + + // make sure they have enough space in the packet buffer + assert(len >= numBytes); + if(len < numBytes) + return GVFalse; + + // get the volume if requested + if(volume) + *volume = gviGetSamplesVolume(audio, numSamples); + + // check against the threshold + if(volume) + { + // we already got the volume, so use that to check + overThreshold = (*volume >= data->m_captureThreshold); + } + else + { + // we didn't get a volume, so check the samples directly + overThreshold = gviIsOverThreshold(audio, numSamples, data->m_captureThreshold); + } + + // did the audio cross the threshold? + if(overThreshold) + { + // update the time at which we crossed + data->m_captureLastCrossedThresholdTime = data->m_captureClock; + } + else + { + // check if we are still within the hold time + overThreshold = ((GVFrameStamp)(data->m_captureClock - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + if(overThreshold) + { + // check if we need to adjust the volume + if(data->m_captureVolume != 1.0) + { + for(i = 0 ; i < numSamples ; i++) + ((GVSample *)audio)[i] = (GVSample)(audio[i] * data->m_captureVolume); + } + + // handle the data one frame at a time + for(i = 0 ; i < numFrames ; i++) + { + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, (GVSample *)audio + (i * GVISamplesPerFrame), (GVFrameStamp)(data->m_captureClock + i)); + + // encode the buffer into the packet + gviEncode(packet + (i * GVIEncodedFrameSize), audio + (i * GVISamplesPerFrame)); + } + } + + // set the len + *packetLen = (numFrames * GVIEncodedFrameSize); + } + + // increment the clock + // Expanded to remove warnings in VS2K5 + data->m_captureClock = data->m_captureClock + (GVFrameStamp)numFrames; + + // return false if we didn't get a packet + if(!overThreshold) + return GVFalse; + + return GVTrue; +} diff --git a/xrGameSpy/gamespy/Voice2/gvCustomDevice.h b/xrGameSpy/gamespy/Voice2/gvCustomDevice.h new file mode 100644 index 00000000000..d0818844295 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvCustomDevice.h @@ -0,0 +1,25 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_CUSTOM_DEVICE_H_ +#define _GV_CUSTOM_DEVICE_H_ + +#include "gvMain.h" +#include "gvDevice.h" + +GVDevice gviCustomNewDevice(GVDeviceType type); + +GVBool gviGetCustomPlaybackAudio(GVIDevice * device, GVSample * audio, int numSamples); + +GVBool gviSetCustomCaptureAudio(GVDevice device, const GVSample * audio, int numSamples, + GVByte * packet, int * packetLen, GVFrameStamp * frameStamp, GVScalar * volume); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvDevice.c b/xrGameSpy/gamespy/Voice2/gvDevice.c new file mode 100644 index 00000000000..792f26de3fb --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvDevice.c @@ -0,0 +1,114 @@ +#include "gvDevice.h" + +/*********** +** DEVICE ** +***********/ +GVIDevice * gviNewDevice(GVDeviceID deviceID, GVHardwareType hardwareType, GVDeviceType types, int dataSize) +{ + GVIDevice * device; + + device = (GVIDevice *)gsimalloc(sizeof(GVIDevice)); + if(!device) + return NULL; + + memset(device, 0, sizeof(GVIDevice)); + memcpy(&device->m_deviceID, &deviceID, sizeof(GVDeviceID)); + device->m_hardwareType = hardwareType; + device->m_types = types; + device->m_data = gsimalloc((unsigned int)dataSize); + if(!device->m_data) + { + gsifree(device); + return NULL; + } + memset(device->m_data, 0, (unsigned int)dataSize); + + return device; +} + +void gviFreeDevice(GVIDevice * device) +{ + gsifree(device->m_data); + gsifree(device); +} + +void gviDeviceUnplugged(GVIDevice * device) +{ + // if they don't have a callback, we can't free the device without them knowing + if(!device->m_unpluggedCallback) + return; + + // let them know it was unplugged... + device->m_unpluggedCallback(device); + + // ...then free the device + device->m_methods.m_freeDevice(device); +} + +/**************** +** DEVICE LIST ** +****************/ +static int gviFindDeviceIndex(GVIDeviceList devices, GVIDevice * device) +{ + int len; + int i; + + assert(devices); + + len = ArrayLength(devices); + for(i = 0 ; i < len ; i++) + { + if(device == gviGetDevice(devices, i)) + return i; + } + + return -1; +} + +GVIDeviceList gviNewDeviceList(ArrayElementFreeFn elemFreeFn) +{ + return ArrayNew(sizeof(GVIDevice *), 2, elemFreeFn); +} + +void gviFreeDeviceList(GVIDeviceList devices) +{ + assert(devices); + + ArrayFree(devices); +} + +void gviAppendDeviceToList(GVIDeviceList devices, GVIDevice * device) +{ + assert(devices); + + ArrayAppend(devices, &device); +} + +void gviDeleteDeviceFromList(GVIDeviceList devices, GVIDevice * device) +{ + int index; + + assert(devices); + + // find the device + index = gviFindDeviceIndex(devices, device); + if(index == -1) + return; + + // delete it from the array + ArrayDeleteAt(devices, index); +} + +int gviGetNumDevices(GVIDeviceList devices) +{ + assert(devices); + + return ArrayLength(devices); +} + +GVIDevice * gviGetDevice(GVIDeviceList devices, int index) +{ + assert(devices); + + return *(GVIDevice **)ArrayNth(devices, index); +} diff --git a/xrGameSpy/gamespy/Voice2/gvDevice.h b/xrGameSpy/gamespy/Voice2/gvDevice.h new file mode 100644 index 00000000000..9832a203ada --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvDevice.h @@ -0,0 +1,90 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_DEVICE_H_ +#define _GV_DEVICE_H_ + +#include "gvMain.h" + +// amount of time to keep capturing even after voice drops below the capture threshold +// makes sure that speech that trails off, or slightly dips in volume, is still captured +#define GVI_HOLD_THRESHOLD_FRAMES 20 + +// buffer sizes for capture and playback +#define GVI_PLAYBACK_BUFFER_MILLISECONDS 200 +#define GVI_CAPTURE_BUFFER_MILLISECONDS 1000 + +/*********** +** DEVICE ** +***********/ +typedef struct +{ + void (* m_freeDevice)(GVDevice device); + + GVBool (* m_startDevice)(GVDevice device, GVDeviceType type); + void (* m_stopDevice)(GVDevice device, GVDeviceType type); + GVBool (* m_isDeviceStarted)(GVDevice device, GVDeviceType type); + + void (* m_setDeviceVolume)(GVDevice device, GVDeviceType type, GVScalar volume); + GVScalar (* m_getDeviceVolume)(GVDevice device, GVDeviceType type); + + void (* m_setCaptureThreshold)(GVDevice device, GVScalar threshold); + GVScalar (* m_getCaptureThreshold)(GVDevice device); + + GVBool (*m_capturePacket)(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume); + int (* m_getAvailableCaptureBytes)(GVDevice device); + + void (* m_playPacket)(GVDevice device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute); + + GVBool (* m_isSourceTalking)(GVDevice device, GVSource source); + int (* m_listTalkingSources)(GVDevice device, GVSource sources[], int maxSources); + + int (* m_getNumChannels)(GVDevice device, GVDeviceType type); + void (* m_getChannelName)(GVDevice device, GVDeviceType type, int channel, gsi_char name[GV_CHANNEL_NAME_LEN]); + + void (* m_setChannel)(GVDevice device, GVDeviceType type, int channel); + int (* m_getChannel)(GVDevice device, GVDeviceType type); +} GVIDeviceMethods; + +typedef struct GVIDevice +{ + GVDeviceID m_deviceID; + GVHardwareType m_hardwareType; + GVDeviceType m_types; + GVIDeviceMethods m_methods; + gvUnpluggedCallback m_unpluggedCallback; + gvFilterCallback m_captureFilterCallback; + gvFilterCallback m_playbackFilterCallback; + void * m_data; + GVCaptureMode m_captureMode; + GVScalar m_savedCaptureThreshold; +} GVIDevice; + +GVIDevice * gviNewDevice(GVDeviceID deviceID, GVHardwareType hardwareType, GVDeviceType types, int dataSize); +void gviFreeDevice(GVIDevice * device); + +void gviDeviceUnplugged(GVIDevice * device); + +/**************** +** DEVICE LIST ** +****************/ +typedef DArray GVIDeviceList; + +GVIDeviceList gviNewDeviceList(ArrayElementFreeFn elemFreeFn); +void gviFreeDeviceList(GVIDeviceList devices); + +void gviAppendDeviceToList(GVIDeviceList devices, GVIDevice * device); +void gviDeleteDeviceFromList(GVIDeviceList devices, GVIDevice * device); + +int gviGetNumDevices(GVIDeviceList devices); +GVIDevice * gviGetDevice(GVIDeviceList devices, int index); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvDirectSound.c b/xrGameSpy/gamespy/Voice2/gvDirectSound.c new file mode 100644 index 00000000000..86ca0b2b7d9 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvDirectSound.c @@ -0,0 +1,1067 @@ +#include +#include +#include "gvDirectSound.h" +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#pragma warning(disable:4201) +#include +#include +#if (DIRECTSOUND_VERSION == 0x0800) +#include +#endif + +#if !defined(_WIN32) +#error This file should only be used with Windows +#endif + +/************ +** DEFINES ** +************/ +// GUID utility macros +#define GVI_GUID_COPY(dest, src) memcpy((dest), (src), sizeof(GUID)) + +// these were copied from dsound.h +const GUID GVDefaultPlaybackDeviceID = {0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03}; +const GUID GVDefaultCaptureDeviceID = {0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03}; + +/********** +** TYPES ** +**********/ +typedef struct +{ + GVBool m_playing; + LPDIRECTSOUND m_playback; + LPDIRECTSOUNDBUFFER m_playbackBuffer; + DWORD m_playbackBufferSize; + DWORD m_playbackBufferHalfSize; + DWORD m_playbackBufferPosition; + GVFrameStamp m_playbackClock; + GVISourceList m_playbackSources; + gsi_time m_playbackLastThink; + + GVBool m_capturing; + LPDIRECTSOUNDCAPTURE m_capture; + LPDIRECTSOUNDCAPTUREBUFFER m_captureBuffer; + DWORD m_captureBufferSize; + DWORD m_captureBufferPosition; + GVScalar m_captureVolume; + GVFrameStamp m_captureClock; + GVScalar m_captureThreshold; + GVFrameStamp m_captureLastCrossedThresholdTime; +} GVIHardwareData; + +typedef struct +{ + GVDeviceInfo * m_devices; + int m_len; + int m_num; + GVBool m_enumeratingCapture; +} GVIEnumDevicesInfo; + +/************ +** GLOBALS ** +************/ +static HWND GVIHwnd; +static GVIDeviceList GVIDevices; +static WAVEFORMATEX GVIWaveFormat; +static GVBool GVICleanupCOM; + +/************** +** FUNCTIONS ** +**************/ +static void gviFreeArrayDevice(void * elem) +{ + GVIDevice * device = *(GVIDevice **)elem; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(device->m_types == GV_PLAYBACK) + { + if(data->m_playbackSources) + gviFreeSourceList(data->m_playbackSources); + if(data->m_playbackBuffer) + IDirectSoundBuffer_Release(data->m_playbackBuffer); + if(data->m_playback) + IDirectSound_Release(data->m_playback); + } + else + { + if(data->m_captureBuffer) + { + IDirectSoundCaptureBuffer_Stop(data->m_captureBuffer); + IDirectSoundCaptureBuffer_Release(data->m_captureBuffer); + } + if(data->m_capture) + IDirectSoundCapture_Release(data->m_capture); + } + + gviFreeDevice(device); +} + +GVBool gviHardwareStartup(HWND hWnd) +{ + HRESULT result; + + // check the hwnd + if(!hWnd) + { + hWnd = GetForegroundWindow(); + if(!hWnd) + hWnd = GetDesktopWindow(); + } + + // store it + GVIHwnd = hWnd; + + // create the devices array + GVIDevices = gviNewDeviceList(gviFreeArrayDevice); + if(!GVIDevices) + return GVFalse; + + // init COM + assert(GVICleanupCOM == GVFalse); + result = CoInitialize(NULL); + if(SUCCEEDED(result)) + GVICleanupCOM = GVTrue; + + return GVTrue; +} + +void gviHardwareCleanup(void) +{ + // cleanup the devices + if(GVIDevices) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + } + + // cleanup COM + if(GVICleanupCOM == GVTrue) + { + CoUninitialize(); + GVICleanupCOM = GVFalse; + } +} + +static GVBool gviPlaybackDeviceThink(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + HRESULT result; + DWORD lockPosition; + LPVOID audioPtr1, audioPtr2; + DWORD audioLen1, audioLen2; + GVBool wroteToBuffer; + DWORD newBytes; + DWORD rawPlayCursor; + DWORD playCursor; + DWORD writeCursor; + gsi_time now; + int diff; + int numFrames; + int i; + + // don't do anythying if we're not playing + if(!data->m_playing) + return GVTrue; + + // get the current position + result = IDirectSoundBuffer_GetCurrentPosition(data->m_playbackBuffer, &rawPlayCursor, &writeCursor); + if(FAILED(result)) + return GVFalse; + + // we only want to deal with whole frames + playCursor = (DWORD)gviRoundDownToNearestMultiple((int)rawPlayCursor, GVIBytesPerFrame); + + // get the number of new bytes + newBytes = (((playCursor + data->m_playbackBufferSize) - data->m_playbackBufferPosition) % data->m_playbackBufferSize); + + // before we store the new position, save the old one + lockPosition = data->m_playbackBufferPosition; + + // store the new position + data->m_playbackBufferPosition = playCursor; + + // figure out how long it has been since out last think + now = current_time(); + diff = (int)(now - data->m_playbackLastThink); + data->m_playbackLastThink = now; + + // adjust the time based on the number of new samples we know about + diff -= gviDivideByBytesPerMillisecond(newBytes); + + // adjust again based on the raw play cursor + // because newBytes is based on an adjusted play cursor + diff -= (rawPlayCursor - playCursor); + + // diff should now be approximately 0 + // if it is closer to a multiple of the buffer length (in ms), + // that is because we have missed at least one loop through the buffer + // we use half of the buffer size because it is half way between + // what we expect and what we are checking for + if(diff >= gviDivideByBytesPerMillisecond((int)data->m_playbackBufferHalfSize)) + { + int numMissedLoops; + int numMissedFrames; + int msPerBuffer = gviDivideByBytesPerMillisecond((int)data->m_playbackBufferSize); + + // estimate how many loops we missed + numMissedLoops = (gviRoundToNearestMultiple(diff, msPerBuffer) / msPerBuffer); + + // convert to frames + numMissedFrames = (numMissedLoops * (data->m_playbackBufferSize / GVIBytesPerFrame)); + + // adjust the clock + // Expanded to remove warnings in VS2K5 + data->m_playbackClock = data->m_playbackClock + (GVFrameStamp)(numMissedFrames); + } + + // if we don't have any new bytes, there's nothing to do + if(newBytes == 0) + return GVTrue; + + // lock the appropriate half of the playback buffer + result = IDirectSoundBuffer_Lock(data->m_playbackBuffer, lockPosition, newBytes, &audioPtr1, &audioLen1, &audioPtr2, &audioLen2, 0); + if(FAILED(result)) + return GVFalse; + + // fill it + numFrames = (audioLen1 / GVIBytesPerFrame); + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, (GVSample *)audioPtr1, numFrames); + if(!wroteToBuffer) + memset(audioPtr1, 0, audioLen1); + + // filter + if(device->m_playbackFilterCallback) + { + for(i = 0 ; i < numFrames ; i++) + device->m_playbackFilterCallback(device, (GVSample *)audioPtr1 + (GVISamplesPerFrame * i), (GVFrameStamp)(data->m_playbackClock + i)); + } + + // update the clock + // Expanded to remove warnings in VS2K5 + data->m_playbackClock = data->m_playbackClock + (GVFrameStamp)numFrames; + + // do the same for the second pointer, if it is set + if(audioPtr2) + { + // fill it + numFrames = (audioLen2 / GVIBytesPerFrame); + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, (GVSample *)audioPtr2, numFrames); + if(!wroteToBuffer) + memset(audioPtr2, 0, audioLen2); + + // filter + if(device->m_playbackFilterCallback) + { + for(i = 0 ; i < numFrames ; i++) + device->m_playbackFilterCallback(device, (GVSample *)audioPtr2 + (GVISamplesPerFrame * i), (GVFrameStamp)(data->m_playbackClock + i)); + } + + // update the clock + // Expanded to remove warnings in VS2K5 + data->m_playbackClock = data->m_playbackClock + (GVFrameStamp)numFrames; + } + + // unlock the buffer + result = IDirectSoundBuffer_Unlock(data->m_playbackBuffer, audioPtr1, audioLen1, audioPtr2, audioLen2); + if(FAILED(result)) + return GVFalse; + + return GVTrue; +} + +void gviHardwareThink(void) +{ + GVIDevice * device; + GVBool rcode; + int num; + int i; + + if(!GVIDevices) + return; + + // loop through backwards so that we can remove devices as we go + num = gviGetNumDevices(GVIDevices); + for(i = (num - 1) ; i >= 0 ; i--) + { + // get the device + device = gviGetDevice(GVIDevices, i); + + // check if this is a playback device + if(device->m_types == GV_PLAYBACK) + { + // let it think + rcode = gviPlaybackDeviceThink(device); + + // check if the device was unplugged + if(!rcode) + gviDeviceUnplugged(device); + } + } +} + +#if !defined(GSI_UNICODE) + static BOOL CALLBACK gviEnumDevicesCallback(LPGUID lpGuid, LPCSTR desc, LPCSTR module, LPVOID lpContext) +#else + static BOOL CALLBACK gviEnumDevicesCallback(LPGUID lpGuid, LPCWSTR desc, LPCWSTR module, LPVOID lpContext) +#endif +{ + if(lpGuid != NULL) + { + GVIEnumDevicesInfo * info = (GVIEnumDevicesInfo *)lpContext; + GVDeviceInfo * device = NULL; + int i; + + // first check if it is already in the list + for(i = 0 ; i < info->m_num ; i++) + { + if(IsEqualGUID(&info->m_devices[i].m_id, lpGuid)) + device = &info->m_devices[i]; + } + + if(!device) + { + // if not, add it + device = &info->m_devices[info->m_num++]; + + // clear it + memset(device, 0, sizeof(GVDeviceInfo)); + + // store the ID and name + GVI_GUID_COPY(&device->m_id, lpGuid); + _tcsncpy(device->m_name, desc, GV_DEVICE_NAME_LEN); + device->m_name[GV_DEVICE_NAME_LEN - 1] = '\0'; + } + + // store if it is a cap or playback device + if(info->m_enumeratingCapture) + device->m_deviceType = GV_CAPTURE; + else + device->m_deviceType = GV_PLAYBACK; + + // directsound device + device->m_hardwareType = GVHardwareDirectSound; + + // check for full list + if(info->m_num == info->m_len) + return FALSE; + } + GSI_UNUSED(module); + return TRUE; +} + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ +#if DIRECTSOUND_VERSION >= 0x0800 + GUID defaultCaptureDevice; + GUID defaultPlaybackDevice; +#endif + GVIEnumDevicesInfo info; + int i; + + // make sure there is space for at least one device + if(maxDevices < 1) + return 0; + + // enumerate capture and playback devices + info.m_devices = devices; + info.m_len = maxDevices; + info.m_num = 0; + if(types & GV_CAPTURE) + { + info.m_enumeratingCapture = GVTrue; +#if !defined(GSI_UNICODE) + DirectSoundCaptureEnumerateA(gviEnumDevicesCallback, &info); +#else + DirectSoundCaptureEnumerateW(gviEnumDevicesCallback, &info); +#endif + } + if(types & GV_PLAYBACK) + { + info.m_enumeratingCapture = GVFalse; +#if !defined(GSI_UNICODE) + DirectSoundEnumerateA(gviEnumDevicesCallback, &info); +#else + DirectSoundEnumerateW(gviEnumDevicesCallback, &info); +#endif + } + +#if DIRECTSOUND_VERSION >= 0x0800 + // check for the default capture and playback devices + GetDeviceID(&DSDEVID_DefaultVoiceCapture, &defaultCaptureDevice); + GetDeviceID(&DSDEVID_DefaultVoicePlayback, &defaultPlaybackDevice); + for(i = 0 ; i < info.m_num ; i++) + { + if(IsEqualGUID(&devices[i].m_id, &defaultCaptureDevice)) + devices[i].m_defaultDevice = GV_CAPTURE; + else if(IsEqualGUID(&devices[i].m_id, &defaultPlaybackDevice)) + devices[i].m_defaultDevice = GV_PLAYBACK; + } +#else + for(i = 0 ; i < info.m_num ; i++) + { + devices[i].m_defaultDevice = (GVDeviceType)0; + } +#endif + + return info.m_num; +} + +static void gviHardwareFreeDevice(GVIDevice * device) +{ + // delete it from the array + // it will clear out internal data in the array's free function + gviDeleteDeviceFromList(GVIDevices, device); +} + +static GVBool gviStartPlaybackDevice(GVIHardwareData * data) +{ + HRESULT result; + LPVOID audioPtr1, audioPtr2; + DWORD audioLen1, audioLen2; + + // make sure the device is stopped + IDirectSoundBuffer_Stop(data->m_playbackBuffer); + + // lock the buffer + result = IDirectSoundBuffer_Lock(data->m_playbackBuffer, 0, 0, &audioPtr1, &audioLen1, &audioPtr2, &audioLen2, DSBLOCK_ENTIREBUFFER); + if(FAILED(result)) + return GVFalse; + + // clear it + memset(audioPtr1, 0, audioLen1); + + // unlock the buffer + result = IDirectSoundBuffer_Unlock(data->m_playbackBuffer, audioPtr1, audioLen1, audioPtr2, audioLen2); + if(FAILED(result)) + return GVFalse; + + // reset the position + result = IDirectSoundBuffer_SetCurrentPosition(data->m_playbackBuffer, 0); + if(FAILED(result)) + return GVFalse; + + // start the buffer + result = IDirectSoundBuffer_Play(data->m_playbackBuffer, 0, 0, DSBPLAY_LOOPING); + if(FAILED(result)) + return GVFalse; + + // clear the playback clocks + data->m_playbackClock = 0; + + // init the think time + data->m_playbackLastThink = current_time(); + + // started playing + data->m_playing = GVTrue; + + return GVTrue; +} + +static GVBool gviStartCaptureDevice(GVIHardwareData * data) +{ + // started capturing + data->m_capturing = GVTrue; + + return GVTrue; +} + +static GVBool gviHardwareStartDevice(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type == GV_PLAYBACK) + return gviStartPlaybackDevice(data); + return gviStartCaptureDevice(data); +} + +static void gviStopPlaybackDevice(GVIHardwareData * data) +{ + // stop the playback buffer + IDirectSoundBuffer_Stop(data->m_playbackBuffer); + + // stopped playing + data->m_playing = GVFalse; + + // clear any pending sources & buffers + gviClearSourceList(data->m_playbackSources); +} + +static void gviStopCaptureDevice(GVIHardwareData * data) +{ + // stopped capturing + data->m_capturing = GVFalse; + + // reset the encoder's state + gviResetEncoder(); +} + +static void gviHardwareStopDevice(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type == GV_PLAYBACK) + gviStopPlaybackDevice(data); + else + gviStopCaptureDevice(data); +} + +static GVBool gviIsPlaybackDeviceStarted(GVIHardwareData * data) +{ + HRESULT result; + DWORD status; + + result = IDirectSoundBuffer_GetStatus(data->m_playbackBuffer, &status); + if(FAILED(result)) + return GVFalse; + + if(status & DSBSTATUS_PLAYING) + return GVTrue; + return GVFalse; +} + +static GVBool gviIsCaptureDeviceStarted(GVIHardwareData * data) +{ + return data->m_capturing; +} + +static GVBool gviHardwareIsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type == GV_PLAYBACK) + return gviIsPlaybackDeviceStarted(data); + return gviIsCaptureDeviceStarted(data); +} + +static void gviSetPlaybackDeviceVolume(GVIHardwareData * data, GVScalar volume) +{ + LONG vol; + + // convert from our scale to DS's scale + if(volume == 0.0) + vol = -10000; + else + vol = (LONG)(log(volume) * 2000); + + // set the volume + IDirectSoundBuffer_SetVolume(data->m_playbackBuffer, vol); +} + +static void gviSetCaptureDeviceVolume(GVIHardwareData * data, GVScalar volume) +{ + data->m_captureVolume = volume; +} + +static void gviHardwareSetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type == GV_PLAYBACK) + gviSetPlaybackDeviceVolume(data, volume); + else + gviSetCaptureDeviceVolume(data, volume); +} + +static GVScalar gviGetPlaybackDeviceVolume(GVIHardwareData * data) +{ + HRESULT result; + LONG vol; + + // get the volume + result = IDirectSoundBuffer_GetVolume(data->m_playbackBuffer, &vol); + if(FAILED(result)) + return (GVScalar)0; + + // convert it to our format + return (GVScalar)(exp(vol / 2000.0)); +} + +static GVScalar gviGetCaptureDeviceVolume(GVIHardwareData * data) +{ + return data->m_captureVolume; +} + +static GVScalar gviHardwareGetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type == GV_PLAYBACK) + return gviGetPlaybackDeviceVolume(data); + return gviGetCaptureDeviceVolume(data); +} + +static void gviHardwareSetCaptureThreshold(GVIDevice * device, GVScalar threshold) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + data->m_captureThreshold = threshold; +} + +static GVScalar gviHardwareGetCaptureThreshold(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + return data->m_captureThreshold; +} + +static int gviHardwareGetAvailableCaptureBytes(GVDevice device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + HRESULT result; + DWORD readPosition; + DWORD newBytes; + int numFrames; + + // get the current position + result = IDirectSoundCaptureBuffer_GetCurrentPosition(data->m_captureBuffer, NULL, &readPosition); + if(FAILED(result)) + { + gviDeviceUnplugged(device); + return 0; + } + + // get the number of new bytes + newBytes = (((readPosition + data->m_captureBufferSize) - data->m_captureBufferPosition) % data->m_captureBufferSize); + + // figure out how many frames this is + numFrames = (newBytes / GVIBytesPerFrame); + + // calculate how many bytes this is once encoded + newBytes = (numFrames * GVIEncodedFrameSize); + + return newBytes; +} + +static GVBool gviHardwareCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + HRESULT result; + DWORD readPosition; + DWORD newBytes; + LPVOID audioPtr1, audioPtr2; + GVSample * audioPtr; + DWORD audioLen, audioLen1, audioLen2; + GVBool overThreshold = GVFalse; + int numFrames; + int i, j; + int lenAvailable; + int framesAvailable; + + // figure out how many encoded bytes they can handle + lenAvailable = *len; + + // clear the len and volume + *len = 0; + if(volume) + *volume = 0; + + // get the current position + result = IDirectSoundCaptureBuffer_GetCurrentPosition(data->m_captureBuffer, NULL, &readPosition); + if(FAILED(result)) + { + gviDeviceUnplugged(device); + return GVFalse; + } + + // get the number of new bytes + newBytes = (((readPosition + data->m_captureBufferSize) - data->m_captureBufferPosition) % data->m_captureBufferSize); + + // figure out how many frames this is + numFrames = (newBytes / GVIBytesPerFrame); + + // figure out how many frames they can handle + framesAvailable = (lenAvailable / GVIEncodedFrameSize); + + // don't give them more frames than they can handle + numFrames = min(numFrames, framesAvailable); + if(!numFrames) + return GVFalse; + + // round off the bytes to a frame boundary + newBytes = (numFrames * GVIBytesPerFrame); + + // only do this part if we are capturing + if(data->m_capturing) + { + // lock the buffer + result = IDirectSoundCaptureBuffer_Lock(data->m_captureBuffer, data->m_captureBufferPosition, newBytes, &audioPtr1, &audioLen1, &audioPtr2, &audioLen2, 0); + if(FAILED(result)) + { + gviDeviceUnplugged(device); + return GVFalse; + } + + // get the volume if requested + if(volume) + { + GVScalar vol1 = gviGetSamplesVolume(audioPtr1, audioLen1 / GV_BYTES_PER_SAMPLE); + GVScalar vol2 = gviGetSamplesVolume(audioPtr2, audioLen2 / GV_BYTES_PER_SAMPLE); + *volume = max(vol1, vol2); + } + + // check against the threshold + if(volume) + { + // we already got the volume, so use that to check + overThreshold = (*volume >= data->m_captureThreshold); + } + else + { + // we didn't get a volume, so check the samples directly + overThreshold = gviIsOverThreshold(audioPtr1, audioLen1 / GV_BYTES_PER_SAMPLE, data->m_captureThreshold); + + // if not over threshold, and there is a second portion of audio, check it + if(!overThreshold && audioPtr2) + overThreshold = gviIsOverThreshold(audioPtr2, audioLen2 / GV_BYTES_PER_SAMPLE, data->m_captureThreshold); + } + + // did the audio cross the threshold? + if(overThreshold) + { + // update the time at which we crossed + data->m_captureLastCrossedThresholdTime = data->m_captureClock; + } + else + { + // check if we are still within the hold time + overThreshold = ((GVFrameStamp)(data->m_captureClock - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + if(overThreshold) + { + // store the frameStamp + *frameStamp = data->m_captureClock; + + // setup the starting audio pointer and len + audioPtr = audioPtr1; + audioLen = audioLen1; + + // handle the data one frame at a time + for(i = 0 ; i < numFrames ; i++) + { + // scale the data + if(data->m_captureVolume < 1.0) + { + for(j = 0 ; j < GVISamplesPerFrame ; j++) + audioPtr[j] = (GVSample)(audioPtr[j] * data->m_captureVolume); + } + + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, audioPtr, (GVFrameStamp)(data->m_captureClock + i)); + + // encode the buffer into the packet + gviEncode(packet + (GVIEncodedFrameSize * i), audioPtr); + + // update the loop info as needed + if(audioLen > (DWORD)GVIBytesPerFrame) + { + audioPtr += GVISamplesPerFrame; + audioLen -= GVIBytesPerFrame; + } + else + { + audioPtr = (GVSample*)audioPtr2; + audioLen = audioLen2; + } + } + } + + // unlock the buffer + result = IDirectSoundCaptureBuffer_Unlock(data->m_captureBuffer, audioPtr1, audioLen1, audioPtr2, audioLen2); + if(FAILED(result)) + { + gviDeviceUnplugged(device); + return GVFalse; + } + } + + // set the new position + data->m_captureBufferPosition += newBytes; + data->m_captureBufferPosition %= data->m_captureBufferSize; + + // increment the clock + // Expanded to remove warnings in VS2K5 + data->m_captureClock = data->m_captureClock + (GVFrameStamp)numFrames; + + // set the len + *len = (numFrames * GVIEncodedFrameSize); + + // return false if we didn't get a packet + if(!overThreshold) + return GVFalse; + + return GVTrue; +} + +static void gviHardwarePlayPacket(GVIDevice * device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // don't do anythying if we're not playing + if(!data->m_playing) + return; + + //add it + gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock); +} + +static GVBool gviHardwareIsSourceTalking(GVDevice device, GVSource source) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // don't do anythying if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviIsSourceTalking(data->m_playbackSources, source); +} + +static int gviHardwareListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // don't do anythying if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviListTalkingSources(data->m_playbackSources, sources, maxSources); +} + +static GVBool gviInitPlaybackDevice(GVIHardwareData * data) +{ + HRESULT result; + DSBUFFERDESC bufferDescriptor; + + // set the cooperative level + result = IDirectSound_SetCooperativeLevel(data->m_playback, GVIHwnd, DSSCL_NORMAL); + if(FAILED(result)) + return GVFalse; + + // setup the buffer size + data->m_playbackBufferSize = gviMultiplyByBytesPerMillisecond(GVI_PLAYBACK_BUFFER_MILLISECONDS); + + // make sure it is a multiple of twice the raw frame size + // it needs to be twice the size because it will be split in two + data->m_playbackBufferSize = gviRoundUpToNearestMultiple(data->m_playbackBufferSize, GVIBytesPerFrame * 2); + + // we use this a lot, so calc it here + data->m_playbackBufferHalfSize = (data->m_playbackBufferSize / 2); + + // set up the buffer descriptor + memset(&bufferDescriptor, 0, sizeof(DSBUFFERDESC)); + bufferDescriptor.dwSize = sizeof(DSBUFFERDESC); + bufferDescriptor.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_GETCURRENTPOSITION2; +#if !defined(GV_NO_GLOBAL_FOCUS) + bufferDescriptor.dwFlags |= DSBCAPS_GLOBALFOCUS; +#endif + bufferDescriptor.dwBufferBytes = (DWORD)data->m_playbackBufferSize; + bufferDescriptor.lpwfxFormat = &GVIWaveFormat; + + // create the buffer + result = IDirectSound_CreateSoundBuffer(data->m_playback, &bufferDescriptor, &data->m_playbackBuffer, NULL); + if(FAILED(result)) + return GVFalse; + + return GVTrue; +} + +static GVBool gviInitCaptureDevice(GVIHardwareData * data) +{ + HRESULT result; + DSCBUFFERDESC bufferDescriptor; + + // setup the buffer size + data->m_captureBufferSize = gviMultiplyByBytesPerMillisecond(GVI_CAPTURE_BUFFER_MILLISECONDS); + + // make sure it is a multiple of the raw frame size + data->m_captureBufferSize = gviRoundUpToNearestMultiple(data->m_captureBufferSize, GVIBytesPerFrame); + + // setup the buffer descriptor + memset(&bufferDescriptor, 0, sizeof(bufferDescriptor)); + bufferDescriptor.dwSize = sizeof(DSCBUFFERDESC); + bufferDescriptor.dwBufferBytes = (DWORD)data->m_captureBufferSize; + bufferDescriptor.lpwfxFormat = &GVIWaveFormat; + + // create the buffer + result = IDirectSoundCapture_CreateCaptureBuffer(data->m_capture, &bufferDescriptor, &data->m_captureBuffer, NULL); + if(FAILED(result)) + return GVFalse; + + // start the buffer + result = IDirectSoundCaptureBuffer_Start(data->m_captureBuffer, DSCBSTART_LOOPING); + if(FAILED(result)) + { + IDirectSoundCaptureBuffer_Release(data->m_captureBuffer); + data->m_captureBuffer = NULL; + return GVFalse; + } + + return GVTrue; +} + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVIHardwareData * data; + HRESULT result; + + // DS can only handle one type or the other + if((type != GV_CAPTURE) && (type != GV_PLAYBACK)) + return NULL; + + //setup the wave format + memset(&GVIWaveFormat, 0, sizeof(WAVEFORMATEX)); + GVIWaveFormat.wFormatTag = WAVE_FORMAT_PCM; + GVIWaveFormat.nChannels = 1; + GVIWaveFormat.nSamplesPerSec = GVISampleRate; + GVIWaveFormat.wBitsPerSample = GV_BITS_PER_SAMPLE; + GVIWaveFormat.nBlockAlign = ((GVIWaveFormat.nChannels * GVIWaveFormat.wBitsPerSample) / 8); + GVIWaveFormat.nAvgBytesPerSec = (GVIWaveFormat.nSamplesPerSec * GVIWaveFormat.nBlockAlign); + + + // create a new device + device = gviNewDevice(deviceID, GVHardwareDirectSound, type, sizeof(GVIHardwareData)); + if(!device) + return NULL; + + // get a pointer to the data + data = (GVIHardwareData *)device->m_data; + + // store the pointers + device->m_methods.m_freeDevice = gviHardwareFreeDevice; + device->m_methods.m_startDevice = gviHardwareStartDevice; + device->m_methods.m_stopDevice = gviHardwareStopDevice; + device->m_methods.m_isDeviceStarted = gviHardwareIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviHardwareSetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviHardwareGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviHardwareSetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviHardwareGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviHardwareGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviHardwareCapturePacket; + device->m_methods.m_playPacket = gviHardwarePlayPacket; + device->m_methods.m_isSourceTalking = gviHardwareIsSourceTalking; + device->m_methods.m_listTalkingSources = gviHardwareListTalkingSources; + + // check if they want to init playback + if(type == GV_PLAYBACK) + { + // create the array of sources + data->m_playbackSources = gviNewSourceList(); + if(!data->m_playbackSources) + { + gviFreeDevice(device); + return NULL; + } + + // create the interface + result = DirectSoundCreate(&deviceID, &data->m_playback, NULL); + if(FAILED(result)) + { + gviFreeSourceList(data->m_playbackSources); + gviFreeDevice(device); + return NULL; + } + + // setup the playback device + if(!gviInitPlaybackDevice(data)) + { + gviFreeSourceList(data->m_playbackSources); + IDirectSound_Release(data->m_playback); + gviFreeDevice(device); + return NULL; + } + } + // check if they want to init capture + else if(type == GV_CAPTURE) + { + // create the interface + result = DirectSoundCaptureCreate(&deviceID, &data->m_capture, NULL); + if(FAILED(result)) + { + gviFreeDevice(device); + return NULL; + } + + // setup the capture device + if(!gviInitCaptureDevice(data)) + { + IDirectSoundCapture_Release(data->m_capture); + gviFreeDevice(device); + return NULL; + } + + // set some data vars + data->m_captureVolume = 1.0; + data->m_captureClock = 0; + data->m_captureLastCrossedThresholdTime = (data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + } + + // add it to the list + gviAppendDeviceToList(GVIDevices, device); + + return device; +} + +#if (DIRECTSOUND_VERSION == 0x0800) +static LPDIRECTPLAYVOICETEST GetVoiceTestInstance(void) +{ + LPDIRECTPLAYVOICETEST voiceTest; + HRESULT result; + + // create the IDirectPlayVoiceTest object + result = CoCreateInstance(&CLSID_DirectPlayVoiceTest, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectPlayVoiceTest, (LPVOID*)&voiceTest); + + if(FAILED(result)) + return NULL; + + return voiceTest; +} + +GVBool gvRunSetupWizard(GVDeviceID captureDeviceID, GVDeviceID playbackDeviceID) +{ + LPDIRECTPLAYVOICETEST voiceTest; + HRESULT result; + + // get the voice test instance + voiceTest = GetVoiceTestInstance(); + if(!voiceTest) + return GVFalse; + + // run the dialog + result = IDirectPlayVoiceTest_CheckAudioSetup(voiceTest, &playbackDeviceID, &captureDeviceID, GVIHwnd, 0); + + // releate the instance + IDirectPlayVoiceTest_Release(voiceTest); + + // check for success + if((result == DV_OK) || (result == DV_FULLDUPLEX) || (result == DV_HALFDUPLEX)) + return GVTrue; + + return GVFalse; +} + +GVBool gvAreDevicesSetup(GVDeviceID captureDevice, GVDeviceID playbackDevice) +{ + LPDIRECTPLAYVOICETEST voiceTest; + HRESULT result; + + // get the voice test instance + voiceTest = GetVoiceTestInstance(); + if(!voiceTest) + return GVFalse; + + // run the dialog + result = IDirectPlayVoiceTest_CheckAudioSetup(voiceTest, &playbackDevice, &captureDevice, GVIHwnd, DVFLAGS_QUERYONLY); + + // releate the instance + IDirectPlayVoiceTest_Release(voiceTest); + + // check for success + if((result == DV_FULLDUPLEX) || (result == DV_HALFDUPLEX)) + return GVTrue; + + return GVFalse; +} +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvDirectSound.h b/xrGameSpy/gamespy/Voice2/gvDirectSound.h new file mode 100644 index 00000000000..fb141e87d7e --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvDirectSound.h @@ -0,0 +1,25 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_DIRECT_SOUND_H_ +#define _GV_DIRECT_SOUND_H_ + +#include "gvMain.h" + +GVBool gviHardwareStartup(HWND hWnd); +void gviHardwareCleanup(void); +void gviHardwareThink(void); + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvFrame.c b/xrGameSpy/gamespy/Voice2/gvFrame.c new file mode 100644 index 00000000000..0d9addc7c71 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvFrame.c @@ -0,0 +1,107 @@ +#include "gvFrame.h" +#include "gvCodec.h" + +// packets are only accepted if they are frameStamped to be played +// within this many frames from the current play clock +#define GVI_INCOMING_PACKET_TIMEFRAME_FRAMES (GVI_FRAMESTAMP_MAX / 2) + +#define GVI_PREALLOCATED_FRAMES 200 + +#if defined(_PS2) || defined(_PSP) +#define GVI_DYNAMICALLY_ALLOCATE_FRAMES 0 +#else +#define GVI_DYNAMICALLY_ALLOCATE_FRAMES 1 +#endif + +// list of available frames +static GVIPendingFrame * GVIAvailableFrames; + +GVBool gviIsFrameStampGT(GVFrameStamp a, GVFrameStamp b) +{ + return ((GVFrameStamp)(b - a) > GVI_INCOMING_PACKET_TIMEFRAME_FRAMES); +} + +GVBool gviIsFrameStampGTE(GVFrameStamp a, GVFrameStamp b) +{ + return ((GVFrameStamp)(b - a - 1) > GVI_INCOMING_PACKET_TIMEFRAME_FRAMES); +} + +static void gviFreePendingFrame(GVIPendingFrame * frame) +{ + gsifree(frame); +} + +static GVIPendingFrame * gviNewPendingFrame(void) +{ + GVIPendingFrame * frame; + + // allocate a new frame +#if GVI_PRE_DECODE + frame = (GVIPendingFrame *)gsimalloc(sizeof(GVIPendingFrame) + GVIBytesPerFrame - sizeof(GVSample)); +#else + frame = (GVIPendingFrame *)gsimalloc(sizeof(GVIPendingFrame) + GVIEncodedFrameSize - 1); +#endif + + // return it + return frame; +} + +void gviPutPendingFrame(GVIPendingFrame * frame) +{ + // put the frame back in the available frames list + frame->m_next = GVIAvailableFrames; + GVIAvailableFrames = frame; +} + +GVIPendingFrame * gviGetPendingFrame(void) +{ + GVIPendingFrame * frame; + + // check the available frames list + if(GVIAvailableFrames) + { + frame = GVIAvailableFrames; + GVIAvailableFrames = frame->m_next; + return frame; + } + +#if GVI_DYNAMICALLY_ALLOCATE_FRAMES + // allocate a new frame + return gviNewPendingFrame(); +#else + // we can't dynamically allocate frames + return NULL; +#endif +} + +void gviFramesStartup(void) +{ + GVIPendingFrame * frame; + int i; + + if(GVIAvailableFrames) + gviFramesCleanup(); + + GVIAvailableFrames = NULL; + + for(i = 0 ; i < GVI_PREALLOCATED_FRAMES ; i++) + { + frame = gviNewPendingFrame(); + if(!frame) + return; + frame->m_next = GVIAvailableFrames; + GVIAvailableFrames = frame; + } +} + +void gviFramesCleanup(void) +{ + GVIPendingFrame * next; + + while(GVIAvailableFrames) + { + next = GVIAvailableFrames->m_next; + gviFreePendingFrame(GVIAvailableFrames); + GVIAvailableFrames = next; + } +} diff --git a/xrGameSpy/gamespy/Voice2/gvFrame.h b/xrGameSpy/gamespy/Voice2/gvFrame.h new file mode 100644 index 00000000000..9bdf85edbf5 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvFrame.h @@ -0,0 +1,51 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_FRAME_H_ +#define _GV_FRAME_H_ + +#include "gvMain.h" + +// max value for a framestamp +#define GVI_FRAMESTAMP_MAX 0xFFFF + +#if defined(_MACOSX) + #define GVI_PRE_DECODE 1 +#else + #define GVI_PRE_DECODE 0 +#endif + +// when allocated, enough memory is allocated to fit an entire +// frame into the m_frame array +typedef struct GVIPendingFrame +{ + GVFrameStamp m_frameStamp; + struct GVIPendingFrame * m_next; + // m_frame must be the last member of this struct +#if GVI_PRE_DECODE + GVSample m_frame[1]; +#else + GVByte m_frame[1]; +#endif +} GVIPendingFrame; + +void gviFramesStartup(void); +void gviFramesCleanup(void); + +GVIPendingFrame * gviGetPendingFrame(void); +void gviPutPendingFrame(GVIPendingFrame * frame); + +// a > b +GVBool gviIsFrameStampGT(GVFrameStamp a, GVFrameStamp b); +// a >= b +GVBool gviIsFrameStampGTE(GVFrameStamp a, GVFrameStamp b); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvGSM.c b/xrGameSpy/gamespy/Voice2/gvGSM.c new file mode 100644 index 00000000000..20230322f1f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvGSM.c @@ -0,0 +1,97 @@ +#include "gvGSM.h" +#include + +// these are standard for GSM +#define GVI_SAMPLES_PER_FRAME 160 +#define GVI_ENCODED_FRAME_SIZE 33 + +static GVBool gviGSMInitialized; +static gsm gviGSMEncoderState; + +GVBool gviGSMInitialize(void) +{ + const int gsm_ltp = 1; + + // we shouldn't already be initialized + if(gviGSMInitialized) + return GVFalse; + + // create a new encoder state + gviGSMEncoderState = gsm_create(); + if(!gviGSMEncoderState) + return GVFalse; + + // set the LTP cut option + gsm_option(gviGSMEncoderState, GSM_OPT_LTP_CUT, &gsm_ltp); + + // we're now initialized + gviGSMInitialized = GVTrue; + + return GVTrue; +} + +void gviGSMCleanup(void) +{ + // make sure there is something to cleanup + if(!gviGSMInitialized) + return; + + // destroy the encoder state + gsm_destroy(gviGSMEncoderState); + gviGSMEncoderState = NULL; + + // no longer initialized + gviGSMInitialized = GVFalse; +} + +int gviGSMGetSamplesPerFrame(void) +{ + return GVI_SAMPLES_PER_FRAME; +} + +int gviGSMGetEncodedFrameSize(void) +{ + return GVI_ENCODED_FRAME_SIZE; +} + +GVBool gviGSMNewDecoder(GVDecoderData * data) +{ + gsm decoder; + + // create a new decoder state + decoder = gsm_create(); + if(!decoder) + return GVFalse; + + *data = decoder; + return GVTrue; +} + +void gviGSMFreeDecoder(GVDecoderData data) +{ + // destory the decoder state + gsm_destroy((gsm)data); +} + +void gviGSMEncode(GVByte * out, const GVSample * in) +{ + gsm_encode((gsm)gviGSMEncoderState, (gsm_signal*)in, (gsm_byte*)out); +} + +void gviGSMDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data) +{ + GVSample temp[GVI_SAMPLES_PER_FRAME]; + int i; + + // decode it + gsm_decode((gsm)data, (gsm_byte*)in, (gsm_signal*)temp); + + // add the output + for(i = 0 ; i < GVI_SAMPLES_PER_FRAME ; i++) + out[i] += temp[i]; +} + +void gviGSMDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data) +{ + gsm_decode((gsm)data, (gsm_byte*)in, (gsm_signal*)out); +} diff --git a/xrGameSpy/gamespy/Voice2/gvGSM.h b/xrGameSpy/gamespy/Voice2/gvGSM.h new file mode 100644 index 00000000000..74d9c1023cd --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvGSM.h @@ -0,0 +1,39 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_GSM_H_ +#define _GV_GSM_H_ + +#include "gvMain.h" + +/* +quality: samplesPerFrame encodedFrameSize bitsPerSecond (at 11025hz) +All: 160 33 18200 +*/ + +GVBool gviGSMInitialize(void); +void gviGSMCleanup(void); + +int gviGSMGetSamplesPerFrame(void); +int gviGSMGetEncodedFrameSize(void); + +GVBool gviGSMNewDecoder(GVDecoderData * data); +void gviGSMFreeDecoder(GVDecoderData data); + +void gviGSMEncode(GVByte * out, const GVSample * in); +void gviGSMDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data); +void gviGSMDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvLogitechPS2Codecs.c b/xrGameSpy/gamespy/Voice2/gvLogitechPS2Codecs.c new file mode 100644 index 00000000000..83d34f65a7c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvLogitechPS2Codecs.c @@ -0,0 +1,118 @@ +#include "gvLogitechPS2Codecs.h" +#include + +#if !defined(_PS2) +#error This file should only be used with the PlayStation2 +#endif + +static GVBool GVILGCodecInitialized; +static int GVILGCodecHandle; +static int GVILGCodecBytesPerFrame; +static int GVILGCodecSamplesPerFrame; +static int GVILGCodecEncodedFrameSize; +static GVSample * GVILGCodecDecodeBuffer; + +GVBool gviLGCodecInitialize(const char * name) +{ + lgCodecDesc * codecDesc; + int i; + int rcode; + + // check if the lib hasn't been initialized + if(!GVILGCodecInitialized) + { + // initialize it + rcode = lgCodecInit(); + if(LGCODEC_FAILED(rcode)) + return GVFalse; + + // we're now initialized + GVILGCodecInitialized = GVTrue; + } + + // find the codec + for(i = 0 ; (codecDesc = lgCodecEnumerate(i)) ; i++) + { + // check if the name matches + if(strcmp(codecDesc->name, name) == 0) + break; + } + + // check if we didn't find it + if(!codecDesc) + return GVFalse; + + // allocate memory for the decode buffer + GVILGCodecDecodeBuffer = (GVSample *)gsimalloc((unsigned int)codecDesc->bytes_per_pcm_frame); + if(!GVILGCodecDecodeBuffer) + return GVFalse; + + // open a handle to the codec + rcode = lgCodecOpen(codecDesc->id, &GVILGCodecHandle); + if(LGCODEC_FAILED(rcode)) + { + gsifree(GVILGCodecDecodeBuffer); + return GVFalse; + } + + // store the codec info + GVILGCodecBytesPerFrame = codecDesc->bytes_per_pcm_frame; + GVILGCodecSamplesPerFrame = (int)(GVILGCodecBytesPerFrame / GV_BYTES_PER_SAMPLE); + GVILGCodecEncodedFrameSize = codecDesc->bytes_per_enc_frame; + + return GVTrue; +} + +void gviLGCodecCleanup(void) +{ + gsifree(GVILGCodecDecodeBuffer); + GVILGCodecDecodeBuffer = NULL; + lgCodecClose(GVILGCodecHandle); +} + +int gviLGCodecGetSamplesPerFrame(void) +{ + return GVILGCodecSamplesPerFrame; +} + +int gviLGCodecGetEncodedFrameSize(void) +{ + return GVILGCodecEncodedFrameSize; +} + +void gviLGCodecEncode(GVByte * out, const GVSample * in) +{ + int destSize = GVILGCodecEncodedFrameSize; + lgCodecEncode(GVILGCodecHandle, in, GVILGCodecBytesPerFrame, out, &destSize); + assert(destSize == GVILGCodecEncodedFrameSize); +} + +void gviLGCodecDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data) +{ + int i; + int destSize; + + destSize = GVILGCodecBytesPerFrame; + lgCodecDecode(GVILGCodecHandle, in, GVILGCodecEncodedFrameSize, GVILGCodecDecodeBuffer, &destSize); + assert(destSize == GVILGCodecBytesPerFrame); + + for(i = 0 ; i < GVILGCodecSamplesPerFrame ; i++) + out[i] += GVILGCodecDecodeBuffer[i]; + + GSI_UNUSED(data); +} + +void gviLGCodecDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data) +{ + int i; + int destSize; + + destSize = GVILGCodecBytesPerFrame; + lgCodecDecode(GVILGCodecHandle, in, GVILGCodecEncodedFrameSize, GVILGCodecDecodeBuffer, &destSize); + assert(destSize == GVILGCodecBytesPerFrame); + + for(i = 0 ; i < GVILGCodecSamplesPerFrame ; i++) + out[i] = GVILGCodecDecodeBuffer[i]; + + GSI_UNUSED(data); +} diff --git a/xrGameSpy/gamespy/Voice2/gvLogitechPS2Codecs.h b/xrGameSpy/gamespy/Voice2/gvLogitechPS2Codecs.h new file mode 100644 index 00000000000..31b2b7c514a --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvLogitechPS2Codecs.h @@ -0,0 +1,41 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_LOGITECH_PS2_CODECS_H_ +#define _GV_LOGITECH_PS2_CODECS_H_ + +#include "gvMain.h" + +/* +name: samplesPerFrame encodedFrameSize bitsPerSecond +LPC10: 180 7 2489 +SPEEX: 160 20 8000 +GSM: 160 33 13200 +G723.24: 160 60 24000 +uLaw: 160 160 64000 +PCM: 160 320 128000 +*/ + +GVBool gviLGCodecInitialize(const char * name); +void gviLGCodecCleanup(void); + +int gviLGCodecGetSamplesPerFrame(void); +int gviLGCodecGetEncodedFrameSize(void); + +void gviLGCodecEncode(GVByte * out, const GVSample * in); +void gviLGCodecDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data); +void gviLGCodecDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvMain.c b/xrGameSpy/gamespy/Voice2/gvMain.c new file mode 100644 index 00000000000..a9eb6bab9e8 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvMain.c @@ -0,0 +1,318 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#include "gvMain.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvFrame.h" +#include "gvCustomDevice.h" +#if !defined(GV_NO_DEFAULT_HARDWARE) + #if defined(_WIN32) + #include "gvDirectSound.h" + #elif defined(_PS2) + #include "gvPS2Audio.h" + #elif defined(_MACOSX) + #include "gvOSXAudio.h" + #elif defined(_PSP) + #include "gvPSPAudio.h" + #elif defined(_PS3) + #include "gvPS3Audio.h" + #else + #error There is no default hardware support on this platform. Define GV_NO_DEFAULT_HARDWARE to compile without default hardware support. + #endif +#endif + + +/************ +** GENERAL ** +************/ +#if defined(_WIN32) +GVBool gvStartup(HWND hWnd) +#else +GVBool gvStartup(void) +#endif +{ + // init codecs + gviCodecsInitialize(); + + GVIGlobalMute = GVFalse; + + // startup the devices +#if !defined(GV_NO_DEFAULT_HARDWARE) + #if defined(_WIN32) + if(!gviHardwareStartup(hWnd)) + #else + if(!gviHardwareStartup()) + #endif + { + return GVFalse; + } +#endif + return GVTrue; +} + +void gvCleanup(void) +{ +#if !defined(GV_NO_DEFAULT_HARDWARE) + gviHardwareCleanup(); +#endif + gviCodecsCleanup(); + gviFramesCleanup(); +} + +void gvThink(void) +{ +#if !defined(GV_NO_DEFAULT_HARDWARE) + gviHardwareThink(); +#endif +} + +/********** +** CODEC ** +**********/ +GVBool gvSetCodec(GVCodec codec) +{ + return gviSetCodec(codec); +} + +void gvSetCustomCodec(GVCustomCodecInfo * info) +{ + gviSetCustomCodec(info); +} + +void gvGetCodecInfo(int * samplesPerFrame, int * encodedFrameSize, int * bitsPerSecond) +{ + if(samplesPerFrame) + *samplesPerFrame = GVISamplesPerFrame; + if(encodedFrameSize) + *encodedFrameSize = GVIEncodedFrameSize; + if(bitsPerSecond) + *bitsPerSecond = (int)(8 * GVIBytesPerSecond * GVIEncodedFrameSize / GVIBytesPerFrame); +} + +/**************** +** Sample Rate ** +****************/ +void gvSetSampleRate(GVRate sampleRate) +{ + gviSetSampleRate(sampleRate); +} + +GVRate gvGetSampleRate(void) +{ + return gviGetSampleRate(); +} + +/************ +** DEVICES ** +************/ +#if !defined(GV_NO_DEFAULT_HARDWARE) +int gvListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + return gviHardwareListDevices(devices, maxDevices, types); +} + +GVDevice gvNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + return gviHardwareNewDevice(deviceID, type); +} +#endif + +void gvFreeDevice(GVDevice device) +{ + device->m_methods.m_freeDevice(device); +} + +GVBool gvStartDevice(GVDevice device, GVDeviceType type) +{ + return device->m_methods.m_startDevice(device, type); +} + +void gvStopDevice(GVDevice device, GVDeviceType type) +{ + device->m_methods.m_stopDevice(device, type); +} + +GVBool gvIsDeviceStarted(GVDevice device, GVDeviceType type) +{ + return device->m_methods.m_isDeviceStarted(device, type); +} + +void gvSetDeviceVolume(GVDevice device, GVDeviceType type, GVScalar volume) +{ + volume = max(volume, 0.0); + volume = min(volume, 1.0); + + device->m_methods.m_setDeviceVolume(device, type, volume); +} + +GVScalar gvGetDeviceVolume(GVDevice device, GVDeviceType type) +{ + return device->m_methods.m_getDeviceVolume(device, type); +} + +void gvSetUnpluggedCallback(GVDevice device, gvUnpluggedCallback unpluggedCallback) +{ + device->m_unpluggedCallback = unpluggedCallback; +} + +void gvSetFilter(GVDevice device, GVDeviceType type, gvFilterCallback callback) +{ + if(type & GV_CAPTURE) + device->m_captureFilterCallback = callback; + if(type & GV_PLAYBACK) + device->m_playbackFilterCallback = callback; +} + +/************ +** CAPTURE ** +************/ +GVBool gvCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + return device->m_methods.m_capturePacket(device, packet, len, frameStamp, volume); +} + +int gvGetAvailableCaptureBytes(GVDevice device) +{ + return device->m_methods.m_getAvailableCaptureBytes(device); +} + +void gvSetCaptureThreshold(GVDevice device, GVScalar threshold) +{ + device->m_methods.m_setCaptureThreshold(device, threshold); +} + +GVScalar gvGetCaptureThreshold(GVDevice device) +{ + return device->m_methods.m_getCaptureThreshold(device); +} + +void gvSetCaptureMode(GVDevice device, GVCaptureMode captureMode) +{ + //This only works with Capture devices. + assert(device->m_types & GV_CAPTURE); + + //See if we are switching from Threshold to PTT. + if ((device->m_captureMode == GVCaptureModeThreshold) && (captureMode == GVCaptureModePushToTalk)) + { + device->m_savedCaptureThreshold = gvGetCaptureThreshold(device); + gvSetCaptureThreshold(device, 0.0f); + + //Stop the capture device. + if (gvIsDeviceStarted(device, GV_CAPTURE)) + gvStopDevice(device, GV_CAPTURE); + } + //See if we are switching from PTT to Threshold. + if ((device->m_captureMode == GVCaptureModePushToTalk) && (captureMode == GVCaptureModeThreshold)) + { + gvSetCaptureThreshold(device, device->m_savedCaptureThreshold); + + //Turn on the capture device. + gvStartDevice(device, GV_CAPTURE); + } + + device->m_captureMode = captureMode; +} + +GVCaptureMode gvGetCaptureMode(GVDevice device) +{ + return device->m_captureMode; +} + +void gvSetPushToTalk(GVDevice device, GVBool talkOn) +{ + if (talkOn) + gvStartDevice(device, GV_CAPTURE); + else + gvStopDevice(device, GV_CAPTURE); +} + +GVBool gvGetPushToTalk(GVDevice device) +{ + return gvIsDeviceStarted(device, GV_CAPTURE); +} + +/************* +** PLAYBACK ** +*************/ +void gvPlayPacket(GVDevice device, const GVByte * data, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + device->m_methods.m_playPacket(device, data, len, source, frameStamp, mute); +} + +GVBool gvIsSourceTalking(GVDevice device, GVSource source) +{ + return device->m_methods.m_isSourceTalking(device, source); +} + +int gvListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + return device->m_methods.m_listTalkingSources(device, sources, maxSources); +} + +void gvSetGlobalMute(GVBool mute) +{ + gviSetGlobalMute(mute); +} + +GVBool gvGetGlobalMute(void) +{ + return gviGetGlobalMute(); +} + + +/****************** +** CUSTOM DEVICE ** +******************/ +GVDevice gvNewCustomDevice(GVDeviceType type) +{ + return gviCustomNewDevice(type); +} + +GVBool gvGetCustomPlaybackAudio(GVDevice device, GVSample * audio, int numSamples) +{ + return gviGetCustomPlaybackAudio(device, audio, numSamples); +} + +GVBool gvSetCustomCaptureAudio(GVDevice device, const GVSample * audio, int numSamples, + GVByte * packet, int * packetLen, GVFrameStamp * frameStamp, GVScalar * volume) +{ + return gviSetCustomCaptureAudio(device, audio, numSamples, packet, packetLen, frameStamp, volume); +} + +/************* +** CHANNELS ** +*************/ +int gvGetNumChannels(GVDevice device, GVDeviceType type) +{ + if(device->m_methods.m_getNumChannels) + return device->m_methods.m_getNumChannels(device, type); + return 0; +} + +void gvGetChannelName(GVDevice device, GVDeviceType type, int channel, gsi_char name[GV_CHANNEL_NAME_LEN]) +{ + if(device->m_methods.m_getNumChannels) + device->m_methods.m_getChannelName(device, type, channel, name); +} + +void gvSetChannel(GVDevice device, GVDeviceType type, int channel) +{ + if(device->m_methods.m_setChannel) + device->m_methods.m_setChannel(device, type, channel); +} + +int gvGetChannel(GVDevice device, GVDeviceType type) +{ + if(device->m_methods.m_getChannel) + return device->m_methods.m_getChannel(device, type); + return 0; +} diff --git a/xrGameSpy/gamespy/Voice2/gvMain.h b/xrGameSpy/gamespy/Voice2/gvMain.h new file mode 100644 index 00000000000..8df1bd20225 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvMain.h @@ -0,0 +1,18 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_MAIN_H_ +#define _GV_MAIN_H_ + +#include "gv.h" +#include "../darray.h" + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvOSXAudio.c b/xrGameSpy/gamespy/Voice2/gvOSXAudio.c new file mode 100644 index 00000000000..48ebfbe7846 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvOSXAudio.c @@ -0,0 +1,1465 @@ +#include "gvOSXAudio.h" +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#include +#include +#include + +#if !defined(_MACOSX) +#error This file should only be used with MacOS X +#endif + +#if !defined(GVI_VOLUME_IN_SOFTWARE) + #define GVI_VOLUME_IN_SOFTWARE 1 +#endif + +/********** +** TYPES ** +**********/ +// when allocated, enough memory is allocated to fit an entire +// captured frame into the m_frame array +typedef struct GVICapturedFrame +{ + GVFrameStamp m_frameStamp; + struct GVICapturedFrame * m_next; + // m_frame must be the last member of this struct + GVSample m_frame[1]; +} GVICapturedFrame; + +typedef struct +{ + GVBool m_playing; + AudioConverterRef m_playbackConverter; + AudioStreamBasicDescription m_playbackStreamDescriptor; + GVFrameStamp m_playbackClock; + GVSample * m_playbackBuffer; + GVISourceList m_playbackSources; + int m_playbackChannel; +#if GVI_VOLUME_IN_SOFTWARE + GVScalar m_playbackVolume; +#endif + + GVBool m_capturing; + AudioConverterRef m_captureConverter; + AudioStreamBasicDescription m_captureStreamDescriptor; + GVFrameStamp m_captureClock; + GVSample * m_captureBuffer; + GVICapturedFrame m_capturedFrames; + GVICapturedFrame m_captureAvailableFrames; + GVScalar m_captureThreshold; + GVFrameStamp m_captureLastCrossedThresholdTime; + int m_captureChannel; +#if GVI_VOLUME_IN_SOFTWARE + GVScalar m_captureVolume; +#endif + + pthread_mutex_t m_mutex; + GVBool m_unplugged; +} GVIHardwareData; + +typedef struct +{ + GVIDevice * m_device; + AudioBufferList * m_capturedAudio; + GVBool m_used; +} GVICaptureConverterData; + +/************ +** GLOBALS ** +************/ +static GVIDeviceList GVIDevices; +static AudioStreamBasicDescription GVIVoiceFormat; + +/************** +** FUNCTIONS ** +**************/ +static void gviFreeCapturedFrames(GVICapturedFrame * frameHead) +{ + GVICapturedFrame * frame; + while(frameHead->m_next) + { + frame = frameHead->m_next; + frameHead->m_next = frame->m_next; + gsifree(frame); + } +} + +static GVICapturedFrame * gviPopFirstFrame(GVICapturedFrame * frameHead) +{ + GVICapturedFrame * frame = frameHead->m_next; + if(frame) + { + frameHead->m_next = frame->m_next; + frame->m_next = NULL; + } + return frame; +} + +static void gviPushFirstFrame(GVICapturedFrame * frameHead, GVICapturedFrame * frame) +{ + frame->m_next = frameHead->m_next; + frameHead->m_next = frame; +} + +static void gviPushLastFrame(GVICapturedFrame * frameHead, GVICapturedFrame * frame) +{ + GVICapturedFrame * lastFrame; + + // find the last frame in the list + lastFrame = frameHead; + while(lastFrame->m_next) + lastFrame = lastFrame->m_next; + + // add this frame to the end of the capture list + lastFrame->m_next = frame; +} + +static GVBool gviLockDevice(GVIHardwareData * data) +{ + int rcode; + rcode = pthread_mutex_lock(&data->m_mutex); + return (rcode == 0)?GVTrue:GVFalse; +} + +static void gviUnlockDevice(GVIHardwareData * data) +{ + pthread_mutex_unlock(&data->m_mutex); +} + +static void gviCleanupPlayback(GVIHardwareData * data) +{ + if(data->m_playbackSources) + gviFreeSourceList(data->m_playbackSources); + if(data->m_playbackConverter) + AudioConverterDispose(data->m_playbackConverter); + gsifree(data->m_playbackBuffer); +} + +static void gviCleanupCapture(GVIHardwareData * data) +{ + if(data->m_captureConverter) + AudioConverterDispose(data->m_captureConverter); + gviFreeCapturedFrames(&data->m_captureAvailableFrames); + gviFreeCapturedFrames(&data->m_capturedFrames); + gsifree(data->m_captureBuffer); +} + +static void gviFreeArrayDevice(void * elem) +{ + GVIDevice * device = *(GVIDevice **)elem; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // stop the device + device->m_methods.m_stopDevice(device, device->m_types); + + // free the mutex + pthread_mutex_destroy(&data->m_mutex); + + // playback specific cleanup + if(device->m_types & GV_PLAYBACK) + { + gviCleanupPlayback(data); + } + + // capture specific cleanup + if(device->m_types & GV_CAPTURE) + { + gviCleanupCapture(data); + } + + gviFreeDevice(device); +} + +GVBool gviHardwareStartup(void) +{ + // create the devices array + GVIDevices = gviNewDeviceList(gviFreeArrayDevice); + if(!GVIDevices) + return GVFalse; + + // setup the format descriptor for the GV format + memset(&GVIVoiceFormat, 0, sizeof(AudioStreamBasicDescription)); + GVIVoiceFormat.mSampleRate = (Float64)GV_SAMPLES_PER_SECOND; + GVIVoiceFormat.mFormatID = kAudioFormatLinearPCM; + GVIVoiceFormat.mFormatFlags = kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked; + GVIVoiceFormat.mBytesPerPacket = GV_BYTES_PER_SAMPLE; + GVIVoiceFormat.mFramesPerPacket = 1; + GVIVoiceFormat.mBytesPerFrame = GV_BYTES_PER_SAMPLE; + GVIVoiceFormat.mChannelsPerFrame = 1; + GVIVoiceFormat.mBitsPerChannel = GV_BITS_PER_SAMPLE; + + return GVTrue; +} + +void gviHardwareCleanup(void) +{ + // cleanup the devices + if(GVIDevices) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + } +} + +void gviHardwareThink(void) +{ + GVIDevice * device; + int num; + int i; + + if(!GVIDevices) + return; + + // loop through backwards so that we can remove devices as we go + num = gviGetNumDevices(GVIDevices); + for(i = (num - 1) ; i >= 0 ; i--) + { + // get the device + device = gviGetDevice(GVIDevices, i); + + // has it been unplugged? + if(((GVIHardwareData*)device->m_data)->m_unplugged) + { + gviDeviceUnplugged(device); + } + } +} + +static GVBool gviCFStringToString(CFStringRef ref, gsi_char str[], int strLen) +{ +#if !defined(GSI_UNICODE) + + Boolean result = CFStringGetCString(ref, str, strLen, kCFStringEncodingASCII); + return (result == true)?GVTrue:GVFalse; + +#else + + CFRange range; + + range.location = 0; + range.length = CFStringGetLength(ref); + range.length = min(range.length, strLen - 1); + + CFStringGetCharacters(ref, range, str); + str[range.length] = '\0'; + + return GVTrue; + +#endif +} + +static int gviCountChannels(AudioDeviceID deviceID, bool input) +{ + OSStatus result; + UInt32 size; + AudioBufferList * list; + int numChannels; + int i; + + // get the size of the buffer list + result = AudioDeviceGetPropertyInfo(deviceID, 0, input, kAudioDevicePropertyStreamConfiguration, &size, NULL); + if(result != noErr) + return 0; + + // allocate the buffer list + list = (AudioBufferList *)gsimalloc(size); + if(list == NULL) + return 0; + + // fill the buffer list + result = AudioDeviceGetProperty(deviceID, 0, input, kAudioDevicePropertyStreamConfiguration, &size, list); + if(result != noErr) + { + gsifree(list); + return 0; + } + + // count the number of channels + numChannels = 0; + for(i = 0 ; i < list->mNumberBuffers ; i++) + numChannels += list->mBuffers[i].mNumberChannels; + + // free the list + gsifree(list); + + return numChannels; +} + +static GVBool gviFillDeviceInfo(AudioDeviceID deviceID, GVDeviceInfo * device, GVDeviceType types) +{ + OSStatus result; + UInt32 size; + UInt32 isAlive; + GVDeviceType supportedTypes; + CFStringRef nameRef; + + // make sure the device is alive + size = sizeof(UInt32); + result = AudioDeviceGetProperty(deviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, &size, &isAlive); + if((result != noErr) || (isAlive != 1)) + return GVFalse; + + // set the hardware type + device->m_hardwareType = GVHardwareMacOSX; + + // store the id + device->m_id = deviceID; + + // figure out what types it supports + supportedTypes = (GVDeviceType)0; + if(gviCountChannels(deviceID, true) > 0) + supportedTypes |= GV_CAPTURE; + if(gviCountChannels(deviceID, false) > 0) + supportedTypes |= GV_PLAYBACK; + + // if there's nothing in common, return + if(!(supportedTypes & types)) + return GVFalse; + + // store the supported types + device->m_deviceType = supportedTypes; + + // get the name + size = sizeof(nameRef); + result = AudioDeviceGetProperty(deviceID, 0, (supportedTypes & GV_CAPTURE)?true:false, kAudioDevicePropertyDeviceNameCFString, &size, &nameRef); + if(result != noErr) + return GVFalse; + + // if there's a blank name, we'll supply our own + if(CFStringGetLength(nameRef) <= 0) + { + CFRelease(nameRef); + nameRef = NULL; + } + + // if there's no name, give a default + if(nameRef == NULL) + { + if(supportedTypes == GV_CAPTURE) + nameRef = CFSTR("Capture Device"); + else if(supportedTypes == GV_PLAYBACK) + nameRef = CFSTR("Playback Device"); + else + nameRef = CFSTR("Capture & Playback Device"); + } + + // convert it to an array of gsi_char + gviCFStringToString(nameRef, device->m_name, GV_DEVICE_NAME_LEN); + + // release the CFString + CFRelease(nameRef); + + return GVTrue; +} + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + OSStatus result; + UInt32 size; + int numDevices; + int deviceCount; + AudioDeviceID * deviceIDs; + AudioDeviceID defaultCaptureDeviceID; + AudioDeviceID defaultPlaybackDeviceID; + GVDeviceType defaultTypes; + int i; + + // get the default device ids + size = sizeof(AudioDeviceID); + result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, &defaultCaptureDeviceID); + if(result != noErr) + defaultCaptureDeviceID = kAudioDeviceUnknown; + result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &defaultPlaybackDeviceID); + if(result != noErr) + defaultPlaybackDeviceID = kAudioDeviceUnknown; + + // get the size of the device ids array + result = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, NULL); + if(result != noErr) + return 0; + + // calc the number of devices + numDevices = (size / sizeof(AudioDeviceID)); + + // allocate the array of device ids + deviceIDs = (AudioDeviceID *)gsimalloc(size); + if(deviceIDs == NULL) + return 0; + + // get the device ids + result = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, deviceIDs); + if(result != noErr) + { + gsifree(deviceIDs); + return 0; + } + + // fill the array of devices with info + deviceCount = 0; + for(i = 0 ; (i < maxDevices) && (deviceCount < numDevices) ; i++) + { + // try to add the device to the list + GVBool addedDevice = gviFillDeviceInfo(deviceIDs[i], &devices[deviceCount], types); + + // check if it was added successfully + if(addedDevice) + { + // check it against the defaults + defaultTypes = (GVDeviceType)0; + if(deviceIDs[i] == defaultCaptureDeviceID) + defaultTypes |= GV_CAPTURE; + if(deviceIDs[i] == defaultPlaybackDeviceID) + defaultTypes |= GV_PLAYBACK; + devices[deviceCount].m_defaultDevice = defaultTypes; + + // increment the count + deviceCount++; + } + } + + // free the array + gsifree(deviceIDs); + + return deviceCount; +} + +static void gviHardwareFreeDevice(GVDevice device) +{ + // delete it from the array + // it will clear out internal data in the array's free function + gviDeleteDeviceFromList(GVIDevices, device); +} + +static OSStatus gviAudioConverterCaptureProc(AudioConverterRef inAudioConverter, + UInt32 * ioNumberDataPackets, + AudioBufferList * ioData, + AudioStreamPacketDescription ** outDataPacketDescription, + void * inUserData) +{ + GVICaptureConverterData * converterData = (GVICaptureConverterData *)inUserData; + GVIDevice * device = converterData->m_device; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + AudioBufferList * bufferList = converterData->m_capturedAudio; + + // check if this data has already been used + if(converterData->m_used) + return (OSStatus)1; + + // it only wants one buffer + ioData->mBuffers[0].mNumberChannels = bufferList->mBuffers[data->m_captureChannel].mNumberChannels; + ioData->mBuffers[0].mData = bufferList->mBuffers[data->m_captureChannel].mData; + ioData->mBuffers[0].mDataByteSize = bufferList->mBuffers[data->m_captureChannel].mDataByteSize; + + // fill in the number of samples we provided + *ioNumberDataPackets = (ioData->mBuffers[0].mDataByteSize / data->m_captureStreamDescriptor.mBytesPerPacket); + + // we've used the buffer + converterData->m_used = GVTrue; + + return noErr; +} + +static OSStatus gviHardwareCaptureIOProc(AudioDeviceID inDevice, + const AudioTimeStamp * inNow, + const AudioBufferList * inInputData, + const AudioTimeStamp * inInputTime, + AudioBufferList * outOutputData, + const AudioTimeStamp * inOutputTime, + void * inClientData) +{ + GVIDevice * device = (GVIDevice *)inClientData; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + OSStatus result; + UInt32 size; + GVICaptureConverterData converterData; + AudioBufferList bufferList; + GVICapturedFrame * frame; + + // get a lock on the device + if(!gviLockDevice(data)) + return (OSStatus)1; + + // make sure we are capturing + if(data->m_capturing) + { + // setup the buffer list + bufferList.mNumberBuffers = 1; + bufferList.mBuffers[0].mNumberChannels = 1; + bufferList.mBuffers[0].mDataByteSize = GVIBytesPerFrame; + bufferList.mBuffers[0].mData = data->m_captureBuffer; + + // setup the converter data struct + converterData.m_device = device; + converterData.m_capturedAudio = (AudioBufferList *)inInputData; + converterData.m_used = GVFalse; + + // loop while it is converting data + do + { + // request one frame + size = GVISamplesPerFrame; + + // convert the captured data into our format + result = AudioConverterFillComplexBuffer(data->m_captureConverter, gviAudioConverterCaptureProc, &converterData, &size, &bufferList, NULL); + + // was there enough to fill a buffer + if(result == noErr) + { + // get a frame + frame = gviPopFirstFrame(&data->m_captureAvailableFrames); + + // if there aren't any available frames, repurpose the oldest captured frame + if(!frame) + { + frame = gviPopFirstFrame(&data->m_capturedFrames); + assert(frame); + if(!frame) + break; + } + + // setup the frame + memcpy(frame->m_frame, data->m_captureBuffer, GVIBytesPerFrame); + frame->m_frameStamp = data->m_captureClock; + + // increment the capture clock + data->m_captureClock++; + + // add this frame to the end of the capture list + gviPushLastFrame(&data->m_capturedFrames, frame); + } + } + while(result == noErr); + } + + // release the device lock + gviUnlockDevice(data); + + return noErr; +} + +static GVBool gviHardwareStartCapture(GVDevice device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + OSStatus result; + + // now capturing + data->m_capturing = GVTrue; + + // add the IO proc + result = AudioDeviceAddIOProc((AudioDeviceID)device->m_deviceID, gviHardwareCaptureIOProc, device); + if(result != noErr) + { + data->m_capturing = GVFalse; + return GVFalse; + } + + // start it + result = AudioDeviceStart((AudioDeviceID)device->m_deviceID, gviHardwareCaptureIOProc); + if(result != noErr) + { + data->m_capturing = GVFalse; + return GVFalse; + } + + return GVTrue; +} + +static OSStatus gviAudioConverterPlaybackProc(AudioConverterRef inAudioConverter, + UInt32 * ioNumberDataPackets, + AudioBufferList * ioData, + AudioStreamPacketDescription ** outDataPacketDescription, + void * inUserData) +{ + GVIDevice * device = (GVIDevice *)inUserData; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVBool wroteToBuffer = GVFalse; + + // make sure we are playing + if(data->m_playing) + { + // write sources to the playback buffer + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, data->m_playbackBuffer, 1); + } + + // clear it if nothing was written + if(!data->m_playing || !wroteToBuffer) + { + memset(data->m_playbackBuffer, 0, (size_t)GVIBytesPerFrame); + } + // check if we need to adjust the volume + else if(data->m_playbackVolume < 1.0) + { + int i; + for(i = 0 ; i < GVISamplesPerFrame ; i++) + data->m_playbackBuffer[i] = (GVSample)(data->m_playbackBuffer[i] * data->m_playbackVolume); + } + + // filter + if(device->m_playbackFilterCallback) + device->m_playbackFilterCallback(device, data->m_playbackBuffer, data->m_playbackClock); + + // setup the output data + ioData->mBuffers[0].mNumberChannels = 1; + ioData->mBuffers[0].mDataByteSize = GVIBytesPerFrame; + ioData->mBuffers[0].mData = (void *)data->m_playbackBuffer; + + // we wrote one frame + *ioNumberDataPackets = GVISamplesPerFrame; + + // update the clock + data->m_playbackClock++; + + return noErr; +} + +static OSStatus gviHardwarePlaybackIOProc(AudioDeviceID inDevice, + const AudioTimeStamp * inNow, + const AudioBufferList * inInputData, + const AudioTimeStamp * inInputTime, + AudioBufferList * outOutputData, + const AudioTimeStamp * inOutputTime, + void * inClientData) +{ + GVIDevice * device = (GVIDevice *)inClientData; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + AudioBufferList bufferList; + OSStatus result; + UInt32 size; + + // get a lock on the device + if(!gviLockDevice(data)) + return (OSStatus)1; + + // calculate the number of samples the proc wants + size = (outOutputData->mBuffers[0].mDataByteSize / data->m_playbackStreamDescriptor.mBytesPerFrame); + + // setup our own buffer list, pointing at the channel (buffer) we want + bufferList.mNumberBuffers = 1; + bufferList.mBuffers[0] = outOutputData->mBuffers[data->m_playbackChannel]; + + // fill the buffer using the callback + result = AudioConverterFillComplexBuffer(data->m_playbackConverter, gviAudioConverterPlaybackProc, device, &size, &bufferList, NULL); + if(result != noErr) + return (OSStatus)1; + + // release the device lock + gviUnlockDevice(data); + + return noErr; +} + +static GVBool gviHardwareStartPlayback(GVDevice device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + OSStatus result; + + // now playing + data->m_playing = GVTrue; + + // reset the playback clock + data->m_playbackClock = 0; + + // add the IO proc + result = AudioDeviceAddIOProc((AudioDeviceID)device->m_deviceID, gviHardwarePlaybackIOProc, device); + if(result != noErr) + { + data->m_playing = GVFalse; + return GVFalse; + } + + // start it + result = AudioDeviceStart((AudioDeviceID)device->m_deviceID, gviHardwarePlaybackIOProc); + if(result != noErr) + { + data->m_playing = GVFalse; + return GVFalse; + } + + return GVTrue; +} + +static GVBool gviHardwareStartDevice(GVDevice device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVBool result; + + // get a lock on the device + if(!gviLockDevice(data)) + return GVFalse; + + // capture + if((type & GV_CAPTURE) && !data->m_capturing) + { + result = gviHardwareStartCapture(device); + if(!result) + { + gviUnlockDevice(data); + return GVFalse; + } + } + + // playback + if((type & GV_PLAYBACK) && !data->m_playing) + { + result = gviHardwareStartPlayback(device); + if(!result) + { + if(type & GV_CAPTURE) + device->m_methods.m_stopDevice(device, GV_CAPTURE); + gviUnlockDevice(data); + return GVFalse; + } + } + + // release the device lock + gviUnlockDevice(data); + + return GVTrue; +} + +static void gviHardwareStopDevice(GVDevice device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVICapturedFrame * frame; + + // lock the device + gviLockDevice(data); + + // capture + if((type & GV_CAPTURE) && data->m_capturing) + { + // unlock so the ioproc can stop + gviUnlockDevice(data); + + // stop io + AudioDeviceStop((AudioDeviceID)device->m_deviceID, gviHardwareCaptureIOProc); + + // relock + gviLockDevice(data); + + // remove the IO proc + AudioDeviceRemoveIOProc((AudioDeviceID)device->m_deviceID, gviHardwareCaptureIOProc); + + // move captured frames back to the available frames list + while((frame = gviPopFirstFrame(&data->m_capturedFrames)) != NULL) + gviPushFirstFrame(&data->m_captureAvailableFrames, frame); + + // no longer capturing + data->m_capturing = GVFalse; + } + + // playback + if((type & GV_PLAYBACK) && data->m_playing) + { + // unlock so the ioproc can stop + gviUnlockDevice(data); + + // stop io + AudioDeviceStop((AudioDeviceID)device->m_deviceID, gviHardwarePlaybackIOProc); + + // relock + gviLockDevice(data); + + // remove the IO proc + AudioDeviceRemoveIOProc((AudioDeviceID)device->m_deviceID, gviHardwarePlaybackIOProc); + + // clear any pending sources & buffers + gviClearSourceList(data->m_playbackSources); + + // no longer playing + data->m_playing = GVFalse; + } + + // unlock the device + gviUnlockDevice(data); +} + +static GVBool gviHardwareIsDeviceStarted(GVDevice device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVBool result = GVFalse; + + // get a lock on the device + if(!gviLockDevice(data)) + return GVFalse; + + // figure out the result + if(type == GV_PLAYBACK) + result = data->m_playing; + else if(type == GV_CAPTURE) + result = data->m_capturing; + else if (type == GV_CAPTURE_AND_PLAYBACK) + result = (data->m_playing && data->m_capturing)?GVTrue:GVFalse; + + // release the device lock + gviUnlockDevice(data); + + return result; +} + +#if GVI_VOLUME_IN_SOFTWARE + + static void gviSetDeviceVolume(GVDevice device, GVBool isInput, GVScalar volume) + { + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(isInput) + data->m_captureVolume = volume; + else + data->m_playbackVolume = volume; + } + + static GVScalar gviGetDeviceVolume(GVDevice device, GVBool isInput) + { + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(isInput) + return data->m_captureVolume; + else + return data->m_playbackVolume; + } + +#else + + static void gviSetDeviceVolume(GVDevice device, GVBool isInput, GVScalar volume) + { + Float32 vol = volume; + int channel; + + // set the volume on all three channels + // this covers mono and stereo devices + for(channel = 0 ; channel < 3 ; channel++) + AudioDeviceSetProperty(device->m_deviceID, NULL, channel, isInput, kAudioDevicePropertyVolumeScalar, sizeof(Float32), &vol); + } + + static GVBool gviGetChannelVolume(GVDevice device, GVBool isInput, int channel, Float32 * volume) + { + OSStatus result; + UInt32 size = sizeof(Float32); + + // get the volume for a specific channel + result = AudioDeviceGetProperty(device->m_deviceID, channel, isInput, kAudioDevicePropertyVolumeScalar, &size, volume); + + return (result == noErr)?GVTrue:GVFalse; + } + + static GVScalar gviGetDeviceVolume(GVDevice device, GVBool isInput) + { + GVBool result; + Float32 channels[2]; + + // check for mono + result = gviGetChannelVolume(device, isInput, 0, &channels[0]); + if(result) + return (GVScalar)channels[0]; + + // get left + result = gviGetChannelVolume(device, isInput, 1, &channels[0]); + if(!result) + return 0; + + // get right + result = gviGetChannelVolume(device, isInput, 2, &channels[1]); + if(!result) + return (GVScalar)channels[0]; + + // return a mix of left and right + return (GVScalar)((channels[0] + channels[1]) / 2); + } + +#endif + +static void gviHardwareSetDeviceVolume(GVDevice device, GVDeviceType type, GVScalar volume) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // get a lock on the device + if(!gviLockDevice(data)) + return; + + // set the volume + if(type & GV_PLAYBACK) + gviSetDeviceVolume(device, GVFalse, volume); + if(type & GV_CAPTURE) + gviSetDeviceVolume(device, GVTrue, volume); + + // release the device lock + gviUnlockDevice(data); +} + +static GVScalar gviHardwareGetDeviceVolume(GVDevice device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVScalar volume = 0; + + // get a lock on the device + if(!gviLockDevice(data)) + return 0; + + // get the volume + if(type & GV_PLAYBACK) + volume = gviGetDeviceVolume(device, GVFalse); + else if(type & GV_CAPTURE) + volume = gviGetDeviceVolume(device, GVTrue); + + // release the device lock + gviUnlockDevice(data); + + return volume; +} + +static void gviHardwareSetCaptureThreshold(GVDevice device, GVScalar threshold) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // get a lock on the device + if(!gviLockDevice(data)) + return; + + // store the threshold + data->m_captureThreshold = threshold; + + // release the device lock + gviUnlockDevice(data); +} + +static GVScalar gviHardwareGetCaptureThreshold(GVDevice device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVScalar threshold; + + // get a lock on the device + if(!gviLockDevice(data)) + return GVFalse; + + // store the threshold + threshold = data->m_captureThreshold; + + // release the device lock + gviUnlockDevice(data); + + return threshold; +} + +static GVBool gviHardwareCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int numFrames; + GVICapturedFrame * frame; + GVScalar frameVolume; + GVBool overThreshold; + + // get a lock on the device + if(!gviLockDevice(data)) + return GVFalse; + + // calculate the number of frames we can put in the packet + numFrames = (*len / GVIEncodedFrameSize); + + // clear the len and volume + *len = 0; + if(volume) + *volume = 0; + + // don't do anything if we're not capturing + if(!data->m_capturing) + { + gviUnlockDevice(data); + return GVFalse; + } + + // don't do anything if there isn't room for a frame + if(numFrames < 1) + { + gviUnlockDevice(data); + return GVFalse; + } + + do + { + // get a frame + frame = gviPopFirstFrame(&data->m_capturedFrames); + if(!frame) + { + gviUnlockDevice(data); + return GVFalse; + } + + // calculate the volume + frameVolume = gviGetSamplesVolume(frame->m_frame, GVISamplesPerFrame); + + // check against the threshold + overThreshold = (frameVolume >= data->m_captureThreshold); + if(overThreshold) + { + // update the time at which we crossed the threshold + data->m_captureLastCrossedThresholdTime = frame->m_frameStamp; + } + else + { + // check if we are still within the hold time + overThreshold = ((GVFrameStamp)(frame->m_frameStamp - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + // check if this should be captured + if(overThreshold) + { + // scale the data + if(data->m_captureVolume < 1.0) + { + int j; + for(j = 0 ; j < GVISamplesPerFrame ; j++) + frame->m_frame[j] = (GVSample)(frame->m_frame[j] * data->m_captureVolume); + } + + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, frame->m_frame, frame->m_frameStamp); + + // encode the frame into the packet + gviEncode(packet, frame->m_frame); + *len = GVIEncodedFrameSize; + *frameStamp = frame->m_frameStamp; + if(volume) + *volume = frameVolume; + } + + // put the frame back in the available list + gviPushFirstFrame(&data->m_captureAvailableFrames, frame); + } + while(!overThreshold); + + // release the device lock + gviUnlockDevice(data); + + return GVTrue; +} + +static int gviHardwareGetAvailableCaptureBytes(GVDevice device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVICapturedFrame * frame; + int count = 0; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return 0; + + // count the number of captured frames + for(frame = data->m_capturedFrames.m_next ; frame ; frame = frame->m_next) + count++; + + // return the number of bytes + return (count * GVIEncodedFrameSize); +} + +static void gviHardwarePlayPacket(GVDevice device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // get a lock on the device + if(!gviLockDevice(data)) + return; + + // check if we're not playing + if(data->m_playing) + { + //add it + gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock); + } + + // release the device lock + gviUnlockDevice(data); +} + +static GVBool gviHardwareIsSourceTalking(GVDevice device, GVSource source) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + GVBool isTalking = GVFalse; + + // get a lock on the device + if(!gviLockDevice(data)) + return GVFalse; + + // check if we're playing + if(data->m_playing) + { + // check if the source is talking + isTalking = gviIsSourceTalking(data->m_playbackSources, source); + } + + // release the device lock + gviUnlockDevice(data); + + return isTalking; +} + +static int gviHardwareListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int numTalking = 0; + + // get a lock on the device + if(!gviLockDevice(data)) + return 0; + + // check if we're not playing + if(data->m_playing) + { + // list them + numTalking = gviListTalkingSources(data->m_playbackSources, sources, maxSources); + } + + // release the device lock + gviUnlockDevice(data); + + return numTalking; +} + +static int gviHardwareGetNumChannels(GVDevice device, GVDeviceType type) +{ + OSStatus result; + UInt32 size; + int numStreams; + + result = AudioDeviceGetPropertyInfo(device->m_deviceID, 0, (type & GV_CAPTURE)?true:false, kAudioDevicePropertyStreams, &size, NULL); + if(result != noErr) + return 1; + + numStreams = (size / sizeof(AudioStreamID)); + + return numStreams; +} + +static void gviHardwareGetChannelName(GVDevice device, GVDeviceType type, int index, gsi_char name[GV_CHANNEL_NAME_LEN]) +{ + OSStatus result; + UInt32 size; + CFStringRef nameRef; + AudioStreamID * streamIDs; + int num; + + // clear the name in case we abort + name[0] = '\0'; + + // figure out how many channels there are + num = gviHardwareGetNumChannels(device, type); + + // make sure the index we have is valid + if((index < 0) || (index >= num)) + return; + + // allocate memory for the stream IDs + size = (num * sizeof(AudioStreamID)); + streamIDs = (AudioStreamID*)gsimalloc(size); + + // get the stream IDs + result = AudioDeviceGetProperty(device->m_deviceID, 0, (type & GV_CAPTURE)?true:false, kAudioDevicePropertyStreams, &size, streamIDs); + if(result == noErr) + { + // get the CFString for this stream + size = sizeof(CFStringRef); + result = AudioStreamGetProperty(streamIDs[index], 0, kAudioDevicePropertyDeviceNameCFString, &size, &nameRef); + if(result != noErr) + nameRef = NULL; + } + + // if there's a blank name, we'll supply our own + if(nameRef && (CFStringGetLength(nameRef) <= 0)) + { + CFRelease(nameRef); + nameRef = NULL; + } + + // if there's no name, give a default + if(nameRef == NULL) + { + CFStringRef format; + + if(type & GV_CAPTURE) + format = CFSTR("Input Channel %d"); + else + format = CFSTR("Output Channel %d"); + + nameRef = CFStringCreateWithFormat(NULL, NULL, format, index); + + CFRelease(format); + } + + // convert it to an array of gsi_char + gviCFStringToString(nameRef, name, GV_CHANNEL_NAME_LEN); + + // release the CFString + CFRelease(nameRef); + + // free the streamIDs + gsifree(streamIDs); +} + +static void gviHardwareSetChannel(GVDevice device, GVDeviceType type, int index) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int num; + + num = gviHardwareGetNumChannels(device, type); + + if((index < 0) || (index >= num)) + return; + + if(type & GV_CAPTURE) + data->m_captureChannel = index; + else + data->m_playbackChannel = index; +} + +static int gviHardwareGetChannel(GVDevice device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type & GV_CAPTURE) + return data->m_captureChannel; + else + return data->m_playbackChannel; +} + +OSStatus gviPropertyListener(AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData) +{ + GVIDevice * device = (GVIDevice*)inClientData; + GVIHardwareData * data = (GVIHardwareData*)device->m_data; + UInt32 value; + UInt32 len = sizeof(UInt32); + OSStatus result; + + result = AudioDeviceGetProperty(device->m_deviceID, 0, isInput, kAudioDevicePropertyDeviceIsAlive, &len, &value); + if((result == noErr) && (value == 0)) + { + // the device has been unplugged + gviLockDevice(device->m_data); + data->m_unplugged = GVTrue; + gviUnlockDevice(device->m_data); + } + + return (OSStatus)0; +} + +static GVBool gviHardwareInitCapture(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + UInt32 size; + OSStatus result; + GVICapturedFrame * frame; + int numCaptureBufferBytes; + int numCaptureBufferFrames; + int i; + + // get the capture format + size = sizeof(AudioStreamBasicDescription); + result = AudioDeviceGetProperty(device->m_deviceID, 0, true, kAudioDevicePropertyStreamFormat, &size, &data->m_captureStreamDescriptor); + if(result != noErr) + return GVFalse; + + // create a converter from the capture format to the GV format + result = AudioConverterNew(&data->m_captureStreamDescriptor, &GVIVoiceFormat, &data->m_captureConverter); + if(result != noErr) + return GVFalse; + + // allocate a capture buffer + data->m_captureBuffer = (GVSample *)gsimalloc(GVIBytesPerFrame); + if(!data->m_captureBuffer) + { + AudioConverterDispose(data->m_captureConverter); + return GVFalse; + } + + // allocate space for holding captured frames + numCaptureBufferBytes = gviMultiplyByBytesPerMillisecond(GVI_CAPTURE_BUFFER_MILLISECONDS); + numCaptureBufferBytes = gviRoundUpToNearestMultiple(numCaptureBufferBytes, GVIBytesPerFrame); + numCaptureBufferFrames = (numCaptureBufferBytes / GVIBytesPerFrame); + for(i = 0 ; i < numCaptureBufferFrames ; i++) + { + frame = (GVICapturedFrame *)gsimalloc(sizeof(GVICapturedFrame) + GVIBytesPerFrame - sizeof(GVSample)); + if(!frame) + { + gviFreeCapturedFrames(&data->m_captureAvailableFrames); + gsifree(data->m_captureBuffer); + AudioConverterDispose(data->m_captureConverter); + return GVFalse; + } + gviPushFirstFrame(&data->m_captureAvailableFrames, frame); + } + + // init the last crossed time + data->m_captureLastCrossedThresholdTime = (data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + + // add property listener + AudioDeviceAddPropertyListener(device->m_deviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, gviPropertyListener, device); + +#if GVI_VOLUME_IN_SOFTWARE + // init volume + data->m_captureVolume = (GVScalar)1.0; +#endif + + return GVTrue; +} + +static GVBool gviHardwareInitPlayback(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + UInt32 size; + OSStatus result; + UInt32 primeMethod; + SInt32 channelMap[100]; + int i; + + // create the array of sources + data->m_playbackSources = gviNewSourceList(); + if(!data->m_playbackSources) + return GVFalse; + + // get the playback format + size = sizeof(AudioStreamBasicDescription); + result = AudioDeviceGetProperty(device->m_deviceID, 0, false, kAudioDevicePropertyStreamFormat, &size, &data->m_playbackStreamDescriptor); + if(result != noErr) + { + gviFreeSourceList(data->m_playbackSources); + return GVFalse; + } + + // create a converter from the GV format to the playback format + result = AudioConverterNew(&GVIVoiceFormat, &data->m_playbackStreamDescriptor, &data->m_playbackConverter); + if(result != noErr) + { + gviFreeSourceList(data->m_playbackSources); + return GVFalse; + } + + // set it to do no priming + primeMethod = kConverterPrimeMethod_None; + result = AudioConverterSetProperty(data->m_playbackConverter, kAudioConverterPrimeMethod, sizeof(UInt32), &primeMethod); + if(result != noErr) + { + AudioConverterDispose(data->m_playbackConverter); + gviFreeSourceList(data->m_playbackSources); + return GVFalse; + } + + // setup the converter to map the input channel to all output channels + result = AudioConverterGetPropertyInfo(data->m_playbackConverter, kAudioConverterChannelMap, &size, NULL); + if(result == noErr) + { + result = AudioConverterGetProperty(data->m_playbackConverter, kAudioConverterChannelMap, &size, channelMap); + if(result == noErr) + { + for(i = 0 ; i < (size / sizeof(SInt32)) ; i++) + channelMap[i] = 0; + + AudioConverterSetProperty(data->m_playbackConverter, kAudioConverterChannelMap, size, channelMap); + } + } + + // allocate the playback buffer + data->m_playbackBuffer = (GVSample *)gsimalloc(GVIBytesPerFrame); + if(!data->m_playbackBuffer) + { + AudioConverterDispose(data->m_playbackConverter); + gviFreeSourceList(data->m_playbackSources); + return GVFalse; + } + + // add property listener + AudioDeviceAddPropertyListener(device->m_deviceID, 0, false, kAudioDevicePropertyDeviceIsAlive, gviPropertyListener, device); + +#if GVI_VOLUME_IN_SOFTWARE + // init volume + data->m_playbackVolume = (GVScalar)1.0; +#endif + + return GVTrue; +} + +static GVBool gviHardwareInitDevice(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int result; + + // init the mutex + result = pthread_mutex_init(&data->m_mutex, NULL); + if(result != 0) + return GVFalse; + + // handle playback specific stuff + if(device->m_types & GV_PLAYBACK) + { + if(!gviHardwareInitPlayback(device)) + { + pthread_mutex_destroy(&data->m_mutex); + return GVFalse; + } + } + + // handle capture specific stuff + if(device->m_types & GV_CAPTURE) + { + if(!gviHardwareInitCapture(device)) + { + pthread_mutex_destroy(&data->m_mutex); + gviCleanupPlayback(data); + return GVFalse; + } + } + + return GVTrue; +} + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVBool result; + + // check for no type + if(!(type & GV_CAPTURE_AND_PLAYBACK)) + return NULL; + + // create a new device + device = gviNewDevice(deviceID, GVHardwareMacOSX, type, sizeof(GVIHardwareData)); + if(!device) + return NULL; + + // init the device + result = gviHardwareInitDevice(device); + if(result == GVFalse) + { + gviFreeDevice(device); + return NULL; + } + + // store the pointers + device->m_methods.m_freeDevice = gviHardwareFreeDevice; + device->m_methods.m_startDevice = gviHardwareStartDevice; + device->m_methods.m_stopDevice = gviHardwareStopDevice; + device->m_methods.m_isDeviceStarted = gviHardwareIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviHardwareSetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviHardwareGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviHardwareSetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviHardwareGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviHardwareGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviHardwareCapturePacket; + device->m_methods.m_playPacket = gviHardwarePlayPacket; + device->m_methods.m_isSourceTalking = gviHardwareIsSourceTalking; + device->m_methods.m_listTalkingSources = gviHardwareListTalkingSources; + device->m_methods.m_getNumChannels = gviHardwareGetNumChannels; + device->m_methods.m_getChannelName = gviHardwareGetChannelName; + device->m_methods.m_setChannel= gviHardwareSetChannel; + device->m_methods.m_getChannel = gviHardwareGetChannel; + + // add it to the list + gviAppendDeviceToList(GVIDevices, device); + + return device; +} diff --git a/xrGameSpy/gamespy/Voice2/gvOSXAudio.h b/xrGameSpy/gamespy/Voice2/gvOSXAudio.h new file mode 100644 index 00000000000..f1ae2b2de06 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvOSXAudio.h @@ -0,0 +1,29 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_OSX_AUDIO_H_ +#define _GV_OSX_AUDIO_H_ + +#include "gvMain.h" + +GVBool gviHardwareStartup(void); +void gviHardwareCleanup(void); +void gviHardwareThink(void); + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Audio.c b/xrGameSpy/gamespy/Voice2/gvPS2Audio.c new file mode 100644 index 00000000000..fd79b0c7fb5 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Audio.c @@ -0,0 +1,107 @@ +#include "gvPS2Audio.h" +#include "gvPS2Spu2.h" +#include "gvPS2Headset.h" +#include "gvPS2Eyetoy.h" + +#if !defined(_PS2) +#error This file should only be used with the PlayStation2 +#endif + +/************** +** FUNCTIONS ** +**************/ +GVBool gviHardwareStartup(void) +{ + // initialize hardware libraries + #if !defined(GV_NO_PS2_SPU2) + if(gviPS2Spu2Startup()) + #endif + { + #if !defined(GV_NO_PS2_HEADSET) + if(gviPS2HeadsetStartup()) + #endif + { + #if !defined(GV_NO_PS2_EYETOY) + if(gviPS2EyetoyStartup()) + #endif + { + return GVTrue; + } + #if !defined(GV_NO_PS2_HEADSET) + gviPS2HeadsetCleanup(); + #endif + } + #if !defined(GV_NO_PS2_SPU2) + gviPS2Spu2Cleanup(); + #endif + } + + return GVFalse; +} + +void gviHardwareCleanup(void) +{ + // cleanup hardware libraries + #if !defined(GV_NO_PS2_SPU2) + gviPS2Spu2Cleanup(); + #endif + #if !defined(GV_NO_PS2_HEADSET) + gviPS2HeadsetCleanup(); + #endif + #if !defined(GV_NO_PS2_EYETOY) + gviPS2EyetoyCleanup(); + #endif +} + +void gviHardwareThink(void) +{ + // let hardware libraries that support playback think + #if !defined(GV_NO_PS2_SPU2) + gviPS2Spu2Think(); + #endif + #if !defined(GV_NO_PS2_HEADSET) + gviPS2HeadsetThink(); + #endif +} + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + int numDevices = 0; + + // enumerate hardware devices + #if !defined(GV_NO_PS2_SPU2) + numDevices += gviPS2Spu2ListDevices(devices + numDevices, maxDevices - numDevices, types); + #endif + #if !defined(GV_NO_PS2_HEADSET) + numDevices += gviPS2HeadsetListDevices(devices + numDevices, maxDevices - numDevices, types); + #endif + #if !defined(GV_NO_PS2_EYETOY) + numDevices += gviPS2EyetoyListDevices(devices + numDevices, maxDevices - numDevices, types); + #endif + + // return the number of devices we found + return numDevices; +} + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + // check if this is the SPU2 device + #if !defined(GV_NO_PS2_SPU2) + if(deviceID == GVPS2Spu2DeviceID) + return gviPS2Spu2NewDevice(deviceID, type); + #endif + + // check if this has the eyetoy bit set + #if !defined(GV_NO_PS2_EYETOY) + if(deviceID & GVI_EYETOY_DEVICEID_BIT) + return gviPS2EyetoyNewDevice(deviceID, type); + #endif + + // this is a headset device + #if !defined(GV_NO_PS2_HEADSET) + return gviPS2HeadsetNewDevice(deviceID, type); + #endif + + // this didn't match anything + return NULL; +} diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Audio.h b/xrGameSpy/gamespy/Voice2/gvPS2Audio.h new file mode 100644 index 00000000000..504032e3439 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Audio.h @@ -0,0 +1,29 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_PS2_AUDIO_H_ +#define _GV_PS2_AUDIO_H_ + +#include "gvMain.h" + +GVBool gviHardwareStartup(void); +void gviHardwareCleanup(void); +void gviHardwareThink(void); + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Eyetoy.c b/xrGameSpy/gamespy/Voice2/gvPS2Eyetoy.c new file mode 100644 index 00000000000..2e5904b9b11 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Eyetoy.c @@ -0,0 +1,560 @@ +#include "gvPS2Eyetoy.h" +#if !defined(GV_NO_PS2_EYETOY) +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#include + +#if !defined(_PS2) +#error This file should only be used with the PlayStation2 +#endif + +/********** +** TYPES ** +**********/ +typedef struct +{ + int m_handle; + + GVBool m_capturing; + GVFrameStamp m_captureClock; + GVScalar m_captureThreshold; + GVFrameStamp m_captureLastCrossedThresholdTime; + GVSample * m_captureBuffer; + int m_captureBufferBytes; +} GVIPS2EyetoyData; + +/************ +** GLOBALS ** +************/ +static GVIDeviceList GVIDevices; +static GVBool GVILGVidInitialized; + +/************** +** FUNCTIONS ** +**************/ +static void gviFreeArrayDevice(void * elem) +{ + GVIDevice * device = *(GVIDevice **)elem; + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + + // close the device + lgVidClose(data->m_handle); + + // cleanup the buffer + gsifree(data->m_captureBuffer); + + // free the device + gviFreeDevice(device); +} + +GVBool gviPS2EyetoyStartup(void) +{ + int result; + + // create the array of devices + GVIDevices = gviNewDeviceList(gviFreeArrayDevice); + if(!GVIDevices) + return GVFalse; + + // initialize the eyetoy library + if(GVILGVidInitialized) + { + result = lgVidReInit(); + } + else + { + lgVidCustomAllocator anAllocator; + anAllocator.pfnMalloc = gsimalloc; + anAllocator.pfnMemAlign = gsimemalign; + anAllocator.pfnFree = gsifree; +#ifdef GVI_LGVID_OLD_DRIVER + result = lgVidInit(NULL); +#else + result = lgVidInit(&anAllocator, NULL, 0); +#endif + + } + if(LGVID_FAILED(result)) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + return GVFalse; + } + + GVILGVidInitialized = GVTrue; + + return GVTrue; +} + +void gviPS2EyetoyCleanup(void) +{ + // free the device array + if(GVIDevices) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + } + + // cleanup the eyetoy library + lgVidUnloadIOPModule(); +} + +int gviPS2EyetoyListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + lgVidDeviceDesc eyetoyDesc; + GVDeviceType supportedTypes; + int result; + int index; + int numDevices = 0; + int modeIndex; + + if(!(types & GV_CAPTURE)) + return 0; + + // find all the eyetoy devices +enumerate: + for(index = 0 ; numDevices < maxDevices ; index++) + { + // get the indexed device + result = lgVidEnumerate(index, &eyetoyDesc); + + // check for the unplugged device error + if(result == LGVID_ERR_DEVICE_LOST) + { + // as recommended by the docs, restart the enumeration + numDevices = 0; + goto enumerate; + } + + // check for any other error + if(LGVID_FAILED(result)) + break; + + // check what this device supports + supportedTypes = (GVDeviceType)0; + for(modeIndex = 0 ; modeIndex < eyetoyDesc.SupportedModesCount ; modeIndex++) + { + if(eyetoyDesc.SupportedModes[modeIndex].OperatingMode.AudioRate == LGVID_AUD_8000) + { + supportedTypes = GV_CAPTURE; + break; + } + } + + if(supportedTypes == GV_CAPTURE) + { +#if defined(GSI_UNICODE) + char name[GV_DEVICE_NAME_LEN]; +#endif + + // store this device's info in the array + devices[numDevices].m_id = (int)(index | GVI_EYETOY_DEVICEID_BIT); +#if defined(GSI_UNICODE) + strncpy(name, eyetoyDesc.FriendlyName, GV_DEVICE_NAME_LEN); + name[GV_DEVICE_NAME_LEN - 1] = '\0'; + AsciiToUCS2String(name, devices[numDevices].m_name); +#else + strncpy(devices[numDevices].m_name, eyetoyDesc.FriendlyName, GV_DEVICE_NAME_LEN); + devices[numDevices].m_name[GV_DEVICE_NAME_LEN - 1] = '\0'; +#endif + devices[numDevices].m_deviceType = supportedTypes; + devices[numDevices].m_defaultDevice = (GVDeviceType)0; // ps2 doesn't support default devices + devices[numDevices].m_hardwareType = GVHardwarePS2Eyetoy; + + // one more device + numDevices++; + } + } + + // return the number of devices we found + return numDevices; +} + +static void gviPS2EyetoyFreeDevice(GVIDevice * device) +{ + // delete it from the array + // it will clear out internal data in the array's free function + gviDeleteDeviceFromList(GVIDevices, device); +} + +static GVBool gviPS2EyetoyStartDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + int result; + + if(type != GV_CAPTURE) + return GVFalse; + + // start streaming + result = lgVidStartStreaming(data->m_handle); + if(LGVID_FAILED(result)) + return GVFalse; + + // no data in the capture buffer + data->m_captureBufferBytes = 0; + + // started capturing + data->m_capturing = GVTrue; + + return GVTrue; +} + +static void gviPS2EyetoyStopDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + + if(!(type & GV_CAPTURE)) + return; + + // stop streaming + lgVidStopStreaming(data->m_handle); + + // stopped capturing + data->m_capturing = GVFalse; + + // so a stop then start isn't continuous + data->m_captureClock++; +} + +static GVBool gviPS2EyetoyIsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + + if(!(type & GV_CAPTURE)) + return GVFalse; + + return data->m_capturing; +} + +static void gviPS2EyetoySetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + lgVidCameraControl cameraControl; + u_char gain; + + if(!(type & GV_CAPTURE)) + return; + + // the gain varies from 0 (silence) to 8 (full gain) + gain = (u_char)(volume * 8); + gain = (unsigned char)min(gain, 8); + + // setup the camera control struct + cameraControl.Flags = LGVID_FLAG_AUDIO_GAIN; + cameraControl.AudioGain = gain; + + // set it + lgVidSetCameraControl(data->m_handle, &cameraControl); +} + +static GVScalar gviPS2EyetoyGetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + lgVidCameraControl cameraControl; + int result; + + if(!(type & GV_CAPTURE)) + return 0; + + cameraControl.Flags = LGVID_FLAG_AUDIO_GAIN; + result = lgVidGetCameraControl(data->m_handle, &cameraControl); + if(LGVID_FAILED(result) || !(cameraControl.Flags & LGVID_FLAG_AUDIO_GAIN)) + return 1.0; + + return (GVScalar)(cameraControl.AudioGain / 8.0); +} + +static void gviPS2EyetoySetCaptureThreshold(GVIDevice * device, GVScalar threshold) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + data->m_captureThreshold = threshold; +} + +static GVScalar gviPS2EyetoyGetCaptureThreshold(GVIDevice * device) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + return data->m_captureThreshold; +} + +static int gviPS2EyetoyGetAvailableCaptureBytes(GVDevice device) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return 0; + + // eyetoy's don't provide this info + // so, let the app think something is available + return 1; +} + +static void gviProcessCapturedFrame(GVDevice device, GVByte * frameOut, GVSample * frameIn, GVScalar * volume, GVBool * threshold) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + GVScalar frameVolume; + + // get the volume if requested + if(volume) + { + frameVolume = gviGetSamplesVolume(frameIn, GVISamplesPerFrame); + if(frameVolume > *volume) + *volume = frameVolume; + } + + // check against the threshold + if(threshold && !*threshold) + { + if(volume) + { + // we already got the volume, so use that to check + *threshold = (*volume >= data->m_captureThreshold); + } + else + { + // we didn't get a volume, so check the samples directly + *threshold = gviIsOverThreshold(frameIn, GVISamplesPerFrame, data->m_captureThreshold); + } + } + + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, frameIn, data->m_captureClock); + + // increment the capture clock + data->m_captureClock++; + + // encode the buffer into the packet + gviEncode(frameOut, frameIn); +} + +static GVBool gviPS2EyetoyCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVIPS2EyetoyData * data = (GVIPS2EyetoyData *)device->m_data; + lgVidAudioDesc audioDesc; + GVBool overThreshold; + int result; + int numFrames; + int lenAvailable; + int framesAvailable; + int framesCaptured; + GVSample * frameIn; + GVByte * frameOut; + + // figure out how many encoded bytes they can handle + lenAvailable = *len; + + // clear the len and volume + *len = 0; + if(volume) + *volume = 0; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return GVFalse; + + // set the frameStamp + *frameStamp = data->m_captureClock; + + // figure out how many frames they can handle + framesAvailable = (lenAvailable / GVIEncodedFrameSize); + + // how many frames have we already captured? + framesCaptured = (data->m_captureBufferBytes / GVIBytesPerFrame); + + // handle the data one frame at a time + overThreshold = GVFalse; + frameIn = data->m_captureBuffer; + frameOut = packet; + for(numFrames = 0 ; (numFrames < framesAvailable) && (numFrames < framesCaptured) ; numFrames++) + { + // process the frame + gviProcessCapturedFrame(device, frameOut, frameIn, volume, &overThreshold); + + // update the frame pointers + frameIn += GVISamplesPerFrame; + frameOut += GVIEncodedFrameSize; + } + + // adjust buffer based on what we delivered + if(numFrames) + { + data->m_captureBufferBytes -= (numFrames * GVIBytesPerFrame); + if(data->m_captureBufferBytes) + memmove(data->m_captureBuffer, data->m_captureBuffer + (numFrames * GVIBytesPerFrame), (unsigned int)data->m_captureBufferBytes); + } + + // read from the device if they still have available frames + if(numFrames < framesAvailable) + { + // if it got here, any pending frames should have already been handled + assert(data->m_captureBufferBytes < GVIBytesPerFrame); + + // setup the audio descriptor + audioDesc.Samples = (((u_char *)data->m_captureBuffer) + data->m_captureBufferBytes); + + // read the audio + result = lgVidReadAudio(data->m_handle, &audioDesc); + if(LGVID_FAILED(result)) + { + gviDeviceUnplugged(device); + return GVFalse; + } + + // check that we got something + if(audioDesc.TimeStamp != -1) + { + // add to our total + data->m_captureBufferBytes += audioDesc.TotalBytes; + + // set the frame buffer pointer + frameIn = data->m_captureBuffer; + + for( ; numFrames < framesAvailable ; numFrames++) + { + // check if we have a full frame + if(data->m_captureBufferBytes < GVIBytesPerFrame) + break; + + // process the frame + gviProcessCapturedFrame(device, frameOut, frameIn, volume, &overThreshold); + + // update the capture buffer count + data->m_captureBufferBytes -= GVIBytesPerFrame; + + // update the frame pointers + frameIn += GVISamplesPerFrame; + frameOut += GVIEncodedFrameSize; + } + + // move what we have to the front of the buffer + if(data->m_captureBufferBytes) + memmove(data->m_captureBuffer, frameIn, (unsigned)data->m_captureBufferBytes); + } + } + + // check if this packet crossed the threshold + if(overThreshold) + { + // store the time we crossed it + data->m_captureLastCrossedThresholdTime = data->m_captureClock; + } + else + { + // check if we are still on the overhang from a previous crossing + overThreshold = ((GVFrameStamp)(*frameStamp - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + // set the len + *len = (numFrames * GVIEncodedFrameSize); + + // return false if we didn't get a packet + if(!overThreshold || (*len == 0)) + return GVFalse; + + return GVTrue; +} + +static GVBool gviPS2EyetoyInitDevice(GVIDevice * device, int deviceIndex, GVDeviceType type) +{ + lgVidDeviceDesc eyetoyDesc; + lgVidOpenParam openParam; + GVIPS2EyetoyData * data; + int result; + int size; + int i; + + // we only support capture + if(type != GV_CAPTURE) + return GVFalse; + + // enum the device to get a list of supported modes + result = lgVidEnumerate(deviceIndex, &eyetoyDesc); + if(LGVID_FAILED(result)) + return GVFalse; + + // find a supported device mode + //TODO: make this better at choosing the video mode that uses the least CPU and memory (ideally none at all) + for(i = 0 ; i < eyetoyDesc.SupportedModesCount ; i++) + { + if(eyetoyDesc.SupportedModes[i].OperatingMode.AudioRate == LGVID_AUD_8000) + break; + } + if(i == eyetoyDesc.SupportedModesCount) + return GVFalse; + + // setup the open param + memcpy(&openParam.OperatingMode, &eyetoyDesc.SupportedModes[i].OperatingMode, sizeof(lgVidOperatingMode)); + openParam.AudioBufferDuration = GVI_CAPTURE_BUFFER_MILLISECONDS; + + // get a pointer to the data + data = (GVIPS2EyetoyData *)device->m_data; + + // open the device + result = lgVidOpen(deviceIndex, &openParam, &data->m_handle); + if(LGVID_FAILED(result)) + return GVFalse; + + // set some data vars + data->m_captureLastCrossedThresholdTime = (GVFrameStamp)(data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + + // allocate the buffer + size = (GVI_CAPTURE_BUFFER_MILLISECONDS * GV_BYTES_PER_SECOND / 1000); + size += GVIBytesPerFrame; + data->m_captureBuffer = (GVSample *)gsimalloc((unsigned)size); + if(!data->m_captureBuffer) + { + lgVidClose(data->m_handle); + return GVFalse; + } + + return GVTrue; +} + +GVDevice gviPS2EyetoyNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVBool result; + + // check for wrong type + if(type != GV_CAPTURE) + return NULL; + + // check for the eyetoy bit + if(!(deviceID & GVI_EYETOY_DEVICEID_BIT)) + return NULL; + + // create a new device + device = gviNewDevice(deviceID, GVHardwarePS2Eyetoy, type, sizeof(GVIPS2EyetoyData)); + if(!device) + return NULL; + + // init the device + result = gviPS2EyetoyInitDevice(device, (int)(deviceID & ~GVI_EYETOY_DEVICEID_BIT), type); + if(result == GVFalse) + { + gviFreeDevice(device); + return NULL; + } + + // store the pointers + device->m_methods.m_freeDevice = gviPS2EyetoyFreeDevice; + device->m_methods.m_startDevice = gviPS2EyetoyStartDevice; + device->m_methods.m_stopDevice = gviPS2EyetoyStopDevice; + device->m_methods.m_isDeviceStarted = gviPS2EyetoyIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviPS2EyetoySetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviPS2EyetoyGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviPS2EyetoySetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviPS2EyetoyGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviPS2EyetoyGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviPS2EyetoyCapturePacket; + + // add it to the list + gviAppendDeviceToList(GVIDevices, device); + + return device; +} + +#endif //!defined(GV_NO_PS2_EYETOY) diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Eyetoy.h b/xrGameSpy/gamespy/Voice2/gvPS2Eyetoy.h new file mode 100644 index 00000000000..6b4983cf65f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Eyetoy.h @@ -0,0 +1,32 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_PS2_EYETOY_H_ +#define _GV_PS2_EYETOY_H_ + +#include "gvMain.h" + +// this is set on all eyetoy GVDeviceID's +// it prevents a conflict with headset id's, which also use a 0-based index +#define GVI_EYETOY_DEVICEID_BIT 0x80000000 + +GVBool gviPS2EyetoyStartup(void); +void gviPS2EyetoyCleanup(void); + +int gviPS2EyetoyListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviPS2EyetoyNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Headset.c b/xrGameSpy/gamespy/Voice2/gvPS2Headset.c new file mode 100644 index 00000000000..39aa74ab0e2 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Headset.c @@ -0,0 +1,751 @@ +#include "gvPS2Headset.h" +#if !defined(GV_NO_PS2_HEADSET) +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#include + +#if !defined(_PS2) +#error This file should only be used with the PlayStation2 +#endif + +/************ +** DEFINES ** +************/ +#define GVI_PLAYBACK_STAYAHEAD_MILLISECONDS 50 + +/********** +** TYPES ** +**********/ +typedef struct +{ + int m_handle; + + GVBool m_playing; + GVScalar m_playbackVolume; + GVFrameStamp m_playbackClock; + GVISourceList m_playbackSources; + GVSample * m_playbackBuffer; + + GVBool m_capturing; + GVScalar m_captureVolume; + GVFrameStamp m_captureClock; + GVScalar m_captureThreshold; + GVFrameStamp m_captureLastCrossedThresholdTime; + GVSample * m_captureBuffer; + int m_captureBufferBytes; +} GVIPS2HeadsetData; + +/************ +** GLOBALS ** +************/ +static GVIDeviceList GVIDevices; + +/************** +** FUNCTIONS ** +**************/ +static GVIDevice * gviFindDeviceByID(GVDeviceID deviceID) +{ + GVIDevice * device; + int num; + int i; + + num = gviGetNumDevices(GVIDevices); + for(i = 0 ; i < num ; i++) + { + device = gviGetDevice(GVIDevices, i); + if(device->m_deviceID == deviceID) + return device; + } + + return NULL; +} + +static void gviFreeArrayDevice(void * elem) +{ + GVIDevice * device = *(GVIDevice **)elem; + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + // close the device + lgAudClose(data->m_handle); + + // playback specific cleanup + if(device->m_types & GV_PLAYBACK) + { + if(data->m_playbackSources) + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + } + + // capture specific cleanup + if(device->m_types & GV_CAPTURE) + { + gsifree(data->m_captureBuffer); + } + + // free the device + gviFreeDevice(device); +} + +GVBool gviPS2HeadsetStartup(void) +{ + int result; + + // create the array of devices + GVIDevices = gviNewDeviceList(gviFreeArrayDevice); + if(!GVIDevices) + return GVFalse; + + // initialize the headset library + result = lgAudInit(gsimalloc, gsifree); + if(LGAUD_FAILED(result)) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + return GVFalse; + } + + return GVTrue; +} + +void gviPS2HeadsetCleanup(void) +{ + // free the device array + if(GVIDevices) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + } + + // cleanup the headset library + lgAudDeInit(); +} + +static GVBool gviPlaybackDeviceThink(GVIDevice * device) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + int result; + int remainingBytes; + int numFrames; + int newBytes; + GVBool wroteToBuffer; + int size; + int i; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVTrue; + + // get the remaining bytes + result = lgAudGetRemainingPlaybackBytes(data->m_handle, &remainingBytes); + if(LGAUD_FAILED(result)) + return GVFalse; + + // figure out how many bytes we need to write to stay ahead + newBytes = (gviMultiplyByBytesPerMillisecond(GVI_PLAYBACK_STAYAHEAD_MILLISECONDS) - remainingBytes); + newBytes = gviRoundUpToNearestMultiple(newBytes, GVIBytesPerFrame); + + // figure out the number of frames that is + numFrames = (newBytes / GVIBytesPerFrame); + + // write the frames + for(i = 0 ; i < numFrames ; i++) + { + // write a frame of sources to our buffer + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, data->m_playbackBuffer, 1); + + // clear it if nothing was written + if(!wroteToBuffer) + memset(data->m_playbackBuffer, 0, (unsigned int)GVIBytesPerFrame); + + // filter + if(device->m_playbackFilterCallback) + device->m_playbackFilterCallback(device, data->m_playbackBuffer, data->m_playbackClock); + + // send it to the device + size = GVIBytesPerFrame; + result = lgAudWrite(data->m_handle, LGAUD_BLOCKMODE_BLOCKING, (u_char *)data->m_playbackBuffer, &size); + if(LGAUD_FAILED(result)) + return GVFalse; + + // update the clock + data->m_playbackClock++; + } + + return GVTrue; +} + +void gviPS2HeadsetThink(void) +{ + GVIDevice * device; + GVBool rcode; + int num; + int i; + + if(!GVIDevices) + return; + + // loop through the devices backwards to that we can remove devices as we go + num = gviGetNumDevices(GVIDevices); + for(i = (num - 1) ; i >= 0 ; i--) + { + // get the device + device = gviGetDevice(GVIDevices, i); + + // // check if playback is setup on the device + if(device->m_types & GV_PLAYBACK) + { + // let it think + rcode = gviPlaybackDeviceThink(device); + + // check if the device was unplugged + if(!rcode) + gviDeviceUnplugged(device); + } + } +} + +static GVBool gviDoesSupportOurFormat(lgAudSamplingFormat * formats, int count) +{ + int i; + + for(i = 0 ; i < count ; i++) + { + if(formats[i].Channels == 1) + if(formats[i].BitResolution == 16) + if(formats[i].LowerSamplingRate <= GV_SAMPLES_PER_SECOND) + if(formats[i].HigherSamplingRate >= GV_SAMPLES_PER_SECOND) + return GVTrue; + } + + return GVFalse; +} + +int gviPS2HeadsetListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + lgAudDeviceDesc headsetDesc; + GVDeviceType supportedTypes; + int result; + int index; + int numDevices = 0; + +enumerate: + for(index = 0 ; numDevices < maxDevices ; index++) + { + // get the indexed device + result = lgAudEnumerate(index, &headsetDesc); + + // check for the unplugged device error + if(result == LGAUD_ERR_DEVICE_LOST) + { + // as recommended by the docs, restart the enumeration + numDevices = 0; + goto enumerate; + } + + // check for any other error + if(LGAUD_FAILED(result)) + break; + + // check what this device supports + supportedTypes = (GVDeviceType)0; + if(gviDoesSupportOurFormat(headsetDesc.RecordingFormats, headsetDesc.RecordingFormatsCount)) + supportedTypes |= GV_CAPTURE; + if(gviDoesSupportOurFormat(headsetDesc.PlaybackFormats, headsetDesc.PlaybackFormatsCount)) + supportedTypes |= GV_PLAYBACK; + + // only add it if it supports a format for a type that the app requested + // this library doesn't support device names or default devices + if(supportedTypes & types) + { + // store this device's info in the array + devices[numDevices].m_id = index; + devices[numDevices].m_deviceType = supportedTypes; + devices[numDevices].m_defaultDevice = (GVDeviceType)0; // ps2 doesn't support default devices + + // set the name and the hardware type based on the capabilities + if(supportedTypes == GV_CAPTURE) + { + _tcscpy(devices[numDevices].m_name, _T("USB Microphone")); + devices[numDevices].m_hardwareType = GVHardwarePS2Microphone; + } + else if(supportedTypes == GV_PLAYBACK) + { + _tcscpy(devices[numDevices].m_name, _T("USB Speakers")); + devices[numDevices].m_hardwareType = GVHardwarePS2Speakers; + } + else + { + _tcscpy(devices[numDevices].m_name, _T("USB Headset")); + devices[numDevices].m_hardwareType = GVHardwarePS2Headset; + } + + // one more device + numDevices++; + } + } + + // return the number of devices we found + return numDevices; +} + +static void gviPS2HeadsetFreeDevice(GVIDevice * device) +{ + // delete it from the array + // it will clear out internal data in the array's free function + gviDeleteDeviceFromList(GVIDevices, device); +} + +static GVBool gviStartPlaybackDevice(GVIPS2HeadsetData * data) +{ + int result; + + // start the buffer + result = lgAudStartPlayback(data->m_handle); + if(LGAUD_FAILED(result)) + return GVFalse; + + // clear the clock + data->m_playbackClock = 0; + + // started playing + data->m_playing = GVTrue; + + return GVTrue; +} + +static GVBool gviStartCaptureDevice(GVIPS2HeadsetData * data) +{ + int result; + + // start the buffer + result = lgAudStartRecording(data->m_handle); + if(LGAUD_FAILED(result)) + return GVFalse; + + // no data in the capture buffer + data->m_captureBufferBytes = 0; + + // started capturing + data->m_capturing = GVTrue; + + return GVTrue; +} + +static GVBool gviPS2HeadsetStartDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + if(type == GV_PLAYBACK) + return gviStartPlaybackDevice(data); + if(type == GV_CAPTURE) + return gviStartCaptureDevice(data); + if(type == GV_CAPTURE_AND_PLAYBACK) + { + if(!gviStartPlaybackDevice(data)) + return GVFalse; + if(!gviStartCaptureDevice(data)) + { + device->m_methods.m_stopDevice(device, GV_PLAYBACK); + return GVFalse; + } + return GVTrue; + } + return GVFalse; +} + +static void gviPS2HeadsetStopDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + if(type & GV_PLAYBACK) + { + // stop the playback buffer + lgAudStopPlayback(data->m_handle); + + // stopped playing + data->m_playing = GVFalse; + + // clear any pending sources & buffers + gviClearSourceList(data->m_playbackSources); + } + if(type & GV_CAPTURE) + { + // stop the capture buffer + lgAudStopRecording(data->m_handle); + + // stopped capturing + data->m_capturing = GVFalse; + + // so a stop then start isn't continuous + data->m_captureClock++; + } +} + +static GVBool gviPS2HeadsetIsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + if(type == GV_PLAYBACK) + return data->m_playing; + if(type == GV_CAPTURE) + return data->m_capturing; + if(type == GV_CAPTURE_AND_PLAYBACK) + return (data->m_playing && data->m_capturing); + return GVFalse; +} + +static void gviPS2HeadsetSetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + if(type & GV_PLAYBACK) + { + lgAudSetPlaybackVolume(data->m_handle, LGAUD_CH_BOTH, (u_char)(volume * 100)); + data->m_playbackVolume = volume; + } + if(type & GV_CAPTURE) + { + lgAudSetRecordingVolume(data->m_handle, LGAUD_CH_BOTH, (u_char)(volume * 100)); + data->m_captureVolume = volume; + } +} + +static GVScalar gviPS2HeadsetGetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + if(type & GV_PLAYBACK) + return data->m_playbackVolume; + return data->m_captureVolume; +} + +static void gviPS2HeadsetSetCaptureThreshold(GVIDevice * device, GVScalar threshold) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + data->m_captureThreshold = threshold; +} + +static GVScalar gviPS2HeadsetGetCaptureThreshold(GVIDevice * device) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + return data->m_captureThreshold; +} + +static int gviPS2HeadsetGetAvailableCaptureBytes(GVDevice device) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + int result; + int newBytes; + int numFrames; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return 0; + + // get the number of new bytes + result = lgAudGetAvailableRecordingBytes(data->m_handle, &newBytes); + if(LGAUD_FAILED(result)) + { + gviDeviceUnplugged(device); + return 0; + } + + // figure out how many frames this is + numFrames = (newBytes / GVIBytesPerFrame); + + // calculate how many bytes this is once encoded + newBytes = (numFrames * GVIEncodedFrameSize); + + return newBytes; +} + +static void gviProcessCapturedFrame(GVDevice device, GVByte * frameOut, GVSample * frameIn, GVScalar * volume, GVBool * threshold) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + GVScalar frameVolume; + + // get the volume if requested + if(volume) + { + frameVolume = gviGetSamplesVolume(frameIn, GVISamplesPerFrame); + if(frameVolume > *volume) + *volume = frameVolume; + } + + // check against the threshold + if(threshold && !*threshold) + { + if(volume) + { + // we already got the volume, so use that to check + *threshold = (*volume >= data->m_captureThreshold); + } + else + { + // we didn't get a volume, so check the samples directly + *threshold = gviIsOverThreshold(frameIn, GVISamplesPerFrame, data->m_captureThreshold); + } + } + + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, frameIn, data->m_captureClock); + + // increment the capture clock + data->m_captureClock++; + + // encode the buffer into the packet + gviEncode(frameOut, frameIn); +} + +static GVBool gviPS2HeadsetCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + GVBool overThreshold; + int result; + int numFrames; + int readSize; + int lenAvailable; + int framesAvailable; + GVSample * frameIn; + GVByte * frameOut; + + // figure out how many encoded bytes they can handle + lenAvailable = *len; + + // clear the len and volume + *len = 0; + if(volume) + *volume = 0; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return GVFalse; + + // set the frameStamp + *frameStamp = data->m_captureClock; + + // figure out how many frames they can handle + framesAvailable = (lenAvailable / GVIEncodedFrameSize); + + // handle the data one frame at a time + overThreshold = GVFalse; + frameIn = data->m_captureBuffer; + frameOut = packet; + for(numFrames = 0 ; numFrames < framesAvailable ; numFrames++) + { + // read this frame + readSize = (GVIBytesPerFrame - data->m_captureBufferBytes); + result = lgAudRead(data->m_handle, LGAUD_BLOCKMODE_NOT_BLOCKING, ((u_char *)data->m_captureBuffer) + data->m_captureBufferBytes, &readSize); + if(LGAUD_FAILED(result)) + { + gviDeviceUnplugged(device); + return GVFalse; + } + + // check if we have a full frame + if(readSize != (GVIBytesPerFrame - data->m_captureBufferBytes)) + { + // add to our count of how many bytes we have + data->m_captureBufferBytes += readSize; + break; + } + + // process the frame + gviProcessCapturedFrame(device, frameOut, frameIn, volume, &overThreshold); + + // we got a full frame, so there's no leftover + data->m_captureBufferBytes = 0; + + // update the frame pointer + frameOut += GVIEncodedFrameSize; + } + + // check if this packet crossed the threshold + if(overThreshold) + { + // store the time we crossed it + data->m_captureLastCrossedThresholdTime = data->m_captureClock; + } + else + { + // check if we are still on the overhang from a previous crossing + overThreshold = ((GVFrameStamp)(*frameStamp - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + // set the len + *len = (numFrames * GVIEncodedFrameSize); + + // return false if we didn't get a packet + if(!overThreshold || (*len == 0)) + return GVFalse; + + return GVTrue; +} + +static void gviPS2HeadsetPlayPacket(GVIDevice * device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return; + + //add it + gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock); +} + +static GVBool gviPS2HeadsetIsSourceTalking(GVDevice device, GVSource source) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviIsSourceTalking(data->m_playbackSources, source); +} + +static int gviPS2HeadsetListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + GVIPS2HeadsetData * data = (GVIPS2HeadsetData *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviListTalkingSources(data->m_playbackSources, sources, maxSources); +} + +static GVBool gviPS2HeadsetInitDevice(GVIDevice * device, int deviceIndex, GVDeviceType type) +{ + GVIPS2HeadsetData * data; + lgAudOpenParam openParam; + int result; + + // setup the open param + openParam.Mode = 0; + if(type & GV_CAPTURE) + { + openParam.Mode |= LGAUD_MODE_RECORDING; + openParam.RecordingFormat.Channels = 1; + openParam.RecordingFormat.BitResolution = 16; + openParam.RecordingFormat.SamplingRate = GV_SAMPLES_PER_SECOND; + openParam.RecordingFormat.BufferMilliseconds = GVI_CAPTURE_BUFFER_MILLISECONDS; + } + if(type & GV_PLAYBACK) + { + openParam.Mode |= LGAUD_MODE_PLAYBACK; + openParam.PlaybackFormat.Channels = 1; + openParam.PlaybackFormat.BitResolution = 16; + openParam.PlaybackFormat.SamplingRate = GV_SAMPLES_PER_SECOND; + openParam.PlaybackFormat.BufferMilliseconds = GVI_PLAYBACK_BUFFER_MILLISECONDS; + } + + // get a pointer to the data + data = (GVIPS2HeadsetData *)device->m_data; + + // open the device + result = lgAudOpen(deviceIndex, &openParam, &data->m_handle); + if(LGAUD_FAILED(result)) + return GVFalse; + + // handle playback specific stuff + if(type & GV_PLAYBACK) + { + // create the array of sources + data->m_playbackSources = gviNewSourceList(); + if(!data->m_playbackSources) + { + lgAudClose(data->m_handle); + return GVFalse; + } + + // allocate the buffer + data->m_playbackBuffer = (GVSample *)gsimalloc((unsigned int)GVIBytesPerFrame); + if(!data->m_playbackBuffer) + { + gviFreeSourceList(data->m_playbackSources); + lgAudClose(data->m_handle); + return GVFalse; + } + + // set data + //data->m_playbackVolume = gviGetMixerVolume(data, GV_PLAYBACK); + data->m_playbackVolume = 1.0; + } + + // handle capture specific stuff + if(type & GV_CAPTURE) + { + // set some data vars + data->m_captureVolume = 1.0; + data->m_captureLastCrossedThresholdTime = (GVFrameStamp)(data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + + // allocate the buffer + data->m_captureBuffer = (GVSample *)gsimalloc((unsigned int)GVIBytesPerFrame); + if(!data->m_captureBuffer) + { + if(type & GV_PLAYBACK) + { + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + } + lgAudClose(data->m_handle); + return GVFalse; + } + } + + return GVTrue; +} + +GVDevice gviPS2HeadsetNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVBool result; + + // check for no type + if(!(type & GV_CAPTURE_AND_PLAYBACK)) + return NULL; + + // check if the device already exists + if(gviFindDeviceByID(deviceID)) + return NULL; + + // create a new device + device = gviNewDevice(deviceID, GVHardwarePS2Headset, type, sizeof(GVIPS2HeadsetData)); + if(!device) + return NULL; + + // init the device + result = gviPS2HeadsetInitDevice(device, deviceID, type); + if(result == GVFalse) + { + gviFreeDevice(device); + return NULL; + } + + // store the pointers + device->m_methods.m_freeDevice = gviPS2HeadsetFreeDevice; + device->m_methods.m_startDevice = gviPS2HeadsetStartDevice; + device->m_methods.m_stopDevice = gviPS2HeadsetStopDevice; + device->m_methods.m_isDeviceStarted = gviPS2HeadsetIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviPS2HeadsetSetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviPS2HeadsetGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviPS2HeadsetSetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviPS2HeadsetGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviPS2HeadsetGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviPS2HeadsetCapturePacket; + device->m_methods.m_playPacket = gviPS2HeadsetPlayPacket; + device->m_methods.m_isSourceTalking = gviPS2HeadsetIsSourceTalking; + device->m_methods.m_listTalkingSources = gviPS2HeadsetListTalkingSources; + + // add it to the list + gviAppendDeviceToList(GVIDevices, device); + + return device; +} + +#endif //!defined(GV_NO_PS2_HEADSET) diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Headset.h b/xrGameSpy/gamespy/Voice2/gvPS2Headset.h new file mode 100644 index 00000000000..6f6481ed3a2 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Headset.h @@ -0,0 +1,29 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_PS2_HEADSET_H_ +#define _GV_PS2_HEADSET_H_ + +#include "gvMain.h" + +GVBool gviPS2HeadsetStartup(void); +void gviPS2HeadsetCleanup(void); +void gviPS2HeadsetThink(void); + +int gviPS2HeadsetListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviPS2HeadsetNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Spu2.c b/xrGameSpy/gamespy/Voice2/gvPS2Spu2.c new file mode 100644 index 00000000000..b2f157c99ee --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Spu2.c @@ -0,0 +1,681 @@ +#include "gvPS2Spu2.h" +#if !defined(GV_NO_PS2_SPU2) +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#include +#include + +#if !defined(_PS2) +#error This file should only be used with the PlayStation2 +#endif + +// Thanks to Martin Jajam at Coresoft for original SPU2 code +//////////////////////////////////////////////////////////// + +/* +The input block we are writing to takes data in the form + +---1st half of buffer----- +256 sample Left channel = 512 bytes ( 1 block ) +256 sample Right channel = 512 bytes + +---2nd half of buffer----- +256 sample Left channel = 512 bytes +256 sample Right channel = 512 bytes + +*/ + +/************ +** DEFINES ** +************/ +#define bss_align(val) \ + __attribute__ ((aligned(val))) __attribute__ ((section (".bss"))) +#define LIMIT(x, minx, maxx) ((x) < (minx) ? (minx) : ((x) > (maxx) ? (maxx) : (x))) + +#define AUTODMA_CH 1 + +#define SPU_BLOCK_SIZE 512 // in samples +#define IOP_BUFF_SIZE 12288 // 24 blocks +#define SPU_BUFF_SIZE 2048 // 4 blocks + +#define CORE0_INPUT_L (0x2000)// * 2) +#define CORE0_INPUT_R (0x2200)// * 2) +#define CORE1_INPUT_L (0x2400)// * 2) +#define CORE1_INPUT_R (0x2600)// * 2) +#if (AUTODMA_CH == 0) +#define CORE_INPUT_L CORE0_INPUT_L +#define CORE_INPUT_R CORE0_INPUT_R +#else +#define CORE_INPUT_L CORE1_INPUT_L +#define CORE_INPUT_R CORE1_INPUT_R +#endif + +// each DMA is 4 blocks = 256 samples * 2 bytes * 4 blocks = 2048 bytes +#define EEBUFFER_SAMPLE_COUNT (IOP_BUFF_SIZE/4) // 2 bytes sample + +/********** +** TYPES ** +**********/ +typedef struct +{ + GVBool m_playing; + GVScalar m_playbackVolume; + GVFrameStamp m_playbackClock; + GVISourceList m_playbackSources; + GVSample * m_playbackBuffer; + int m_playbackBufferPos; +} GVIPS2Spu2Data; + +/************ +** GLOBALS ** +************/ +const GVDeviceID GVPS2Spu2DeviceID = -1; +static GVIDevice * GVIPS2Spu2Device; + +static gsi_u16 EEBuffer[IOP_BUFF_SIZE] bss_align(64); +static int IOPBuffer = 0; +static int gEEStreanIntr = 0; // flag for when an endpoint is reached by the audio play head. +static int gEEDataSampleCount = 0; // how many samples do we have buffered up? ( 0 - 256 ) + +/************** +** FUNCTIONS ** +**************/ +static int DMA_EE_To_IOP(int dst, u_char *src, int size) +{ + sceSifDmaData transData; + int did; + + assert((((gsi_u32)src) & 0x3f) == 0); // assert 64 byte aligned + + if (size <= 0) { + return 0; + } + + transData.data = (u_int)src; + transData.addr = (u_int)dst; + transData.size = (unsigned int)size; + transData.mode = 0; // caution + FlushCache(0); + + did = (int)sceSifSetDma( &transData, 1 ); + + while (sceSifDmaStat((unsigned int)did) >= 0) + ; + + return size; +} + +static int cbEEStreamTransfer( void* common ) +{ + gEEStreanIntr = 1; + GSI_UNUSED(common); + return 0; +} + +static void EEStreamClearSPUBuffer() +{ + memset (EEBuffer, 0, IOP_BUFF_SIZE); + FlushCache(0); + DMA_EE_To_IOP( IOPBuffer, // IOP side destination address + (u_char *)EEBuffer, // EE side source address + IOP_BUFF_SIZE); + + DMA_EE_To_IOP( IOPBuffer + IOP_BUFF_SIZE, // IOP side destination address + (u_char *)EEBuffer, // EE side source address + IOP_BUFF_SIZE); + + // Clear out SPU2 input area + sceSdRemote(1, rSdVoiceTrans, AUTODMA_CH, SD_TRANS_MODE_WRITE | SD_TRANS_BY_DMA, + IOPBuffer, CORE_INPUT_L, 0x800 ); + sceSdRemote(1, rSdVoiceTrans, AUTODMA_CH, SD_TRANS_MODE_WRITE | SD_TRANS_BY_DMA, + IOPBuffer + IOP_BUFF_SIZE, CORE_INPUT_R, 0x800 ); + + sceSdRemote (1, rSdVoiceTransStatus, AUTODMA_CH, SD_TRANS_STATUS_WAIT); +} + +GVBool gviPS2Spu2Startup(void) +{ + // clear the device pointer + GVIPS2Spu2Device = NULL; + + // do general initialization + if(sceSdRemoteInit() != 0) + return GVFalse; + if(sceSdRemote(1, rSdInit, SD_INIT_COLD) != 0) + return GVFalse; + if(sceSifInitIopHeap() != 0) + return GVFalse; + + return GVTrue; +} + +void gviPS2Spu2Cleanup(void) +{ + // free the device array + if(GVIPS2Spu2Device) + gviFreeDevice(GVIPS2Spu2Device); +} + +static void AudioUpSample(gsi_i16* Dest48Khz, const gsi_i16* Src8Khz, int num8Khzsamples) +// 16 bit audio upsample from 8khz to 48khz +// numsamples = Src samples (8khz ) +{ +#if(0) + // Point sample + while (num8Khzsamples) + { + int a = Src8Khz[0]; + + + // bad alias upsampling code here.... + Dest48Khz[0] = a; + Dest48Khz[1] = a; + Dest48Khz[2] = a; + Dest48Khz[3] = a; + Dest48Khz[4] = a; + Dest48Khz[5] = a; + + Dest48Khz +=6; + Src8Khz ++; + num8Khzsamples--; + } +#elif (1) + // linear interpolate + int a=0,b=0; + while (num8Khzsamples - 1) + { + + a = Src8Khz[0]; + b = Src8Khz[1]; + + + // bad alias upsampling code here.... + Dest48Khz[0] = (gsi_i16)a; + Dest48Khz[1] = (gsi_i16)((5*a)/6 +(1*b)/6); + Dest48Khz[2] = (gsi_i16)((4*a)/6 +(2*b)/6); + Dest48Khz[3] = (gsi_i16)((3*a)/6 +(3*b)/6); + Dest48Khz[4] = (gsi_i16)((2*a)/6 +(4*b)/6); + Dest48Khz[5] = (gsi_i16)((1*a)/6 +(5*b)/6); + + Dest48Khz +=6; + Src8Khz ++; + num8Khzsamples--; + } + Dest48Khz[0] = (gsi_i16)b; + Dest48Khz[1] = (gsi_i16)b; + Dest48Khz[2] = (gsi_i16)b; + Dest48Khz[3] = (gsi_i16)b; + Dest48Khz[4] = (gsi_i16)b; + Dest48Khz[5] = (gsi_i16)b; + +#else + + // use catmull-rom spline to interpolate + + + // multiply tr vector by abcd matrix to get point + + float a = (float)Src8Khz[ 0]; + float b = (float)Src8Khz[ 0]; + float c = (float)Src8Khz[ 1]; + float d = (float)Src8Khz[ 2]; + float v; + + // bad alias upsampling code here.... + Dest48Khz[0] =Src8Khz[ 0]; // t= 0; + Dest48Khz[1] =(gsi_u16)(a * -0.058f + b * 0.938f + c * 0.132f + d * -0.012f ); // t= 1/6; + Dest48Khz[2] =(gsi_u16)(a * -0.074f + b * 0.778f + c * 0.333f + d * -0.037f ); // t= 2/6; + Dest48Khz[3] =(gsi_u16)(a * -0.063f + b * 0.563f + c * 0.563f + d * -0.063f ); // t= 3/6; + Dest48Khz[4] =(gsi_u16)(a * -0.037f + b * 0.333f + c * 0.778f + d * -0.074f ); // t= 4/6; + Dest48Khz[5] =(gsi_u16)(a * -0.012f + b * 0.132f + c * 0.938f + d * -0.058f ); // t= 5/6; + + Dest48Khz +=6; + Src8Khz ++; + num8Khzsamples-=3; + + while (num8Khzsamples) + { + a = (float)Src8Khz[-1]; + b = (float)Src8Khz[ 0]; + c = (float)Src8Khz[ 1]; + d = (float)Src8Khz[ 2]; + + // bad alias upsampling code here.... + Dest48Khz[0] =Src8Khz[ 0]; // t= 0; + + v = (a * -0.058f + b * 0.938f + c * 0.132f + d * -0.012f ); + Dest48Khz[1] =(gsi_u16) LIMIT(v,0.0f,65535.0f); // t= 1/6; + + v = (a * -0.074f + b * 0.778f + c * 0.333f + d * -0.037f ); + Dest48Khz[2] =(gsi_u16) LIMIT(v,0.0f,65535.0f); // t= 2/6; + + v = (a * -0.063f + b * 0.563f + c * 0.563f + d * -0.063f ); + Dest48Khz[3] =(gsi_u16) LIMIT(v,0.0f,65535.0f); // t= 3/6; + + v= (a * -0.037f + b * 0.333f + c * 0.778f + d * -0.074f ); + Dest48Khz[4] =(gsi_u16) LIMIT(v,0.0f,65535.0f); // t= 4/6; + + v=(a * -0.012f + b * 0.132f + c * 0.938f + d * -0.058f ); + Dest48Khz[5] =(gsi_u16) LIMIT(v,0.0f,65535.0f); // t= 5/6; + + Dest48Khz +=6; + Src8Khz ++; + num8Khzsamples--; + } + + a = (float)Src8Khz[ 0]; + b = (float)Src8Khz[ 0]; + c = (float)Src8Khz[ 1]; + d = (float)Src8Khz[ 1]; + + // bad alias upsampling code here.... + Dest48Khz[0] =Src8Khz[ 0]; // t= 0; + Dest48Khz[1] =(gsi_u16)(a * -0.058f + b * 0.938f + c * 0.132f + d * -0.012f ); // t= 1/6; + Dest48Khz[2] =(gsi_u16)(a * -0.074f + b * 0.778f + c * 0.333f + d * -0.037f ); // t= 2/6; + Dest48Khz[3] =(gsi_u16)(a * -0.063f + b * 0.563f + c * 0.563f + d * -0.063f ); // t= 3/6; + Dest48Khz[4] =(gsi_u16)(a * -0.037f + b * 0.333f + c * 0.778f + d * -0.074f ); // t= 4/6; + Dest48Khz[5] =(gsi_u16)(a * -0.012f + b * 0.132f + c * 0.938f + d * -0.058f ); // t= 5/6; + + Dest48Khz +=6; + Src8Khz ++; + + a = (float)Src8Khz[ 0]; + b = (float)Src8Khz[ 0]; + c = (float)Src8Khz[ 0]; + d = (float)Src8Khz[ 0]; + + // bad alias upsampling code here.... + Dest48Khz[0] =Src8Khz[ 0]; // t= 0; + Dest48Khz[1] =(gsi_u16)(a * -0.058f + b * 0.938f + c * 0.132f + d * -0.012f ); // t= 1/6; + Dest48Khz[2] =(gsi_u16)(a * -0.074f + b * 0.778f + c * 0.333f + d * -0.037f ); // t= 2/6; + Dest48Khz[3] =(gsi_u16)(a * -0.063f + b * 0.563f + c * 0.563f + d * -0.063f ); // t= 3/6; + Dest48Khz[4] =(gsi_u16)(a * -0.037f + b * 0.333f + c * 0.778f + d * -0.074f ); // t= 4/6; + Dest48Khz[5] =(gsi_u16)(a * -0.012f + b * 0.132f + c * 0.938f + d * -0.058f ); // t= 5/6; + + Dest48Khz +=6; + Src8Khz ++; + + +#endif + +} + +static int EEStreamDataPush(const gsi_u16* data, int num8Khzsamples) +// numsamples is in 8khz format +// copies and converts. returns numsamples read +{ + int remain48Khz = EEBUFFER_SAMPLE_COUNT - gEEDataSampleCount; + + if (num8Khzsamples *6 > remain48Khz) + { + num8Khzsamples = remain48Khz/6; + } + + assert(EEBUFFER_SAMPLE_COUNT >= num8Khzsamples*6); + + AudioUpSample((gsi_i16*)&EEBuffer[gEEDataSampleCount],(const gsi_i16*)data,num8Khzsamples); + + gEEDataSampleCount+=num8Khzsamples*6; + + return num8Khzsamples; +} + +static void EEStreamConvertAndTransfer(GVIDevice * device, int which) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + GVBool wroteToBuffer; + int samplesPushed; + +static int BlockSize= 256; // in samples +static int EEMul = 2; +static int IOPMul = 4; + + int iopmem; + u_char *eemem; + int i; + + // push any pending data + if(data->m_playbackBufferPos) + { + EEStreamDataPush(data->m_playbackBuffer + data->m_playbackBufferPos, GVISamplesPerFrame - data->m_playbackBufferPos); + data->m_playbackBufferPos = 0; + } + + do + { + // write a frame of sources to our buffer + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, data->m_playbackBuffer, 1); + + // clear it if nothing was written + if(!wroteToBuffer) + memset(data->m_playbackBuffer, 0, (unsigned int)GVIBytesPerFrame); + + // filter + if(device->m_playbackFilterCallback) + device->m_playbackFilterCallback(device, data->m_playbackBuffer, data->m_playbackClock); + + // push it + samplesPushed = EEStreamDataPush(data->m_playbackBuffer, GVISamplesPerFrame); + + // update the clock + data->m_playbackClock++; + } + while(gEEDataSampleCount < EEBUFFER_SAMPLE_COUNT); + + // store the position at which the push stopped + if(samplesPushed < GVISamplesPerFrame) + data->m_playbackBufferPos = samplesPushed; + else + data->m_playbackBufferPos = 0; + + gEEDataSampleCount = 0; // reset + + // Do a memcpy from EE to IOP memory using DMA, respecting 256 sample interleave + iopmem = IOPBuffer + which * IOP_BUFF_SIZE; + eemem = (u_char *)(&EEBuffer[0]); + for (i=0; i< EEBUFFER_SAMPLE_COUNT;i+= BlockSize) + { + //left + DMA_EE_To_IOP( iopmem, // IOP side destination address + eemem, // EE side source address + BlockSize*2); + + //right + DMA_EE_To_IOP( iopmem+BlockSize*2, // IOP side destination address + eemem, // EE side source address + BlockSize*2); + + iopmem += BlockSize * IOPMul; // 4 ,2, + eemem += BlockSize * EEMul; // 2 ,2, + } +} + +void gviPS2Spu2Think(void) +{ + GVIPS2Spu2Data * data; + int v; + int which; + + if(!GVIPS2Spu2Device) + return; + + // get the data + data = (GVIPS2Spu2Data *)GVIPS2Spu2Device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return; + + // Check if an interrupt has occured. IF this were a separate thread, it could sleep until this happens. + if(!gEEStreanIntr) + return; + + // IOP_BUFF_SIZE has been played + // clear flag + gEEStreanIntr = 0; + + v = sceSdRemote(1, rSdBlockTransStatus ,AUTODMA_CH,0); + + which = 1 - (v >>24); + + // done transfer, send some more data + EEStreamConvertAndTransfer(GVIPS2Spu2Device, which); +} + +int gviPS2Spu2ListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + // check for no room + if(maxDevices < 1) + return 0; + + // check for no playback devices wanted + if(!(types & GV_PLAYBACK)) + return 0; + + // store this device's info in the array + devices[0].m_id = GVPS2Spu2DeviceID; + strcpy(devices[0].m_name, "System Sound"); + devices[0].m_deviceType = GV_PLAYBACK; + devices[0].m_defaultDevice = (GVDeviceType)0; // ps2 doesn't support default devices + devices[0].m_hardwareType = GVHardwarePS2Spu2; + + return 1; +} + +static GVBool gviPS2Spu2StartDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + if(!(type & GV_PLAYBACK)) + return GVFalse; + + // clear the clock + data->m_playbackClock = 0; + + // started playing + data->m_playing = GVTrue; + + return GVTrue; +} + +static void gviPS2Spu2StopDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + if(!(type & GV_PLAYBACK)) + return; + + // stopped playing + data->m_playing = GVFalse; + + // clear any pending sources & buffers + gviClearSourceList(data->m_playbackSources); + + // clear the SPU + EEStreamClearSPUBuffer(); +} + +static GVBool gviPS2Spu2IsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + if(type == GV_PLAYBACK) + return data->m_playing; + return GVFalse; +} + +static void gviPS2Spu2SetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + gsi_i16 sVol; + + if(!(type & GV_PLAYBACK)) + return; + + // store the volume + data->m_playbackVolume = volume; + + // convert it into a signed short + sVol = (gsi_i16)(volume * 0x3FFF); + sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_BVOLL, sVol); + sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_BVOLR, sVol); +} + +static GVScalar gviPS2Spu2GetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + if(!(type & GV_PLAYBACK)) + return 0; + + return data->m_playbackVolume; +} + +static void gviPS2Spu2PlayPacket(GVIDevice * device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return; + + //add it + gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock); +} + +static GVBool gviPS2Spu2IsSourceTalking(GVDevice device, GVSource source) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviIsSourceTalking(data->m_playbackSources, source); +} + +static int gviPS2Spu2ListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviListTalkingSources(data->m_playbackSources, sources, maxSources); +} + +static void gviPS2Spu2FreeDevice(GVIDevice * device) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + EEStreamClearSPUBuffer(); + + // Free resources + sceSifFreeIopHeap((void *)IOPBuffer); + + IOPBuffer = (int)NULL; + + // Turn off interrupt + sceSdRemoteCallbackQuit(); + sceSdRemote(1, rSdSetTransIntrHandler,AUTODMA_CH,NULL, NULL); + + // kill volume + //changeInputVolume(0x0000); + + if(data->m_playbackSources) + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + + // free the device + gviFreeDevice(device); + + GVIPS2Spu2Device = NULL; +} + +static GVBool gviPS2Spu2InitDevice(GVIDevice * device, int deviceIndex, GVDeviceType type) +{ + GVIPS2Spu2Data * data = (GVIPS2Spu2Data *)device->m_data; + + // create the array of sources + data->m_playbackSources = gviNewSourceList(); + if(!data->m_playbackSources) + return GVFalse; + + // allocate the buffer + data->m_playbackBuffer = (GVSample *)gsimalloc((unsigned int)GVIBytesPerFrame); + if(!data->m_playbackBuffer) + { + gviFreeSourceList(data->m_playbackSources); + return GVFalse; + } + + // these are the buffers which the audio (SPU) will stream from on the IOP. + // they are double buffered, with one half being read while the other is dma'ed into from the EE + IOPBuffer = (int)sceSifAllocIopHeap(IOP_BUFF_SIZE*2); + assert(IOPBuffer ); + + // Set interrupt to receive mid and end point in buffer + sceSdRemoteCallbackInit(5); + sceSdRemote(1, rSdSetTransIntrHandler,AUTODMA_CH,cbEEStreamTransfer, NULL); + + + // clear interrupt flag. After this each interrupt, this flag will be set to 1. + gEEStreanIntr = 0; + + EEStreamClearSPUBuffer(); + + + // Turn on the auto dma transfer process. From here in the dma continuously + // load data into the sound processor memory, playing it. + // at mid and end points, cbEEStreamTransfer will be called + + sceSdRemote(1, rSdBlockTrans, AUTODMA_CH, + (SD_TRANS_MODE_WRITE| SD_BLOCK_LOOP), + IOPBuffer, // start of buffer + IOP_BUFF_SIZE*2, // size of buffer + IOPBuffer // where in buffer to start + ); + + sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_BVOLL, 0x3FFF); + sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_BVOLR, 0x3FFF); + sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_MVOLL, 0x3FFF); + sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_MVOLR, 0x3FFF); + + // set data + data->m_playbackVolume = 1.0; + GSI_UNUSED(deviceIndex); + GSI_UNUSED(type); + return GVTrue; +} + +GVDevice gviPS2Spu2NewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVBool result; + + // check if the device already exists + if(GVIPS2Spu2Device) + return NULL; + + // check the ID + if(deviceID != GVPS2Spu2DeviceID) + return NULL; + + // check the type + if(type != GV_PLAYBACK) + return NULL; + + // create a new device + device = gviNewDevice(deviceID, GVHardwarePS2Spu2, type, sizeof(GVIPS2Spu2Data)); + if(!device) + return NULL; + + // init the device + result = gviPS2Spu2InitDevice(device, deviceID, type); + if(result == GVFalse) + { + gviFreeDevice(device); + return NULL; + } + + // store the pointers + device->m_methods.m_freeDevice = gviPS2Spu2FreeDevice; + device->m_methods.m_startDevice = gviPS2Spu2StartDevice; + device->m_methods.m_stopDevice = gviPS2Spu2StopDevice; + device->m_methods.m_isDeviceStarted = gviPS2Spu2IsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviPS2Spu2SetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviPS2Spu2GetDeviceVolume; + device->m_methods.m_playPacket = gviPS2Spu2PlayPacket; + device->m_methods.m_isSourceTalking = gviPS2Spu2IsSourceTalking; + device->m_methods.m_listTalkingSources = gviPS2Spu2ListTalkingSources; + + // store a pointer to the device + GVIPS2Spu2Device = device; + + return device; +} + +#endif //!defined(GV_NO_PS2_SPU2) diff --git a/xrGameSpy/gamespy/Voice2/gvPS2Spu2.h b/xrGameSpy/gamespy/Voice2/gvPS2Spu2.h new file mode 100644 index 00000000000..576772c808f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS2Spu2.h @@ -0,0 +1,29 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_PS2_SPU2_H_ +#define _GV_PS2_SPU2_H_ + +#include "gvMain.h" + +GVBool gviPS2Spu2Startup(void); +void gviPS2Spu2Cleanup(void); +void gviPS2Spu2Think(void); + +int gviPS2Spu2ListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviPS2Spu2NewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvPS3Audio.c b/xrGameSpy/gamespy/Voice2/gvPS3Audio.c new file mode 100644 index 00000000000..4050096e15f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS3Audio.c @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gvPS3Audio.h" +#include "gvPS3Headset.h" + +#if !defined(_PS3) +#error This file should only be used with the PlayStation3 +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// starts up the devices +GVBool gviHardwareStartup(void) +{ + return gviPS3HeadsetStartup(); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// cleans up the devices +void gviHardwareCleanup(void) +{ + gviPS3HeadsetCleanup(); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// should be called every once in a while +void gviHardwareThink(void) +{ + gviPS3HeadsetThink(); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// lists the connected devices +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + return gviPS3HeadsetListDevices(devices, maxDevices, types); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// initializes a new device +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + return gviPS3HeadsetNewDevice(deviceID, type); +} diff --git a/xrGameSpy/gamespy/Voice2/gvPS3Audio.h b/xrGameSpy/gamespy/Voice2/gvPS3Audio.h new file mode 100644 index 00000000000..76b0395ac49 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS3Audio.h @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef _GV_PS3_AUDIO_H_ +#define _GV_PS3_AUDIO_H_ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gvMain.h" + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Public Interfaces +GVBool gviHardwareStartup(void); +void gviHardwareCleanup(void); +void gviHardwareThink(void); + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif // _GV_PS3_AUDIO_H_ diff --git a/xrGameSpy/gamespy/Voice2/gvPS3Headset.c b/xrGameSpy/gamespy/Voice2/gvPS3Headset.c new file mode 100644 index 00000000000..7c447215a6b --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS3Headset.c @@ -0,0 +1,1141 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gvPS3Headset.h" +#if !defined(GV_NO_PS3_HEADSET) +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#include +#include +#include +#include +#include +#include + + +#if !defined(_PS3) +#error This file should only be used with the PlayStation3 +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// definitions +#define GVI_PLAYBACK_STAYAHEAD_MILLISECONDS 50 + +// Used as a starting value for the audio port queue key +#define GVI_AUDIO_QUEUE_KEY_BASE 0x0000998877660000ULL + +// Used as a starting value for the capture event queue key +#define GVI_CAPTURE_QUEUE_KEY_BASE 0x0000000072110700UL + +#define GVI_AUDIO_QUEUE_DEPTH 4 +#define GVI_CAPTURE_VOLUME_MAX 241 +#define GVI_PLAYBACK_NUM_BLOCKS CELL_AUDIO_BLOCK_32 +#define GVI_PLAYBACK_BLOCK_SAMPLES CELL_AUDIO_BLOCK_SAMPLES +#define GVI_PLAYBACK_SAMPLE_RATE 48000 //Hz +#define GVI_PS3_MIC_BUFFER_MS 1000 +#define GVI_LOCAL_TALK_MAX 10 +#define GVI_PLAYBACK_SAMPLE_FACTOR (GVI_PLAYBACK_SAMPLE_RATE / gviGetSampleRate()) +#define GVI_NUM_CHANNELS CELL_AUDIO_PORT_2CH + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// structs +typedef struct +{ + sys_event_t m_captureCallbackEvent; + sys_event_queue_t m_captureCallbackQueue; + uint64_t m_captureEventQueueKey; + GVBool m_capturing; + GVScalar m_captureVolume; + GVFrameStamp m_captureClock; + GVScalar m_captureThreshold; + GVFrameStamp m_captureLastCrossedThresholdTime; + float *m_capturePreConvertBuffer; + size_t m_capturePreConvertBufferLen; + GVSample *m_captureBuffer; + + int m_captureBufferBytes; + int m_deviceNum; // used to keep the microphone device number + GVBool m_captureMicOpen; + + GVBool m_playing; + GVScalar m_playbackVolume; + GVFrameStamp m_playbackClock; + GVISourceList m_playbackSources; + GVSample *m_playbackBuffer; + gsi_u32 m_playbackCellAudioPortNum; + CellAudioPortConfig m_playbackCellAudioConfig; + sys_event_queue_t m_playbackQueue; + uint64_t m_playbackQueueKey; + int m_playbackPortPos; +} GVIPS3HeadsetData; + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// globals +static GVIDeviceList GVIDevices; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// gets the device by the deviceID +static GVIDevice * gviFindDeviceByID(GVDeviceID deviceID) +{ + GVIDevice * device; + int num; + int i; + + num = gviGetNumDevices(GVIDevices); + for(i = 0 ; i < num ; i++) + { + device = gviGetDevice(GVIDevices, i); + if(device->m_deviceID == deviceID) + return device; + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// frees the device +static void gviFreeArrayDevice(void * elem) +{ + GS_ASSERT(elem); + GVIDevice * device = *(GVIDevice **)elem; + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + int result; + + // turn off mic if its a capture device and if the mic port is open + if (data->m_capturing && cellMicIsOpen(data->m_deviceNum)) + result = cellMicClose(data->m_deviceNum); + + // Destroy the callback and playback queues + if (data->m_playbackQueue) + cellAudioRemoveNotifyEventQueue(data->m_playbackQueueKey); + if (data->m_captureCallbackQueue) + cellMicRemoveNotifyEventQueue(data->m_captureEventQueueKey); + if (data->m_playbackQueue) + sys_event_queue_destroy(data->m_playbackQueue, 0); + if (data->m_captureCallbackQueue) + sys_event_queue_destroy(data->m_captureCallbackQueue, 0); + + // close audio port + if (data->m_playing) + cellAudioPortClose(data->m_playbackCellAudioPortNum); + + // playback specific cleanup + if(device->m_types & GV_PLAYBACK) + { + if(data->m_playbackSources) + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + } + + // capture specific cleanup + if(device->m_types & GV_CAPTURE) + { + gsifree(data->m_captureBuffer); + gsifree(data->m_capturePreConvertBuffer); + } + + // free the device + gviFreeDevice(device); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// starts up the headset +GVBool gviPS3HeadsetStartup(void) +{ + int result; + + // create the array of devices + GVIDevices = gviNewDeviceList(gviFreeArrayDevice); + if(!GVIDevices) + return GVFalse; + + // initialize the mic library + result = cellSysmoduleLoadModule(CELL_SYSMODULE_MIC); + if(result != CELL_OK) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + return GVFalse; + } + + result = cellMicInit(); + if(result != CELL_OK) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + return GVFalse; + } + + // initialize the audio library + result = cellSysmoduleLoadModule(CELL_SYSMODULE_AUDIO); + if(result != CELL_OK) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + return GVFalse; + } + + result = cellAudioInit(); + if(result != CELL_OK && result != CELL_AUDIO_ERROR_ALREADY_INIT) + { + gviFreeDeviceList(GVIDevices); + cellMicEnd(); + GVIDevices = NULL; + return GVFalse; + } + + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// unloads the headset +void gviPS3HeadsetCleanup(void) +{ + // free the device array + if(GVIDevices) + { + gviFreeDeviceList(GVIDevices); + GVIDevices = NULL; + } + + cellMicEnd(); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// process playback if there is any in the queue +static GVBool gviPlaybackDeviceThink(GVIDevice * device) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + int remainingSamples; + int numFrames; + GVBool wroteToBuffer; + int i, j, k; + sys_event_t playbackQueueEvent; + int result; + int playbackReadPos; + unsigned int currentBlock; + int totalSamples; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVTrue; + + // check the queue + result = sys_event_queue_receive(data->m_playbackQueue, &playbackQueueEvent, 1); + if(result == ETIMEDOUT) + { + return GVTrue; + } + if(result != CELL_OK) + { + return GVFalse; + } + + totalSamples = (GVI_PLAYBACK_NUM_BLOCKS * GVI_PLAYBACK_BLOCK_SAMPLES); + + currentBlock = (unsigned int)*(uint64_t *)(data->m_playbackCellAudioConfig.readIndexAddr); + playbackReadPos = (currentBlock * GVI_PLAYBACK_BLOCK_SAMPLES); + + if(data->m_playbackPortPos == -1) + { + unsigned int nextBlock = (currentBlock + 1) % GVI_PLAYBACK_NUM_BLOCKS; // write target is next block + data->m_playbackPortPos = (nextBlock * GVI_PLAYBACK_BLOCK_SAMPLES); + } + + remainingSamples = (((playbackReadPos + totalSamples) - data->m_playbackPortPos) % totalSamples); + + // figure out the number of frames that we can write + numFrames = ((remainingSamples / GVI_PLAYBACK_SAMPLE_FACTOR) / GVISamplesPerFrame); + + // write the frames + for(i = 0 ; i < numFrames ; i++) + { + // write a frame of sources to our buffer + wroteToBuffer = gviWriteSourcesToBuffer(data->m_playbackSources, data->m_playbackClock, data->m_playbackBuffer, 1); + + // clear it if nothing was written + if(!wroteToBuffer) + memset(data->m_playbackBuffer, 0, (unsigned int)GVIBytesPerFrame); + + // filter + if(device->m_playbackFilterCallback) + device->m_playbackFilterCallback(device, data->m_playbackBuffer, data->m_playbackClock); + + // write to port buffer from m_playbackBuffer + // converting from sample to float + // converting from 8khz or 16KHz to 48khz and mono to stereo (write each sample 6-12 + // times depending on sample rate) + for(j = 0 ; j < GVISamplesPerFrame ; j++) + { + float sample = ((float)data->m_playbackBuffer[j] / (float)SHRT_MAX); + for(k = 0; k < GVI_PLAYBACK_SAMPLE_FACTOR; k++) + { + float *dest = (float *)(data->m_playbackCellAudioConfig.portAddr + + (data->m_playbackPortPos * GVI_NUM_CHANNELS * sizeof(float))); + *dest++ = sample; + *dest = sample; + data->m_playbackPortPos++; + data->m_playbackPortPos %= totalSamples; + } + } + + // update the clock + data->m_playbackClock++; + } + + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// called every once in a while to process playback +void gviPS3HeadsetThink(void) +{ + GVIDevice * device; + GVBool rcode; + int num; + int i; + + if(!GVIDevices) + return; + + // loop through the devices backwards to that we can remove devices as we go + num = gviGetNumDevices(GVIDevices); + for(i = (num - 1) ; i >= 0 ; i--) + { + // get the device + device = gviGetDevice(GVIDevices, i); + + // // check if playback is setup on the device + if(device->m_types & GV_PLAYBACK) + { + // let it think + rcode = gviPlaybackDeviceThink(device); + + // check if the device was unplugged + if(!rcode) + gviDeviceUnplugged(device); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// gets the devices detected +int gviPS3HeadsetListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + int index; + int numDevices = 0; + + maxDevices = min(maxDevices, CELL_MAX_MICS); + + for(index = 0 ; index < maxDevices ; index++) + { + if(cellMicIsAttached(index)) + { + int deviceType; + if (cellMicGetType(index, &deviceType) == CELL_OK) + { + if (deviceType == CELLMIC_TYPE_USBAUDIO) + { + devices[numDevices].m_id = index; + devices[numDevices].m_deviceType = GV_CAPTURE | GV_PLAYBACK; + devices[numDevices].m_defaultDevice = (GVDeviceType)0; + _tcscpy(devices[numDevices].m_name, _T("USB Headset")); + devices[numDevices].m_hardwareType = GVHardwarePS3Headset; + } + else if (deviceType == CELLMIC_TYPE_BLUETOOTH) + { + devices[numDevices].m_id = index; + devices[numDevices].m_deviceType = GV_CAPTURE | GV_PLAYBACK; + devices[numDevices].m_defaultDevice = (GVDeviceType)0; + _tcscpy(devices[numDevices].m_name, _T("Bluetooth Headset")); + devices[numDevices].m_hardwareType = GVHardwarePS3Headset; + } + } + + numDevices++; + } + } + return numDevices; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// unloades the device from the device array +static void gviPS3HeadsetFreeDevice(GVIDevice * device) +{ + // delete it from the array + // it will clear out internal data in the array's free function + gviDeleteDeviceFromList(GVIDevices, device); +} + +static GVBool gviPS3HeadsetInitHeadphone(GVIPS3HeadsetData *data) +{ + int result; + CellAudioPortParam audioParam; + sys_event_queue_attribute_t aQueueAttr; + int aCount; + + audioParam.attr = CELL_AUDIO_PORTATTR_OUT_SECONDARY; + audioParam.nBlock = GVI_PLAYBACK_NUM_BLOCKS; + audioParam.nChannel = GVI_NUM_CHANNELS; + + // set the audio port value to something really abnormal + // so that if the open function fails, the gviPS3HeadsetClose + // will close the port only if a valid port number is assigned + data->m_playbackCellAudioPortNum = 0xFFFFFFFF; + + // Playback + /////////// + + result = cellAudioPortOpen(&audioParam, &data->m_playbackCellAudioPortNum); + if (result != CELL_OK) + { + return GVFalse; + } + + // get the config for the audio port so we can use it to write data to the audio port ring buffer + result = cellAudioGetPortConfig(data->m_playbackCellAudioPortNum, &data->m_playbackCellAudioConfig); + if (result != CELL_OK) + { + return GVFalse; + } + + // Event queue notify tells us when the system is ready to play new data + aCount = 0; + sys_event_queue_attribute_initialize(aQueueAttr); + aQueueAttr.attr_protocol = SYS_SYNC_FIFO; + data->m_playbackQueueKey = GVI_AUDIO_QUEUE_KEY_BASE; + + while (aCount < 10) + { + result = sys_event_queue_create(&data->m_playbackQueue, &aQueueAttr, + data->m_playbackQueueKey, GVI_AUDIO_QUEUE_DEPTH); + if (result == CELL_OK) + { + break; + } + // search unused key + data->m_playbackQueueKey = GVI_AUDIO_QUEUE_KEY_BASE | (rand() & 0x0ffff); + aCount++; + } + + if (result != CELL_OK) + { + return GVFalse; + } + + // register event queue to libaudio + result = cellAudioSetNotifyEventQueue(data->m_playbackQueueKey); + if (result < 0) + { + return GVFalse; + } + + return GVTrue; +} + +GVBool gviPS3HeadsetInitMic(GVIPS3HeadsetData *data) +{ + int result = 0; + int aMsg = 0; + int aDevNum=0; + + int aCount = 0; + sys_event_queue_attribute_t equeue_attr = {SYS_SYNC_FIFO, SYS_PPU_QUEUE, ""}; + + // Event queue key for libmic + // checks for an event occurrence + //create event queue to recv "MicIn" callback from MIOS + data->m_captureEventQueueKey = GVI_CAPTURE_QUEUE_KEY_BASE; + + while ( (aCount++) < 100 ) + { + result = sys_event_queue_create(&data->m_captureCallbackQueue, + &equeue_attr, data->m_captureEventQueueKey, 32); + if (result == CELL_OK) break; + data->m_captureEventQueueKey = GVI_CAPTURE_QUEUE_KEY_BASE | ( rand() & 0xffff); + } + if (result != CELL_OK) + { + return GVFalse; + } + + //install "MicIn" system-callback(with devnum == -1) to recv attach/detach event + result = cellMicSetNotifyEventQueue(data->m_captureEventQueueKey); + if (result != CELL_OK) + { + return GVFalse; + } + + // Wait up to 10 ms before checking if the mike is attached + result = sys_event_queue_receive(data->m_captureCallbackQueue, + &data->m_captureCallbackEvent, 10000); + if(result == ETIMEDOUT) + return GVFalse; + + aMsg = (int)data->m_captureCallbackEvent.data1; + aDevNum = (int)data->m_captureCallbackEvent.data2; + + if (aMsg == CELLMIC_ATTACH && aDevNum == data->m_deviceNum) + { + // start with the default audio device + result = cellMicOpenEx(data->m_deviceNum, GVI_PLAYBACK_SAMPLE_RATE, 1, + GV_SAMPLES_PER_SECOND, GVI_PS3_MIC_BUFFER_MS, CELLMIC_SIGTYPE_DSP); + + if (result != CELL_OK) + { + return GVFalse; + } + data->m_captureMicOpen = GVTrue; + } + return GVTrue; +} + +void gviPS3HeadsetCloseHeadphone(GVIPS3HeadsetData *data) +{ + // Remove and Destroy the callback and playback queues + if (data->m_playbackQueue) + cellAudioRemoveNotifyEventQueue(data->m_playbackQueue); + if (data->m_playbackQueue) + sys_event_queue_destroy(data->m_playbackQueue, 0); + + // the audio port needs to be closed if a device wasn't initialized properly + if (data->m_playbackCellAudioPortNum != 0xFFFFFFFF) + cellAudioPortClose(data->m_playbackCellAudioPortNum); +} + +void gviPS3HeadsetCloseMic(GVIPS3HeadsetData *data) +{ + // Remove and Destroy the callback and playback queues + if (data->m_captureCallbackQueue) + cellAudioRemoveNotifyEventQueue(data->m_captureCallbackQueue); + if (data->m_captureCallbackQueue) + sys_event_queue_destroy(data->m_captureCallbackQueue, 0); + + // The mic should be closed if it is open + if (cellMicIsOpen(data->m_deviceNum)) + cellMicClose(data->m_deviceNum); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// initializes the device for playback +static GVBool gviStartPlaybackDevice(GVIPS3HeadsetData * data) +{ + int result; + + sys_event_queue_drain(data->m_playbackQueue); + + data->m_playbackPortPos = -1; + + result = cellAudioPortStart(data->m_playbackCellAudioPortNum); + if (result != CELL_OK) + { + return GVFalse; + } + + // clear the clock + data->m_playbackClock = 0; + + // started playing + data->m_playing = GVTrue; + + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// initializes the device for capture +static GVBool gviStartCaptureDevice(GVIPS3HeadsetData * data) +{ + int result; + // start the mic capture + if (data->m_captureMicOpen) + { + result = cellMicStart(data->m_deviceNum); + if (result != CELL_OK) + return GVFalse; + } + else + return GVFalse; + + cellMicReset(data->m_deviceNum); + // no data in the capture buffer + data->m_captureBufferBytes = 0; + data->m_capturePreConvertBufferLen = 0; + + // started capturing + data->m_capturing = GVTrue; + + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// stops the device +static void gviPS3HeadsetStopDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + if(type & GV_PLAYBACK) + { + cellAudioPortStop(data->m_playbackCellAudioPortNum); + + // clear the playback buffer + memset(data->m_playbackBuffer, 0, GVIBytesPerFrame); + + // stopped playing + data->m_playing = GVFalse; + + // clear any pending sources & buffers + gviClearSourceList(data->m_playbackSources); + } + if(type & GV_CAPTURE) + { + // stop the capture buffer + cellMicStop(data->m_deviceNum); + + // clear capture buffer + memset(data->m_captureBuffer, 0, GVIBytesPerFrame); + + // stopped capturing + data->m_capturing = GVFalse; + + // so a stop then start isn't continuous + data->m_captureClock++; + } + +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// starts the device +static GVBool gviPS3HeadsetStartDevice(GVIDevice * device, GVDeviceType type) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + if(type == GV_PLAYBACK) + { + return gviStartPlaybackDevice(data); + } + if(type == GV_CAPTURE) + { + return gviStartCaptureDevice(data); + } + if(type == GV_CAPTURE_AND_PLAYBACK) + { + if(!gviStartPlaybackDevice(data)) + return GVFalse; + if(!gviStartCaptureDevice(data)) + { + gviPS3HeadsetStopDevice(device, GV_PLAYBACK); + return GVFalse; + } + return GVTrue; + } + return GVFalse; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// checks to see if the device is ready +static GVBool gviPS3HeadsetIsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + // NULL device means not even created or started + GS_ASSERT(device); + if (!device) + return GVFalse; + + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + if(type == GV_PLAYBACK) + return data->m_playing; + if(type == GV_CAPTURE) + return data->m_capturing; + if(type == GV_CAPTURE_AND_PLAYBACK) + return (data->m_playing && data->m_capturing); + return GVFalse; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// sets the volume for the device +static void gviPS3HeadsetSetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + if(type & GV_PLAYBACK) + { + cellAudioSetPortLevel(data->m_playbackCellAudioPortNum, volume); + data->m_playbackVolume = volume; + } + if(type & GV_CAPTURE) + { + cellMicSetDeviceAttr(data->m_deviceNum, CELLMIC_DEVATTR_VOLUME, (int)(volume * GVI_CAPTURE_VOLUME_MAX), 0); + data->m_captureVolume = volume; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// gets the device volume +static GVScalar gviPS3HeadsetGetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + if(type & GV_PLAYBACK) + return data->m_playbackVolume; + return data->m_captureVolume; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// sets the capture threshold +static void gviPS3HeadsetSetCaptureThreshold(GVIDevice * device, GVScalar threshold) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + data->m_captureThreshold = threshold; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// gets the capture threshold +static GVScalar gviPS3HeadsetGetCaptureThreshold(GVIDevice * device) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + return data->m_captureThreshold; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// gets the available capture bytes +static int gviPS3HeadsetGetAvailableCaptureBytes(GVDevice device) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return 0; + + // no call listed in the Sony documentation, so just return 1 + return 1; +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// +GVBool gviPS3HeadsetHandleMicAttach(GVIPS3HeadsetData *data) +{ + int result; + + // start with the default audio device + result = cellMicOpenEx(data->m_deviceNum, GVI_PLAYBACK_SAMPLE_RATE, 1, + GV_SAMPLES_PER_SECOND, GVI_PS3_MIC_BUFFER_MS, CELLMIC_SIGTYPE_DSP); + + if (result != CELL_OK) + { + return GVFalse; + } + data->m_captureMicOpen = GVTrue; + result = cellMicStart(data->m_deviceNum); + if (result != CELL_OK) + { + return GVFalse; + } + result = cellMicReset(data->m_deviceNum); + if (result != CELL_OK) + { + return GVFalse; + } + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// processes the captured frame +static void gviProcessCapturedFrame(GVDevice device, GVSample *frameIn, GVByte* frameOut, GVScalar *volume, GVBool *threshold) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + GVScalar frameVolume; + + // get the volume if requested + if(volume) + { + frameVolume = gviGetSamplesVolume(frameIn, GVISamplesPerFrame); + if(frameVolume > *volume) + *volume = frameVolume; + } + + // check against the threshold + if(threshold && !*threshold) + { + if(volume) + { + // we already got the volume, so use that to check + *threshold = (*volume >= data->m_captureThreshold); + } + else + { + // we didn't get a volume, so check the samples directly + *threshold = gviIsOverThreshold(frameIn, GVISamplesPerFrame, data->m_captureThreshold); + } + } + + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, frameIn, data->m_captureClock); + + // increment the capture clock + data->m_captureClock++; + + // encode the buffer into the packet + gviEncode(frameOut, frameIn); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// captures a packet +static GVBool gviPS3HeadsetCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + GVBool overThreshold; + int result; + int numFrames; + int readSize; + int lenAvailable; + int framesAvailable; + GVByte * frameOut; + float *frameIn; + int aCaptureQueueMsg; + int aDeviceIndex; + int sample; + int localtalk; + // figure out how many encoded bytes they can handle + lenAvailable = *len; + + // clear the len and volume + *len = 0; + if(volume) + *volume = 0; + + // don't do anything if we're not capturing + if(!data->m_capturing) + return GVFalse; + + // set the frameStamp + *frameStamp = data->m_captureClock; + + // figure out how many frames they can handle + framesAvailable = (lenAvailable / GVIEncodedFrameSize); + overThreshold = GVFalse; + + frameOut = packet; + //frameIn = data->m_capturePreConvertBuffer; + // handle the data one frame at a time + for(numFrames = 0 ; numFrames < framesAvailable ; numFrames++) + { + // Wait up to 1 us before checking if the mike is attached + result = sys_event_queue_receive(data->m_captureCallbackQueue, + &data->m_captureCallbackEvent, 1); + if(result == ETIMEDOUT) + { + break; + } + + aCaptureQueueMsg = (int)data->m_captureCallbackEvent.data1; + aDeviceIndex = (int)data->m_captureCallbackEvent.data2; + if (aDeviceIndex != data->m_deviceNum) + continue; + + if (aCaptureQueueMsg == CELLMIC_ATTACH) + { + if (!gviPS3HeadsetHandleMicAttach(data)) + { + break; + } + } + else if (aCaptureQueueMsg == CELLMIC_DETACH) + { + gviDeviceUnplugged(device); + return GVFalse; + } + else if (aCaptureQueueMsg == CELLMIC_DATA) + { + // read this frame + //readSize = (GVIBytesPerFrame - data->m_captureBufferBytes); + readSize = ((GVISamplesPerFrame - data->m_capturePreConvertBufferLen) * sizeof(float)); + frameIn = data->m_capturePreConvertBuffer + data->m_capturePreConvertBufferLen; + readSize = cellMicRead(data->m_deviceNum, frameIn, readSize); + + cellMicGetSignalState(0, CELLMIC_SIGSTATE_LOCTALK, &localtalk); + if (localtalk < (int)(GVI_LOCAL_TALK_MAX * data->m_captureThreshold)) + { + return GVFalse; + } + + if (readSize == CELL_MICIN_ERROR_DEVICE_NOT_FOUND) + { + gviDeviceUnplugged(device); + return GVFalse; + } + + data->m_capturePreConvertBufferLen += (readSize / sizeof(float)); + if(data->m_capturePreConvertBufferLen < GVISamplesPerFrame) + { + break; + } + + // convert the data from 32 bit Big Endian Floats [-1.0,1.0] + // to 16 bit short and write the values into the buffer + for (sample = 0; sample < GVISamplesPerFrame; sample++) + { + data->m_captureBuffer[sample] = (GVSample)((SHRT_MAX)*data->m_capturePreConvertBuffer[sample]); + } + + // process the frame + gviProcessCapturedFrame(device, data->m_captureBuffer, frameOut, volume, &overThreshold); + + // we got a full frame, so there's no leftover + data->m_captureBufferBytes = 0; + + // update the frame pointer + frameOut += GVIEncodedFrameSize; + + data->m_capturePreConvertBufferLen = 0; + } + } + + // check if this packet crossed the threshold + if(overThreshold) + { + // store the time we crossed it + data->m_captureLastCrossedThresholdTime = data->m_captureClock; + } + else + { + // check if we are still on the overhang from a previous crossing + overThreshold = ((GVFrameStamp)(*frameStamp - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + // set the len + *len = (numFrames * GVIEncodedFrameSize); + + // return false if we didn't get a packet + if(!overThreshold || (*len == 0)) + return GVFalse; + + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// sends the packet to the mixer +static void gviPS3HeadsetPlayPacket(GVIDevice * device, const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return; + + //add it + gviAddPacketToSourceList(data->m_playbackSources, packet, len, source, frameStamp, mute, data->m_playbackClock); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// checks to see if we're talking +static GVBool gviPS3HeadsetIsSourceTalking(GVDevice device, GVSource source) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviIsSourceTalking(data->m_playbackSources, source); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// lists the talking sources +static int gviPS3HeadsetListTalkingSources(GVDevice device, GVSource sources[], int maxSources) +{ + GVIPS3HeadsetData * data = (GVIPS3HeadsetData *)device->m_data; + + // don't do anything if we're not playing + if(!data->m_playing) + return GVFalse; + + return gviListTalkingSources(data->m_playbackSources, sources, maxSources); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// initializes the device +static GVBool gviPS3HeadsetInitDevice(GVIDevice * device, int deviceIndex, GVDeviceType type) +{ + GVIPS3HeadsetData * data; + + // get a pointer to the data + data = (GVIPS3HeadsetData *)device->m_data; + data->m_deviceNum = deviceIndex; + + // handle playback specific stuff + if(type & GV_PLAYBACK) + { + // create the array of sources + data->m_playbackSources = gviNewSourceList(); + if(!data->m_playbackSources) + { + return NULL; + } + + // allocate the buffer to hold one frame + data->m_playbackBuffer = (GVSample *)gsimemalign(16, (unsigned int)(GVIBytesPerFrame)); + if(!data->m_playbackBuffer) + { + gviFreeSourceList(data->m_playbackSources); + return NULL; + } + if (!gviPS3HeadsetInitHeadphone(data)) + { + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + gviPS3HeadsetCloseHeadphone(data); + return NULL; + } + data->m_playbackVolume = 1.0; + } + + // handle capture specific stuff + if(type & GV_CAPTURE) + { + // set some data vars + data->m_captureClock = 0; + data->m_captureVolume = 1.0; + data->m_capturePreConvertBufferLen = 0; + + data->m_captureLastCrossedThresholdTime = (GVFrameStamp)(data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + + // allocate the buffer + data->m_captureBuffer = (GVSample *)gsimemalign(16, (unsigned int)(GVIBytesPerFrame)); + if(!data->m_captureBuffer) + { + // Need to free any resources in data for playback + // Also library needs to close audio port and mic + // The library still needs to remain + if(type & GV_PLAYBACK) + { + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + gviPS3HeadsetCloseHeadphone(data); + } + return NULL; + } + + data->m_capturePreConvertBuffer = (float *)gsimemalign(16,(unsigned int)(GVISamplesPerFrame * sizeof(float))); + if(!data->m_capturePreConvertBuffer) + { + // Need to free any resources in data for playback + // Also library needs to close audio port and mic + // The library still needs to remain + if(type & GV_PLAYBACK) + { + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + gviPS3HeadsetCloseHeadphone(data); + } + + // Still need to free capture buffer + gsifree(data->m_captureBuffer); + return NULL; + } + + if (!gviPS3HeadsetInitMic(data)) + { + // Need to free any resources in data for playback + // Also library needs to close audio port and mic + // The library still needs to remain + if(type & GV_PLAYBACK) + { + gviFreeSourceList(data->m_playbackSources); + gsifree(data->m_playbackBuffer); + gviPS3HeadsetCloseHeadphone(data); + } + gviPS3HeadsetCloseMic(data); + gsifree(data->m_captureBuffer); + gsifree(data->m_capturePreConvertBuffer); + return NULL; + } + } + + return GVTrue; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// initializes a new device +GVDevice gviPS3HeadsetNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVBool result; + + // check for no type + if(!(type & GV_CAPTURE_AND_PLAYBACK)) + return NULL; + + // check if the device already exists + if(gviFindDeviceByID(deviceID)) + return NULL; + + // create a new device + device = gviNewDevice(deviceID, GVHardwarePS3Headset, type, sizeof(GVIPS3HeadsetData)); + if(!device) + return NULL; + + // init the device + result = gviPS3HeadsetInitDevice(device, deviceID, type); + if(result == GVFalse) + { + gviFreeDevice(device); + return NULL; + } + + // store the pointers + device->m_methods.m_freeDevice = gviPS3HeadsetFreeDevice; + device->m_methods.m_startDevice = gviPS3HeadsetStartDevice; + device->m_methods.m_stopDevice = gviPS3HeadsetStopDevice; + device->m_methods.m_isDeviceStarted = gviPS3HeadsetIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviPS3HeadsetSetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviPS3HeadsetGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviPS3HeadsetSetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviPS3HeadsetGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviPS3HeadsetGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviPS3HeadsetCapturePacket; + device->m_methods.m_playPacket = gviPS3HeadsetPlayPacket; + device->m_methods.m_isSourceTalking = gviPS3HeadsetIsSourceTalking; + device->m_methods.m_listTalkingSources = gviPS3HeadsetListTalkingSources; + + // add it to the list + gviAppendDeviceToList(GVIDevices, device); + return device; +} + +#endif //!defined(GV_NO_PS3_HEADSET) diff --git a/xrGameSpy/gamespy/Voice2/gvPS3Headset.h b/xrGameSpy/gamespy/Voice2/gvPS3Headset.h new file mode 100644 index 00000000000..459b147bceb --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPS3Headset.h @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef _GV_PS3_HEADSET_H_ +#define _GV_PS3_HEADSET_H_ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// headers +#include "gvMain.h" + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// public interfaces +GVBool gviPS3HeadsetStartup(void); +void gviPS3HeadsetCleanup(void); +void gviPS3HeadsetThink(void); + +int gviPS3HeadsetListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviPS3HeadsetNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif // _GV_PS3_HEADSET_H_ diff --git a/xrGameSpy/gamespy/Voice2/gvPSPAudio.c b/xrGameSpy/gamespy/Voice2/gvPSPAudio.c new file mode 100644 index 00000000000..5b87cd7e966 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPSPAudio.c @@ -0,0 +1,503 @@ +#include "gvDevice.h" +#include "gvCodec.h" +#include "gvSource.h" +#include "gvUtil.h" +#include + +#if !defined(_PSP) +#error This file should only be used with the PSP +#endif + +/************ +** DEFINES ** +************/ +// the number of samples to capture at a time +// is a multiple of 64 and 160 +// at 11025hz, corresponds to about 30ms +#define GVI_INPUT_LEN 320 + +#define GVI_CAPTURE_THREAD_STACK_SIZE (1024 * 4) + +// ADC settings +#define GVI_ADC_ALC -6 // -6 dB +#define GVI_ADC_GAIN +30 // +30 dB +#define GVI_ADC_NOIZ -60 // -60 dB +#define GVI_ADC_HOLD 0 // 0 ms +#define GVI_ADC_DECAY 3 // 192 ms +#define GVI_ADC_ATTACK 2 // 24 ms + +/********** +** TYPES ** +**********/ +typedef struct +{ + GVBool m_capturing; + GVScalar m_captureVolume; + GVFrameStamp m_captureClock; + GVScalar m_captureThreshold; + GVFrameStamp m_captureLastCrossedThresholdTime; + GVSample * m_captureBuffer; + size_t m_captureBufferLen; // len in samples (not bytes) + size_t m_captureBufferWritePos; + size_t m_captureBufferReadPos; + SceUID m_captureBufferSemaphore; + SceUID m_captureThreadID; + GVBool m_captureThreadStop; +} GVIHardwareData; + +/************ +** GLOBALS ** +************/ +static GVIDevice * GVIPSPDevice = NULL; + +/************** +** FUNCTIONS ** +**************/ +static void gviHardwareFreeDevice(GVIDevice * device); + +static GVBool gviWaitSemaphore(GVIHardwareData * data) +{ + int rcode = sceKernelWaitSema(data->m_captureBufferSemaphore, 1, NULL); + if(rcode == 0) + return GVTrue; + return GVFalse; +} + +static GVBool gviSignalSemaphore(GVIHardwareData * data) +{ + int rcode = sceKernelSignalSema(data->m_captureBufferSemaphore, 1); + if(rcode == 0) + return GVTrue; + return GVFalse; +} + +GVBool gviHardwareStartup(void) +{ + SceAudioInputParam param; + int rcode; + + // init mic capture + param.alc = GVI_ADC_ALC; + param.gain = GVI_ADC_GAIN; + param.noiz = GVI_ADC_NOIZ; + param.hold = GVI_ADC_HOLD; + param.decay = GVI_ADC_DECAY; + param.attack = GVI_ADC_ATTACK; + rcode = sceAudioInputInitEx(¶m); + if(rcode < 0) + return GVFalse; + + return GVTrue; +} + +void gviHardwareCleanup(void) +{ + if(GVIPSPDevice) + { + gviHardwareFreeDevice(GVIPSPDevice); + GVIPSPDevice = NULL; + } +} + +void gviHardwareThink(void) +{ + // no thinking needed +} + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types) +{ + if(maxDevices < 1) + return 0; + + if(!(types & GV_CAPTURE)) + return 0; + + memset(&devices[0], 0, sizeof(GVDeviceInfo)); + devices[0].m_id = 0; + strcpy(devices[0].m_name, _T("Headset Mic")); + devices[0].m_deviceType = GV_CAPTURE; + devices[0].m_defaultDevice = GV_CAPTURE; + devices[0].m_hardwareType = GVHardwarePSPHeadset; + + return 1; +} + +static void gviHardwareFreeDevice(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + // don't track this device anymore + GVIPSPDevice = NULL; + + // tell the thread to stop + // the thread will free the device after it stops + data->m_captureThreadStop = GVTrue; +} + +static GVBool gviHardwareStartDevice(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type != GV_CAPTURE) + return GVFalse; + + // already capturing? + if(data->m_capturing == GVTrue) + return GVTrue; + + // set vars + data->m_captureBufferWritePos = 0; + data->m_captureBufferReadPos = 0; + + // start capturing + data->m_capturing = GVTrue; + + return GVTrue; +} + +static void gviHardwareStopDevice(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + + if(type != GV_CAPTURE) + return; + + // stop capturing + data->m_capturing = GVFalse; + + // increment the clock so new audio isn't contiguous + data->m_captureClock++; +} + +static GVBool gviHardwareIsDeviceStarted(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + if(type != GV_CAPTURE) + return GVFalse; + return data->m_capturing; +} + +static void gviHardwareSetDeviceVolume(GVIDevice * device, GVDeviceType type, GVScalar volume) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + if(type != GV_CAPTURE) + return; + data->m_captureVolume = volume; +} + +static GVScalar gviHardwareGetDeviceVolume(GVIDevice * device, GVDeviceType type) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + if(type != GV_CAPTURE) + return (GVScalar)0; + return data->m_captureVolume; +} + +static void gviHardwareSetCaptureThreshold(GVIDevice * device, GVScalar threshold) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + data->m_captureThreshold = threshold; +} + +static GVScalar gviHardwareGetCaptureThreshold(GVIDevice * device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + return data->m_captureThreshold; +} + +static int gviHardwareGetAvailableCaptureBytes(GVDevice device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int numSamples; + + if(!data->m_capturing) + return GVFalse; + + // figure out how many samples are available + gviWaitSemaphore(data); + if(data->m_captureBufferWritePos < data->m_captureBufferReadPos) + numSamples = (data->m_captureBufferLen - data->m_captureBufferReadPos); + else + numSamples = (data->m_captureBufferWritePos - data->m_captureBufferReadPos); + gviSignalSemaphore(data); + + return numSamples; +} + +static GVBool gviHardwareCapturePacket(GVDevice device, GVByte * packet, int * len, GVFrameStamp * frameStamp, GVScalar * volume) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int numBytes; + int numSamples; + int numFrames; + GVBool overThreshold = GVFalse; + int lenAvailable; + int framesAvailable; + int i, j; + GVSample * readPtr; + + if(!data->m_capturing) + return GVFalse; + + // figure out how many encoded bytes they can handle + lenAvailable = *len; + + // clear the len and volume + *len = 0; + if(volume) + *volume = 0; + + // figure out how many bytes can be captured + numSamples = gviHardwareGetAvailableCaptureBytes(device); + numBytes = (numSamples * GV_BYTES_PER_SAMPLE); + + // figure out how many frames that is + numFrames = (numBytes / GVIBytesPerFrame); + + if(numFrames == 0) + return GVFalse; + + // figure out how many frames they can handle + framesAvailable = (lenAvailable / GVIEncodedFrameSize); + + // don't give them more frames than they can handle + numFrames = min(numFrames, framesAvailable); + if(!numFrames) + return GVFalse; + + // figure out how many bytes to capture + numBytes = (numFrames * GVIBytesPerFrame); + numSamples = (numBytes / GV_BYTES_PER_SAMPLE); + + // get the read pointer + readPtr = (data->m_captureBuffer + data->m_captureBufferReadPos); + + // get the volume if they're interested + if(volume) + *volume = gviGetSamplesVolume(readPtr, numSamples); + + // check against the threshold + if(volume) + { + // we already got the volume, so use that to check + overThreshold = (*volume >= data->m_captureThreshold); + } + else + { + // we didn't get a volume, so check the samples directly + overThreshold = gviIsOverThreshold(readPtr, numSamples, data->m_captureThreshold); + } + + // did the audio cross the threshold? + if(overThreshold) + { + // update the time at which we crossed + data->m_captureLastCrossedThresholdTime = data->m_captureClock; + } + else + { + // check if we are still within the hold time + overThreshold = ((GVFrameStamp)(data->m_captureClock - data->m_captureLastCrossedThresholdTime) < GVI_HOLD_THRESHOLD_FRAMES); + } + + if(overThreshold) + { + // store the framestamp + *frameStamp = data->m_captureClock; + + // handle the data one frame at a time + for(i = 0 ; i < numFrames ; i++) + { + // scale the data + if(data->m_captureVolume < 1.0) + { + for(j = 0 ; j < GVISamplesPerFrame ; j++) + readPtr[j] = (GVSample)(readPtr[j] * data->m_captureVolume); + } + + // filter + if(device->m_captureFilterCallback) + device->m_captureFilterCallback(device, readPtr, (GVFrameStamp)(data->m_captureClock + i)); + + // encode the buffer into the packet + gviEncode(packet + (GVIEncodedFrameSize * i), readPtr); + + // update the loop info as needed + readPtr += GVISamplesPerFrame; + } + } + + // advance the read position and clock + data->m_captureBufferReadPos += numSamples; + data->m_captureBufferReadPos %= data->m_captureBufferLen; + data->m_captureClock += numFrames; + + // set the len + *len = (numFrames * GVIEncodedFrameSize); + + // return false if we didn't get a packet + if(!overThreshold) + return GVFalse; + + return GVTrue; +} + +static int gviPSPCaptureThread(SceSize args, void * argp) +{ + GVIDevice * device = *(GVIDevice **)argp; + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + int rcode; + + assert(device); + assert(args == sizeof(GVIDevice*)); + + // loop until we're told to stop + while(!data->m_captureThreadStop) + { + // are we capturing? + if(data->m_capturing) + { + // get some input + rcode = sceAudioInputBlocking(GVI_INPUT_LEN, GV_SAMPLES_PER_SECOND, + data->m_captureBuffer + data->m_captureBufferWritePos); + if(rcode < 0) + { + gviDeviceUnplugged(device); + } + else + { + gviWaitSemaphore(data); + data->m_captureBufferWritePos += GVI_INPUT_LEN; + data->m_captureBufferWritePos %= data->m_captureBufferLen; + gviSignalSemaphore(data); + } + } + else + { + // sleep + msleep(10); + } + } + + // end sampling + // if another device has already been created, don't do this + if(GVIPSPDevice != NULL) + sceAudioInputBlocking(GVI_INPUT_LEN, GV_SAMPLES_PER_SECOND, NULL); + + // free the device and its memory + gsifree(data->m_captureBuffer); + sceKernelDeleteSema(data->m_captureBufferSemaphore); + gviFreeDevice(device); + + sceKernelExitThread(0); + + return 0; +} + +static GVBool gviPSPAudioInitDevice(GVIDevice *device) +{ + GVIHardwareData * data = (GVIHardwareData *)device->m_data; + size_t size; + size_t oldSize; + int rcode; + + // create a semaphore + data->m_captureBufferSemaphore = sceKernelCreateSema("capture buffer", SCE_KERNEL_SA_THFIFO, 1, 1, NULL); + if(data->m_captureBufferSemaphore <= 0) + return GVFalse; + + // figure out the buffer size + size = gviMultiplyByBytesPerMillisecond(GVI_CAPTURE_BUFFER_MILLISECONDS); + size /= GV_BYTES_PER_SAMPLE; // convert from bytes to samples + do + { + // it needs to be a multiple of both the frame size and the input len + oldSize = size; + size = gviRoundUpToNearestMultiple(size, GVISamplesPerFrame); + size = gviRoundUpToNearestMultiple(size, GVI_INPUT_LEN); + } + while(size != oldSize); + data->m_captureBufferLen = size; + + // allocate the buffer + data->m_captureBuffer = (GVSample *)gsimalloc(size * GV_BYTES_PER_SAMPLE); + if(!data->m_captureBuffer) + { + sceKernelDeleteSema(data->m_captureBufferSemaphore); + return GVFalse; + } + + // create capture thread + data->m_captureThreadID = sceKernelCreateThread("capture",gviPSPCaptureThread, + SCE_KERNEL_USER_HIGHEST_PRIORITY, GVI_CAPTURE_THREAD_STACK_SIZE, 0, NULL); + if(data->m_captureThreadID < 0) + { + gsifree(data->m_captureBuffer); + sceKernelDeleteSema(data->m_captureBufferSemaphore); + return GVFalse; + } + + // start capture thread + rcode = sceKernelStartThread(data->m_captureThreadID, sizeof(GVIDevice*), &device); + if(rcode < 0) + { + sceKernelDeleteThread(data->m_captureThreadID); + gsifree(data->m_captureBuffer); + sceKernelDeleteSema(data->m_captureBufferSemaphore); + return GVFalse; + } + + return GVTrue; +} + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type) +{ + GVIDevice * device; + GVIHardwareData * data; + GVBool result; + + // we only do capture + if(type != GV_CAPTURE) + return NULL; + + // there can only be one device at a time + if(GVIPSPDevice != NULL) + return NULL; + + // create the device + device = gviNewDevice(deviceID, GVHardwarePSPHeadset, type, sizeof(GVIHardwareData)); + if(!device) + return NULL; + + // init the device + result = gviPSPAudioInitDevice(device); + if(result == GVFalse) + { + gviFreeDevice(device); + return NULL; + } + + // store the pointers + device->m_methods.m_freeDevice = gviHardwareFreeDevice; + device->m_methods.m_startDevice = gviHardwareStartDevice; + device->m_methods.m_stopDevice = gviHardwareStopDevice; + device->m_methods.m_isDeviceStarted = gviHardwareIsDeviceStarted; + device->m_methods.m_setDeviceVolume = gviHardwareSetDeviceVolume; + device->m_methods.m_getDeviceVolume = gviHardwareGetDeviceVolume; + device->m_methods.m_setCaptureThreshold = gviHardwareSetCaptureThreshold; + device->m_methods.m_getCaptureThreshold = gviHardwareGetCaptureThreshold; + device->m_methods.m_getAvailableCaptureBytes = gviHardwareGetAvailableCaptureBytes; + device->m_methods.m_capturePacket = gviHardwareCapturePacket; + + // get a pointer to the data + data = (GVIHardwareData *)device->m_data; + + // init vars + data->m_captureVolume = (GVScalar)1.0; + data->m_captureClock = 0; + data->m_captureLastCrossedThresholdTime = (data->m_captureClock - GVI_HOLD_THRESHOLD_FRAMES - 1); + + GVIPSPDevice = device; + + return device; +} diff --git a/xrGameSpy/gamespy/Voice2/gvPSPAudio.h b/xrGameSpy/gamespy/Voice2/gvPSPAudio.h new file mode 100644 index 00000000000..8b2e7897c46 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvPSPAudio.h @@ -0,0 +1,29 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_PSP_H_ +#define _GV_PSP_H_ + +#include "gvMain.h" + +GVBool gviHardwareStartup(void); +void gviHardwareCleanup(void); +void gviHardwareThink(void); + +int gviHardwareListDevices(GVDeviceInfo devices[], int maxDevices, GVDeviceType types); + +GVDevice gviHardwareNewDevice(GVDeviceID deviceID, GVDeviceType type); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvSource.c b/xrGameSpy/gamespy/Voice2/gvSource.c new file mode 100644 index 00000000000..4242abf8164 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvSource.c @@ -0,0 +1,486 @@ +#include "gvSource.h" +#include "gvCodec.h" +#include "gvFrame.h" +#include "gvUtil.h" +#include "gvMain.h" +#include + +// some code based on: +// "Skew Detection and Compensation for Internet Audio Applications" +// http://csperkins.org/publications/icme2000.pdf + +#define GVI_SYNCHRONIZATION_DELAY 200 + +#define GVI_MAX_SOURCES 8 + +#define GVI_CLOCK_OFFSET_AVERAGING_FACTOR 0.96875 //(31/32) + +#define GVI_DIVERGENCE_HIGH_WATERMARK 10 +#define GVI_DIVERGENCE_LOW_WATERMARK ((GVFrameStamp)-5) + +#define GVI_SHOW_SKEW_CORRECTIONS 0 +#define GVI_SHOW_SOURCELIST_CHANGES 0 + +typedef struct GVISource +{ + GVBool m_inUse; + GVSource m_source; + GVBool m_isTalking; + GVFrameStamp m_finishedTalkingTime; + GVFrameStamp m_clockOffset; + float m_clockOffsetAverage; + GVDecoderData m_decoderData; + GVIPendingFrame m_frameHead; +} GVISource; + +static int GVISynchronizationDelayFrames; +GVBool GVIGlobalMute; + + +static void gviFreeSource(GVISource * source) +{ + GVIPendingFrame * frame = source->m_frameHead.m_next; + GVIPendingFrame * next; + + // make sure it is in use + if(!source->m_inUse) + return; + + // put all of the pending frames back into the list + while(frame) + { + next = frame->m_next; + gviPutPendingFrame(frame); + frame = next; + } + + // free the decoder data + gviFreeDecoder(source->m_decoderData); + +#if GVI_SHOW_SOURCELIST_CHANGES + printf("Freed source\n"); +#endif + + // it is no longer in use + source->m_inUse = GVFalse; +} + +GVISourceList gviNewSourceList(void) +{ + int size; + GVISourceList sourceList; + + if(!GVISynchronizationDelayFrames) + { + int delay; + + delay = gviMultiplyByBytesPerMillisecond(GVI_SYNCHRONIZATION_DELAY); + delay = gviRoundUpToNearestMultiple(delay, GVIBytesPerFrame); + + GVISynchronizationDelayFrames = (delay / GVIBytesPerFrame); + } + + size = (sizeof(GVISource) * GVI_MAX_SOURCES); + sourceList = (GVISourceList)gsimalloc((unsigned int)size); + if(sourceList) + memset(sourceList, 0, (unsigned int)size); + + return sourceList; +} + +void gviFreeSourceList(GVISourceList sourceList) +{ + gviClearSourceList(sourceList); + gsifree(sourceList); +} + +void gviClearSourceList(GVISourceList sourceList) +{ + int i; + + assert(sourceList); + + for(i = 0 ; i < GVI_MAX_SOURCES ; i++) + gviFreeSource(&sourceList[i]); +} + +static GVISource * gviFindSourceInList(GVISourceList sourceList, GVSource source) +{ + GVISource * gviSource; + int i; + + // check if this source is in the list + for(i = 0 ; i < GVI_MAX_SOURCES ; i++) + { + gviSource = &sourceList[i]; + if(gviSource->m_inUse) + { + if(memcmp(&gviSource->m_source, &source, sizeof(GVSource)) == 0) + { + return gviSource; + } + } + } + + return NULL; +} + +GVBool gviIsSourceTalking(GVISourceList sourceList, GVSource source) +{ + GVISource * gviSource = gviFindSourceInList(sourceList, source); + if(!gviSource) + return GVFalse; + + return gviSource->m_isTalking; +} + +int gviListTalkingSources(GVISourceList sourceList, GVSource sources[], int maxSources) +{ + GVISource * gviSource; + int numTalking = 0; + int i; + + // loop through the sources + for(i = 0 ; i < GVI_MAX_SOURCES ; i++) + { + gviSource = &sourceList[i]; + + // check if the source is in use and talking + if(gviSource->m_inUse && gviSource->m_isTalking) + { + // add it to the list + memcpy(&sources[numTalking], &gviSource->m_source, sizeof(GVSource)); + + // one more talker + numTalking++; + + // check for the max + if(numTalking == maxSources) + break; + } + } + + return numTalking; +} + +void gviSetGlobalMute(GVBool mute) + +{ + GVIGlobalMute = mute; +} + +GVBool gviGetGlobalMute(void) +{ + return GVIGlobalMute; +} + +static GVISource * gviAddSourceToList(GVISourceList sourceList, GVSource source) +{ + GVBool result; + GVISource * gviSource = NULL; + int i; + + // loop through the sources + for(i = 0 ; i < GVI_MAX_SOURCES ; i++) + { + // check if this source is available + if(!sourceList[i].m_inUse) + { + gviSource = &sourceList[i]; + break; + } + + // also look for a source without frames + // if we don't find a totally free one, we can take this one over + if(!gviSource && !sourceList[i].m_frameHead.m_next) + gviSource = &sourceList[i]; + } + + // check if we didn't find anything + if(!gviSource) + return NULL; + + // if this source is already in use, free it first + if(gviSource->m_inUse) + gviFreeSource(gviSource); + + // make sure we can get a new decoder before moving on + result = gviNewDecoder(&gviSource->m_decoderData); + if(!result) + return NULL; + + // mark as in use + gviSource->m_inUse = GVTrue; + + // set the rest of the info + memcpy(&gviSource->m_source, &source, sizeof(GVSource)); + gviSource->m_clockOffset = 0; + gviSource->m_clockOffsetAverage = 0; + gviSource->m_isTalking = GVFalse; + gviSource->m_finishedTalkingTime = 0; + gviSource->m_frameHead.m_next = NULL; + +#if GVI_SHOW_SOURCELIST_CHANGES + printf("Added source\n"); +#endif + + return gviSource; +} + +static void gviAddPacketToSource(GVISource * source, GVFrameStamp frameStamp, const GVByte * packet, int len, GVBool mute) +{ + GVIPendingFrame * frame; + GVIPendingFrame * nextFrame; + GVIPendingFrame * newFrame; + GVFrameStamp packetFinishedTime; + int numFrames; + int i; + + // the packet len should be a multiple of the encoded frame size + assert(!(len % GVIEncodedFrameSize)); + + // calculate the number of frames in this packet + numFrames = (len / GVIEncodedFrameSize); + + // use the clock offset to adjust the frameStamp + // Expanded to remove warnings in VS2K5 + frameStamp = frameStamp + (GVFrameStamp)source->m_clockOffset; + + // figure out when this packet will be finished + packetFinishedTime = (GVFrameStamp)(frameStamp + numFrames); + + // update the time at which this source is done talking + if(gviIsFrameStampGT(packetFinishedTime, source->m_finishedTalkingTime)) + source->m_finishedTalkingTime = packetFinishedTime; + + // if muted, don't add. + if(mute || GVIGlobalMute) + { + //Flag that they are currently talking because we skip this step in the hardware. + source->m_isTalking = GVTrue; + return; + } + + // find where to add it + // it must be in chronological order + for(frame = &source->m_frameHead ; frame->m_next ; frame = frame->m_next) + { + // store a pointer to the next frame + // this is the frame we will compare to this time through the loop + nextFrame = frame->m_next; + + // check if the framestamp is the same (a repeated packet) + if(nextFrame->m_frameStamp == frameStamp) + return; + + // check if the new frame should be placed in front of the next frame + if(gviIsFrameStampGT(nextFrame->m_frameStamp, frameStamp)) + { + // check that the packet's finish time doesn't cross over the next frame + assert(!gviIsFrameStampGT(packetFinishedTime, nextFrame->m_frameStamp)); + + // everything is good, break out so we can insert the new frames + break; + } + } + + // loop through the frames in the packet + for(i = 0 ; i < numFrames ; i++) + { + // get a new frame + newFrame = gviGetPendingFrame(); + if(!newFrame) + return; + + // fill it in + newFrame->m_frameStamp = frameStamp; +#if GVI_PRE_DECODE + gviDecodeSet(newFrame->m_frame, packet, source->m_decoderData); +#else + memcpy(newFrame->m_frame, packet, (unsigned int)GVIEncodedFrameSize); +#endif + newFrame->m_next = frame->m_next; + + // setup the previous frame's next pointer to point to this one + frame->m_next = newFrame; + + // adjust vars + frameStamp++; + packet += GVIEncodedFrameSize; + frame = newFrame; + } +} + +void gviAddPacketToSourceList(GVISourceList sourceList, + const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute, + GVFrameStamp currentPlayClock) +{ + GVFrameStamp playTime; + GVISource * gviSource; + GVFrameStamp clockOffset; + GVFrameStamp divergence; + int unwrappedClockOffset; + + // add the sync delay to the clock to get the play time + playTime = (GVFrameStamp)(currentPlayClock + GVISynchronizationDelayFrames); + + // calculate the clock offset + clockOffset = (GVFrameStamp)(playTime - frameStamp); + + // check if this source already exists + gviSource = gviFindSourceInList(sourceList, source); + if(!gviSource) + { + // it isn't, so add it + gviSource = gviAddSourceToList(sourceList, source); + + // drop the packet if it couldn't be added + if(!gviSource) + return; + + // store the clock offset + gviSource->m_clockOffset = clockOffset; + gviSource->m_clockOffsetAverage = (float)clockOffset; + + // init the finished talking time + gviSource->m_finishedTalkingTime = (GVFrameStamp)(frameStamp + gviSource->m_clockOffset); + } + else + { + // unwrap the clock offset if needed + if((clockOffset < gviSource->m_clockOffsetAverage) && gviIsFrameStampGT(clockOffset, (GVFrameStamp)gviSource->m_clockOffsetAverage)) + { + unwrappedClockOffset = (clockOffset + GVI_FRAMESTAMP_MAX); + } + else if((gviSource->m_clockOffsetAverage < clockOffset) && gviIsFrameStampGT((GVFrameStamp)gviSource->m_clockOffsetAverage, clockOffset)) + { + unwrappedClockOffset = (clockOffset - GVI_FRAMESTAMP_MAX); + } + else + { + unwrappedClockOffset = clockOffset; + } + + // update the running average of the clock offset + gviSource->m_clockOffsetAverage = + (float)((gviSource->m_clockOffsetAverage * GVI_CLOCK_OFFSET_AVERAGING_FACTOR) + + (unwrappedClockOffset * (1.0 - GVI_CLOCK_OFFSET_AVERAGING_FACTOR))); + if(gviSource->m_clockOffsetAverage < 0) + gviSource->m_clockOffsetAverage += GVI_FRAMESTAMP_MAX; + else if(gviSource->m_clockOffsetAverage >= GVI_FRAMESTAMP_MAX) + gviSource->m_clockOffsetAverage -= GVI_FRAMESTAMP_MAX; + + // calculate the divergence + divergence = (GVFrameStamp)(gviSource->m_clockOffset - (GVFrameStamp)gviSource->m_clockOffsetAverage); + + // check against the high-water mark + if(gviIsFrameStampGT(divergence, GVI_DIVERGENCE_HIGH_WATERMARK)) + { +#if GVI_SHOW_SKEW_CORRECTIONS + static int dropCount; + printf("DROP: %d\n", ++dropCount); +#endif + + // update the clock offset + gviSource->m_clockOffset--; + + // if this is a one frame packet, just drop it + if(len == GVIEncodedFrameSize) + return; + + // otherwise update the params + packet += GVIEncodedFrameSize; + len -= GVIEncodedFrameSize; + } + // check against the low-water mark + else if(gviIsFrameStampGT(GVI_DIVERGENCE_LOW_WATERMARK, divergence)) + { +#if GVI_SHOW_SKEW_CORRECTIONS + static int insertCount; + printf("INSERT: %d\n", ++insertCount); +#endif + + // update the clock offset + // this will basically add a frame of silence + gviSource->m_clockOffset++; + } + + // check if this packet is too old or too far ahead to play + if(gviIsFrameStampGT(currentPlayClock, (GVFrameStamp)(frameStamp + gviSource->m_clockOffset))) + return; + } + + // add the packet to the source + gviAddPacketToSource(gviSource, frameStamp, packet, len, mute); +} + +GVBool gviWriteSourcesToBuffer(GVISourceList sourceList, GVFrameStamp startTime, + GVSample * sampleBuffer, int numFrames) +{ + GVISource * source; + GVFrameStamp timeSliceEnd; + GVIPendingFrame * frame; + int i; + GVBool result = GVFalse; + + // calculate the end of the time slice + timeSliceEnd = (GVFrameStamp)(startTime + numFrames); + + // clear the sample buffer + memset(sampleBuffer, 0, (unsigned int)numFrames * GVIBytesPerFrame); + + // loop through the sources + for(i = 0 ; i < GVI_MAX_SOURCES ; i++) + { + // get the next source + source = &sourceList[i]; + + // check if it is in use + if(!source->m_inUse) + continue; + + // keep going while there are pending frames for this source + while(source->m_frameHead.m_next) + { + // cache a pointer to the first frame + frame = source->m_frameHead.m_next; + + // check if this frame is too far ahead + if(gviIsFrameStampGTE(frame->m_frameStamp, timeSliceEnd)) + break; + + // make sure this buffer's timeslice hasn't already elapsed + if(gviIsFrameStampGTE(frame->m_frameStamp, startTime)) + { + // add the frame to the buffer + GVSample * writePtr = (sampleBuffer + ((GVFrameStamp)(frame->m_frameStamp - startTime) * GVISamplesPerFrame)); +#if GVI_PRE_DECODE + int j; + for(j = 0 ; j < GVISamplesPerFrame ; j++) + writePtr[j] += frame->m_frame[j]; +#else + gviDecodeAdd(writePtr, frame->m_frame, source->m_decoderData); +#endif + + // this source is talking + source->m_isTalking = GVTrue; + + // set the return value to indicate that decoding took place + result = GVTrue; + } + + // update the source to point to the next frame + source->m_frameHead.m_next = frame->m_next; + + // free the frame we just used + gviPutPendingFrame(frame); + } + + // remove the source if it has no more frames and is marked as finished + if(!source->m_frameHead.m_next && gviIsFrameStampGTE(timeSliceEnd, source->m_finishedTalkingTime)) + gviFreeSource(source); + } + + return result; + +} diff --git a/xrGameSpy/gamespy/Voice2/gvSource.h b/xrGameSpy/gamespy/Voice2/gvSource.h new file mode 100644 index 00000000000..0184f189a39 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvSource.h @@ -0,0 +1,40 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_SOURCE_H_ +#define _GV_SOURCE_H_ + +#include "gvMain.h" +/************ +** GLOBALS ** +************/ +extern GVBool GVIGlobalMute; + +typedef struct GVISource * GVISourceList; + +GVISourceList gviNewSourceList(void); +void gviFreeSourceList(GVISourceList sourceList); +void gviClearSourceList(GVISourceList sourceList); + +GVBool gviIsSourceTalking(GVISourceList sourceList, GVSource source); +int gviListTalkingSources(GVISourceList sourceList, GVSource sources[], int maxSources); + +void gviSetGlobalMute(GVBool mute); +GVBool gviGetGlobalMute(void); + +void gviAddPacketToSourceList(GVISourceList sourceList, + const GVByte * packet, int len, GVSource source, GVFrameStamp frameStamp, GVBool mute, + GVFrameStamp currentPlayClock); + +GVBool gviWriteSourcesToBuffer(GVISourceList sourceList, GVFrameStamp startTime, + GVSample * sampleBuffer, int numFrames); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvSpeex.c b/xrGameSpy/gamespy/Voice2/gvSpeex.c new file mode 100644 index 00000000000..7c7b322ca11 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvSpeex.c @@ -0,0 +1,187 @@ +#include "gvSpeex.h" +#include +#include "gvCodec.h" + + +static GVBool gviSpeexInitialized; +static void * gviSpeexEncoderState; +static SpeexBits gviSpeexBits; +static int gviSpeexEncodedFrameSize; +static int gviSpeexSamplesPerFrame; + +//Encode/Decode buffer. +static float * gviSpeexBuffer; + +GVBool gviSpeexInitialize(int quality, GVRate sampleRate) +{ + int rate; + int bitsPerFrame; + int samplesPerSecond; + + // we shouldn't already be initialized + if(gviSpeexInitialized) + return GVFalse; + + // create a new encoder state + if (sampleRate == GVRate_8KHz) + gviSpeexEncoderState = speex_encoder_init(&speex_nb_mode); + else if (sampleRate == GVRate_16KHz) + gviSpeexEncoderState = speex_encoder_init(&speex_wb_mode); + else + return GVFalse; + + if(!gviSpeexEncoderState) + return GVFalse; + + // set the sampling rate + samplesPerSecond = sampleRate; + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_SET_SAMPLING_RATE, &samplesPerSecond); + + // Get the samples per frame setting. + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_GET_FRAME_SIZE, &gviSpeexSamplesPerFrame); + + // set the quality + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_SET_QUALITY, &quality); + + // initialize the bits struct + speex_bits_init(&gviSpeexBits); + + // get the bitrate + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_GET_BITRATE, &rate); + + // convert to bits per frame + bitsPerFrame = (rate / (sampleRate / gviSpeexSamplesPerFrame)); + + // convert to bytes per frame and store, round up to allocate more space than needed. + gviSpeexEncodedFrameSize = (bitsPerFrame / 8); + if (bitsPerFrame % 8) + gviSpeexEncodedFrameSize++; + + // create our encoding and decoding buffer. + gviSpeexBuffer = (float *)gsimalloc(gviSpeexSamplesPerFrame * sizeof(float)); + + // we're now initialized + gviSpeexInitialized = GVTrue; + + return GVTrue; +} + +void gviSpeexCleanup(void) +{ + // make sure there is something to cleanup + if(!gviSpeexInitialized) + return; + + // free up encoding and decoding buffer. + gsifree(gviSpeexBuffer); + + // destroy the encoder state + speex_encoder_destroy(gviSpeexEncoderState); + gviSpeexEncoderState = NULL; + + // destroy the bits struct + speex_bits_destroy(&gviSpeexBits); + + // no longer initialized + gviSpeexInitialized = GVFalse; +} + +int gviSpeexGetSamplesPerFrame(void) +{ + return gviSpeexSamplesPerFrame; +} + +int gviSpeexGetEncodedFrameSize(void) +{ + return gviSpeexEncodedFrameSize; +} + +GVBool gviSpeexNewDecoder(GVDecoderData * data) +{ + void * decoder; + int perceptualEnhancement = 1; + + // create a new decoder state + if (gviGetSampleRate() == GVRate_8KHz) + decoder = speex_decoder_init(&speex_nb_mode); + else if (gviGetSampleRate() == GVRate_16KHz) + decoder = speex_decoder_init(&speex_wb_mode); + else + return GVFalse; + + if(!decoder) + return GVFalse; + + // turn on the perceptual enhancement + speex_decoder_ctl(decoder, SPEEX_SET_ENH, &perceptualEnhancement); + + *data = decoder; + return GVTrue; +} + +void gviSpeexFreeDecoder(GVDecoderData data) +{ + // destory the decoder state + speex_decoder_destroy((void *)data); +} + +void gviSpeexEncode(GVByte * out, const GVSample * in) +{ + int bytesWritten; + int i; + + // convert the input to floats for encoding + for(i = 0 ; i < gviSpeexSamplesPerFrame ; i++) + gviSpeexBuffer[i] = in[i]; + + // flush the bits + speex_bits_reset(&gviSpeexBits); + + // encode the frame + speex_encode(gviSpeexEncoderState, gviSpeexBuffer, &gviSpeexBits); + + // write the bits to the output + bytesWritten = speex_bits_write(&gviSpeexBits, (char *)out, gviSpeexEncodedFrameSize); + assert(bytesWritten == gviSpeexEncodedFrameSize); +} + +void gviSpeexDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data) +{ + int rcode; + int i; + + // read the data into the bits + speex_bits_read_from(&gviSpeexBits, (char *)in, gviSpeexEncodedFrameSize); + + // decode it + rcode = speex_decode((void *)data, &gviSpeexBits, gviSpeexBuffer); + assert(rcode == 0); + + // convert the output from floats + for(i = 0 ; i < gviSpeexSamplesPerFrame ; i++) + // Expanded to remove warnings in VS2K5 + out[i] = out[i] + (GVSample)gviSpeexBuffer[i]; +} + +void gviSpeexDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data) +{ + int rcode; + int i; + + // read the data into the bits + speex_bits_read_from(&gviSpeexBits, (char *)in, gviSpeexEncodedFrameSize); + + // decode it + rcode = speex_decode((void *)data, &gviSpeexBits, gviSpeexBuffer); + assert(rcode == 0); + + // convert the output from floats + for(i = 0 ; i < gviSpeexSamplesPerFrame ; i++) + out[i] = (GVSample)gviSpeexBuffer[i]; +} + +void gviSpeexResetEncoder(void) +{ + // reset the encoder's state + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_RESET_STATE, NULL); +} diff --git a/xrGameSpy/gamespy/Voice2/gvSpeex.h b/xrGameSpy/gamespy/Voice2/gvSpeex.h new file mode 100644 index 00000000000..b2db0524789 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvSpeex.h @@ -0,0 +1,62 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_SPEEX_H_ +#define _GV_SPEEX_H_ + +#include "gvMain.h" + +/* + 8000kHz +quality: samplesPerFrame encodedFrameSize bitsPerSecond +0: 160 6 2150 +1: 160 10 3950 +2: 160 15 5950 +3: 160 20 8000 +4: 160 20 8000 +5: 160 28 11000 +6: 160 28 11000 +7: 160 38 15000 +8: 160 38 15000 +9: 160 46 18200 +10: 160 62 24600 + + 16000kHz +quality: samplesPerFrame encodedFrameSize bitsPerSecond +0: 320 10 3950 +1: 320 15 5750 +2: 320 20 7750 +3: 320 25 9800 +4: 320 32 12800 +5: 320 42 16800 +6: 320 52 20600 +7: 320 60 23800 +8: 320 70 27800 +9: 320 86 34200 +10: 320 106 42200 +*/ + +GVBool gviSpeexInitialize(int quality, GVRate sampleRate); +void gviSpeexCleanup(void); + +int gviSpeexGetSamplesPerFrame(void); +int gviSpeexGetEncodedFrameSize(void); + +GVBool gviSpeexNewDecoder(GVDecoderData * data); +void gviSpeexFreeDecoder(GVDecoderData data); + +void gviSpeexEncode(GVByte * out, const GVSample * in); +void gviSpeexDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data); +void gviSpeexDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data); + +void gviSpeexResetEncoder(void); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvSpeexSpu.c b/xrGameSpy/gamespy/Voice2/gvSpeexSpu.c new file mode 100644 index 00000000000..a0ae2f45f2c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvSpeexSpu.c @@ -0,0 +1,226 @@ +#include "gvSpeexSpu.h" +#include +#include "gvCodec.h" + +#define GVI_SPEEX_ENCODED_BUFFER 128 //dma has trouble when smaller than +struct SpursSpeexTaskOutput gSpeexTaskOutput; +char *gviSpeexEncoderStateBuffer; +static GVBool gviSpeexEncoderInitialized; +static int gviSpeexEncodedFrameSize; +static int gviSpeexSamplesPerFrame; +char *gviSpeexEncodedBuffer; +short *gviSpeexDecodedBuffer; +// used for decoding if SPU decoding isn't used +#if defined(GVI_NOT_USING_SPURS_DECODE_TASK) +static float * gviSpeexBuffer; +static SpeexBits gviSpeexBits; +#endif + + +GVBool gviSpeexInitialize(int quality, GVRate sampleRate) +{ + // we shouldn't already be initialized + if(gviSpeexEncoderInitialized) + return GVFalse; + + // align on a 128 byte boundary to make DMA in spurs task easier + gviSpeexEncoderStateBuffer = (char *)gsimemalign(128,SPEEX_ENCODER_STATE_BUFFER_SIZE); + gSpeexTaskOutput.mSpeexReturnCode = -1; + + // initialize the bits struct +#if defined(GVI_NOT_USING_SPURS_DECODE_TASK) + speex_bits_init(&gviSpeexBits); +#endif + + if (initializeSpursSampleTask() != 0) + return GVFalse; + + // initialize the encoder given the the buffer used to keep track of state + if (issueSampleTaskEncodeInit(quality, sampleRate, &gSpeexTaskOutput,gviSpeexEncoderStateBuffer,SPEEX_ENCODER_STATE_BUFFER_SIZE) != 0) + return GVFalse; + + assert(gSpeexTaskOutput.mSpeexReturnCode == 0); + if (gSpeexTaskOutput.mSpeexInitialized != GVTrue) + { + return GVFalse; + } + + gviSpeexSamplesPerFrame = gSpeexTaskOutput.mSpeexSamplesPerFrame; + gviSpeexEncodedFrameSize = gSpeexTaskOutput.mSpeexEncodedFrameSize; + +#if defined(GVI_NOT_USING_SPURS_DECODE_TASK) + gviSpeexBuffer = (float *)gsimalloc(gviSpeexSamplesPerFrame * sizeof(float)); +#endif + gviSpeexEncodedBuffer = (char *)gsimemalign(128, GVI_SPEEX_ENCODED_BUFFER); + gviSpeexDecodedBuffer = (short *)gsimemalign(128, gviSpeexSamplesPerFrame*sizeof(short)); + // we're now initialized + gviSpeexEncoderInitialized = GVTrue; + + return GVTrue; +} + +void gviSpeexCleanup(void) +{ + // make sure there is something to cleanup + if(!gviSpeexEncoderInitialized) + return; + +#ifdef GVI_NOT_USING_SPURS_DECODE_TASK + // free up encoding and decoding buffer. + gsifree(gviSpeexBuffer); + + // destroy the bits struct + speex_bits_destroy(&gviSpeexBits); +#endif + + // destroy speex state buffer + gsifree(gviSpeexEncoderStateBuffer); + gsifree(gviSpeexEncodedBuffer); + gsifree(gviSpeexDecodedBuffer); + // cleanup spu + shutdownSpursTask(); + + // no longer initialized + gviSpeexEncoderInitialized = GVFalse; +} + +int gviSpeexGetSamplesPerFrame(void) +{ + return gviSpeexSamplesPerFrame; +} + +int gviSpeexGetEncodedFrameSize(void) +{ + return gviSpeexEncodedFrameSize; +} + +GVBool gviSpeexNewDecoder(GVDecoderData * data) +{ +#ifdef GVI_NOT_USING_SPURS_DECODE_TASK + void * decoder; + int perceptualEnhancement = 1; + + // create a new decoder state + if (gviGetSampleRate() == GVRate_8KHz) + decoder = speex_decoder_init(&speex_nb_mode); + else if (gviGetSampleRate() == GVRate_16KHz) + decoder = speex_decoder_init(&speex_wb_mode); + else + return GVFalse; + + if(!decoder) + return GVFalse; + + // turn on the perceptual enhancement + speex_decoder_ctl(decoder, SPEEX_SET_ENH, &perceptualEnhancement); + + *data = decoder; + + return GVTrue; + +#else + char *decoder = (char *)gsimemalign(128, SPEEX_DECODER_STATE_BUFFER_SIZE); + gSpeexTaskOutput.mSpeexReturnCode = -1; + + if (issueSampleTaskDecodeInit(decoder, SPEEX_DECODER_STATE_BUFFER_SIZE, gviGetSampleRate(), &gSpeexTaskOutput) != 0) + return GVFalse; + + if (gSpeexTaskOutput.mSpeexReturnCode != 0) + return GVFalse; + + *data = decoder; + return GVTrue; +#endif // USE SPU ENCODING +} + +void gviSpeexFreeDecoder(GVDecoderData data) +{ +#ifdef GVI_NOT_USING_SPURS_DECODE_TASK + // destroy the decoder state + speex_decoder_destroy((void *)data); +#else + gsifree(data); +#endif +} + + +void gviSpeexEncode(GVByte * out, const GVSample * in) +{ + int immediateReturn = 0; + gSpeexTaskOutput.mSpeexInitialized = 1; + gSpeexTaskOutput.mSpeexReturnCode = -1; + memset(gviSpeexEncodedBuffer, 0, GVI_SPEEX_ENCODED_BUFFER); + immediateReturn = issueSampleTaskEncode((short *)in, gviSpeexSamplesPerFrame, gviSpeexEncodedFrameSize, (char *)gviSpeexEncodedBuffer, + GVI_SPEEX_ENCODED_BUFFER, &gSpeexTaskOutput,gviSpeexEncoderStateBuffer,SPEEX_ENCODER_STATE_BUFFER_SIZE); + assert(immediateReturn == 0); + assert(gSpeexTaskOutput.mSpeexReturnCode == 0); + memcpy(out, gviSpeexEncodedBuffer, gviSpeexEncodedFrameSize); + assert(gSpeexTaskOutput.mSpeexOutBufferSize == gviSpeexEncodedFrameSize); +} + +void gviSpeexDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data) +{ +#ifdef GVI_NOT_USING_SPURS_DECODE_TASK + int rcode; + int i; + + // read the data into the bits + speex_bits_read_from(&gviSpeexBits, (char *)in, gviSpeexEncodedFrameSize); + + // decode it + rcode = speex_decode((void *)data, &gviSpeexBits, gviSpeexBuffer); + assert(rcode == 0); + + // convert the output from floats + for(i = 0 ; i < gviSpeexSamplesPerFrame ; i++) + // Expanded to remove warnings in VS2K5 + out[i] = out[i] + (GVSample)gviSpeexBuffer[i]; +#else + int immediateReturn = 0, i; + gSpeexTaskOutput.mSpeexInitialized = 1; + gSpeexTaskOutput.mSpeexReturnCode = -1; + memset(gviSpeexEncodedBuffer, 0, GVI_SPEEX_ENCODED_BUFFER); + memcpy(gviSpeexEncodedBuffer, in, gviSpeexEncodedFrameSize); + immediateReturn = issueSampleTaskDecodeAdd(data, SPEEX_DECODER_STATE_BUFFER_SIZE, gviSpeexEncodedBuffer, GVI_SPEEX_ENCODED_BUFFER, + gviSpeexEncodedFrameSize, gviSpeexDecodedBuffer, gviSpeexSamplesPerFrame, &gSpeexTaskOutput); + for (i = 0; i < gviSpeexSamplesPerFrame; i++) + out[i] = out[i] + (GVSample)gviSpeexDecodedBuffer[i]; + assert(immediateReturn == 0); + assert(gSpeexTaskOutput.mSpeexReturnCode == 0); +#endif +} + +void gviSpeexDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data) +{ +#ifdef GVI_USE_SPURS_DECODE_TASK + int rcode; + int i; + + // read the data into the bits + speex_bits_read_from(&gviSpeexBits, (char *)in, gviSpeexEncodedFrameSize); + + // decode it + rcode = speex_decode((void *)data, &gviSpeexBits, gviSpeexBuffer); + + assert(rcode == 0); + + // convert the output from floats + for(i = 0 ; i < gviSpeexSamplesPerFrame ; i++) + out[i] = (GVSample)gviSpeexBuffer[i]; +#else + int immediateReturn = 0; + gSpeexTaskOutput.mSpeexInitialized = 1; + gSpeexTaskOutput.mSpeexReturnCode = -1; + memset(gviSpeexEncodedBuffer, 0, GVI_SPEEX_ENCODED_BUFFER); + memcpy(gviSpeexEncodedBuffer, in, gviSpeexEncodedFrameSize); + immediateReturn = issueSampleTaskDecodeSet(data, SPEEX_DECODER_STATE_BUFFER_SIZE, gviSpeexEncodedBuffer, GVI_SPEEX_ENCODED_BUFFER, + gviSpeexEncodedFrameSize, out, gviSpeexSamplesPerFrame, &gSpeexTaskOutput); + assert(immediateReturn == 0); + assert(gSpeexTaskOutput.mSpeexReturnCode == 0); +#endif +} + +void gviSpeexResetEncoder(void) +{ + speex_encoder_ctl((void *)gviSpeexEncoderStateBuffer, SPEEX_RESET_STATE, NULL); +} diff --git a/xrGameSpy/gamespy/Voice2/gvSpeexSpu.h b/xrGameSpy/gamespy/Voice2/gvSpeexSpu.h new file mode 100644 index 00000000000..add14dad940 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvSpeexSpu.h @@ -0,0 +1,65 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_SPEEXSPU_H_ +#define _GV_SPEEXSPU_H_ + +#include "../common/gsPlatform.h" +#include "gvMain.h" +#include "SpuSpeexTaskOutput.h" +#include "SpursSpeexCInterface.h" + +/* +8000kHz +quality: samplesPerFrame encodedFrameSize bitsPerSecond +0: 160 6 2150 +1: 160 10 3950 +2: 160 15 5950 +3: 160 20 8000 +4: 160 20 8000 +5: 160 28 11000 +6: 160 28 11000 +7: 160 38 15000 +8: 160 38 15000 +9: 160 46 18200 +10: 160 62 24600 + +16000kHz +quality: samplesPerFrame encodedFrameSize bitsPerSecond +0: 320 10 3950 +1: 320 15 5750 +2: 320 20 7750 +3: 320 25 9800 +4: 320 32 12800 +5: 320 42 16800 +6: 320 52 20600 +7: 320 60 23800 +8: 320 70 27800 +9: 320 86 34200 +10: 320 106 42200 +*/ + +GVBool gviSpeexInitialize(int quality, GVRate sampleRate); +void gviSpeexCleanup(void); + +int gviSpeexGetSamplesPerFrame(void); +int gviSpeexGetEncodedFrameSize(void); + +GVBool gviSpeexNewDecoder(GVDecoderData * data); +void gviSpeexFreeDecoder(GVDecoderData data); + +void gviSpeexEncode(GVByte * out, const GVSample * in); +void gviSpeexDecodeAdd(GVSample * out, const GVByte * in, GVDecoderData data); +void gviSpeexDecodeSet(GVSample * out, const GVByte * in, GVDecoderData data); + +void gviSpeexResetEncoder(void); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/gvUtil.c b/xrGameSpy/gamespy/Voice2/gvUtil.c new file mode 100644 index 00000000000..d99ba152a2f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvUtil.c @@ -0,0 +1,78 @@ +#include "gvUtil.h" +#include +#include + +GVScalar gviGetSamplesVolume(const GVSample * samplesPtr, int numSamples) +{ + GVSample value; + GVSample max = 0; + int i; + + for(i = 0 ; i < numSamples ; i++) + { + value = samplesPtr[i]; + if(value < 0) + value = (GVSample)(-value); + if(value > max) + max = value; + } + + return ((GVScalar)max / -SHRT_MIN); +} + +GVBool gviIsOverThreshold(const GVSample * samplesPtr, int numSamples, GVScalar threshold) +{ + int i; + + if(threshold == (GVScalar)0.0) + return GVTrue; + + for(i = 0 ; i < numSamples ; i++) + { + if(labs(samplesPtr[i]) > (threshold * SHRT_MAX)) + return GVTrue; + } + + return GVFalse; +} + +int gviRoundUpToNearestMultiple(int value, int base) +{ + int remainder; + + remainder = (value % base); + if(remainder) + value += (base - remainder); + + return value; +} + +int gviRoundDownToNearestMultiple(int value, int base) +{ + value -= (value % base); + + return value; +} + +int gviRoundToNearestMultiple(int value, int base) +{ + int remainder; + + remainder = (value % base); + if(remainder < (base / 2)) + value -= remainder; + else + value += (base - remainder); + + return value; +} + +int gviMultiplyByBytesPerMillisecond(int value) +{ + return (int)(value * GVISampleRate * GV_BYTES_PER_SAMPLE / 1000); +} + +int gviDivideByBytesPerMillisecond(int value) +{ + return (int)(value * 1000 / (GVISampleRate * GV_BYTES_PER_SAMPLE)); +} diff --git a/xrGameSpy/gamespy/Voice2/gvUtil.h b/xrGameSpy/gamespy/Voice2/gvUtil.h new file mode 100644 index 00000000000..e67253d5bdc --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/gvUtil.h @@ -0,0 +1,35 @@ +/* +GameSpy Voice2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2004 GameSpy Industries, Inc + +devsupport@gamespy.com +http://gamespy.net +*/ + +#ifndef _GV_UTIL_H_ +#define _GV_UTIL_H_ + +#include "gvMain.h" +#include "gvCodec.h" + +// gets the volume for a set of samples +GVScalar gviGetSamplesVolume(const GVSample * samplesPtr, int numSamples); + +// checks if any samples in the set are above the given threshold +GVBool gviIsOverThreshold(const GVSample * samplesPtr, int numSamples, GVScalar threshold); + +// returns the lowest multiple of base that is >= value +int gviRoundUpToNearestMultiple(int value, int base); +// returns the highest multiple of base that is <= value +int gviRoundDownToNearestMultiple(int value, int base); +// rounds the multiple of base that is closest to value +int gviRoundToNearestMultiple(int value, int base); + +// multiply or divide by bytes per millisecond +int gviMultiplyByBytesPerMillisecond(int value); +int gviDivideByBytesPerMillisecond(int value); + +#endif diff --git a/xrGameSpy/gamespy/Voice2/libspeex/libspeex.dsp b/xrGameSpy/gamespy/Voice2/libspeex/libspeex.dsp new file mode 100644 index 00000000000..c5409380cc6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/libspeex/libspeex.dsp @@ -0,0 +1,274 @@ +# Microsoft Developer Studio Project File - Name="libspeex" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libspeex - 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 "libspeex.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 "libspeex.mak" CFG="libspeex - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libspeex - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libspeex - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/IGNCP/Gamespy/GOA/Voice2/libspeex" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libspeex - 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 Target_Dir "" +F90=df.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W1 /GX /O2 /I "..\speex-1.0.5\include" /I "..\speex-1.0.5\win32" /I "..\speex-1.0.5\include\speex" /I "..\speex-1.0.5\libspeex" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libspeex - 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 Target_Dir "" +F90=df.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W1 /Gm /GX /ZI /Od /I "..\speex-1.0.5\include" /I "..\speex-1.0.5\win32" /I "..\speex-1.0.5\include\speex" /I "..\speex-1.0.5\libspeex" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libspeex - Win32 Release" +# Name "libspeex - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\bits.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\cb_search.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\cb_search.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\exc_10_16_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\exc_10_32_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\exc_20_32_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\exc_5_256_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\exc_5_64_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\exc_8_128_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\filters.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\filters.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\filters_sse.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\gain_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\gain_table_lbr.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\hexc_10_32_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\hexc_table.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\high_lsp_tables.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\lpc.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\lpc.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\lsp.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\lsp.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\lsp_tables_nb.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\ltp.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\ltp.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\ltp_sse.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\math_approx.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\math_approx.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\misc.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\misc.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\modes.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\modes.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\nb_celp.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\nb_celp.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\quant_lsp.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\quant_lsp.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\sb_celp.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\sb_celp.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\speex_callbacks.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\speex_header.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\stack_alloc.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\stereo.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\vbr.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\vbr.h" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\vq.c" +# End Source File +# Begin Source File + +SOURCE="..\speex-1.0.5\libspeex\vq.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.c b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.c new file mode 100644 index 00000000000..61511310bd0 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.c @@ -0,0 +1,261 @@ +#include "../gv.h" +#include "voicesample.h" +#include + +GVByte voice_sample[80000]; + +#if defined(_PS2) + +#include "../gvLogitechPS2Codecs.h" + +static GVBool Init(GVCodec codec) +{ + const char * name; + + // figure out the quality + // the mapping of codec to quality is copied from gvCodec.c + if(codec == GVCodecSuperHighQuality) + name = "uLaw"; + else if(codec == GVCodecHighQuality) + name = "G723.24"; + else if(codec == GVCodecAverage) + name = "GSM"; + else if(codec == GVCodecLowBandwidth) + name = "SPEEX"; + else if(codec == GVCodecSuperLowBandwidth) + name = "LPC10"; + else + return GVFalse; + + return gviLGCodecInitialize(name); +} + +static void Cleanup(void) +{ + gviLGCodecCleanup(); +} + +static int GetSamplesPerFrame(void) +{ + return gviLGCodecGetSamplesPerFrame(); +} + +static GVBool NewDecoder(GVDecoderData * data) +{ + data = NULL; + return GVTrue; +} + +static void FreeDecoder(GVDecoderData data) +{ +} + +static void Encode(GVByte * out, const GVSample * in) +{ + gviLGCodecEncode(out, in); +} + +static void Decode(GVSample * out, const GVByte * in, GVDecoderData data) +{ + gviLGCodecDecodeAdd(out, in, data); +} + +#elif defined(_PSP) || defined(_WIN32) + +#include "../gsm-1.0-pl12/inc/gsm.h" + +gsm EncoderState; + +static GVBool Init(GVCodec codec) +{ + int gsm_ltp = 1; + EncoderState = gsm_create(); + gsm_option(EncoderState, GSM_OPT_LTP_CUT, &gsm_ltp); + + GSI_UNUSED(codec); + return (EncoderState != NULL)?GVTrue:GVFalse; +} + +static void Cleanup(void) +{ + gsm_destroy(EncoderState); +} + +static int GetSamplesPerFrame(void) +{ + return 160; +} + +static GVBool NewDecoder(GVDecoderData * data) +{ + *data = (GVDecoderData)gsm_create(); + return (*data != NULL)?GVTrue:GVFalse; +} + +static void FreeDecoder(GVDecoderData data) +{ + gsm_destroy((gsm)data); +} + +static void Encode(GVByte * out, const GVSample * in) +{ + gsm_encode((gsm)EncoderState, (gsm_signal*)in, (gsm_byte*)out); +} + +static void Decode(GVSample * out, const GVByte * in, GVDecoderData data) +{ + gsm_decode((gsm)data, (gsm_byte*)in, (gsm_signal*)out); +} + +#else + +#include "../gvSpeex.h" + +static GVBool Init(GVCodec codec, GVRate sampleRate) +{ + int quality; + + // figure out the quality + // the mapping of codec to quality is copied from gvCodec.c + if(codec == GVCodecSuperHighQuality) + quality = 10; + else if(codec == GVCodecHighQuality) + quality = 7; + else if(codec == GVCodecAverage) + quality = 4; + else if(codec == GVCodecLowBandwidth) + quality = 2; + else if(codec == GVCodecSuperLowBandwidth) + quality = 1; + else + return GVFalse; + + gvSetSampleRate(sampleRate); + return gviSpeexInitialize(quality, sampleRate); +} + +static void Cleanup(void) +{ + gviSpeexCleanup(); +} + +static int GetSamplesPerFrame(void) +{ + return gviSpeexGetSamplesPerFrame(); +} + +static GVBool NewDecoder(GVDecoderData * data) +{ + return gviSpeexNewDecoder(data); +} + +static void FreeDecoder(GVDecoderData data) +{ + gviSpeexFreeDecoder(data); +} + +static void Encode(GVByte * out, const GVSample * in) +{ + gviSpeexEncode(out, in); +} + +static void Decode(GVSample * out, const GVByte * in, GVDecoderData data) +{ + gviSpeexDecodeAdd(out, in, data); +} + +#endif + +static void TestCodec(GVCodec codec, GVRate sampleRate, const char * name) +{ + int samplesPerFrame; + GVSample * samples; + int numFrames; + GVByte encodeOut[1000]; + GVSample decodeOut[1000]; + int i; + unsigned long startTime; + unsigned long endTime; + GVDecoderData decoderData; + unsigned long sampleTime = 0; + unsigned long totalEncodeTime = 0; + unsigned long totalDecodeTime = 0; + double encodeFraction; + double decodeFraction; + + printf("Testing %s\n", name); + + + if(!Init(codec, sampleRate)) + { + printf("Failed to init\n"); + return; + } + + sampleTime = (unsigned long)((double)sizeof(voice_sample) / ((int)(sampleRate) * GV_BYTES_PER_SAMPLE) * 1000000); + + if(!NewDecoder(&decoderData)) + { + printf("Failed to allocate decoder data\n"); + return; + } + + samplesPerFrame = GetSamplesPerFrame(); + numFrames = (sizeof(voice_sample) / GV_BYTES_PER_SAMPLE / samplesPerFrame); + + samples = (GVSample *)voice_sample; + + totalEncodeTime = 0; + for(i = 0 ; i < numFrames ; i++) + { + startTime = current_time_hires(); + Encode(encodeOut, samples); + endTime = current_time_hires(); + totalEncodeTime += (endTime - startTime); + samples += samplesPerFrame; + msleep(0); + + startTime = current_time_hires(); + Decode(decodeOut, encodeOut, decoderData); + endTime = current_time_hires(); + totalDecodeTime += (endTime - startTime); + msleep(0); + } + + encodeFraction = ((double)totalEncodeTime / sampleTime); + decodeFraction = ((double)totalDecodeTime / sampleTime); + + printf("Encode: %0.1f%%\n", encodeFraction * 100); + printf("Decode: %0.1f%%\n", decodeFraction * 100); + + FreeDecoder(decoderData); + + Cleanup(); +} + +#if defined(_PS2) || defined(_PSP) + #ifdef __MWERKS__ // CodeWarrior will warn if not prototyped + int test_main(int argc, char **argp); + #endif +int test_main(int argc, char **argp) +#else +int main(int argc, char **argp) +#endif // _PS2 +{ + printf("Testing codecs\n"); + + TestCodec(GVCodecSuperLowBandwidth, GVRate_8KHz, "GVCodecSuperLowBandwidth"); +#if !defined(_PS2) + TestCodec(GVCodecLowBandwidth, GVRate_8KHz, "GVCodecLowBandwidth"); +#endif + TestCodec(GVCodecAverage, GVRate_8KHz, "GVCodecAverage"); + TestCodec(GVCodecHighQuality, GVRate_8KHz, "GVCodecHighQuality"); + TestCodec(GVCodecSuperHighQuality, GVRate_8KHz, "GVCodecSuperHighQuality"); + + printf("Testing complete\n"); + + GSI_UNUSED(argc); + GSI_UNUSED(argp); + + return 0; +} diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.dsp b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.dsp new file mode 100644 index 00000000000..bd50af624c0 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.dsp @@ -0,0 +1,536 @@ +# Microsoft Developer Studio Project File - Name="voice2bench" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=voice2bench - 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 "voice2bench.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 "voice2bench.mak" CFG="voice2bench - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "voice2bench - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "voice2bench - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/IGNCP/Gamespy/GOA/Voice2/voice2bench" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "voice2bench - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I "..\speex-1.0.5\include" /I "..\gsm-1.0-pl12\inc" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "HAVE_CONFIG_H" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 libgsm.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 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:console /machine:I386 /libpath:"..\libgsm\Release" /libpath:"..\libspeex\Release" /ignore:4089 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "voice2bench - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "..\speex-1.0.5\include" /I "..\gsm-1.0-pl12\inc" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LTP_CUT" /D "HAVE_CONFIG_H" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libspeex.lib libgsm.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 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:console /debug /machine:I386 /pdbtype:sept /libpath:"..\libgsm\Debug" /libpath:"..\libspeex\Debug" + +!ENDIF + +# Begin Target + +# Name "voice2bench - Win32 Release" +# Name "voice2bench - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\voice2bench.c + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\voicesample.h +# End Source File +# End Group +# Begin Group "VoiceSDK" + +# PROP Default_Filter "" +# Begin Group "VoiceHeaders" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gv.h +# End Source File +# Begin Source File + +SOURCE=..\gvCodec.h +# End Source File +# Begin Source File + +SOURCE=..\gvCustomDevice.h +# End Source File +# Begin Source File + +SOURCE=..\gvDevice.h +# End Source File +# Begin Source File + +SOURCE=..\gvFrame.h +# End Source File +# Begin Source File + +SOURCE=..\gvMain.h +# End Source File +# Begin Source File + +SOURCE=..\gvSource.h +# End Source File +# Begin Source File + +SOURCE=..\gvSpeex.h +# End Source File +# Begin Source File + +SOURCE=..\gvUtil.h +# End Source File +# End Group +# Begin Group "VoiceSource" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gvCodec.c +# End Source File +# Begin Source File + +SOURCE=..\gvCustomDevice.c +# End Source File +# Begin Source File + +SOURCE=..\gvDevice.c +# End Source File +# Begin Source File + +SOURCE=..\gvFrame.c +# End Source File +# Begin Source File + +SOURCE=..\gvSource.c +# End Source File +# Begin Source File + +SOURCE=..\gvSpeex.c +# End Source File +# Begin Source File + +SOURCE=..\gvUtil.c +# End Source File +# End Group +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# End Group +# Begin Group "Gsm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\add.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\code.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\debug.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\decode.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\gsm_create.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\gsm_decode.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\gsm_destroy.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\gsm_encode.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\gsm_option.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\long_term.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\lpc.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\preprocess.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\rpe.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\short_term.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\gsm-1.0-pl12\src\table.c" + +!IF "$(CFG)" == "voice2bench - Win32 Release" + +# ADD CPP /D "LTP_CUT" +# SUBTRACT CPP /D "HAVE_CONFIG_H" + +!ELSEIF "$(CFG)" == "voice2bench - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /WX /D "HAVE_CONFIG_H" + +!ENDIF + +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.vcproj b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.vcproj new file mode 100644 index 00000000000..7ec8ff83cd1 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.vcproj @@ -0,0 +1,1495 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.vcproj.vspscc b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench_vs2005.vcproj b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench_vs2005.vcproj new file mode 100644 index 00000000000..b1ea5d3d4b6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench_vs2005.vcproj @@ -0,0 +1,1505 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2bench_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchmacosx/Makefile b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchmacosx/Makefile new file mode 100644 index 00000000000..8734065b951 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchmacosx/Makefile @@ -0,0 +1,47 @@ +# Voice2 SDK benchmarking Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=voice2bench + +SPEEX=../../speex-1.0.5/ +SPEEX_SRC=$(SPEEX)libspeex/ +SPEEX_INC=$(SPEEX)include/ + +INCLUDES=-I$(SPEEX_INC) + +PROG_OBJS = \ + ../../../nonport.o\ + ../../gvSpeex.o\ + ../voice2bench.o\ + $(SPEEX_SRC)bits.o\ + $(SPEEX_SRC)cb_search.o\ + $(SPEEX_SRC)exc_10_16_table.o\ + $(SPEEX_SRC)exc_10_32_table.o\ + $(SPEEX_SRC)exc_20_32_table.o\ + $(SPEEX_SRC)exc_5_256_table.o\ + $(SPEEX_SRC)exc_5_64_table.o\ + $(SPEEX_SRC)exc_8_128_table.o\ + $(SPEEX_SRC)filters.o\ + $(SPEEX_SRC)gain_table.o\ + $(SPEEX_SRC)gain_table_lbr.o\ + $(SPEEX_SRC)hexc_10_32_table.o\ + $(SPEEX_SRC)hexc_table.o\ + $(SPEEX_SRC)high_lsp_tables.o\ + $(SPEEX_SRC)lpc.o\ + $(SPEEX_SRC)lsp.o\ + $(SPEEX_SRC)lsp_tables_nb.o\ + $(SPEEX_SRC)ltp.o\ + $(SPEEX_SRC)math_approx.o\ + $(SPEEX_SRC)misc.o\ + $(SPEEX_SRC)modes.o\ + $(SPEEX_SRC)nb_celp.o\ + $(SPEEX_SRC)quant_lsp.o\ + $(SPEEX_SRC)sb_celp.o\ + $(SPEEX_SRC)speex_callbacks.o\ + $(SPEEX_SRC)speex_header.o\ + $(SPEEX_SRC)stereo.o\ + $(SPEEX_SRC)vbr.o\ + $(SPEEX_SRC)vq.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_eenet_debug.h b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_eenet_debug.h new file mode 100644 index 00000000000..0c26e218d41 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_eenet_debug.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_eenet_debug.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_eenet_release.h b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_eenet_release.h new file mode 100644 index 00000000000..aca5ec0131c --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_eenet_release.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" +#include "cw/cwprefix_eenet_release.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_insock_debug.h b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_insock_debug.h new file mode 100644 index 00000000000..b9b266c1fd7 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_insock_debug.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_insock_debug.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_insock_release.h b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_insock_release.h new file mode 100644 index 00000000000..2a208213376 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_insock_release.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_insock_release.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_snsystems_debug.h b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_snsystems_debug.h new file mode 100644 index 00000000000..6e5f7cbb5a3 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_snsystems_debug.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" +#include "cw/cwprefix_snsystems_debug.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_snsystems_release.h b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_snsystems_release.h new file mode 100644 index 00000000000..71936c6e49d --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2bench_prefix_snsystems_release.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" +#include "cw/cwprefix_snsystems_release.h" + +#define GSI_VOICE \ No newline at end of file diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2benchps2cw.mcp b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2benchps2cw.mcp new file mode 100644 index 00000000000..41e1c845819 Binary files /dev/null and b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2cw/voice2benchps2cw.mcp differ diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2prodg/voice2benchps2prodg.dsp b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2prodg/voice2benchps2prodg.dsp new file mode 100644 index 00000000000..0f82216a8ec --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2prodg/voice2benchps2prodg.dsp @@ -0,0 +1,138 @@ +# Microsoft Developer Studio Project File - Name="voice2benchps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=voice2benchps2prodg - Win32 Release_EENet +!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 "voice2benchps2prodg.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 "voice2benchps2prodg.mak" CFG="voice2benchps2prodg - Win32 Release_EENet" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "voice2benchps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "voice2benchps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/Voice2/voice2bench/voice2benchps2prodg" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "voice2benchps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "GSI_VOICE" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\voice2benchps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a liblgaud.a liblgcodec.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\voice2benchps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "voice2benchps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "GSI_VOICE" /Fo"PS2_EE_Release/" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\voice2benchps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a liblgaud.a liblgcodec.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\voice2benchps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "voice2benchps2prodg - Win32 Debug_EENet" +# Name "voice2benchps2prodg - Win32 Release_EENet" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\gvLogitechPS2Codecs.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\nonport.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# Begin Source File + +SOURCE=..\..\voice2bench\voice2bench.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\gvLogitechPS2Codecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\nonport.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# Begin Source File + +SOURCE=..\..\voice2bench\voicesample.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2prodg/voice2benchps2prodg.dsw b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2prodg/voice2benchps2prodg.dsw new file mode 100644 index 00000000000..5c7166a9615 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps2prodg/voice2benchps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "voice2benchps2prodg"=.\voice2benchps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/Voice2/voice2bench/voice2benchps2prodg + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/Voice2/voice2bench/voice2benchps2prodg + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.sln b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.sln new file mode 100644 index 00000000000..79caa6dbe07 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.sln @@ -0,0 +1,76 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "voice2benchps3prodg", "voice2benchps3prodg.vcproj", "{C8987F15-3163-467E-93DF-870CC9DBD1D1}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {090CCE44-29BC-436D-A8A3-82398190DE52} = {090CCE44-29BC-436D-A8A3-82398190DE52} + {240177C7-AE7B-48E3-871D-82B7CB809D28} = {240177C7-AE7B-48E3-871D-82B7CB809D28} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeexSpursTask", "..\..\..\common\ps3\SpeexSpursTaskManager\SpeexSpursTask\SpeexSpursTask_vs2005.vcproj", "{090CCE44-29BC-436D-A8A3-82398190DE52}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeexSpursTaskManager", "..\..\..\common\ps3\SpeexSpursTaskManager\SpeexSpursTaskManager_vs2005.vcproj", "{240177C7-AE7B-48E3-871D-82B7CB809D28}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = voice2benchps3prodg.vcproj + SccLocalPath1 = . + SccProjectUniqueName2 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager\\SpeexSpursTask\\SpeexSpursTask_vs2005.vcproj + SccProjectName2 = ../../../common/ps3/SpeexSpursTaskManager/SpeexSpursTask + SccLocalPath2 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager\\SpeexSpursTask + SccProjectUniqueName3 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager\\SpeexSpursTaskManager_vs2005.vcproj + SccProjectName3 = ../../../common/ps3/SpeexSpursTaskManager + SccLocalPath3 = ..\\..\\..\\common\\ps3\\SpeexSpursTaskManager + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + PS3_SpeexSPU_Debug|Win32 = PS3_SpeexSPU_Debug|Win32 + PS3_SpeexSPU_Release|Win32 = PS3_SpeexSPU_Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3_SpeexSPU_Debug|Win32.ActiveCfg = PS3_SpeexSPU_Debug|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3_SpeexSPU_Debug|Win32.Build.0 = PS3_SpeexSPU_Debug|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3_SpeexSPU_Release|Win32.ActiveCfg = PS3_SpeexSPU_Release|Win32 + {C8987F15-3163-467E-93DF-870CC9DBD1D1}.PS3_SpeexSPU_Release|Win32.Build.0 = PS3_SpeexSPU_Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3_SpeexSPU_Debug|Win32.ActiveCfg = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3_SpeexSPU_Debug|Win32.Build.0 = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3_SpeexSPU_Release|Win32.ActiveCfg = PS3 Release|Win32 + {090CCE44-29BC-436D-A8A3-82398190DE52}.PS3_SpeexSPU_Release|Win32.Build.0 = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3_SpeexSPU_Debug|Win32.ActiveCfg = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3_SpeexSPU_Debug|Win32.Build.0 = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3_SpeexSPU_Release|Win32.ActiveCfg = PS3 Release|Win32 + {240177C7-AE7B-48E3-871D-82B7CB809D28}.PS3_SpeexSPU_Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vcproj b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vcproj new file mode 100644 index 00000000000..b414849070f --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vcproj @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vcproj.vspscc b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vssscc b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voice2benchps3prodg/voice2benchps3prodg.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/Voice2/voice2bench/voicesample.h b/xrGameSpy/gamespy/Voice2/voice2bench/voicesample.h new file mode 100644 index 00000000000..19c3a8975d2 --- /dev/null +++ b/xrGameSpy/gamespy/Voice2/voice2bench/voicesample.h @@ -0,0 +1,6671 @@ +GVByte voice_sample[80000]= +{ + 0x08,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x06,0x00,0x03,0x00, + 0x01,0x00,0x01,0x00,0xFD,0xFF,0xFC,0xFF,0xFD,0xFF,0xFE,0xFF, + 0xFC,0xFF,0xFC,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFD,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x02,0x00,0xFF,0xFF,0xFE,0xFF,0x01,0x00,0xFE,0xFF, + 0xFF,0xFF,0x01,0x00,0x00,0x00,0x01,0x00,0x03,0x00,0x03,0x00, + 0x03,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x00,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0x04,0x00, + 0x02,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0xFF,0xFF,0x00,0x00, + 0x02,0x00,0xFD,0xFF,0x03,0x00,0x01,0x00,0xF1,0xFF,0xF0,0xFF, + 0xFC,0xFF,0xFE,0xFF,0x01,0x00,0x07,0x00,0x05,0x00,0x03,0x00, + 0xF1,0xFF,0xFE,0xFF,0x01,0x00,0x01,0x00,0x12,0x00,0x01,0x00, + 0xFF,0xFF,0xFD,0xFF,0xFA,0xFF,0xFC,0xFF,0xFC,0xFF,0xFB,0xFF, + 0x05,0x00,0x02,0x00,0xF5,0xFF,0xFD,0xFF,0x05,0x00,0x01,0x00, + 0xFE,0xFF,0x0A,0x00,0x10,0x00,0x0D,0x00,0x0A,0x00,0xFA,0xFF, + 0xF5,0xFF,0xFA,0xFF,0x00,0x00,0x04,0x00,0xFF,0xFF,0x03,0x00, + 0xFD,0xFF,0xFD,0xFF,0xEF,0xFF,0x07,0x00,0x07,0x00,0xF3,0xFF, + 0x17,0x00,0x08,0x00,0xF4,0xFF,0xF4,0xFF,0xFF,0xFF,0xFA,0xFF, + 0xFC,0xFF,0xFC,0xFF,0x0A,0x00,0x14,0x00,0x00,0x00,0x10,0x00, + 0xFE,0xFF,0xFA,0xFF,0xFE,0xFF,0x06,0x00,0xF1,0xFF,0xEC,0xFF, + 0x0C,0x00,0xF8,0xFF,0x03,0x00,0x06,0x00,0x01,0x00,0xF6,0xFF, + 0xF4,0xFF,0x07,0x00,0x02,0x00,0x0C,0x00,0x0B,0x00,0x00,0x00, + 0xFB,0xFF,0x07,0x00,0x0B,0x00,0xF9,0xFF,0xFB,0xFF,0x11,0x00, + 0x06,0x00,0xE5,0xFF,0xF4,0xFF,0xFD,0xFF,0xFE,0xFF,0x01,0x00, + 0x07,0x00,0x04,0x00,0xFE,0xFF,0x0E,0x00,0x0E,0x00,0xFF,0xFF, + 0xFA,0xFF,0xFA,0xFF,0x01,0x00,0xF8,0xFF,0xF0,0xFF,0x02,0x00, + 0xFC,0xFF,0x02,0x00,0xFA,0xFF,0xF6,0xFF,0xFC,0xFF,0xFC,0xFF, + 0x10,0x00,0xF8,0xFF,0xFC,0xFF,0x0A,0x00,0x05,0x00,0x0B,0x00, + 0x02,0x00,0xFF,0xFF,0x09,0x00,0x0C,0x00,0xFA,0xFF,0xFF,0xFF, + 0x02,0x00,0xE9,0xFF,0xF6,0xFF,0x04,0x00,0xF8,0xFF,0xF6,0xFF, + 0xFF,0xFF,0x06,0x00,0x00,0x00,0x0C,0x00,0x14,0x00,0x0A,0x00, + 0x08,0x00,0x04,0x00,0xFB,0xFF,0x03,0x00,0xFD,0xFF,0xFA,0xFF, + 0x03,0x00,0xFF,0xFF,0x00,0x00,0xF9,0xFF,0xF7,0xFF,0x00,0x00, + 0xFF,0xFF,0xF5,0xFF,0x05,0x00,0x0B,0x00,0x05,0x00,0x06,0x00, + 0x00,0x00,0x01,0x00,0xF0,0xFF,0x03,0x00,0x0D,0x00,0xF7,0xFF, + 0xFF,0xFF,0xFB,0xFF,0xF0,0xFF,0xEB,0xFF,0x02,0x00,0x10,0x00, + 0x0B,0x00,0x07,0x00,0xFB,0xFF,0x03,0x00,0x05,0x00,0x00,0x00, + 0x02,0x00,0x11,0x00,0x0F,0x00,0xFB,0xFF,0xF8,0xFF,0xED,0xFF, + 0xEB,0xFF,0xF8,0xFF,0x05,0x00,0x0B,0x00,0x0A,0x00,0x09,0x00, + 0x02,0x00,0xF5,0xFF,0xF5,0xFF,0xF8,0xFF,0xF8,0xFF,0x07,0x00, + 0x12,0x00,0x09,0x00,0x01,0x00,0xFF,0xFF,0xF9,0xFF,0xF4,0xFF, + 0xFD,0xFF,0x06,0x00,0x02,0x00,0x0C,0x00,0x0A,0x00,0xFA,0xFF, + 0xF4,0xFF,0xFA,0xFF,0x06,0x00,0xFA,0xFF,0x07,0x00,0x10,0x00, + 0xFE,0xFF,0xFB,0xFF,0xF2,0xFF,0xFD,0xFF,0xFC,0xFF,0xFB,0xFF, + 0x10,0x00,0x18,0x00,0x05,0x00,0x00,0x00,0x01,0x00,0xE2,0xFF, + 0xEA,0xFF,0x02,0x00,0x0E,0x00,0x00,0x00,0x06,0x00,0x0B,0x00, + 0xEE,0xFF,0xF8,0xFF,0xF9,0xFF,0xFC,0xFF,0xFE,0xFF,0x13,0x00, + 0x16,0x00,0xF8,0xFF,0xFE,0xFF,0x03,0x00,0xFF,0xFF,0xF7,0xFF, + 0x03,0x00,0x0E,0x00,0xFC,0xFF,0xFE,0xFF,0x0B,0x00,0xFB,0xFF, + 0xF8,0xFF,0x06,0x00,0x04,0x00,0xFC,0xFF,0xFE,0xFF,0x07,0x00, + 0xF8,0xFF,0xF3,0xFF,0x03,0x00,0x01,0x00,0xF3,0xFF,0xFC,0xFF, + 0x0B,0x00,0x06,0x00,0x02,0x00,0x06,0x00,0xFE,0xFF,0xFB,0xFF, + 0x04,0x00,0x00,0x00,0xFD,0xFF,0x03,0x00,0x06,0x00,0x02,0x00, + 0xF5,0xFF,0xFA,0xFF,0x01,0x00,0xFD,0xFF,0xFC,0xFF,0xFC,0xFF, + 0x03,0x00,0x03,0x00,0xFF,0xFF,0x03,0x00,0x00,0x00,0xFE,0xFF, + 0x03,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0xFF,0xFF, + 0x04,0x00,0x03,0x00,0xFE,0xFF,0x02,0x00,0x01,0x00,0x01,0x00, + 0xFF,0xFF,0xFC,0xFF,0x08,0x00,0xFE,0xFF,0xFD,0xFF,0x06,0x00, + 0xF9,0xFF,0xFD,0xFF,0x00,0x00,0x01,0x00,0xFD,0xFF,0xF7,0xFF, + 0x03,0x00,0xFF,0xFF,0xF4,0xFF,0x03,0x00,0x03,0x00,0xF9,0xFF, + 0x01,0x00,0x04,0x00,0x03,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0xFF,0xFF,0x06,0x00,0xFD,0xFF,0xFB,0xFF,0x03,0x00,0x02,0x00, + 0xFE,0xFF,0xFE,0xFF,0x01,0x00,0x02,0x00,0x00,0x00,0xFE,0xFF, + 0x01,0x00,0xFC,0xFF,0x01,0x00,0x02,0x00,0x05,0x00,0x06,0x00, + 0xFC,0xFF,0x03,0x00,0x00,0x00,0xFE,0xFF,0x04,0x00,0x02,0x00, + 0xFE,0xFF,0x01,0x00,0x02,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x02,0x00,0xFD,0xFF,0xFE,0xFF,0x02,0x00,0x02,0x00,0xFB,0xFF, + 0x02,0x00,0x03,0x00,0xFC,0xFF,0x03,0x00,0xFC,0xFF,0xFC,0xFF, + 0x02,0x00,0xFD,0xFF,0x02,0x00,0x01,0x00,0xFE,0xFF,0x01,0x00, + 0xFE,0xFF,0x01,0x00,0x02,0x00,0xFF,0xFF,0x01,0x00,0x02,0x00, + 0x06,0x00,0x03,0x00,0xFE,0xFF,0xF7,0xFF,0x00,0x00,0x04,0x00, + 0xFD,0xFF,0x01,0x00,0xFE,0xFF,0x01,0x00,0x01,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00, + 0xF7,0xFF,0x01,0x00,0x00,0x00,0xFB,0xFF,0x04,0x00,0xFE,0xFF, + 0xFD,0xFF,0x05,0x00,0x02,0x00,0x00,0x00,0x05,0x00,0xFA,0xFF, + 0xFC,0xFF,0xFB,0xFF,0x00,0x00,0xFC,0xFF,0xFB,0xFF,0x04,0x00, + 0xFB,0xFF,0x03,0x00,0x09,0x00,0x07,0x00,0x03,0x00,0x03,0x00, + 0xFB,0xFF,0x00,0x00,0x03,0x00,0x06,0x00,0x01,0x00,0xFF,0xFF, + 0xFE,0xFF,0xF4,0xFF,0x04,0x00,0xFE,0xFF,0x00,0x00,0x02,0x00, + 0xF8,0xFF,0xF6,0xFF,0xFE,0xFF,0x03,0x00,0xFC,0xFF,0xFE,0xFF, + 0x0C,0x00,0x02,0x00,0xF7,0xFF,0x0C,0x00,0xFE,0xFF,0xFD,0xFF, + 0x07,0x00,0xFC,0xFF,0x0D,0x00,0x0A,0x00,0xF6,0xFF,0x06,0x00, + 0x07,0x00,0xF9,0xFF,0xFE,0xFF,0x02,0x00,0xFC,0xFF,0xFF,0xFF, + 0x04,0x00,0xFD,0xFF,0xF6,0xFF,0xFE,0xFF,0xFF,0xFF,0xFC,0xFF, + 0x02,0x00,0x09,0x00,0x02,0x00,0xFF,0xFF,0x04,0x00,0xF6,0xFF, + 0x00,0x00,0xFF,0xFF,0x0B,0x00,0xFC,0xFF,0xF7,0xFF,0xF3,0xFF, + 0xFF,0xFF,0x0C,0x00,0xEF,0xFF,0x00,0x00,0xEF,0xFF,0x11,0x00, + 0x0A,0x00,0xFB,0xFF,0xE7,0xFF,0x12,0x00,0x3D,0x00,0xF8,0xFF, + 0x05,0x00,0xE7,0xFF,0x0D,0x00,0x12,0x00,0xE4,0xFF,0xD8,0xFF, + 0x14,0x00,0x0A,0x00,0x5A,0x00,0x41,0x00,0x66,0xFF,0x17,0x00, + 0xD9,0xFF,0xB0,0xFF,0x00,0x00,0xE0,0xFF,0x16,0x00,0x11,0x00, + 0x19,0x00,0x02,0x00,0x26,0x00,0x21,0x00,0xFC,0xFF,0xF8,0xFF, + 0x08,0x00,0x1F,0x00,0x12,0x00,0xF9,0xFF,0xEA,0xFF,0x00,0x00, + 0x20,0x00,0xE7,0xFF,0xE1,0xFF,0x1F,0x00,0xD8,0xFF,0xE7,0xFF, + 0x0E,0x00,0xEE,0xFF,0x08,0x00,0x0E,0x00,0x09,0x00,0xEC,0xFF, + 0x13,0x00,0x0D,0x00,0xE4,0xFF,0x1B,0x00,0xF2,0xFF,0xED,0xFF, + 0x22,0x00,0xF0,0xFF,0x02,0x00,0x19,0x00,0x09,0x00,0x0C,0x00, + 0xE0,0xFF,0x1C,0x00,0xF7,0xFF,0xFE,0xFF,0xD8,0xFF,0x0E,0x00, + 0x05,0x00,0xAE,0xFF,0x24,0x00,0xED,0xFF,0x1F,0x00,0x18,0x00, + 0xB9,0x00,0x6A,0x00,0x0B,0x00,0x4F,0xFF,0xD9,0xFE,0x67,0x00, + 0xE2,0xFF,0x92,0xFF,0x94,0xFF,0xB8,0xFF,0xDE,0xFF,0x38,0x00, + 0x68,0x00,0xF8,0xFF,0x5D,0x00,0x73,0x00,0x74,0x00,0x94,0x00, + 0x89,0x00,0x12,0x00,0x19,0x00,0x2C,0x00,0xA2,0x00,0x64,0x00, + 0x67,0xFF,0x21,0xFF,0x17,0xFF,0x72,0xFF,0x4E,0xFF,0x99,0xFF, + 0xA0,0xFF,0xBD,0xFF,0x24,0x00,0x51,0x00,0x6A,0x00,0xCF,0xFF, + 0x12,0x00,0x85,0x00,0x86,0x00,0x8E,0x00,0x0B,0x00,0x6D,0x00, + 0xEE,0x00,0xFE,0xFF,0x13,0x00,0xDF,0xFF,0x9E,0xFF,0x81,0xFF, + 0x7E,0xFF,0x2C,0xFF,0x46,0xFF,0xAF,0x00,0x72,0xFF,0xBD,0xFF, + 0x82,0x00,0xE4,0xFF,0x3B,0x00,0x02,0x00,0xAE,0xFF,0x16,0x01, + 0x31,0x01,0x6B,0x00,0x3F,0x00,0x42,0xFE,0xD5,0xFF,0xA7,0x01, + 0x97,0x00,0xFE,0xFE,0x45,0xFD,0x4C,0xFD,0xDF,0xFE,0x65,0x00, + 0x58,0x00,0xA3,0x00,0xCE,0x00,0xB2,0x01,0xD0,0x02,0x6D,0x02, + 0x56,0x01,0x06,0x00,0xD8,0xFF,0x4B,0xFF,0xD2,0xFF,0x5C,0x00, + 0x99,0xFE,0xB8,0xFD,0x00,0xFE,0xB7,0xFE,0xAE,0xFF,0x1F,0x00, + 0xC7,0xFF,0x9C,0xFF,0x68,0x00,0xE0,0x00,0x27,0x01,0x91,0x01, + 0x0F,0x01,0x62,0x00,0x37,0x00,0x06,0x00,0xC6,0xFF,0xBC,0xFF, + 0x6F,0xFF,0x0F,0xFF,0x3F,0xFF,0x5F,0xFF,0x4F,0xFF,0x84,0xFF, + 0xFA,0xFF,0x1D,0x00,0x51,0x00,0xAD,0x00,0xC1,0x00,0xD5,0x00, + 0xE2,0x00,0x95,0x00,0x23,0x00,0x0B,0x00,0xB9,0xFF,0x6E,0xFF, + 0x76,0xFF,0x61,0xFF,0x36,0xFF,0x2C,0xFF,0x6F,0xFF,0x89,0xFF, + 0x92,0xFF,0x13,0x00,0x5A,0x00,0x3D,0x00,0x5A,0x00,0x40,0x00, + 0x1F,0x00,0x52,0x00,0x70,0x00,0x19,0x00,0xCA,0xFF,0x96,0xFF, + 0x3F,0xFF,0xDC,0xFF,0x83,0x00,0x3A,0x00,0x33,0x00,0xB1,0x00, + 0xC9,0x00,0xF2,0x00,0xA5,0x01,0x1D,0x01,0x7B,0x00,0xFF,0x00, + 0xA2,0x00,0x02,0x00,0x4F,0x00,0x5D,0xFF,0x71,0xFE,0x03,0x00, + 0x2A,0x00,0xC5,0x01,0x06,0x06,0x38,0x04,0xD0,0x00,0x4E,0xFF, + 0xD5,0xFC,0x06,0xFC,0x37,0xFC,0xDF,0xFB,0xB5,0xF8,0x25,0xF7, + 0x1F,0xF9,0xCC,0xF9,0x55,0xFC,0xFE,0xFE,0x4A,0xFF,0x9F,0x00, + 0x49,0x03,0x38,0x06,0xAF,0x07,0x8B,0x08,0x5D,0x08,0x39,0x06, + 0xE3,0x05,0xB4,0x05,0xCC,0x03,0xEF,0x01,0x31,0xFF,0x81,0xFC, + 0xE0,0xFA,0x54,0xFB,0x16,0xFC,0x4D,0xFB,0x63,0xFD,0xCF,0xFF, + 0x73,0xFF,0x65,0x00,0x94,0x01,0xC3,0x00,0xCD,0x00,0xF5,0x01, + 0x89,0x01,0xDD,0xFF,0xCD,0xFF,0x89,0xFF,0x09,0xFE,0x6D,0xFE, + 0x52,0xFE,0x32,0xFD,0x60,0xFD,0x3A,0xFE,0xAE,0xFE,0x2F,0xFF, + 0x04,0x00,0x39,0x00,0x4C,0x00,0x2B,0x01,0x30,0x02,0x4F,0x02, + 0x92,0x01,0xCB,0x00,0x57,0x00,0x0C,0x00,0x7A,0x00,0x63,0x00, + 0x18,0x00,0xD6,0x00,0x8B,0x00,0x20,0x00,0x5B,0x02,0xC1,0x01, + 0x7F,0x01,0x6D,0x08,0xD2,0x08,0xE8,0x02,0x2D,0x01,0x63,0xFD, + 0x4D,0xF9,0x8B,0xF9,0xAC,0xFA,0xFA,0xF7,0xB8,0xF3,0x45,0xF5, + 0x45,0xF6,0x2E,0xF7,0xF5,0xFC,0xD2,0xFF,0x07,0x00,0x83,0x02, + 0x2C,0x06,0xB6,0x08,0x54,0x0A,0xA8,0x0C,0x79,0x0B,0xED,0x07, + 0xE3,0x07,0x87,0x06,0x5B,0x03,0x65,0x01,0xD7,0xFE,0x49,0xFB, + 0xD3,0xF8,0x73,0xF9,0xE7,0xF9,0x8D,0xF9,0x6A,0xFB,0x0A,0xFD, + 0x69,0xFE,0x8E,0x01,0xC4,0x03,0xED,0x03,0x58,0x03,0xF2,0x02, + 0x55,0x02,0x89,0x01,0x92,0x01,0x2D,0x00,0xAD,0xFD,0xA1,0xFC, + 0xCA,0xFB,0x1C,0xFB,0x83,0xFB,0x5C,0xFC,0xCF,0xFC,0x80,0xFD, + 0x62,0xFF,0xA7,0x00,0x3B,0x01,0x92,0x02,0xE1,0x02,0x5D,0x02, + 0x81,0x02,0x7B,0x02,0xF2,0x01,0xFD,0x00,0x58,0x00,0x9B,0xFF, + 0xC0,0xFE,0xE8,0xFE,0xEC,0xFE,0x1F,0xFF,0x94,0xFF,0xDD,0xFF, + 0x29,0x00,0xE1,0xFF,0xA1,0x00,0xBF,0x00,0x88,0x02,0xE2,0x06, + 0x2B,0x05,0x3C,0x02,0x47,0x01,0x09,0xFE,0x22,0xFD,0xF5,0xFD, + 0x8F,0xFE,0xFD,0xFC,0x33,0xFA,0x2F,0xFA,0x2B,0xF9,0x33,0xF9, + 0x53,0xFC,0x8E,0xFD,0xE5,0xFD,0xF7,0xFE,0x6C,0x00,0x54,0x02, + 0xE5,0x03,0x6C,0x06,0x2F,0x07,0x04,0x06,0xE0,0x05,0x01,0x05, + 0xF4,0x03,0x81,0x03,0xDE,0x02,0xAC,0x01,0xF9,0xFF,0x29,0xFF, + 0xC9,0xFE,0x3D,0xFE,0xA2,0xFE,0xD4,0xFE,0x8C,0xFE,0xDB,0xFE, + 0x2F,0xFF,0x1D,0xFF,0x07,0xFF,0x31,0xFF,0x3F,0xFF,0x46,0xFF, + 0x83,0xFF,0x86,0xFF,0x51,0xFF,0x0D,0xFF,0xA6,0xFE,0x2D,0xFE, + 0xE6,0xFD,0xF6,0xFD,0x1D,0xFE,0x4F,0xFE,0xA2,0xFE,0xDE,0xFE, + 0x1D,0xFF,0x7E,0xFF,0xDD,0xFF,0x47,0x00,0x85,0x00,0xB1,0x00, + 0xCC,0x00,0xD8,0x00,0xFD,0x00,0xFA,0x00,0x14,0x01,0x2C,0x01, + 0xFA,0x00,0xFA,0x00,0x08,0x01,0xF1,0x00,0xDE,0x00,0xC6,0x00, + 0xB7,0x00,0x61,0x00,0x2C,0x00,0x27,0x00,0xE6,0xFF,0xC1,0xFF, + 0xD5,0xFF,0x0F,0x00,0x28,0x00,0x2C,0x00,0x42,0x00,0x27,0x00, + 0x14,0x00,0x42,0x00,0x5F,0x00,0x6D,0x00,0x5A,0x00,0xFE,0xFF, + 0x70,0xFF,0xEF,0xFE,0xB3,0xFE,0x8C,0xFE,0x79,0xFE,0x6D,0xFE, + 0x3E,0xFE,0x24,0xFE,0x43,0xFE,0x9B,0xFE,0x1D,0xFF,0xA7,0xFF, + 0x1A,0x00,0x59,0x00,0x8B,0x00,0xD4,0x00,0x29,0x01,0x8B,0x01, + 0xDF,0x01,0xFE,0x01,0xFB,0x01,0xF1,0x01,0xE6,0x01,0xE1,0x01, + 0xE8,0x01,0xDC,0x01,0xAA,0x01,0x6D,0x01,0x1D,0x01,0xC6,0x00, + 0x76,0x00,0x32,0x00,0xF4,0xFF,0xA9,0xFF,0x58,0xFF,0x0C,0xFF, + 0xC2,0xFE,0x7E,0xFE,0x4F,0xFE,0x2A,0xFE,0x01,0xFE,0xE1,0xFD, + 0xCE,0xFD,0xC3,0xFD,0xD3,0xFD,0x04,0xFE,0x3F,0xFE,0x75,0xFE, + 0xB6,0xFE,0xF4,0xFE,0x33,0xFF,0x80,0xFF,0xDB,0xFF,0x2F,0x00, + 0x79,0x00,0xBB,0x00,0xED,0x00,0x15,0x01,0x45,0x01,0x72,0x01, + 0x88,0x01,0x91,0x01,0x8C,0x01,0x74,0x01,0x53,0x01,0x3A,0x01, + 0x21,0x01,0xF8,0x00,0xBC,0x00,0x87,0x00,0x52,0x00,0x1D,0x00, + 0xFB,0xFF,0xDC,0xFF,0xBD,0xFF,0x9E,0xFF,0xA3,0xFF,0xC4,0xFF, + 0xCF,0xFF,0xD5,0xFF,0xDD,0xFF,0xDF,0xFF,0xE6,0xFF,0x00,0x00, + 0x1F,0x00,0x24,0x00,0xF9,0xFF,0xB7,0xFF,0x66,0xFF,0x16,0xFF, + 0xE9,0xFE,0xD4,0xFE,0xC9,0xFE,0xB6,0xFE,0xAB,0xFE,0xB8,0xFE, + 0xE0,0xFE,0x35,0xFF,0x9B,0xFF,0xFB,0xFF,0x46,0x00,0x85,0x00, + 0xB7,0x00,0xE5,0x00,0x19,0x01,0x4A,0x01,0x6F,0x01,0x70,0x01, + 0x67,0x01,0x58,0x01,0x42,0x01,0x3B,0x01,0x33,0x01,0x1F,0x01, + 0xFF,0x00,0xD6,0x00,0xA2,0x00,0x66,0x00,0x35,0x00,0x08,0x00, + 0xD9,0xFF,0xA7,0xFF,0x71,0xFF,0x3B,0xFF,0x03,0xFF,0xD5,0xFE, + 0xB4,0xFE,0x92,0xFE,0x77,0xFE,0x65,0xFE,0x58,0xFE,0x5E,0xFE, + 0x74,0xFE,0x9B,0xFE,0xCA,0xFE,0xFB,0xFE,0x36,0xFF,0x6F,0xFF, + 0xA2,0xFF,0xE0,0xFF,0x21,0x00,0x57,0x00,0x8A,0x00,0xB6,0x00, + 0xD8,0x00,0xF1,0x00,0x0D,0x01,0x21,0x01,0x2D,0x01,0x28,0x01, + 0x1B,0x01,0x08,0x01,0xEA,0x00,0xD7,0x00,0xBC,0x00,0x9A,0x00, + 0x74,0x00,0x51,0x00,0x2D,0x00,0x0B,0x00,0xF1,0xFF,0xDA,0xFF, + 0xC1,0xFF,0xAD,0xFF,0xA3,0xFF,0x90,0xFF,0x87,0xFF,0x8A,0xFF, + 0x9C,0xFF,0xBD,0xFF,0xD4,0xFF,0xE2,0xFF,0xF3,0xFF,0xFE,0xFF, + 0x0D,0x00,0x24,0x00,0x37,0x00,0x40,0x00,0x28,0x00,0xFF,0xFF, + 0xD5,0xFF,0xAC,0xFF,0x8C,0xFF,0x79,0xFF,0x6E,0xFF,0x5A,0xFF, + 0x4D,0xFF,0x54,0xFF,0x6A,0xFF,0x90,0xFF,0xC4,0xFF,0xF4,0xFF, + 0x17,0x00,0x38,0x00,0x56,0x00,0x71,0x00,0x8A,0x00,0xA6,0x00, + 0xB9,0x00,0xBC,0x00,0xBC,0x00,0xB3,0x00,0xAF,0x00,0xAD,0x00, + 0xAB,0x00,0xAD,0x00,0x9C,0x00,0x79,0x00,0x5D,0x00,0x39,0x00, + 0x17,0x00,0xFE,0xFF,0xE5,0xFF,0xC3,0xFF,0x92,0xFF,0x63,0xFF, + 0x3B,0xFF,0x1B,0xFF,0x07,0xFF,0x01,0xFF,0xFB,0xFE,0xF6,0xFE, + 0xFB,0xFE,0x0D,0xFF,0x2C,0xFF,0x54,0xFF,0x82,0xFF,0xA6,0xFF, + 0xC9,0xFF,0xE6,0xFF,0x06,0x00,0x28,0x00,0x45,0x00,0x64,0x00, + 0x75,0x00,0x87,0x00,0x8D,0x00,0x90,0x00,0x98,0x00,0x97,0x00, + 0x9B,0x00,0x92,0x00,0x83,0x00,0x73,0x00,0x64,0x00,0x56,0x00, + 0x49,0x00,0x3C,0x00,0x29,0x00,0x1C,0x00,0x10,0x00,0x01,0x00, + 0xF9,0xFF,0xF3,0xFF,0xEA,0xFF,0xE5,0xFF,0xDE,0xFF,0xDB,0xFF, + 0xD9,0xFF,0xDD,0xFF,0xE1,0xFF,0xE4,0xFF,0xED,0xFF,0xF1,0xFF, + 0xF5,0xFF,0xFB,0xFF,0xFD,0xFF,0x03,0x00,0x0B,0x00,0x09,0x00, + 0x05,0x00,0x04,0x00,0x04,0x00,0x02,0x00,0x05,0x00,0x04,0x00, + 0xFB,0xFF,0xF0,0xFF,0xE5,0xFF,0xDD,0xFF,0xD4,0xFF,0xD4,0xFF, + 0xD6,0xFF,0xD0,0xFF,0xD0,0xFF,0xD6,0xFF,0xDA,0xFF,0xE8,0xFF, + 0xF8,0xFF,0x02,0x00,0x0E,0x00,0x15,0x00,0x1D,0x00,0x22,0x00, + 0x27,0x00,0x33,0x00,0x38,0x00,0x39,0x00,0x39,0x00,0x33,0x00, + 0x32,0x00,0x31,0x00,0x2B,0x00,0x29,0x00,0x1F,0x00,0x12,0x00, + 0x05,0x00,0xFA,0xFF,0xEE,0xFF,0xE5,0xFF,0xDC,0xFF,0xD1,0xFF, + 0xC5,0xFF,0xBC,0xFF,0xB7,0xFF,0xB1,0xFF,0xAC,0xFF,0xAF,0xFF, + 0xB0,0xFF,0xAC,0xFF,0xB1,0xFF,0xB6,0xFF,0xBA,0xFF,0xC8,0xFF, + 0xD2,0xFF,0xDA,0xFF,0xE7,0xFF,0xEB,0xFF,0xF6,0xFF,0x04,0x00, + 0x0B,0x00,0x18,0x00,0x1E,0x00,0x25,0x00,0x2E,0x00,0x32,0x00, + 0x3B,0x00,0x42,0x00,0x4A,0x00,0x4B,0x00,0x4A,0x00,0x50,0x00, + 0x52,0x00,0x4C,0x00,0x4B,0x00,0x4B,0x00,0x42,0x00,0x41,0x00, + 0x39,0x00,0x2D,0x00,0x28,0x00,0x1B,0x00,0x16,0x00,0x13,0x00, + 0xFF,0xFF,0xF6,0xFF,0xEC,0xFF,0xE2,0xFF,0xE0,0xFF,0xDB,0xFF, + 0xDB,0xFF,0xD6,0xFF,0xD5,0xFF,0xD0,0xFF,0xCA,0xFF,0xD2,0xFF, + 0xCF,0xFF,0xD3,0xFF,0xD6,0xFF,0xD7,0xFF,0xE1,0xFF,0xE5,0xFF, + 0xEE,0xFF,0xFA,0xFF,0x03,0x00,0x0B,0x00,0x15,0x00,0x19,0x00, + 0x1B,0x00,0x23,0x00,0x26,0x00,0x28,0x00,0x2C,0x00,0x28,0x00, + 0x22,0x00,0x1E,0x00,0x16,0x00,0x14,0x00,0x0E,0x00,0x02,0x00, + 0xFA,0xFF,0xF3,0xFF,0xE9,0xFF,0xDF,0xFF,0xDC,0xFF,0xD2,0xFF, + 0xCD,0xFF,0xCB,0xFF,0xC3,0xFF,0xC7,0xFF,0xC0,0xFF,0xC5,0xFF, + 0xC9,0xFF,0xCA,0xFF,0xD2,0xFF,0xD1,0xFF,0xD9,0xFF,0xE3,0xFF, + 0xE8,0xFF,0xF0,0xFF,0xF8,0xFF,0xFD,0xFF,0x05,0x00,0x0A,0x00, + 0x0E,0x00,0x15,0x00,0x18,0x00,0x1B,0x00,0x20,0x00,0x23,0x00, + 0x29,0x00,0x2A,0x00,0x2C,0x00,0x2C,0x00,0x2C,0x00,0x2E,0x00, + 0x2B,0x00,0x2C,0x00,0x29,0x00,0x28,0x00,0x26,0x00,0x20,0x00, + 0x21,0x00,0x1D,0x00,0x15,0x00,0x16,0x00,0x12,0x00,0x0D,0x00, + 0x09,0x00,0x01,0x00,0x00,0x00,0xFD,0xFF,0xF9,0xFF,0xF5,0xFF, + 0xF4,0xFF,0xF3,0xFF,0xF2,0xFF,0xEF,0xFF,0xF1,0xFF,0xF3,0xFF, + 0xF1,0xFF,0xF4,0xFF,0xF2,0xFF,0xF1,0xFF,0xF7,0xFF,0xF5,0xFF, + 0xF6,0xFF,0xF8,0xFF,0xF8,0xFF,0xFA,0xFF,0xFA,0xFF,0xFC,0xFF, + 0xFF,0xFF,0x00,0x00,0xFC,0xFF,0xFD,0xFF,0x01,0x00,0xFD,0xFF, + 0xFC,0xFF,0xFC,0xFF,0xFE,0xFF,0xFE,0xFF,0xFD,0xFF,0xFC,0xFF, + 0xFC,0xFF,0xFA,0xFF,0xFA,0xFF,0xF8,0xFF,0xF8,0xFF,0xF7,0xFF, + 0xF2,0xFF,0xF6,0xFF,0xF6,0xFF,0xF3,0xFF,0xF5,0xFF,0xF0,0xFF, + 0xF1,0xFF,0xF4,0xFF,0xF4,0xFF,0xF3,0xFF,0xF6,0xFF,0xF9,0xFF, + 0xF8,0xFF,0xF9,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF,0xFF,0x01,0x00, + 0x00,0x00,0x03,0x00,0x04,0x00,0x07,0x00,0x08,0x00,0x06,0x00, + 0x0A,0x00,0x0B,0x00,0x0B,0x00,0x0B,0x00,0x0B,0x00,0x0B,0x00, + 0x0B,0x00,0x0A,0x00,0x0D,0x00,0x0C,0x00,0x0C,0x00,0x0B,0x00, + 0x05,0x00,0x0B,0x00,0x09,0x00,0x09,0x00,0x0A,0x00,0x06,0x00, + 0x07,0x00,0x08,0x00,0x07,0x00,0x06,0x00,0x06,0x00,0x07,0x00, + 0x09,0x00,0x03,0x00,0x02,0x00,0x06,0x00,0x04,0x00,0x04,0x00, + 0x01,0x00,0x01,0x00,0x02,0x00,0xFE,0xFF,0x00,0x00,0xFE,0xFF, + 0xFB,0xFF,0xFC,0xFF,0xFC,0xFF,0xFC,0xFF,0xFC,0xFF,0xFA,0xFF, + 0xFD,0xFF,0xFB,0xFF,0xF8,0xFF,0xFD,0xFF,0xFB,0xFF,0xF8,0xFF, + 0xFA,0xFF,0xFC,0xFF,0xFC,0xFF,0xF9,0xFF,0xFA,0xFF,0xFD,0xFF, + 0xFB,0xFF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFF,0xFC,0xFF,0xFC,0xFF, + 0xFA,0xFF,0xFC,0xFF,0xFD,0xFF,0xFB,0xFF,0xFA,0xFF,0xFC,0xFF, + 0xFC,0xFF,0xFD,0xFF,0xFC,0xFF,0xFC,0xFF,0xFE,0xFF,0xFD,0xFF, + 0xFD,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0x00,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF,0x03,0x00,0x01,0x00, + 0x00,0x00,0x03,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00, + 0x04,0x00,0x06,0x00,0x01,0x00,0x05,0x00,0x05,0x00,0x04,0x00, + 0x07,0x00,0x06,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00, + 0x04,0x00,0x02,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x02,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0xFE,0xFF, + 0xFE,0xFF,0x02,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00, + 0xFE,0xFF,0xFD,0xFF,0x00,0x00,0xFD,0xFF,0xFC,0xFF,0xFE,0xFF, + 0xFE,0xFF,0xFF,0xFF,0xFC,0xFF,0xFC,0xFF,0x01,0x00,0xFF,0xFF, + 0xFC,0xFF,0x00,0x00,0xFD,0xFF,0xFD,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFE,0xFF,0xFE,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFE,0xFF,0x00,0x00,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0xFC,0xFF, + 0xFC,0xFF,0xFF,0xFF,0x00,0x00,0xFE,0xFF,0xFE,0xFF,0x00,0x00, + 0x01,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x02,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x01,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x03,0x00, + 0x01,0x00,0x04,0x00,0xFD,0xFF,0xFE,0xFF,0x09,0x00,0xFF,0xFF, + 0xFF,0xFF,0x01,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x06,0x00, + 0x02,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x01,0x00,0x03,0x00, + 0x03,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFC,0xFF,0xFC,0xFF,0xF9,0xFF, + 0xF8,0xFF,0xFB,0xFF,0xF9,0xFF,0xF5,0xFF,0xF9,0xFF,0xF9,0xFF, + 0xF8,0xFF,0xFB,0xFF,0xFC,0xFF,0xFD,0xFF,0xFD,0xFF,0xFD,0xFF, + 0x02,0x00,0x02,0x00,0x02,0x00,0x04,0x00,0x06,0x00,0x08,0x00, + 0x07,0x00,0x04,0x00,0x05,0x00,0x03,0x00,0x05,0x00,0x01,0x00, + 0x02,0x00,0x01,0x00,0xFE,0xFF,0xFF,0xFF,0xFB,0xFF,0x02,0x00, + 0xFD,0xFF,0x00,0x00,0xFA,0xFF,0x00,0x00,0xFC,0xFF,0xFE,0xFF, + 0xF8,0xFF,0xFD,0xFF,0xF8,0xFF,0xFF,0xFF,0x01,0x00,0xF6,0xFF, + 0x10,0x00,0xEE,0xFF,0x32,0x00,0x9C,0xFF,0x61,0x00,0x64,0x00, + 0x8C,0x00,0xDA,0x02,0x98,0x00,0x85,0xFF,0x4B,0x01,0xD3,0xFF, + 0x56,0xFE,0x9F,0x00,0xF0,0xFF,0xEA,0xFA,0x03,0xFE,0x9B,0x04, + 0x36,0x00,0x9C,0xFA,0xA8,0xFB,0xBF,0xFC,0x0E,0xFD,0xBB,0xFF, + 0x95,0x03,0xDA,0x01,0x6B,0xFD,0xC9,0xFD,0xFB,0x01,0x60,0x04, + 0xE2,0x04,0xC2,0x05,0xD2,0x04,0x9B,0x01,0x0F,0x01,0x0D,0x04, + 0x7D,0x05,0x07,0x03,0xE3,0xFE,0x88,0xFC,0x45,0xFB,0x78,0xFA, + 0x2D,0xFC,0x2A,0xFF,0x40,0xFF,0x90,0xFC,0x22,0xFB,0xC2,0xFC, + 0xFD,0xFE,0x05,0x01,0x31,0x03,0x27,0x03,0x98,0x00,0x6F,0xFE, + 0x0C,0xFF,0x9C,0x01,0x9B,0x02,0x26,0x01,0x0C,0xFF,0x35,0xFD, + 0x87,0xFC,0xFE,0xFD,0x70,0x00,0xD6,0x01,0x78,0x00,0x2F,0xFE, + 0xEB,0xFE,0xBA,0x00,0x7A,0x01,0x82,0x02,0xC0,0x02,0xCB,0x00, + 0x39,0x00,0x5A,0x00,0x6D,0x00,0xB1,0x01,0x25,0x01,0x31,0xFF, + 0xAC,0xFE,0xD0,0xFE,0x89,0xFE,0xC1,0xFF,0x3B,0x01,0xA9,0x00, + 0x14,0xFF,0xA2,0xFF,0xA7,0x01,0xDB,0x02,0x0E,0x02,0xAC,0x00, + 0x09,0x00,0xDD,0xFD,0xC2,0xFD,0xCE,0xFE,0xF7,0xFE,0x38,0xFF, + 0x9E,0xFE,0xCE,0xFF,0x8A,0x01,0x3C,0x09,0x51,0x12,0x01,0x0F, + 0x8B,0x04,0xE5,0xFA,0x0C,0xF6,0x2D,0xF5,0xAF,0xF5,0xCC,0xF7, + 0xF9,0xF7,0xAC,0xF1,0x85,0xED,0x9C,0xF1,0xBA,0xF9,0x9A,0x01, + 0x0C,0x06,0x26,0x0A,0x76,0x0A,0x6F,0x07,0x5E,0x08,0xDE,0x0C, + 0xF0,0x0E,0x04,0x0C,0xC3,0x05,0x7F,0xFF,0x99,0xFB,0x89,0xF8, + 0x6D,0xF9,0x6B,0xFC,0x9B,0xFC,0x49,0xFB,0xE2,0xFB,0x21,0xFF, + 0x4D,0x02,0xC6,0x03,0x5C,0x04,0x95,0x04,0x24,0x02,0x9A,0xFF, + 0xC4,0xFF,0x92,0x00,0x2F,0x00,0x55,0xFE,0xD7,0xFC,0xE6,0xFB, + 0x28,0xFB,0x91,0xFB,0xCF,0xFD,0xF9,0xFF,0x43,0x00,0x46,0xFF, + 0x71,0xFE,0x5E,0xFF,0x0A,0x01,0xEE,0x02,0xB6,0x03,0x83,0x02, + 0x12,0x00,0x60,0xFE,0x67,0xFE,0xB3,0xFE,0x5D,0xFF,0x4B,0x00, + 0x1E,0x00,0x74,0x02,0x85,0x10,0x75,0x1C,0x1D,0x16,0x96,0x06, + 0xB8,0xF9,0xCB,0xF3,0x6B,0xF0,0x40,0xEF,0xA6,0xF2,0x23,0xF4, + 0xD6,0xEA,0x08,0xE3,0x7A,0xE8,0x0A,0xF5,0xB7,0x01,0x12,0x09, + 0xAF,0x0F,0x20,0x13,0x19,0x10,0x25,0x0E,0x60,0x13,0x7A,0x18, + 0x63,0x14,0x23,0x09,0x63,0xFD,0x49,0xF7,0xEC,0xF1,0xFB,0xEF, + 0xC1,0xF4,0xC2,0xF9,0xDD,0xF8,0x9B,0xF4,0x5E,0xF6,0x39,0xFE, + 0x2C,0x06,0xCD,0x09,0xB1,0x0C,0x2E,0x0D,0xE4,0x08,0x1B,0x04, + 0x0A,0x03,0x1C,0x05,0xE3,0x02,0x6E,0xFC,0xC1,0xF6,0xB0,0xF4, + 0x89,0xF4,0xFC,0xF5,0x8B,0xF9,0xA5,0xFC,0x92,0xFD,0x00,0xFD, + 0x6F,0xFE,0xC0,0x01,0xBB,0x04,0xD7,0x05,0xFE,0x05,0x68,0x06, + 0x5F,0x03,0x3A,0x00,0x00,0x00,0xBB,0x00,0x4B,0x0F,0xCB,0x21, + 0x27,0x1D,0xC5,0x07,0x34,0xF4,0x89,0xEB,0x7B,0xEB,0xE0,0xEB, + 0x31,0xED,0xD4,0xF0,0x55,0xE9,0xC9,0xDE,0x3C,0xE3,0xD1,0xF3, + 0x0F,0x08,0xC3,0x11,0xB5,0x13,0xC6,0x15,0x40,0x15,0xD7,0x12, + 0x53,0x16,0x17,0x1C,0xC0,0x18,0x93,0x09,0x97,0xF5,0xF9,0xED, + 0x63,0xEE,0x3D,0xEF,0x2E,0xF2,0xA5,0xF5,0x05,0xF7,0xF1,0xF4, + 0x7E,0xF6,0xBF,0x00,0xD3,0x0E,0xA0,0x13,0xED,0x10,0xE2,0x0C, + 0x27,0x09,0x6C,0x06,0xC3,0x02,0x93,0x01,0x6A,0xFF,0x53,0xF8, + 0xA5,0xEF,0x29,0xED,0xE0,0xF1,0xF1,0xF7,0x10,0xFB,0x38,0xFB, + 0xFC,0xFC,0xF7,0xFE,0x69,0x01,0xAB,0x05,0xB6,0x0A,0xF6,0x0C, + 0x28,0x09,0x43,0x03,0x73,0xFD,0x58,0xFB,0x47,0xFE,0xF6,0x0D, + 0xAA,0x23,0xAD,0x21,0xF8,0x07,0x93,0xED,0xCD,0xE6,0x92,0xED, + 0xDA,0xF2,0x5C,0xF3,0x48,0xF1,0x53,0xEA,0x49,0xDD,0x46,0xDF, + 0x3C,0xF3,0x53,0x0C,0x6F,0x17,0x7A,0x12,0x89,0x0D,0xFD,0x0D, + 0x6B,0x12,0x70,0x16,0xC5,0x1B,0xB1,0x17,0x5B,0x08,0x95,0xF3, + 0x53,0xE9,0x3B,0xEF,0x71,0xF6,0x32,0xF9,0xC0,0xF5,0x66,0xF4, + 0x7C,0xF4,0x76,0xF9,0x90,0x03,0xF2,0x0F,0x6B,0x16,0x9D,0x0F, + 0x44,0x07,0x12,0x03,0xF1,0x05,0x93,0x06,0x64,0x02,0xF5,0xFB, + 0x0B,0xF5,0xEF,0xEF,0xFC,0xED,0x76,0xF4,0x27,0xFC,0xC4,0xFF, + 0x35,0xFC,0xAC,0xF9,0xF8,0xFD,0x02,0x04,0x9A,0x08,0xE8,0x0A, + 0xBF,0x0B,0xB9,0x07,0x19,0xFF,0x19,0xF8,0x5C,0xFD,0xB6,0x11, + 0x97,0x27,0x58,0x23,0x85,0x07,0x24,0xED,0xDD,0xE4,0xEB,0xEB, + 0x0A,0xF2,0x89,0xF4,0x16,0xEF,0x73,0xE5,0xBE,0xDA,0x15,0xDF, + 0xDA,0xF6,0x12,0x0F,0xCF,0x19,0x19,0x13,0x9A,0x0C,0x23,0x0D, + 0x02,0x14,0xD0,0x19,0xA6,0x1B,0x52,0x14,0xF6,0x01,0xD1,0xEF, + 0xFD,0xE7,0x8F,0xEF,0x5C,0xF8,0x60,0xFA,0xFA,0xF4,0xCF,0xF1, + 0x13,0xF5,0x95,0xFD,0xDF,0x09,0xCF,0x12,0x8A,0x15,0xA0,0x0D, + 0x28,0x05,0xED,0x02,0x75,0x06,0xAF,0x07,0xE8,0x00,0xF7,0xF7, + 0x82,0xF0,0x3B,0xEF,0x53,0xF1,0x69,0xF7,0x68,0xFD,0x4B,0xFE, + 0x02,0xFB,0x26,0xF9,0x9F,0xFE,0xA9,0x06,0xB5,0x0D,0xB3,0x0E, + 0x18,0x0B,0xE3,0x00,0xAB,0xF8,0x93,0xFD,0x02,0x14,0x9B,0x2D, + 0xC1,0x25,0x2A,0x04,0x54,0xE4,0xDE,0xDF,0xE6,0xEB,0xC3,0xF3, + 0xC7,0xF4,0x30,0xEC,0x65,0xE3,0x3B,0xD9,0x51,0xE1,0xB0,0xFB, + 0x5C,0x17,0x72,0x1F,0x60,0x12,0x89,0x08,0x7D,0x0A,0xDD,0x17, + 0xB6,0x1C,0x5F,0x1A,0xCE,0x0D,0x33,0xFB,0xE5,0xEA,0x5A,0xE5, + 0x5B,0xF1,0x70,0xFC,0xDF,0xFE,0x52,0xF3,0xE6,0xED,0x3C,0xF5, + 0x11,0x04,0x40,0x11,0x34,0x14,0x91,0x12,0x97,0x09,0x27,0x03, + 0x33,0x01,0x9A,0x06,0xFF,0x08,0x9E,0x00,0x18,0xF4,0xD4,0xEB, + 0xB1,0xEF,0x2D,0xF6,0x04,0xFC,0x1D,0xFD,0x44,0xFB,0xE4,0xF8, + 0xF0,0xF8,0xC1,0x00,0x96,0x0B,0x7C,0x13,0x3A,0x0F,0x40,0x00, + 0xA1,0xF8,0x61,0x02,0xDF,0x1D,0x84,0x31,0xF3,0x21,0x89,0xFD, + 0xFA,0xDE,0xFC,0xDC,0xC7,0xE9,0x6F,0xF4,0x42,0xF4,0x91,0xE8, + 0x37,0xDD,0x8C,0xD7,0xE8,0xE7,0x4F,0x05,0x2A,0x1E,0xDB,0x1F, + 0x7D,0x11,0x40,0x07,0xE1,0x0B,0x19,0x1B,0xD1,0x1F,0x55,0x19, + 0xFC,0x04,0xF6,0xF1,0xEB,0xE5,0x43,0xE8,0x1C,0xF6,0x04,0xFF, + 0xA2,0xFD,0x0C,0xEF,0x88,0xEB,0x9B,0xF6,0xBF,0x0B,0x95,0x18, + 0x83,0x15,0x02,0x0D,0xC1,0x03,0xFE,0x02,0xDC,0x04,0xCD,0x09, + 0x85,0x07,0xBD,0xFC,0x9D,0xEF,0xD6,0xE9,0x6A,0xF1,0xC5,0xFA, + 0x65,0xFF,0x0F,0xFA,0x6A,0xF5,0xA1,0xF5,0xE0,0xFD,0x96,0x09, + 0xE1,0x11,0x06,0x10,0x70,0x03,0xC7,0xFD,0xBC,0x08,0x59,0x28, + 0x8A,0x34,0xE3,0x1B,0x1E,0xF2,0x12,0xD9,0xF8,0xE0,0x90,0xED, + 0x1F,0xF4,0xA9,0xEA,0x68,0xE1,0x23,0xDA,0x52,0xDB,0x29,0xF0, + 0xF3,0x0C,0x4C,0x23,0x17,0x1D,0x7E,0x0D,0x44,0x06,0x6D,0x14, + 0x70,0x23,0xD9,0x20,0x30,0x10,0x66,0xF9,0xBF,0xED,0x76,0xE7, + 0xBA,0xEE,0x52,0xF8,0xEC,0xFD,0x9E,0xF5,0x14,0xE8,0x2D,0xEC, + 0xB7,0xFE,0x1C,0x16,0xB1,0x18,0xBF,0x0F,0x5C,0x05,0x47,0x04, + 0x35,0x09,0x13,0x0B,0x30,0x0B,0x0C,0x02,0x16,0xF7,0xCB,0xEB, + 0xC5,0xEC,0x74,0xF6,0x81,0xFD,0x5F,0xFA,0xB9,0xF0,0x62,0xF1, + 0x3A,0xFB,0x81,0x0A,0x0B,0x0F,0xCE,0x09,0x16,0x05,0x24,0x09, + 0x7F,0x1F,0xDA,0x30,0x90,0x28,0x06,0x08,0x7C,0xE8,0x01,0xE1, + 0xB5,0xE8,0xD7,0xF0,0x54,0xEB,0xA1,0xDF,0xAC,0xD7,0x41,0xD9, + 0xA7,0xE8,0x57,0xFF,0xB8,0x14,0x26,0x1A,0x17,0x14,0xE7,0x0C, + 0x70,0x13,0x75,0x21,0x07,0x25,0x12,0x19,0xC4,0x01,0x13,0xF3, + 0x92,0xED,0x6B,0xF1,0x44,0xF5,0x15,0xF5,0xF0,0xF0,0x24,0xE9, + 0x9C,0xEB,0xF2,0xF7,0xCA,0x0A,0xF8,0x13,0xC3,0x10,0x7B,0x09, + 0x0F,0x07,0xF3,0x0C,0x59,0x10,0x17,0x0E,0xF1,0x03,0x6C,0xF9, + 0x4A,0xF2,0x1F,0xF1,0xF4,0xF4,0xAC,0xF7,0xE3,0xF5,0x6B,0xEF, + 0x8F,0xEF,0xC7,0xF8,0x30,0x07,0xB4,0x0B,0x68,0x07,0x31,0x05, + 0x84,0x0D,0x7D,0x26,0x8D,0x31,0xA6,0x22,0xAE,0x01,0x6D,0xEA, + 0x89,0xEB,0x11,0xF2,0x33,0xF3,0xAB,0xE5,0x70,0xDA,0x9C,0xD6, + 0x4A,0xDD,0xBE,0xED,0x31,0x00,0x1B,0x0F,0xB7,0x0F,0x90,0x0C, + 0x14,0x0D,0x05,0x1B,0x12,0x27,0xBB,0x23,0x73,0x12,0xB2,0xFE, + 0x9E,0xF8,0x21,0xF8,0xF7,0xF9,0x23,0xF5,0x6A,0xEF,0x1E,0xEA, + 0xBF,0xE7,0xDA,0xEE,0xA3,0xFA,0x63,0x08,0xB0,0x0A,0x29,0x07, + 0xCD,0x05,0x9E,0x0C,0x63,0x15,0xDA,0x13,0x32,0x0B,0x05,0x00, + 0xB0,0xFB,0x22,0xFA,0x07,0xF9,0x15,0xF7,0x0A,0xF4,0xAD,0xF0, + 0x28,0xED,0x35,0xF1,0x75,0xFB,0x8E,0x05,0x33,0x05,0x42,0x01, + 0xD7,0x03,0x20,0x16,0x5D,0x2D,0xD1,0x2B,0x90,0x13,0xEB,0xF6, + 0x28,0xF1,0x92,0xFA,0xB0,0xFD,0x2F,0xF2,0xEE,0xDE,0xE9,0xD7, + 0x0A,0xDB,0x9F,0xE7,0xDC,0xF4,0xEF,0xFF,0x97,0x04,0x78,0x03, + 0x71,0x06,0x5B,0x11,0x46,0x22,0x28,0x26,0x7A,0x1A,0x45,0x08, + 0x7F,0x00,0x23,0x04,0xFB,0x05,0x95,0xFE,0x3C,0xF0,0x47,0xE9, + 0xA1,0xE9,0xE1,0xEF,0xDF,0xF5,0x52,0xFA,0x99,0xFD,0x35,0xFE, + 0x87,0x01,0xE2,0x07,0x64,0x11,0x0F,0x15,0x7F,0x0F,0x95,0x06, + 0xD2,0x01,0xC9,0x03,0xC0,0x03,0x43,0xFE,0xAC,0xF5,0x45,0xF1, + 0x57,0xF2,0x28,0xF4,0x99,0xF5,0xCB,0xF7,0x94,0xFC,0x8A,0xFD, + 0x7C,0xFD,0x27,0x02,0x00,0x10,0xF6,0x22,0x53,0x24,0x33,0x13, + 0x99,0xFE,0xB0,0xFA,0xBE,0x04,0x7E,0x06,0x36,0xF9,0x75,0xE4, + 0xD2,0xDC,0x33,0xE3,0xB6,0xED,0x40,0xF3,0x16,0xF4,0x18,0xF6, + 0x6F,0xFA,0xFC,0x02,0x66,0x0D,0x68,0x18,0x35,0x1B,0xB1,0x14, + 0xB5,0x0B,0x06,0x0A,0x47,0x0F,0x21,0x0F,0xC6,0x04,0xC3,0xF4, + 0x9F,0xED,0x66,0xF0,0x2C,0xF6,0xAE,0xF7,0x0B,0xF4,0xF7,0xF2, + 0xEF,0xF5,0x70,0xFD,0xEA,0x04,0x1A,0x0A,0xB5,0x0B,0x33,0x09, + 0xB3,0x07,0x8D,0x08,0x31,0x0B,0xE8,0x09,0xA0,0x02,0xD3,0xFA, + 0xA3,0xF7,0x04,0xFA,0xA0,0xFB,0x78,0xF9,0xD0,0xF5,0x64,0xF5, + 0xD2,0xF9,0x16,0xFF,0x73,0x02,0x82,0x02,0x71,0x01,0xC8,0x01, + 0x72,0x04,0xB7,0x07,0xB3,0x07,0x59,0x03,0xBA,0xFC,0xAB,0x00, + 0x24,0x0E,0x82,0x12,0x04,0x06,0x41,0xF3,0xB3,0xF0,0x3E,0xFD, + 0x25,0x06,0x30,0xFE,0x5D,0xEE,0x1E,0xEB,0x34,0xF4,0x78,0xFE, + 0xBE,0xFF,0x35,0xFC,0xE1,0xFB,0x5E,0xFF,0xC2,0x03,0xE7,0x07, + 0x8A,0x0C,0xA9,0x0D,0x17,0x09,0xE6,0x02,0xD3,0x02,0x86,0x08, + 0x74,0x0A,0x62,0x02,0x34,0xF8,0x90,0xF6,0xA0,0xFC,0x8F,0x00, + 0x1A,0xFC,0xDB,0xF5,0xED,0xF5,0x05,0xFC,0xF2,0x00,0x38,0x01, + 0x55,0x00,0x3F,0x01,0x98,0x03,0xEC,0x04,0x01,0x05,0x40,0x05, + 0x79,0x04,0x18,0x02,0x9D,0xFF,0x68,0xFF,0x0D,0x01,0x87,0x00, + 0x1F,0xFD,0x3B,0xFA,0x9F,0xFB,0x3D,0xFF,0x4A,0x00,0x1C,0xFE, + 0xF3,0xFB,0xCE,0xFD,0x87,0x01,0x2D,0x03,0xCF,0x01,0xA4,0xFF, + 0xE2,0x00,0x16,0x04,0x8C,0x05,0x4D,0x03,0x9E,0xFF,0xD3,0xFE, + 0xD7,0xFF,0x47,0x00,0x37,0xFE,0x8A,0xFB,0xAB,0xFA,0xBF,0xFA, + 0x86,0xFB,0x1A,0xFC,0xF9,0xFC,0x2F,0xFE,0xC2,0xFE,0x71,0xFF, + 0xE2,0x00,0x22,0x03,0x55,0x04,0xB9,0x03,0xD6,0x02,0xFD,0x02, + 0x0D,0x04,0xB8,0x03,0x84,0x01,0x0B,0xFF,0x1E,0xFE,0x8A,0xFE, + 0xBE,0xFE,0x4B,0xFD,0xFB,0xFB,0x62,0xFC,0x13,0xFE,0x95,0x00, + 0x3F,0x02,0xB2,0x07,0xF2,0x0D,0x29,0x0E,0xA0,0x07,0xF5,0x00, + 0xEE,0x02,0x83,0x07,0xB3,0x05,0x8B,0xFA,0xAB,0xF0,0x80,0xF1, + 0x5D,0xF7,0xD4,0xF8,0x9D,0xF2,0xE2,0xED,0x1A,0xF2,0x05,0xFB, + 0xBF,0x00,0xA2,0x00,0x60,0x00,0x3A,0x04,0xC0,0x09,0x72,0x0D, + 0x54,0x0D,0x1A,0x0C,0xFB,0x09,0x93,0x07,0xDE,0x05,0x4C,0x04, + 0x95,0x02,0xEB,0xFD,0xDC,0xF8,0xC6,0xF6,0x9E,0xF8,0xF0,0xFA, + 0x76,0xF9,0x06,0xF7,0xA5,0xF7,0xFC,0xFC,0x36,0x02,0xDE,0x02, + 0x4F,0x01,0x45,0x01,0xF8,0x04,0x4B,0x08,0xDF,0x07,0x02,0x05, + 0x8F,0x02,0xC0,0x02,0xFD,0x02,0xCE,0x01,0x40,0xFF,0xCA,0xFC, + 0x03,0xFC,0xB9,0xFB,0xF9,0xFB,0xDE,0xFB,0x89,0xFB,0x87,0xFB, + 0xF4,0xFB,0xBC,0xFD,0x77,0xFF,0x67,0x00,0x59,0x00,0xAB,0x00, + 0x1D,0x02,0xE4,0x03,0xCF,0x04,0x6D,0x03,0xD3,0x01,0xE8,0x01, + 0x08,0x03,0xCF,0x02,0x5E,0x00,0x06,0xFE,0xBD,0xFD,0xF8,0xFE, + 0x05,0xFF,0x3A,0xFD,0xC4,0xFB,0x59,0xFC,0x7F,0xFE,0xAA,0xFF, + 0x2C,0xFF,0xB0,0xFE,0x96,0xFF,0x92,0x01,0xAA,0x02,0x5B,0x02, + 0xA6,0x01,0xBF,0x01,0x71,0x02,0x8E,0x02,0xDE,0x01,0xDC,0x00, + 0x40,0x00,0x12,0x00,0x04,0x00,0xB0,0xFF,0x5D,0xFF,0x53,0xFF, + 0xF7,0xFF,0xA6,0x00,0x3C,0x00,0xA4,0xFF,0x59,0xFF,0x37,0x00, + 0x08,0x01,0x3C,0x00,0xC2,0xFE,0xC3,0xFD,0x7A,0xFE,0x22,0xFF, + 0x95,0xFE,0x37,0xFD,0x65,0xFC,0x77,0xFD,0xAC,0xFE,0x18,0xFF, + 0x89,0xFE,0x5F,0xFE,0xCA,0xFF,0x40,0x01,0xF9,0x01,0xC1,0x01, + 0xB0,0x01,0x61,0x02,0xFE,0x02,0x28,0x03,0x84,0x02,0xE4,0x01, + 0x94,0x01,0x64,0x01,0x2F,0x01,0x7A,0x00,0xC6,0xFF,0x40,0xFF, + 0x1F,0xFF,0x47,0xFF,0x1A,0xFF,0xB9,0xFE,0x66,0xFE,0x90,0xFE, + 0x28,0xFF,0x7B,0xFF,0x53,0xFF,0x1D,0xFF,0x67,0xFF,0x17,0x00, + 0x74,0x00,0x43,0x00,0xF6,0xFF,0x17,0x00,0x99,0x00,0xCB,0x00, + 0x69,0x00,0xE3,0xFF,0xEB,0xFF,0x2A,0x00,0x3D,0x00,0xFA,0xFF, + 0x79,0xFF,0x7F,0xFF,0xC4,0xFF,0xB6,0xFF,0x7B,0xFF,0x72,0xFF, + 0x9D,0xFF,0xA3,0xFF,0x84,0xFF,0x8E,0xFF,0xE5,0xFF,0x1D,0x00, + 0xF2,0xFF,0xD9,0xFF,0x01,0x00,0x65,0x00,0x8C,0x00,0x3F,0x00, + 0x17,0x00,0x68,0x00,0xD1,0x00,0xC1,0x00,0x7A,0x00,0x19,0x00, + 0x66,0x00,0xC6,0x00,0x3A,0x00,0xED,0xFF,0x04,0x00,0x2A,0x00, + 0x0A,0x00,0xBA,0xFF,0xBD,0xFF,0xF1,0xFF,0xEC,0xFF,0xD9,0xFF, + 0x3D,0x00,0xA3,0x00,0xAE,0x00,0x4C,0x00,0xF5,0xFF,0x6E,0x00, + 0x02,0x01,0xC7,0x00,0xE2,0xFF,0x5D,0xFF,0xBC,0xFF,0x20,0x00, + 0xA5,0xFF,0xA2,0xFE,0x3D,0xFE,0xC6,0xFE,0x54,0xFF,0x22,0xFF, + 0xA3,0xFE,0xB5,0xFE,0x6C,0xFF,0xFA,0xFF,0xEF,0xFF,0xB9,0xFF, + 0xE0,0xFF,0x69,0x00,0xBF,0x00,0x9A,0x00,0x6C,0x00,0x82,0x00, + 0xB4,0x00,0xCE,0x00,0xB6,0x00,0x97,0x00,0x9A,0x00,0xA9,0x00, + 0xA8,0x00,0x99,0x00,0x8E,0x00,0x7C,0x00,0x5D,0x00,0x49,0x00, + 0x3E,0x00,0x31,0x00,0x05,0x00,0xD2,0xFF,0xC0,0xFF,0xBA,0xFF, + 0xB4,0xFF,0x8F,0xFF,0x62,0xFF,0x64,0xFF,0x78,0xFF,0x83,0xFF, + 0x71,0xFF,0x59,0xFF,0x6C,0xFF,0x97,0xFF,0xAF,0xFF,0xA8,0xFF, + 0x9D,0xFF,0xB5,0xFF,0xE1,0xFF,0xF7,0xFF,0xF7,0xFF,0xF7,0xFF, + 0x04,0x00,0x1C,0x00,0x34,0x00,0x3B,0x00,0x35,0x00,0x32,0x00, + 0x42,0x00,0x56,0x00,0x50,0x00,0x45,0x00,0x42,0x00,0x43,0x00, + 0x4B,0x00,0x4C,0x00,0x3B,0x00,0x31,0x00,0x34,0x00,0x36,0x00, + 0x2E,0x00,0x1D,0x00,0x16,0x00,0x14,0x00,0x12,0x00,0x08,0x00, + 0xFC,0xFF,0xF9,0xFF,0xF4,0xFF,0xF2,0xFF,0xF0,0xFF,0xEA,0xFF, + 0xE6,0xFF,0xE8,0xFF,0xE8,0xFF,0xE9,0xFF,0xEA,0xFF,0xE7,0xFF, + 0xE4,0xFF,0xE4,0xFF,0xED,0xFF,0xF3,0xFF,0xEC,0xFF,0xE5,0xFF, + 0xEF,0xFF,0xFA,0xFF,0xFC,0xFF,0xFB,0xFF,0xF8,0xFF,0xFF,0xFF, + 0x07,0x00,0x09,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x09,0x00, + 0x0C,0x00,0x04,0x00,0xFA,0xFF,0x01,0x00,0x06,0x00,0xFF,0xFF, + 0xFA,0xFF,0xF8,0xFF,0xFC,0xFF,0xFB,0xFF,0xFA,0xFF,0xF8,0xFF, + 0xF2,0xFF,0xF2,0xFF,0xF5,0xFF,0xF7,0xFF,0xF3,0xFF,0xEE,0xFF, + 0xF1,0xFF,0xF9,0xFF,0xF7,0xFF,0xF2,0xFF,0xF5,0xFF,0xF8,0xFF, + 0xFC,0xFF,0xFC,0xFF,0xFA,0xFF,0xFC,0xFF,0x02,0x00,0x03,0x00, + 0x03,0x00,0xFF,0xFF,0x02,0x00,0x06,0x00,0x07,0x00,0x0C,0x00, + 0x09,0x00,0x09,0x00,0x0B,0x00,0x0C,0x00,0x0F,0x00,0x0C,0x00, + 0x09,0x00,0x0F,0x00,0x0A,0x00,0x08,0x00,0x12,0x00,0x0A,0x00, + 0x04,0x00,0x0A,0x00,0x0B,0x00,0x09,0x00,0x07,0x00,0x04,0x00, + 0x08,0x00,0x05,0x00,0x02,0x00,0x04,0x00,0x01,0x00,0xFE,0xFF, + 0xFE,0xFF,0xFD,0xFF,0x00,0x00,0xFA,0xFF,0xFA,0xFF,0x00,0x00, + 0xFA,0xFF,0xF9,0xFF,0xFC,0xFF,0xFF,0xFF,0x00,0x00,0xFD,0xFF, + 0x00,0x00,0x00,0x00,0x04,0x00,0x05,0x00,0x02,0x00,0x06,0x00, + 0x00,0x00,0x02,0x00,0x08,0x00,0x01,0x00,0x01,0x00,0x04,0x00, + 0x02,0x00,0x03,0x00,0xFE,0xFF,0xFC,0xFF,0x01,0x00,0xFA,0xFF, + 0xFC,0xFF,0xFE,0xFF,0xF9,0xFF,0xFC,0xFF,0xFB,0xFF,0xFA,0xFF, + 0xFB,0xFF,0xFA,0xFF,0xFA,0xFF,0xFA,0xFF,0xFA,0xFF,0xFC,0xFF, + 0xFC,0xFF,0xFE,0xFF,0xFC,0xFF,0xFA,0xFF,0x00,0x00,0xFF,0xFF, + 0xFC,0xFF,0xFB,0xFF,0xFD,0xFF,0x00,0x00,0xFD,0xFF,0xFB,0xFF, + 0xFF,0xFF,0x02,0x00,0xFF,0xFF,0xFD,0xFF,0x01,0x00,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xFF,0xFF,0xFF,0xFF, + 0x04,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x04,0x00, + 0x01,0x00,0xFF,0xFF,0x04,0x00,0x03,0x00,0x03,0x00,0x05,0x00, + 0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x04,0x00,0x03,0x00, + 0x02,0x00,0x00,0x00,0x03,0x00,0x06,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x03,0x00,0x06,0x00,0x05,0x00,0x02,0x00,0x02,0x00, + 0x03,0x00,0x05,0x00,0x03,0x00,0x02,0x00,0xFF,0xFF,0x00,0x00, + 0x05,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFE,0xFF,0x02,0x00, + 0xFF,0xFF,0xFD,0xFF,0x00,0x00,0xFD,0xFF,0xFD,0xFF,0xFC,0xFF, + 0xFE,0xFF,0xFD,0xFF,0xFB,0xFF,0xFC,0xFF,0xFE,0xFF,0xFF,0xFF, + 0xFD,0xFF,0xFD,0xFF,0x01,0x00,0x01,0x00,0xFD,0xFF,0xFE,0xFF, + 0x03,0x00,0x02,0x00,0xFD,0xFF,0x02,0x00,0x00,0x00,0xFF,0xFF, + 0x03,0x00,0xFD,0xFF,0xFD,0xFF,0xFF,0xFF,0xFE,0xFF,0x05,0x00, + 0x01,0x00,0xF4,0xFF,0x00,0x00,0x03,0x00,0xF9,0xFF,0x00,0x00, + 0xFD,0xFF,0x00,0x00,0x03,0x00,0xFB,0xFF,0x00,0x00,0x00,0x00, + 0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0x01,0x00,0xFC,0xFF, + 0xFE,0xFF,0x01,0x00,0xFE,0xFF,0x00,0x00,0x01,0x00,0x01,0x00, + 0x02,0x00,0x03,0x00,0x03,0x00,0x04,0x00,0x04,0x00,0x04,0x00, + 0x03,0x00,0x02,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0xFE,0xFF,0xFE,0xFF,0xFC,0xFF,0xFD,0xFF,0xFE,0xFF,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x02,0x00, + 0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00, + 0x01,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x01,0x00,0x00,0x00, + 0xFF,0xFF,0x01,0x00,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0x00,0x00, + 0xFF,0xFF,0xFE,0xFF,0x01,0x00,0x02,0x00,0x01,0x00,0x01,0x00, + 0x02,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x03,0x00, + 0x01,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFC,0xFF, + 0xFC,0xFF,0x03,0x00,0xFA,0xFF,0x04,0x00,0xFD,0xFF,0xFE,0xFF, + 0x01,0x00,0x00,0x00,0x01,0x00,0xFA,0xFF,0x0D,0x00,0xED,0xFF, + 0x14,0x00,0xE8,0xFF,0x0D,0x00,0xF0,0xFF,0x05,0x00,0xFD,0xFF, + 0x1F,0x00,0xD4,0xFF,0x14,0x00,0x06,0x00,0x0F,0x00,0x18,0x00, + 0x89,0xFF,0xEE,0x00,0x38,0xFD,0xBC,0x07,0x80,0x00,0xC5,0xF4, + 0x1A,0x06,0x36,0xFD,0x41,0xFD,0xA9,0x05,0x43,0xFB,0x24,0x02, + 0x90,0x02,0xDC,0xFB,0xD9,0x03,0x12,0xFF,0x16,0xFF,0xD9,0x03, + 0xE2,0xFC,0xA7,0x01,0x02,0x01,0x17,0xFE,0x6B,0x01,0x43,0xFF, + 0xF9,0xFE,0x98,0x01,0xE5,0xFE,0xC6,0xFE,0x67,0x01,0x4B,0xFE, + 0x79,0x00,0xD7,0x00,0x0C,0xFE,0x93,0x00,0x4B,0x01,0x0D,0xFF, + 0x1B,0x00,0xC1,0x00,0x04,0xFF,0x63,0x01,0x5B,0xFF,0x72,0x00, + 0xE1,0xFF,0x67,0xFF,0x3B,0x01,0x31,0xFD,0xB1,0x06,0xE5,0xFE, + 0x5B,0xFA,0x28,0x04,0xF1,0xFB,0x42,0xFE,0xD8,0x02,0xFE,0xFC, + 0x34,0x02,0xCD,0x01,0xC9,0xFC,0xCC,0x03,0x3F,0xFD,0x5E,0x04, + 0x13,0x03,0x1E,0xF9,0x66,0x04,0x30,0xFD,0xF5,0xFD,0xF8,0x04, + 0x7F,0xF9,0x7A,0x02,0x70,0x05,0x97,0xF7,0x9F,0x06,0x09,0xFE, + 0xA6,0xFB,0x25,0x09,0x6B,0xF9,0xE8,0xFF,0x0B,0x05,0x3A,0xFB, + 0x13,0x01,0x43,0x03,0x51,0xFA,0xFE,0x01,0x7F,0x02,0xA7,0xFA, + 0x7C,0x04,0xFD,0xFC,0xB5,0xFF,0x53,0x03,0xA2,0xFA,0x15,0x05, + 0xB3,0xFC,0xD0,0x01,0xBA,0x02,0xB3,0xF8,0x9D,0x08,0xF6,0xFC, + 0xF2,0xFA,0xF9,0x09,0xAA,0xF7,0x93,0x02,0x14,0x05,0x50,0xF6, + 0xAA,0x08,0x1B,0xFB,0x82,0x00,0x68,0x03,0x5F,0xFA,0x69,0x03, + 0xC1,0xFF,0xF6,0xFF,0x7C,0xFE,0xB6,0x01,0xA1,0xFF,0x05,0xFF, + 0x20,0x01,0xC6,0x00,0x46,0xFC,0xB4,0x03,0x25,0x00,0xDF,0xFB, + 0xAA,0x04,0x2C,0xFD,0xAF,0x01,0xAE,0xFE,0xBB,0x01,0x30,0xFE, + 0x14,0x00,0x14,0x04,0xAE,0xF8,0x40,0x07,0xB6,0xFB,0x4A,0xFF, + 0x6D,0x05,0x3A,0xF9,0xA9,0x03,0x09,0x01,0x8A,0xFC,0x84,0x01, + 0x4B,0x02,0xCA,0xFC,0x3C,0x00,0xCC,0x03,0x67,0xFC,0xE9,0xFD, + 0x45,0x08,0xF3,0xF7,0x0F,0xFF,0x28,0x0B,0xC9,0xF3,0x7B,0x03, + 0x82,0x07,0x0E,0xF1,0xE6,0x0D,0x63,0xFD,0xE0,0xF3,0x79,0x13, + 0xAD,0xEF,0xDD,0x05,0xF4,0x05,0x1E,0xF4,0xEB,0x0A,0xD6,0xF9, + 0xCE,0x01,0x6E,0x00,0x9A,0xFD,0x48,0x03,0x92,0xFD,0x12,0x01, + 0x39,0x02,0x04,0xF8,0xCF,0x07,0x87,0x04,0xDF,0xED,0xD4,0x12, + 0xCE,0xFB,0x4A,0xF1,0xDA,0x15,0x89,0xF3,0xFB,0xFC,0x66,0x0C, + 0x45,0xF4,0x80,0x04,0xBD,0x03,0x94,0xF7,0xFE,0x07,0xB1,0xFC, + 0x63,0xFC,0x82,0x07,0x8C,0xFA,0x1E,0x00,0x11,0x03,0xC2,0xFD, + 0x19,0x01,0x7F,0xFE,0xC6,0x01,0x65,0x00,0xE0,0xFB,0x7F,0x07, + 0x1D,0xF8,0xC7,0x01,0x11,0x09,0x92,0xF0,0xA9,0x09,0x4B,0x02, + 0xAB,0xF5,0xAC,0x08,0xB9,0xFE,0xF4,0xFC,0x7D,0x03,0x23,0xFC, + 0x5B,0x05,0x1B,0xFD,0xDF,0xFC,0x7C,0x08,0x28,0xF6,0x7B,0x06, + 0xB0,0x01,0x57,0xF5,0xF9,0x0A,0x2A,0xFF,0x0A,0xF5,0x52,0x0D, + 0xE5,0xFA,0xC9,0xF9,0x8F,0x09,0x5F,0xFB,0xDC,0x00,0x82,0xFE, + 0x55,0x01,0xD3,0x01,0xB7,0xFD,0x48,0xFF,0xAC,0x03,0x37,0xFB, + 0xE7,0x02,0x57,0x00,0x3B,0xFC,0xAB,0x07,0x0C,0xF8,0x58,0x04, + 0x06,0x00,0xB4,0xFA,0xA8,0x09,0x51,0xF7,0xEC,0xFF,0xAC,0x09, + 0xAE,0xF5,0x27,0x02,0x05,0x04,0x7A,0xFD,0x40,0x00,0x90,0xFB, + 0x51,0x0B,0x9B,0xF5,0x6A,0xFF,0x4B,0x0E,0xBD,0xEB,0x37,0x0D, + 0x6F,0x02,0xD1,0xF1,0x36,0x10,0x15,0xF6,0x2B,0xFE,0xFB,0x0B, + 0x6A,0xF1,0x76,0x08,0x1D,0x02,0x21,0xF5,0x7A,0x0A,0x7F,0xFE, + 0x06,0xFA,0xC9,0x02,0x16,0x07,0xB2,0xF4,0xF7,0x04,0x51,0x06, + 0x10,0xF3,0xF4,0x08,0xCA,0x02,0xBA,0xF5,0x7C,0x05,0x37,0x06, + 0x78,0xF4,0x1B,0x07,0x7B,0x01,0x90,0xF8,0xB0,0x07,0x1A,0xFE, + 0x51,0xFB,0xF1,0x02,0xFD,0x05,0x1B,0xF4,0xE7,0x06,0xA9,0x03, + 0x18,0xF4,0xD8,0x0C,0x74,0xFA,0x5A,0xFB,0x5B,0x07,0xC7,0x00, + 0x12,0xF7,0x0A,0x07,0xAE,0x03,0xAA,0xF0,0x20,0x13,0x1B,0xF9, + 0x97,0xF2,0x7D,0x15,0xCE,0xF8,0x9E,0xF3,0x9B,0x0E,0xE6,0xFF, + 0x10,0xF3,0x6F,0x0B,0xAF,0x00,0xD8,0xF2,0xC9,0x0C,0x47,0x01, + 0x5C,0xF2,0x8B,0x0D,0x80,0xFC,0x8A,0xF8,0xE7,0x06,0x25,0x05, + 0x24,0xF5,0xDB,0xFF,0xD3,0x0F,0xE3,0xEC,0x56,0x0A,0xDA,0x03, + 0x1A,0xF3,0x35,0x08,0xE8,0x00,0xC2,0xFF,0xC2,0xFB,0x16,0x00, + 0x0A,0x07,0x47,0xFB,0x43,0xFA,0xE9,0x07,0x2D,0x00,0xDE,0xF9, + 0x17,0x00,0x3F,0x0A,0x45,0xF6,0x40,0xFE,0xE0,0x0E,0x66,0xEF, + 0x8A,0x03,0x6C,0x0D,0xD8,0xEE,0xAD,0x05,0x0D,0x08,0xE0,0xF5, + 0xB8,0x00,0x1D,0x06,0xB8,0xFB,0xF3,0xFA,0x38,0x0E,0x7D,0xF3, + 0x76,0xFE,0x6C,0x0F,0xBD,0xED,0xD1,0x0A,0x99,0x03,0x99,0xEF, + 0xBA,0x0E,0x96,0x01,0x56,0xF3,0x6C,0x03,0x20,0x0D,0x1E,0xF4, + 0x2F,0xFA,0x51,0x0F,0x60,0xF5,0xB7,0x02,0x88,0x04,0x28,0xF7, + 0x82,0x03,0xE1,0x06,0x66,0xF9,0x10,0xFC,0x50,0x0B,0xA7,0xF7, + 0xC1,0x00,0xF2,0x02,0x75,0xFB,0x77,0x05,0xF1,0xFA,0xB0,0x03, + 0x6F,0xFE,0x6E,0xFC,0xA2,0x0A,0x9F,0xF5,0xEF,0x01,0x38,0x05, + 0x98,0xF6,0x0D,0x0E,0xC2,0xF5,0x04,0xF9,0xF4,0x13,0x08,0xF7, + 0x0F,0xF6,0x68,0x07,0xB0,0x08,0x28,0xF5,0x44,0xFB,0xB5,0x10, + 0x94,0xF2,0x4F,0xFE,0xDC,0x0D,0xFF,0xF2,0xC5,0x02,0xD0,0x08, + 0x96,0xF9,0xF4,0xF6,0xC4,0x0F,0x24,0xFE,0x31,0xF2,0x6B,0x0F, + 0x6A,0xF9,0x16,0xFA,0xB1,0x08,0x68,0x06,0x44,0xEE,0x53,0x04, + 0xC4,0x0F,0xDC,0xED,0x19,0x06,0xD4,0x04,0x73,0xF6,0x3F,0x02, + 0x90,0x0A,0x35,0xF9,0x84,0xF5,0x26,0x0E,0xB0,0x01,0x0F,0xF2, + 0xB9,0x07,0xE6,0x03,0x31,0xF6,0x90,0x09,0x1E,0x00,0xE2,0xF6, + 0xE5,0x04,0xFE,0x04,0xB8,0xFB,0xED,0xFD,0xD1,0x02,0xB8,0xFE, + 0xE6,0xFF,0x01,0xFF,0x04,0x03,0xB0,0xFC,0x86,0xFE,0x66,0x07, + 0x5B,0xFD,0x6D,0xF9,0x1B,0x04,0x50,0x08,0xE8,0xF8,0x37,0xFC, + 0x53,0x02,0x37,0x04,0x34,0xFF,0x18,0xFC,0x09,0x02,0xE3,0xFD, + 0xA4,0x00,0x9C,0x01,0xBD,0x02,0x59,0xF6,0xDE,0x06,0xA6,0x07, + 0x5E,0xEF,0x35,0x05,0xFC,0x09,0x15,0xF9,0xD8,0xFB,0x94,0x07, + 0xDD,0xFE,0xD9,0xFA,0x70,0x01,0x3D,0x03,0xBE,0x01,0x5D,0xFC, + 0x1B,0xFE,0x6D,0x01,0x8E,0x03,0x6E,0xFF,0x65,0xF9,0x15,0x02, + 0xC9,0x09,0xB8,0xF7,0x02,0xF7,0x2B,0x12,0xF4,0xFB,0x49,0xF0, + 0x3E,0x0C,0x67,0x05,0x53,0xF9,0x60,0xFC,0x18,0x06,0x26,0xFE, + 0x22,0xFC,0xA6,0x08,0x0F,0xFB,0xB8,0xFA,0x71,0x07,0x3F,0x01, + 0x2A,0xF9,0x85,0xFF,0x56,0x0A,0x0A,0xFB,0x1F,0xF7,0x62,0x09, + 0x77,0x01,0x92,0xFA,0x5A,0x03,0xF5,0xFE,0xC3,0xFC,0xF4,0x05, + 0xF5,0xFD,0x8C,0xFC,0x0C,0x04,0x84,0xFF,0xDF,0xFD,0x27,0x00, + 0x20,0x00,0xB0,0x00,0xEB,0x00,0x00,0xFF,0xC9,0xFF,0x6D,0xFF, + 0x69,0x03,0xC8,0xFC,0x08,0xFC,0x7E,0x06,0x49,0x01,0xD1,0xFB, + 0xC5,0xFD,0x1E,0x06,0xFB,0xFE,0x06,0xF9,0x56,0x05,0x1B,0x05, + 0x11,0xF9,0x7F,0xFD,0x4D,0x06,0x7D,0xFF,0x5C,0xFD,0x47,0x01, + 0xE6,0x00,0x58,0xFE,0xF0,0x00,0x61,0xFF,0x78,0xFE,0x05,0x04, + 0xAB,0xFF,0x63,0xFA,0xB4,0x02,0xB6,0x03,0x99,0xFC,0x3A,0xFE, + 0xCF,0x02,0x99,0x02,0x54,0xFB,0xB0,0xFF,0x35,0x04,0x15,0xFE, + 0x0A,0xFF,0x35,0x01,0x64,0xFF,0x5E,0x00,0x78,0x00,0xDD,0xFE, + 0x8F,0xFF,0x2B,0x01,0xE9,0x00,0xEF,0xFE,0x43,0xFF,0x59,0x01, + 0x3A,0x00,0x44,0xFE,0x6D,0x00,0x35,0xFF,0x31,0x01,0x9A,0x01, + 0xAC,0xFD,0x93,0xFF,0x65,0x01,0xDA,0x00,0x74,0xFE,0xD0,0xFF, + 0x98,0x01,0x4B,0xFF,0xB4,0xFE,0x0A,0x01,0x96,0x00,0x91,0xFE, + 0x3F,0x00,0x94,0x00,0xDA,0xFF,0x16,0x00,0x34,0xFF,0x18,0x00, + 0x14,0x01,0x54,0x00,0xA5,0xFE,0x8D,0xFF,0xFB,0x01,0x8A,0xFF, + 0xAE,0xFE,0xC9,0x00,0xBC,0x00,0x60,0xFF,0x78,0xFF,0x2E,0x01, + 0x88,0xFF,0x91,0xFF,0x07,0x01,0x5A,0xFF,0x99,0xFF,0x87,0x00, + 0x5D,0x00,0x5F,0xFF,0xC5,0xFF,0x66,0x00,0xB0,0xFF,0xC1,0xFF, + 0x68,0x00,0xC3,0xFF,0x5C,0xFF,0xA1,0x00,0x52,0x00,0x81,0xFF, + 0xB5,0xFF,0xC8,0x00,0x30,0x00,0x51,0xFF,0x57,0x00,0x9C,0x00, + 0xAB,0xFF,0x93,0xFF,0x98,0x00,0x85,0x00,0x8B,0xFF,0xAB,0xFF, + 0x1C,0x00,0x14,0x00,0xF5,0xFF,0xCC,0xFF,0xE4,0xFF,0x04,0x00, + 0x31,0x00,0xA7,0xFF,0x03,0x00,0x1C,0x00,0xFB,0xFF,0x07,0x00, + 0xC2,0xFF,0x37,0x00,0x53,0x00,0xBE,0xFF,0xC7,0xFF,0x59,0x00, + 0x13,0x00,0xC7,0xFF,0xF8,0xFF,0x42,0x00,0xF4,0xFF,0xD5,0xFF, + 0xFE,0xFF,0x28,0x00,0xD6,0xFF,0x09,0x00,0x13,0x00,0xF5,0xFF, + 0x05,0x00,0xD4,0xFF,0x1C,0x00,0x0D,0x00,0xF5,0xFF,0xF7,0xFF, + 0x0B,0x00,0x0B,0x00,0x08,0x00,0xEA,0xFF,0x06,0x00,0x20,0x00, + 0x02,0x00,0xCF,0xFF,0x16,0x00,0x27,0x00,0xDE,0xFF,0xE8,0xFF, + 0x21,0x00,0x12,0x00,0xD4,0xFF,0x05,0x00,0x16,0x00,0x03,0x00, + 0xD1,0xFF,0x14,0x00,0x17,0x00,0xDF,0xFF,0xFE,0xFF,0x0B,0x00, + 0xFC,0xFF,0xF7,0xFF,0x0B,0x00,0xFC,0xFF,0xF6,0xFF,0x08,0x00, + 0x0D,0x00,0xFE,0xFF,0xFD,0xFF,0x02,0x00,0x09,0x00,0x03,0x00, + 0xFC,0xFF,0xFF,0xFF,0x01,0x00,0x0A,0x00,0xFB,0xFF,0xE8,0xFF, + 0x08,0x00,0x10,0x00,0xF4,0xFF,0xF0,0xFF,0x06,0x00,0x0B,0x00, + 0xF6,0xFF,0xF5,0xFF,0x09,0x00,0x0F,0x00,0xF2,0xFF,0xF9,0xFF, + 0x0D,0x00,0x03,0x00,0xF5,0xFF,0xFD,0xFF,0x0A,0x00,0x04,0x00, + 0xFA,0xFF,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0xFE,0xFF, + 0xFE,0xFF,0x02,0x00,0x03,0x00,0xFD,0xFF,0xFF,0xFF,0x04,0x00, + 0xFC,0xFF,0xFD,0xFF,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00, + 0x03,0x00,0xFA,0xFF,0xFF,0xFF,0x0A,0x00,0x03,0x00,0xF7,0xFF, + 0x05,0x00,0x17,0x00,0xF9,0xFF,0xF5,0xFF,0x01,0x00,0x08,0x00, + 0x02,0x00,0xF5,0xFF,0x02,0x00,0x0A,0x00,0xFE,0xFF,0xF4,0xFF, + 0x00,0x00,0x08,0x00,0xFD,0xFF,0xF8,0xFF,0x04,0x00,0x08,0x00, + 0xFC,0xFF,0xF8,0xFF,0x08,0x00,0x06,0x00,0xFC,0xFF,0xFE,0xFF, + 0x03,0x00,0x02,0x00,0xFE,0xFF,0xFE,0xFF,0x03,0x00,0x03,0x00, + 0xFD,0xFF,0xFD,0xFF,0x03,0x00,0x02,0x00,0xFC,0xFF,0xFE,0xFF, + 0x03,0x00,0x01,0x00,0xFD,0xFF,0xFF,0xFF,0x00,0x00,0xFE,0xFF, + 0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0x00,0x00,0xFF,0xFF,0xFD,0xFF, + 0x02,0x00,0xFF,0xFF,0xFD,0xFF,0xFE,0xFF,0x01,0x00,0x00,0x00, + 0xFC,0xFF,0x00,0x00,0x01,0x00,0xFE,0xFF,0xFF,0xFF,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0xFF,0xFF,0x01,0x00,0x04,0x00, + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x02,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x03,0x00, + 0xFE,0xFF,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x02,0x00,0x01,0x00,0xFF,0xFF,0xFF,0xFF, + 0x02,0x00,0x02,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF, + 0x01,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x02,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFE,0xFF,0xFE,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x03,0x00, + 0xFF,0xFF,0xFF,0xFF,0x02,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0xFF,0xFF, + 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x02,0x00, + 0xFD,0xFF,0x02,0x00,0x01,0x00,0x01,0x00,0xFD,0xFF,0x01,0x00, + 0x03,0x00,0x00,0x00,0x03,0x00,0xF8,0xFF,0x09,0x00,0xF9,0xFF, + 0x02,0x00,0xFA,0xFF,0x12,0x00,0xF4,0xFF,0xFE,0xFF,0x06,0x00, + 0xFB,0xFF,0x0A,0x00,0xEC,0xFF,0x06,0x00,0x04,0x00,0x3D,0x00, + 0xB0,0xFF,0x23,0x00,0x13,0x00,0x76,0x00,0x57,0xFF,0x7A,0x00, + 0x47,0xFF,0xC7,0x00,0xB0,0x05,0xF2,0xFB,0x8C,0xF9,0x0E,0x00, + 0x14,0x04,0x65,0x00,0xB3,0xFB,0x13,0x00,0x38,0x04,0xAA,0x01, + 0x0C,0xFD,0x50,0xFF,0x1F,0x03,0x35,0x02,0x28,0xFE,0x8D,0xFE, + 0x6A,0x01,0xB1,0x01,0xAA,0xFE,0x01,0xFE,0x6C,0x00,0x3B,0x01, + 0x45,0xFF,0x47,0xFE,0x9A,0xFF,0xEE,0x00,0x3C,0x00,0xA4,0xFE, + 0xD9,0xFF,0xBB,0x00,0xA1,0x00,0x8E,0xFF,0xB1,0xFF,0xD1,0x00, + 0x4A,0x00,0x8B,0xFF,0xF0,0xFF,0x76,0x00,0x7A,0x00,0xA6,0xFF, + 0x51,0xFF,0x5A,0x00,0x6B,0x00,0x05,0x00,0x4C,0xFF,0x44,0x00, + 0xEA,0x00,0x68,0xFF,0x8A,0xFF,0x6F,0x00,0x23,0x00,0xD2,0xFF, + 0x65,0xFF,0x10,0x00,0xF8,0x00,0xE0,0xFF,0xAF,0xFF,0x8D,0xFF, + 0x8E,0x00,0x26,0x00,0x59,0xFF,0x4B,0x00,0x30,0x00,0xAB,0xFF, + 0x91,0xFF,0xDA,0x00,0x1A,0x00,0x82,0xFF,0xC7,0xFF,0xFC,0xFF, + 0xDD,0x00,0x3A,0x00,0x6F,0xFF,0xF6,0xFF,0x7E,0x00,0x49,0x00, + 0x32,0xFF,0x02,0xFF,0xB0,0x00,0xDC,0xFF,0x0F,0x00,0xFE,0x00, + 0x4F,0xFE,0x15,0x00,0x02,0x01,0x71,0xFF,0x0D,0x00,0xF1,0xFF, + 0xF9,0x00,0x59,0xFF,0xE6,0xFF,0x42,0x01,0x72,0x00,0x53,0xFF, + 0x81,0xFE,0x3F,0x01,0xBA,0x00,0x10,0xFF,0x92,0xFE,0xC2,0x00, + 0xD9,0x01,0x28,0xFF,0x84,0xFE,0xBF,0xFF,0x22,0x00,0xAB,0xFF, + 0xF6,0x00,0x8F,0xFF,0xD4,0xFF,0xEF,0x00,0x33,0x00,0x5E,0xFF, + 0xD5,0x00,0xE4,0x00,0x51,0xFF,0xC7,0x00,0x82,0xFF,0x1D,0xFF, + 0x5E,0xFF,0x2E,0x01,0xDD,0xFF,0x0A,0xFF,0x02,0x00,0xA0,0x00, + 0xB1,0x00,0x15,0xFF,0xBB,0xFF,0x1B,0x00,0xCF,0xFF,0xFE,0xFF, + 0x4C,0x01,0xE3,0xFE,0xF6,0xFF,0xFC,0xFF,0x03,0x00,0xD6,0xFF, + 0x52,0x00,0xE2,0x00,0x23,0xFF,0x92,0x00,0xF8,0xFF,0x6C,0x01, + 0xBE,0xFF,0xCE,0xFE,0xCB,0xFF,0x4F,0x01,0x7F,0x00,0x00,0xFE, + 0x3C,0xFF,0x73,0x00,0xE7,0x00,0x31,0xFF,0xF8,0xFD,0x8B,0x00, + 0xC3,0x01,0x65,0xFF,0x13,0xFF,0x23,0xFF,0xC9,0x01,0x5B,0x01, + 0x75,0xFF,0x03,0x00,0x0C,0x00,0x2E,0x01,0x59,0xFF,0x6A,0x00, + 0x5E,0x00,0x91,0xFF,0xEF,0x00,0xBB,0xFE,0xE0,0xFF,0xBB,0xFF, + 0xDB,0xFE,0x61,0x00,0x10,0x00,0xE1,0xFF,0x9A,0xFF,0xE9,0x00, + 0x18,0x00,0x46,0x00,0xB8,0x00,0x6E,0xFF,0x3B,0xFF,0x74,0xFF, + 0x54,0x01,0xBB,0xFF,0x05,0xFF,0x78,0xFF,0x06,0x01,0x02,0x01, + 0x5A,0xFD,0x4C,0xFF,0x45,0x02,0x7C,0x00,0x55,0xFE,0xAC,0xFF, + 0x53,0x01,0xD0,0x01,0x28,0x00,0x10,0xFF,0x74,0x00,0x76,0x00, + 0x38,0x00,0x04,0xFF,0xE8,0xFE,0xBF,0x00,0x58,0x01,0x50,0xFF, + 0x7B,0xFE,0x5A,0xFF,0xD8,0xFF,0x54,0x00,0x0D,0xFF,0x37,0xFF, + 0x47,0x01,0x4C,0x01,0x4C,0xFF,0xC2,0x00,0xC7,0xFF,0x52,0xFF, + 0x37,0x00,0x73,0x00,0xCA,0x00,0xEC,0xFE,0xCD,0x01,0x5E,0x02, + 0x25,0x00,0xB3,0xFF,0x54,0xFF,0xF7,0x00,0x1A,0x00,0xD4,0xFD, + 0x6D,0xFE,0x47,0xFE,0xC7,0x00,0x63,0x00,0x4F,0xFE,0xA9,0xFE, + 0x5C,0x00,0xEF,0x02,0xED,0x00,0x08,0xFE,0x72,0x00,0x43,0x02, + 0x60,0xFF,0x41,0xFF,0x5E,0xFF,0xAB,0x00,0x7D,0x02,0x98,0xFF, + 0x05,0xFC,0x2B,0xFD,0xE4,0x03,0x64,0x01,0xE7,0xFA,0x2F,0x01, + 0xA7,0x02,0xF7,0x00,0x27,0xFF,0x40,0xFE,0xB1,0x03,0x2A,0x02, + 0x30,0xFE,0x0E,0xFF,0x9D,0x01,0xEA,0xFF,0x57,0xFF,0xB7,0xFF, + 0x68,0xFE,0x83,0x00,0x10,0xFF,0x1C,0xFD,0x65,0x02,0xB8,0x02, + 0x8E,0xFD,0x9C,0xFE,0x45,0x02,0xB4,0x01,0x08,0xFE,0x87,0xFD, + 0xEF,0x01,0x14,0x04,0x7F,0xFE,0xCC,0xFD,0x4D,0x01,0xCC,0x01, + 0xA0,0x01,0x61,0xFD,0x55,0xFC,0x62,0x02,0xE4,0x01,0x24,0xFB, + 0x3E,0xFE,0x05,0x04,0x78,0x01,0xE7,0xFA,0x74,0xFE,0xD5,0x05, + 0x47,0x01,0xBB,0xFD,0xF8,0xFE,0xC8,0x00,0x82,0x03,0x20,0xFF, + 0x1E,0xFE,0x2C,0x02,0xD9,0x01,0x66,0xFE,0xB0,0xFC,0xB9,0x00, + 0xCD,0x01,0xB8,0x01,0x5C,0xFE,0x0C,0xFB,0x98,0xFF,0xA8,0x04, + 0x0E,0x00,0x06,0xFB,0x61,0x01,0x5C,0x03,0xDA,0xFF,0x9E,0xFF, + 0x95,0xFD,0x5D,0x02,0x71,0x04,0x4C,0xFD,0xE0,0xFC,0xE6,0xFE, + 0x0E,0x03,0xC7,0x01,0x3D,0xFD,0x56,0xFD,0xB0,0xFF,0x48,0x05, + 0x16,0x02,0x55,0xFC,0xC7,0xFB,0x3F,0x02,0x8D,0x07,0x35,0xFD, + 0x0A,0xF9,0xE1,0xFE,0x61,0x06,0xB7,0x04,0xB9,0xF8,0x0E,0xFB, + 0x88,0x03,0x29,0x04,0x4C,0x00,0xA7,0xFB,0x20,0xFE,0x05,0x04, + 0x1F,0x03,0xE2,0xFD,0x33,0xFC,0x72,0x02,0x9C,0x04,0xF1,0xFF, + 0x8B,0xFB,0x00,0xFE,0x2C,0x05,0x5D,0x02,0x35,0xFC,0xE7,0xFC, + 0xB3,0xFE,0xAC,0x01,0xED,0x02,0x97,0xFD,0x31,0xFD,0xB9,0x00, + 0xDA,0x05,0xF8,0xFE,0x0C,0xFC,0x57,0x04,0x3E,0x01,0x98,0xFF, + 0xCB,0xFD,0x0D,0x00,0xE0,0x02,0x11,0x00,0x5A,0xFC,0x2E,0xFD, + 0xAB,0x01,0x6F,0x02,0x98,0xFE,0x3C,0xFC,0x8F,0x00,0xAD,0x02, + 0xA2,0x00,0xA7,0xFD,0xA0,0xFF,0xBE,0x01,0x88,0x00,0x7D,0x00, + 0x40,0xFF,0x50,0x00,0x92,0x02,0x4D,0x00,0xF0,0xFF,0x78,0xFE, + 0xAB,0xFF,0x14,0x02,0x96,0xFE,0xCA,0xFF,0x6F,0xFF,0xC1,0xFE, + 0xA1,0xFF,0x42,0x00,0xCC,0x00,0xE4,0xFD,0x05,0x00,0xE5,0x00, + 0x1C,0xFF,0xE5,0x00,0x04,0x01,0xA4,0xFE,0x9C,0xFF,0xE4,0x01, + 0xB1,0xFF,0x20,0xFF,0xAA,0x01,0x59,0x01,0x6C,0xFE,0xFB,0xFF, + 0x97,0x01,0xB8,0x00,0x2E,0xFF,0x43,0xFD,0x38,0x01,0x78,0x01, + 0x0C,0xFF,0x98,0xFE,0x00,0xFE,0xC6,0x01,0x92,0x01,0xCA,0xFF, + 0xEC,0xFE,0x86,0xFF,0x60,0x01,0x27,0x00,0x50,0x02,0x89,0xFF, + 0xB5,0xFD,0x55,0x00,0x6F,0x00,0x32,0x00,0x9D,0xFE,0x37,0x00, + 0x4B,0x00,0x44,0xFF,0x3D,0xFF,0x63,0xFF,0xFA,0x00,0x09,0x02, + 0xBA,0xFE,0x80,0xFE,0x35,0x01,0x4E,0x01,0xE2,0x01,0xAF,0xFE, + 0x31,0x00,0x1E,0x00,0x0C,0x00,0x32,0x02,0xFA,0xFD,0x97,0xFE, + 0x9E,0xFF,0xDB,0x00,0x81,0x00,0x79,0xFD,0x17,0xFF,0x25,0x01, + 0x05,0x02,0x2B,0x00,0x5D,0xFE,0xEE,0xFF,0xA0,0x01,0x2F,0x01, + 0xF4,0xFF,0x78,0xFE,0x17,0xFF,0x53,0x00,0xF7,0xFF,0x4C,0xFF, + 0xC4,0xFD,0xC1,0xFF,0x9D,0x00,0x0F,0xFF,0x27,0xFF,0x54,0xFF, + 0xDF,0x01,0x94,0x00,0xFF,0xFE,0x1E,0x01,0xD2,0x01,0xFF,0x01, + 0xC5,0xFF,0x35,0xFF,0xE9,0xFF,0xAD,0x00,0xC3,0x00,0x22,0xFE, + 0x93,0xFF,0x76,0x01,0x3A,0x00,0xE1,0x00,0x17,0x00,0x95,0xFF, + 0x4F,0x01,0xCB,0x00,0x53,0x00,0x92,0xFE,0x30,0xFF,0x4E,0x00, + 0x5F,0xFE,0xC9,0xFE,0x77,0xFF,0xAF,0x00,0x22,0xFF,0x33,0xFE, + 0xE4,0xFE,0xB6,0xFE,0xC5,0x00,0xE3,0x04,0x05,0x0B,0x3C,0x06, + 0xA8,0xFF,0x79,0x04,0x1D,0x04,0x7B,0xFF,0x17,0xFD,0x5F,0xF8, + 0xA0,0xF8,0x9E,0xF8,0x32,0xF8,0x3D,0xFC,0x41,0xF7,0xB2,0xF7, + 0xBD,0xFC,0xDE,0xFD,0x63,0xFF,0x41,0xFD,0xB4,0x02,0x8F,0x04, + 0xC5,0x02,0x26,0x08,0xAA,0x07,0xE3,0x06,0xEB,0x06,0xBB,0x05, + 0x5F,0x05,0x79,0x01,0x8B,0x01,0xB9,0x01,0x39,0xFF,0x15,0xFF, + 0x08,0xFE,0x58,0xFE,0x6B,0x00,0xB7,0xFF,0xF3,0xFE,0x81,0xFE, + 0x40,0xFF,0x4A,0x03,0xF1,0x01,0x97,0xFD,0x1A,0xFE,0x8B,0x01, + 0x8D,0x01,0x72,0xFD,0x36,0xFC,0x33,0xFE,0x4C,0xFD,0x8A,0xFC, + 0xF5,0xFA,0xE2,0xF8,0x5A,0xFE,0x56,0x08,0xDA,0x13,0xC7,0x0C, + 0xA5,0x00,0xF0,0x05,0xDC,0x0B,0xD7,0x02,0xCF,0xF1,0xD7,0xEF, + 0x63,0xF2,0x0A,0xF1,0xA6,0xF0,0xD4,0xEE,0x2D,0xEE,0x98,0xF2, + 0xBF,0xFC,0x16,0x03,0xE9,0xFE,0x2D,0x02,0x2C,0x0C,0xB9,0x11, + 0x88,0x12,0xB4,0x0D,0x8C,0x0F,0x20,0x12,0xA4,0x0E,0xAE,0x08, + 0xF3,0x01,0x1E,0xFF,0x86,0xFE,0xC9,0xFA,0x96,0xF5,0x50,0xF5, + 0xC9,0xF6,0x5A,0xF9,0x83,0xFC,0xE9,0xFC,0x3B,0xFF,0x16,0x03, + 0x0A,0x06,0x88,0x06,0x66,0x03,0x94,0x02,0x60,0x03,0x02,0x02, + 0x0F,0xFF,0xEA,0xF9,0x26,0xFA,0x9A,0xFE,0x81,0xFD,0xF3,0xF9, + 0x26,0xFA,0x24,0xFD,0x73,0xFE,0xB3,0xFE,0xF5,0xFF,0xD0,0xFF, + 0x92,0x01,0x80,0x01,0x35,0x02,0x9E,0x06,0x65,0x11,0xB6,0x19, + 0xFF,0x04,0x9B,0x01,0xF2,0x0A,0x06,0xFF,0xD0,0xF5,0x1D,0xE9, + 0x04,0xE7,0xDA,0xE9,0xCE,0xEB,0xD0,0xF3,0xFC,0xEC,0xF5,0xEF, + 0xB4,0x00,0x2A,0x05,0x18,0x07,0x49,0x06,0xB6,0x0B,0x56,0x12, + 0x14,0x14,0x0D,0x15,0x5A,0x0C,0x08,0x0A,0xCC,0x0E,0x92,0x09, + 0xC9,0xFC,0x8F,0xFA,0x25,0xFC,0x5E,0xF9,0x2D,0xF9,0xB5,0xF7, + 0x87,0xF6,0x13,0xF9,0x79,0xFF,0xFF,0x01,0xCE,0xFD,0x8E,0xFF, + 0xF7,0x06,0x8E,0x07,0x0C,0x03,0x02,0x01,0xEA,0x00,0x38,0x01, + 0xA4,0xFF,0xBD,0xFC,0xC7,0xFA,0xB6,0xF9,0xC6,0xFA,0x71,0xFD, + 0xE7,0xFE,0x5B,0xFC,0x45,0xFC,0xCA,0x01,0xAC,0x04,0x89,0x00, + 0x97,0x00,0x28,0x02,0xD1,0x02,0xC9,0xF9,0xE1,0x0B,0xA3,0x2E, + 0xD6,0xFF,0xD3,0xF5,0x3A,0x18,0x25,0x04,0x36,0xFA,0x30,0xEB, + 0x8C,0xE6,0x4C,0xEB,0x27,0xE6,0xAA,0xF6,0xC1,0xEC,0x33,0xE1, + 0x55,0x00,0xC1,0x05,0xE4,0x00,0x31,0x04,0xB3,0x07,0x82,0x15, + 0x14,0x15,0xE6,0x12,0x9E,0x0F,0x88,0x09,0x42,0x0F,0x0A,0x0F, + 0xD1,0xFE,0x90,0xFA,0xC6,0xFB,0xE8,0xFA,0xB0,0xFA,0xD7,0xF4, + 0x7E,0xF4,0xC3,0xF8,0x33,0xFF,0x6A,0x01,0xFC,0xFC,0x29,0x00, + 0x58,0x08,0xA3,0x07,0x7E,0x04,0x20,0x03,0x12,0x00,0xC2,0x01, + 0x58,0x03,0x96,0xFC,0x16,0xF8,0x8A,0xFA,0xD8,0xFE,0x4B,0xFA, + 0xAF,0xF5,0x2A,0xFC,0xC1,0xFF,0x8C,0xFF,0x1E,0x01,0x3A,0x02, + 0xBD,0x02,0xE9,0x04,0xB7,0x03,0x94,0xFF,0xB3,0xF7,0xF4,0x1B, + 0x98,0x2B,0x41,0xEE,0x4D,0x02,0x85,0x19,0x0C,0xFA,0x07,0xFB, + 0x0C,0xE9,0x48,0xE3,0xA5,0xED,0xC7,0xF0,0xDF,0xF4,0x70,0xE4, + 0xF8,0xE9,0xBF,0x07,0x60,0x01,0xA0,0xFD,0xF5,0x06,0x7A,0x07, + 0x65,0x13,0xA2,0x19,0x0D,0x0E,0x6C,0x08,0xCC,0x0E,0x1F,0x11, + 0xF4,0x08,0xEC,0xF8,0x86,0xFF,0x3E,0xFF,0xA6,0xF7,0xCD,0xFC, + 0x68,0xF4,0x1A,0xF2,0x0F,0xFE,0x51,0x02,0xB9,0xFB,0xF3,0xFC, + 0xBE,0x03,0xDE,0x09,0x69,0x05,0xDB,0x01,0x57,0x02,0x3C,0x00, + 0x6F,0x04,0x5A,0x01,0x04,0xF9,0x38,0xFA,0xE8,0xFF,0x73,0xFC, + 0xF4,0xF7,0x80,0xF8,0x61,0xFB,0x2B,0xFF,0x4B,0x01,0x59,0xFF, + 0x7F,0xFF,0x0A,0x04,0x40,0x07,0x18,0x03,0xEA,0xFD,0xFA,0xFF, + 0x02,0x13,0x9A,0x21,0xE0,0xFC,0x8A,0xFB,0xBC,0x15,0xCC,0xFE, + 0x95,0xF7,0xA5,0xF2,0x2D,0xE6,0x6D,0xEF,0xF7,0xF7,0xF4,0xEE, + 0xC5,0xEA,0x09,0xF2,0x3E,0xF9,0x7C,0x02,0x27,0xFE,0xF7,0xFD, + 0xA6,0x07,0x49,0x0E,0xF3,0x12,0x6D,0x0E,0xB8,0x07,0x8A,0x0E, + 0x63,0x11,0xF9,0x06,0x0E,0x02,0x14,0x00,0x65,0xFE,0x18,0x00, + 0x31,0xFE,0x32,0xF5,0x8D,0xF6,0x92,0xFD,0xFB,0xFE,0x68,0xFC, + 0xB6,0xFA,0x48,0x01,0x37,0x04,0xB2,0x02,0xC0,0x01,0x32,0x00, + 0x87,0xFF,0x5B,0x04,0x09,0x03,0xB3,0xFB,0xAA,0xFD,0x7E,0x00, + 0xFD,0xFE,0x2B,0xFC,0x21,0xFB,0x45,0xFA,0x5C,0xFC,0x26,0x01, + 0xF9,0xFF,0x81,0xFC,0x67,0x00,0x89,0x05,0xDB,0x01,0x54,0x01, + 0x33,0x01,0x04,0xFE,0x1F,0x03,0xDE,0x0E,0xE0,0x0F,0x43,0xFD, + 0x5A,0x01,0x46,0x10,0x30,0xFF,0xAB,0xF6,0x16,0xFC,0x65,0xF4, + 0x39,0xF2,0xA0,0xFC,0x37,0xF8,0x8B,0xED,0x66,0xF7,0xFD,0xFC, + 0xCF,0xF7,0x43,0xFB,0x6A,0x00,0x01,0x00,0x61,0x03,0xAD,0x09, + 0x4C,0x07,0x40,0x06,0x8E,0x0A,0xAE,0x09,0xFF,0x06,0x02,0x07, + 0x3B,0x06,0xB1,0x03,0x5B,0x02,0xFD,0x01,0x0C,0x00,0x7C,0xFE, + 0x26,0xFF,0x9C,0xFE,0x49,0xFD,0xEA,0xFD,0xBB,0xFE,0xD3,0xFD, + 0xEB,0xFC,0xBF,0xFD,0x51,0xFE,0xDF,0xFD,0x2F,0xFE,0xEE,0xFE, + 0xBA,0xFE,0x4D,0xFF,0x10,0x00,0x2C,0xFF,0xB7,0xFE,0x68,0xFF, + 0x59,0xFF,0x6B,0xFE,0xCE,0xFE,0x39,0xFF,0x0C,0xFF,0x07,0x00, + 0x70,0x00,0xB7,0xFF,0xE7,0xFF,0x28,0x00,0x47,0xFF,0xA7,0xFF, + 0xE3,0x02,0x47,0x07,0x3B,0x07,0x09,0x07,0xC9,0x08,0x2C,0x05, + 0x53,0x02,0x03,0x02,0xF7,0xFF,0xE5,0xFC,0x97,0xFC,0x2A,0xFC, + 0x15,0xF8,0x96,0xF6,0x8E,0xF5,0xE0,0xF4,0x21,0xF6,0xB1,0xF7, + 0x38,0xF8,0x34,0xF9,0xAD,0xFC,0x82,0xFE,0xDE,0x00,0x7B,0x04, + 0xC8,0x05,0x83,0x06,0x49,0x09,0xA3,0x0A,0x43,0x09,0x69,0x09, + 0x67,0x09,0x8C,0x07,0x92,0x06,0x21,0x06,0xFF,0x03,0x02,0x02, + 0x5A,0x01,0xBA,0xFF,0x6C,0xFD,0x51,0xFC,0x46,0xFB,0x13,0xFA, + 0x2F,0xFA,0xCD,0xFA,0x30,0xFB,0x89,0xFB,0xE7,0xFB,0x2C,0xFC, + 0xF5,0xFC,0xAE,0xFD,0x05,0xFE,0x5B,0xFE,0xD9,0xFE,0xE7,0xFF, + 0xAC,0x00,0x2D,0x01,0x3D,0x01,0x71,0x01,0x73,0x01,0x25,0x01, + 0x03,0x01,0xB0,0x00,0x25,0x04,0x59,0x08,0x57,0x07,0x45,0x07, + 0x44,0x08,0x86,0x04,0xA6,0x00,0xF9,0x00,0xED,0xFF,0xB9,0xFB, + 0x36,0xFB,0xE2,0xFA,0x94,0xF7,0x7B,0xF5,0x2D,0xF5,0x65,0xF5, + 0x1D,0xF6,0x09,0xF8,0x08,0xF9,0xB6,0xFA,0xE3,0xFC,0x06,0xFF, + 0x99,0x02,0x54,0x05,0x0F,0x06,0x8E,0x07,0x74,0x0A,0x71,0x0A, + 0x85,0x09,0xBF,0x09,0x7D,0x08,0x7B,0x06,0x4C,0x06,0xB8,0x05, + 0x0C,0x03,0x9B,0x01,0xB0,0x00,0xC9,0xFE,0x11,0xFD,0xD1,0xFB, + 0x5E,0xFA,0xFF,0xF9,0xB4,0xFA,0xEF,0xFA,0x29,0xFB,0x7A,0xFB, + 0xAD,0xFB,0x5D,0xFC,0x5A,0xFD,0x6E,0xFD,0xB5,0xFD,0xC5,0xFE, + 0xA4,0xFF,0x65,0x00,0x4E,0x01,0x94,0x01,0x87,0x01,0xEA,0x01, + 0xD5,0x01,0x4B,0x01,0x86,0x00,0xD7,0x03,0x99,0x08,0x29,0x07, + 0x06,0x07,0xB3,0x08,0x0E,0x05,0xA5,0x00,0x86,0x00,0x23,0x00, + 0xD4,0xFB,0xE3,0xFA,0xE3,0xFA,0xD6,0xF7,0xC8,0xF5,0x13,0xF5, + 0x52,0xF5,0x05,0xF6,0xCF,0xF7,0xE5,0xF8,0xAA,0xFA,0xDF,0xFC, + 0x88,0xFE,0x34,0x02,0x5E,0x05,0x04,0x06,0x97,0x07,0xAB,0x0A, + 0x92,0x0A,0xA8,0x09,0x04,0x0A,0x87,0x08,0x35,0x06,0x34,0x06, + 0xC1,0x05,0x03,0x03,0x6C,0x01,0x8A,0x00,0xCE,0xFE,0x04,0xFD, + 0xEA,0xFB,0x84,0xFA,0x0D,0xFA,0x9D,0xFA,0x0D,0xFB,0x65,0xFB, + 0x64,0xFB,0xB2,0xFB,0x6D,0xFC,0x79,0xFD,0x62,0xFD,0xD0,0xFD, + 0x27,0xFF,0xD4,0xFF,0x5F,0x00,0x7B,0x01,0xDA,0x01,0x21,0x01, + 0xA8,0x01,0xF5,0x01,0xAF,0x00,0xDD,0x01,0xE2,0x07,0x22,0x08, + 0xFA,0x05,0x4B,0x09,0x27,0x07,0x7D,0x01,0x4F,0x00,0xE6,0x00, + 0xF0,0xFC,0xAB,0xFA,0x98,0xFB,0x43,0xF8,0xE6,0xF5,0x6B,0xF5, + 0xE6,0xF4,0x2C,0xF5,0x38,0xF7,0x7E,0xF8,0x78,0xF9,0x6B,0xFC, + 0xFF,0xFD,0x97,0x00,0xA2,0x04,0x3D,0x06,0x25,0x07,0x32,0x0A, + 0x34,0x0B,0xFC,0x09,0x3E,0x0A,0xA2,0x09,0xFB,0x06,0x3F,0x06, + 0x62,0x06,0xB3,0x03,0x9E,0x01,0x03,0x01,0x44,0xFF,0x14,0xFD, + 0x60,0xFC,0x0A,0xFB,0xB9,0xF9,0x63,0xFA,0x06,0xFB,0x1E,0xFB, + 0x32,0xFB,0xB2,0xFB,0xFC,0xFB,0xE4,0xFC,0x31,0xFD,0x96,0xFD, + 0xF3,0xFE,0x86,0xFF,0x47,0x00,0x70,0x01,0xF2,0x01,0x1B,0x01, + 0x81,0x01,0xC7,0x01,0xA2,0x00,0x6D,0x04,0x27,0x09,0xEB,0x06, + 0x18,0x07,0x13,0x0A,0xAA,0x05,0x79,0x00,0x30,0x01,0x0D,0x00, + 0x39,0xFB,0x55,0xFB,0x11,0xFB,0x9B,0xF6,0x0C,0xF5,0x6B,0xF5, + 0x99,0xF4,0x04,0xF5,0x94,0xF7,0x56,0xF8,0xFD,0xF9,0xF7,0xFC, + 0xC7,0xFE,0xD6,0x01,0x27,0x05,0x92,0x06,0x5C,0x08,0x2B,0x0B, + 0x0C,0x0B,0x3A,0x0A,0xA4,0x0A,0x23,0x09,0xCE,0x06,0xA4,0x06, + 0xA4,0x05,0xA0,0x02,0x8C,0x01,0xBE,0x00,0x49,0xFE,0xA6,0xFC, + 0x19,0xFC,0x62,0xFA,0x99,0xF9,0x93,0xFA,0xC5,0xFA,0xBA,0xFA, + 0x4B,0xFB,0xC2,0xFB,0x0D,0xFC,0xCE,0xFC,0x4D,0xFD,0x34,0xFE, + 0x4D,0xFF,0xB7,0xFF,0xD0,0x00,0xF8,0x01,0xBC,0x01,0x37,0x01, + 0xA0,0x01,0x44,0x01,0x51,0x04,0xF4,0x08,0x51,0x07,0x69,0x07, + 0xB6,0x09,0x7A,0x06,0x60,0x01,0x12,0x01,0x34,0x00,0x64,0xFB, + 0x35,0xFB,0x07,0xFB,0xEC,0xF6,0x98,0xF4,0x26,0xF5,0xDC,0xF4, + 0x94,0xF4,0xFC,0xF6,0x3F,0xF8,0x9F,0xF9,0x66,0xFC,0xF2,0xFE, + 0xC4,0x01,0xB5,0x04,0xD9,0x06,0xB3,0x08,0xF1,0x0A,0x52,0x0B, + 0x98,0x0A,0x7C,0x0A,0x53,0x09,0x64,0x07,0x8D,0x06,0x54,0x05, + 0xDC,0x02,0x4D,0x01,0x4F,0x00,0x55,0xFE,0xB1,0xFC,0xF6,0xFB, + 0xB1,0xFA,0xFD,0xF9,0x8B,0xFA,0xD2,0xFA,0xD5,0xFA,0x69,0xFB, + 0xDE,0xFB,0xFC,0xFB,0xC5,0xFC,0xA9,0xFD,0x79,0xFE,0x25,0xFF, + 0xD3,0xFF,0xDD,0x00,0x81,0x01,0x70,0x01,0xD7,0x00,0xDE,0x00, + 0x6C,0x04,0xAC,0x08,0x3A,0x07,0xF2,0x07,0x78,0x0A,0xC6,0x06, + 0xB5,0x02,0xF7,0x01,0x60,0x00,0xE0,0xFB,0x84,0xFB,0x0C,0xFB, + 0xED,0xF6,0xF9,0xF4,0x79,0xF4,0x73,0xF4,0x88,0xF4,0x3D,0xF6, + 0x73,0xF7,0x39,0xF9,0xF5,0xFB,0xE4,0xFD,0x83,0x01,0x96,0x04, + 0x64,0x06,0x86,0x08,0x3F,0x0B,0xAD,0x0B,0xB0,0x0A,0x26,0x0B, + 0xD4,0x09,0xA4,0x07,0xE9,0x06,0xE8,0x05,0x19,0x03,0x47,0x01, + 0x93,0x00,0x5B,0xFE,0xD6,0xFC,0x10,0xFC,0xBD,0xFA,0xF9,0xF9, + 0x75,0xFA,0xC0,0xFA,0xA8,0xFA,0x6E,0xFB,0x9C,0xFB,0xCD,0xFB, + 0xE0,0xFC,0xB5,0xFD,0x46,0xFE,0x08,0xFF,0x0F,0x00,0xA1,0x00, + 0x51,0x01,0x51,0x01,0x31,0x00,0x29,0x02,0xA9,0x07,0x13,0x08, + 0xA7,0x06,0x97,0x0A,0xA6,0x09,0x52,0x04,0xE4,0x02,0x07,0x02, + 0x92,0xFD,0x68,0xFB,0xEC,0xFB,0x39,0xF8,0x5D,0xF5,0xB2,0xF4, + 0x2D,0xF4,0x37,0xF4,0xE3,0xF4,0x0D,0xF6,0xF0,0xF7,0x1F,0xFC, + 0x29,0xFD,0x45,0xFE,0xBA,0x03,0xC9,0x04,0x7B,0x05,0xB8,0x0C, + 0x65,0x0D,0x22,0x08,0x96,0x0C,0xBE,0x0D,0x56,0x07,0x3A,0x08, + 0xC1,0x07,0x64,0x01,0x78,0x02,0xB3,0x03,0x29,0xFB,0x27,0xFB, + 0x5F,0xFE,0x00,0xF9,0xA9,0xF9,0xF3,0xFB,0x3E,0xF8,0xD7,0xF9, + 0x85,0xFE,0x89,0xFA,0x4B,0xFA,0x0D,0xFF,0x78,0xFD,0xB2,0xFE, + 0x49,0x00,0x01,0xFF,0x74,0x00,0x72,0x02,0x89,0xFC,0x1A,0x02, + 0xF6,0x19,0x59,0x08,0x0B,0xFA,0xDE,0x19,0x57,0x0F,0x60,0xFB, + 0x82,0x08,0xAD,0xFB,0xC3,0xEC,0x22,0xFF,0x59,0xF9,0xA3,0xE3, + 0x2B,0xF1,0xC7,0xF3,0x2F,0xEE,0xEB,0xF5,0x42,0xF3,0x46,0xF5, + 0xF8,0x00,0x72,0x05,0x85,0x04,0x2C,0x07,0x00,0x0C,0x40,0x15, + 0xD3,0x13,0x1B,0x0C,0x9A,0x0F,0xB2,0x0E,0x49,0x0B,0xE4,0x08, + 0x76,0xFF,0x89,0xFA,0x0F,0xFE,0xC1,0xFA,0xF4,0xF3,0x40,0xF4, + 0xF3,0xF6,0x9A,0xF8,0x4B,0xFA,0xE1,0xF9,0x4F,0xFA,0x7B,0xFE, + 0x36,0x03,0x5A,0x02,0xE1,0xFE,0x95,0x01,0xF0,0x04,0x2B,0x05, + 0xAC,0x01,0x6B,0x00,0x82,0x00,0xE8,0x00,0xAD,0x02,0x55,0xFD, + 0xAB,0xFB,0xD2,0xF6,0x2D,0x0B,0x35,0x25,0x05,0xF8,0xB9,0xFA, + 0xC2,0x24,0xA6,0x04,0x37,0xFF,0x2F,0x00,0x3E,0xE9,0x01,0xF7, + 0x81,0xFB,0xCC,0xE8,0xBD,0xE3,0x86,0xEA,0x1A,0xF7,0xD0,0xF5, + 0x8A,0xEA,0x35,0xF9,0x12,0x01,0x62,0x05,0x86,0x11,0x98,0x06, + 0xC8,0x08,0x33,0x1D,0x11,0x1A,0x17,0x0F,0x9E,0x0B,0x97,0x0E, + 0x5C,0x0F,0x7E,0x04,0xC2,0xFD,0xEA,0xF6,0xD9,0xF6,0x30,0xFC, + 0x5F,0xF3,0xC5,0xEA,0x1F,0xF6,0xD8,0xFC,0xFA,0xF9,0x4B,0xFB, + 0xCA,0xFB,0x6C,0x02,0x1D,0x06,0xCA,0x06,0xD2,0x01,0xD3,0x00, + 0x9B,0x07,0x9E,0x06,0x81,0xFF,0x76,0xFC,0x4A,0x00,0xE7,0xFE, + 0x8B,0xFD,0x0F,0xFD,0xAD,0xFA,0xBF,0xFD,0x98,0xF8,0xD1,0x04, + 0xD8,0x26,0xBE,0x01,0x99,0xF8,0x66,0x24,0x66,0x0A,0x80,0x01, + 0x71,0xFC,0xE1,0xED,0x4F,0xF8,0xCC,0xEF,0x7F,0xEC,0x61,0xE5, + 0x72,0xE1,0x14,0xF9,0xBD,0xF3,0x05,0xEA,0xF4,0xFB,0x3D,0xFF, + 0xA3,0x09,0x0B,0x10,0x8B,0x09,0x79,0x10,0x05,0x19,0xBA,0x1C, + 0xC5,0x14,0xDF,0x07,0xBC,0x0F,0x70,0x0D,0x50,0x00,0x56,0xFD, + 0xDD,0xF2,0xC8,0xF5,0xA1,0xF7,0xAE,0xF0,0x8E,0xEE,0xD3,0xF2, + 0xAB,0xFC,0xAD,0xFE,0x92,0xFA,0xBD,0xFF,0xF0,0x05,0x4E,0x06, + 0x7D,0x09,0xA8,0x03,0xD2,0x02,0x1B,0x06,0xDC,0x04,0x5D,0x01, + 0xAD,0xFA,0xDC,0xFC,0xBF,0xFE,0xFD,0xFB,0x84,0xFC,0x2C,0xFA, + 0x13,0xFB,0x5B,0xF6,0xD9,0x10,0x97,0x29,0x9E,0xF5,0xE3,0x01, + 0xE9,0x24,0x55,0x08,0x11,0x02,0x18,0xF3,0x86,0xF1,0x3A,0xF5, + 0xD5,0xEC,0xE4,0xEF,0xDA,0xDB,0xDC,0xE3,0xF1,0xFE,0x22,0xEF, + 0x28,0xEE,0x2C,0xFB,0x5F,0x03,0xB0,0x10,0xA6,0x0C,0xE4,0x0E, + 0x7E,0x12,0xA5,0x18,0x27,0x22,0xD4,0x0F,0x83,0x06,0x6C,0x0F, + 0x2D,0x08,0x5D,0x01,0x20,0xF6,0x8C,0xF0,0x33,0xF6,0x0B,0xF3, + 0x9D,0xF3,0x20,0xED,0x81,0xF2,0x43,0x01,0x04,0xFF,0x00,0xFE, + 0x6D,0x01,0x31,0x06,0x00,0x0B,0x71,0x08,0x09,0x05,0xDB,0x02, + 0xCE,0x02,0x29,0x07,0xF1,0xFF,0x09,0xF8,0x97,0xFB,0x41,0xFC, + 0x5A,0xFD,0x7B,0xFA,0x92,0xF8,0xB4,0xFA,0xD9,0xF4,0x06,0x1E, + 0x54,0x26,0x6B,0xEE,0x8B,0x0C,0x81,0x21,0xC3,0x0A,0x1B,0x00, + 0x5A,0xEC,0x40,0xF7,0xBD,0xEF,0x72,0xED,0x21,0xF0,0x25,0xD4, + 0xE0,0xE8,0x94,0xFD,0x86,0xEF,0x37,0xF1,0xAB,0xF6,0x7F,0x0A, + 0x6C,0x12,0x48,0x0C,0xD6,0x13,0x89,0x10,0xED,0x1A,0x75,0x23, + 0xD1,0x0D,0xBD,0x06,0xD2,0x0C,0xF8,0x07,0xAC,0xFF,0xE0,0xF2, + 0x85,0xF1,0x8A,0xF2,0xEC,0xF2,0xB7,0xF4,0xA6,0xEB,0x7E,0xF3, + 0x27,0x01,0xE4,0x01,0x29,0xFF,0xE3,0x00,0xCF,0x08,0x00,0x0B, + 0xBF,0x08,0xC4,0x06,0x09,0x02,0x7F,0x02,0x1E,0x06,0x4B,0xFF, + 0x70,0xF7,0xB8,0xF9,0xBC,0xFC,0xBA,0xFA,0xFF,0xF9,0x64,0xFA, + 0x66,0xFB,0x7F,0xF5,0x96,0x0A,0x0F,0x2F,0x59,0x05,0x51,0xF8, + 0x87,0x1F,0x51,0x14,0x9D,0x07,0xC6,0xF0,0x5F,0xF0,0xA9,0xF5, + 0x32,0xE7,0xC9,0xF3,0xFB,0xDF,0xE2,0xD8,0x1A,0xF5,0x68,0xF6, + 0xE2,0xF5,0x05,0xF1,0x21,0xFF,0x34,0x15,0xBC,0x0E,0x7B,0x13, + 0xB3,0x13,0x0C,0x14,0x21,0x20,0xEE,0x19,0xDA,0x0B,0xB6,0x05, + 0x63,0x07,0xCE,0x05,0x5E,0xF7,0x4A,0xF1,0x2A,0xF0,0x05,0xEF, + 0xDD,0xF5,0x06,0xF2,0xD4,0xEF,0x9A,0xF7,0x7F,0x02,0x3D,0x05, + 0xE5,0xFF,0xCB,0x04,0xCA,0x09,0x6B,0x0A,0xC6,0x09,0xB5,0x04, + 0x11,0x02,0xB3,0x02,0x03,0x02,0x84,0xFC,0xFF,0xF6,0xD0,0xF8, + 0xBE,0xFA,0xE0,0xF8,0xDD,0xFB,0x87,0xFA,0x0D,0xFC,0x87,0xFB, + 0x24,0xFF,0x40,0x2B,0x6F,0x19,0x10,0xF5,0xCF,0x15,0x8E,0x16, + 0xEA,0x0E,0x9E,0xF6,0xAE,0xEB,0xF8,0xF7,0x1F,0xE2,0x98,0xF2, + 0xA6,0xEC,0x53,0xD4,0x48,0xE9,0x68,0xF5,0x33,0xFE,0xD8,0xF2, + 0xFC,0xF4,0x33,0x13,0x67,0x0F,0x99,0x14,0x1B,0x19,0xA4,0x10, + 0x1A,0x1A,0x57,0x1A,0xEA,0x16,0xDB,0x06,0x28,0xFD,0x69,0x0A, + 0x57,0xFC,0xDA,0xF1,0x02,0xF3,0xC7,0xEB,0x5D,0xF2,0x20,0xF3, + 0x2F,0xF6,0x2C,0xF5,0x06,0xF7,0xB6,0x08,0x04,0x05,0x27,0x03, + 0x3D,0x07,0x9B,0x07,0x39,0x0C,0x5C,0x07,0x26,0x05,0x21,0x01, + 0xEF,0xFE,0x57,0x02,0x5D,0xF9,0xCC,0xF5,0xD3,0xF8,0x2D,0xF8, + 0x9F,0xFA,0x2A,0xFA,0xF8,0xFC,0x3A,0xFE,0xE9,0xFD,0x5A,0xFD, + 0x68,0x0D,0xD6,0x2B,0x7C,0x0C,0x2B,0xFE,0xB6,0x17,0x76,0x0F, + 0x26,0x09,0xAE,0xF2,0x47,0xEE,0xA9,0xED,0xA8,0xE4,0x90,0xF6, + 0xC9,0xE3,0x6A,0xD9,0xFD,0xEC,0xC0,0xF7,0x1A,0xFF,0x9F,0xF4, + 0x29,0xFF,0xC0,0x0F,0x2D,0x10,0xC6,0x1B,0x76,0x17,0x76,0x11, + 0xA4,0x17,0xA6,0x18,0xC5,0x14,0xE0,0x03,0xE7,0xFC,0xAA,0x03, + 0xD8,0xF9,0x8A,0xF4,0xBD,0xF0,0x5A,0xEB,0x06,0xF2,0x49,0xF4, + 0xBD,0xF8,0x14,0xF7,0xE8,0xF9,0x50,0x06,0x13,0x07,0x7B,0x07, + 0x52,0x06,0x93,0x06,0x5B,0x0A,0x85,0x08,0xB3,0x05,0x05,0x00, + 0xF9,0xFD,0x39,0x00,0x2A,0xFB,0x5E,0xF6,0xAF,0xF5,0x8E,0xF7, + 0x8B,0xFA,0x60,0xFA,0x88,0xFC,0x89,0xFE,0xDB,0xFE,0x57,0x04, + 0x44,0xFE,0x42,0x0A,0x91,0x29,0x5E,0x11,0x38,0x01,0x05,0x0E, + 0xE8,0x0D,0xC8,0x0B,0x5D,0xF1,0x35,0xF0,0x5F,0xED,0x73,0xE2, + 0xBD,0xF4,0x91,0xE9,0x64,0xE0,0xBA,0xE5,0x2F,0xF4,0xFA,0x05, + 0x9B,0xF7,0x29,0xFE,0xB7,0x0C,0x67,0x0F,0xB6,0x1B,0x5A,0x18, + 0x1C,0x16,0xC3,0x11,0xC0,0x12,0x8D,0x18,0x87,0x06,0x9C,0xFC, + 0x80,0xFC,0x62,0xFB,0x0F,0xF9,0x2A,0xEF,0x95,0xEF,0xC1,0xEF, + 0x31,0xF2,0x6F,0xFB,0xD4,0xF8,0xAE,0xFB,0xA8,0x00,0xDD,0x05, + 0xDD,0x0A,0x05,0x06,0xAE,0x07,0x3F,0x07,0x30,0x07,0x20,0x08, + 0xEF,0x01,0xCB,0xFF,0xD1,0xFC,0x60,0xFC,0xAD,0xFB,0x07,0xF6, + 0xED,0xF5,0xE2,0xF7,0x49,0xFA,0xDE,0xFB,0x80,0xFC,0xBA,0xFE, + 0xFF,0x00,0xA2,0x01,0xA7,0x04,0xE7,0x01,0x8D,0x04,0xA3,0x23, + 0xE3,0x18,0xD0,0xFF,0xB6,0x09,0x3C,0x08,0x32,0x0B,0xA6,0xF8, + 0xC2,0xEF,0x47,0xF0,0xD9,0xE0,0x46,0xF3,0x46,0xF1,0x92,0xE4, + 0xF0,0xE6,0x18,0xEE,0x9E,0x03,0xD6,0xFD,0xD1,0xFE,0x92,0x0A, + 0xA8,0x09,0x31,0x17,0x60,0x1A,0x32,0x18,0x58,0x11,0xFC,0x0B, + 0xC1,0x15,0x44,0x0C,0x03,0x00,0x60,0xFC,0x8C,0xF6,0x8D,0xF9, + 0x3E,0xF6,0x49,0xF2,0x19,0xF1,0x7A,0xEE,0x3A,0xFA,0x36,0xFD, + 0xA8,0xFC,0x47,0xFF,0x31,0x00,0xF3,0x09,0x16,0x09,0xE6,0x07, + 0x94,0x06,0x7F,0x02,0x2A,0x07,0xCA,0x04,0x79,0x01,0x2B,0xFD, + 0x5D,0xF9,0x1E,0xFD,0x44,0xFB,0x90,0xF9,0x40,0xF8,0x64,0xF5, + 0x01,0xFA,0x58,0xFE,0xDE,0xFF,0xEE,0xFD,0xE8,0xFD,0x91,0x03, + 0xFE,0x02,0x82,0x02,0x2A,0x07,0x57,0x01,0x13,0x06,0xE0,0x1F, + 0x6B,0x14,0xFA,0xFF,0x45,0x02,0xED,0x06,0xF6,0x09,0x4B,0xF5, + 0x18,0xF3,0xFB,0xEF,0x53,0xE4,0x15,0xF3,0xD5,0xF2,0x8A,0xEC, + 0x76,0xE5,0x02,0xF0,0x4C,0x05,0xA1,0xFE,0xA4,0x01,0x5A,0x08, + 0xDA,0x0A,0x19,0x13,0x0A,0x17,0xBB,0x1A,0x9C,0x0E,0x0C,0x09, + 0xC8,0x11,0x03,0x0C,0x7F,0x02,0xBF,0xFA,0xB0,0xF7,0xB8,0xF7, + 0x88,0xF5,0xFE,0xF8,0x59,0xF3,0x25,0xEF,0x2A,0xF8,0xFA,0xFD, + 0x67,0x01,0x64,0xFE,0x89,0x00,0x26,0x05,0xD8,0x05,0x49,0x0B, + 0x0B,0x08,0x43,0x02,0x06,0x01,0x4C,0x03,0x47,0x04,0x53,0xFD, + 0x28,0xFA,0xB7,0xF9,0x19,0xF9,0xF6,0xFB,0x80,0xFC,0x04,0xFA, + 0xA0,0xF8,0xC2,0xFB,0x96,0x00,0x03,0x00,0x24,0x00,0x2F,0x01, + 0xCF,0x00,0x7E,0x03,0xE0,0x04,0x1D,0x03,0xCC,0xFE,0x8F,0x00, + 0x27,0x01,0x29,0x0F,0x37,0x1B,0x73,0x04,0x2B,0xFF,0x8B,0x03, + 0x9A,0x09,0xB4,0x06,0x37,0xF4,0x83,0xF6,0xB1,0xEC,0x89,0xED, + 0xA9,0xF7,0xAC,0xF1,0x9F,0xEC,0xF2,0xE6,0x47,0xF7,0x4B,0x02, + 0x95,0xFD,0xEC,0x02,0x72,0x04,0x1B,0x0A,0x77,0x11,0xDB,0x16, + 0xAA,0x17,0x06,0x0B,0x3B,0x0B,0x80,0x10,0x49,0x0B,0x98,0x04, + 0xA4,0xFB,0x75,0xF9,0x72,0xF6,0xBE,0xF5,0xF4,0xFA,0x17,0xF5, + 0x01,0xF2,0xB9,0xF5,0x92,0xFD,0xA4,0x01,0xB9,0xFE,0x0D,0x02, + 0x5D,0x02,0x29,0x04,0xB1,0x08,0x1B,0x08,0x8D,0x04,0x90,0xFF, + 0x89,0x01,0xB8,0x02,0x67,0xFE,0x79,0xFC,0xB6,0xF9,0xB3,0xF8, + 0x3F,0xFA,0x0A,0xFC,0xC6,0xFC,0x4A,0xFA,0x7D,0xFC,0xBB,0xFF, + 0xE5,0x00,0xAD,0x01,0xC4,0x00,0xB1,0x01,0x0E,0x02,0xC2,0x03, + 0x5D,0x03,0xF2,0x00,0xC2,0x00,0x35,0x00,0xB1,0x00,0x4C,0xFC, + 0x25,0xFF,0x9B,0x13,0xAB,0x11,0x0A,0x01,0xCD,0x02,0x7E,0x06, + 0x15,0x09,0xFA,0xFF,0xFC,0xFB,0x87,0xF9,0x6D,0xEB,0xDE,0xF1, + 0x1F,0xF7,0x35,0xF3,0x2D,0xEB,0x56,0xEB,0xB0,0xF9,0xDE,0xF9, + 0x0B,0xFE,0xFB,0x04,0xC1,0x04,0x43,0x07,0x7A,0x0D,0x71,0x18, + 0x9A,0x14,0x5C,0x0C,0x8F,0x0E,0x77,0x0D,0xE9,0x09,0x9B,0x05, + 0xAD,0x01,0x3D,0xFB,0xA0,0xF3,0x9F,0xF7,0x61,0xF9,0xE9,0xF3, + 0x0D,0xF3,0x40,0xF7,0xD3,0xFC,0xA4,0xFB,0xF6,0xFF,0x0D,0x04, + 0x3F,0x01,0x9E,0x03,0xA6,0x06,0x54,0x08,0xF7,0x03,0x24,0x02, + 0xB9,0x03,0xCE,0xFF,0x6C,0xFE,0xC5,0xFD,0xFA,0xFB,0x88,0xF9, + 0x1C,0xF9,0xF2,0xFB,0xFD,0xFA,0x35,0xFB,0x82,0xFD,0x3B,0xFE, + 0xEC,0xFF,0x08,0x01,0xC0,0x02,0x02,0x02,0x41,0x01,0x31,0x03, + 0x9D,0x02,0x2A,0x03,0xD8,0x01,0x34,0x00,0x20,0x00,0xFA,0xFF, + 0x1B,0x00,0x7D,0xFD,0xD2,0xF8,0x4F,0x03,0xE2,0x15,0x79,0x0C, + 0x20,0x03,0x1C,0x03,0xB8,0x05,0xE5,0x07,0xE6,0xFF,0x0C,0x02, + 0x68,0xF5,0xC7,0xEB,0xE9,0xF2,0x44,0xF6,0x33,0xF5,0xD7,0xEA, + 0xDE,0xEF,0x4E,0xF6,0x8A,0xF7,0x49,0x01,0x97,0x05,0xFA,0x05, + 0xBD,0x04,0xF3,0x0C,0xF2,0x16,0xBE,0x12,0xDF,0x0F,0x5A,0x0E, + 0x92,0x0A,0xAC,0x07,0xE2,0x05,0x78,0x05,0x96,0xFB,0x5C,0xF4, + 0x17,0xF7,0x10,0xF7,0x7A,0xF6,0x87,0xF4,0xEB,0xF6,0x66,0xF8, + 0x9D,0xFA,0x00,0x02,0x8F,0x02,0x51,0x02,0x0F,0x02,0x33,0x05, + 0x5C,0x07,0x5C,0x05,0xE5,0x05,0x9B,0x02,0xAF,0xFF,0x03,0xFF, + 0xD7,0xFE,0xB8,0xFD,0xED,0xF9,0xCB,0xF9,0x84,0xF9,0xA1,0xF9, + 0x57,0xFC,0x26,0xFD,0x24,0xFE,0xE5,0xFD,0x43,0x00,0xED,0x02, + 0x1F,0x03,0x6D,0x04,0x71,0x02,0x01,0x02,0x41,0x02,0x05,0x02, + 0xEF,0x02,0x73,0x00,0x75,0xFF,0xC4,0xFE,0x18,0xFE,0xFA,0xFF, + 0x07,0xFC,0xAE,0xF9,0xBF,0x09,0x53,0x12,0x09,0x09,0x93,0x04, + 0x13,0x04,0x61,0x07,0xA8,0x02,0xD8,0x01,0xBF,0x01,0x62,0xF3, + 0xCD,0xEE,0xB1,0xF1,0xF7,0xF6,0xB2,0xF2,0x84,0xEE,0x5D,0xF4, + 0xDB,0xF3,0x03,0xF8,0xBD,0x00,0x5E,0x07,0x71,0x06,0xB4,0x04, + 0x11,0x0E,0x21,0x12,0xFD,0x10,0x01,0x11,0xE5,0x0E,0x15,0x0A, + 0x4B,0x04,0x0D,0x06,0xF9,0x04,0xB6,0xFC,0xAC,0xF8,0x2B,0xF7, + 0x4A,0xF6,0xD0,0xF4,0x2C,0xF7,0x0A,0xFA,0x8E,0xF6,0x5A,0xF8, + 0x36,0xFE,0xE6,0x02,0xFE,0x02,0x72,0x02,0x62,0x05,0x87,0x03, + 0x71,0x04,0xEB,0x06,0xDC,0x05,0xDD,0x01,0x26,0xFE,0x47,0xFF, + 0x90,0xFD,0x32,0xFC,0x02,0xFC,0xE5,0xF9,0x05,0xF9,0x27,0xF9, + 0xCA,0xFC,0x1B,0xFE,0xE2,0xFD,0xAC,0xFF,0x17,0x00,0x46,0x02, + 0x6B,0x03,0xA4,0x04,0xA5,0x04,0x23,0x02,0x59,0x02,0xBD,0x01, + 0xAE,0x01,0x3E,0x01,0xBD,0xFF,0x7C,0xFF,0x12,0xFE,0x94,0xFE, + 0x8C,0xFD,0x90,0xF9,0x34,0x03,0x84,0x0F,0x5D,0x0B,0x57,0x06, + 0xC0,0x03,0x36,0x05,0x4B,0x03,0xFD,0x00,0x1E,0x04,0xCE,0xF9, + 0xBF,0xF1,0x0B,0xF1,0x49,0xF5,0xE7,0xF5,0x92,0xF1,0xC8,0xF5, + 0x86,0xF4,0x1C,0xF5,0xAB,0xFB,0x90,0x03,0x15,0x07,0x69,0x04, + 0x9C,0x09,0x32,0x0D,0x7E,0x0D,0x9A,0x0F,0x2C,0x10,0x3E,0x0D, + 0xDF,0x05,0xD7,0x04,0x98,0x05,0x1F,0x01,0xEC,0xFD,0x4C,0xFB, + 0xAC,0xF8,0x14,0xF5,0xF0,0xF5,0x59,0xFA,0xE7,0xF8,0xA9,0xF8, + 0xCF,0xF9,0xAD,0xFC,0x58,0xFF,0xDA,0x01,0x9C,0x05,0xFA,0x02, + 0xBE,0x02,0xCC,0x03,0x17,0x05,0x01,0x05,0x9B,0x02,0x23,0x02, + 0x05,0xFE,0xFA,0xFC,0x82,0xFD,0xDD,0xFC,0x1C,0xFC,0x25,0xFA, + 0x22,0xFB,0x02,0xFB,0x74,0xFC,0x0A,0xFF,0x65,0xFF,0x75,0x00, + 0xA2,0x00,0x21,0x02,0x19,0x03,0x6B,0x03,0x0D,0x04,0xB0,0x02, + 0x28,0x02,0x49,0x01,0xAF,0x00,0xCE,0x00,0x45,0x00,0x5B,0x00, + 0x0A,0xFF,0xDD,0xFD,0x26,0xFA,0x16,0xFE,0x2B,0x0C,0x48,0x0C, + 0xB5,0x07,0x3A,0x04,0x4D,0x02,0x53,0x02,0xBA,0xFF,0x00,0x04, + 0x0A,0xFF,0x69,0xF6,0xCE,0xF2,0x61,0xF3,0x90,0xF6,0x9A,0xF4, + 0x07,0xF8,0x6A,0xF7,0xD1,0xF4,0xD5,0xF7,0x9C,0xFE,0x6D,0x05, + 0x2D,0x05,0x51,0x08,0x2B,0x0A,0x87,0x09,0xB3,0x0B,0x5D,0x0E, + 0xF0,0x0E,0x28,0x09,0xEC,0x05,0xC1,0x04,0xB1,0x01,0x18,0x00, + 0x3C,0xFF,0x1D,0xFD,0x04,0xF8,0x07,0xF6,0x81,0xF8,0x11,0xF9, + 0xE6,0xF9,0x1D,0xFB,0x69,0xFB,0xF4,0xFB,0x44,0xFE,0x62,0x02, + 0xFE,0x02,0xC4,0x02,0x1E,0x03,0x0F,0x03,0xD3,0x02,0xDD,0x02, + 0x87,0x03,0x55,0x01,0x24,0xFF,0x57,0xFE,0x7A,0xFD,0xF4,0xFC, + 0xF0,0xFC,0x54,0xFD,0x78,0xFC,0x13,0xFC,0x25,0xFD,0x29,0xFE, + 0x78,0xFF,0xAF,0x00,0x4E,0x01,0x39,0x01,0x82,0x01,0x34,0x02, + 0x7F,0x02,0xB9,0x02,0x4E,0x02,0x3C,0x01,0x2E,0x00,0x57,0x00, + 0xCF,0x00,0x87,0x00,0xD9,0xFF,0xA0,0xFC,0x0E,0xFB,0xDD,0x04, + 0xD4,0x0B,0x68,0x09,0xBC,0x06,0xC0,0x02,0x31,0x01,0x50,0xFE, + 0x3C,0x01,0xE6,0x02,0xA7,0xFB,0xA4,0xF6,0xAC,0xF3,0x6F,0xF5, + 0xF9,0xF4,0xC2,0xF7,0x78,0xFA,0x2A,0xF7,0xED,0xF6,0xE4,0xF9, + 0xF0,0x00,0xEB,0x03,0x43,0x07,0x38,0x0A,0x7E,0x08,0x7D,0x08, + 0x49,0x0A,0x65,0x0D,0x83,0x0B,0xCC,0x08,0xBB,0x06,0x8C,0x02, + 0xF5,0xFF,0x8E,0xFF,0xBA,0xFF,0x77,0xFC,0x26,0xF9,0x9B,0xF8, + 0xDE,0xF7,0xAA,0xF8,0x92,0xFA,0xC7,0xFC,0xF6,0xFD,0xD6,0xFC, + 0x1F,0xFE,0x3C,0xFF,0xE1,0x00,0xA2,0x02,0x58,0x03,0x3F,0x03, + 0x2F,0x01,0x56,0x01,0x16,0x01,0x43,0x01,0x03,0x01,0xB9,0xFF, + 0x8F,0xFE,0x24,0xFD,0xBC,0xFD,0x0F,0xFE,0xB7,0xFE,0xB1,0xFE, + 0x26,0xFE,0x3B,0xFE,0xD4,0xFE,0x29,0x00,0xC2,0x00,0x90,0x01, + 0x41,0x01,0xA1,0x00,0x7F,0x00,0xCF,0x00,0x4E,0x01,0x3C,0x01, + 0x67,0x01,0xCB,0x00,0xD7,0xFF,0xAF,0xFE,0x8E,0xFC,0x04,0x01, + 0xCD,0x09,0xDA,0x09,0xA7,0x07,0x73,0x04,0xB6,0x01,0xA6,0xFF, + 0x12,0xFF,0xB0,0x02,0xA4,0xFE,0xCA,0xF9,0x0F,0xF6,0x2F,0xF5, + 0x66,0xF5,0xDE,0xF5,0x06,0xFA,0x9E,0xF8,0xDA,0xF7,0xF3,0xF8, + 0x54,0xFD,0x98,0x01,0x86,0x04,0x2D,0x09,0xC1,0x08,0x43,0x08, + 0x93,0x08,0xBE,0x0A,0x46,0x0B,0xB4,0x09,0xF6,0x08,0xFF,0x04, + 0xB7,0x01,0xC4,0xFF,0xA3,0xFF,0x3C,0xFE,0xC5,0xFB,0xD3,0xFA, + 0xE1,0xF8,0x63,0xF8,0x0F,0xF9,0xC2,0xFB,0x58,0xFE,0x24,0xFD, + 0x63,0xFD,0x8D,0xFD,0x61,0xFE,0x69,0x00,0x2E,0x02,0xA7,0x03, + 0xA5,0x01,0x11,0x01,0x84,0x00,0xA8,0x00,0x55,0x01,0x2A,0x01, + 0xE7,0x00,0xC1,0xFE,0x5F,0xFE,0x0E,0xFE,0xD1,0xFE,0x70,0xFF, + 0x50,0xFF,0x22,0xFF,0x50,0xFE,0x00,0xFF,0x4C,0xFF,0x8F,0x00, + 0x1C,0x01,0x94,0x00,0xFE,0xFF,0x81,0xFF,0x85,0x00,0xD3,0x00, + 0xC0,0x01,0x83,0x01,0x96,0xFF,0x0B,0xFD,0x1F,0xFF,0x84,0x08, + 0x1D,0x0A,0xB0,0x08,0x59,0x06,0xCE,0x01,0x62,0xFF,0xEC,0xFD, + 0x7B,0x02,0x27,0x00,0xC8,0xFB,0x63,0xF8,0x18,0xF5,0xD0,0xF4, + 0xCA,0xF4,0xF1,0xF9,0x68,0xF9,0x9E,0xF8,0x4D,0xF9,0x78,0xFB, + 0x6D,0xFF,0x7C,0x02,0x95,0x08,0x9A,0x08,0x35,0x08,0x00,0x08, + 0x08,0x09,0x26,0x0A,0xB1,0x09,0x8A,0x0A,0x8F,0x06,0x0D,0x03, + 0x5B,0x00,0xA6,0xFF,0x94,0xFE,0x2D,0xFD,0xB0,0xFC,0x42,0xFA, + 0xC1,0xF8,0x16,0xF9,0x30,0xFC,0x84,0xFC,0x70,0xFC,0x32,0xFD, + 0xAE,0xFC,0x38,0xFD,0xDB,0xFE,0xBD,0x01,0xFC,0x01,0x93,0x01, + 0x77,0x01,0x96,0x00,0xA7,0x00,0x35,0x01,0x44,0x02,0x68,0x01, + 0x6A,0x00,0xBB,0xFF,0xCC,0xFE,0x26,0xFF,0x7D,0xFF,0xFD,0xFF, + 0x1C,0xFF,0xAE,0xFE,0x9A,0xFE,0x55,0xFE,0x52,0xFF,0xF1,0xFF, + 0x2D,0x00,0x92,0xFF,0xF8,0xFF,0x2C,0x00,0x40,0x00,0xAA,0x00, + 0x09,0x00,0x45,0xFE,0x45,0x02,0x63,0x09,0xF7,0x08,0xD5,0x07, + 0xF7,0x04,0x80,0x02,0x72,0xFF,0x6F,0xFF,0x45,0x02,0xA3,0xFE, + 0xB1,0xFB,0xED,0xF7,0x98,0xF6,0xA7,0xF4,0x2E,0xF6,0x98,0xF9, + 0x9D,0xF8,0x34,0xF9,0x84,0xF9,0xF1,0xFC,0xE6,0xFE,0x7E,0x03, + 0x6B,0x07,0x8E,0x07,0x0A,0x08,0xE3,0x07,0xB6,0x09,0x23,0x09, + 0x3B,0x0A,0x39,0x09,0x01,0x06,0x02,0x03,0xC6,0x00,0x32,0x00, + 0x27,0xFE,0xCC,0xFD,0x3B,0xFC,0x50,0xFA,0x1B,0xFA,0x28,0xFB, + 0x3E,0xFB,0x85,0xFB,0x48,0xFC,0x4B,0xFC,0x8C,0xFC,0xD3,0xFD, + 0xB3,0xFF,0x1C,0x00,0x24,0x01,0x5F,0x01,0x0D,0x01,0xDA,0x00, + 0x7B,0x01,0x14,0x02,0xB7,0x01,0xB4,0x01,0xF8,0x00,0x26,0x00, + 0x99,0xFF,0xE8,0xFF,0xA3,0xFF,0x1C,0xFF,0xF5,0xFE,0x9D,0xFE, + 0x2E,0xFE,0x4C,0xFE,0x5B,0xFF,0x69,0xFF,0xA1,0xFF,0xA5,0xFF, + 0x16,0x00,0xF5,0xFF,0x92,0xFF,0x08,0xFF,0xF6,0xFF,0x20,0x07, + 0xFF,0x08,0x0A,0x08,0x51,0x06,0x03,0x03,0x64,0x01,0x84,0xFF, + 0x5F,0x02,0x5F,0x00,0x4C,0xFD,0x33,0xFA,0x56,0xF7,0x77,0xF6, + 0xAA,0xF5,0x2A,0xF9,0x8A,0xF8,0xEF,0xF8,0x30,0xF9,0x01,0xFB, + 0xD3,0xFD,0x87,0x00,0x65,0x05,0xC3,0x05,0x5D,0x07,0x81,0x07, + 0xEB,0x08,0x56,0x09,0x93,0x09,0xE8,0x09,0xB9,0x06,0x0D,0x05, + 0x2F,0x02,0x57,0x01,0x65,0xFF,0x87,0xFE,0x6D,0xFD,0x99,0xFA, + 0xF9,0xFA,0x94,0xFB,0x6B,0xFB,0x29,0xFB,0x01,0xFC,0xC3,0xFB, + 0xB7,0xFB,0x6D,0xFD,0xF6,0xFE,0x69,0xFF,0x36,0x00,0xEA,0x00, + 0xC0,0x00,0xD4,0x00,0xBB,0x01,0x1C,0x02,0xDB,0x01,0xDF,0x01, + 0x53,0x01,0xB0,0x00,0x30,0x00,0x76,0x00,0xA9,0xFF,0x2D,0xFF, + 0x08,0xFF,0x95,0xFE,0x57,0xFE,0x64,0xFE,0x1E,0xFF,0xE2,0xFE, + 0x4E,0xFF,0xB4,0xFF,0xA7,0xFF,0x40,0xFF,0x1A,0xFF,0xD2,0xFE, + 0x72,0x04,0xD5,0x08,0x44,0x07,0xAC,0x06,0x93,0x03,0x1B,0x02, + 0x21,0x00,0x2F,0x02,0xF7,0x01,0xF5,0xFD,0xEA,0xFB,0xC5,0xF8, + 0x23,0xF8,0xD2,0xF6,0x84,0xF9,0x4C,0xF9,0x65,0xF8,0x3B,0xF9, + 0x31,0xFA,0x0E,0xFD,0x0F,0xFF,0xA3,0x03,0x4C,0x04,0x61,0x05, + 0xB7,0x06,0xF3,0x07,0xEC,0x08,0xE8,0x08,0x92,0x09,0x9C,0x06, + 0x06,0x05,0x67,0x03,0x1D,0x02,0xAD,0x00,0x30,0xFF,0x3F,0xFE, + 0x09,0xFB,0x61,0xFB,0x20,0xFD,0xE7,0xFB,0xC8,0xFB,0xFD,0xFB, + 0xB2,0xFB,0x62,0xFB,0x62,0xFD,0x7C,0xFF,0xC3,0xFE,0xD2,0xFF, + 0x35,0x00,0x51,0x00,0x89,0x00,0xF9,0x01,0x16,0x02,0x16,0x01, + 0xC1,0x01,0xFA,0x00,0xCA,0x00,0x49,0x00,0xD1,0x00,0x9A,0xFF, + 0x06,0xFF,0x41,0xFF,0x6B,0xFE,0xE7,0xFE,0x22,0xFF,0xD3,0xFF, + 0xEF,0xFE,0x67,0xFF,0x7B,0xFF,0x3D,0xFF,0x95,0xFF,0x3B,0x00, + 0x73,0xFF,0x7D,0x02,0xB0,0x07,0xED,0x05,0x92,0x05,0xA0,0x03, + 0x26,0x02,0x10,0x00,0xDB,0x00,0xE1,0x01,0x5B,0xFD,0x22,0xFC, + 0xE1,0xF9,0x66,0xF9,0x4F,0xF8,0x0F,0xFA,0x80,0xFA,0x9A,0xF8, + 0x70,0xFA,0x75,0xFB,0x06,0xFE,0x88,0xFF,0x10,0x03,0xD0,0x03, + 0x26,0x04,0x9C,0x06,0x59,0x07,0x1B,0x08,0x97,0x07,0xE6,0x07, + 0x53,0x05,0xBC,0x03,0x73,0x03,0x8B,0x01,0x50,0x00,0x23,0xFF, + 0xBC,0xFE,0x6C,0xFD,0x30,0xFC,0x6C,0xFC,0xAF,0xFB,0xB3,0xFB, + 0x6C,0xFC,0xAC,0xFC,0xCB,0xFC,0x50,0xFD,0xCF,0xFE,0x05,0xFF, + 0x23,0x00,0xB8,0x00,0xA4,0x00,0xE0,0x00,0x80,0x01,0xEE,0x01, + 0x4F,0x01,0xDA,0x01,0x23,0x01,0x5B,0x00,0xE1,0xFF,0x2D,0x00, + 0xC1,0xFF,0x0E,0xFF,0x25,0xFF,0xB1,0xFE,0x27,0xFF,0x09,0xFF, + 0x5E,0xFF,0xE1,0xFE,0x1B,0xFF,0x3F,0xFF,0x99,0xFF,0xD0,0xFF, + 0x7A,0x01,0xA3,0x06,0x90,0x05,0x6D,0x04,0x74,0x03,0x83,0x01, + 0xB8,0x00,0x5A,0x00,0x65,0x01,0x6E,0xFD,0x07,0xFC,0x25,0xFB, + 0x50,0xFA,0xB1,0xFA,0xC9,0xFA,0x6A,0xFB,0x8C,0xF9,0x6D,0xFB, + 0xB2,0xFC,0x8B,0xFE,0x8C,0x00,0xE7,0x01,0xD5,0x02,0xDC,0x02, + 0xCD,0x05,0x59,0x06,0xDE,0x06,0x5E,0x06,0x79,0x05,0x0A,0x04, + 0x10,0x03,0x82,0x03,0x96,0x01,0xEB,0xFF,0xB2,0xFE,0xEB,0xFF, + 0xC3,0xFE,0x9D,0xFD,0xE9,0xFD,0x49,0xFC,0x40,0xFC,0xA8,0xFC, + 0xFB,0xFD,0x43,0xFD,0x16,0xFE,0x22,0xFF,0xC8,0xFE,0x53,0x00, + 0xC1,0x00,0xE0,0x00,0x09,0x00,0xF9,0x00,0xCC,0x00,0x79,0x00, + 0x05,0x01,0xD6,0xFF,0x74,0xFF,0x6A,0xFF,0x7F,0x00,0x3D,0x00, + 0xCA,0x00,0xB2,0x00,0xEE,0xFE,0xC4,0xFE,0x54,0xFF,0xFF,0xFF, + 0xFD,0xFF,0x55,0x00,0x61,0xFF,0xF7,0xFE,0x53,0x00,0x5F,0x00, + 0xE9,0x02,0xB7,0x04,0x1D,0x03,0x4A,0x02,0xE5,0x00,0xB9,0x00, + 0xBB,0xFF,0xF0,0xFF,0xEB,0xFE,0x81,0xFC,0x71,0xFC,0xDA,0xFB, + 0x6F,0xFC,0x8D,0xFB,0x23,0xFC,0xCF,0xFB,0x1B,0xFC,0x95,0xFD, + 0xAE,0xFE,0x8C,0x00,0xC3,0x00,0x42,0x02,0xE8,0x02,0x7D,0x04, + 0x40,0x05,0x96,0x05,0x0B,0x05,0xBE,0x03,0xF0,0x03,0x12,0x03, + 0xDE,0x02,0x09,0x01,0xD5,0xFF,0xEA,0x00,0xC2,0x00,0xA8,0xFF, + 0x45,0xFE,0x6B,0xFD,0x64,0xFC,0x97,0xFC,0x7C,0xFE,0x26,0xFE, + 0x64,0xFD,0x28,0xFD,0x2F,0xFE,0x5D,0xFF,0x8D,0x00,0xEA,0x00, + 0x95,0xFF,0xA0,0xFF,0x12,0x00,0x78,0x01,0x25,0x01,0x03,0x01, + 0xD5,0xFF,0x8A,0xFF,0xCE,0x01,0x9D,0x01,0xE5,0x00,0xE9,0xFF, + 0xBC,0xFF,0xE4,0xFE,0x56,0xFF,0xA8,0xFF,0xC2,0xFE,0x1C,0xFF, + 0x14,0xFF,0xB5,0xFF,0x80,0xFF,0x95,0xFF,0xD7,0xFF,0x0B,0x00, + 0x93,0xFF,0x40,0x00,0x90,0x02,0x7A,0x01,0x75,0x01,0x39,0x01, + 0x53,0x00,0x90,0xFF,0xC3,0xFF,0x26,0x00,0x5B,0xFE,0x4D,0xFE, + 0x13,0xFE,0x4C,0xFE,0xFB,0xFD,0x81,0xFE,0x35,0xFE,0x9B,0xFD, + 0x5D,0xFF,0x98,0xFF,0xB0,0x00,0xE5,0x00,0x2C,0x01,0x99,0x01, + 0x61,0x02,0x14,0x03,0x57,0x02,0xD6,0x02,0x0B,0x02,0x6A,0x02, + 0xFF,0x01,0x07,0x01,0xEA,0x00,0x07,0x00,0x4F,0xFF,0x96,0xFE, + 0xC4,0xFE,0x3A,0xFF,0x4C,0xFF,0x5E,0xFE,0x7A,0xFE,0xE1,0xFF, + 0xE6,0xFF,0xB3,0xFF,0x58,0xFF,0xCC,0xFF,0x42,0x00,0xDA,0x00, + 0x2D,0x01,0x42,0xFE,0x0C,0x01,0x5B,0x00,0x80,0xFF,0xC6,0x00, + 0xF3,0xFE,0xE9,0xFE,0x0C,0xFF,0x22,0x02,0xDD,0xFF,0x25,0xFE, + 0x14,0xFF,0x71,0xFF,0x12,0x01,0x89,0xFF,0xED,0xFD,0xEA,0xFF, + 0x86,0xFD,0xE6,0x00,0x32,0x02,0xF8,0xFD,0x71,0x00,0xE6,0xFE, + 0x1D,0x00,0x43,0xFF,0x1E,0x01,0xD4,0x00,0x49,0xFE,0xBB,0x00, + 0x9B,0xFF,0x9B,0x00,0x2D,0x01,0xD0,0xFF,0x44,0xFF,0x97,0x01, + 0xF7,0xFF,0x41,0x00,0xBB,0x01,0xC6,0xFF,0x9E,0xFF,0xB9,0x00, + 0x78,0x00,0x45,0xFF,0x04,0x00,0xD9,0xFF,0x25,0x00,0xF8,0xFF, + 0x3E,0x00,0xA6,0xFF,0x60,0x00,0x4A,0x00,0x9B,0xFF,0x58,0x01, + 0x82,0x00,0xB0,0x00,0xCB,0xFE,0xA0,0x00,0x47,0x01,0xE1,0xFF, + 0x1E,0x02,0xE9,0xFE,0x5B,0xFF,0x8A,0xFF,0x1F,0x00,0xAB,0x00, + 0x19,0xFF,0x20,0xFF,0x2A,0x00,0x69,0x00,0x1F,0x00,0xB8,0x00, + 0x04,0xFF,0x40,0x00,0x8E,0x00,0xC9,0xFE,0x62,0xFE,0xAC,0x01, + 0x71,0x00,0x38,0xFE,0xFA,0x00,0x73,0xFF,0xC1,0xFF,0x7D,0x00, + 0xE2,0xFE,0xC6,0xFF,0xFE,0xFE,0x6A,0x00,0xE2,0x01,0x66,0xFF, + 0xF4,0xFE,0x32,0xFD,0xFC,0x00,0xDE,0x00,0x51,0xFC,0xA0,0x01, + 0x35,0xFF,0xD6,0xFF,0x04,0x03,0x4E,0xFF,0x36,0xFF,0x5B,0x01, + 0x53,0x01,0x73,0xFD,0x61,0x01,0x45,0xFF,0x64,0x00,0x2E,0x01, + 0x6E,0xFD,0x13,0xFF,0xD8,0xFE,0xC2,0x03,0x09,0xFE,0x2C,0xFF, + 0xF4,0x02,0x38,0xFF,0xCD,0x01,0x39,0x01,0xF2,0x00,0x06,0x00, + 0x4C,0x00,0xDA,0x00,0xFD,0xFE,0x08,0x01,0xF6,0xFC,0x90,0xFF, + 0xAF,0x01,0x43,0xFF,0xA3,0xFF,0x03,0xFF,0x57,0x00,0x1E,0x01, + 0x1F,0x02,0x4D,0xFD,0xE2,0x01,0xFD,0xFE,0xB2,0x00,0x25,0x03, + 0x62,0xFE,0x1F,0xFF,0x8C,0xFE,0x86,0x01,0x2A,0x01,0xC0,0x00, + 0xA0,0xFE,0x9D,0xFF,0x4A,0xFF,0x56,0x00,0x73,0xFF,0xD1,0xFD, + 0x0E,0x00,0x51,0xFF,0x9F,0x00,0x83,0xFF,0xE4,0x00,0xE3,0x01, + 0x29,0xFD,0x75,0x00,0x26,0x00,0xA0,0xFF,0xB5,0x00,0x3F,0xFE, + 0x3D,0x00,0x55,0x01,0x8B,0x01,0xD1,0xFE,0xBF,0xFE,0xF2,0xFE, + 0x6F,0x01,0x49,0xFF,0x2B,0x00,0x13,0xFE,0xA1,0xFE,0xB7,0x02, + 0xBB,0xFF,0xA0,0x02,0x20,0x00,0x90,0xFE,0xA4,0x01,0xA8,0x01, + 0x4B,0xFE,0x00,0xFF,0x6B,0xFE,0x6A,0x01,0x79,0x00,0xFC,0xFF, + 0x99,0xFD,0x6D,0x03,0x06,0x02,0xF7,0xFB,0x26,0x02,0xA9,0xFE, + 0xE7,0x00,0x92,0xFD,0xD6,0x00,0xCA,0x02,0x5F,0xFE,0x83,0x00, + 0xAD,0xFE,0x06,0x00,0x45,0x01,0x1A,0xFF,0x57,0x00,0xBE,0xFF, + 0x31,0xFF,0xA2,0x01,0x9C,0x01,0x6C,0xFF,0x22,0x00,0x29,0x00, + 0xC2,0xFE,0x0B,0x01,0x8F,0xFD,0x7B,0xFF,0xBF,0x00,0xDE,0xFE, + 0xAF,0x02,0xB3,0xFE,0xED,0xFF,0x87,0x01,0xC8,0xFF,0x38,0x00, + 0x1F,0x00,0xAD,0xFF,0x3C,0xFF,0x6A,0x01,0xE3,0xFE,0x4E,0xFE, + 0xE8,0x01,0x69,0xFE,0xC0,0xFE,0xB7,0x02,0x7A,0xFE,0x22,0x00, + 0x60,0xFF,0x45,0xFF,0x85,0x01,0x57,0x00,0xF3,0xFF,0x82,0xFE, + 0x69,0x01,0x60,0x01,0xF6,0xFF,0xFC,0xFD,0xC8,0x01,0x60,0xFF, + 0x37,0xFE,0xCF,0x03,0x8C,0xFD,0x75,0x00,0x0A,0x00,0x42,0x00, + 0x60,0xFF,0xE0,0x00,0x1F,0x02,0x19,0xFD,0xD7,0x00,0x5B,0xFE, + 0xD3,0x00,0xE0,0x00,0x9C,0xFE,0xC7,0xFF,0x1B,0x00,0x8F,0xFE, + 0x1C,0x01,0xD5,0x00,0x59,0x00,0x3B,0x00,0xDC,0xFD,0x62,0x00, + 0x01,0x01,0x56,0x01,0xD6,0xFF,0x74,0x00,0x30,0xFF,0xD4,0x01, + 0xE4,0xFE,0xCF,0xFE,0xFB,0x00,0x12,0xFD,0x9B,0xFF,0x4B,0x04, + 0x70,0xFF,0xD4,0xFC,0x11,0x03,0x34,0xFD,0x1D,0x03,0x04,0xFF, + 0x4B,0xFC,0x4D,0x03,0x43,0xFE,0xBE,0x02,0xB6,0xFF,0xA6,0xFD, + 0x28,0x02,0xD6,0xFE,0x4E,0x01,0x18,0x01,0xAD,0xFC,0xDD,0x02, + 0xED,0xFE,0xCA,0xFF,0x3B,0x01,0x43,0xFE,0x73,0x01,0xD6,0xFF, + 0xA8,0xFD,0x8D,0x00,0xBD,0x01,0xC5,0xFD,0xB5,0x01,0x4F,0xFD, + 0x49,0x00,0xE5,0x00,0xC1,0xFF,0xDC,0x01,0x39,0xFD,0xA6,0x02, + 0x64,0xFF,0x14,0x01,0x68,0x01,0xA5,0xFE,0x4D,0xFE,0xD0,0x00, + 0x2C,0x00,0x7C,0x00,0x3D,0x01,0x3A,0xFD,0xF3,0x01,0x7A,0xFF, + 0x2A,0x01,0x67,0xFF,0x4B,0xFF,0xEC,0xFF,0x00,0xFF,0x1B,0x00, + 0x6C,0xFE,0x66,0x01,0xFC,0xFF,0x3E,0x02,0x15,0x00,0x30,0xFE, + 0xB8,0x00,0x47,0xFF,0x80,0x01,0xD3,0xFF,0x38,0xFE,0xAB,0x00, + 0x41,0xFF,0xF8,0xFF,0xDB,0x00,0xCC,0xFF,0xE6,0xFE,0x8C,0xFF, + 0x3E,0x01,0xF9,0xFF,0xF8,0x01,0xE2,0xFF,0xF2,0xFD,0x51,0x00, + 0x0B,0x01,0x3A,0x02,0xC1,0xFF,0xC1,0xFC,0x6D,0x00,0x36,0x01, + 0xBD,0x00,0xC0,0x00,0xFA,0xFC,0x45,0xFF,0x06,0xFF,0xFA,0x00, + 0xEC,0xFF,0x92,0x00,0xAD,0xFE,0x89,0xFE,0x70,0x04,0x61,0xFE, + 0x39,0x01,0x98,0x00,0x4B,0xFC,0x81,0x04,0xB4,0xFE,0xA2,0xFF, + 0x19,0x02,0xBE,0xFC,0x64,0x02,0x0A,0xFF,0x38,0x00,0xA8,0xFE, + 0xF7,0x00,0x52,0x00,0x12,0xFE,0x2E,0x01,0x0C,0xFF,0x8A,0xFE, + 0xC8,0xFF,0x4C,0x02,0xDF,0xFF,0x42,0x00,0x1B,0x01,0x42,0x00, + 0xB4,0xFF,0x20,0x01,0xAE,0xFE,0x7D,0xFF,0xB4,0x01,0x3C,0xFF, + 0xC3,0xFF,0x5F,0x00,0xA5,0x00,0xFC,0xFD,0xF5,0xFD,0x1E,0xFF, + 0x59,0x00,0xB5,0x05,0xFB,0xFB,0xDE,0xFF,0x2A,0x01,0x05,0xFF, + 0x57,0x03,0xF4,0xFB,0x39,0x03,0x12,0xFF,0xDE,0xFF,0x08,0x01, + 0xEE,0xFE,0xBB,0x02,0x17,0xFF,0x5A,0xFD,0x6F,0x00,0xC6,0x00, + 0xF1,0xFF,0xAD,0xFF,0x4A,0xFC,0x7B,0x00,0xA4,0xFF,0x25,0x04, + 0xD6,0xFF,0x07,0xFE,0xF0,0xFF,0x03,0x02,0xC3,0x03,0xD3,0xFA, + 0x89,0x01,0xF4,0xFD,0x49,0x02,0xDE,0x01,0xDF,0xFB,0x92,0x02, + 0xCC,0xFE,0x2A,0x00,0xA4,0xFF,0x64,0x01,0xF2,0xFD,0xC2,0xFF, + 0xCD,0x01,0x4E,0xFD,0x91,0x01,0x05,0x00,0xAE,0xFF,0x99,0xFD, + 0x83,0x01,0x44,0x01,0xF0,0xFD,0x0E,0x03,0x97,0x00,0x2F,0xFF, + 0x46,0xFE,0x6D,0x02,0x9F,0xFF,0x4C,0xFD,0xAE,0x02,0x85,0xFF, + 0xF1,0x01,0x74,0xFE,0xF3,0x01,0x83,0xFD,0xCA,0xFF,0xFE,0x01, + 0xA6,0xFA,0xB9,0x02,0x7A,0xFD,0x7A,0x02,0x28,0xFE,0x54,0x01, + 0x84,0x01,0x05,0xFE,0x79,0x03,0x90,0xFC,0x5E,0x02,0x0C,0x01, + 0x95,0xFE,0x2C,0xFE,0x07,0x02,0x78,0x02,0x66,0xFF,0xE8,0xFE, + 0x62,0xFD,0xDB,0x01,0x71,0x01,0x0A,0xFE,0x63,0xFF,0x71,0xFF, + 0xC6,0xFF,0xFE,0x01,0x95,0xFD,0x56,0x02,0x5B,0xFF,0x33,0xFD, + 0xF9,0x02,0x97,0xFD,0x8A,0x02,0x61,0xFF,0xE7,0xFE,0x63,0x02, + 0xB6,0x00,0xAF,0xFF,0x96,0x01,0x50,0x00,0xEC,0xFB,0x77,0x02, + 0xB5,0xFE,0xD0,0xFF,0x6C,0xFE,0x31,0x00,0xB9,0x00,0x0F,0xFD, + 0x1D,0x03,0xAF,0xFF,0x14,0x00,0x7F,0xFF,0x30,0x00,0x9F,0x01, + 0xAD,0x00,0x2A,0x01,0x3C,0xFD,0x7F,0x00,0x7D,0x00,0xF0,0xFF, + 0xD3,0x01,0x63,0xFD,0xFE,0xFF,0x4A,0xFF,0x50,0x01,0x45,0x01, + 0xE6,0xFD,0x62,0xFF,0x03,0x00,0xA0,0xFF,0x0C,0x01,0x1B,0x01, + 0x07,0xFD,0xCC,0x00,0xE5,0xFD,0x3C,0x04,0x61,0x00,0x1D,0xFD, + 0x9C,0x02,0x75,0xFE,0xCF,0x01,0x9B,0x00,0x3C,0x01,0x5F,0xFC, + 0x54,0xFF,0xB2,0x02,0xBF,0xFF,0x7F,0xFE,0xA7,0x01,0x45,0xFE, + 0x7A,0xFF,0x88,0x03,0xE3,0xFB,0x46,0x01,0x85,0xFE,0x04,0x01, + 0x9A,0xFF,0x98,0xFF,0x9E,0x01,0x8A,0xFE,0x26,0x03,0x1B,0xFD, + 0x0D,0x02,0x1F,0x00,0x11,0xFE,0x16,0x01,0xCA,0xFE,0xA4,0xFF, + 0x49,0x00,0x7D,0x02,0xD8,0xFD,0x57,0x01,0x0C,0xFF,0x27,0xFF, + 0xDF,0x01,0x01,0xFF,0x58,0x01,0xF8,0xFE,0xA9,0x00,0xB2,0x00, + 0x8E,0x01,0xD5,0xFE,0xD4,0x00,0x04,0xFE,0x5E,0xFF,0xAE,0x00, + 0x71,0xFD,0xE8,0xFF,0x7F,0xFE,0xA1,0x04,0x1E,0xFD,0x0C,0x01, + 0xAC,0xFF,0x18,0x00,0x33,0x03,0xBB,0xFF,0xAE,0x00,0xD7,0xFC, + 0x5B,0x01,0x03,0x01,0x4B,0x00,0xAB,0xFB,0x1E,0x00,0xE9,0x01, + 0x9A,0x00,0x35,0xFE,0x9D,0xFF,0x19,0x00,0x9A,0xFF,0xE6,0x01, + 0xCD,0xFF,0x22,0x01,0xC6,0xFE,0x96,0x03,0x08,0x01,0x32,0xFE, + 0x6D,0xFD,0x17,0xFF,0x50,0x00,0x47,0x01,0x8A,0xFF,0xD9,0xFD, + 0x26,0x00,0xCE,0xFF,0x65,0x03,0xBB,0xFF,0xCE,0xFD,0xED,0x01, + 0x8D,0xFF,0x31,0x00,0xB3,0x00,0x94,0xFD,0x81,0xFF,0xF2,0xFE, + 0xDD,0x02,0xDF,0x00,0xE0,0xFE,0x3E,0x01,0xC2,0xFE,0xE7,0x01, + 0x89,0x01,0x55,0xFB,0xE8,0xFF,0x7D,0x02,0xA2,0xFF,0xC2,0x00, + 0xFF,0x00,0xBD,0xFD,0x56,0x01,0xEF,0x00,0x22,0xFD,0x01,0x00, + 0xD7,0xFE,0xBA,0x00,0x46,0x00,0x4F,0x01,0x3F,0xFB,0x17,0x01, + 0x89,0x02,0xF2,0xFE,0x79,0x02,0xE0,0xFE,0x61,0x00,0x2D,0x01, + 0xBF,0xFF,0x79,0x00,0x3A,0x02,0x54,0xFC,0xA9,0x00,0x7D,0xFF, + 0x29,0x00,0x3D,0xFF,0x6B,0xFF,0x59,0x01,0xC5,0xFE,0x31,0x00, + 0x31,0x00,0x17,0x01,0x17,0xFE,0xD3,0x00,0xB7,0xFE,0x89,0x01, + 0xD0,0x01,0x68,0xFE,0x42,0x00,0xBE,0x01,0x13,0xFF,0xE8,0xFE, + 0x18,0x00,0xD9,0xFD,0x1F,0x02,0x0F,0x01,0x11,0xFE,0x65,0x00, + 0x48,0x00,0x9A,0xFF,0xAD,0x01,0x95,0xFF,0x57,0xFC,0x44,0x00, + 0x3E,0x02,0x9C,0x02,0x24,0xFE,0x59,0xFD,0x0E,0x02,0x36,0x00, + 0x15,0x02,0x42,0xFE,0x4F,0xFF,0x22,0x01,0xE7,0xFE,0xA3,0x00, + 0x6A,0x01,0x7A,0xFE,0x37,0xFE,0x25,0x01,0x3A,0x02,0x2D,0x00, + 0x54,0xFC,0xBC,0x02,0xA2,0xFF,0x8D,0xFD,0xE9,0x02,0x1F,0x00, + 0x36,0xFD,0x6B,0x01,0xED,0x00,0xB7,0xFF,0x68,0xFF,0x4F,0xFE, + 0xFC,0x04,0x89,0xFE,0x06,0xFC,0x6B,0x02,0x8A,0xFF,0x1F,0xFF, + 0x6A,0xFF,0x66,0xFE,0x15,0x04,0xF3,0x00,0xEA,0xFE,0x01,0x00, + 0x7B,0x00,0xE7,0xFE,0x47,0xFE,0xA6,0x01,0x8F,0xFC,0xD5,0x05, + 0x3A,0x00,0x3A,0xFD,0x36,0x03,0x57,0xFD,0xB6,0x01,0x75,0xFF, + 0x1A,0xFF,0xA1,0xFE,0xC7,0xFF,0x77,0x01,0xE1,0xFD,0x86,0xFF, + 0xA2,0x00,0xAA,0xFE,0xB5,0x02,0x3A,0x02,0x21,0xFD,0xAB,0x01, + 0x0E,0xFE,0x5F,0x02,0xF1,0xFF,0x45,0xFF,0xDB,0xFF,0x50,0xFE, + 0x20,0x04,0x63,0xFD,0x47,0x02,0x1D,0xFC,0x35,0x01,0x5D,0x02, + 0xD6,0xFD,0x04,0x01,0x27,0xFC,0xD6,0x01,0xA7,0xFD,0x6D,0x03, + 0xC3,0xFE,0xD2,0xFF,0x87,0x02,0x57,0xFE,0xB1,0x03,0x15,0xFE, + 0xA2,0x00,0x2D,0xFD,0xA1,0x04,0xF6,0xFC,0xAC,0xFC,0xD5,0x02, + 0xBE,0xFC,0xCA,0x04,0xA7,0xFD,0x6D,0xFE,0xB6,0x00,0xF0,0xFE, + 0x47,0x01,0x0A,0x02,0x42,0x00,0x56,0x01,0x0A,0xFF,0x13,0x01, + 0xF0,0x01,0x30,0xFC,0xB5,0x00,0x7A,0xFD,0xC2,0xFD,0x3F,0x03, + 0x98,0xFE,0xD5,0x01,0xEC,0x00,0xE7,0xFD,0xF7,0xFE,0x80,0xFF, + 0xF0,0x04,0x73,0xFE,0xDD,0xFD,0xCA,0xFF,0xAA,0x01,0xE2,0x02, + 0x06,0x00,0x68,0xFC,0x52,0xFF,0x11,0x04,0xF3,0xFB,0x0E,0x01, + 0xCC,0xFD,0x36,0x00,0xE9,0x00,0x50,0x00,0x34,0x03,0xE7,0xFB, + 0xC3,0x01,0xB1,0xFC,0x0E,0x04,0xAE,0xFE,0xC1,0xFE,0x4B,0x03, + 0x29,0xFF,0x69,0x04,0xA3,0xFB,0x29,0x02,0x29,0xFF,0x8C,0xFE, + 0x19,0x01,0x18,0x01,0x05,0xFD,0xBA,0xFF,0x53,0x01,0x9A,0xFB, + 0x00,0x03,0x28,0xFE,0x9F,0xFF,0xDC,0xFF,0xC5,0x00,0xC9,0x02, + 0x1D,0xFF,0x9B,0x01,0x38,0x00,0xFA,0xFD,0xA2,0x03,0x67,0xFE, + 0x49,0xFE,0x98,0x00,0x7C,0xFD,0xA9,0x04,0x05,0xFF,0x57,0xFE, + 0x3B,0xFF,0x70,0xFE,0xB1,0x02,0xC1,0x00,0xE6,0xFE,0x89,0xFD, + 0x94,0x02,0xC1,0x01,0x8B,0x00,0x26,0xFF,0x11,0xFC,0xE2,0x03, + 0x1A,0x00,0x5D,0xFD,0x19,0x00,0xA3,0xFF,0x93,0x00,0xFF,0x00, + 0x63,0x00,0xBC,0xFD,0x19,0x02,0xBF,0x01,0xD5,0xFD,0xCB,0xFD, + 0xA6,0x01,0xFD,0x00,0xE0,0xFF,0xA8,0xFF,0xCE,0xFD,0x94,0x04, + 0xF0,0xFE,0xCD,0xFE,0xBB,0x01,0x00,0xFC,0x42,0x00,0xCB,0x01, + 0x7C,0x00,0xF2,0xFF,0xC2,0xFF,0x81,0x00,0x75,0x02,0x39,0xFE, + 0x65,0xFF,0x65,0xFF,0x7F,0x00,0x35,0x01,0x56,0xFC,0xD1,0x04, + 0x94,0xFB,0xFA,0xFF,0x1D,0x01,0x12,0xFD,0x73,0x02,0x55,0xFE, + 0x36,0x02,0xBC,0xFD,0xB6,0x03,0x30,0xFE,0x0C,0x01,0xA1,0x05, + 0xDD,0xFB,0x54,0xFF,0x5C,0x01,0x16,0xFF,0xE2,0xFE,0x4A,0x02, + 0x60,0xFB,0x52,0x00,0x0F,0x01,0x90,0xFC,0xBA,0x02,0xFE,0xFF, + 0x41,0x00,0x9B,0x00,0x9F,0x00,0xED,0xFF,0x40,0xFF,0x5E,0x03, + 0xDF,0xFD,0xD6,0xFF,0x3E,0x02,0xF5,0xFD,0xC0,0xFF,0x82,0xFE, + 0xE4,0xFE,0x87,0x01,0x52,0x00,0x92,0xFE,0xEE,0xFF,0x3A,0x04, + 0x13,0xFF,0x0B,0xFE,0xB3,0x02,0x51,0xFF,0x0E,0xFF,0xFB,0xFE, + 0x6F,0x00,0xB6,0xFE,0x4A,0x01,0x79,0x01,0x96,0xFD,0x5D,0x00, + 0x32,0x00,0x10,0xFE,0x5F,0x01,0xF7,0x00,0xE3,0xFD,0x0D,0x05, + 0xB9,0x02,0x9C,0xF9,0xA2,0x01,0x8A,0xFF,0xB1,0xFD,0xFF,0x01, + 0x9D,0xFE,0xB2,0xFE,0x74,0xFF,0xBF,0x03,0x1F,0xFE,0x57,0x03, + 0xBF,0xFD,0xA0,0xFE,0x80,0x03,0x01,0xFF,0x19,0x00,0x77,0xFD, + 0x13,0x02,0x81,0xFD,0x58,0x03,0xAB,0x00,0x45,0x00,0xC8,0xFF, + 0xB0,0x00,0x4E,0xFE,0x90,0xFD,0x06,0x03,0xD7,0xFA,0xC4,0x01, + 0x5B,0xFE,0x93,0x00,0x26,0x01,0x3C,0xFE,0x73,0x02,0x30,0x02, + 0x21,0x02,0xF4,0xFE,0x00,0xFF,0xAB,0xFE,0xD2,0xFF,0x11,0x02, + 0x8D,0x00,0x3C,0xFB,0x6D,0xFF,0x98,0x01,0xEC,0xFF,0x9C,0x02, + 0x8A,0xFE,0xEF,0xFC,0xA3,0x01,0x0A,0x02,0xE9,0x02,0x75,0x00, + 0x4C,0xFD,0x75,0xFF,0xD8,0xFE,0x12,0x02,0x87,0x00,0x5D,0xFD, + 0xA7,0xFF,0x57,0x00,0xD4,0x00,0x15,0x01,0x9C,0xFD,0xF5,0x00, + 0xF6,0xFF,0x6C,0xFC,0x8F,0x04,0x48,0xFE,0x58,0xFF,0x7C,0x02, + 0x71,0xFE,0xDF,0x01,0x02,0xFF,0x2A,0x00,0xFC,0x01,0x04,0xFF, + 0xAF,0xFD,0x2B,0x02,0x0C,0xFF,0x43,0x00,0xB7,0x00,0x9B,0xFD, + 0x2E,0x01,0x76,0xFE,0x40,0x00,0xB9,0xFF,0x6F,0x02,0xB1,0xFD, + 0x6C,0x00,0xAF,0x00,0xD3,0xFF,0x21,0x02,0x6C,0xFD,0x41,0x02, + 0x23,0xFF,0x80,0x02,0xD5,0xFA,0xC3,0xFF,0x59,0x03,0x72,0x00, + 0x2B,0x01,0xD3,0xFB,0x0A,0x01,0xB0,0xFF,0x3E,0x02,0xF9,0xFE, + 0x4F,0x01,0xAE,0xFD,0x7B,0xFF,0x48,0x03,0x34,0xFF,0x24,0x01, + 0x65,0xFC,0x8C,0xFF,0x48,0x00,0x9B,0x01,0xE9,0x02,0xE5,0xFD, + 0xDC,0xFD,0x3B,0x02,0x5E,0xFE,0x48,0xFF,0xA2,0x02,0xA7,0xFE, + 0x89,0xFF,0x5E,0x00,0x5B,0xFF,0xC8,0x01,0x3E,0xFF,0x9A,0xFD, + 0x50,0x00,0x73,0x00,0xD1,0x02,0xBD,0xFB,0x32,0x00,0x5F,0x01, + 0x38,0x01,0x64,0x03,0x8A,0xFD,0x08,0xFF,0xF4,0xFD,0xCA,0x04, + 0x3A,0xFF,0x4B,0xFF,0x47,0x00,0x59,0xFD,0x9C,0x00,0x6F,0x02, + 0xF0,0xFF,0x4F,0xFB,0xC4,0x03,0xD1,0xFB,0xFD,0x01,0xD4,0x03, + 0xC0,0xFD,0x4B,0x01,0xD1,0xFC,0xD7,0x02,0x0B,0xFF,0x35,0xFF, + 0xF8,0xFE,0x2A,0x01,0xC6,0xFF,0x88,0xFF,0x0B,0x04,0x90,0xFD, + 0x7B,0x01,0x89,0xFC,0xB3,0x02,0x0B,0xFF,0x9C,0xFE,0x45,0x03, + 0xF3,0xFB,0xDD,0x02,0xA1,0xFD,0x44,0x01,0xBF,0x00,0x76,0xFF, + 0xFF,0x00,0xD5,0xFD,0x82,0x01,0x24,0xFD,0xFF,0x02,0x84,0x00, + 0xB6,0xFD,0x50,0x01,0x5A,0xFC,0x55,0x07,0x72,0xFE,0x93,0xFC, + 0x06,0x01,0x7E,0xFD,0x5A,0x05,0x6A,0xFE,0xC6,0xFE,0x47,0xFF, + 0x7C,0xFF,0xF5,0x00,0xAD,0x02,0xD6,0xFD,0x60,0xFD,0x90,0x02, + 0xE0,0x01,0x68,0x01,0xC1,0xFD,0xBA,0xFF,0xDB,0xFD,0xD4,0x00, + 0x4C,0x00,0x8D,0xFF,0xF2,0xFF,0xD8,0xFF,0x08,0x00,0xD3,0x00, + 0x95,0x02,0xCB,0xFD,0x19,0x00,0x44,0xFE,0x02,0x01,0x78,0x00, + 0xDE,0xFF,0x88,0x00,0x07,0xFF,0xDE,0x01,0xC4,0xFE,0xA4,0xFF, + 0xBC,0xFE,0xCA,0x01,0x99,0xFF,0x75,0xFF,0x80,0x00,0x11,0xFF, + 0xB5,0x02,0x31,0xFF,0xEE,0xFF,0x2F,0xFD,0xC1,0xFF,0x03,0x02, + 0xCB,0xFF,0xE2,0x01,0xA9,0xFF,0x47,0x00,0x9C,0xFE,0x41,0x00, + 0x71,0x00,0x89,0xFF,0x64,0xFE,0xFA,0xFF,0x0F,0x04,0xAA,0xFC, + 0xE3,0x00,0xB1,0x00,0x0D,0xFF,0xC7,0x01,0x06,0xFC,0x47,0x01, + 0x18,0x01,0x38,0x00,0x5E,0xFF,0x96,0xFF,0x84,0x00,0x8A,0x00, + 0xE6,0xFF,0x15,0xFD,0x49,0x03,0x17,0xFE,0xDB,0x00,0x49,0x00, + 0xDE,0x01,0x22,0x02,0xCB,0xFC,0x61,0x02,0xEB,0xFC,0x64,0x00, + 0x7A,0xFF,0x4B,0xFF,0xC6,0xFF,0xCD,0xFE,0xC2,0x01,0x1E,0x01, + 0x6F,0xFF,0xE2,0xFF,0xAB,0xFF,0x56,0xFE,0x21,0x02,0xBD,0xFE, + 0x0F,0x01,0xAC,0x02,0xD8,0xFD,0x1D,0x00,0x02,0x02,0x4E,0xFE, + 0x60,0x01,0x45,0xFD,0x70,0xFF,0x7D,0x00,0x99,0xFF,0xAF,0x04, + 0xA1,0xFC,0x27,0xFF,0x75,0xFE,0x57,0x01,0xE8,0x00,0x0C,0x00, + 0xA7,0xFD,0xF7,0x01,0x40,0x03,0x2B,0xFB,0x24,0x05,0x54,0xFB, + 0x44,0xFE,0x50,0x05,0x9C,0xFD,0x72,0x01,0x4D,0xFF,0xA0,0xFD, + 0x02,0x03,0x99,0xFF,0xCC,0xFE,0x73,0x00,0xDB,0xFD,0xBC,0x01, + 0x47,0x02,0xF9,0xFD,0x08,0xFF,0x1C,0x00,0xD0,0x01,0xD6,0xFF, + 0x1D,0xFC,0xBC,0x05,0xF4,0xFC,0xC1,0xFE,0x54,0x03,0xFA,0xFD, + 0x82,0x01,0x0B,0xFF,0xC9,0xFF,0x90,0xFF,0x3F,0x02,0xA3,0xFD, + 0x0D,0x01,0x8F,0x00,0x25,0xFF,0x2D,0x02,0x98,0xFE,0x28,0x00, + 0xDC,0xFE,0xFA,0xFE,0x24,0x00,0xAE,0x01,0x68,0xFE,0x56,0x00, + 0xB9,0xFE,0xC5,0xFF,0x1C,0x04,0xF2,0xFE,0x2D,0x00,0xC2,0xFE, + 0xDE,0xFF,0x35,0x00,0x49,0x01,0xC9,0xFF,0x2C,0xFD,0xC1,0x01, + 0xFF,0xFF,0xCD,0xFF,0x25,0x01,0x4B,0xFF,0x7F,0xFF,0xCF,0xFF, + 0xB0,0x00,0xEF,0x00,0xC4,0xFF,0xDD,0xFD,0x4A,0x01,0x30,0x01, + 0xEB,0xFC,0x53,0x04,0xEE,0xFB,0x56,0x01,0xA0,0x01,0x36,0xFC, + 0xB8,0x04,0x83,0xFC,0x1B,0x02,0x9F,0xFF,0x42,0xFF,0x7C,0x00, + 0x85,0xFF,0x7A,0xFF,0xE1,0xFF,0x19,0x01,0x53,0xFE,0x63,0x03, + 0x0A,0xFD,0xD0,0x01,0x82,0x00,0x75,0xFE,0xFC,0x00,0xFF,0xFD, + 0x7F,0x03,0x42,0xFE,0x4A,0x01,0x1B,0xFE,0x50,0x00,0x17,0x00, + 0x22,0xFE,0x22,0x02,0x6C,0xFB,0x38,0x04,0x70,0x00,0x21,0x00, + 0xF8,0xFF,0x61,0xFD,0x8F,0x02,0xDD,0xFE,0x0E,0x00,0xB2,0xFF, + 0x59,0xFF,0xD9,0x01,0x37,0xFF,0x48,0x00,0x14,0x01,0x8F,0xFF, + 0xED,0x00,0x6A,0x00,0x8B,0xFF,0xB8,0xFD,0x10,0x02,0xC9,0xFE, + 0xF5,0xFF,0xB7,0x00,0xC2,0xFC,0x46,0x03,0x66,0xFD,0x24,0x01, + 0x52,0xFF,0xB7,0x00,0x61,0x02,0xCF,0xFC,0x86,0x04,0xB6,0xFC, + 0x17,0x03,0xA6,0xFD,0x7E,0xFD,0xAA,0x02,0x68,0xFD,0x76,0x03, + 0x0D,0xFE,0xAB,0x00,0x4F,0xFE,0x51,0x00,0xE7,0x00,0x5C,0x00, + 0x5C,0xFF,0xC0,0x01,0x87,0x01,0x2F,0xFD,0xF7,0x01,0xA6,0xFE, + 0xD6,0x00,0x27,0xFF,0xB0,0xFD,0x43,0x01,0xF5,0xFF,0x51,0x00, + 0x18,0x00,0xF6,0xFB,0x16,0x04,0x87,0x01,0x18,0xFE,0x32,0x02, + 0x5B,0xFE,0x57,0x02,0xA5,0xFF,0xB4,0xFB,0xDC,0x00,0xEC,0x03, + 0x1E,0xFF,0xCB,0xFD,0x2C,0xFE,0xF2,0x02,0xEB,0x01,0x2E,0xFE, + 0x62,0xFD,0x41,0xFE,0x4D,0x04,0xFE,0xFE,0xE4,0x00,0x73,0xFF, + 0x60,0xFE,0x15,0x01,0x4F,0x00,0x5C,0x01,0x71,0x00,0x4F,0x01, + 0xF6,0xFC,0x77,0xFF,0xC2,0x02,0xC3,0xFE,0xC4,0x01,0x2F,0xFE, + 0x60,0xFE,0x52,0x01,0x08,0xFE,0xDE,0x01,0xDE,0xFE,0x45,0x01, + 0x97,0xFE,0x9D,0xFE,0x6F,0xFF,0x11,0x01,0x36,0x04,0x2B,0xFD, + 0xA2,0x02,0x13,0xFD,0xCD,0xFF,0xEF,0x03,0xD5,0xFD,0x31,0x01, + 0xA0,0xFD,0xD4,0x00,0x96,0xFF,0xD7,0x00,0xAE,0xFF,0xA0,0xFD, + 0xB9,0x02,0x0F,0xFF,0x08,0x02,0x4F,0xFB,0x67,0x02,0x90,0x01, + 0xD3,0xFC,0xEC,0x01,0x91,0xFD,0xB1,0x03,0xF4,0xFC,0x30,0x01, + 0xD0,0x01,0x40,0xFF,0x0D,0x01,0x36,0xFE,0x5E,0x02,0xE3,0xFC, + 0xD6,0x02,0xD1,0xFE,0x4E,0x00,0xF3,0x00,0xF4,0xFB,0xF9,0x03, + 0xFB,0xFD,0x7C,0x00,0xF2,0xFD,0x24,0x01,0x89,0x00,0x56,0xFF, + 0x9C,0x01,0x32,0xFE,0x06,0x02,0x57,0xFD,0x67,0x03,0xA2,0xFF, + 0x2A,0xFE,0xA6,0xFF,0xC6,0xFF,0x5E,0x02,0xC8,0xFD,0xE8,0x01, + 0xDE,0xFD,0x1A,0xFF,0x55,0x02,0x12,0x00,0x0D,0x00,0x6A,0xFF, + 0x03,0x01,0xE7,0xFE,0xB5,0xFF,0x99,0x00,0xD0,0xFF,0xF3,0x02, + 0x7B,0xFC,0x6E,0xFE,0xDC,0x03,0xEC,0xFF,0xFB,0xFF,0x66,0xFE, + 0xEF,0xFF,0xF2,0xFC,0x75,0x01,0x13,0x01,0x57,0x00,0x79,0x02, + 0x53,0xFB,0x34,0x01,0xBA,0x00,0x2D,0x03,0xB8,0xFE,0x8F,0xFF, + 0xD0,0x00,0xFF,0xFC,0x98,0x03,0x09,0xFC,0xF1,0x00,0xFD,0x01, + 0x5E,0xFD,0x56,0x00,0x5E,0x01,0x57,0x02,0x5A,0xFB,0x3A,0x00, + 0xEC,0x01,0x88,0x00,0xE6,0x02,0x92,0xFB,0x70,0x00,0x68,0x01, + 0x1E,0x00,0x40,0x00,0xE7,0xFD,0x10,0x00,0x7C,0xFF,0x2B,0x02, + 0x39,0xFE,0x26,0x00,0x1C,0x01,0x99,0xFD,0x3F,0x02,0xD3,0x00, + 0x4D,0x01,0x6C,0xFD,0x73,0x00,0x0C,0x00,0x9B,0xFE,0xA4,0x01, + 0xB9,0xFE,0x63,0x00,0x7D,0xFF,0x7B,0x01,0xEB,0xFD,0xD0,0x00, + 0x24,0x00,0x07,0xFF,0x8F,0x02,0x11,0xFE,0x1D,0x01,0x9F,0xFF, + 0x07,0x00,0x6E,0x01,0x1A,0xFF,0x46,0x00,0xF8,0xFE,0x26,0x01, + 0xDB,0xFF,0xDB,0xFD,0xF8,0x00,0x77,0xFF,0x3C,0xFF,0x0B,0x01, + 0xFC,0x00,0xF9,0xFE,0x0D,0x00,0x3F,0x00,0xCB,0xFF,0x8F,0x02, + 0xEE,0x00,0xC5,0xFE,0x03,0xFF,0xBD,0x00,0x13,0xFF,0xA4,0x00, + 0xA5,0x00,0x9C,0xFE,0x36,0x00,0xD8,0xFE,0x81,0x00,0x27,0xFF, + 0xB9,0xFF,0x7F,0x00,0x14,0x00,0x24,0x00,0xE4,0xFE,0x38,0x01, + 0xDB,0xFE,0x4C,0x01,0xCB,0x01,0x52,0xFE,0x65,0x00,0x72,0x00, + 0x37,0x00,0x6F,0xFE,0xB3,0xFF,0x2B,0x01,0x37,0x00,0xCB,0xFF, + 0xD4,0xFF,0x4A,0x00,0x3C,0xFF,0xA5,0x00,0x4D,0x00,0xB5,0x00, + 0x8F,0xFF,0x83,0xFF,0x77,0x00,0x11,0xFF,0x14,0x00,0x0B,0x00, + 0xFE,0x00,0x31,0xFF,0x9A,0xFF,0x02,0x00,0x1C,0xFF,0xDD,0xFF, + 0x0E,0x00,0x38,0x01,0x19,0x00,0xB3,0xFF,0x3E,0x00,0xD4,0xFF, + 0xBE,0xFF,0x5A,0x00,0x19,0x01,0x14,0x00,0x8F,0xFF,0x34,0xFF, + 0x4B,0xFF,0x45,0x00,0xB4,0x00,0xC6,0x00,0x75,0xFF,0x52,0x00, + 0x73,0xFF,0x06,0xFF,0x36,0x01,0x42,0x00,0x35,0x00,0x6A,0x00, + 0xC3,0xFE,0x27,0x00,0x95,0xFF,0x9C,0x00,0xB2,0xFF,0x70,0x00, + 0xFB,0xFF,0x0A,0xFF,0x3E,0x01,0xF4,0xFB,0x32,0x06,0xEE,0xFD, + 0x3E,0xFE,0x17,0x08,0xC7,0xF9,0x9E,0x00,0x7E,0xFF,0x08,0xFB, + 0x37,0x01,0x5F,0x00,0x58,0xFE,0x39,0x00,0xA7,0x00,0xF2,0xFD, + 0x9D,0x00,0x92,0x01,0xD0,0x00,0x9F,0x02,0x7C,0x01,0x59,0x00, + 0x0C,0x00,0x85,0x00,0x6E,0x00,0x3A,0x00,0x37,0x01,0xD2,0xFE, + 0x81,0xFF,0x92,0xFF,0x45,0xFF,0xD9,0xFE,0x5A,0xFE,0x58,0x00, + 0x2E,0xFF,0x6B,0x01,0x3A,0x00,0x48,0xFE,0x4B,0x00,0x91,0x00, + 0x56,0x00,0x3F,0x00,0x4E,0x00,0xB1,0xFF,0x11,0x01,0xD0,0xFF, + 0x0B,0xFF,0xB0,0xFF,0x5B,0x00,0xD8,0xFE,0x4C,0x00,0x76,0x00, + 0xFE,0xFE,0xD7,0xFF,0xD7,0xFF,0xD2,0x00,0xE7,0xFD,0x1B,0x02, + 0xBC,0xFF,0x4B,0xFF,0xCC,0x02,0xB2,0xFE,0xBB,0x01,0x53,0x00, + 0x5F,0xFE,0xF7,0x00,0x46,0x00,0x7C,0x00,0x98,0x00,0xFE,0xFD, + 0xEB,0xFE,0x76,0x00,0x92,0x00,0xF9,0x00,0xE2,0xFF,0xF2,0xFE, + 0x70,0xFE,0x5B,0xFF,0x4C,0x01,0xD7,0x00,0xB1,0x00,0x80,0x00, + 0x61,0xFF,0x48,0xFF,0xDC,0xFF,0x85,0x00,0x88,0x00,0xCD,0x00, + 0x18,0x00,0x70,0xFF,0xF9,0xFF,0xB6,0xFF,0x2A,0xFF,0xFA,0xFF, + 0x92,0x00,0x1D,0x00,0x06,0x00,0xF3,0xFF,0x9B,0xFF,0x5A,0x00, + 0x9E,0xFF,0x75,0xFF,0x87,0x00,0x17,0x00,0xE9,0x00,0x5A,0x00, + 0x28,0xFF,0xB8,0xFF,0xA1,0xFF,0xCC,0xFF,0xAB,0x00,0x90,0xFF, + 0xA9,0xFF,0x1B,0x00,0xAC,0xFE,0xD1,0xFF,0x94,0xFF,0x88,0xFF, + 0x91,0x00,0xC6,0xFF,0xE5,0xFF,0xC6,0xFF,0x99,0xFF,0x29,0x00, + 0xA4,0x00,0xA9,0x00,0x8F,0x00,0x21,0x00,0x9E,0xFF,0xE5,0xFF, + 0x19,0x01,0x6B,0x00,0xE0,0xFF,0x90,0x00,0x34,0x00,0x71,0x00, + 0x03,0x00,0x33,0x00,0x52,0x00,0xD8,0x00,0x7B,0x00,0x9C,0xFF, + 0x9E,0x00,0x21,0x00,0x8F,0xFF,0x5F,0xFF,0x93,0xFF,0x90,0xFF, + 0x40,0xFF,0x2C,0xFF,0x79,0xFF,0x37,0x00,0xF8,0x00,0x33,0x02, + 0x0B,0x03,0xAE,0x03,0xCC,0x02,0xBA,0x00,0x3E,0xFF,0x7C,0xFD, + 0xB3,0xFC,0x24,0xFD,0xF2,0xFC,0x23,0xFD,0x64,0xFD,0x9A,0xFC, + 0x47,0xFC,0x1C,0xFC,0xEB,0xFB,0x21,0xFD,0xC7,0xFE,0x8F,0x00, + 0x8D,0x02,0xAB,0x03,0x79,0x04,0x81,0x04,0x20,0x04,0xD6,0x03, + 0xB8,0x03,0x6E,0x04,0xB5,0x04,0x8C,0x04,0xB1,0x03,0x93,0x01, + 0x55,0xFF,0x53,0xFD,0xC8,0xFB,0x6B,0xFB,0xAF,0xFB,0x7B,0xFC, + 0xB4,0xFD,0x5B,0xFE,0x84,0xFE,0x75,0xFE,0x84,0xFE,0xB3,0xFE, + 0x99,0xFF,0xDD,0x00,0x9E,0x01,0x24,0x02,0xCD,0x01,0x40,0x01, + 0x3A,0x01,0x97,0x00,0x3F,0x00,0x6D,0x00,0x7B,0x00,0x90,0x00, + 0x98,0xFF,0xF7,0xFE,0x6D,0xFE,0x6A,0xFD,0xDA,0xFD,0x7A,0xFF, + 0x26,0x02,0xC6,0x04,0xB4,0x06,0x16,0x07,0xDA,0x04,0xBE,0x01, + 0x42,0xFE,0x17,0xFB,0x81,0xFA,0xFB,0xFA,0x9F,0xFB,0x0B,0xFD, + 0xAE,0xFC,0x70,0xFB,0x3D,0xFA,0xE6,0xF8,0xF0,0xF8,0xAB,0xFA, + 0xB3,0xFD,0xE2,0x00,0x20,0x04,0x5B,0x06,0xD9,0x06,0xEC,0x06, + 0x58,0x06,0x69,0x05,0x9F,0x05,0xB0,0x05,0x67,0x05,0xB8,0x05, + 0xB7,0x04,0xE8,0x02,0x28,0x01,0xAE,0xFE,0x93,0xFC,0x4B,0xFB, + 0x9E,0xFA,0x84,0xFA,0x29,0xFB,0xCE,0xFB,0xFF,0xFB,0xD2,0xFC, + 0x3B,0xFD,0xA1,0xFD,0xF1,0xFE,0xE1,0xFF,0x24,0x01,0x64,0x02, + 0xAD,0x02,0xC7,0x02,0xA3,0x02,0x2F,0x02,0x9D,0x01,0x4F,0x01, + 0xE6,0x00,0x5D,0x00,0x08,0x00,0x1C,0xFF,0x6E,0xFE,0x12,0xFE, + 0x69,0xFD,0x11,0xFD,0x31,0xFD,0x3C,0xFF,0x77,0x02,0x86,0x05, + 0x53,0x08,0x54,0x08,0x3C,0x06,0xBE,0x02,0x87,0xFE,0x85,0xFB, + 0x2E,0xFA,0x9E,0xFA,0x34,0xFB,0x2B,0xFC,0xD3,0xFB,0x31,0xFA, + 0xC8,0xF8,0x4A,0xF7,0x64,0xF7,0x74,0xF9,0xD7,0xFC,0xB7,0x00, + 0x81,0x04,0xF0,0x06,0xBC,0x07,0xBD,0x07,0x15,0x07,0x69,0x06, + 0xAE,0x06,0xCD,0x06,0x0A,0x07,0x63,0x07,0xE9,0x05,0x08,0x04, + 0x40,0x01,0x0C,0xFE,0x8F,0xFB,0xE3,0xF9,0x71,0xF9,0x86,0xF9, + 0xB8,0xFA,0x31,0xFB,0xB4,0xFB,0x5A,0xFC,0x4E,0xFC,0x5B,0xFD, + 0x84,0xFE,0x0C,0x00,0xD7,0x01,0x3F,0x03,0xDB,0x03,0xD3,0x03, + 0x78,0x03,0x87,0x02,0x0C,0x02,0x99,0x01,0xEE,0x00,0x81,0x00, + 0xB2,0xFF,0xA9,0xFE,0xDC,0xFD,0x0F,0xFD,0x33,0xFC,0xBE,0xFB, + 0xD9,0xFD,0x92,0x01,0x31,0x05,0x0B,0x09,0xB4,0x09,0x8A,0x07, + 0xC1,0x03,0xF3,0xFE,0x60,0xFB,0x9B,0xF9,0x77,0xFA,0x25,0xFB, + 0x2B,0xFC,0xF2,0xFB,0x5A,0xF9,0xA3,0xF7,0x97,0xF5,0x94,0xF5, + 0x29,0xF8,0x16,0xFC,0xCF,0x00,0xD3,0x04,0x9E,0x07,0x28,0x08, + 0xE6,0x07,0x7E,0x07,0xD2,0x06,0xBB,0x07,0x71,0x08,0x7C,0x08, + 0xE1,0x08,0xDB,0x06,0xFA,0x03,0xFA,0x00,0x51,0xFD,0xFF,0xFA, + 0x95,0xF9,0x78,0xF9,0xA1,0xF9,0x68,0xFA,0xE5,0xFA,0x82,0xFA, + 0x60,0xFB,0x8B,0xFB,0xAE,0xFC,0xDD,0xFE,0x63,0x00,0x5F,0x02, + 0x9A,0x03,0xD8,0x03,0x8E,0x03,0x25,0x03,0x9A,0x02,0x34,0x02, + 0x55,0x02,0xB3,0x01,0x03,0x01,0x24,0x00,0x7F,0xFE,0x63,0xFD, + 0xA7,0xFC,0xF0,0xFB,0x8B,0xFB,0x35,0xFE,0x47,0x02,0xA1,0x05, + 0xA6,0x09,0x61,0x09,0x9D,0x06,0xEB,0x02,0x05,0xFE,0x78,0xFB, + 0x38,0xFA,0xC6,0xFB,0x2D,0xFC,0x3C,0xFC,0x80,0xFB,0x72,0xF7, + 0x20,0xF6,0x7F,0xF4,0x51,0xF5,0x6A,0xF9,0x46,0xFD,0x13,0x02, + 0xEF,0x04,0xD1,0x06,0xC3,0x06,0x67,0x06,0x46,0x07,0x77,0x07, + 0x7E,0x09,0x98,0x0A,0xA8,0x09,0xAE,0x08,0xD9,0x05,0x3C,0x02, + 0xD0,0xFF,0xBD,0xFD,0x4C,0xFC,0xEC,0xFB,0x52,0xFB,0x7E,0xFA, + 0xB1,0xF9,0x3D,0xF9,0xD2,0xF8,0xAF,0xF9,0xCC,0xFB,0x1B,0xFD, + 0x90,0xFF,0x08,0x01,0x49,0x01,0x5B,0x02,0x43,0x02,0x9B,0x02, + 0x32,0x03,0x91,0x03,0xAF,0x03,0x0D,0x03,0x63,0x02,0x8D,0x00, + 0x61,0xFF,0x6E,0xFE,0x76,0xFD,0x8E,0xFD,0x2F,0xFD,0xA4,0xFC, + 0x21,0xFD,0x8F,0x00,0xA8,0x03,0x01,0x07,0x7F,0x09,0x3C,0x07, + 0xBF,0x04,0x6D,0x00,0x26,0xFD,0xEB,0xFB,0xAD,0xFB,0x57,0xFD, + 0xF9,0xFB,0x92,0xFB,0xAA,0xF8,0x19,0xF5,0x3A,0xF5,0xB6,0xF4, + 0x4E,0xF8,0x70,0xFC,0xF6,0xFF,0x2D,0x03,0x1D,0x04,0x39,0x05, + 0xF0,0x04,0x73,0x06,0x7D,0x08,0xBD,0x09,0xC8,0x0B,0xAE,0x0A, + 0x84,0x08,0x78,0x06,0x25,0x03,0x0D,0x01,0x14,0x00,0xE3,0xFE, + 0xEC,0xFD,0x86,0xFC,0xBB,0xFA,0xE4,0xF8,0xF2,0xF7,0x6F,0xF8, + 0x07,0xF9,0x6A,0xFB,0x40,0xFD,0xE3,0xFD,0x89,0xFF,0x6E,0xFF, + 0x1F,0x00,0xAA,0x01,0x9C,0x02,0x0F,0x04,0x6C,0x04,0x68,0x04, + 0x38,0x03,0x21,0x02,0x2E,0x01,0xEA,0xFF,0xF5,0xFF,0x6A,0xFF, + 0xE0,0xFE,0x2A,0xFE,0xFB,0xFC,0x87,0xFB,0x4B,0xFD,0xB3,0x01, + 0x94,0x04,0xCE,0x08,0xC5,0x08,0x54,0x05,0xC9,0x01,0x1A,0xFD, + 0x18,0xFC,0xE2,0xFB,0x29,0xFE,0xE9,0xFE,0x56,0xFC,0x0C,0xFB, + 0xC4,0xF5,0x08,0xF4,0x55,0xF5,0x09,0xF7,0x6F,0xFC,0x84,0xFF, + 0xF5,0x01,0x2D,0x02,0x0C,0x02,0x25,0x03,0xE6,0x03,0x0A,0x08, + 0x6D,0x0A,0xAC,0x0B,0x67,0x0B,0x2F,0x08,0xF3,0x05,0x50,0x03, + 0x9E,0x02,0x68,0x02,0xB7,0x01,0xBE,0x00,0x9B,0xFD,0x3D,0xFB, + 0xAB,0xF8,0xB0,0xF7,0xD8,0xF8,0x18,0xFA,0xD5,0xFB,0xA0,0xFC, + 0xD1,0xFC,0x7D,0xFC,0xFD,0xFC,0xB2,0xFE,0xA4,0x00,0x12,0x03, + 0x58,0x04,0x2B,0x04,0x8C,0x03,0x5B,0x02,0xB7,0x01,0xE9,0x01, + 0x22,0x02,0x15,0x02,0x44,0x01,0xDE,0xFF,0xF3,0xFD,0xDF,0xFC, + 0xB8,0xFB,0x27,0xFB,0x6E,0x00,0xFB,0x04,0x73,0x06,0x30,0x09, + 0xAA,0x06,0x95,0x00,0x43,0xFD,0x0C,0xFD,0xC1,0xFE,0x94,0x01, + 0x35,0x03,0xED,0xFC,0xCD,0xF5,0xB8,0xF2,0xE8,0xEE,0xB9,0xF3, + 0x50,0xFB,0xE8,0xFC,0xDA,0xFD,0xDC,0xFC,0xD2,0xFB,0x87,0xFE, + 0xA6,0x07,0x46,0x0E,0x0F,0x10,0xEA,0x10,0xD8,0x0A,0xAF,0x05, + 0xC6,0x07,0x72,0x0B,0xA5,0x09,0x3E,0x06,0xC3,0xFF,0xF3,0xF3, + 0xD0,0xF2,0x2C,0xF5,0x23,0xF6,0xB5,0xF9,0x52,0xF8,0xB6,0xF5, + 0x5F,0xF7,0x84,0xFE,0xC3,0x02,0x14,0x07,0x8F,0x09,0x9E,0x03, + 0xE3,0x03,0xC9,0x05,0xE2,0x05,0x56,0x06,0x4A,0x03,0xF5,0xFD, + 0xAF,0xF9,0xE0,0xFB,0xE6,0xFB,0x79,0xFC,0xBC,0xFD,0x34,0xFA, + 0x85,0xF9,0xCD,0xFB,0xC1,0xFD,0xD1,0xFD,0xAB,0x0D,0x88,0x1A, + 0x58,0x10,0x94,0x0F,0x4A,0x09,0xF5,0xFA,0xE3,0xFE,0xC6,0xFF, + 0x48,0xF4,0xD1,0xEB,0xA8,0xE9,0x00,0xE5,0x26,0xEA,0x13,0xF7, + 0x83,0xF3,0x44,0xF5,0x6F,0xFE,0x88,0x01,0xBB,0x0B,0x5E,0x16, + 0x0F,0x16,0x90,0x10,0xD6,0x13,0xF7,0x12,0x55,0x0E,0x06,0x10, + 0x42,0x05,0x9D,0xF8,0x3E,0xF7,0x4C,0xF7,0xB1,0xF2,0x6B,0xF2, + 0x39,0xF3,0x83,0xED,0x57,0xF5,0xE9,0xFD,0xDA,0xFE,0x00,0x05, + 0xD4,0x06,0x42,0x07,0xF5,0x0A,0x69,0x0E,0xBD,0x09,0xBD,0x05, + 0x5B,0x05,0x9A,0xFE,0x8F,0xFE,0x27,0xFE,0xB4,0xF7,0x00,0xF5, + 0x86,0xF5,0x50,0xF6,0x89,0xF8,0xC2,0xFD,0xA3,0xFC,0x9A,0xFD, + 0xAF,0x03,0x8E,0x04,0x38,0x07,0xE4,0x07,0x03,0x05,0xBC,0x00, + 0x1F,0x00,0x89,0x13,0x21,0x1C,0x84,0x09,0xDE,0x02,0x3A,0xFD, + 0xAE,0xF2,0xFA,0xFA,0xC2,0xF9,0xDB,0xE8,0x63,0xE3,0xAD,0xEA, + 0xFC,0xEF,0xD4,0xF5,0x44,0xFD,0xF5,0xF5,0x7B,0xFA,0x96,0x0B, + 0x3A,0x10,0x74,0x12,0x97,0x12,0xE4,0x0E,0x75,0x0C,0xD3,0x13, + 0xE8,0x10,0x62,0x03,0x7E,0xFF,0x77,0xF8,0x3F,0xF8,0x0D,0xFC, + 0xFE,0xF5,0xCF,0xEE,0x72,0xF1,0x28,0xF9,0x54,0xFB,0x25,0x01, + 0x4C,0x01,0x1D,0xFF,0x37,0x07,0xD0,0x0C,0xFB,0x0B,0x05,0x08, + 0x3D,0x05,0xF5,0x01,0xFE,0x02,0x55,0x03,0x57,0xFB,0xF7,0xF7, + 0xB2,0xF7,0x50,0xF7,0x20,0xF9,0x67,0xF9,0xF6,0xF7,0xD3,0xFA, + 0x48,0x01,0x37,0x03,0x08,0x04,0x27,0x05,0x90,0x03,0x20,0x05, + 0x67,0x07,0x79,0x01,0x7C,0xFC,0x86,0x11,0xC9,0x1C,0x2F,0x04, + 0x78,0x00,0x5B,0x02,0x36,0xF4,0x4A,0xF9,0x32,0xFA,0x79,0xE7, + 0x70,0xE3,0x60,0xF1,0x72,0xF3,0x21,0xF2,0xD4,0xF9,0xC8,0xF6, + 0xEE,0xFC,0x02,0x0F,0x5D,0x10,0xEC,0x0A,0xF2,0x0E,0x53,0x13, + 0x6E,0x0F,0xB9,0x12,0xB3,0x0D,0x65,0xFF,0x24,0x00,0xA7,0xFE, + 0x37,0xFA,0x4C,0xF9,0x2A,0xF3,0xF4,0xEE,0x64,0xF6,0xA6,0xFC, + 0xD3,0xF9,0x9A,0xFC,0xB2,0x00,0x10,0x03,0x04,0x09,0xE6,0x0B, + 0xC8,0x07,0x15,0x05,0x84,0x07,0x05,0x05,0x52,0x02,0x70,0xFF, + 0xEE,0xF9,0x6D,0xF9,0xF3,0xFA,0xEC,0xF8,0x28,0xF6,0xA2,0xF7, + 0x90,0xF9,0x29,0xFE,0x02,0x02,0x7E,0x00,0x33,0x02,0x7A,0x05, + 0x89,0x06,0xF4,0x04,0x28,0x05,0xFE,0xFE,0xED,0xFE,0xEE,0x1B, + 0xA0,0x1A,0xFB,0xFA,0x48,0x00,0xFD,0x04,0x35,0xF7,0x27,0xF8, + 0x35,0xF3,0xE5,0xE2,0x0E,0xE7,0x46,0xF7,0x55,0xF1,0x55,0xED, + 0x6E,0xF8,0x5B,0xFA,0x66,0x03,0xA6,0x0F,0x6A,0x0D,0x2C,0x09, + 0xA8,0x12,0xD1,0x18,0x45,0x0F,0xED,0x0E,0x36,0x0A,0x95,0x01, + 0x60,0x02,0xAA,0xFD,0x83,0xF5,0xA8,0xF1,0xCE,0xF7,0xD4,0xF5, + 0xA2,0xF1,0xED,0xF9,0x48,0xFB,0x04,0xFD,0x25,0x04,0x93,0x06, + 0x74,0x05,0x5A,0x09,0x4A,0x0C,0xF0,0x06,0x0F,0x06,0x50,0x04, + 0x66,0xFF,0x7E,0xFE,0xC6,0xFC,0xED,0xF8,0x4A,0xF7,0xDA,0xF8, + 0x75,0xF7,0x0B,0xF7,0x52,0xFB,0x69,0xFE,0xB5,0xFF,0xE0,0x01, + 0x75,0x04,0x30,0x05,0x75,0x06,0x71,0x05,0xC4,0x03,0xE7,0xFE, + 0xE7,0x02,0xFE,0x1D,0x07,0x16,0x89,0xF7,0x23,0x02,0xC8,0x06, + 0x92,0xF8,0x5D,0xF4,0x67,0xEE,0x3F,0xE6,0xA5,0xEB,0xF6,0xF6, + 0xF0,0xEC,0xDB,0xEB,0x4A,0xFB,0x7F,0xFE,0xF5,0x03,0x32,0x0A, + 0xAE,0x0C,0x93,0x0D,0xDD,0x14,0x17,0x17,0x8A,0x0C,0x53,0x0E, + 0x9A,0x0C,0x49,0x04,0xE8,0xFF,0x2D,0xFA,0x89,0xF6,0xE5,0xF6, + 0x9C,0xF5,0x3C,0xEF,0x17,0xF5,0x11,0xFB,0x3C,0xFA,0x3D,0xFE, + 0xCA,0x01,0x99,0x06,0x58,0x08,0xBB,0x0A,0x57,0x09,0xF4,0x06, + 0x2A,0x08,0x8C,0x03,0x2C,0x01,0xC1,0xFD,0xFB,0xFA,0xCE,0xF9, + 0x8F,0xF8,0xDD,0xF7,0x43,0xF5,0xC4,0xF8,0x47,0xFB,0x08,0xFD, + 0x08,0x00,0x5C,0x01,0x06,0x04,0x96,0x05,0x88,0x06,0x45,0x04, + 0xC9,0x04,0xCD,0xFF,0x8B,0x04,0x10,0x20,0x75,0x12,0x45,0xF6, + 0xC1,0x04,0x00,0x08,0x07,0xF8,0x89,0xF1,0xC8,0xED,0x56,0xE9, + 0x5C,0xED,0xA0,0xF4,0x55,0xEA,0x5F,0xEC,0x89,0xFD,0x1F,0xFF, + 0x78,0x01,0x81,0x07,0xF8,0x0D,0xDC,0x10,0xE6,0x13,0xD2,0x14, + 0x25,0x0D,0x32,0x10,0x75,0x0E,0x7F,0x04,0x8A,0xFE,0x8E,0xFA, + 0xA7,0xF8,0xDA,0xF3,0xDB,0xF4,0x7D,0xF4,0x1F,0xF2,0x88,0xF7, + 0xE4,0xFC,0xAB,0xFD,0x8C,0xFF,0xEF,0x06,0x95,0x08,0x65,0x08, + 0x51,0x0A,0x08,0x09,0xE2,0x06,0x88,0x04,0x21,0x02,0x72,0xFD, + 0x19,0xFC,0xDF,0xFA,0xFD,0xF7,0x87,0xF7,0x91,0xF6,0xB6,0xF7, + 0xD1,0xF9,0xAF,0xFD,0x52,0xFF,0xAE,0xFF,0x78,0x04,0x20,0x06, + 0x8D,0x05,0x8B,0x04,0x16,0x05,0x2C,0x00,0x8D,0x05,0x36,0x21, + 0xB8,0x11,0x80,0xF4,0x44,0x07,0x0F,0x09,0x80,0xF7,0xF3,0xF0, + 0x3A,0xEC,0x2C,0xEC,0x17,0xEE,0x7A,0xF2,0xD4,0xE8,0x05,0xEC, + 0xD1,0xFE,0x4A,0xFE,0xA8,0x00,0x38,0x05,0x87,0x0E,0xB0,0x13, + 0x4A,0x12,0x36,0x14,0x04,0x0E,0xF7,0x11,0x7E,0x0F,0xB1,0x04, + 0x69,0xFE,0xAB,0xFA,0x0B,0xFA,0x9B,0xF4,0x75,0xF4,0xFA,0xEE, + 0xC0,0xF2,0x9C,0xFB,0x63,0xF8,0x9D,0xFC,0xE0,0xFF,0x2C,0x07, + 0xDB,0x09,0x7C,0x08,0x32,0x0A,0x2C,0x08,0xAB,0x0A,0xDA,0x04, + 0xE4,0x00,0x2D,0xFF,0xE8,0xFB,0xBC,0xFB,0xEC,0xF6,0x1F,0xF7, + 0x95,0xF6,0xE7,0xF7,0xE5,0xF9,0x3E,0xFA,0xA3,0xFF,0xFE,0xFF, + 0x70,0x02,0xA3,0x05,0x59,0x05,0xBA,0x05,0xC9,0x04,0xD1,0x02, + 0x84,0x00,0xC9,0x15,0xD0,0x1E,0xD3,0xFB,0x58,0xFC,0x59,0x0E, + 0x0F,0xFE,0xE9,0xF3,0x11,0xEE,0x00,0xEC,0x0B,0xEF,0x35,0xF1, + 0x26,0xED,0x6C,0xE6,0xE6,0xF8,0xC0,0xFF,0x42,0xFC,0x9D,0x02, + 0x9D,0x08,0xB0,0x13,0x0D,0x12,0x6E,0x12,0xBE,0x10,0x34,0x10, + 0x4F,0x14,0x5F,0x08,0xAF,0x01,0xB0,0xFC,0x93,0xFC,0xDA,0xF6, + 0x92,0xF0,0xFA,0xF6,0xE9,0xEF,0x28,0xF4,0x6C,0xFB,0x4F,0xF9, + 0xF3,0xFD,0xFB,0x02,0x7C,0x08,0x61,0x07,0xD6,0x09,0xFD,0x0A, + 0xCF,0x07,0xAF,0x08,0x4D,0x03,0x67,0x00,0xDC,0xFE,0xE6,0xFB, + 0xAD,0xF9,0xE2,0xF6,0x8D,0xF7,0x06,0xF7,0x47,0xF8,0x56,0xFA, + 0xE9,0xFB,0xB9,0xFF,0xBD,0x00,0xD2,0x02,0xE8,0x04,0x70,0x06, + 0x39,0x05,0x33,0x03,0xC0,0x02,0xB2,0x03,0xFA,0x1B,0xFC,0x16, + 0xCA,0xF4,0x11,0x05,0x11,0x0C,0x53,0xFA,0x7F,0xF3,0xC5,0xEB, + 0xE6,0xEE,0x66,0xF0,0xC5,0xF1,0x4B,0xE8,0xDF,0xE9,0xC5,0xFE, + 0x11,0xFC,0x8A,0xFD,0x2C,0x02,0xDF,0x0A,0xC5,0x14,0xFF,0x10, + 0xB8,0x11,0xA5,0x0E,0xD4,0x14,0x13,0x12,0x83,0x05,0xA3,0x01, + 0x12,0xFD,0xD6,0xFD,0x34,0xF4,0xCD,0xF0,0xDA,0xF2,0x9B,0xF5, + 0xEA,0xF9,0x30,0xF2,0xF7,0xFA,0x78,0x02,0x53,0x03,0xA2,0x06, + 0x08,0x05,0xF4,0x0A,0x10,0x0B,0x66,0x09,0x1D,0x05,0xBC,0x01, + 0xD7,0x03,0x2E,0xFE,0x76,0xFB,0x41,0xF8,0xA2,0xF7,0x61,0xF9, + 0xFE,0xF6,0x6E,0xF7,0x2C,0xF9,0xAE,0xFE,0xFF,0xFF,0x76,0xFF, + 0xC1,0x02,0x04,0x04,0xAF,0x07,0x4E,0x04,0xC4,0x01,0xBE,0x02, + 0x9C,0x08,0xE9,0x1F,0x7F,0x0E,0xC2,0xF4,0xDF,0x0A,0x54,0x09, + 0x5B,0xF9,0x35,0xF1,0xC3,0xEB,0x2F,0xF1,0x9D,0xF0,0xA1,0xEF, + 0x32,0xE5,0x9B,0xEE,0x96,0xFF,0x4F,0xF9,0x0D,0xFE,0x7D,0x02, + 0x88,0x0D,0x7C,0x14,0x60,0x10,0x0F,0x11,0xF0,0x0F,0xB9,0x17, + 0x00,0x0F,0x74,0x04,0x92,0x02,0xC2,0xFD,0x82,0xFD,0xAA,0xF1, + 0xBF,0xF0,0x34,0xF3,0xE2,0xF5,0x05,0xFA,0x43,0xF1,0xD0,0xFA, + 0x43,0x04,0xF1,0x03,0x0C,0x05,0x45,0x05,0xF8,0x0B,0xC8,0x0B, + 0xB7,0x08,0x42,0x04,0x39,0x02,0x6D,0x04,0x23,0xFE,0xE7,0xF9, + 0x66,0xF8,0x70,0xF8,0x84,0xF9,0xAA,0xF6,0xB7,0xF6,0xF9,0xF9, + 0xCC,0xFE,0x8C,0xFF,0x10,0xFF,0xD4,0x02,0x6A,0x04,0x51,0x07, + 0xD2,0x03,0xF7,0x01,0xB5,0x03,0xED,0x08,0x72,0x20,0x37,0x0D, + 0xDF,0xF4,0xDF,0x0C,0x95,0x07,0x9F,0xF9,0x3A,0xF2,0x6E,0xEB, + 0x47,0xF1,0xD2,0xF0,0xD2,0xEF,0xC2,0xE3,0x76,0xEF,0x60,0xFF, + 0xBD,0xF7,0x8D,0xFE,0x2F,0x02,0x25,0x0D,0x14,0x14,0xED,0x10, + 0xD0,0x10,0xB0,0x0F,0x28,0x19,0xB2,0x0E,0xB1,0x04,0x88,0x03, + 0xBB,0xFD,0xA8,0xFD,0x8A,0xF1,0x41,0xF2,0x98,0xF5,0xDE,0xF1, + 0x54,0xF6,0x56,0xF5,0xE9,0xFA,0xBE,0x00,0x83,0x03,0x68,0x05, + 0x1B,0x06,0x7C,0x0C,0x75,0x0B,0xE5,0x07,0x30,0x06,0xDB,0x03, + 0x47,0x03,0x1B,0xFF,0x80,0xFA,0x96,0xF8,0x16,0xF9,0xD7,0xF8, + 0xE1,0xF5,0xDB,0xF6,0x30,0xFA,0xC3,0xFC,0x8E,0xFE,0xFA,0xFE, + 0x66,0x02,0x81,0x04,0x42,0x06,0x99,0x04,0x9C,0x02,0x9E,0x04, + 0xCC,0x07,0x08,0x1E,0x43,0x12,0x32,0xF5,0x75,0x0A,0x31,0x0A, + 0x1F,0xFA,0xFB,0xF3,0xC1,0xEB,0x58,0xF0,0xD3,0xF0,0xA6,0xF0, + 0x34,0xE4,0xF9,0xEB,0x2F,0xFF,0x4A,0xF7,0xBD,0xFC,0x54,0x02, + 0xA4,0x0A,0x46,0x13,0xC5,0x11,0x85,0x11,0xA3,0x0E,0x21,0x19, + 0x00,0x12,0xF7,0x04,0xE2,0x04,0x2B,0xFF,0xF8,0xFD,0xFC,0xF3, + 0xAA,0xF1,0x67,0xF2,0xC9,0xF3,0xB2,0xFA,0xBD,0xF0,0xEA,0xF6, + 0x0A,0x03,0x53,0x02,0xB3,0x03,0xB9,0x04,0x52,0x0A,0x85,0x0B, + 0x89,0x0A,0x5A,0x06,0x63,0x02,0x20,0x06,0x0E,0x01,0x2F,0xFB, + 0xFC,0xF9,0xBE,0xF8,0x4F,0xF9,0xAB,0xF7,0x2E,0xF6,0xEF,0xF6, + 0xD2,0xFB,0xEB,0xFF,0x88,0xFE,0x62,0xFF,0x5F,0x03,0xBE,0x07, + 0xB3,0x03,0xCB,0x02,0x89,0x05,0x48,0x07,0xE7,0x20,0xDC,0x12, + 0xE0,0xF3,0x89,0x0B,0x37,0x0B,0x2A,0xFB,0x70,0xF3,0xCE,0xEB, + 0xCA,0xEF,0x7D,0xF0,0xF8,0xF1,0xA7,0xE1,0x0F,0xEA,0x7E,0xFF, + 0x27,0xF7,0x97,0xFB,0xC0,0x00,0x04,0x0B,0xC4,0x12,0xD7,0x12, + 0x48,0x12,0x6B,0x0D,0xD7,0x1A,0xFA,0x13,0x30,0x06,0xEB,0x04, + 0xE9,0xFF,0x8B,0xFF,0xD4,0xF3,0x3D,0xF3,0x5E,0xF4,0x17,0xF0, + 0x5C,0xF6,0xCB,0xF3,0x8F,0xF6,0xEB,0xFD,0xD5,0x01,0x81,0x03, + 0xD6,0x04,0xAD,0x0A,0xA1,0x0A,0x74,0x0A,0xC2,0x08,0xB4,0x04, + 0x39,0x05,0xD9,0x02,0x95,0xFD,0x26,0xFA,0xDC,0xF9,0x2D,0xF9, + 0xCB,0xF6,0x5C,0xF6,0x1A,0xF7,0xE0,0xF9,0x37,0xFD,0x2E,0xFE, + 0x76,0xFF,0xAF,0x01,0x0E,0x06,0xB2,0x03,0x59,0x03,0xC8,0x06, + 0xEE,0x04,0x48,0x1D,0xF9,0x17,0x43,0xF7,0x14,0x09,0xBF,0x0B, + 0xDA,0xFD,0x0F,0xF7,0xDB,0xED,0x4F,0xEF,0x41,0xEF,0x3D,0xF4, + 0xA6,0xE4,0x43,0xE6,0x97,0xFB,0xFA,0xF6,0xA3,0xFA,0x17,0xFE, + 0x13,0x07,0x85,0x0F,0xF6,0x11,0xBD,0x13,0x5D,0x0C,0x4B,0x18, + 0x00,0x17,0xF8,0x0A,0xA2,0x07,0xD7,0x01,0x44,0x02,0x25,0xF8, + 0x8A,0xF5,0xCF,0xF2,0xE1,0xF0,0xE2,0xF9,0x2E,0xF1,0xA3,0xF1, + 0xED,0xFB,0x22,0xFF,0x64,0x00,0xAE,0x01,0xF0,0x06,0x44,0x08, + 0xA6,0x0B,0xE6,0x09,0x72,0x04,0x58,0x07,0xFB,0x05,0x4C,0x01, + 0x9D,0xFD,0x87,0xFB,0xC3,0xFA,0xA6,0xF9,0xF1,0xF7,0x2F,0xF5, + 0x83,0xF8,0x28,0xFC,0xFF,0xFB,0xAE,0xFD,0x7E,0xFE,0x78,0x02, + 0xC7,0x03,0x09,0x02,0x76,0x05,0xCD,0x01,0x29,0x13,0x38,0x20, + 0x49,0x01,0xCB,0x01,0x18,0x0E,0xE4,0x03,0x12,0xFF,0x86,0xF3, + 0x38,0xEF,0xDF,0xEF,0x59,0xF6,0x46,0xED,0x2A,0xE1,0xE4,0xF2, + 0x29,0xF6,0x30,0xF7,0xFB,0xFA,0x39,0xFD,0xA0,0x07,0xFC,0x0D, + 0x5E,0x13,0xEB,0x0B,0x19,0x11,0x85,0x19,0x05,0x12,0xE8,0x0E, + 0xA2,0x06,0xFE,0x05,0xF9,0x01,0x16,0xFD,0x6D,0xF9,0xD3,0xF0, + 0xED,0xF8,0x3F,0xF4,0x9A,0xEF,0x8C,0xF5,0xDE,0xF5,0x1D,0xFB, + 0xFD,0xFC,0x46,0x00,0x39,0x01,0x0D,0x06,0xA3,0x0A,0xF0,0x05, + 0x28,0x08,0xE8,0x07,0xAC,0x06,0x8C,0x05,0xD1,0x01,0x60,0xFF, + 0x0B,0xFD,0x12,0xFD,0xE1,0xF8,0xA9,0xF7,0x2C,0xFB,0xEC,0xF9, + 0x68,0xFA,0xEF,0xFB,0x85,0xFD,0x58,0xFF,0xDA,0xFE,0x55,0x02, + 0xEC,0xFF,0x17,0x0B,0x92,0x1B,0x43,0x05,0xE9,0x01,0x90,0x0D, + 0xDD,0x04,0xCE,0x04,0x85,0xFC,0x1C,0xF6,0xAB,0xF3,0x10,0xF9, + 0x6D,0xF7,0x07,0xE8,0x7C,0xF1,0x83,0xF3,0x28,0xF5,0xD3,0xF9, + 0xDA,0xF7,0x8F,0xFD,0xEE,0x01,0x07,0x0C,0x62,0x08,0xE4,0x08, + 0x69,0x10,0x20,0x0E,0x97,0x11,0x4C,0x0C,0xB1,0x09,0xBA,0x07, + 0x1D,0x05,0xC9,0x05,0x24,0x00,0xA4,0xFC,0x87,0xF8,0xEB,0xFA, + 0x1D,0xF9,0x55,0xF6,0x78,0xF7,0xED,0xF5,0x1A,0xFA,0x4A,0xFA, + 0xDA,0xFB,0x33,0xFC,0xA9,0xFE,0xE2,0x02,0x57,0x02,0xE5,0x04, + 0x89,0x03,0xED,0x04,0xAE,0x05,0x57,0x04,0x65,0x03,0x9D,0x00, + 0x0A,0x02,0x5F,0x00,0x68,0xFF,0xEA,0xFE,0x17,0xFD,0x19,0xFE, + 0x4C,0xFD,0x53,0xFD,0xCC,0xFC,0x9B,0xFC,0xF5,0xFD,0x67,0xFD, + 0x44,0x00,0x88,0x06,0xB9,0x01,0xA9,0xFE,0x42,0x04,0xF9,0x01, + 0x8E,0x03,0xA0,0x02,0x63,0x00,0x6D,0xFF,0x41,0xFE,0x5F,0x01, + 0x74,0xFB,0xFD,0xFB,0xEE,0xFB,0xC2,0xFA,0x07,0xFE,0xB5,0xFB, + 0x37,0xFD,0xB4,0xFB,0xCB,0xFE,0x74,0x00,0x5E,0xFF,0x6A,0x02, + 0xD2,0x00,0xAC,0x03,0xCB,0x03,0x1C,0x04,0x3A,0x04,0xE2,0x02, + 0xD7,0x04,0x42,0x03,0x6F,0x04,0x9D,0x02,0xA2,0x02,0x8B,0x02, + 0xF9,0xFF,0xF8,0x01,0x8F,0xFF,0xB0,0xFF,0xAA,0xFE,0xD1,0xFD, + 0x37,0xFE,0xCA,0xFC,0x79,0xFE,0xB9,0xFC,0xBD,0xFD,0x01,0xFE, + 0x05,0xFE,0xF6,0xFE,0x37,0xFE,0x97,0xFF,0x90,0xFE,0x25,0x00, + 0xDF,0xFF,0x56,0xFF,0x86,0x00,0xAC,0xFF,0x96,0x00,0xD4,0xFF, + 0x16,0x00,0xAD,0xFF,0x98,0xFF,0x6F,0x00,0x84,0xFF,0xB6,0xFF, + 0x7B,0xFF,0xC1,0xFF,0x76,0x00,0x8D,0x03,0x44,0x02,0x28,0x00, + 0x2C,0x03,0xA0,0x01,0x0E,0x02,0x7B,0x01,0x39,0x00,0x57,0x00, + 0x99,0xFF,0xF7,0x00,0x2C,0xFE,0x41,0xFE,0xE5,0xFD,0xB0,0xFC, + 0x00,0xFE,0xDE,0xFC,0x78,0xFD,0x8D,0xFC,0xB4,0xFD,0x78,0xFE, + 0x4C,0xFE,0x29,0x00,0x75,0xFF,0xE5,0x00,0x73,0x01,0xD9,0x01, + 0x2D,0x02,0x9C,0x01,0xC8,0x02,0x73,0x02,0xCE,0x02,0x20,0x02, + 0xE8,0x01,0x42,0x02,0xDB,0x01,0x56,0x02,0x45,0x01,0x33,0x01, + 0xFF,0x00,0xC5,0x00,0x86,0x00,0x8A,0xFF,0x66,0xFF,0xD0,0xFE, + 0x15,0xFF,0x93,0xFE,0x3C,0xFE,0x39,0xFE,0xF5,0xFD,0x8C,0xFE, + 0x41,0xFE,0x95,0xFE,0x7E,0xFE,0x8C,0xFE,0x28,0xFF,0x41,0xFF, + 0x6D,0xFF,0x35,0xFF,0xAF,0xFF,0xB5,0xFF,0xCC,0xFF,0xF7,0xFF, + 0xBE,0xFF,0xD1,0xFF,0xC8,0xFF,0xA8,0x01,0x07,0x02,0x8A,0x00, + 0x63,0x01,0x86,0x01,0x7E,0x01,0x2B,0x02,0x61,0x01,0xBA,0x00, + 0xDB,0x00,0x2A,0x01,0x56,0x00,0x5F,0xFF,0x0F,0xFF,0x1D,0xFE, + 0x05,0xFE,0x2E,0xFE,0xA3,0xFD,0x0C,0xFD,0x46,0xFD,0xFA,0xFD, + 0x34,0xFE,0x08,0xFF,0x5A,0xFF,0x78,0xFF,0x5F,0x00,0xFE,0x00, + 0x2B,0x01,0x2A,0x01,0x9E,0x01,0x97,0x01,0xB5,0x01,0x10,0x02, + 0xC3,0x01,0xC7,0x01,0xD1,0x01,0x50,0x02,0xF3,0x01,0x68,0x01, + 0xDB,0x01,0x4A,0x01,0x4A,0x01,0x1F,0x01,0x59,0x00,0x0D,0x00, + 0xB5,0xFF,0x86,0xFF,0xDC,0xFE,0x9E,0xFE,0x4F,0xFE,0xE7,0xFD, + 0x48,0xFE,0x10,0xFE,0xDC,0xFD,0x1F,0xFE,0x4A,0xFE,0x70,0xFE, + 0xD2,0xFE,0x18,0xFF,0x23,0xFF,0x6E,0xFF,0xA4,0xFF,0xD6,0xFF, + 0xE2,0xFF,0x13,0x00,0x1D,0x00,0x25,0x00,0x6F,0x00,0x81,0x00, + 0x6C,0x01,0x78,0x01,0xF3,0x00,0x8A,0x01,0x81,0x01,0xAE,0x01, + 0xE0,0x01,0x60,0x01,0x29,0x01,0xF5,0x00,0xE5,0x00,0x54,0x00, + 0x95,0xFF,0x29,0xFF,0x77,0xFE,0x44,0xFE,0x1C,0xFE,0xAD,0xFD, + 0x6D,0xFD,0x9D,0xFD,0x08,0xFE,0x4D,0xFE,0xBF,0xFE,0x32,0xFF, + 0x9C,0xFF,0x11,0x00,0x94,0x00,0xCD,0x00,0xF4,0x00,0x2F,0x01, + 0x2D,0x01,0x83,0x01,0x85,0x01,0x63,0x01,0x7D,0x01,0x70,0x01, + 0xA0,0x01,0x7F,0x01,0x74,0x01,0x93,0x01,0x37,0x01,0x44,0x01, + 0x4B,0x01,0xAE,0x00,0x6A,0x00,0x70,0x00,0x12,0x00,0xD6,0xFF, + 0xAA,0xFF,0x1C,0xFF,0xD7,0xFE,0xC8,0xFE,0x79,0xFE,0x16,0xFE, + 0x10,0xFE,0x03,0xFE,0xF2,0xFD,0x53,0xFE,0x58,0xFE,0x62,0xFE, + 0xB2,0xFE,0x04,0xFF,0x56,0xFF,0x85,0xFF,0xCE,0xFF,0xEA,0xFF, + 0x2D,0x00,0x7B,0x00,0x82,0x00,0xA4,0x00,0xC8,0x00,0xD4,0x00, + 0xF5,0x00,0x55,0x01,0x99,0x01,0x65,0x01,0x31,0x01,0x76,0x01, + 0x78,0x01,0x73,0x01,0x93,0x01,0x0D,0x01,0xD8,0x00,0xC0,0x00, + 0x67,0x00,0xED,0xFF,0x56,0xFF,0xF7,0xFE,0x60,0xFE,0x3E,0xFE, + 0x13,0xFE,0xB4,0xFD,0xC9,0xFD,0xFA,0xFD,0x51,0xFE,0x90,0xFE, + 0x06,0xFF,0x4F,0xFF,0x89,0xFF,0x21,0x00,0x3D,0x00,0x78,0x00, + 0xD0,0x00,0xCF,0x00,0xE9,0x00,0x16,0x01,0x25,0x01,0x2F,0x01, + 0x3D,0x01,0x43,0x01,0x68,0x01,0x54,0x01,0x52,0x01,0x3F,0x01, + 0x0A,0x01,0x1B,0x01,0xDA,0x00,0xA7,0x00,0x75,0x00,0x32,0x00, + 0x09,0x00,0xD2,0xFF,0xA9,0xFF,0x66,0xFF,0x3A,0xFF,0x32,0xFF, + 0x3B,0xFF,0xEF,0xFE,0xFF,0xFE,0x12,0xFF,0xA6,0xFE,0x2F,0xFF, + 0x23,0xFF,0xDB,0xFE,0x37,0xFF,0x19,0xFF,0x1F,0xFF,0x36,0xFF, + 0x57,0xFF,0x31,0xFF,0x5C,0xFF,0xAB,0xFF,0x84,0xFF,0xE0,0xFF, + 0x00,0x00,0x10,0x00,0x4F,0x00,0x8F,0x00,0xB6,0x00,0xA5,0x00, + 0xF3,0x00,0xE9,0x00,0xE1,0x00,0x00,0x01,0xE6,0x00,0xE5,0x00, + 0xCE,0x00,0xDA,0x00,0xAD,0x00,0x9F,0x00,0x98,0x00,0x60,0x00, + 0x4C,0x00,0x38,0x00,0x22,0x00,0xF0,0xFF,0xF1,0xFF,0xBE,0xFF, + 0xA7,0xFF,0xB4,0xFF,0x8D,0xFF,0x8E,0xFF,0x7B,0xFF,0x88,0xFF, + 0x7D,0xFF,0x81,0xFF,0x8F,0xFF,0x87,0xFF,0x9B,0xFF,0x9D,0xFF, + 0xB9,0xFF,0xB3,0xFF,0xCF,0xFF,0xDC,0xFF,0xE0,0xFF,0x03,0x00, + 0x05,0x00,0x18,0x00,0x17,0x00,0x28,0x00,0x19,0x00,0xFE,0xFF, + 0x26,0x00,0x32,0x00,0xE8,0xFF,0xED,0xFF,0xF5,0xFF,0x09,0x00, + 0x23,0x00,0xC9,0xFF,0x34,0x00,0x47,0x00,0xEE,0xFF,0x4C,0x00, + 0x65,0x00,0x52,0x00,0x4D,0x00,0x60,0x00,0x76,0x00,0x58,0x00, + 0x77,0x00,0x5D,0x00,0x54,0x00,0x74,0x00,0x15,0x00,0x1D,0x00, + 0x34,0x00,0xE2,0xFF,0x08,0x00,0xF9,0xFF,0x98,0xFF,0xE2,0xFF, + 0xA5,0xFF,0x5A,0xFF,0xB3,0xFF,0x7E,0xFF,0x77,0xFF,0xB0,0xFF, + 0xA4,0xFF,0x72,0xFF,0x9D,0xFF,0xCF,0xFF,0xB6,0xFF,0x24,0x00, + 0xA7,0xFF,0x20,0x00,0xE5,0xFF,0x00,0x00,0x17,0x00,0xE9,0xFF, + 0x6E,0xFF,0x2C,0xFF,0x76,0x04,0xF5,0xFD,0xE1,0xFD,0x72,0x02, + 0x01,0xFB,0xEF,0xFF,0xFC,0xFE,0xA8,0xFD,0xB9,0x02,0xE2,0xFE, + 0xF6,0x00,0x28,0x02,0xF6,0xFF,0x41,0x02,0xCF,0x00,0x5E,0x01, + 0x56,0x02,0xC3,0xFF,0xAF,0x01,0xCA,0x00,0xA7,0xFF,0x86,0x01, + 0xF1,0xFF,0xE9,0xFF,0x5C,0x00,0x8E,0xFF,0xE4,0xFF,0xCD,0xFF, + 0x7A,0xFF,0x6B,0xFF,0x6D,0xFF,0xA4,0xFF,0x8C,0xFF,0x4C,0xFF, + 0x47,0xFF,0xB9,0xFF,0x51,0xFF,0x96,0xFF,0xAA,0xFF,0xFA,0xFE, + 0xF2,0xFF,0xCD,0xFF,0x72,0xFF,0x6F,0xFF,0x4F,0x00,0x06,0xFE, + 0x17,0x04,0x8C,0x02,0xC8,0xF9,0x9A,0x02,0xA9,0xFE,0x33,0xFE, + 0x2B,0x02,0xAF,0xFC,0xD4,0x00,0xC7,0x01,0x84,0xFF,0xF6,0x00, + 0x3D,0x00,0xCC,0xFF,0xAF,0x01,0xCA,0x00,0x84,0x01,0x64,0x00, + 0xAF,0xFF,0x5D,0x01,0xC9,0xFF,0xBF,0x00,0x18,0x00,0x97,0xFF, + 0xD7,0xFF,0x93,0xFF,0xEA,0xFF,0x4A,0xFE,0x18,0xFF,0x85,0xFE, + 0xEA,0xFE,0x1D,0x00,0xB8,0xFF,0x4B,0x00,0x01,0x00,0x38,0x01, + 0x9D,0x00,0xA4,0x01,0xFC,0x00,0x4F,0xFF,0xD7,0x00,0xC9,0xFF, + 0xDB,0xFF,0x45,0xFF,0xC9,0xFE,0x3F,0xFF,0x98,0xFF,0x77,0xFF, + 0xDA,0xFF,0x8C,0x00,0x19,0x00,0xF3,0x00,0x27,0x01,0x46,0x01, + 0x0A,0x01,0xBC,0x00,0x70,0x01,0x45,0x00,0xAA,0xFE,0x0C,0xFF, + 0x63,0xFE,0xBE,0xFD,0x9B,0xFE,0xC8,0xFD,0xB1,0xFD,0x8D,0xFF, + 0x4D,0xFF,0x75,0xFF,0x26,0x00,0xC8,0x00,0x44,0x01,0xD5,0x01, + 0x69,0x02,0x74,0x01,0x41,0x02,0x7D,0x01,0x14,0x01,0x58,0x01, + 0xEC,0x00,0x07,0x00,0xF6,0xFE,0x17,0x01,0xD5,0x00,0x8E,0xFF, + 0xEA,0xFF,0xE4,0xFE,0xDA,0x01,0x95,0x02,0x70,0xFE,0x59,0xFF, + 0xEC,0xFD,0xEC,0xFD,0xD6,0xFE,0xC4,0xFC,0x38,0xFC,0xEC,0xFA, + 0x9F,0xFD,0xC6,0xFD,0xB3,0xFD,0x23,0xFF,0x9C,0xFE,0x35,0x01, + 0xFF,0x02,0x8A,0x03,0x70,0x03,0x9F,0x03,0x36,0x04,0x3E,0x04, + 0xDE,0x03,0xA6,0x02,0x96,0x00,0x02,0x00,0xB9,0xFF,0x3D,0xFE, + 0xB0,0xFD,0x92,0xFC,0xA0,0xFC,0x2C,0xFD,0x2E,0xFE,0xB7,0xFE, + 0xD8,0xFE,0x52,0x00,0x25,0x01,0x3F,0x02,0xDB,0x02,0xA7,0x02, + 0x61,0x02,0x4F,0x02,0xED,0x01,0x13,0x01,0xE9,0xFF,0xF0,0xFE, + 0x21,0xFE,0x87,0xFD,0x8A,0xFD,0xF1,0xFC,0x03,0xFD,0x91,0xFD, + 0x2F,0xFE,0x1C,0xFF,0xFB,0xFF,0x95,0x00,0x23,0x01,0xF4,0x01, + 0x61,0x02,0x58,0x02,0x01,0x02,0x9D,0x01,0xDA,0x00,0x79,0x00, + 0xC4,0xFF,0xDC,0xFE,0x71,0xFE,0xE5,0xFD,0x03,0xFE,0x33,0xFE, + 0x74,0xFE,0xF8,0xFE,0x79,0xFF,0x59,0x00,0x0C,0x01,0x8C,0x01, + 0x06,0x02,0x15,0x02,0x12,0x02,0xEC,0x01,0x7C,0x01,0xE9,0x00, + 0x17,0x00,0x82,0xFF,0xEE,0xFE,0x7E,0xFE,0x4C,0xFE,0x0F,0xFE, + 0x41,0xFE,0xA1,0xFE,0x31,0xFF,0xCB,0xFF,0x4E,0x00,0xE0,0x00, + 0x54,0x01,0xA8,0x01,0xC6,0x01,0x98,0x01,0x42,0x01,0xD0,0x00, + 0x49,0x00,0xC3,0xFF,0x2D,0xFF,0xC2,0xFE,0x74,0xFE,0x61,0xFE, + 0x7C,0xFE,0xC2,0xFE,0x2A,0xFF,0x98,0xFF,0x30,0x00,0xB4,0x00, + 0x1B,0x01,0x5E,0x01,0x7D,0x01,0x5A,0x01,0x1C,0x01,0xC7,0x00, + 0x52,0x00,0xBD,0xFF,0x65,0xFF,0xD5,0xFE,0xBF,0xFE,0x72,0xFE, + 0xB6,0xFE,0x53,0xFF,0xAB,0xFE,0xE4,0xFF,0x15,0x00,0x63,0x00, + 0x8E,0x01,0x2D,0x01,0x33,0x01,0x97,0x00,0x89,0x01,0xBC,0x02, + 0x00,0x00,0xFE,0xFE,0x8F,0xFF,0x4C,0xFE,0xF6,0xFE,0xCD,0xFE, + 0x54,0xFE,0x9A,0xFD,0x26,0xFE,0x7D,0x00,0xC8,0xFF,0x97,0x00, + 0x4E,0x01,0xC0,0x00,0x6F,0x01,0x16,0x02,0xB1,0x01,0xA3,0x00, + 0x2C,0x00,0x58,0x00,0x9D,0xFF,0x85,0xFF,0xAB,0xFF,0x46,0xFE, + 0xB8,0xFE,0x46,0xFF,0xCC,0xFF,0xF1,0xFF,0x36,0x00,0xA6,0x00, + 0x72,0x00,0x47,0x01,0x8E,0x01,0xD1,0x00,0x7B,0x00,0x62,0x00, + 0xDF,0xFF,0xAF,0xFF,0x65,0xFF,0x2D,0xFF,0x6E,0xFE,0xB6,0xFE, + 0x4C,0xFF,0x2E,0xFF,0xD6,0xFF,0x08,0x00,0xFA,0xFF,0x35,0x00, + 0xC5,0x00,0xBD,0x00,0x7E,0x00,0xE5,0x00,0xBB,0x00,0xBA,0xFF, + 0xB7,0xFF,0xD9,0xFF,0x6C,0xFF,0xA9,0xFF,0xB4,0xFF,0x75,0xFF, + 0x4D,0xFF,0xF7,0xFF,0x4D,0x00,0x4A,0x00,0x61,0x01,0xF3,0x00, + 0xED,0xFF,0x6D,0x00,0x33,0x00,0x86,0xFF,0x51,0xFF,0x0C,0xFF, + 0xBB,0xFE,0x69,0xFE,0xA9,0xFF,0xF0,0xFF,0x85,0xFF,0x4E,0x00, + 0xB6,0x00,0xCA,0x01,0x25,0x02,0xC2,0x02,0x3E,0x02,0xCF,0x00, + 0x93,0x00,0x8A,0xFF,0xC3,0xFF,0x97,0x01,0xB9,0x00,0xA7,0xFE, + 0x18,0xFF,0x81,0xFE,0x21,0xFE,0x08,0xFF,0x2A,0xFF,0x29,0xFE, + 0x0B,0xFD,0x7A,0xFE,0xFB,0xFE,0x2B,0xFF,0xE4,0x00,0x02,0x00, + 0x4E,0xFF,0x4F,0x00,0x28,0x01,0x6F,0x01,0xE5,0x00,0x0F,0x01, + 0x0C,0x00,0x43,0xFF,0xC3,0x00,0xCD,0x00,0xFC,0xFF,0xF8,0xFF, + 0x91,0xFF,0xEB,0xFF,0x35,0x00,0x26,0x01,0x0B,0x01,0xDE,0xFF, + 0xA5,0x00,0x8A,0x00,0x45,0x00,0xF9,0x00,0xA2,0x00,0x9F,0xFF, + 0x6B,0xFF,0xB5,0xFF,0xD8,0xFF,0x8A,0xFF,0xFD,0xFF,0xAA,0xFF, + 0x16,0xFF,0xFB,0xFF,0x59,0x00,0x3E,0x00,0x3C,0x00,0x3A,0x00, + 0xD4,0xFF,0xB9,0xFF,0x4D,0x00,0x2F,0x00,0x74,0xFF,0x92,0xFF, + 0x6B,0xFF,0x36,0xFF,0xB6,0xFF,0x02,0x00,0xC7,0xFF,0x91,0xFF, + 0xFF,0xFF,0x1A,0x00,0x1A,0x00,0x9B,0x00,0x68,0x00,0xD9,0xFF, + 0x01,0x00,0x18,0x00,0xFA,0xFF,0xFB,0xFF,0x15,0x00,0xC7,0xFF, + 0x80,0xFF,0x09,0x00,0x35,0x00,0x12,0x00,0x52,0x00,0x44,0x00, + 0x0D,0x00,0x2C,0x00,0x73,0x00,0x56,0x00,0x05,0x00,0x0C,0x00, + 0xE2,0xFF,0xA2,0xFF,0xE7,0xFF,0x09,0x00,0xCB,0xFF,0xD4,0xFF, + 0xF3,0xFF,0xF7,0xFF,0x09,0x00,0x4F,0x00,0x4B,0x00,0x00,0x00, + 0x0D,0x00,0x0F,0x00,0xE5,0xFF,0xF9,0xFF,0x07,0x00,0xDF,0xFF, + 0xB0,0xFF,0xE4,0xFF,0xE7,0xFF,0xF8,0xFF,0x2B,0x00,0x01,0x00, + 0x2C,0x00,0x12,0x00,0x21,0x00,0x0F,0x00,0xF7,0xFF,0x1F,0x00, + 0xF7,0xFF,0xB2,0xFF,0xDF,0xFF,0xEB,0xFF,0xD4,0xFF,0x06,0x00, + 0xFB,0xFF,0x0E,0x00,0xED,0xFF,0x1D,0x00,0x30,0x00,0x0F,0x00, + 0x21,0x00,0x0A,0x00,0xDD,0xFF,0xE9,0xFF,0xF4,0xFF,0x01,0x00, + 0xF4,0xFF,0xF1,0xFF,0x0B,0x00,0x11,0x00,0x29,0x00,0x27,0x00, + 0x67,0xFF,0x87,0xFF,0x46,0x05,0x8D,0x07,0x1F,0x00,0x79,0xFB, + 0x06,0xF9,0x2E,0xF7,0x08,0xFC,0xF6,0x00,0x83,0x01,0x85,0xFE, + 0x8F,0xFD,0xD3,0xFF,0x10,0x01,0xB5,0x05,0xCE,0x08,0x34,0x05, + 0x9D,0x02,0x3E,0x01,0x4A,0xFF,0x99,0x00,0xC4,0x04,0xB1,0x04, + 0x69,0xFE,0x39,0xFB,0x7B,0xF9,0xC0,0xF7,0x95,0xFB,0xA1,0xFF, + 0xF1,0xFE,0xED,0xFC,0x9E,0xFD,0x24,0xFF,0xF7,0x00,0x27,0x05, + 0x17,0x07,0x13,0x03,0x5E,0x00,0x88,0xFF,0x6F,0xFE,0x8B,0xFF, + 0xF4,0x00,0xB4,0xFF,0x7E,0xFC,0x0F,0xFC,0x6A,0xFD,0x22,0xFF, + 0xB6,0x02,0xC9,0x04,0xBB,0x02,0xEB,0x00,0x5E,0x00,0xFF,0xFF, + 0x07,0x01,0x49,0x02,0x3F,0x01,0x21,0xFE,0x08,0xFD,0x3C,0xFD, + 0xF2,0xFD,0xB0,0x00,0x49,0x02,0xF8,0x00,0xCF,0xFF,0xB4,0xFF, + 0x9F,0xFF,0x75,0x00,0x1E,0x02,0xB7,0x01,0x56,0xFF,0x93,0xFE, + 0x60,0xFE,0x3F,0xFE,0x08,0x00,0x66,0x01,0x94,0x00,0x64,0xFF, + 0x3F,0xFF,0x04,0xFF,0x49,0xFF,0xD9,0x00,0x3D,0x01,0x10,0x00, + 0x84,0xFF,0x4A,0xFF,0xE9,0xFE,0xDC,0xFF,0x0F,0x01,0xD4,0x00, + 0x09,0x00,0xD0,0xFF,0x64,0xFF,0x3C,0xFF,0x3F,0x00,0xD1,0x00, + 0x6C,0x00,0x1A,0x00,0xEF,0xFF,0x65,0xFF,0xB4,0xFF,0x9C,0x00, + 0xDB,0x00,0xA9,0x00,0x45,0x00,0xAD,0xFF,0x2C,0xFF,0x7D,0xFF, + 0xFF,0xFF,0x38,0x00,0x50,0x00,0x32,0x00,0xCA,0xFF,0xB5,0xFF, + 0x27,0x00,0x86,0x00,0xC9,0x00,0xB3,0x00,0x21,0x00,0x6A,0xFF, + 0x32,0xFF,0x56,0xFF,0xA4,0xFF,0x17,0x00,0x00,0x00,0xF6,0xFF, + 0xB5,0xFF,0xB2,0xFF,0x5E,0x00,0x96,0x00,0xF8,0x00,0xB4,0x00, + 0x12,0x00,0xA9,0xFF,0x5A,0xFF,0x98,0xFF,0xC1,0xFF,0x10,0x00, + 0xFC,0xFF,0xAC,0xFF,0xB6,0xFF,0xB6,0xFF,0x02,0x00,0x80,0x00, + 0x94,0x00,0x76,0x00,0x22,0x00,0xB5,0xFF,0x98,0xFF,0xA8,0xFF, + 0xFE,0xFF,0x1B,0x00,0xFF,0xFF,0xFA,0xFF,0xC2,0xFF,0xB7,0xFF, + 0x0C,0x00,0x3D,0x00,0x65,0x00,0x5F,0x00,0x19,0x00,0xDA,0xFF, + 0xAB,0xFF,0xCB,0xFF,0xF2,0xFF,0x14,0x00,0x2C,0x00,0x04,0x00, + 0xD7,0xFF,0xDF,0xFF,0xC9,0xFF,0x0D,0x00,0x4A,0x00,0x37,0x00, + 0x2B,0x00,0xDD,0xFF,0xCD,0xFF,0xC7,0xFF,0xEF,0xFF,0x21,0x00, + 0x32,0x00,0x1F,0x00,0xF0,0xFF,0xCF,0xFF,0xD5,0xFF,0xF1,0xFF, + 0x10,0x00,0x43,0x00,0x26,0x00,0x1D,0x00,0xF0,0xFF,0xD6,0xFF, + 0xA8,0xFF,0x33,0x00,0x34,0x02,0x76,0x02,0xCA,0x00,0x6A,0xFF, + 0x62,0xFD,0x24,0xFC,0x62,0xFD,0xCF,0xFE,0x5A,0x00,0x66,0x01, + 0xC7,0x00,0x1B,0x00,0xE4,0xFF,0x1E,0x00,0xD8,0x00,0xD6,0x01, + 0x2E,0x02,0xFA,0x00,0xE8,0xFF,0x56,0xFF,0xAB,0xFE,0x78,0xFF, + 0xA7,0x00,0xF7,0x00,0x15,0x01,0x41,0x00,0x26,0xFF,0xCB,0xFE, + 0xEC,0xFE,0xB3,0xFF,0x67,0x00,0xA9,0x00,0x75,0x00,0xA8,0xFF, + 0x58,0xFF,0x6E,0xFF,0xB7,0xFF,0x84,0x00,0xB4,0x00,0x4A,0x00, + 0xC6,0xFF,0x0C,0xFF,0xE9,0xFE,0x66,0xFF,0x00,0x00,0xA5,0x00, + 0xBA,0x00,0x6F,0x00,0xF8,0xFF,0x85,0xFF,0xBD,0xFF,0x05,0x00, + 0x57,0x00,0xAC,0x00,0x40,0x00,0xBD,0xFF,0x7C,0xFF,0x3A,0xFF, + 0x94,0xFF,0x2A,0x00,0x69,0x00,0x7F,0x00,0x46,0x00,0xEC,0xFF, + 0xAC,0xFF,0xC9,0xFF,0x29,0x00,0x49,0x00,0x62,0x00,0x66,0x00, + 0xF4,0xFF,0xC9,0xFF,0xDD,0xFF,0xE6,0xFF,0x59,0x00,0x7F,0x00, + 0x5F,0x00,0x51,0x00,0x00,0x00,0xD9,0xFF,0xF7,0xFF,0x05,0x00, + 0x22,0x00,0x16,0x00,0xF9,0xFF,0xD1,0xFF,0x95,0xFF,0xB2,0xFF, + 0xC2,0xFF,0xCF,0xFF,0xFF,0xFF,0xEB,0xFF,0xF2,0xFF,0xCD,0xFF, + 0x74,0xFF,0xBD,0xFF,0x16,0x00,0x74,0x00,0xDA,0x00,0x91,0x00, + 0x3D,0x00,0xCC,0xFF,0x53,0xFF,0x41,0xFF,0x4A,0xFF,0xB1,0xFF, + 0x1F,0x00,0x48,0x00,0x48,0x00,0xE3,0xFF,0xAF,0xFF,0xFF,0xFF, + 0x93,0x00,0x4B,0x01,0x83,0x01,0x10,0x01,0x28,0x00,0x10,0xFF, + 0x56,0xFE,0x3E,0xFE,0xDA,0xFE,0xB0,0xFF,0x1D,0x00,0x4C,0x00, + 0x3E,0x00,0xEA,0xFF,0xD8,0xFF,0xF4,0xFF,0x20,0x00,0x52,0x00, + 0x37,0x00,0x06,0x00,0xDD,0xFF,0xCA,0xFF,0x09,0x00,0x62,0x00, + 0xB1,0x00,0xA6,0x00,0x3E,0x00,0xDC,0xFF,0x88,0xFF,0xAF,0xFF, + 0x2F,0x00,0x92,0x00,0xED,0x00,0x00,0x01,0xA3,0x00,0x09,0x00, + 0x21,0xFF,0x03,0xFF,0x8D,0xFF,0xF8,0xFF,0x92,0x01,0x8D,0x02, + 0x0F,0x02,0x9C,0x01,0xC4,0xFF,0x89,0xFD,0xFC,0xFD,0xBC,0x00, + 0xFD,0x05,0x0D,0x0B,0x28,0x09,0x36,0x02,0xB6,0xF8,0x7A,0xEE, + 0x02,0xEB,0x84,0xEE,0xE8,0xF6,0x63,0x01,0xD4,0x07,0x76,0x09, + 0x86,0x06,0xC3,0x01,0x84,0xFF,0x46,0x00,0x38,0x04,0xBB,0x07, + 0xA8,0x07,0xCC,0x04,0xDC,0xFE,0x87,0xF9,0x8A,0xF8,0xA8,0xFA, + 0xCF,0xFF,0xF2,0x04,0xBE,0x06,0x7D,0x05,0x85,0x01,0xDB,0xFD, + 0x9B,0xFC,0x12,0xFE,0xBF,0x01,0x7A,0x04,0x28,0x05,0x5C,0x03, + 0x2F,0xFF,0x84,0xFC,0x74,0xFB,0x31,0xFC,0x44,0xFF,0xDE,0x00, + 0x3C,0x01,0xC9,0xFF,0xDB,0xFC,0xC3,0xFB,0x0C,0xFC,0x5A,0xFE, + 0x82,0x01,0x14,0x03,0x63,0x03,0x70,0x01,0xDD,0xFE,0x97,0xFD, + 0xF8,0xFC,0x3E,0xFE,0x02,0x00,0xC5,0x00,0x26,0x01,0x24,0x00, + 0x17,0xFF,0x25,0xFF,0xC9,0xFF,0x5D,0x01,0xB1,0x02,0xEC,0x02, + 0x34,0x02,0x81,0x00,0xD8,0xFE,0xF3,0xFD,0x43,0xFE,0xB0,0xFF, + 0xDC,0x00,0x38,0x01,0xE0,0x00,0x79,0xFF,0x44,0xFE,0x94,0xFD, + 0xAB,0xFD,0x52,0x03,0x64,0x07,0xAF,0x07,0x42,0x0B,0x89,0x06, + 0xD3,0xFF,0x69,0xFC,0x45,0xF4,0xA3,0xF4,0xA7,0xF6,0x83,0xF6, + 0x89,0xFD,0x42,0xFF,0xEA,0xFE,0xEB,0x00,0x6E,0x00,0x88,0x01, + 0x67,0x02,0x62,0x04,0x67,0x05,0x1C,0x03,0xD6,0x02,0x22,0x00, + 0xE5,0xFD,0xA1,0xFF,0xDC,0xFE,0xFA,0x00,0x4E,0x03,0x62,0x01, + 0xF1,0x01,0xC1,0x00,0xD4,0xFE,0xAD,0xFF,0x9D,0x00,0x82,0x02, + 0xB1,0x03,0x30,0x04,0xB3,0x02,0x73,0xFF,0xBC,0xFD,0x39,0xFB, + 0x9F,0xFA,0x9A,0xFC,0xDB,0xFC,0x7B,0xFE,0xD2,0xFF,0xF5,0xFE, + 0x90,0xFF,0xBD,0xFF,0xB6,0xFF,0xFE,0x00,0x94,0x01,0x81,0x01, + 0x36,0x01,0x5B,0x00,0x0E,0xFF,0x90,0xFE,0xD9,0xFE,0xD5,0xFE, + 0x68,0xFF,0xDB,0xFF,0x3B,0xFF,0x2C,0xFF,0x6C,0xFF,0x9D,0xFF, + 0xC9,0x00,0x39,0x02,0x43,0x02,0x08,0x02,0x60,0x01,0x5E,0xFF, + 0xE3,0xFE,0x94,0xFE,0x32,0xFE,0xC8,0xFD,0x38,0x03,0xE4,0x0D, + 0x10,0x10,0xD1,0x0F,0x3B,0x08,0x21,0xF9,0xA3,0xF0,0xC4,0xE6, + 0xB2,0xE7,0x7D,0xF3,0x5E,0xF9,0x06,0x03,0xF4,0x08,0x41,0x05, + 0xBF,0x01,0xD4,0xFE,0x93,0xFF,0xAE,0x02,0xE9,0x06,0x82,0x0A, + 0xFC,0x07,0x4A,0x04,0xC1,0xFE,0xCD,0xF9,0xF4,0xFB,0x82,0xFD, + 0x44,0x01,0x98,0x06,0xCE,0x04,0x84,0x02,0xDE,0xFF,0xE0,0xFB, + 0xD8,0xFC,0x84,0x01,0x0B,0x06,0xCE,0x08,0xD0,0x07,0x5A,0x02, + 0x0C,0xFC,0x81,0xF7,0x99,0xF5,0xD6,0xF7,0x2A,0xFC,0x2F,0xFF, + 0x34,0x01,0x63,0x01,0xE5,0xFE,0xE1,0xFD,0xD5,0xFE,0x17,0x00, + 0x9A,0x02,0x29,0x04,0xE9,0x02,0xB1,0x00,0x13,0xFE,0xB6,0xFB, + 0x17,0xFC,0xD5,0xFD,0x8D,0xFF,0xC0,0x01,0x11,0x02,0xF8,0x00, + 0x12,0x00,0x8F,0xFE,0x4F,0xFE,0x44,0x00,0x04,0x02,0xFA,0x02, + 0xDC,0x02,0xA2,0x01,0xAE,0xFF,0xF7,0xFD,0x1A,0xFB,0x95,0xFC, + 0x73,0x09,0x05,0x11,0xDC,0x12,0xC6,0x10,0xB0,0x00,0xC6,0xF3, + 0xF5,0xE7,0x72,0xE1,0x75,0xEC,0x42,0xF5,0x3E,0xFF,0xCA,0x09, + 0x36,0x08,0x63,0x03,0x41,0xFE,0xCC,0xFC,0xEF,0xFF,0xB6,0x04, + 0xCA,0x0B,0x1D,0x0C,0x2C,0x08,0xAF,0x02,0x69,0xFA,0xC9,0xF9, + 0xE5,0xFB,0xCD,0xFE,0x78,0x06,0x85,0x07,0x94,0x04,0x50,0x01, + 0xEE,0xFB,0xD4,0xFC,0x4E,0x01,0xB7,0x05,0x34,0x09,0xE3,0x06, + 0x3E,0x01,0x83,0xF9,0xF1,0xF3,0xC9,0xF4,0xEF,0xF7,0x1B,0xFE, + 0xB3,0x03,0x5A,0x04,0xC1,0x02,0x1C,0xFE,0x42,0xFB,0x66,0xFC, + 0x81,0xFE,0xFB,0x02,0x95,0x05,0x8B,0x04,0x5C,0x01,0xFE,0xFC, + 0xEE,0xFA,0xF8,0xFA,0x6D,0xFD,0x05,0x01,0xC5,0x02,0x7C,0x02, + 0x15,0x00,0xCF,0xFD,0x28,0xFD,0x28,0xFE,0xEE,0x00,0xF7,0x03, + 0x44,0x05,0xDA,0x03,0x20,0x01,0x9E,0xFD,0x6F,0xF8,0xBC,0xFB, + 0x10,0x0B,0x30,0x14,0x31,0x17,0xA4,0x11,0x06,0xFE,0x70,0xEE, + 0x13,0xDF,0xC3,0xDA,0x85,0xEA,0x04,0xF7,0x4A,0x05,0x4A,0x10, + 0xC7,0x0C,0xBC,0x04,0x93,0xFC,0x1B,0xFB,0xB5,0xFE,0x8A,0x05, + 0x72,0x0D,0x08,0x0D,0xBB,0x08,0x5D,0x00,0xF1,0xF7,0x45,0xF9, + 0xFA,0xFB,0xB9,0x01,0xC1,0x09,0xC8,0x08,0x28,0x04,0x6A,0xFE, + 0x1D,0xF8,0x11,0xF8,0x43,0xFD,0x1A,0x04,0x25,0x0B,0xD8,0x0C, + 0x9C,0x07,0xA9,0x00,0xF2,0xF8,0x03,0xF5,0x24,0xF6,0x81,0xF9, + 0x9E,0xFE,0xFD,0xFF,0x7C,0xFF,0x2E,0xFE,0xAB,0xFC,0x9F,0xFE, + 0xC2,0x00,0x10,0x04,0x7F,0x05,0xA0,0x02,0xC2,0xFF,0x1C,0xFC, + 0x24,0xFA,0xA9,0xFB,0x28,0xFE,0x21,0x01,0x87,0x02,0x6E,0x01, + 0x9A,0xFF,0xD2,0xFD,0x3C,0xFD,0xAD,0xFE,0xBD,0x01,0x04,0x04, + 0x18,0x04,0xD7,0x02,0xAC,0x00,0xA1,0xFE,0xF7,0xFD,0xB8,0xFB, + 0x2F,0xFF,0x9B,0x10,0x9D,0x18,0x0A,0x17,0xF4,0x0F,0xE4,0xF7, + 0xC8,0xE8,0xA1,0xDD,0x47,0xDB,0x7B,0xEF,0xEE,0xFA,0xA6,0x05, + 0x52,0x0D,0x94,0x06,0xBF,0xFF,0x4B,0xFA,0x76,0xFE,0x13,0x05, + 0x39,0x0B,0xCC,0x10,0xEA,0x09,0x8E,0x02,0xB8,0xFA,0xDF,0xF4, + 0x1E,0xFC,0xD4,0x01,0xA5,0x06,0xBC,0x0B,0xA9,0x05,0x7A,0xFE, + 0xFA,0xF9,0x2F,0xF8,0xF8,0xFC,0x6E,0x03,0x5C,0x09,0x98,0x08, + 0x97,0x05,0xC4,0x01,0x29,0xFD,0x60,0x00,0x2D,0xFF,0x85,0xFD, + 0x93,0xFD,0xB9,0xF6,0x57,0xF5,0x0A,0xF6,0x80,0xF8,0x49,0x00, + 0x3B,0x05,0x3E,0x08,0xCD,0x06,0x3B,0x02,0x8B,0xFD,0x6D,0xFA, + 0x41,0xFD,0x04,0xFF,0x14,0x01,0xCD,0x02,0x61,0xFE,0xED,0xFC, + 0xB5,0xFC,0xDF,0xFC,0xF9,0x00,0x84,0x02,0x8A,0x02,0xE4,0x01, + 0x00,0x00,0x1F,0xFF,0x6D,0xFF,0xE0,0x01,0x9D,0x02,0x58,0x03, + 0x04,0x00,0x19,0xF9,0xF0,0x07,0xB3,0x16,0xBD,0x17,0xF9,0x18, + 0xC4,0x02,0x61,0xED,0x64,0xE0,0xA3,0xD4,0x49,0xE6,0x57,0xF7, + 0xA9,0x01,0xB0,0x0C,0xC4,0x08,0xB9,0x00,0xCC,0xF8,0xA3,0xFD, + 0x66,0x06,0xE5,0x0B,0xB4,0x13,0x4E,0x0B,0x21,0x01,0xE1,0xF9, + 0x94,0xF2,0x7F,0xFB,0x5C,0x04,0x19,0x08,0x9C,0x0B,0xD7,0x04, + 0xFB,0xFB,0x8F,0xF7,0x86,0xF9,0x0C,0x00,0xC5,0x05,0x8B,0x0B, + 0x2E,0x07,0x00,0x01,0xF6,0xFC,0x96,0xF8,0x53,0x00,0x96,0x05, + 0x8D,0x08,0x8B,0x07,0x0F,0xFB,0x76,0xF3,0xD7,0xED,0x44,0xF1, + 0x6F,0xFB,0x2E,0x02,0xD7,0x09,0x9F,0x06,0x76,0x01,0xA4,0xFE, + 0xD9,0xFA,0x4A,0xFF,0x87,0x01,0xE5,0x02,0xBD,0x02,0x0B,0xFD, + 0x93,0xFB,0xA3,0xFA,0xE6,0xFC,0x98,0x01,0x22,0x03,0x89,0x04, + 0xDF,0x00,0x67,0xFD,0x90,0xFD,0x72,0xFD,0xB0,0x01,0x3C,0x04, + 0x23,0x05,0xBD,0x04,0x79,0x00,0x40,0xFB,0x4F,0xF9,0x88,0x0B, + 0xD2,0x1A,0xCE,0x1B,0x6F,0x16,0x65,0xFA,0x69,0xE6,0x8F,0xDC, + 0x25,0xD9,0x5F,0xEF,0x7E,0xFD,0x4B,0x03,0xD6,0x05,0xDB,0xFE, + 0xD7,0xFA,0xE3,0xFA,0x75,0x07,0xFE,0x0F,0xED,0x11,0xEE,0x0F, + 0xCF,0x00,0x70,0xF9,0x93,0xF6,0x80,0xF8,0x3B,0x05,0x36,0x09, + 0xAC,0x06,0x61,0x02,0xC8,0xFA,0x70,0xF8,0x4E,0xFC,0x22,0x04, + 0x38,0x08,0x07,0x08,0xB0,0x04,0xCE,0xFC,0xF4,0xFB,0x40,0xFE, + 0x17,0x02,0x9A,0x07,0x05,0x06,0x4A,0x02,0x7A,0xFD,0x57,0xF9, + 0xE1,0xF6,0x0F,0xF8,0x86,0xFB,0x35,0xFB,0xF4,0xFD,0x22,0xFE, + 0xD8,0xFD,0xF8,0x01,0x7C,0x02,0x39,0x04,0x40,0x04,0x69,0x00, + 0xB0,0xFD,0x6B,0xFC,0x93,0xFC,0x3C,0xFE,0x42,0x01,0x03,0x01, + 0xD3,0xFF,0x9A,0xFF,0xB6,0xFD,0xEF,0xFE,0x47,0x01,0xEE,0x00, + 0x67,0x01,0x4B,0x00,0xF3,0xFE,0x92,0x00,0x47,0x02,0x38,0x03, + 0x47,0x03,0xE3,0xFF,0xC4,0xFC,0x7C,0x09,0x51,0x17,0xE3,0x17, + 0x45,0x12,0x83,0xFD,0x0F,0xEB,0xE6,0xE2,0x70,0xE0,0x9A,0xEE, + 0x7C,0xFA,0x8E,0xFD,0x01,0xFE,0x4A,0xFC,0xE2,0xFB,0xF1,0xFE, + 0xE3,0x0A,0xDB,0x10,0x11,0x10,0xD1,0x0B,0x5C,0x00,0xC7,0xFB, + 0x6D,0xFB,0x58,0xFE,0xDD,0x04,0x35,0x05,0xA0,0x00,0xE7,0xFB, + 0x99,0xFA,0xF8,0xFB,0x07,0x01,0x02,0x07,0x5C,0x06,0x17,0x04, + 0xC0,0x00,0x8B,0xFD,0x81,0x00,0xB1,0x03,0xF9,0x05,0x60,0x05, + 0xE0,0xFF,0xEF,0xFB,0x59,0xFA,0xB0,0xFC,0xC9,0xFE,0x19,0xFE, + 0x86,0xFC,0x33,0xF8,0x29,0xF8,0x35,0xFB,0xA1,0xFE,0xC7,0x03, + 0xA1,0x04,0x4B,0x03,0x54,0x01,0x20,0xFF,0xEF,0xFE,0x4A,0xFF, + 0x5F,0x00,0x83,0xFF,0xB1,0xFE,0xB4,0xFD,0x14,0xFD,0xA4,0xFF, + 0xDB,0x00,0xBE,0x01,0x71,0x01,0xBA,0xFF,0x94,0xFE,0x9E,0xFE, + 0x65,0x00,0xBA,0x01,0xE6,0x02,0xC4,0x02,0xA9,0x00,0xD0,0xFF, + 0x96,0xFE,0xFB,0x00,0xA0,0x0E,0xCA,0x17,0xAF,0x14,0x47,0x0A, + 0x0E,0xF8,0x62,0xEC,0xD6,0xE8,0xED,0xEA,0xA9,0xF4,0xB6,0xF8, + 0x50,0xF7,0x25,0xF6,0x93,0xF8,0xCC,0xFC,0x50,0x04,0x12,0x0E, + 0x3A,0x0E,0xFD,0x0B,0xBD,0x06,0x5C,0x01,0xED,0x01,0xE7,0x02, + 0xB2,0x04,0xFA,0x03,0xDC,0xFF,0x54,0xFA,0x2B,0xF9,0x00,0xFC, + 0xE5,0xFE,0x42,0x03,0xD9,0x03,0x8B,0x01,0x4D,0x00,0x14,0x00, + 0xA1,0x02,0xFE,0x05,0x32,0x07,0x4B,0x05,0x74,0x01,0x9E,0xFE, + 0x4F,0xFD,0x55,0xFD,0x76,0xFD,0x26,0xFC,0xBF,0xFA,0x80,0xF8, + 0xE9,0xF7,0x0F,0xFB,0x12,0xFE,0xA6,0x00,0x81,0x02,0x8B,0x02, + 0x77,0x01,0x1E,0x01,0xC3,0x01,0xC3,0x01,0x8E,0x01,0xFD,0xFF, + 0x90,0xFE,0x05,0xFE,0x4F,0xFD,0x5E,0xFE,0x7C,0xFF,0xB5,0xFF, + 0x6D,0xFF,0x44,0xFF,0x6F,0xFF,0xC6,0xFF,0xE4,0x00,0x45,0x01, + 0xCB,0x01,0x44,0x02,0x22,0x02,0xF3,0x01,0x4D,0x01,0x96,0xFF, + 0x09,0xFF,0xEA,0x05,0x17,0x0E,0xAA,0x0F,0x83,0x0A,0x3C,0x01, + 0x07,0xFA,0x75,0xF3,0x92,0xF1,0xCE,0xF5,0x15,0xF7,0x71,0xF6, + 0xEE,0xF5,0x6F,0xF6,0xC6,0xF7,0xC5,0xFB,0x2D,0x02,0xA0,0x06, + 0xAE,0x08,0x3B,0x07,0x7B,0x06,0x55,0x06,0x25,0x06,0x94,0x07, + 0x98,0x07,0xF4,0x04,0x2B,0x01,0xE9,0xFE,0x40,0xFD,0x5D,0xFD, + 0x4A,0xFE,0x62,0xFE,0xC3,0xFE,0x42,0xFE,0x3D,0xFE,0x6E,0xFF, + 0xCF,0x00,0xEE,0x01,0x41,0x03,0x80,0x03,0x9F,0x02,0xCB,0x01, + 0xE4,0xFF,0x4B,0xFF,0x72,0xFF,0x36,0xFE,0xD9,0xFD,0xA9,0xFD, + 0xA4,0xFC,0x43,0xFC,0xB9,0xFC,0xDF,0xFC,0x95,0xFD,0xCE,0xFE, + 0x05,0xFF,0xAF,0xFF,0xE3,0xFF,0x80,0xFF,0x39,0x00,0xA0,0x00, + 0xB0,0x00,0x25,0x01,0x24,0x01,0x5A,0x00,0x3B,0x00,0x36,0x00, + 0xD3,0xFF,0x41,0x00,0x20,0x00,0xC3,0xFF,0xD5,0xFF,0xC8,0xFF, + 0x0F,0x00,0x95,0x00,0xE1,0x00,0xBB,0x00,0x9B,0x00,0x49,0x00, + 0xE4,0xFF,0xD5,0x02,0x2B,0x07,0x09,0x05,0x11,0x03,0xAD,0x04, + 0x4F,0x01,0x48,0xFF,0xDF,0x00,0x14,0x00,0x4E,0xFE,0x05,0xFD, + 0x2B,0xFB,0xEF,0xF8,0xB2,0xF8,0x71,0xF8,0x1C,0xFA,0x33,0xFC, + 0xB0,0xFA,0x81,0xFB,0xE3,0xFC,0x42,0xFD,0xBF,0xFF,0x3B,0x03, + 0x8E,0x04,0xDC,0x04,0x37,0x06,0x5A,0x05,0x92,0x05,0x5B,0x06, + 0xB2,0x05,0x3C,0x06,0xA4,0x05,0xDB,0x03,0x78,0x02,0xA7,0x01, + 0x0E,0x00,0x31,0x00,0x51,0x01,0x40,0xFF,0x4B,0xFE,0xA4,0xFD, + 0x12,0xFC,0x4F,0xFC,0x1B,0xFD,0x1B,0xFD,0xD4,0xFC,0x01,0xFD, + 0x6C,0xFC,0xBE,0xFC,0x44,0xFD,0x3D,0xFD,0x77,0xFE,0xCF,0xFE, + 0xA2,0xFE,0x4D,0xFF,0xBF,0xFF,0xF4,0xFF,0xFE,0x00,0xBF,0x01, + 0x92,0x01,0xB7,0x01,0x46,0x01,0xD2,0x00,0x2B,0x01,0xFF,0x00, + 0xB4,0x00,0xA5,0x00,0x2A,0x00,0x84,0xFF,0xD2,0xFF,0x1E,0x00, + 0xFA,0xFF,0x30,0x00,0xFE,0xFF,0x9C,0xFF,0x19,0x00,0x1E,0x04, + 0x57,0x06,0x9D,0x03,0x4F,0x04,0x46,0x04,0xE5,0x00,0x40,0x00, + 0x93,0x00,0x49,0xFF,0x84,0xFD,0xB0,0xFC,0xB2,0xFA,0x6E,0xF9, + 0x12,0xF9,0xE2,0xF8,0xE8,0xFA,0xAB,0xFA,0x22,0xFA,0xD4,0xFB, + 0x0F,0xFD,0x7E,0xFE,0x4B,0x01,0xCB,0x03,0xD4,0x03,0xE7,0x04, + 0xA3,0x05,0x74,0x05,0x8E,0x06,0x69,0x06,0x24,0x06,0xB3,0x05, + 0x81,0x04,0x11,0x03,0x83,0x02,0xDB,0x01,0xC2,0x00,0x05,0x01, + 0xCE,0xFF,0x9E,0xFE,0x8D,0xFE,0xDD,0xFD,0x5B,0xFD,0x86,0xFD, + 0xA9,0xFD,0xE6,0xFC,0xEA,0xFC,0xBB,0xFC,0x6E,0xFC,0xE7,0xFC, + 0xC0,0xFC,0x28,0xFD,0x84,0xFD,0x78,0xFD,0x06,0xFE,0xE7,0xFE, + 0x5A,0xFF,0xED,0xFF,0x03,0x01,0x17,0x01,0x5A,0x01,0xC2,0x01, + 0x8D,0x01,0xB8,0x01,0xC2,0x01,0x76,0x01,0x39,0x01,0x30,0x01, + 0x78,0x00,0x1E,0x00,0x64,0x00,0x27,0x00,0x3D,0x00,0x14,0x00, + 0x18,0x00,0xD9,0xFF,0x6E,0xFF,0x8C,0xFF,0x7C,0x01,0x51,0x05, + 0x38,0x04,0xE7,0x02,0xA6,0x04,0x52,0x02,0x6D,0x00,0xF7,0x00, + 0x1E,0x00,0xFD,0xFD,0x17,0xFD,0x04,0xFC,0xFA,0xF9,0xF5,0xF9, + 0x32,0xF9,0xCC,0xF9,0xFF,0xFA,0xFB,0xF9,0xF1,0xFA,0xCF,0xFC, + 0x0E,0xFE,0xD6,0xFF,0xBC,0x02,0x6A,0x03,0x99,0x03,0x5D,0x05, + 0x59,0x05,0x21,0x06,0xCD,0x06,0x36,0x06,0xA0,0x05,0xE1,0x04, + 0xAB,0x03,0xBC,0x02,0xCD,0x02,0x80,0x01,0x07,0x01,0x82,0x00, + 0xF7,0xFE,0xA8,0xFE,0xE5,0xFD,0x3D,0xFD,0x88,0xFD,0xC2,0xFD, + 0xD4,0xFC,0xAA,0xFC,0x11,0xFD,0x76,0xFC,0xFF,0xFC,0x59,0xFD, + 0x24,0xFD,0x5A,0xFD,0x6C,0xFD,0xC9,0xFD,0xA8,0xFE,0x46,0xFF, + 0x8F,0xFF,0xA1,0x00,0xE5,0x00,0xCC,0x00,0x8F,0x01,0xAE,0x01, + 0xA4,0x01,0xD0,0x01,0xAC,0x01,0x25,0x01,0x0B,0x01,0xE1,0x00, + 0x52,0x00,0x73,0x00,0x5D,0x00,0x34,0x00,0x2D,0x00,0x0A,0x00, + 0x2B,0x00,0xFE,0xFF,0xD4,0xFF,0xAD,0xFF,0xDC,0xFF,0xE5,0x02, + 0x18,0x05,0x19,0x03,0x6F,0x03,0x0B,0x04,0x45,0x01,0x63,0x00, + 0x8C,0x00,0x06,0xFF,0x5C,0xFD,0xE9,0xFC,0x7D,0xFB,0x50,0xFA, + 0x14,0xFA,0x66,0xF9,0x93,0xFA,0xCF,0xFA,0x88,0xFA,0x2C,0xFC, + 0xC2,0xFD,0xDB,0xFE,0xD2,0x00,0xFF,0x02,0xFB,0x02,0x0F,0x04, + 0x61,0x05,0x81,0x05,0x56,0x06,0x53,0x06,0xAE,0x05,0xEB,0x04, + 0x47,0x04,0x27,0x03,0xE5,0x02,0x7D,0x02,0x2B,0x01,0xE4,0x00, + 0xB1,0xFF,0x82,0xFE,0x60,0xFE,0xF2,0xFD,0x3F,0xFD,0xA4,0xFD, + 0x9C,0xFD,0xAB,0xFC,0xFB,0xFC,0x04,0xFD,0xF0,0xFC,0x41,0xFD, + 0x55,0xFD,0x3F,0xFD,0x68,0xFD,0xA5,0xFD,0x0A,0xFE,0x1C,0xFF, + 0x41,0xFF,0xAB,0xFF,0x82,0x00,0xA3,0x00,0xF3,0x00,0x88,0x01, + 0xBA,0x01,0x89,0x01,0xD2,0x01,0x7D,0x01,0x2C,0x01,0x4F,0x01, + 0xE6,0x00,0xB3,0x00,0xAA,0x00,0x56,0x00,0x0E,0x00,0x40,0x00, + 0x15,0x00,0xFB,0xFF,0x46,0x00,0xF2,0xFF,0xBD,0xFF,0x8C,0xFF, + 0x56,0xFF,0x80,0x02,0x09,0x05,0x8E,0x02,0x36,0x03,0x48,0x04, + 0x10,0x01,0x34,0x00,0xE0,0x00,0x1C,0xFF,0x4C,0xFD,0x7A,0xFD, + 0xCC,0xFB,0x78,0xFA,0x8F,0xFA,0xAD,0xF9,0xBD,0xFA,0x2F,0xFB, + 0xBD,0xFA,0x31,0xFC,0x17,0xFE,0xBB,0xFE,0x86,0x00,0xEC,0x02, + 0x83,0x02,0xA2,0x03,0x4C,0x05,0x4E,0x05,0x01,0x06,0x6C,0x06, + 0x79,0x05,0x93,0x04,0x6D,0x04,0x24,0x03,0xE9,0x02,0xAF,0x02, + 0x35,0x01,0xBB,0x00,0xCB,0xFF,0x4A,0xFE,0xFD,0xFD,0x69,0xFE, + 0x27,0xFD,0x35,0xFD,0xDD,0xFD,0x9E,0xFC,0xEF,0xFC,0x70,0xFD, + 0x28,0xFD,0x47,0xFD,0x95,0xFD,0x43,0xFD,0x7B,0xFD,0x16,0xFE, + 0xFD,0xFD,0x18,0xFF,0x6C,0xFF,0x4F,0xFF,0x3B,0x00,0xAF,0x00, + 0xBF,0x00,0x63,0x01,0xE5,0x01,0x4C,0x01,0x97,0x01,0x83,0x01, + 0xF4,0x00,0x69,0x01,0x35,0x01,0xA8,0x00,0xC3,0x00,0xA7,0x00, + 0xF5,0xFF,0x48,0x00,0x7A,0x00,0xFF,0xFF,0x27,0x00,0x2B,0x00, + 0x06,0x00,0xE0,0xFF,0xDE,0xFF,0x4D,0xFF,0xA6,0xFF,0x16,0x03, + 0x03,0x04,0x12,0x02,0x80,0x03,0x90,0x03,0xA8,0x00,0x5E,0x00, + 0x77,0x00,0x76,0xFE,0x4B,0xFD,0x58,0xFD,0xEA,0xFB,0x07,0xFB, + 0xC5,0xFA,0x32,0xFA,0x0C,0xFB,0x34,0xFB,0x4A,0xFB,0xF9,0xFC, + 0x83,0xFE,0x26,0xFF,0xED,0x00,0x9B,0x02,0x70,0x02,0xCF,0x03, + 0x44,0x05,0x7B,0x05,0xF6,0x05,0x05,0x06,0x0B,0x05,0x58,0x04, + 0x2F,0x04,0x14,0x03,0xD4,0x02,0x55,0x02,0xE1,0x00,0x3E,0x00, + 0x7A,0xFF,0x30,0xFE,0xCE,0xFD,0x20,0xFE,0x05,0xFD,0x01,0xFD, + 0x97,0xFD,0xC9,0xFC,0x1F,0xFD,0xB0,0xFD,0x66,0xFD,0x3A,0xFD, + 0xB4,0xFD,0x89,0xFD,0xC2,0xFD,0x76,0xFE,0x82,0xFE,0x13,0xFF, + 0x63,0xFF,0x8E,0xFF,0x16,0x00,0xF7,0x00,0xC6,0x00,0x92,0x01, + 0x77,0x01,0xD6,0x00,0xE6,0x01,0x48,0x01,0x55,0x01,0x56,0x01, + 0x2E,0x01,0xD1,0x00,0x84,0x00,0xBA,0x00,0x10,0x00,0x35,0x00, + 0x81,0x00,0xFE,0xFF,0xD7,0xFF,0x34,0x00,0x06,0x00,0xCD,0xFF, + 0x11,0x00,0xFB,0xFF,0x78,0xFF,0x99,0xFF,0x30,0x02,0x0D,0x04, + 0x4D,0x02,0xD9,0x02,0xB5,0x03,0x0E,0x01,0xEA,0xFF,0x76,0x00, + 0x05,0xFF,0x15,0xFD,0x76,0xFD,0x75,0xFC,0xDA,0xFA,0x0C,0xFB, + 0xA3,0xFA,0xD4,0xFA,0x6D,0xFB,0xC5,0xFB,0xC7,0xFC,0x91,0xFE, + 0x95,0xFF,0x88,0x00,0x85,0x02,0xBA,0x02,0x55,0x03,0x1B,0x05, + 0x93,0x05,0x88,0x05,0xD4,0x05,0x54,0x05,0xFB,0x03,0xDE,0x03, + 0x52,0x03,0x5E,0x02,0x02,0x02,0x0A,0x01,0xFA,0xFF,0x42,0xFF, + 0x79,0xFE,0x8A,0xFD,0xFF,0xFD,0xAA,0xFD,0x87,0xFC,0x85,0xFD, + 0x82,0xFD,0xE5,0xFC,0xB1,0xFD,0x06,0xFE,0x44,0xFD,0x71,0xFD, + 0x40,0xFE,0xE0,0xFD,0x67,0xFE,0x0D,0xFF,0xE7,0xFE,0x5B,0xFF, + 0xBA,0xFF,0xF3,0xFF,0x97,0x00,0x27,0x01,0xFF,0x00,0x4B,0x01, + 0x7E,0x01,0xFE,0x00,0x3D,0x01,0x57,0x01,0xFF,0x00,0xE9,0x00, + 0xCD,0x00,0x7F,0x00,0x82,0x00,0x9D,0x00,0x36,0x00,0x5B,0x00, + 0x68,0x00,0xF2,0xFF,0x2A,0x00,0x74,0x00,0x24,0x00,0x09,0x00, + 0x4D,0x00,0xE9,0xFF,0x91,0xFF,0x19,0x01,0x6D,0x03,0xE8,0x02, + 0xCC,0x01,0xFD,0x02,0x01,0x02,0xCD,0xFF,0x05,0x00,0xD4,0xFF, + 0xC8,0xFD,0xD3,0xFC,0xEE,0xFC,0x8F,0xFB,0xD8,0xFA,0x35,0xFB, + 0xFF,0xFA,0x4C,0xFB,0xE8,0xFB,0xC6,0xFC,0x32,0xFE,0xC5,0xFF, + 0xBF,0x00,0xD6,0x01,0x0B,0x03,0x22,0x03,0x21,0x04,0x7C,0x05, + 0x87,0x05,0x61,0x05,0x3E,0x05,0x58,0x04,0x35,0x03,0x1D,0x03, + 0x8E,0x02,0x88,0x01,0x05,0x01,0x12,0x00,0x1D,0xFF,0x7D,0xFE, + 0xEF,0xFD,0x79,0xFD,0xA1,0xFD,0xC1,0xFD,0x3F,0xFD,0x5B,0xFD, + 0xC9,0xFD,0xF6,0xFD,0x1C,0xFE,0x39,0xFE,0x17,0xFE,0xF6,0xFD, + 0x69,0xFE,0xC4,0xFE,0x19,0xFF,0x32,0xFF,0x20,0xFF,0x3C,0xFF, + 0x9E,0xFF,0xF2,0xFF,0x50,0x00,0xD2,0x00,0x82,0x00,0x8C,0x01, + 0x93,0x01,0x6A,0x00,0xC1,0x00,0xDF,0x00,0x54,0x01,0xDC,0x00, + 0x2D,0x00,0x70,0x00,0x26,0x00,0x33,0x00,0x37,0x00,0xB9,0xFF, + 0xB1,0xFF,0x0E,0x00,0x7F,0x00,0xE5,0x00,0x47,0x01,0xCE,0x00, + 0x78,0x00,0x64,0xFF,0x10,0x01,0xBF,0x07,0xEC,0x08,0x16,0x07, + 0x3C,0x04,0xD3,0xFF,0xD9,0xFE,0x93,0xFD,0xB7,0xFB,0xE8,0xF7, + 0x36,0xF5,0xAD,0xF3,0x53,0xF5,0x85,0xFA,0x42,0xFA,0xFC,0xFA, + 0xB2,0xFC,0x95,0xFE,0x6B,0x02,0x17,0x07,0x72,0x09,0x54,0x07, + 0x38,0x08,0xA5,0x07,0x87,0x07,0x05,0x08,0xD4,0x04,0x59,0x01, + 0x89,0xFE,0x09,0xFE,0xDE,0xFC,0x9C,0xFD,0x79,0xFC,0x32,0xFA, + 0xD6,0xFB,0x6A,0xFD,0xF2,0xFF,0xDC,0x01,0xE8,0x02,0xD8,0x01, + 0x21,0x02,0x81,0x03,0x22,0x02,0x74,0x03,0x3D,0x03,0x7F,0xFF, + 0xCD,0xFD,0x45,0xFD,0x27,0xFC,0xC4,0xFB,0xFA,0xFA,0xF3,0xF8, + 0xD3,0xF9,0x82,0xFC,0xF9,0xFD,0x44,0x00,0x21,0x01,0x0D,0x00, + 0x8C,0x01,0xC7,0x03,0x9A,0x03,0xF1,0x02,0x77,0x02,0xAA,0x00, + 0x99,0x00,0x67,0x01,0x27,0x00,0x13,0xFF,0x22,0xFE,0xC4,0xFD, + 0xA3,0xFE,0x10,0x00,0xA3,0xFF,0x79,0xFF,0xC6,0x00,0x08,0x01, + 0xCC,0x01,0x34,0x02,0x3C,0x02,0xE6,0x01,0x0B,0x02,0x21,0x02, + 0xBC,0x00,0x44,0x00,0x01,0xFE,0xB4,0xFC,0xA7,0x05,0xE1,0x09, + 0x97,0x04,0x15,0x03,0xE5,0xFD,0xE0,0xFB,0xE6,0xFD,0x7F,0xFB, + 0xD1,0xF6,0xBE,0xF3,0xA7,0xF5,0xF5,0xF6,0x84,0xFD,0x55,0xFF, + 0xE4,0xFB,0x68,0xFF,0x64,0x02,0x03,0x06,0xA6,0x08,0xB6,0x09, + 0xE1,0x05,0x82,0x04,0x6C,0x07,0x33,0x05,0x8C,0x04,0x11,0x01, + 0xF1,0xFC,0x19,0xFC,0xC5,0xFD,0x49,0xFE,0xC3,0xFC,0x78,0xFD, + 0xEA,0xFB,0x13,0xFE,0x43,0x02,0x18,0x03,0xE1,0x02,0xB2,0x02, + 0xC0,0x02,0x1C,0x02,0x5D,0x03,0x6D,0x01,0x45,0xFD,0x35,0xFF, + 0xD8,0xFF,0x01,0xFE,0xB8,0xFD,0x5B,0xFB,0xBD,0xF9,0xCB,0xFA, + 0xDA,0xFC,0x49,0xFC,0x42,0xFD,0x6D,0xFF,0x1A,0xFF,0xD9,0x02, + 0xA1,0x03,0xB1,0x01,0xB0,0x01,0xB5,0x01,0x29,0x01,0xBB,0x00, + 0xAD,0x01,0x0A,0xFF,0xBF,0xFE,0xE7,0xFF,0x5F,0xFF,0xF6,0xFF, + 0xA2,0xFF,0x57,0xFF,0x47,0xFF,0x5A,0x01,0x8E,0x01,0x36,0x01, + 0x1D,0x02,0xF7,0x00,0xE1,0x00,0xAC,0x01,0xF2,0x01,0xC5,0x00, + 0xC1,0x00,0x81,0xFF,0x20,0xFE,0xD8,0xFC,0x24,0x02,0x31,0x0C, + 0xCF,0x06,0xD8,0x03,0xFF,0x00,0xF5,0xFB,0x58,0xFF,0xB9,0xFC, + 0x8C,0xF8,0x7F,0xF2,0x76,0xF3,0x65,0xF6,0xA6,0xF9,0xEC,0xFF, + 0x32,0xFB,0x05,0xFD,0xD5,0x01,0xA9,0x05,0x26,0x09,0x16,0x09, + 0x2D,0x08,0xD5,0x03,0xA1,0x07,0xC4,0x07,0x84,0x04,0x88,0x02, + 0x34,0xFD,0x16,0xFC,0xBB,0xFC,0xCC,0xFE,0xAE,0xFC,0xB6,0xFB, + 0xE1,0xFC,0xE6,0xFC,0x6E,0x01,0x69,0x03,0xC9,0x02,0x5E,0x02, + 0xD2,0x02,0x8A,0x03,0x3B,0x03,0xB8,0x02,0x38,0xFF,0xD7,0xFB, + 0x44,0xFD,0x52,0xFF,0x72,0xFE,0xDF,0xFD,0xA2,0xFB,0xF2,0xF9, + 0x9E,0xFC,0x4B,0xFE,0x1E,0xFE,0xF4,0xFD,0x93,0xFE,0x4B,0xFF, + 0xE7,0x01,0xB3,0x03,0x2B,0x01,0x76,0x00,0x77,0x00,0x1F,0x00, + 0xFB,0x00,0x19,0x01,0xA5,0xFF,0x4E,0xFE,0x0F,0x00,0x4A,0x00, + 0x35,0x00,0x12,0x01,0xED,0xFF,0x26,0x00,0x4C,0x01,0xE4,0x01, + 0x77,0x01,0x67,0x01,0xE3,0x00,0xE3,0xFF,0x9C,0x01,0xA3,0x01, + 0xD9,0xFF,0x23,0x00,0xA8,0xFF,0x51,0xFF,0x77,0xFF,0x5D,0xFF, + 0x6C,0xFD,0xEA,0x01,0x60,0x0A,0x38,0x05,0xA4,0x03,0xD4,0x01, + 0x5A,0xFC,0x83,0xFE,0x23,0xFD,0xC8,0xF9,0x61,0xF4,0x81,0xF6, + 0x41,0xF8,0xE8,0xF9,0xDE,0xFF,0x60,0xFC,0x71,0xFD,0x55,0x01, + 0xE2,0x04,0x16,0x06,0xCE,0x06,0xCB,0x06,0x1D,0x03,0x15,0x07, + 0x27,0x07,0x74,0x04,0x7E,0x02,0x98,0xFF,0x07,0xFE,0xEB,0xFD, + 0xE1,0xFF,0xAE,0xFC,0xEF,0xFB,0x4D,0xFD,0x75,0xFD,0x28,0x00, + 0x8D,0x01,0xF0,0x00,0x69,0x00,0x77,0x02,0xFD,0x02,0x40,0x01, + 0x0F,0x02,0xB3,0x01,0x9A,0x00,0x49,0x00,0x96,0xFD,0x70,0xFC, + 0x36,0xFC,0xDB,0xFB,0xBC,0xFB,0x93,0xFB,0x4A,0xFC,0xB6,0xFC, + 0x64,0xFF,0xE9,0x00,0xA2,0x00,0xDF,0x00,0x73,0x01,0x27,0x02, + 0x34,0x02,0x4E,0x02,0xA3,0x00,0x1A,0x00,0x6F,0x00,0x56,0x00, + 0x55,0x00,0x95,0xFF,0x40,0xFF,0xDC,0xFE,0xFF,0xFF,0xAA,0x00, + 0x76,0x00,0xCA,0x00,0xAF,0x00,0x12,0x01,0xA8,0x01,0xB3,0x01, + 0x07,0x01,0xDF,0x00,0xE3,0x00,0x8F,0x00,0x80,0x00,0xA0,0xFF, + 0xE0,0xFE,0xC6,0xFE,0x44,0xFF,0x39,0xFF,0x3F,0xFF,0x35,0x04, + 0x64,0x04,0x2B,0x02,0xA3,0x02,0x07,0xFF,0x6B,0xFE,0xE8,0xFD, + 0x06,0xFD,0x7D,0xFA,0x3C,0xF9,0x31,0xFB,0xB6,0xFA,0xEE,0xFD, + 0x0F,0xFE,0xA8,0xFD,0x4E,0xFF,0x57,0x01,0x6C,0x03,0x4E,0x03, + 0x0D,0x05,0x2A,0x03,0xC3,0x03,0x8C,0x05,0x11,0x04,0x89,0x03, + 0xCE,0x01,0xA7,0x00,0x90,0xFF,0x3F,0x00,0xD1,0xFF,0xED,0xFD, + 0x6E,0xFE,0x46,0xFE,0xC7,0xFE,0x49,0x00,0x15,0x00,0xE0,0xFF, + 0xFF,0x01,0x7C,0x03,0x4A,0x02,0x42,0x01,0x1E,0x00,0x2F,0xFE, + 0x27,0xFD,0x9D,0xFC,0x3D,0xFB,0x9C,0xFA,0xC7,0xFB,0xB9,0xFC, + 0x42,0xFE,0x58,0xFF,0x07,0xFF,0x8E,0xFF,0x12,0x01,0x83,0x01, + 0x11,0x01,0x92,0x01,0x31,0x01,0x5C,0x01,0x4D,0x02,0xFC,0x01, + 0xF5,0x00,0x63,0x00,0x71,0x00,0x91,0x00,0xE8,0x00,0xCB,0xFF, + 0x84,0xFE,0xF7,0xFE,0xDF,0xFF,0x67,0x00,0xE7,0x00,0xBA,0x00, + 0x13,0x00,0x73,0x00,0xF4,0x00,0xD6,0x00,0x19,0x00,0x48,0xFF, + 0x18,0xFF,0xA1,0xFF,0x47,0x00,0x07,0x00,0x59,0xFF,0xE7,0xFE, + 0x0D,0xFF,0xEA,0xFF,0x26,0x00,0x97,0xFF,0x3A,0xFF,0xD0,0xFF, + 0x48,0x00,0x63,0x00,0x18,0x01,0xE1,0x00,0xAE,0x00,0xC3,0x00, + 0xDF,0x00,0xB0,0x00,0x4A,0x00,0xFD,0xFF,0xCB,0xFE,0x01,0xFF, + 0x64,0xFF,0x80,0xFF,0xA6,0xFF,0x24,0xFF,0x46,0xFF,0x8C,0xFF, + 0x7A,0x00,0x99,0x00,0x9C,0x00,0x01,0x01,0xB3,0x00,0x55,0x01, + 0x78,0x01,0xFC,0x00,0xD3,0x00,0xC3,0x00,0x7C,0x00,0x9C,0x00, + 0x98,0x00,0xA6,0xFF,0x91,0xFF,0x2A,0x00,0x42,0xFF,0x4E,0xFE, + 0x15,0xFF,0xC1,0xFE,0xDE,0xFE,0x8B,0xFF,0xE0,0xFE,0x11,0xFF, + 0x6B,0xFF,0x6D,0xFF,0x69,0xFF,0xD2,0xFF,0x20,0x00,0x20,0xFF, + 0x33,0x00,0x0E,0x00,0xF0,0xFF,0x38,0x01,0xE9,0xFF,0x45,0x00, + 0x6C,0x00,0x79,0x00,0x17,0x00,0x3C,0x00,0xF4,0xFF,0x32,0xFF, + 0xE2,0xFF,0x46,0xFF,0xF2,0xFF,0x48,0xFF,0x67,0xFF,0x37,0x00, + 0x37,0x00,0xCD,0x00,0xB4,0xFF,0x61,0x00,0x59,0x00,0xAD,0x00, + 0x0D,0x01,0x01,0x00,0x63,0x00,0xE2,0xFF,0x6F,0x00,0x70,0x00, + 0xC2,0xFF,0x6B,0xFF,0x59,0xFF,0x96,0xFF,0xAE,0xFF,0x9B,0xFF, + 0xA1,0xFF,0x62,0x00,0x9E,0x00,0xE7,0x00,0x71,0x01,0x3C,0x00, + 0x80,0x00,0x4D,0x00,0x89,0x00,0x90,0x01,0x71,0xFF,0xB2,0xFF, + 0x3D,0xFF,0xF5,0xFF,0xFA,0xFF,0x63,0xFF,0x0A,0xFF,0x5C,0xFF, + 0x73,0x01,0xF6,0x00,0x50,0x00,0x6B,0xFF,0x72,0x00,0x4F,0x00, + 0x4F,0x00,0xA4,0x00,0x8E,0x00,0xDC,0x00,0xF9,0xFE,0x42,0xFF, + 0x90,0xFF,0xFA,0xFF,0x1C,0xFF,0x9E,0xFD,0xC9,0xFF,0x70,0x00, + 0xCC,0xFF,0x9C,0xFF,0xA6,0xFF,0x5F,0xFF,0xF6,0x00,0x0F,0x00, + 0x53,0xFF,0x6D,0x01,0xD6,0xFF,0x09,0xFF,0x1B,0x00,0x9E,0x00, + 0x40,0x00,0xDA,0xFE,0x96,0xFF,0x48,0x00,0xD4,0xFE,0x7F,0x00, + 0x38,0xFF,0x80,0xFF,0xB6,0x00,0x09,0xFE,0x8F,0x01,0xF9,0x01, + 0x72,0xFF,0x5F,0x00,0x9C,0x00,0xA2,0x00,0x3A,0xFF,0x58,0x00, + 0x31,0x00,0x18,0x00,0x40,0xFF,0xF6,0xFD,0x33,0x00,0xF0,0xFF, + 0x6F,0x00,0x90,0xFF,0x4F,0x00,0xD0,0x00,0x1F,0x01,0x74,0xFF, + 0xF7,0xFF,0xEE,0x00,0xAC,0xFE,0xB8,0x02,0x8E,0x00,0x37,0xFF, + 0x25,0x00,0x68,0x00,0xDF,0xFF,0x6B,0xFE,0x9D,0x00,0x23,0xFF, + 0x72,0x00,0x4B,0xFE,0x5C,0xFF,0x2E,0x03,0x12,0xFF,0x89,0xFE, + 0xF4,0x01,0xD4,0x01,0x74,0xFE,0x32,0x01,0x20,0x00,0x2C,0xFF, + 0xC0,0x01,0x65,0xFF,0x28,0xFF,0xBA,0x01,0x52,0xFE,0xAD,0xFE, + 0x55,0x01,0x10,0xFF,0xE4,0x00,0xB0,0xFE,0xAB,0xFF,0x44,0x00, + 0xFF,0xFE,0x4F,0x00,0x1A,0x01,0xAE,0x00,0x95,0xFE,0x48,0x01, + 0xE8,0x00,0x60,0x00,0x85,0xFF,0x0A,0xFF,0x50,0x00,0x2B,0xFE, + 0xCC,0xFF,0x75,0x00,0xCB,0xFE,0x95,0x00,0x64,0x00,0xD8,0xFF, + 0x77,0x00,0xC1,0xFF,0x48,0x00,0x29,0x00,0x8F,0xFF,0x03,0x01, + 0x93,0xFE,0x05,0x01,0xA2,0x01,0xDE,0xFD,0x1B,0x00,0x97,0xFE, + 0x9F,0x01,0x35,0xFE,0xA1,0x00,0x6C,0x01,0x4C,0xFD,0x81,0x01, + 0xBA,0xFF,0xFA,0xFF,0xC7,0xFF,0x66,0x01,0xC1,0xFE,0x71,0x02, + 0xF7,0x00,0xF1,0xFE,0x5C,0x00,0x26,0xFE,0x16,0xFF,0x34,0xFE, + 0xDE,0x01,0x4F,0xFF,0x58,0x02,0x51,0xFD,0xE8,0xFF,0x9A,0x04, + 0x7A,0xFD,0x89,0x01,0xD8,0xFC,0x71,0x01,0x78,0x02,0xE3,0xFD, + 0xC2,0xFF,0x77,0xFE,0xAA,0x01,0xF2,0xFF,0xF7,0x00,0x3E,0xFF, + 0x9A,0xFE,0xCD,0x00,0xDD,0xFF,0x6E,0x01,0x6E,0x00,0xCA,0xFE, + 0xB3,0xFE,0x44,0x02,0x8F,0x00,0x46,0xFF,0xA2,0xFF,0x89,0x00, + 0x83,0x00,0xBA,0xFF,0xF6,0xFF,0x6B,0xFE,0xF1,0x00,0xF5,0xFE, + 0x47,0x01,0x6B,0x00,0xD4,0xFD,0x68,0x02,0xCA,0xFD,0x1C,0x02, + 0xAF,0x00,0xBE,0xFC,0x71,0x02,0x9D,0xFF,0x5D,0x01,0x96,0x00, + 0x69,0xFE,0x7C,0xFE,0xA5,0x01,0x6D,0xFF,0xB8,0xFE,0x02,0x01, + 0xB4,0xFF,0xB6,0xFF,0x71,0x00,0xB5,0x01,0x15,0xFD,0xA9,0x00, + 0x8D,0x00,0xB2,0xFF,0xF3,0x01,0xC4,0xFD,0x14,0x00,0x39,0x01, + 0x2A,0x00,0x73,0x00,0x44,0xFF,0x73,0x00,0xDD,0xFE,0x4B,0x00, + 0x47,0x00,0x36,0xFE,0x5B,0x01,0x4C,0x00,0x45,0xFD,0xCD,0x00, + 0x30,0x02,0x0C,0x00,0xF0,0xFD,0x8B,0xFF,0x4A,0x01,0x75,0x00, + 0x10,0x00,0xE7,0xFD,0x5A,0x02,0x1D,0xFF,0x04,0x01,0xDA,0x00, + 0x47,0xFE,0xCD,0x01,0xB7,0xFF,0xE8,0xFD,0x61,0x00,0xEB,0xFF, + 0x78,0xFE,0xD8,0x02,0x67,0xFE,0x35,0x02,0x0A,0xFF,0x7A,0xFD, + 0x0A,0x01,0x4F,0x00,0x5A,0x00,0xF4,0xFE,0xC3,0x01,0x76,0x00, + 0xAD,0x01,0x15,0xFF,0xBA,0xFF,0x7B,0xFE,0x84,0xFE,0x5B,0x02, + 0x1A,0xFF,0x84,0x00,0x78,0x01,0xC6,0xFE,0x01,0xFF,0x38,0x01, + 0xB2,0xFD,0x6D,0x01,0x29,0x00,0xD9,0xFD,0x79,0x03,0x8C,0xFE, + 0xE4,0x01,0x7C,0xFE,0xB3,0xFF,0x76,0x00,0x59,0x00,0x29,0x01, + 0x8F,0xFE,0xD7,0xFF,0x08,0xFF,0x0D,0x03,0xDD,0xFD,0xBC,0x01, + 0x50,0xFD,0x0A,0x00,0x4F,0x02,0x8E,0xFD,0xCD,0x00,0x65,0xFF, + 0x09,0x01,0xBF,0xFE,0xBA,0x01,0x83,0xFF,0xE4,0xFE,0xBF,0x01, + 0xF6,0xFF,0xA4,0xFE,0xA0,0x00,0xC8,0x00,0x23,0xFF,0xFA,0x01, + 0x8E,0xFE,0xBB,0xFF,0x5D,0x01,0x73,0xFF,0x1C,0x00,0xC9,0xFD, + 0x0B,0x01,0x0B,0x00,0x76,0x00,0x45,0x00,0x12,0xFE,0x53,0x00, + 0xF0,0xFE,0x04,0x02,0x1A,0x01,0x1F,0xFE,0xF3,0xFF,0xE7,0x00, + 0x96,0x00,0x46,0x01,0x68,0xFF,0x17,0xFD,0xC2,0x00,0x8F,0x02, + 0x9A,0x00,0xD6,0xFD,0x73,0xFD,0xC7,0x01,0xD6,0xFE,0x56,0x00, + 0x54,0x01,0xA0,0xFE,0xD8,0xFF,0xCD,0xFF,0x98,0x02,0x90,0xFF, + 0x0A,0x00,0x2A,0xFF,0x34,0x01,0x42,0xFF,0xAE,0x00,0x27,0x01, + 0x14,0xFD,0x89,0x02,0x59,0xFE,0x5A,0x00,0xE1,0xFF,0x08,0xFF, + 0x9B,0x01,0x94,0xFE,0xA1,0xFE,0x7F,0x01,0x0A,0x00,0x50,0x00, + 0xBF,0x00,0x4D,0xFE,0x54,0x01,0x11,0x01,0x3F,0xFF,0x4A,0xFE, + 0x82,0x01,0xC8,0x01,0x17,0xFE,0x9E,0xFF,0x6E,0xFF,0x9B,0x00, + 0x52,0x00,0x1B,0xFF,0x9D,0xFF,0xE1,0xFF,0xFE,0x00,0x4B,0xFF, + 0x5A,0x00,0xC8,0x00,0x2D,0x02,0xAF,0xFE,0x40,0xFD,0xD9,0x01, + 0x4E,0x01,0x2F,0x01,0x68,0xFD,0x34,0x00,0x2F,0x02,0xA9,0xFD, + 0xDA,0xFF,0x1A,0x00,0x2C,0xFE,0xA5,0x00,0xBB,0x00,0x66,0xFF, + 0xC5,0x01,0x92,0xFE,0x46,0x00,0x61,0x01,0xFF,0xFD,0xA5,0x01, + 0x58,0xFF,0x74,0x01,0x0D,0x01,0x54,0xFD,0x33,0x00,0xF4,0xFE, + 0x7E,0x00,0xFC,0x01,0x72,0xFE,0xAD,0x00,0x80,0x00,0xB3,0xFC, + 0x1C,0x02,0xD1,0xFF,0x8C,0x00,0x8E,0xFF,0x68,0xFE,0x18,0x04, + 0xA3,0xFD,0x72,0x00,0xF3,0x01,0x95,0xFD,0xF4,0xFF,0xEE,0xFF, + 0xA6,0xFE,0x4B,0x02,0xEA,0xFF,0x0B,0xFF,0x58,0x00,0x9D,0x00, + 0xCE,0x01,0x23,0xFC,0x7B,0x01,0x32,0x00,0x59,0xFE,0x33,0x03, + 0x2D,0xFE,0x26,0x01,0x3B,0x00,0x25,0xFC,0xC6,0x02,0x2F,0x00, + 0xEF,0xFD,0x6E,0x01,0x3F,0x01,0x38,0x00,0x29,0xFF,0x6D,0xFE, + 0xAA,0x00,0x62,0x00,0xDF,0xFE,0x0E,0x00,0xE9,0x01,0x54,0xFF, + 0x8E,0xFE,0xC4,0x02,0x07,0xFC,0xDC,0x01,0x29,0x03,0xEA,0xFD, + 0x0E,0x00,0x18,0x00,0xB3,0x00,0xEB,0xFF,0x87,0xFF,0x2F,0x00, + 0x01,0x00,0x64,0xFE,0xF2,0x01,0x3C,0xFE,0x67,0x01,0x6F,0xFE, + 0xA0,0xFE,0xA2,0x03,0x29,0xFD,0x87,0xFF,0x27,0x01,0x85,0x01, + 0x45,0xFE,0xCE,0x00,0xE7,0xFF,0x0F,0xFF,0x9E,0x01,0xD6,0xFF, + 0x45,0x01,0xD0,0xFD,0x6C,0x01,0x48,0x00,0xB6,0xFF,0x45,0x00, + 0x2B,0xFE,0x49,0x01,0x63,0xFE,0x51,0x02,0x1D,0xFE,0x28,0xFF, + 0x24,0x02,0x7A,0xFF,0xCB,0x00,0x65,0xFD,0xC2,0x01,0x20,0x00, + 0xB2,0x00,0xD3,0xFF,0x37,0xFE,0xAA,0x00,0x36,0x01,0xCB,0x00, + 0xC3,0xFE,0xAD,0xFE,0x37,0xFF,0xED,0x03,0xDE,0xFD,0x2B,0x00, + 0x06,0x00,0x61,0xFF,0x0F,0x02,0x99,0xFD,0x42,0x01,0xA7,0xFE, + 0x4E,0x00,0xF3,0xFE,0x43,0x02,0xF3,0xFF,0x63,0xFE,0x78,0x01, + 0xFD,0xFE,0xC3,0x00,0xA4,0xFE,0x8F,0x01,0xC1,0xFF,0xF1,0x01, + 0xA6,0xFD,0x41,0x00,0x3C,0x01,0x8C,0xFF,0x82,0x01,0x92,0xFC, + 0x8B,0x01,0xC4,0xFE,0x97,0x00,0xD0,0xFE,0x74,0x00,0xCC,0x00, + 0x98,0xFE,0x61,0x00,0xFA,0xFF,0x99,0x02,0x9D,0xFE,0x9F,0x01, + 0xCA,0xFF,0x14,0xFE,0x1A,0x02,0x16,0xFF,0x50,0x00,0x33,0x00, + 0x12,0xFE,0x20,0x01,0x56,0xFD,0x76,0x00,0x00,0x01,0x01,0x00, + 0x53,0x01,0x3B,0xFD,0xAB,0x01,0xB7,0x01,0x7A,0x01,0xCA,0xFD, + 0x97,0x00,0xEF,0xFE,0xFB,0x00,0x79,0x02,0x9A,0xFC,0x32,0x02, + 0xC5,0xFC,0x75,0xFF,0x2D,0x01,0xA8,0xFF,0x8B,0xFE,0x63,0x01, + 0x88,0x00,0x37,0xFE,0x22,0x04,0x9A,0xFE,0x2C,0x00,0xDA,0xFF, + 0x73,0xFE,0x5B,0x01,0x67,0x00,0xC3,0xFC,0x88,0x01,0x89,0x02, + 0xDD,0xFC,0x10,0x03,0xAD,0xFE,0x35,0x00,0xE9,0x00,0xCA,0xFD, + 0xAC,0x00,0xA4,0xFD,0x6A,0x01,0xEB,0x00,0x05,0x00,0x1D,0xFF, + 0x4C,0x01,0x73,0xFF,0x93,0x00,0x06,0x03,0xC6,0xFB,0xDB,0x01, + 0xED,0xFD,0x2B,0x01,0xC0,0x02,0x39,0xFB,0xDC,0x00,0x1D,0x00, + 0xA6,0x01,0xE8,0xFE,0x75,0x00,0xB9,0xFF,0x15,0x01,0x35,0xFF, + 0xF8,0xFF,0x64,0x03,0x0A,0xFB,0x78,0x02,0xD1,0xFF,0x8D,0x00, + 0xDD,0xFF,0xD6,0xFD,0x61,0x01,0xC8,0xFF,0xA3,0x00,0xCD,0xFE, + 0xC4,0xFE,0x82,0xFF,0x0C,0x02,0x76,0xFF,0xE5,0xFE,0x3B,0x02, + 0xE9,0xFE,0x6A,0x00,0xF7,0x02,0xB0,0xFF,0x9E,0xFE,0xD9,0xFF, + 0x90,0xFF,0x25,0xFF,0x2A,0x02,0x44,0xFD,0x51,0xFF,0x3F,0x00, + 0x4E,0xFE,0x76,0x01,0xB9,0x00,0x54,0x00,0xD0,0x00,0xAF,0x00, + 0x7E,0xFF,0xFB,0x01,0x81,0xFF,0xF9,0xFF,0x1B,0xFF,0x17,0x00, + 0xA0,0x00,0xC5,0xFC,0xF8,0x02,0x95,0xFD,0x6C,0xFE,0x13,0x03, + 0xFD,0xFD,0xBB,0xFF,0xFD,0xFF,0x38,0x02,0x36,0x01,0x6D,0xFF, + 0x40,0xFF,0x0C,0x00,0x13,0x01,0xC4,0x00,0xDA,0xFD,0xB1,0xFF, + 0x90,0xFF,0x6C,0xFF,0xA0,0x01,0xB2,0xFE,0xDC,0x00,0xF5,0xFF, + 0x83,0xFF,0x92,0x00,0xE1,0xFF,0xC5,0xFE,0x1F,0x02,0x5E,0x00, + 0x4C,0xFF,0xA3,0xFE,0xC4,0xFF,0xB4,0x02,0xEC,0x00,0x48,0x00, + 0xC8,0xFC,0x91,0x01,0x64,0xFF,0x3B,0xFE,0x4C,0x01,0x3B,0xFF, + 0xCA,0xFF,0x31,0xFE,0xC9,0x01,0xCB,0x01,0x34,0x02,0xA8,0xFE, + 0x9E,0xFB,0x15,0x02,0xBC,0x01,0xCD,0xFF,0x91,0x00,0x7A,0x00, + 0xD7,0xFA,0x19,0x02,0x22,0x03,0x7B,0xFD,0x17,0x01,0x91,0xFD, + 0x46,0x01,0x78,0x02,0x8E,0x00,0x13,0xFD,0x2F,0x00,0xA2,0x01, + 0xBE,0xFF,0x93,0x00,0x7B,0xFC,0x54,0x01,0x1C,0x00,0x50,0x00, + 0x48,0xFF,0xF9,0xFD,0xE0,0x01,0x83,0x00,0xC6,0x01,0x35,0x00, + 0xF1,0xFE,0x0C,0x02,0xED,0xFD,0xF1,0x00,0x69,0x00,0xBE,0xFD, + 0x4F,0x01,0x2E,0xFE,0x2F,0xFF,0x34,0x01,0x55,0x00,0x75,0xFD, + 0x1F,0x02,0xB0,0xFF,0x4E,0x00,0x56,0x01,0xD6,0x00,0x96,0x01, + 0x14,0xFC,0x56,0x03,0x34,0x00,0xBA,0xFD,0x6E,0x00,0xFB,0xFF, + 0xC0,0xFF,0x01,0xFD,0x87,0x02,0x67,0xFF,0xA4,0xFF,0x63,0x00, + 0x7B,0xFD,0x99,0x03,0xAA,0x00,0xD6,0xFE,0x5C,0xFF,0x15,0x00, + 0x10,0x00,0x6F,0x02,0x43,0xFF,0x68,0xFE,0x06,0x02,0x11,0xFF, + 0xA1,0xFF,0x63,0xFE,0xE2,0x00,0x60,0xFF,0x54,0x01,0xEC,0xFE, + 0xB1,0xFE,0xF3,0x02,0xD1,0xFF,0xED,0xFE,0x0F,0x00,0x78,0xFF, + 0xDA,0x00,0xB0,0x00,0x5B,0xFE,0xD4,0x02,0x10,0xFD,0x46,0x02, + 0x99,0xFF,0x30,0xFF,0xE3,0x02,0x11,0xFC,0x51,0x00,0xC6,0x00, + 0xBB,0x00,0x98,0xFD,0x90,0x02,0x1F,0xFD,0xE2,0xFF,0x92,0x02, + 0xC9,0xFE,0x47,0x01,0x7E,0xFD,0xC4,0x02,0xBD,0x00,0x63,0xFF, + 0x6E,0xFE,0xE7,0x00,0x82,0x00,0xFE,0xFF,0xDA,0x00,0x45,0xFF, + 0x03,0xFF,0x22,0xFE,0xCD,0x01,0xFB,0xFE,0xCE,0xFF,0x7F,0x01, + 0x4D,0xFE,0xC7,0x00,0x64,0x02,0xF9,0xFF,0x05,0x00,0xAA,0xFE, + 0x59,0xFF,0xD6,0x00,0xF2,0xFF,0xEE,0x00,0x67,0xFD,0x14,0x00, + 0x71,0x00,0x79,0x00,0x14,0x01,0x7F,0xFD,0xFE,0x01,0x52,0x00, + 0xA3,0xFF,0x1F,0x00,0x60,0xFF,0xA7,0xFE,0x86,0x01,0x56,0x01, + 0xF4,0xFE,0x6B,0x00,0x87,0xFF,0xD8,0x00,0x15,0x00,0xCF,0x00, + 0xF7,0xFD,0x99,0xFE,0x6D,0x00,0x44,0x00,0x7D,0x00,0xA8,0xFF, + 0xEF,0xFE,0xBB,0x01,0x30,0x01,0x78,0xFE,0x7A,0x00,0x8F,0xFF, + 0x43,0x01,0x37,0xFF,0xDC,0x00,0x8B,0xFF,0x2F,0x02,0x53,0xFE, + 0x02,0xFE,0x8E,0x02,0xDA,0xFC,0x2E,0x01,0xBD,0xFD,0x25,0x02, + 0xEC,0x00,0xF3,0xFD,0x5F,0x01,0x36,0xFE,0x27,0x02,0xBA,0xFF, + 0x84,0xFF,0xA2,0xFF,0x32,0x00,0x64,0x02,0xE0,0xFE,0xF6,0x02, + 0x5A,0xFD,0x92,0xFF,0x94,0x01,0xF7,0xFD,0x9F,0x01,0xF2,0xFE, + 0x0C,0x00,0x1F,0xFF,0xED,0x00,0x31,0xFD,0x7D,0x02,0xC9,0xFF, + 0x1F,0xFD,0xFB,0x03,0x39,0xFC,0x0F,0x01,0x66,0x04,0xFA,0xFF, + 0x59,0xFE,0xB9,0xFF,0xB0,0xFF,0x57,0x00,0xAD,0x00,0x68,0xFD, + 0x60,0xFE,0xF6,0x01,0x90,0xFF,0x95,0x00,0xEE,0x00,0x22,0xFF, + 0xBB,0x00,0x32,0x00,0x0D,0x00,0xB8,0xFD,0xF7,0x00,0x3C,0x00, + 0xC6,0x00,0x42,0x01,0x5D,0x00,0x23,0xFE,0x74,0x00,0x7A,0x01, + 0x9E,0xFC,0xB8,0x02,0x5E,0xFE,0xD8,0xFE,0x8A,0x00,0x94,0xFF, + 0x84,0x01,0xE6,0x00,0xA0,0xFE,0xF9,0xFF,0x09,0x02,0x24,0xFF, + 0x0F,0x01,0xAA,0xFF,0x3B,0xFE,0x61,0x00,0x4E,0x01,0xA1,0xFD, + 0x10,0x02,0xB3,0xFE,0x6F,0xFE,0x85,0x01,0x4C,0xFF,0xD7,0x00, + 0x19,0x00,0xEE,0x00,0xA6,0xFD,0xBB,0x03,0x2F,0x00,0xF0,0xFD, + 0x55,0x00,0x4C,0xFD,0x69,0x02,0x35,0x00,0xDB,0xFF,0x87,0xFE, + 0xC2,0xFF,0x33,0x00,0x33,0x00,0x25,0x02,0x7B,0xFE,0x1D,0x00, + 0x54,0x00,0x63,0x01,0x54,0xFE,0x8D,0x01,0x00,0x00,0x85,0xFD, + 0xFE,0x01,0x33,0xFD,0x11,0x01,0xDE,0x00,0xEF,0xFF,0x08,0x00, + 0xFC,0xFE,0xF6,0xFF,0xE6,0xFF,0x01,0x01,0x30,0x00,0x72,0x01, + 0x23,0xFD,0xC2,0x01,0x2B,0x01,0x80,0xFF,0xED,0x02,0xB9,0xFB, + 0x40,0x01,0xC9,0xFF,0x6A,0xFF,0xFA,0x00,0xDD,0xFC,0x57,0x00, + 0x9F,0xFF,0xA9,0x00,0x88,0xFF,0x9F,0x01,0xB0,0xFF,0x7C,0xFE, + 0xA0,0x03,0x18,0xFE,0x0A,0x00,0x9D,0xFF,0x08,0x00,0x98,0x02, + 0x6C,0xFD,0x8A,0x01,0x3C,0xFF,0xDE,0xFE,0x5E,0x02,0x24,0x00, + 0x0E,0x00,0xA5,0xFE,0x17,0x00,0x1D,0x01,0x56,0x00,0x2D,0xFD, + 0x95,0x01,0x36,0x00,0x86,0xFC,0x94,0x02,0x30,0xFF,0xBB,0x00, + 0x37,0x00,0x63,0xFE,0x25,0x01,0x95,0xFF,0x66,0x00,0xC6,0x00, + 0xB3,0xFF,0x98,0x00,0x44,0x00,0x03,0x01,0x35,0x00,0x74,0xFE, + 0x2C,0x00,0x01,0x00,0x6C,0xFF,0x9A,0xFF,0xCE,0xFE,0x73,0xFF, + 0xED,0x01,0x31,0xFF,0x53,0xFF,0x96,0x00,0x22,0xFF,0x85,0x01, + 0xF5,0x01,0x14,0x00,0x7B,0xFE,0x1A,0xFF,0x41,0x02,0xBB,0xFF, + 0xEE,0xFE,0x1C,0x00,0xCF,0xFF,0x0D,0x00,0xB9,0x00,0x5B,0xFF, + 0xFC,0xFD,0x9F,0x02,0x30,0xFF,0xFE,0xFE,0x37,0x01,0x67,0xFF, + 0x36,0x00,0x18,0x00,0xBC,0xFF,0xA0,0xFF,0xC4,0x00,0x92,0xFF, + 0xFA,0xFF,0x83,0x01,0x98,0x00,0x13,0xFE,0xC5,0x00,0xBA,0x00, + 0xE3,0xFE,0x1C,0x01,0xCC,0xFE,0x2A,0xFF,0xC0,0x00,0x4F,0x00, + 0x9F,0xFF,0x42,0xFF,0x39,0xFF,0xBD,0x01,0x40,0x00,0xB8,0xFE, + 0x13,0x00,0xB8,0x00,0xFD,0x00,0xC3,0xFF,0x75,0x00,0xCE,0xFE, + 0x32,0xFF,0x44,0x01,0x34,0x00,0x5A,0xFF,0x3D,0xFF,0x07,0xFF, + 0x0B,0x01,0x83,0x00,0x7B,0xFF,0xF9,0x00,0x9B,0x00,0xE2,0xFE, + 0xA3,0xFF,0xCA,0x01,0xF3,0xFF,0x0D,0xFF,0x5A,0x01,0x31,0xFF, + 0x3C,0xFF,0x70,0x00,0xDF,0xFF,0x19,0x01,0xDB,0xFF,0x5E,0xFE, + 0x92,0xFE,0xAC,0x01,0x61,0x00,0x68,0xFF,0x36,0x00,0xC3,0xFE, + 0x3A,0xFF,0xAC,0x00,0xB6,0x01,0xC0,0xFF,0xAD,0xFF,0x3C,0xFF, + 0xD9,0xFD,0xC4,0x03,0xEA,0x03,0xD0,0xFF,0x19,0x01,0x5B,0x02, + 0x24,0x02,0xC8,0xFE,0xE6,0xFE,0x94,0xFE,0xCD,0xFC,0xD7,0xFC, + 0xE7,0xFC,0xDE,0xFC,0x0D,0xFC,0x9D,0xFD,0x68,0xFF,0x18,0x00, + 0x68,0x00,0x86,0x01,0x57,0x02,0x17,0x02,0xB9,0x02,0x5E,0x03, + 0xF2,0x02,0x3D,0x02,0x34,0x02,0x41,0x02,0x85,0x01,0xB6,0x00, + 0x0F,0x00,0x75,0xFF,0xC6,0xFE,0xA9,0xFE,0xDA,0xFE,0xB6,0xFE, + 0xDD,0xFE,0xC8,0xFE,0xD6,0xFE,0xA2,0xFE,0xAB,0xFE,0xD5,0xFE, + 0x35,0xFF,0xEA,0xFF,0xC2,0xFF,0x0B,0x00,0x4B,0x00,0xF4,0xFF, + 0xEE,0xFF,0xFD,0xFF,0x26,0x00,0xFE,0xFF,0xC3,0xFF,0x0B,0x00, + 0x77,0x00,0x5D,0x00,0xF1,0xFF,0x08,0x00,0x62,0x00,0x8E,0x00, + 0x1B,0x00,0x39,0x00,0x53,0x00,0x14,0x00,0x3A,0x00,0xF5,0xFF, + 0x1B,0x00,0x0D,0x00,0xD6,0xFF,0x1E,0x00,0x5D,0x00,0x5E,0x00, + 0x3B,0x00,0x42,0x00,0x53,0x00,0x41,0x00,0x4D,0x00,0x7E,0x00, + 0x2F,0x00,0xF4,0xFF,0x18,0x00,0xF8,0xFF,0xC8,0xFF,0xA3,0xFF, + 0xBB,0xFF,0x94,0xFF,0x94,0xFF,0xDB,0xFF,0x7C,0xFF,0x8F,0xFF, + 0xAC,0xFF,0xD7,0xFF,0xE1,0xFF,0xD3,0xFF,0xE1,0xFF,0xB9,0xFF, + 0x37,0x00,0x22,0x00,0xF9,0xFF,0x37,0x00,0x58,0x00,0x1C,0x00, + 0xE9,0xFF,0x30,0x00,0x38,0x00,0x08,0x00,0xFC,0xFF,0x30,0x00, + 0x1E,0x00,0x1D,0x00,0x0D,0x00,0x03,0x00,0x1C,0x00,0xF4,0xFF, + 0xEC,0xFF,0x17,0x00,0x2D,0x00,0xC3,0xFF,0xD5,0xFF,0x2D,0x00, + 0xE1,0xFF,0xE0,0xFF,0x05,0x00,0xF8,0xFF,0xB9,0xFF,0xD2,0xFF, + 0x2C,0x00,0xE8,0xFF,0xEF,0xFF,0x1C,0x00,0xEC,0xFF,0xD4,0xFF, + 0x24,0x00,0x19,0x00,0xB7,0xFF,0xD1,0xFF,0x20,0x00,0x28,0x00, + 0xD9,0xFF,0xFF,0xFF,0xF7,0xFF,0xDD,0xFF,0x3C,0x00,0x1E,0x00, + 0xEB,0xFF,0x37,0x00,0x57,0x00,0x04,0x00,0x10,0x00,0x23,0x00, + 0xE4,0xFF,0x18,0x00,0x2A,0x00,0x04,0x00,0xDE,0xFF,0xF3,0xFF, + 0x12,0x00,0xE9,0xFF,0x04,0x00,0x27,0x00,0x16,0x00,0xCD,0xFF, + 0x0D,0x00,0x29,0x00,0xF3,0xFF,0xEB,0xFF,0xE0,0xFF,0x08,0x00, + 0x01,0x00,0xF7,0xFF,0xDD,0xFF,0xD2,0xFF,0xE3,0xFF,0xFC,0xFF, + 0xFA,0xFF,0xDD,0xFF,0xF5,0xFF,0x2D,0x00,0x36,0x00,0xFD,0xFF, + 0xEE,0xFF,0x04,0x00,0x1E,0x00,0xF5,0xFF,0xDA,0xFF,0xF0,0xFF, + 0x05,0x00,0x1A,0x00,0x1B,0x00,0x15,0x00,0xDF,0xFF,0x0C,0x00, + 0xFC,0xFF,0xE6,0xFF,0x06,0x00,0x0D,0x00,0x18,0x00,0x0B,0x00, + 0x20,0x00,0xD6,0xFF,0xEF,0xFF,0x0C,0x00,0xF4,0xFF,0xFD,0xFF, + 0x20,0x00,0x25,0x00,0xDF,0xFF,0xF4,0xFF,0xF4,0xFF,0xF3,0xFF, + 0xDA,0xFF,0xFA,0xFF,0x21,0x00,0x09,0x00,0x03,0x00,0xF0,0xFF, + 0xF7,0xFF,0xD7,0xFF,0xEB,0xFF,0x06,0x00,0x0C,0x00,0x1D,0x00, + 0x11,0x00,0x1C,0x00,0x04,0x00,0x10,0x00,0x05,0x00,0xE8,0xFF, + 0xFA,0xFF,0xFE,0xFF,0x16,0x00,0xFC,0xFF,0xFA,0xFF,0xF7,0xFF, + 0xF1,0xFF,0x0E,0x00,0x1C,0x00,0x21,0x00,0x1A,0x00,0x1C,0x00, + 0xF5,0xFF,0xDC,0xFF,0xF3,0xFF,0xFB,0xFF,0xF2,0xFF,0x11,0x00, + 0x23,0x00,0x0F,0x00,0xF7,0xFF,0xE7,0xFF,0xDB,0xFF,0xCC,0xFF, + 0xD4,0xFF,0xDE,0xFF,0xF5,0xFF,0xF0,0xFF,0xF7,0xFF,0x0C,0x00, + 0xFB,0xFF,0xEC,0xFF,0xF5,0xFF,0xF5,0xFF,0xE6,0xFF,0x01,0x00, + 0x1B,0x00,0x1A,0x00,0x07,0x00,0x1C,0x00,0x24,0x00,0x09,0x00, + 0x0B,0x00,0x13,0x00,0x14,0x00,0x0D,0x00,0x0F,0x00,0x05,0x00, + 0xFA,0xFF,0x01,0x00,0xF7,0xFF,0xEE,0xFF,0xF9,0xFF,0xF7,0xFF, + 0xFB,0xFF,0x05,0x00,0x18,0x00,0x1E,0x00,0x0A,0x00,0x1C,0x00, + 0x1F,0x00,0x08,0x00,0x00,0x00,0xFE,0xFF,0x07,0x00,0x1D,0x00, + 0x35,0x00,0x2F,0x00,0x38,0x00,0x80,0x00,0xEF,0x00,0x36,0x01, + 0x1E,0x01,0xF9,0x00,0xE4,0x00,0x7A,0x00,0xE9,0xFF,0xA6,0xFF, + 0x48,0xFF,0x96,0xFE,0x22,0xFE,0xEE,0xFD,0x84,0xFD,0x3A,0xFD, + 0x7A,0xFD,0xB5,0xFD,0xC3,0xFD,0x34,0xFE,0xD7,0xFE,0x4A,0xFF, + 0x01,0x00,0xF8,0x00,0x9F,0x01,0x13,0x02,0x92,0x02,0xCE,0x02, + 0xDB,0x02,0xF9,0x02,0xD4,0x02,0x6D,0x02,0x07,0x02,0x86,0x01, + 0xEB,0x00,0x70,0x00,0x0A,0x00,0x99,0xFF,0x4B,0xFF,0x10,0xFF, + 0xB5,0xFE,0x75,0xFE,0x66,0xFE,0x5D,0xFE,0x8A,0xFE,0xE0,0xFE, + 0x15,0xFF,0x55,0xFF,0xC3,0xFF,0xFE,0xFF,0xFB,0xFF,0x2A,0x00, + 0x50,0x00,0x27,0x00,0x25,0x00,0x39,0x00,0xFE,0xFF,0x06,0x00, + 0x69,0x01,0xDE,0x02,0x7A,0x02,0x0F,0x02,0x78,0x02,0x95,0x01, + 0xEC,0xFF,0xCE,0xFF,0xBA,0xFF,0xF4,0xFD,0x00,0xFD,0xED,0xFC, + 0xA4,0xFB,0xA3,0xFA,0x4C,0xFB,0xDB,0xFB,0x9C,0xFB,0x47,0xFC, + 0x40,0xFD,0x97,0xFD,0xC7,0xFE,0xAB,0x00,0xF5,0x01,0xF3,0x02, + 0x1A,0x04,0xB1,0x04,0xD1,0x04,0x54,0x05,0x87,0x05,0x2C,0x05, + 0xEB,0x04,0x66,0x04,0x87,0x03,0x30,0x03,0xCE,0x02,0xC2,0x01, + 0x10,0x01,0x97,0x00,0x54,0xFF,0xEF,0xFD,0x60,0xFD,0x97,0xFC, + 0xC4,0xFB,0xF6,0xFB,0x24,0xFC,0xEA,0xFB,0x0C,0xFC,0x9A,0xFC, + 0xC6,0xFC,0x11,0xFD,0xF1,0xFD,0x6E,0xFE,0xEA,0xFE,0xC2,0xFF, + 0x6A,0x00,0xDC,0x00,0x6D,0x01,0xE3,0x01,0xF7,0x01,0x23,0x02, + 0x2A,0x02,0xAD,0x01,0x47,0x01,0x25,0x01,0xCE,0x00,0x5F,0x00, + 0x40,0x00,0x10,0x00,0xEF,0xFF,0x61,0x01,0x58,0x03,0x17,0x03, + 0x6C,0x02,0xEE,0x02,0x2F,0x02,0x36,0x00,0xFF,0xFF,0x60,0x00, + 0x83,0xFE,0x27,0xFD,0x14,0xFD,0x88,0xFB,0xD0,0xF9,0x3B,0xFA, + 0x0C,0xFB,0xA7,0xFA,0x39,0xFB,0x77,0xFC,0xB4,0xFC,0x99,0xFD, + 0xB9,0xFF,0x5C,0x01,0x6B,0x02,0xE1,0x03,0xD1,0x04,0xDA,0x04, + 0x34,0x05,0x9B,0x05,0x48,0x05,0x3B,0x05,0xB3,0x05,0x0B,0x05, + 0xD6,0x03,0x3B,0x03,0x43,0x02,0xE6,0x00,0x27,0x00,0xAE,0xFF, + 0x47,0xFE,0x01,0xFD,0x83,0xFC,0xB8,0xFB,0x53,0xFB,0xC5,0xFB, + 0x39,0xFC,0x6E,0xFC,0xE5,0xFC,0x4C,0xFD,0x4E,0xFD,0xCA,0xFD, + 0xA0,0xFE,0x35,0xFF,0xFF,0xFF,0xD4,0x00,0xF1,0x00,0x01,0x01, + 0x6B,0x01,0x98,0x01,0x71,0x01,0x94,0x01,0xAD,0x01,0x08,0x01, + 0xB3,0x00,0x9B,0x00,0x31,0x00,0x0D,0x00,0x01,0x01,0xE4,0x02, + 0xA7,0x03,0x18,0x03,0xD4,0x02,0x84,0x02,0x36,0x01,0x11,0x00, + 0x36,0x00,0xB7,0xFF,0x03,0xFE,0x0B,0xFD,0x14,0xFC,0x53,0xFA, + 0x79,0xF9,0x33,0xFA,0xCF,0xFA,0xF0,0xFA,0xC6,0xFB,0x8F,0xFC, + 0xE4,0xFC,0x24,0xFE,0x3A,0x00,0xE9,0x01,0x56,0x03,0xBF,0x04, + 0x6C,0x05,0x5C,0x05,0x6B,0x05,0x84,0x05,0x47,0x05,0x90,0x05, + 0xF1,0x05,0x17,0x05,0xF4,0x03,0x13,0x03,0xB9,0x01,0x4A,0x00, + 0xB8,0xFF,0x3B,0xFF,0xD7,0xFD,0xDB,0xFC,0x44,0xFC,0x36,0xFB, + 0xC1,0xFA,0x4D,0xFB,0xE6,0xFB,0x56,0xFC,0x11,0xFD,0x88,0xFD, + 0x7B,0xFD,0xD9,0xFD,0xA3,0xFE,0x4D,0xFF,0x44,0x00,0x3E,0x01, + 0x82,0x01,0x96,0x01,0xBC,0x01,0xA6,0x01,0x6C,0x01,0x8D,0x01, + 0x9B,0x01,0x40,0x01,0x13,0x01,0xB3,0x00,0x12,0x00,0xEC,0xFF, + 0xA2,0x00,0x52,0x02,0x72,0x03,0x24,0x03,0xBD,0x02,0x5B,0x02, + 0x20,0x01,0xAF,0xFF,0xB3,0xFF,0xC0,0xFF,0x55,0xFE,0x5C,0xFD, + 0x92,0xFC,0xBC,0xFA,0x60,0xF9,0xD8,0xF9,0xC2,0xFA,0xFA,0xFA, + 0xEF,0xFB,0x25,0xFD,0x57,0xFD,0x02,0xFE,0xD6,0xFF,0x71,0x01, + 0xC2,0x02,0x7D,0x04,0xC2,0x05,0xCC,0x05,0x8F,0x05,0x84,0x05, + 0xF9,0x04,0xE2,0x04,0x88,0x05,0x36,0x05,0x4E,0x04,0xA3,0x03, + 0x49,0x02,0x57,0x00,0x4D,0xFF,0xF1,0xFE,0xD2,0xFD,0x05,0xFD, + 0xEC,0xFC,0xFA,0xFB,0xEC,0xFA,0x03,0xFB,0x67,0xFB,0xA1,0xFB, + 0x90,0xFC,0xAA,0xFD,0xE7,0xFD,0x0E,0xFE,0xA6,0xFE,0xEF,0xFE, + 0x60,0xFF,0x89,0x00,0x72,0x01,0xDC,0x01,0x3A,0x02,0x55,0x02, + 0xE2,0x01,0x81,0x01,0x72,0x01,0x32,0x01,0x2A,0x01,0x2D,0x01, + 0xB7,0x00,0x3E,0x00,0x27,0x00,0xE1,0x00,0x3F,0x02,0xDB,0x02, + 0x82,0x02,0x71,0x02,0x02,0x02,0x8D,0x00,0x55,0xFF,0xAB,0xFF, + 0xF2,0xFE,0xAF,0xFD,0x3D,0xFD,0x5A,0xFC,0xB2,0xFB,0xE8,0xF9, + 0x08,0xFA,0xBE,0xFA,0xA2,0xFA,0x64,0xFC,0x68,0xFD,0x83,0xFD, + 0x4B,0xFE,0x9C,0xFF,0xE9,0x00,0xA3,0x02,0x2B,0x05,0x4E,0x07, + 0xBB,0x07,0x7D,0x07,0xBF,0x06,0xCF,0x05,0xD7,0x05,0xFE,0x05, + 0xE7,0x05,0x05,0x05,0xD8,0x02,0x09,0x00,0x0A,0xFD,0x4E,0xFB, + 0xE0,0xFA,0xC7,0xFA,0x1A,0xFB,0xAC,0xFA,0xD4,0xF9,0xA5,0xF9, + 0x6A,0xFA,0xB4,0xFC,0xD3,0xFE,0x9E,0x00,0xE4,0x01,0x8E,0x01, + 0x36,0x01,0x25,0x01,0xE9,0x01,0xC1,0x02,0x93,0x02,0xF5,0x01, + 0x6A,0x00,0xFF,0xFE,0xA9,0xFE,0x76,0xFE,0x92,0xFE,0xE2,0xFE, + 0xFE,0xFE,0x80,0xFE,0x6F,0xFE,0x7E,0xFF,0x92,0x01,0xB3,0x07, + 0xFB,0x0B,0x00,0x0A,0x2F,0x07,0x64,0x02,0x48,0xFE,0x48,0xFD, + 0x45,0xFC,0xBA,0xFB,0x0A,0xF8,0x4F,0xF4,0x16,0xF3,0xD5,0xF2, + 0xB6,0xF6,0x28,0xFA,0xD5,0xFC,0x12,0xFF,0x7B,0xFF,0x35,0x02, + 0xE9,0x05,0xF1,0x09,0xF5,0x0C,0x91,0x0C,0x1F,0x0B,0x47,0x08, + 0xD9,0x05,0x62,0x05,0xBD,0x03,0x27,0x01,0xAD,0xFD,0xD0,0xFA, + 0x03,0xFA,0x7C,0xF9,0x27,0xFB,0xA2,0xFC,0x25,0xFC,0xCC,0xFC, + 0x80,0xFD,0xFC,0xFE,0x5B,0x01,0xEE,0x02,0x6F,0x03,0x6D,0x02, + 0xB6,0x01,0x23,0x01,0xAD,0x00,0x58,0x01,0x91,0x00,0xD4,0xFE, + 0xA9,0xFD,0x85,0xFC,0x75,0xFC,0x12,0xFD,0xF2,0xFD,0x3F,0xFE, + 0xED,0xFD,0x73,0xFE,0x25,0xFF,0x9F,0x00,0x1F,0x02,0x56,0x02, + 0xE8,0x01,0xFE,0x00,0x3A,0x01,0xA5,0x01,0x80,0x01,0xE7,0x01, + 0xF9,0x00,0xFF,0x03,0xD5,0x09,0xA0,0x08,0x7F,0x05,0x0E,0x02, + 0xC4,0xFC,0xCF,0xFA,0xDD,0xF9,0xBE,0xF9,0xC5,0xF7,0x32,0xF4, + 0x4E,0xF4,0x4A,0xF4,0x9A,0xF7,0xE6,0xFB,0xBD,0xFD,0x79,0x00, + 0x39,0x01,0x87,0x03,0xEB,0x06,0xDD,0x09,0x66,0x0C,0x4A,0x0B, + 0xBF,0x09,0xDB,0x07,0x32,0x05,0x67,0x04,0xD0,0x02,0xB7,0xFF, + 0x9C,0xFC,0x2B,0xFB,0x35,0xFB,0x8D,0xFA,0x3C,0xFC,0x68,0xFD, + 0x6F,0xFC,0xB9,0xFD,0x12,0xFF,0x69,0x00,0x09,0x02,0xC5,0x02, + 0xAD,0x02,0x35,0x01,0x06,0x01,0xCD,0x00,0xF8,0xFF,0x4D,0x00, + 0x1B,0xFF,0xA9,0xFD,0x38,0xFD,0xEB,0xFC,0x43,0xFD,0x7D,0xFD, + 0x06,0xFE,0x21,0xFE,0x04,0xFE,0x45,0xFF,0x42,0x00,0x55,0x01, + 0x25,0x02,0xA3,0x01,0x4B,0x01,0xDD,0x00,0xA1,0x01,0xD2,0x01, + 0x06,0x01,0x30,0x01,0xD3,0x00,0x48,0x06,0x6D,0x0B,0x50,0x08, + 0x46,0x05,0x34,0x00,0x86,0xFB,0xE4,0xFA,0xFD,0xF9,0xFA,0xF9, + 0x23,0xF6,0xE5,0xF2,0x54,0xF3,0xC3,0xF3,0x06,0xF9,0x5C,0xFC, + 0x4B,0xFE,0x76,0x00,0xF4,0x00,0xCF,0x04,0x44,0x08,0xBA,0x0B, + 0x55,0x0D,0x33,0x0B,0xD4,0x09,0x7D,0x07,0x97,0x05,0x0A,0x05, + 0x44,0x02,0xB7,0xFE,0xD6,0xFB,0xD3,0xFA,0x58,0xFA,0x5F,0xFA, + 0x67,0xFC,0x08,0xFC,0xCC,0xFB,0x84,0xFD,0xE8,0xFE,0x08,0x01, + 0x85,0x02,0x36,0x03,0x99,0x02,0x88,0x01,0xBF,0x01,0x1A,0x01, + 0xE5,0x00,0x7A,0x00,0x9D,0xFE,0x95,0xFD,0xDD,0xFC,0xD4,0xFC, + 0x29,0xFD,0x53,0xFD,0xA1,0xFD,0x53,0xFD,0xE3,0xFD,0x60,0xFF, + 0x89,0x00,0xDF,0x01,0x08,0x02,0xB1,0x01,0x5A,0x01,0x65,0x01, + 0x4F,0x02,0x82,0x01,0x38,0x01,0xCE,0x00,0x33,0x04,0x09,0x0B, + 0xA2,0x09,0x24,0x06,0x3E,0x02,0x0A,0xFC,0xE4,0xFA,0x30,0xFA, + 0xEF,0xF9,0xA5,0xF7,0x23,0xF3,0x19,0xF3,0xA5,0xF2,0xA8,0xF6, + 0x6B,0xFB,0x17,0xFD,0x18,0x00,0x87,0x00,0x58,0x03,0x35,0x07, + 0xB2,0x0A,0xBE,0x0D,0x83,0x0C,0x23,0x0B,0x1A,0x09,0x61,0x06, + 0xD5,0x05,0xAF,0x03,0x2E,0x00,0x70,0xFD,0x49,0xFB,0xF3,0xF9, + 0x76,0xF9,0x10,0xFB,0x4D,0xFB,0xEE,0xFA,0x7A,0xFC,0xA8,0xFD, + 0x9D,0xFF,0xD3,0x01,0x32,0x03,0x5B,0x03,0x79,0x02,0x63,0x02, + 0xBE,0x01,0x6B,0x01,0x55,0x01,0xCF,0xFF,0x96,0xFE,0x67,0xFD, + 0xB9,0xFC,0xBA,0xFC,0xD8,0xFC,0x18,0xFD,0xF4,0xFC,0x60,0xFD, + 0x8B,0xFE,0x8C,0xFF,0xE2,0x00,0xC2,0x01,0xF1,0x01,0xEF,0x01, + 0xA0,0x01,0x02,0x02,0x9D,0x01,0x6B,0x01,0x0E,0x01,0x98,0x03, + 0xB0,0x0A,0xA9,0x0A,0xD6,0x06,0xB6,0x03,0x3D,0xFD,0xC6,0xFA, + 0x57,0xFA,0xBC,0xF9,0x33,0xF8,0xA8,0xF3,0xE3,0xF2,0x00,0xF2, + 0x9D,0xF4,0x0D,0xFA,0x1D,0xFC,0x7C,0xFF,0x67,0x00,0x82,0x02, + 0x22,0x06,0x9A,0x09,0xAC,0x0D,0x7C,0x0D,0x8D,0x0C,0xBA,0x0A, + 0x74,0x07,0x72,0x06,0x77,0x04,0xA7,0x01,0xA5,0xFF,0x70,0xFC, + 0xBA,0xF9,0xA3,0xF8,0x2C,0xF9,0xE7,0xF9,0x47,0xFA,0x9D,0xFB, + 0x88,0xFC,0xF8,0xFD,0x8D,0x00,0x86,0x02,0xE0,0x03,0xC6,0x03, + 0x40,0x03,0x9E,0x02,0xD9,0x01,0xBF,0x01,0xFE,0x00,0x05,0x00, + 0x8C,0xFE,0xF7,0xFC,0x46,0xFC,0x0A,0xFC,0x3A,0xFC,0xB4,0xFC, + 0x41,0xFD,0xFC,0xFD,0xBF,0xFE,0xDE,0xFF,0x1B,0x01,0xF2,0x01, + 0x35,0x02,0x18,0x02,0x1A,0x02,0x9B,0x01,0x21,0x01,0x63,0x01, + 0xA6,0x06,0x89,0x0C,0x28,0x0A,0xB4,0x06,0x3C,0x02,0xE8,0xFB, + 0x9E,0xFA,0x2C,0xFA,0xAD,0xF9,0x86,0xF6,0xCF,0xF2,0x1B,0xF2, + 0x09,0xF1,0x99,0xF5,0xE5,0xF9,0xA0,0xFC,0xC8,0xFF,0x6E,0x00, + 0x71,0x03,0x7E,0x06,0x15,0x0B,0x57,0x0E,0xEE,0x0D,0xA5,0x0D, + 0xA3,0x0A,0xEA,0x07,0xB4,0x06,0x30,0x04,0x5D,0x02,0xD3,0xFF, + 0xE6,0xFB,0x0C,0xF9,0xB9,0xF7,0x11,0xF8,0xBD,0xF8,0xDD,0xF9, + 0x37,0xFB,0xD8,0xFB,0xD6,0xFD,0x3D,0x00,0x80,0x02,0x31,0x04, + 0x31,0x04,0x02,0x04,0x02,0x03,0x64,0x02,0x20,0x02,0x87,0x01, + 0xC0,0x00,0xC7,0xFE,0x37,0xFD,0x19,0xFC,0x57,0xFB,0xB3,0xFB, + 0xA3,0xFC,0x72,0xFD,0xBD,0xFD,0x73,0xFE,0x81,0xFF,0x70,0x00, + 0x93,0x01,0x45,0x02,0x7A,0x02,0x34,0x02,0x5F,0x01,0x7D,0x00, + 0x24,0x05,0xC2,0x0C,0x54,0x0C,0xFB,0x08,0x06,0x05,0x75,0xFD, + 0x28,0xFA,0x05,0xFA,0xE3,0xF9,0xA7,0xF7,0x8F,0xF3,0x04,0xF2, + 0x97,0xEF,0x8E,0xF2,0xFB,0xF7,0x40,0xFB,0x6B,0xFF,0x59,0x00, + 0x46,0x02,0xAD,0x04,0x10,0x09,0xE2,0x0D,0xC4,0x0E,0x88,0x0F, + 0xE8,0x0C,0x2D,0x09,0x60,0x07,0x28,0x05,0xC4,0x03,0xD8,0x01, + 0x53,0xFE,0x26,0xFA,0x41,0xF7,0xD5,0xF6,0x3C,0xF7,0xB7,0xF8, + 0x8A,0xFA,0x32,0xFB,0x49,0xFC,0x32,0xFE,0xC6,0x00,0x2C,0x03, + 0x62,0x04,0x12,0x05,0x10,0x04,0x04,0x03,0x7F,0x02,0x1E,0x02, + 0xFA,0x01,0x85,0x00,0xF0,0xFE,0xDA,0xFC,0x10,0xFB,0xD2,0xFA, + 0xAD,0xFB,0x0D,0xFD,0xAF,0xFD,0x3C,0xFE,0x77,0xFE,0x09,0xFF, + 0x52,0x00,0x8C,0x01,0xA9,0x02,0xD7,0x02,0x11,0x02,0x4E,0x00, + 0xC2,0x04,0xB3,0x0C,0xCF,0x0C,0xDB,0x0A,0xCE,0x06,0x7E,0xFE, + 0xED,0xF9,0xEB,0xF8,0x44,0xF9,0x80,0xF7,0xC5,0xF4,0xEC,0xF2, + 0x55,0xEF,0xA2,0xF1,0x3E,0xF6,0x3C,0xFA,0x03,0xFF,0x9C,0x00, + 0x39,0x02,0x6C,0x03,0xBC,0x07,0x72,0x0C,0x72,0x0E,0xA0,0x10, + 0x58,0x0E,0x92,0x0A,0xD2,0x07,0x78,0x05,0x85,0x04,0x1A,0x03, + 0x9B,0x00,0xF0,0xFB,0xE4,0xF7,0x3D,0xF6,0xB7,0xF5,0x84,0xF7, + 0xB7,0xF9,0xE9,0xFA,0x9C,0xFB,0x9D,0xFC,0xEA,0xFE,0x22,0x01, + 0x84,0x03,0x80,0x05,0x36,0x05,0x4F,0x04,0x3B,0x03,0xB0,0x02, + 0x53,0x02,0x61,0x01,0x56,0x00,0xED,0xFD,0xC4,0xFB,0xA9,0xFA, + 0x0B,0xFB,0x71,0xFC,0x63,0xFD,0x4D,0xFE,0x32,0xFE,0x5E,0xFE, + 0x16,0xFF,0x77,0x00,0x32,0x02,0x28,0x03,0x9F,0x02,0xAA,0x00, + 0x0D,0x06,0xCD,0x0C,0x25,0x0C,0x9C,0x0B,0xEE,0x06,0x67,0xFE, + 0xB2,0xF9,0x64,0xF8,0xDD,0xF8,0xEB,0xF6,0xE0,0xF5,0xB6,0xF3, + 0xED,0xEF,0x55,0xF2,0x69,0xF5,0xAB,0xF9,0x2A,0xFE,0x7A,0x00, + 0x2D,0x02,0x00,0x03,0xAF,0x07,0x49,0x0B,0x18,0x0E,0xC8,0x10, + 0x99,0x0E,0x86,0x0B,0x30,0x08,0x2A,0x06,0x27,0x05,0xB2,0x03, + 0xA6,0x01,0xB0,0xFC,0x90,0xF8,0x1E,0xF6,0x1B,0xF5,0xC6,0xF6, + 0xB6,0xF8,0x4E,0xFA,0xD1,0xFA,0xCF,0xFB,0xFF,0xFD,0xF0,0xFF, + 0x21,0x03,0x76,0x05,0xB8,0x05,0xFA,0x04,0xBA,0x03,0x30,0x03, + 0x49,0x02,0xEE,0x01,0x1F,0x01,0xCB,0xFE,0xBA,0xFC,0x0C,0xFB, + 0x40,0xFB,0x1C,0xFC,0x28,0xFD,0x03,0xFE,0xC6,0xFD,0x11,0xFE, + 0x62,0xFE,0xF6,0xFF,0xA9,0x01,0x83,0x02,0x60,0x01,0x52,0x02, + 0x62,0x0A,0x99,0x0D,0x75,0x0C,0x0F,0x0B,0x32,0x03,0x35,0xFC, + 0x78,0xF9,0x57,0xF9,0xE4,0xF8,0xE7,0xF6,0x43,0xF6,0xE2,0xF1, + 0x63,0xF0,0x3C,0xF3,0x8F,0xF5,0x6B,0xFA,0xCC,0xFD,0x78,0x00, + 0x6F,0x01,0x32,0x04,0x4F,0x09,0xBE,0x0B,0x91,0x0F,0x37,0x10, + 0xA6,0x0D,0xCA,0x0A,0x1B,0x08,0xF5,0x06,0x54,0x05,0x80,0x04, + 0xD3,0x00,0xA4,0xFB,0x92,0xF8,0xD1,0xF5,0x9F,0xF5,0x12,0xF7, + 0xC2,0xF8,0x81,0xF9,0xE7,0xF9,0xBD,0xFB,0x58,0xFD,0x33,0x00, + 0x6B,0x03,0xD4,0x04,0x36,0x05,0x86,0x04,0xCC,0x03,0x11,0x03, + 0xE0,0x02,0xBC,0x02,0x20,0x01,0x6B,0xFF,0x2E,0xFD,0xB2,0xFB, + 0xEA,0xFB,0x9E,0xFC,0x9C,0xFD,0xA0,0xFD,0xAD,0xFD,0x62,0xFD, + 0xBD,0xFD,0x75,0xFF,0xC4,0x00,0xA0,0x01,0xD3,0x00,0x85,0x05, + 0xF9,0x0C,0x40,0x0D,0x32,0x0C,0x2F,0x08,0x7F,0x00,0xF5,0xFB, + 0x78,0xFA,0xB2,0xFA,0x2D,0xF9,0xD2,0xF7,0x45,0xF5,0xA8,0xF0, + 0x37,0xF1,0xE5,0xF2,0x00,0xF6,0xA9,0xFA,0x01,0xFE,0x4E,0x00, + 0x3F,0x01,0xB5,0x05,0x31,0x09,0x27,0x0C,0x9B,0x0F,0xEE,0x0E, + 0x43,0x0D,0xBE,0x0A,0x82,0x09,0x99,0x07,0x34,0x05,0xC7,0x04, + 0x7B,0x00,0x5C,0xFB,0xDF,0xF8,0x80,0xF6,0x69,0xF5,0x0D,0xF7, + 0x7A,0xF8,0x3D,0xF8,0x51,0xF9,0x5A,0xFB,0xC4,0xFC,0x92,0xFF, + 0x19,0x03,0x29,0x04,0x8C,0x04,0xB0,0x04,0xCF,0x03,0x4C,0x03, + 0xE3,0x03,0xAA,0x03,0xB6,0x01,0x59,0x00,0x41,0xFE,0x68,0xFC, + 0x77,0xFC,0x10,0xFD,0x28,0xFD,0xE2,0xFC,0x46,0xFD,0xBA,0xFC, + 0x59,0xFD,0xF6,0xFE,0x19,0x00,0xA4,0x00,0x83,0x00,0x37,0x07, + 0x8F,0x0D,0xB5,0x0C,0xCA,0x0B,0x0D,0x07,0xFE,0xFF,0x75,0xFC, + 0xE2,0xFB,0xFE,0xFB,0xED,0xF9,0x68,0xF8,0x73,0xF4,0x03,0xF0, + 0xE5,0xF0,0x8F,0xF2,0x9C,0xF6,0x11,0xFB,0xEC,0xFD,0x2B,0xFF, + 0x85,0x00,0x9E,0x05,0x86,0x08,0x77,0x0C,0xB3,0x0F,0xE8,0x0E, + 0x5F,0x0D,0x37,0x0B,0xA6,0x0A,0x87,0x07,0xCF,0x05,0xC8,0x04, + 0x91,0xFF,0xCE,0xFB,0x05,0xF9,0x55,0xF7,0x56,0xF6,0x18,0xF7, + 0x1C,0xF8,0x17,0xF7,0xCD,0xF8,0x6F,0xFA,0x2B,0xFC,0xAB,0xFF, + 0x74,0x02,0xD6,0x03,0xC1,0x03,0x81,0x04,0x09,0x04,0xCA,0x03, + 0xE1,0x04,0xF0,0x03,0xA7,0x02,0xDF,0x00,0x02,0xFF,0x3A,0xFD, + 0xA3,0xFC,0x41,0xFD,0x81,0xFC,0xA6,0xFC,0x96,0xFC,0x21,0xFC, + 0xC9,0xFC,0x48,0xFE,0xBF,0xFF,0x1E,0x00,0x5E,0x00,0x0A,0x03, + 0x9E,0x0A,0xFA,0x0D,0x88,0x0C,0xC7,0x0A,0xC8,0x03,0x6B,0xFE, + 0xA0,0xFC,0xD6,0xFC,0x75,0xFC,0x6C,0xF9,0xF6,0xF6,0x14,0xF1, + 0xFF,0xEE,0x1F,0xF1,0x48,0xF4,0x39,0xF9,0x96,0xFB,0x01,0xFE, + 0x7B,0xFE,0xE0,0x01,0xB7,0x06,0x4A,0x0A,0x19,0x0F,0x95,0x0F, + 0xF1,0x0E,0x98,0x0C,0x44,0x0B,0x1A,0x0A,0x5E,0x07,0x12,0x06, + 0x66,0x01,0x26,0xFE,0x1B,0xFB,0x1A,0xF8,0x7D,0xF7,0x49,0xF6, + 0x91,0xF6,0x40,0xF6,0x47,0xF7,0xE0,0xF8,0x97,0xFA,0x36,0xFE, + 0x85,0x00,0xBC,0x02,0x9A,0x03,0x24,0x04,0xDB,0x04,0xCA,0x04, + 0x8D,0x05,0xD6,0x04,0xE2,0x03,0x40,0x02,0x42,0x00,0xFD,0xFE, + 0x5B,0xFD,0x13,0xFD,0x2E,0xFC,0xFF,0xFB,0xF3,0xFB,0x67,0xFB, + 0x56,0xFC,0xF4,0xFC,0xA3,0xFE,0x4B,0xFF,0x35,0x00,0xA9,0x00, + 0x78,0x03,0x4C,0x0C,0x56,0x0E,0x14,0x0D,0xA8,0x0A,0x21,0x03, + 0x5E,0xFE,0x03,0xFD,0x26,0xFE,0xF3,0xFB,0xD4,0xF8,0x89,0xF5, + 0x02,0xEF,0xA8,0xEE,0x7E,0xF1,0x34,0xF5,0xAD,0xF8,0x6D,0xFB, + 0x7F,0xFD,0x89,0xFD,0xB3,0x02,0xD0,0x07,0xFD,0x0B,0xD1,0x0F, + 0x62,0x10,0x17,0x0F,0x1A,0x0C,0x27,0x0C,0xA7,0x0A,0x0C,0x08, + 0x8D,0x05,0x71,0x00,0x6F,0xFC,0xC6,0xF9,0x82,0xF8,0xDC,0xF6, + 0x6E,0xF6,0xEE,0xF5,0x02,0xF5,0x7C,0xF6,0xB9,0xF8,0xCB,0xFB, + 0xA2,0xFE,0x9A,0x01,0xC1,0x02,0x5C,0x03,0xDD,0x04,0x62,0x05, + 0x52,0x06,0x3C,0x06,0x5D,0x05,0x5B,0x03,0x7B,0x01,0x40,0x00, + 0x83,0xFE,0xBF,0xFD,0xAC,0xFC,0x9D,0xFB,0xD9,0xFA,0x0C,0xFB, + 0x63,0xFB,0x15,0xFC,0x8B,0xFD,0x78,0xFE,0x98,0xFF,0x2D,0x00, + 0xD8,0x00,0x6E,0x02,0xBA,0x09,0xB0,0x0F,0xF0,0x0D,0x0C,0x0C, + 0xDF,0x05,0x42,0xFF,0x57,0xFD,0xAE,0xFD,0x20,0xFD,0xEA,0xF8, + 0xE7,0xF5,0x52,0xF0,0x66,0xED,0x82,0xF0,0xBB,0xF3,0xBA,0xF7, + 0x24,0xFA,0xA5,0xFC,0x47,0xFD,0xC7,0x00,0x60,0x07,0x5E,0x0B, + 0xA7,0x0F,0xD4,0x10,0xE5,0x0F,0x4A,0x0D,0x64,0x0C,0x1A,0x0C, + 0xFF,0x08,0x6D,0x06,0x81,0x01,0x7E,0xFC,0x47,0xF9,0x8F,0xF8, + 0x4B,0xF7,0xFD,0xF5,0x24,0xF6,0x55,0xF4,0x4F,0xF5,0xEB,0xF7, + 0x6B,0xFB,0x75,0xFE,0x13,0x01,0x37,0x03,0x03,0x03,0xEE,0x04, + 0xF3,0x05,0xA8,0x06,0xE4,0x06,0xC0,0x05,0xF3,0x03,0x58,0x01, + 0x8F,0x00,0xCE,0xFE,0xB0,0xFD,0xB6,0xFC,0x57,0xFB,0x5D,0xFA, + 0x2E,0xFA,0xA5,0xFB,0x0A,0xFC,0x86,0xFD,0x78,0xFE,0x47,0xFF, + 0x0F,0x00,0xDA,0x00,0x0B,0x02,0x81,0x03,0xA3,0x0B,0x6F,0x0F, + 0x20,0x0D,0xFE,0x0A,0x3C,0x04,0xA4,0xFE,0x87,0xFC,0x5E,0xFD, + 0x87,0xFB,0xAC,0xF7,0x16,0xF5,0x87,0xEF,0x62,0xEE,0x58,0xF1, + 0x0F,0xF5,0x5D,0xF8,0x02,0xFB,0x8F,0xFD,0x08,0xFE,0xAD,0x02, + 0x45,0x08,0x3B,0x0C,0xA0,0x0F,0x74,0x10,0x4E,0x0F,0x65,0x0C, + 0x38,0x0C,0xD3,0x0A,0x07,0x08,0x38,0x05,0x36,0x00,0x9C,0xFB, + 0x82,0xF8,0xAF,0xF8,0x65,0xF7,0xBB,0xF6,0xE2,0xF6,0x26,0xF5, + 0x2F,0xF6,0xBD,0xF8,0x55,0xFC,0xED,0xFE,0xC0,0x01,0x4D,0x03, + 0x14,0x03,0xC8,0x04,0x6D,0x05,0xF8,0x05,0xC0,0x05,0xEA,0x04, + 0xE4,0x02,0xCF,0x00,0x1D,0x00,0x76,0xFE,0xDC,0xFD,0xFA,0xFC, + 0x61,0xFC,0x9A,0xFB,0x89,0xFB,0xAD,0xFC,0xFF,0xFC,0x61,0xFE, + 0x0A,0xFF,0x2D,0x00,0xF3,0x00,0x33,0x01,0x36,0x02,0x50,0x01, + 0x70,0x03,0x7E,0x08,0xA1,0x09,0xA7,0x08,0x8B,0x06,0x4C,0x01, + 0xCF,0xFC,0xD6,0xFB,0x18,0xFC,0x38,0xFB,0x41,0xFA,0xAD,0xF8, + 0xC9,0xF5,0x98,0xF5,0x73,0xF7,0x74,0xF9,0xFA,0xFB,0xA9,0xFE, + 0x37,0x00,0xF4,0x00,0xF9,0x02,0x96,0x04,0x18,0x06,0xDA,0x07, + 0xB6,0x08,0x4C,0x08,0x1A,0x07,0x66,0x06,0xD2,0x04,0x73,0x03, + 0x90,0x02,0x31,0x01,0xBA,0xFF,0x84,0xFE,0x04,0xFE,0x75,0xFD, + 0x74,0xFD,0x91,0xFD,0x87,0xFD,0xB9,0xFD,0x0A,0xFE,0x2E,0xFE, + 0x2B,0xFE,0xAF,0xFE,0xE6,0xFE,0x36,0xFF,0x8E,0xFF,0xBB,0xFF, + 0xC8,0xFF,0x95,0xFF,0x8A,0xFF,0x5F,0xFF,0x64,0xFF,0x9E,0xFF, + 0xDF,0xFF,0xB9,0xFF,0xC7,0xFF,0xDC,0xFF,0xAA,0xFF,0xF9,0xFF, + 0x02,0x00,0x05,0x00,0xF9,0xFF,0x04,0x00,0xF9,0xFF,0xCD,0xFF, + 0x1E,0x00,0x36,0x00,0x3D,0x00,0x2C,0x00,0x41,0x00,0x36,0x00, + 0x38,0x00,0x79,0x00,0x33,0x00,0x59,0x00,0x09,0x01,0x5E,0x01, + 0x63,0x01,0x4A,0x01,0xD4,0x00,0x22,0x00,0xD0,0xFF,0xE1,0xFF, + 0xF0,0xFF,0x10,0x00,0xFC,0xFF,0x46,0xFF,0x9C,0xFE,0x30,0xFE, + 0xFE,0xFD,0x2F,0xFE,0x9D,0xFE,0xFD,0xFE,0x1C,0xFF,0x57,0xFF, + 0x8D,0xFF,0xD3,0xFF,0x49,0x00,0xB8,0x00,0x13,0x01,0x49,0x01, + 0x66,0x01,0x38,0x01,0x1D,0x01,0x22,0x01,0x0C,0x01,0x05,0x01, + 0x0F,0x01,0x09,0x01,0xDC,0x00,0xBF,0x00,0x9A,0x00,0x81,0x00, + 0x81,0x00,0x8B,0x00,0x8D,0x00,0x50,0x00,0x25,0x00,0xD7,0xFF, + 0x8A,0xFF,0x6F,0xFF,0x52,0xFF,0x46,0xFF,0x3D,0xFF,0x2C,0xFF, + 0xF1,0xFE,0xDA,0xFE,0xD5,0xFE,0xD5,0xFE,0xF2,0xFE,0x16,0xFF, + 0x2A,0xFF,0x33,0xFF,0x52,0xFF,0x55,0xFF,0x6E,0xFF,0x9E,0xFF, + 0xC7,0xFF,0xE3,0xFF,0xF1,0xFF,0x0F,0x00,0x22,0x00,0x34,0x00, + 0x50,0x00,0x6B,0x00,0x89,0x00,0xA3,0x00,0xAB,0x00,0xAF,0x00, + 0xAF,0x00,0xA1,0x00,0x9C,0x00,0x96,0x00,0x88,0x00,0x7C,0x00, + 0x67,0x00,0x52,0x00,0x43,0x00,0x33,0x00,0x21,0x00,0x13,0x00, + 0x09,0x00,0x00,0x00,0xF3,0xFF,0xE4,0xFF,0xDF,0xFF,0xDA,0xFF, + 0xD0,0xFF,0xCC,0xFF,0xC9,0xFF,0xC2,0xFF,0xC4,0xFF,0xC3,0xFF, + 0xBF,0xFF,0xC1,0xFF,0xBD,0xFF,0xB0,0xFF,0xA9,0xFF,0xA7,0xFF, + 0xAB,0xFF,0xB5,0xFF,0xB6,0xFF,0xCA,0xFF,0xDD,0xFF,0xEE,0xFF, + 0x10,0x00,0x25,0x00,0x43,0x00,0x58,0x00,0x6E,0x00,0x85,0x00, + 0x8C,0x00,0x98,0x00,0x95,0x00,0x91,0x00,0x89,0x00,0x76,0x00, + 0x66,0x00,0x5D,0x00,0x49,0x00,0x2D,0x00,0x1C,0x00,0xFF,0xFF, + 0xEC,0xFF,0xD5,0xFF,0xC6,0xFF,0xB6,0xFF,0x9D,0xFF,0xA0,0xFF, + 0x92,0xFF,0x8C,0xFF,0x89,0xFF,0x8B,0xFF,0x94,0xFF,0x96,0xFF, + 0xA2,0xFF,0xA5,0xFF,0xB7,0xFF,0xBD,0xFF,0xB7,0xFF,0xD2,0xFF, + 0xE3,0xFF,0xDF,0xFF,0xE8,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB,0xFF, + 0x0F,0x00,0x0A,0x00,0x11,0x00,0x1B,0x00,0x13,0x00,0x22,0x00, + 0x27,0x00,0x16,0x00,0x2E,0x00,0x2C,0x00,0x2B,0x00,0x2C,0x00, + 0x2D,0x00,0x35,0x00,0x28,0x00,0x2C,0x00,0x26,0x00,0x2D,0x00, + 0x29,0x00,0x27,0x00,0x14,0x00,0x13,0x00,0x1E,0x00,0x0D,0x00, + 0x15,0x00,0x10,0x00,0x02,0x00,0xF7,0xFF,0x05,0x00,0xF9,0xFF, + 0xED,0xFF,0xFF,0xFF,0xF6,0xFF,0xF8,0xFF,0xF4,0xFF,0xF0,0xFF, + 0xFB,0xFF,0x05,0x00,0xF9,0xFF,0xFC,0xFF,0x04,0x00,0x05,0x00, + 0x00,0x00,0xFA,0xFF,0x0F,0x00,0xF6,0xFF,0x16,0x00,0x19,0x00, + 0xE3,0xFF,0x02,0x00,0x16,0x00,0x06,0x00,0xFA,0xFF,0xFF,0xFF, + 0x00,0x00,0xF9,0xFF,0xF7,0xFF,0xF8,0xFF,0xF2,0xFF,0xF9,0xFF, + 0xFC,0xFF,0xE0,0xFF,0xEE,0xFF,0xF7,0xFF,0xEB,0xFF,0xEE,0xFF, + 0xF2,0xFF,0xEA,0xFF,0xE1,0xFF,0xFA,0xFF,0xEE,0xFF,0xE3,0xFF, + 0xF9,0xFF,0xF5,0xFF,0xDE,0xFF,0x03,0x00,0x13,0x00,0xD9,0xFF, + 0xED,0xFF,0x1B,0x00,0x01,0x00,0xF4,0xFF,0x1C,0x00,0x02,0x00, + 0xE4,0xFF,0x22,0x00,0x12,0x00,0xEA,0xFF,0x23,0x00,0x0F,0x00, + 0xF1,0xFF,0x12,0x00,0x07,0x00,0xF9,0xFF,0x10,0x00,0x0F,0x00, + 0xF2,0xFF,0x10,0x00,0x15,0x00,0xFF,0xFF,0x05,0x00,0x06,0x00, + 0x16,0x00,0xFD,0xFF,0x14,0x00,0x05,0x00,0xF3,0xFF,0x16,0x00, + 0xFE,0xFF,0x18,0x00,0xEC,0xFF,0xF5,0xFF,0x19,0x00,0x0B,0x00, + 0xEA,0xFF,0x06,0x00,0x09,0x00,0xEA,0xFF,0x23,0x00,0xEC,0xFF, + 0xFB,0xFF,0xFE,0xFF,0xFE,0xFF,0x0D,0x00,0xFD,0xFF,0xFA,0xFF, + 0xF0,0xFF,0x0C,0x00,0x00,0x00,0x09,0x00,0x01,0x00,0x04,0x00, + 0x09,0x00,0xFA,0xFF,0x10,0x00,0xF9,0xFF,0xFD,0xFF,0x13,0x00, + 0xF4,0xFF,0xF8,0xFF,0xEF,0xFF,0xFC,0xFF,0x10,0x00,0xEC,0xFF, + 0xF5,0xFF,0xFF,0xFF,0xFB,0xFF,0xFA,0xFF,0xFD,0xFF,0xFD,0xFF, + 0xFF,0xFF,0x0F,0x00,0xF8,0xFF,0x03,0x00,0x08,0x00,0xF3,0xFF, + 0x09,0x00,0xF7,0xFF,0xF9,0xFF,0x00,0x00,0xEE,0xFF,0xFC,0xFF, + 0x08,0x00,0x02,0x00,0x10,0x00,0xF2,0xFF,0xE3,0xFF,0x17,0x00, + 0xFB,0xFF,0xF9,0xFF,0xF3,0xFF,0x0D,0x00,0x1E,0x00,0xF3,0xFF, + 0x08,0x00,0xD9,0xFF,0x21,0x00,0x22,0x00,0xE6,0xFF,0x0C,0x00, + 0xE1,0xFF,0x1A,0x00,0xEE,0xFF,0xDE,0xFF,0x22,0x00,0xEB,0xFF, + 0xF4,0xFF,0x0E,0x00,0x05,0x00,0xFE,0xFF,0x00,0x00,0x03,0x00, + 0x0C,0x00,0x15,0x00,0xE5,0xFF,0xFF,0xFF,0x1C,0x00,0xE0,0xFF, + 0xF8,0xFF,0x0C,0x00,0x01,0x00,0x10,0x00,0xF1,0xFF,0x15,0x00, + 0x0E,0x00,0xFD,0xFF,0x1B,0x00,0xEB,0xFF,0xFD,0xFF,0x01,0x00, + 0xFF,0xFF,0x02,0x00,0x2A,0x00,0x0C,0x00,0xBE,0xFF,0xE3,0xFF, + 0xE5,0xFF,0x0E,0x00,0x08,0x00,0xF7,0xFF,0x16,0x00,0xF9,0xFF, + 0xD2,0xFF,0xF6,0xFF,0x35,0x00,0x2F,0x00,0x05,0x00,0xE8,0xFF, + 0x13,0x00,0x4F,0x00,0x19,0x00,0xDD,0xFF,0x00,0x00,0xE2,0xFF, + 0xDC,0xFF,0xF1,0xFF,0x07,0x00,0x13,0x00,0x27,0x00,0xD3,0xFF, + 0x3A,0x00,0xC4,0xFF,0x65,0x00,0xF3,0xFF,0x09,0x00,0xDD,0xFF, + 0x45,0xFE,0x5B,0x05,0xB6,0x02,0x68,0xFD,0x08,0xFD,0xFE,0xFB, + 0xEB,0xFE,0x49,0xFF,0xC0,0xFF,0x8A,0xFF,0x18,0x01,0x6D,0x01, + 0x77,0x01,0x74,0x01,0xC1,0x00,0x81,0x00,0x58,0x00,0xA0,0x00, + 0x5A,0x00,0x71,0x01,0xE7,0xFF,0x9B,0xFF,0x65,0xFF,0xBB,0xFE, + 0xB4,0xFF,0xFC,0xFE,0x66,0xFF,0x0C,0x00,0x3D,0xFF,0x77,0xFF, + 0xAF,0xFF,0x4C,0xFF,0x45,0x00,0x9A,0x00,0x4D,0x00,0xA5,0x00, + 0x32,0x00,0xE7,0xFF,0x4D,0x00,0x64,0x00,0x0B,0x00,0xC0,0xFF, + 0x42,0x00,0x02,0x00,0x59,0xFF,0x7C,0x00,0x67,0x00,0xEE,0xFF, + 0x43,0x00,0xE0,0xFF,0x0F,0x00,0x94,0xFF,0xEF,0xFF,0x4C,0x00, + 0xA8,0xFF,0x9D,0xFF,0xE2,0xFF,0xD3,0xFF,0x5F,0x00,0x3C,0x00, + 0x86,0xFF,0x5B,0x00,0x3D,0x00,0xCE,0xFF,0xD2,0xFF,0xB8,0x00, + 0x11,0x00,0xFD,0xFF,0x9F,0x00,0xA8,0xFF,0xB6,0xFF,0xAE,0xFF, + 0x51,0x00,0xF0,0xFF,0xA7,0xFF,0xA4,0xFF,0xF9,0xFF,0x87,0x01, + 0x8D,0x00,0xD7,0xFF,0x97,0xFE,0xA7,0xFE,0x39,0x00,0xA4,0xFF, + 0x44,0x00,0xAC,0x00,0x36,0x00,0x91,0xFF,0x51,0x00,0x5D,0x00, + 0xD0,0xFF,0x02,0x00,0x69,0xFF,0x5F,0x00,0xBE,0x00,0x7F,0x01, + 0xA1,0x00,0x4B,0xFF,0x1E,0x00,0xB2,0xFD,0xB0,0x00,0xDE,0x01, + 0xB9,0xFD,0x98,0xFE,0x63,0xFF,0x71,0x00,0xBF,0x00,0x35,0x02, + 0x56,0x00,0xF5,0xFE,0x2D,0xFF,0x51,0xFF,0xB6,0x00,0xE4,0xFE, + 0x3A,0x00,0x4B,0x00,0xC6,0xFF,0x55,0xFF,0x3A,0x00,0x64,0x01, + 0x27,0x00,0x93,0xFF,0x5E,0xFF,0x57,0x00,0x60,0x00,0x5B,0x00, + 0x5E,0x00,0xB6,0xFF,0xB8,0x00,0xE1,0x02,0x54,0x00,0x1C,0xFE, + 0x4C,0x00,0x92,0x00,0xBD,0xFF,0xB7,0xFF,0x18,0xFD,0x51,0xFD, + 0x25,0xFF,0xD4,0xFE,0x12,0x01,0x78,0x00,0xB8,0xFF,0x95,0xFF, + 0xD3,0xFF,0x18,0x02,0x87,0x02,0x54,0x03,0xC9,0x02,0x5E,0x00, + 0x86,0xFF,0x5F,0xFF,0xEA,0xFF,0x53,0x00,0xF8,0xFE,0x09,0xFD, + 0x5B,0xFD,0x07,0xFF,0x6A,0xFE,0xE6,0xFE,0x6A,0x00,0xF1,0x00, + 0xC4,0xFF,0xD2,0xFE,0xA5,0x00,0xB8,0x01,0xBF,0x03,0x5F,0x02, + 0x0D,0xFE,0x96,0xFE,0xB1,0xFF,0x51,0x00,0x8E,0x00,0x43,0xFF, + 0xA7,0xFD,0x71,0xFF,0x63,0x00,0x43,0xFF,0x4B,0x01,0xA6,0x00, + 0x7F,0xFF,0xB7,0x01,0x0F,0x01,0xB6,0xFE,0x5E,0x00,0xD1,0xFE, + 0xFC,0xFE,0x1A,0x03,0xBA,0x01,0x5F,0xFE,0xE4,0xFE,0xC1,0x00, + 0x8E,0x00,0x25,0x00,0x1D,0xFF,0x40,0x00,0x9A,0x00,0x37,0x01, + 0xCB,0x00,0xCD,0xFE,0xB8,0x00,0x3C,0x00,0x93,0xFE,0xAA,0xFF, + 0xC0,0xFF,0x94,0xFE,0xAC,0xFE,0x51,0xFF,0xAB,0xFF,0x1D,0x00, + 0xF5,0xFE,0x90,0xFE,0x73,0x00,0x5F,0x00,0xFB,0xFF,0x9A,0x00, + 0xA6,0x00,0x45,0x00,0x50,0x00,0xE9,0x00,0x97,0x00,0x84,0x00, + 0xE0,0x00,0xB1,0x00,0x56,0x00,0x22,0x00,0x15,0x00,0x18,0x00, + 0x87,0x00,0x9C,0x00,0xEB,0xFF,0x3B,0xFF,0xAE,0xFF,0x2D,0x00, + 0xBF,0xFF,0xB5,0xFF,0xC0,0xFF,0xCD,0xFF,0xB8,0xFF,0xAB,0xFF, + 0xD5,0xFF,0xEC,0xFF,0xE0,0xFF,0x94,0xFF,0xBA,0xFF,0xD8,0xFF, + 0xB8,0xFF,0xE6,0xFF,0xD2,0xFF,0xCB,0xFF,0xEB,0xFF,0xCC,0xFF, + 0xD0,0xFF,0xE6,0xFF,0x00,0x00,0xF8,0xFF,0x1A,0x00,0x36,0x00, + 0x06,0x00,0x17,0x00,0x57,0x00,0x57,0x00,0x2A,0x00,0x4A,0x00, + 0x4E,0x00,0x3C,0x00,0x34,0x00,0x16,0x00,0x00,0x00,0xFA,0xFF, + 0xF6,0xFF,0xE7,0xFF,0xDB,0xFF,0x03,0x00,0x1A,0x00,0xBB,0xFF, + 0xD7,0xFF,0x21,0x00,0xF9,0xFF,0x19,0x00,0x35,0x00,0x09,0x00, + 0x26,0x00,0x26,0x00,0x28,0x00,0x30,0x00,0x15,0x00,0x25,0x00, + 0x23,0x00,0x48,0x00,0x49,0x00,0x2A,0x00,0x19,0x00,0xE9,0xFF, + 0xE0,0xFF,0xCF,0xFF,0xA8,0xFF,0x8F,0xFF,0x95,0xFF,0xAE,0xFF, + 0x8F,0xFF,0x8D,0xFF,0xA5,0xFF,0xAF,0xFF,0xCD,0xFF,0xE8,0xFF, + 0xEF,0xFF,0x11,0x00,0x33,0x00,0x2E,0x00,0x36,0x00,0x47,0x00, + 0x45,0x00,0x37,0x00,0x32,0x00,0x24,0x00,0x13,0x00,0x1A,0x00, + 0x27,0x00,0x20,0x00,0x10,0x00,0x04,0x00,0xFD,0xFF,0xF2,0xFF, + 0xF1,0xFF,0xE8,0xFF,0xE3,0xFF,0xF7,0xFF,0xFB,0xFF,0xFD,0xFF, + 0xFD,0xFF,0xF5,0xFF,0xF8,0xFF,0xFD,0xFF,0xF1,0xFF,0xEE,0xFF, + 0xF1,0xFF,0xEB,0xFF,0xE3,0xFF,0xDF,0xFF,0xE5,0xFF,0xE7,0xFF, + 0xF3,0xFF,0xFC,0xFF,0xFE,0xFF,0x0B,0x00,0x10,0x00,0x17,0x00, + 0x1E,0x00,0x1E,0x00,0x1C,0x00,0x0A,0x00,0x05,0x00,0x07,0x00, + 0x02,0x00,0xFF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA,0xFF, + 0xF8,0xFF,0xFB,0xFF,0x00,0x00,0x09,0x00,0x0B,0x00,0x0C,0x00, + 0x10,0x00,0x15,0x00,0x17,0x00,0x1B,0x00,0x1D,0x00,0x1B,0x00, + 0x1D,0x00,0x18,0x00,0x12,0x00,0x10,0x00,0x0A,0x00,0x08,0x00, + 0x06,0x00,0x06,0x00,0x06,0x00,0x04,0x00,0x02,0x00,0x00,0x00, + 0xFE,0xFF,0xFC,0xFF,0xFB,0xFF,0xF9,0xFF,0xF4,0xFF,0xEE,0xFF, + 0xEC,0xFF,0xEC,0xFF,0xE9,0xFF,0xE6,0xFF,0xE4,0xFF,0xE4,0xFF, + 0xE4,0xFF,0xE5,0xFF,0xE5,0xFF,0xE3,0xFF,0xE3,0xFF,0xE5,0xFF, + 0xE6,0xFF,0xEA,0xFF,0xEC,0xFF,0xF1,0xFF,0xF8,0xFF,0xF9,0xFF, + 0xFB,0xFF,0x00,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x0B,0x00, + 0x0F,0x00,0x0C,0x00,0x13,0x00,0x1C,0x00,0x09,0x00,0x0B,0x00, + 0x0D,0x00,0x04,0x00,0x05,0x00,0x02,0x00,0x07,0x00,0x08,0x00, + 0x00,0x00,0x04,0x00,0x07,0x00,0x04,0x00,0x07,0x00,0x08,0x00, + 0x0B,0x00,0x07,0x00,0x0A,0x00,0x09,0x00,0x04,0x00,0x04,0x00, + 0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xFA,0xFF,0x01,0x00, + 0x01,0x00,0xFE,0xFF,0x01,0x00,0x03,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x02,0x00,0x08,0x00,0xFF,0xFF,0xFB,0xFF,0xFD,0xFF, + 0x04,0x00,0x05,0x00,0x04,0x00,0x03,0x00,0x02,0x00,0x03,0x00, + 0x02,0x00,0x03,0x00,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFC,0xFF, + 0xFE,0xFF,0x05,0x00,0xF6,0xFF,0xF1,0xFF,0xF8,0xFF,0xF2,0xFF, + 0xF3,0xFF,0xF7,0xFF,0xFD,0xFF,0xFB,0xFF,0xFC,0xFF,0xFC,0xFF, + 0xFE,0xFF,0x01,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x03,0x00, + 0x03,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x01,0x00,0x02,0x00, + 0x01,0x00,0xFE,0xFF,0x02,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0xFE,0xFF,0x00,0x00,0x02,0x00,0xFF,0xFF,0x03,0x00,0x01,0x00, + 0x00,0x00,0x06,0x00,0x03,0x00,0x04,0x00,0x04,0x00,0x04,0x00, + 0x05,0x00,0x03,0x00,0x02,0x00,0x01,0x00,0x02,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0xFD,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF, + 0xFD,0xFF,0xFD,0xFF,0xFC,0xFF,0xFD,0xFF,0xFF,0xFF,0xFC,0xFF, + 0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF, + 0xFC,0xFF,0xFC,0xFF,0xFE,0xFF,0xFE,0xFF,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x03,0x00,0x03,0x00,0xFF,0xFF,0x01,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF, + 0x01,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x02,0x00, + 0x02,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x02,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xFF,0xFF,0x01,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x03,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0xFE,0xFF,0xFE,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00, + 0xFE,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFD,0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF, + 0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00, + 0x01,0x00,0x02,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0xFF,0xFF,0x01,0x00,0x04,0x00,0x02,0x00,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0x03,0x00,0x05,0x00,0x03,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x01,0x00,0xFF,0xFF,0xFE,0xFF, + 0xFE,0xFF,0x02,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x02,0x00,0xFF,0xFF,0x02,0x00,0x01,0x00,0x01,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xFE,0xFF,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0x00,0x00, + 0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFE,0xFF,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF, + 0x00,0x00,0x01,0x00,0xFF,0xFF,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF, + 0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0x01,0x00,0x01,0x00, + 0x00,0x00,0x01,0x00,0xFE,0xFF,0x01,0x00,0x03,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x03,0x00, + 0x00,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x00,0x00,0x02,0x00, + 0x01,0x00,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0xFE,0xFF,0xFF,0xFF, + 0x02,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x01,0x00, + 0xFF,0xFF,0x02,0x00,0xFE,0xFF,0xFF,0xFF,0x02,0x00,0xFF,0xFF, + 0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFF,0xFF,0x01,0x00,0xFE,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00, + 0xFE,0xFF,0xFD,0xFF,0xFC,0xFF,0xFD,0xFF,0xFB,0xFF,0xFA,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF, + 0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x03,0x00, + 0x04,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00, + 0x00,0x00,0xFE,0xFF,0xFA,0xFF,0xFE,0xFF,0xFB,0xFF,0x00,0x00, + 0xFD,0xFF,0xFE,0xFF,0x02,0x00,0x00,0x00,0x05,0x00,0xF8,0xFF, + 0x10,0x00,0xF7,0xFF,0x0B,0x00,0xE5,0xFF,0xFA,0xFF,0x91,0x00, + 0x54,0x00,0xED,0xFF,0xDD,0xFF,0xAA,0xFF,0x07,0x00,0xDD,0x00, + 0xB0,0x00,0x49,0x01,0xC5,0xFF,0x26,0xFE,0x34,0xFF,0xE9,0xFF, + 0x7A,0x00,0xA0,0xFE,0x67,0x01,0xDE,0xFE,0x40,0xFE,0x4B,0x06, + 0xA0,0x00,0x59,0xFD,0x47,0xFD,0x4B,0xF9,0x72,0xFB,0x2F,0x00, + 0xED,0x01,0x1E,0x01,0x79,0x03,0xAE,0x04,0xA8,0x00,0x9B,0x01, + 0x30,0x04,0xF9,0xFF,0x85,0x00,0xC9,0x01,0xC8,0xFE,0xD7,0xFE, + 0xC9,0xFF,0x3D,0x00,0xDD,0xFE,0xBB,0xFE,0x0B,0x00,0xD0,0xFC, + 0x29,0xFC,0x5D,0xFF,0x73,0xFE,0x71,0xFF,0x50,0x03,0xBE,0x02, + 0xBD,0x01,0x1E,0x02,0x64,0x01,0x66,0xFF,0x1E,0xFE,0xB2,0xFF, + 0x64,0xFE,0x91,0xFD,0x95,0x00,0x57,0xFF,0x89,0xFE,0x90,0x00, + 0x72,0x00,0xB4,0xFF,0x78,0x00,0x3F,0x01,0x04,0x00,0x9D,0xFF, + 0xD1,0x00,0x1C,0x01,0xDE,0xFF,0x3B,0x01,0x2D,0x01,0x26,0xFE, + 0xBF,0xFE,0x93,0xFF,0xF4,0xFE,0x9F,0xFF,0x13,0x01,0x11,0x00, + 0x3D,0xFF,0x34,0x00,0xFB,0x00,0x7B,0xFF,0x0F,0x00,0x50,0x02, + 0x1D,0xFF,0x97,0xFF,0x94,0x00,0x64,0xFF,0x84,0xFF,0xE3,0xFF, + 0x2E,0x01,0xA0,0xFF,0x49,0xFF,0xAD,0x01,0x14,0x00,0x19,0x00, + 0x73,0x01,0x02,0xFF,0x80,0x01,0x0B,0xFE,0xA1,0x00,0x52,0x00, + 0x93,0xFD,0xD7,0x02,0xCC,0xFC,0xF7,0x01,0xD4,0xFF,0xC9,0xFE, + 0xEB,0x02,0xD1,0xFC,0xD1,0x00,0x48,0x00,0x29,0xFF,0xEB,0x00, + 0xBA,0xFF,0x96,0x00,0x44,0x00,0x63,0xFF,0x12,0x00,0x16,0xFF, + 0xE6,0xFF,0xF9,0xFF,0x43,0xFE,0xE7,0x00,0xC4,0xFF,0x5E,0xFF, + 0x5F,0x01,0xFD,0xFE,0x3D,0xFF,0x14,0x00,0xD5,0x00,0x01,0x00, + 0xB8,0xFF,0x36,0x02,0xEC,0xFF,0x6E,0x00,0x6F,0x00,0xC7,0xFF, + 0x9B,0xFE,0x61,0xFE,0x5D,0x01,0x0C,0xFE,0xEC,0xFF,0x95,0x00, + 0xCD,0xFE,0xDD,0x00,0x1F,0x01,0xF2,0x00,0xBC,0xFF,0x8C,0x00, + 0xBC,0xFF,0xC0,0xFF,0xC2,0x01,0x1A,0x01,0x36,0xFF,0xB6,0xFF, + 0xD1,0xFF,0xD5,0xFE,0xB4,0xFF,0x30,0xFF,0x24,0xFF,0xF6,0xFF, + 0x94,0x01,0x4D,0x01,0x72,0x00,0x06,0xFF,0xBE,0xFF,0x86,0x00, + 0x74,0x00,0xF9,0x01,0xC0,0xFE,0x45,0x00,0xEA,0xFF,0x29,0xFF, + 0x28,0x01,0xDE,0xFE,0xF1,0xFE,0x54,0xFF,0x02,0x01,0xB0,0xFF, + 0xBA,0xFE,0x8B,0x01,0x45,0xFF,0xE1,0xFE,0x33,0x02,0x46,0x01, + 0x08,0xFF,0x5B,0xFF,0x37,0x00,0x38,0x00,0x53,0x00,0x94,0x00, + 0xAA,0xFE,0x64,0xFF,0x5D,0x01,0x2C,0xFF,0x75,0xFF,0xA6,0x00, + 0x3E,0xFF,0xCF,0xFE,0x5F,0x01,0x39,0x00,0xDE,0xFD,0x77,0x00, + 0x08,0x00,0x84,0xFF,0x58,0x01,0x17,0x01,0x89,0xFF,0xB8,0xFF, + 0x71,0x01,0xB2,0xFE,0x01,0xFE,0x1F,0x00,0x12,0x00,0x94,0x00, + 0x0A,0x00,0xD6,0x00,0x0E,0x01,0xB7,0x01,0x01,0x00,0x12,0xFF, + 0x27,0x00,0x37,0xFE,0xC6,0xFF,0xDE,0xFF,0xF3,0xFF,0xC7,0x00, + 0x27,0x00,0xC3,0xFF,0x8E,0xFF,0x26,0x01,0x05,0x00,0x9D,0x00, + 0x70,0x00,0x04,0xFF,0x22,0x00,0x20,0xFE,0xE8,0xFF,0x37,0x00, + 0x64,0xFF,0x51,0x01,0xCF,0xFF,0x53,0xFF,0x54,0x01,0xAE,0x00, + 0xEF,0xFE,0x9D,0x00,0x6D,0x00,0xBE,0xFE,0xE7,0x00,0x23,0x01, + 0x03,0xFE,0x24,0x00,0xAD,0x00,0x8D,0xFE,0xEB,0xFF,0xCD,0x00, + 0x11,0x00,0xD6,0x00,0xD6,0xFF,0xEA,0xFE,0xE2,0xFF,0x5A,0xFF, + 0x15,0x01,0xE0,0xFF,0x8E,0xFF,0x43,0x00,0xA8,0xFF,0xED,0x00, + 0xF8,0xFF,0x59,0xFF,0x85,0x00,0xDF,0x01,0x8A,0x00,0xCC,0xFF, + 0x69,0x00,0x48,0xFF,0xBB,0xFF,0xE0,0x00,0x1E,0xFF,0xBD,0xFE, + 0x97,0x00,0x35,0xFF,0x56,0xFF,0xBC,0xFF,0xA2,0xFF,0x40,0x00, + 0x73,0x00,0xC0,0x00,0xEE,0xFF,0x29,0x00,0xE8,0xFE,0xAD,0x00, + 0x7C,0x00,0x3B,0xFF,0xCF,0x01,0xCA,0xFF,0xED,0xFD,0x20,0x00, + 0x9C,0x00,0xA7,0xFE,0x9C,0x00,0x01,0x02,0x17,0xFE,0x8F,0xFF, + 0x5E,0x02,0xB9,0xFD,0xC8,0xFF,0xC6,0x01,0xFB,0xFF,0xA4,0xFF, + 0x27,0x01,0xB2,0x00,0x50,0xFD,0xB2,0x01,0x5F,0x01,0x6F,0xFE, + 0x05,0x00,0xE8,0x00,0x32,0xFE,0x9B,0xFF,0xB3,0x01,0xDF,0xFD, + 0x3E,0x00,0xBD,0x01,0x09,0xFF,0x60,0x00,0x5C,0x01,0xB7,0xFE, + 0xDD,0xFE,0xC6,0x00,0xBF,0xFF,0x73,0xFE,0x2E,0x01,0xD8,0x00, + 0x3B,0xFE,0x34,0x01,0xEF,0x00,0x5E,0xFE,0xB7,0x00,0x05,0x01, + 0x8D,0xFE,0xCE,0xFF,0xBE,0x00,0x43,0xFE,0x46,0x00,0x26,0x01, + 0x30,0xFE,0xED,0x00,0x81,0x00,0xBB,0x00,0xCF,0xFE,0x25,0x01, + 0xFF,0x00,0x8E,0xFD,0x09,0x03,0x43,0xFE,0x2E,0x00,0x26,0x01, + 0x35,0xFF,0x53,0x00,0x83,0x00,0xE8,0xFF,0x26,0xFE,0x30,0x01, + 0xD9,0xFF,0x88,0xFF,0xC7,0x00,0xE7,0x00,0xB6,0xFF,0x21,0x00, + 0xE9,0x00,0x94,0xFF,0x4F,0xFF,0x90,0x00,0x2E,0xFF,0x14,0xFF, + 0x41,0x00,0xB8,0xFF,0x3F,0x00,0xD2,0xFF,0x7C,0x00,0xF0,0xFF, + 0x05,0x00,0x54,0x00,0xEC,0xFF,0xCA,0x00,0xE0,0xFF,0xA3,0xFF, + 0x07,0x00,0x9B,0xFF,0x92,0xFF,0x26,0x00,0xE0,0xFF,0xE9,0xFE, + 0xE8,0x00,0xE6,0xFF,0x38,0xFF,0x20,0x01,0x7A,0xFF,0x0A,0x00, + 0x22,0x01,0xB0,0xFF,0xBF,0xFF,0x89,0x00,0x5C,0xFF,0x96,0xFF, + 0x8D,0x00,0xD7,0xFF,0xA8,0xFF,0x6B,0x00,0x3C,0x00,0x84,0xFE, + 0x48,0x00,0x75,0x00,0x5F,0xFE,0x32,0x01,0xB3,0x00,0x3D,0xFF, + 0x5F,0x00,0x76,0x00,0x87,0xFF,0xC8,0xFF,0x91,0x01,0x5F,0xFF, + 0x18,0x00,0xFD,0x00,0x06,0xFF,0xCF,0xFF,0x6D,0x00,0xA4,0xFF, + 0x54,0xFF,0xF6,0x00,0xB3,0xFF,0xDC,0xFE,0x9A,0x00,0x62,0xFF, + 0x71,0xFF,0xBA,0x00,0x1F,0x00,0x3A,0x00,0xB6,0x00,0x22,0x00, + 0xCD,0xFF,0x0E,0x00,0x1A,0x00,0xD2,0xFF,0xFA,0xFF,0x32,0x00, + 0xCA,0xFF,0x1E,0x00,0xDC,0xFF,0x03,0x00,0x26,0x00,0x32,0x00, + 0x43,0x00,0x21,0x00,0x0D,0x00,0x59,0xFF,0x34,0x00,0xF2,0xFF, + 0x01,0x00,0xF0,0xFF,0x10,0x00,0xCD,0xFF,0x5C,0xFF,0x6B,0x00, + 0x51,0xFF,0x50,0xFF,0x64,0x00,0x33,0x00,0xE2,0xFF,0x0B,0x01, + 0x38,0x00,0x73,0xFF,0x6F,0x00,0x54,0x00,0xE0,0xFF,0x10,0x00, + 0xA7,0x00,0x67,0xFF,0x1C,0x00,0x84,0x00,0x0C,0xFF,0x95,0xFF, + 0x1B,0x00,0xC1,0xFF,0x41,0x00,0xCA,0x00,0xA0,0xFF,0x1A,0x00, + 0x8D,0x00,0x75,0xFF,0x50,0x00,0xEB,0xFF,0x41,0xFF,0x33,0x00, + 0x0A,0x00,0x50,0xFF,0xDA,0xFF,0x5C,0x00,0xF3,0xFF,0x30,0x00, + 0x85,0x00,0x2E,0x00,0x56,0x00,0xA8,0x00,0x5C,0x00,0x33,0x01, + 0xE8,0x00,0x6D,0x00,0xC4,0x00,0x29,0x00,0x75,0xFF,0xF6,0xFE, + 0xE3,0xFE,0xFE,0xFD,0x96,0xFD,0x28,0xFE,0xD8,0xFD,0xF2,0xFD, + 0xEE,0xFE,0xD4,0xFE,0xD1,0xFF,0x91,0x00,0x55,0x00,0x0B,0x01, + 0x56,0x01,0x50,0x01,0x9D,0x01,0x4D,0x02,0xEA,0x01,0xD3,0x01, + 0xE4,0x01,0xDA,0x00,0xBF,0x00,0xD7,0x00,0x0C,0x00,0xBD,0xFF, + 0x1D,0xFF,0xE2,0xFE,0x5C,0xFF,0xA4,0xFF,0x01,0x00,0x0D,0x00, + 0x8D,0x00,0x70,0x00,0x15,0x00,0x2A,0x00,0xE9,0xFF,0x20,0xFF, + 0x03,0xFF,0x2F,0xFF,0x72,0xFE,0xA7,0xFE,0xDA,0xFE,0xF4,0xFD, + 0xE4,0xFD,0x32,0x01,0xD4,0x03,0x9B,0x06,0x58,0x0A,0x3F,0x06, + 0x16,0x05,0xBD,0x02,0x64,0xF8,0x07,0xF8,0xC4,0xF7,0x41,0xF3, + 0x4E,0xF7,0x69,0xFB,0x71,0xF9,0xD1,0xFA,0x9E,0xFE,0x92,0xFC, + 0xD9,0xFD,0xF6,0x03,0x52,0x03,0x1F,0x06,0x31,0x0B,0x6E,0x08, + 0xD9,0x08,0x60,0x09,0xF9,0x04,0x4D,0x03,0x55,0x03,0x11,0x00, + 0x5A,0xFE,0xC1,0xFF,0x21,0xFE,0x9A,0xFD,0x7C,0xFE,0x43,0xFC, + 0xF8,0xFB,0xF6,0xFB,0xC6,0xFB,0xC4,0xFD,0xA0,0xFE,0x08,0x00, + 0x28,0x01,0x45,0x01,0x7E,0x01,0x1F,0x01,0xB6,0x00,0xFA,0xFF, + 0x24,0x00,0xB4,0xFF,0x8E,0xFE,0x9C,0xFE,0x61,0xFD,0xA8,0xFD, + 0xE7,0xFE,0x92,0xFF,0xF3,0x00,0x48,0x01,0xF2,0x00,0x5A,0x00, + 0x02,0x00,0x98,0xFF,0x03,0xFF,0x33,0xFF,0xD0,0x00,0x43,0x05, + 0x97,0x09,0xCA,0x0B,0xF4,0x0B,0xDA,0x07,0x03,0x05,0x10,0xF9, + 0xEE,0xEE,0xB1,0xF2,0x7B,0xEF,0x51,0xF2,0x46,0xFB,0x8B,0xFB, + 0xF1,0xFB,0x6E,0xFD,0xE4,0xFB,0xE0,0xFB,0x19,0x00,0xC9,0x04, + 0xCF,0x08,0x49,0x0E,0xAC,0x0E,0x70,0x0B,0xC9,0x08,0x37,0x02, + 0x1F,0xFF,0xC3,0xFD,0x41,0xFD,0x16,0xFF,0xBF,0xFE,0xA7,0xFE, + 0x59,0xFC,0x91,0xFA,0x25,0xFD,0x2E,0x00,0x3A,0x05,0xF6,0x07, + 0xD7,0x06,0xFD,0x03,0xBB,0xFD,0x74,0xFA,0xF1,0xF8,0xE6,0xFA, + 0x71,0xFF,0x36,0x01,0x72,0x02,0x7A,0xFF,0xCC,0xFB,0x87,0xFA, + 0x5E,0xFA,0x85,0xFE,0xDC,0x01,0xE4,0x02,0xF6,0x02,0x9C,0xFF, + 0x65,0xFE,0xCB,0xFE,0x22,0x00,0x1D,0x03,0x3A,0x03,0x46,0x02, + 0xDE,0xFE,0xDB,0xFA,0xB5,0xF9,0x57,0xFB,0xFD,0x08,0x25,0x1B, + 0xD1,0x1D,0x8F,0x17,0xBC,0x03,0x8B,0xE9,0x77,0xDC,0xDF,0xD7, + 0x13,0xE7,0x76,0xF8,0x25,0x04,0x41,0x0A,0xEA,0x02,0xA5,0xFF, + 0x5D,0xFD,0x89,0x03,0x73,0x11,0x8C,0x14,0x12,0x10,0x5E,0x05, + 0x18,0xF5,0x01,0xEE,0x99,0xF1,0x89,0xFD,0x3E,0x08,0xDE,0x0A, + 0x92,0x07,0xE4,0xFC,0x45,0xF8,0xAD,0xFB,0xDB,0x02,0x54,0x0B, + 0x96,0x0C,0xC8,0x07,0xD2,0x01,0x3A,0xFB,0xBC,0xFA,0x93,0xFF, + 0xB3,0x02,0xE9,0x01,0xC6,0xFB,0x82,0xF6,0x97,0xF3,0x63,0xF7, + 0x0D,0x00,0xBB,0x05,0xDB,0x07,0x11,0x04,0xCE,0xFF,0xD8,0xFE, + 0xFA,0xFF,0x00,0x03,0x79,0x03,0x36,0x00,0x17,0xFB,0xFC,0xF7, + 0xD6,0xF9,0x5F,0xFC,0x04,0x00,0xA0,0x02,0xCD,0x00,0x25,0xFF, + 0xFF,0xFE,0xDA,0xFE,0xF0,0x01,0x23,0x06,0xA7,0x06,0xA1,0x11, + 0xC8,0x1E,0xB4,0x13,0x72,0x03,0xB4,0xF1,0x7A,0xDD,0xFA,0xDC, + 0xA7,0xE7,0x80,0xF5,0xEF,0xFE,0x53,0x03,0x72,0x03,0xBE,0x02, + 0x42,0x0B,0x73,0x0F,0x18,0x0E,0x0E,0x0B,0x37,0xFE,0xFF,0xF2, + 0xA0,0xF3,0xAE,0xF8,0x61,0xFF,0x88,0x04,0x49,0x06,0x3B,0x02, + 0x21,0x00,0xEA,0x04,0x4B,0x06,0xB3,0x07,0xE6,0x05,0xEA,0xFD, + 0x1E,0xF9,0x3F,0xF9,0x9F,0xFF,0xC2,0x06,0x10,0x08,0x91,0x05, + 0xF4,0xFE,0x84,0xFB,0xEB,0xFB,0xB4,0xFB,0x1F,0xFE,0x76,0xFC, + 0x19,0xFA,0xF7,0xFB,0x49,0xFF,0x35,0x04,0x2D,0x06,0xAF,0x05, + 0xB7,0x01,0xF7,0xFC,0xAC,0xFC,0x99,0xFC,0x25,0xFE,0x31,0xFF, + 0xFC,0xFC,0x5A,0xFD,0xD3,0xFD,0x46,0xFE,0x69,0x00,0xF8,0x02, + 0xE5,0x02,0xB0,0xFF,0xF4,0x00,0x07,0x00,0x78,0xFE,0x91,0x01, + 0x87,0x02,0x9F,0x12,0xE1,0x21,0x60,0x11,0xB0,0xFE,0x5C,0xEC, + 0x38,0xDD,0x1C,0xE5,0xB6,0xF1,0x1B,0xFC,0xD4,0xFC,0xAE,0xFC, + 0x71,0x01,0x62,0x06,0x0B,0x12,0x57,0x11,0xA6,0x05,0xF8,0xFD, + 0xC6,0xF4,0xF5,0xF4,0x8A,0xFE,0x16,0x03,0x0B,0x03,0x15,0xFF, + 0xAB,0x00,0x33,0x03,0x8E,0x06,0x24,0x0C,0x2A,0x05,0xBA,0xFD, + 0xF9,0xF9,0xDA,0xF8,0x61,0xFE,0x2E,0x02,0x55,0x06,0x84,0x06, + 0x06,0x02,0x3C,0x02,0x69,0x01,0x39,0x01,0xB9,0xFF,0x3F,0xF9, + 0xA2,0xF6,0xAA,0xF6,0x32,0xFB,0x67,0x01,0x84,0x04,0xFD,0x04, + 0x66,0x01,0xE0,0x00,0x93,0x01,0xB0,0x00,0x80,0x00,0x7C,0xFD, + 0x75,0xFB,0xB6,0xFB,0xA1,0xFC,0x91,0xFF,0x62,0x00,0xB9,0xFF, + 0x99,0xFF,0xE8,0xFF,0x83,0x01,0xFA,0x01,0x28,0x02,0x8B,0x00, + 0x9C,0xFE,0xBF,0xFD,0x6C,0xFC,0xB3,0x0C,0xC5,0x24,0x13,0x1A, + 0xDC,0x00,0xB2,0xF0,0xBC,0xDF,0x4D,0xE5,0xFC,0xF4,0xE3,0xF9, + 0x46,0xF8,0x77,0xF6,0xC3,0xFE,0xD6,0x08,0x4C,0x14,0x28,0x13, + 0xD6,0x01,0xE5,0xF9,0x45,0xF8,0x93,0xF9,0xB8,0x02,0xCD,0x03, + 0x7B,0xFD,0x3C,0xFA,0x27,0x00,0xA5,0x08,0x95,0x09,0xEC,0x09, + 0x57,0x01,0xD1,0xF8,0xDF,0xFB,0x57,0xFF,0x72,0x02,0x8F,0x01, + 0x57,0xFE,0x26,0xFE,0x95,0x03,0x51,0x0D,0x23,0x0A,0x84,0xFF, + 0x6F,0xFA,0xAC,0xF4,0x07,0xF7,0xF8,0xFC,0x19,0xFD,0x9B,0xFC, + 0x62,0xFD,0x18,0x02,0x83,0x05,0x39,0x07,0xEA,0x03,0x92,0xFC, + 0x25,0xFC,0x71,0xFD,0x81,0xFE,0xAE,0x00,0x54,0xFE,0xDA,0xFB, + 0xA0,0xFC,0x2F,0x00,0xB9,0x02,0xFF,0x00,0x7A,0xFF,0x83,0xFE, + 0xAC,0x00,0x54,0x03,0xE9,0x01,0x32,0x00,0x00,0xFE,0x2A,0xF9, + 0x8D,0xFC,0x98,0x17,0x16,0x29,0x76,0x10,0x57,0xF9,0x90,0xEB, + 0x3C,0xE1,0x36,0xF0,0xF0,0xF9,0x75,0xF5,0x75,0xF0,0x8D,0xF6, + 0x41,0x06,0x14,0x11,0xC9,0x16,0x1A,0x08,0x25,0xF7,0xD6,0xFA, + 0x54,0xFE,0xC8,0x01,0x39,0x04,0x66,0xFC,0x2F,0xF7,0x94,0xFC, + 0x4F,0x0A,0x30,0x0C,0x45,0x06,0x10,0x02,0xAC,0xF9,0x76,0xFC, + 0x6A,0x03,0xD0,0x02,0x12,0xFF,0x58,0xFB,0xC9,0xFD,0xAF,0x02, + 0xE4,0x09,0xB8,0x0E,0x9A,0x03,0x3E,0xF8,0x5A,0xF9,0xA9,0xF9, + 0xA7,0xFB,0x32,0xFD,0xE0,0xF8,0x9E,0xF9,0xA8,0x00,0x12,0x07, + 0x76,0x07,0xD5,0x03,0x6A,0xFE,0x8C,0xFA,0x49,0xFF,0x10,0x02, + 0xE7,0xFD,0x52,0xFD,0x7C,0xFC,0x4E,0xFD,0x39,0x01,0x51,0x02, + 0xA0,0x00,0xFA,0xFC,0x0A,0xFE,0x7D,0x00,0xA6,0x02,0xAA,0x03, + 0xAE,0xFE,0x9D,0xFE,0x23,0x00,0xFC,0xFD,0xFB,0xFB,0x3D,0x04, + 0xE2,0x20,0x41,0x20,0x64,0x02,0xE0,0xF6,0xDE,0xE8,0x53,0xE9, + 0x9A,0xF6,0x51,0xF4,0xFD,0xEF,0xC0,0xF0,0x79,0x01,0x6D,0x0E, + 0x8A,0x11,0x5E,0x0D,0xCF,0xFA,0x50,0xFA,0xCD,0x03,0x75,0x02, + 0x8E,0x01,0x71,0xFB,0x8A,0xF8,0x98,0xFC,0x92,0x07,0x4E,0x0D, + 0xE9,0x02,0xB9,0xFF,0x50,0xFE,0x43,0xFF,0xAA,0x04,0x9C,0x01, + 0xAB,0xFC,0x3D,0xFA,0x73,0xFF,0xBA,0x04,0xB2,0x07,0x78,0x0A, + 0xAA,0x00,0x5B,0xFC,0x06,0x00,0x3F,0xFD,0x91,0xFB,0x57,0xF9, + 0x07,0xF8,0x56,0xFA,0x3D,0x01,0xAD,0x05,0x5E,0x02,0xD6,0x01, + 0x34,0x00,0xEA,0xFE,0xE3,0x01,0xA1,0xFF,0x01,0xFC,0xC2,0xFC, + 0xDF,0xFE,0x7C,0xFF,0x6A,0x00,0xA3,0x00,0x18,0xFE,0xC0,0xFE, + 0x6D,0x00,0x61,0xFF,0x28,0x00,0xBA,0x01,0x9D,0x00,0x07,0x00, + 0x3A,0x01,0x89,0x00,0x69,0xFE,0x7B,0xFE,0x04,0xFC,0xA1,0x02, + 0xC4,0x20,0x18,0x20,0x4A,0xFE,0xEB,0xF5,0xFB,0xEE,0x67,0xED, + 0x5F,0xF7,0x70,0xF2,0x8C,0xEC,0x52,0xF1,0xDA,0x05,0x6C,0x0F, + 0xB4,0x0B,0x44,0x08,0x0A,0xFA,0x03,0xFE,0x88,0x09,0x6E,0x03, + 0x99,0xFC,0xC2,0xF8,0xFF,0xFC,0x3E,0x01,0x40,0x08,0x0F,0x09, + 0xE1,0xFC,0xB2,0xFE,0x43,0x03,0x57,0x03,0x47,0x02,0xC8,0xFD, + 0x9D,0xFB,0x72,0xFD,0xEC,0x04,0xC8,0x04,0xC7,0x00,0x5D,0x02, + 0x07,0x05,0x17,0x07,0x12,0x00,0x76,0xFA,0xD1,0xF7,0x2B,0xF7, + 0xF7,0xFD,0xE1,0xFD,0xDF,0xFC,0x04,0xFF,0x69,0x01,0x90,0x05, + 0x69,0x04,0x2B,0x00,0xD9,0xFB,0x15,0xFD,0x0A,0x01,0xB5,0xFF, + 0x79,0xFE,0x39,0xFD,0x1E,0xFE,0x1C,0x01,0xCC,0x01,0x72,0x00, + 0x13,0xFD,0x75,0xFD,0xA1,0x00,0x30,0x02,0x97,0x01,0x3F,0xFF, + 0x47,0xFF,0x02,0x01,0x86,0x02,0x2C,0x00,0xBA,0xFD,0x12,0xFC, + 0x43,0xFE,0xBD,0x1A,0x97,0x23,0xB6,0x01,0xE1,0xF5,0xD4,0xF3, + 0xC0,0xF0,0x57,0xF7,0xEA,0xF1,0x02,0xEB,0xBC,0xEE,0x54,0x04, + 0x58,0x0F,0xF2,0x07,0xF3,0x05,0xA4,0xFC,0x3D,0x00,0xB5,0x0B, + 0x69,0x04,0x68,0xFA,0xFD,0xF7,0x58,0x00,0x73,0x03,0x0F,0x05, + 0xF6,0x04,0xE7,0xFB,0xF6,0xFF,0x82,0x06,0xF5,0x04,0x4D,0xFF, + 0xCA,0xFB,0x34,0xFE,0x44,0x00,0xAA,0x04,0x56,0x02,0xE7,0xFD, + 0xDC,0x01,0x28,0x04,0xE0,0x06,0x2A,0x06,0x74,0xFA,0x98,0xF6, + 0x29,0xFC,0x5F,0xFC,0x78,0xFC,0xF4,0xFB,0xA8,0xFC,0xCF,0x00, + 0x0F,0x05,0x50,0x05,0x7C,0xFE,0xCB,0xFD,0x0B,0xFF,0xCE,0xFE, + 0x37,0x01,0xA2,0xFD,0x0F,0xFC,0x85,0xFF,0x6C,0x02,0x6F,0x01, + 0xC5,0xFE,0xEA,0xFE,0x04,0xFE,0x48,0x00,0xBE,0x01,0xD1,0xFE, + 0xAA,0xFE,0x86,0x01,0x93,0x01,0x50,0xFF,0xEA,0x00,0xC3,0x00, + 0xC4,0xFE,0x92,0x00,0xDF,0xFC,0xFD,0x04,0x8D,0x21,0xCE,0x16, + 0x51,0xF8,0xFA,0xF7,0x83,0xF5,0x8E,0xF4,0x4A,0xF4,0xFB,0xED, + 0xB4,0xEB,0xE3,0xF5,0x40,0x0C,0xAF,0x09,0x44,0x02,0x50,0x03, + 0x05,0x00,0xB9,0x08,0xB1,0x08,0x9C,0xFE,0x2B,0xF8,0xCF,0xFD, + 0x77,0x06,0xD9,0x00,0x7A,0x00,0xC3,0xFF,0x3D,0xFF,0x3D,0x05, + 0xA7,0x05,0x2E,0x00,0xAB,0xFB,0x56,0x00,0xF5,0x02,0x30,0x01, + 0x96,0x00,0x04,0xFF,0xD1,0x00,0x46,0x04,0xF8,0x03,0x81,0xFF, + 0x5E,0xFD,0xE8,0xFE,0xC8,0xFE,0xEC,0xFD,0xBA,0xFB,0x17,0xFC, + 0x67,0xFC,0xCD,0x01,0x7D,0x19,0xB2,0x0A,0x91,0xE7,0x32,0xF4, + 0xDA,0xFD,0xED,0xFB,0x5F,0xFB,0x99,0xF7,0xFB,0xFA,0x8D,0x04, + 0xE3,0x12,0x6D,0x05,0x24,0xF9,0xD6,0xFE,0x1A,0xFD,0x11,0x04, + 0x1B,0x02,0x89,0xF9,0xA5,0xFA,0x17,0x05,0xA5,0x08,0xB1,0xFB, + 0x59,0xFE,0xF0,0x02,0x3C,0x01,0x05,0x02,0xB6,0xFF,0x7F,0xFE, + 0x8C,0xFC,0x06,0x00,0x85,0xFF,0xE9,0x12,0x48,0x20,0x98,0x00, + 0x68,0xF9,0x53,0xFF,0x64,0xF8,0x22,0xF2,0xE4,0xE9,0x4C,0xEC, + 0xB7,0xEF,0x0A,0x00,0x8F,0x09,0xE3,0xFF,0x10,0x04,0x0E,0x08, + 0x08,0x0A,0x9D,0x08,0x96,0x00,0xB6,0xFC,0x25,0xFD,0x13,0x04, + 0x00,0x00,0x0F,0xFA,0xF0,0xFE,0x65,0x02,0xC8,0x03,0xD6,0x02, + 0x20,0x02,0xDB,0x00,0xBA,0x01,0xA2,0x04,0x33,0x01,0xEC,0xFD, + 0x8A,0xFF,0xD7,0x01,0x5A,0x02,0x9D,0xFF,0x53,0xFF,0x8C,0x00, + 0x26,0x00,0xB6,0xFF,0x0B,0xFD,0xD3,0xFE,0xEC,0xFF,0x18,0xFE, + 0xD5,0xFE,0x05,0xFE,0x8D,0xFF,0x2D,0xFF,0x48,0xFF,0x92,0x00, + 0x9F,0xFE,0x13,0xFF,0x90,0xFF,0x1D,0xFF,0xB2,0xFC,0xF9,0xFC, + 0x7C,0xFF,0x42,0xFF,0x9F,0x00,0xD7,0x00,0xBC,0x00,0xBE,0x01, + 0x92,0x02,0x59,0x01,0xC6,0xFE,0xAF,0xFF,0x94,0xFF,0xB8,0xFE, + 0x13,0x00,0xC4,0xFF,0xC7,0xFE,0x59,0x00,0xA4,0x02,0xFE,0x01, + 0x95,0xFF,0xC2,0x00,0x9E,0x02,0x28,0x01,0xC5,0xFE,0xD8,0xFE, + 0x01,0xFC,0xE9,0x06,0x2B,0x1D,0xF2,0x08,0x37,0xF4,0xC9,0xFF, + 0xD7,0x00,0xF3,0xF7,0xE1,0xEC,0x98,0xEE,0x64,0xF3,0x4B,0xFC, + 0x40,0x07,0xF2,0xFD,0x07,0xFE,0x67,0x07,0x12,0x0A,0x2E,0x05, + 0x3F,0xFF,0xB4,0x00,0xE2,0x00,0x31,0x04,0x8C,0x01,0x9D,0xFA, + 0xF8,0xFD,0x1D,0x05,0x0E,0x04,0xEC,0xFD,0x88,0xFF,0x15,0x03, + 0xD9,0x02,0xAF,0x01,0xE0,0xFF,0xCC,0xFD,0xB3,0x00,0x39,0x04, + 0x79,0x01,0x1A,0xFE,0x09,0x00,0x17,0x03,0x5D,0x00,0x63,0xFD, + 0x6C,0xFC,0xC1,0xFC,0x67,0xFE,0xF0,0xFE,0xB0,0xFD,0x8F,0xFD, + 0xFD,0x00,0x33,0x03,0x0F,0x00,0xE7,0xFF,0xFC,0xFD,0x9D,0x04, + 0x41,0x16,0x88,0xFD,0x43,0xE7,0xB9,0xFB,0xE5,0x02,0xA3,0xF7, + 0xDD,0xF0,0x60,0xFC,0x80,0x04,0x09,0x07,0xD9,0x0A,0x44,0x01, + 0x2E,0xFE,0x4E,0x05,0xD0,0x04,0xA7,0xFB,0xD7,0xFA,0x10,0x01, + 0xB0,0x03,0x82,0x02,0x6C,0xFF,0x3B,0xFE,0xDE,0x01,0x2E,0x07, + 0x8F,0xFF,0x54,0xF9,0x38,0x00,0x56,0x05,0x2E,0x00,0x19,0xFB, + 0xED,0xFC,0x13,0x00,0x8D,0x01,0x38,0x0E,0xC9,0x14,0x52,0xFC, + 0x63,0xFB,0xC0,0x08,0x1A,0xFE,0x22,0xEE,0xB4,0xEB,0xE8,0xF6, + 0x15,0xF8,0x54,0xFB,0xA7,0xFD,0x88,0xFD,0x50,0x04,0x81,0x09, + 0x1C,0x06,0x45,0xFF,0x80,0x05,0x65,0x07,0x9E,0x03,0xA8,0xFF, + 0x82,0xFD,0x64,0xFF,0xE7,0x00,0xD3,0x01,0x2E,0xFC,0xB7,0xFD, + 0xF1,0x03,0x76,0x04,0xCB,0xFF,0xED,0xFE,0xAE,0x01,0x0C,0x02, + 0x3E,0x02,0x72,0xFF,0xE9,0xFF,0x63,0x01,0xA8,0x02,0x50,0x00, + 0x55,0xFD,0x61,0xFE,0xC9,0xFE,0x78,0xFE,0xD2,0xFC,0x39,0xFD, + 0x49,0xFE,0xE6,0xFF,0xD8,0xFF,0x4A,0xFF,0xAD,0xFF,0x36,0x01, + 0xA9,0x01,0x23,0x01,0x68,0x00,0x60,0x01,0xFD,0x02,0xCD,0xFB, + 0x60,0xFC,0x2B,0xFF,0x5F,0xFD,0x3E,0xFC,0x70,0xFC,0xCA,0x00, + 0x05,0x00,0x31,0x01,0x1A,0x01,0xE4,0x01,0x51,0x02,0x42,0x00, + 0x5D,0x01,0x27,0x00,0xA9,0x00,0xB5,0xFF,0x26,0x00,0x9E,0x00, + 0xF9,0xFF,0x4B,0x01,0x2E,0x01,0xC6,0x00,0xFE,0xFF,0x0E,0x01, + 0x17,0x01,0xF3,0xFF,0xB1,0xFF,0x26,0x00,0x80,0x00,0xFC,0xFF, + 0xA0,0xFF,0xD0,0xFF,0x5A,0x00,0x53,0x00,0xDC,0xFF,0x89,0xFF, + 0xB7,0xFF,0xDF,0xFF,0x05,0x00,0x38,0xFF,0x63,0x01,0xE8,0x02, + 0x30,0x00,0x89,0xFF,0x44,0x00,0xC6,0xFF,0x87,0xFD,0x42,0xFD, + 0xD0,0xFD,0x3D,0xFD,0xF3,0xFD,0xD0,0xFE,0x0B,0xFF,0x39,0xFF, + 0x50,0x00,0x0E,0x01,0x3B,0x01,0xA5,0x01,0x08,0x02,0xE6,0x01, + 0xA0,0x01,0x78,0x01,0xB1,0x00,0x50,0x00,0x28,0x00,0x74,0xFF, + 0x65,0xFF,0xD5,0xFF,0xB0,0xFF,0x57,0xFF,0xE6,0xFF,0xA1,0x00, + 0x5B,0x00,0x71,0x00,0x23,0x01,0x4A,0x01,0xA2,0x00,0x6E,0x00, + 0x5E,0x00,0x86,0xFF,0x3A,0xFF,0x06,0xFF,0x9A,0xFE,0x92,0xFE, + 0x1E,0xFF,0x41,0xFF,0x29,0xFF,0xA2,0xFF,0xF7,0xFF,0x0E,0x00, + 0x2C,0x00,0x5A,0x00,0x0C,0x00,0xF5,0xFF,0xF1,0xFF,0x71,0xFF, + 0xB0,0xFE,0x61,0xFE,0x4F,0xFE,0xB9,0xFE,0xFB,0xFF,0xC5,0x00, + 0x91,0x00,0x41,0x01,0x34,0x02,0xC0,0x01,0x91,0x00,0xF8,0xFF, + 0x51,0x01,0x93,0x03,0x1B,0x0A,0xED,0x05,0x4D,0xFE,0x7A,0x03, + 0xD2,0x02,0x04,0xFB,0xC8,0xF3,0x0C,0xF8,0x25,0xFB,0x72,0xF7, + 0xFA,0xF8,0x1C,0xFC,0xC9,0x00,0xF8,0x00,0xC2,0x01,0x9A,0x02, + 0xAC,0x04,0x58,0x07,0xB1,0x04,0xB6,0x02,0x92,0x02,0x63,0x03, + 0x7E,0x00,0x00,0xFE,0x9E,0xFE,0x35,0xFF,0x3E,0xFF,0xDE,0xFE, + 0x1A,0xFF,0xDE,0xFF,0xF7,0x00,0x16,0x01,0x74,0x00,0x75,0x01, + 0x11,0x03,0x48,0x02,0x08,0x01,0xF4,0x00,0x36,0x01,0x7F,0xFF, + 0x16,0xFE,0xEC,0xFD,0xFC,0xFD,0x11,0xFE,0xC2,0xFD,0x06,0xFE, + 0x5A,0xFE,0x66,0xFF,0xAB,0xFF,0xBE,0xFF,0x7D,0x00,0x55,0x01, + 0x57,0x01,0xC1,0x00,0x89,0x00,0x2A,0x00,0xC4,0xFF,0xE0,0xFE, + 0x81,0xFE,0x8B,0xFE,0x99,0xFE,0x8C,0xFE,0xD7,0xFE,0x87,0xFF, + 0xD6,0xFF,0x32,0x00,0xD3,0x00,0xE9,0x00,0x0A,0x01,0x60,0x01, + 0x11,0x01,0x9D,0x00,0x6A,0x00,0x9D,0x00,0xFD,0xFF,0xBC,0xFF, + 0x17,0x00,0x0E,0x00,0xDA,0xFF,0xEB,0xFF,0x66,0x00,0x39,0x00, + 0x36,0x00,0x60,0x00,0x64,0x00,0x3D,0x00,0x16,0x00,0xFD,0xFF, + 0xD2,0xFF,0xD8,0xFF,0xCB,0xFF,0xA4,0xFF,0xBD,0xFF,0x06,0x00, + 0xFD,0xFF,0xEC,0xFF,0x01,0x00,0x28,0x00,0x1F,0x00,0x11,0x00, + 0x17,0x00,0x11,0x00,0x17,0x00,0x16,0x00,0x03,0x00,0xD8,0xFF, + 0xE9,0xFF,0x03,0x00,0xEF,0xFF,0xD9,0xFF,0xF2,0xFF,0x08,0x00, + 0x07,0x00,0x09,0x00,0x16,0x00,0x27,0x00,0x2C,0x00,0x2F,0x00, + 0x26,0x00,0x1D,0x00,0x13,0x00,0xF8,0xFF,0xD0,0xFF,0xCB,0xFF, + 0xCE,0xFF,0xB4,0xFF,0xB1,0xFF,0xD5,0xFF,0xE8,0xFF,0xE8,0xFF, + 0xFD,0xFF,0x18,0x00,0x1D,0x00,0x16,0x00,0x18,0x00,0x10,0x00, + 0x0A,0x00,0xFF,0xFF,0xEC,0xFF,0xD3,0xFF,0xD4,0xFF,0xDE,0xFF, + 0xCE,0xFF,0xCD,0xFF,0xE2,0xFF,0xFD,0xFF,0x01,0x00,0x03,0x00, + 0x1A,0x00,0x27,0x00,0x28,0x00,0x25,0x00,0x1D,0x00,0x1C,0x00, + 0x19,0x00,0x09,0x00,0xF4,0xFF,0xEE,0xFF,0xF9,0xFF,0xEC,0xFF, + 0xDF,0xFF,0xE8,0xFF,0xF8,0xFF,0xF8,0xFF,0xF8,0xFF,0x07,0x00, + 0x10,0x00,0x14,0x00,0x15,0x00,0x1B,0x00,0x1B,0x00,0x18,0x00, + 0x12,0x00,0x06,0x00,0x01,0x00,0xFC,0xFF,0xF2,0xFF,0xE7,0xFF, + 0xE6,0xFF,0xE8,0xFF,0xE8,0xFF,0xF0,0xFF,0xF9,0xFF,0x03,0x00, + 0x0D,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x1B,0x00,0x18,0x00, + 0x0F,0x00,0x09,0x00,0x07,0x00,0xFF,0xFF,0xF9,0xFF,0xF8,0xFF, + 0xF9,0xFF,0xF6,0xFF,0xF8,0xFF,0xFD,0xFF,0xFD,0xFF,0x03,0x00, + 0x06,0x00,0x08,0x00,0x08,0x00,0x0B,0x00,0x0B,0x00,0x06,0x00, + 0x03,0x00,0x00,0x00,0xFE,0xFF,0xF7,0xFF,0xF4,0xFF,0xF9,0xFF, + 0xF5,0xFF,0xF5,0xFF,0xFA,0xFF,0xF7,0xFF,0xFB,0xFF,0xFB,0xFF, + 0x03,0x00,0x02,0x00,0x04,0x00,0x07,0x00,0x07,0x00,0x05,0x00, + 0xFB,0xFF,0x0A,0x00,0xF6,0xFF,0x02,0x00,0xE7,0xFF,0xFC,0xFF, + 0xF0,0xFF,0x05,0x00,0xE4,0xFF,0x04,0x00,0x04,0x00,0x21,0x00, + 0x14,0x00,0xE9,0xFF,0x2E,0x00,0xDE,0xFE,0x8B,0x03,0xEC,0x02, + 0x3F,0xFE,0x02,0x00,0xDC,0x01,0x72,0xFE,0x27,0xF9,0xD6,0xFD, + 0xD3,0xFF,0x32,0xFD,0xA3,0xFC,0xE0,0x01,0x58,0x03,0x62,0xFF, + 0x14,0x00,0xF9,0x02,0xDC,0x03,0x71,0x00,0xBB,0x01,0x32,0x03, + 0x5A,0x02,0x74,0xFF,0xE6,0xFF,0x6E,0x01,0xB0,0xFF,0x38,0xFE, + 0xBD,0xFE,0x79,0x00,0x7B,0xFE,0x9C,0xFD,0x3E,0xFE,0x60,0xFF, + 0x61,0xFE,0x7C,0xFE,0x14,0x00,0x78,0x00,0xD7,0xFF,0xA3,0xFF, + 0x99,0x00,0x0F,0x00,0x97,0xFF,0xA1,0xFF,0x50,0x00,0x30,0x00, + 0x10,0x00,0x3A,0x00,0x49,0x00,0x24,0x00,0xF5,0xFF,0x32,0x00, + 0x52,0x00,0x87,0x00,0x84,0x00,0xB6,0x00,0xB1,0x00,0x88,0x00, + 0x93,0x00,0x63,0x00,0x4B,0x00,0x3F,0x00,0x45,0x00,0xEE,0xFF, + 0xD4,0xFF,0xF6,0xFF,0xBC,0xFF,0x8E,0xFF,0xF3,0xFF,0x0E,0x00, + 0xC9,0xFF,0x05,0x00,0x39,0x00,0x08,0x00,0xB6,0xFF,0x1E,0x00, + 0xFB,0xFF,0xB5,0xFF,0xBF,0xFF,0x06,0x00,0xC3,0xFF,0x87,0xFF, + 0xC9,0xFF,0xBD,0xFF,0x9C,0xFF,0x8B,0xFF,0xD0,0xFF,0xB9,0xFF, + 0xBC,0xFF,0xB3,0xFF,0xE1,0xFF,0xDE,0xFF,0xE0,0xFF,0xF0,0xFF, + 0x18,0x00,0x3A,0x00,0x2A,0x00,0x43,0x00,0x51,0x00,0x5C,0x00, + 0x40,0x00,0x4E,0x00,0x45,0x00,0x38,0x00,0x1F,0x00,0x31,0x00, + 0x25,0x00,0x02,0x00,0xF6,0xFF,0x0F,0x00,0x11,0x00,0xF6,0xFF, + 0xFB,0xFF,0x0B,0x00,0x08,0x00,0xF3,0xFF,0xFB,0xFF,0xFF,0xFF, + 0xFA,0xFF,0xEB,0xFF,0xFA,0xFF,0xFD,0xFF,0xFB,0xFF,0xF2,0xFF, + 0xF3,0xFF,0xF1,0xFF,0xFB,0xFF,0xF3,0xFF,0xEB,0xFF,0xFD,0xFF, + 0xFD,0xFF,0xF1,0xFF,0xF3,0xFF,0x06,0x00,0xF9,0xFF,0xEF,0xFF, + 0xFA,0xFF,0x08,0x00,0x06,0x00,0x02,0x00,0x11,0x00,0x10,0x00, + 0x08,0x00,0x0D,0x00,0x0F,0x00,0x07,0x00,0xFD,0xFF,0x02,0x00, + 0x06,0x00,0xFD,0xFF,0xF8,0xFF,0xFE,0xFF,0xFE,0xFF,0xFC,0xFF, + 0xFD,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFF,0xF5,0xFF, + 0xF8,0xFF,0xF6,0xFF,0xF4,0xFF,0xF4,0xFF,0xFA,0xFF,0xF7,0xFF, + 0xF4,0xFF,0xF9,0xFF,0xFF,0xFF,0x00,0x00,0xF9,0xFF,0x00,0x00, + 0x04,0x00,0x03,0x00,0xFE,0xFF,0x03,0x00,0x07,0x00,0x02,0x00, + 0xFF,0xFF,0x06,0x00,0x09,0x00,0x01,0x00,0x03,0x00,0x05,0x00, + 0x08,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x06,0x00,0x06,0x00, + 0x04,0x00,0x05,0x00,0x04,0x00,0x04,0x00,0x02,0x00,0x03,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0xFE,0xFF,0xFE,0xFF,0xFC,0xFF, + 0xFC,0xFF,0xFB,0xFF,0xFA,0xFF,0xFC,0xFF,0xFB,0xFF,0xFA,0xFF, + 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0x01,0x00,0x02,0x00, + 0xFF,0xFF,0x02,0x00,0x01,0x00,0x01,0x00,0x04,0x00,0x04,0x00, + 0x06,0x00,0x05,0x00,0x02,0x00,0x05,0x00,0x06,0x00,0x02,0x00, + 0x02,0x00,0x00,0x00,0x03,0x00,0xFE,0xFF,0xFC,0xFF,0xFE,0xFF, + 0xFE,0xFF,0x00,0x00,0xFF,0xFF,0xFC,0xFF,0xFD,0xFF,0xFF,0xFF, + 0xFD,0xFF,0xFE,0xFF,0xFC,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF, + 0xFD,0xFF,0xFE,0xFF,0xFD,0xFF,0xFB,0xFF,0xFD,0xFF,0xFE,0xFF, + 0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x01,0x00,0x01,0x00, + 0xFE,0xFF,0xFE,0xFF,0xFF,0xFF,0x02,0x00,0x02,0x00,0x01,0x00, + 0x02,0x00,0x01,0x00,0x05,0x00,0x02,0x00,0x02,0x00,0x04,0x00, + 0x00,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFD,0xFF,0xFE,0xFF,0x01,0x00, + 0xFD,0xFF,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0x02,0x00,0xFF,0xFF,0xFF,0xFF,0x02,0x00,0x02,0x00,0x01,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00, + 0xFF,0xFF,0x00,0x00,0x02,0x00,0x01,0x00,0xFE,0xFF,0xFE,0xFF, + 0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFD,0xFF,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x02,0x00,0xFE,0xFF,0x00,0x00,0x03,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0xFE,0xFF, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0xFD,0xFF, + 0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x01,0x00, + 0xFF,0xFF,0x01,0x00,0x01,0x00,0xFE,0xFF,0x01,0x00,0x02,0x00, + 0x02,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0x02,0x00,0xFF,0xFF, + 0xFF,0xFF,0x02,0x00,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0x01,0x00, + 0xFF,0xFF,0xFE,0xFF,0x01,0x00,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0xFF,0xFF,0xFE,0xFF,0x01,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00, + 0x01,0x00,0x01,0x00,0x01,0x00,0xFE,0xFF,0x02,0x00,0x02,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x02,0x00,0xFF,0xFF,0xFB,0xFF,0x00,0x00, + 0x01,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xFE,0xFF, + 0x00,0x00,0x02,0x00,0x01,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x01,0x00, + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFE,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x01,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00,0x01,0x00,0x02,0x00, + 0xFF,0xFF,0xFF,0xFF,0x02,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF, + 0x01,0x00,0x01,0x00,0x01,0x00,0xFC,0xFF,0xFE,0xFF,0xFF,0xFF, + 0xFE,0xFF,0x00,0x00,0x01,0x00,0x02,0x00,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x03,0x00,0xFE,0xFF, + 0xFF,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0xFE,0xFF,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x02,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x02,0x00,0xF8,0xFF,0xF8,0xFF,0x0B,0x00,0x0A,0x00,0xFB,0xFF, + 0xF3,0xFF,0xFC,0xFF,0x05,0x00,0x03,0x00,0xFF,0xFF,0xFF,0xFF, + 0x02,0x00,0xFF,0xFF,0xFC,0xFF,0xFF,0xFF,0x05,0x00,0x02,0x00, + 0xFE,0xFF,0xFF,0xFF,0x03,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF, + 0x03,0x00,0x02,0x00,0xFD,0xFF,0xFD,0xFF,0x01,0x00,0x02,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xFD,0xFF,0x31,0x00,0x49,0x00,0x0A,0x00, + 0xF4,0xFF,0x1B,0x00,0xF4,0xFF,0x95,0xFF,0xB4,0xFF,0xF5,0xFF, + 0xBD,0xFF,0x9B,0xFF,0xF9,0xFF,0x16,0x00,0xCC,0xFF,0xEC,0xFF, + 0x5E,0x00,0x4B,0x00,0x0A,0x00,0x50,0x00,0x8D,0x00,0x39,0x00, + 0x0B,0x00,0x4E,0x00,0x3B,0x00,0xD6,0xFF,0xD9,0xFF,0x19,0x00, + 0xE4,0xFF,0x9B,0xFF,0xD2,0xFF,0xF8,0xFF,0xB7,0xFF,0xAE,0xFF, + 0xFB,0xFF,0x00,0x00,0xCB,0xFF,0xF1,0xFF,0x2F,0x00,0x04,0x00, + 0xE0,0xFF,0x12,0x00,0x25,0x00,0xF3,0xFF,0xF3,0xFF,0x28,0x00, + 0x1C,0x00,0xF0,0xFF,0x0A,0x00,0x28,0x00,0xFF,0xFF,0xE8,0xFF, + 0x0A,0x00,0x12,0x00,0xEF,0xFF,0xF1,0xFF,0x14,0x00,0x06,0x00, + 0xEE,0xFF,0x03,0x00,0x15,0x00,0xFC,0xFF,0xF5,0xFF,0x0F,0x00, + 0x0E,0x00,0xFA,0xFF,0x00,0x00,0x16,0x00,0x08,0x00,0xF7,0xFF, + 0x09,0x00,0x12,0x00,0xFE,0xFF,0xF7,0xFF,0x0B,0x00,0x0A,0x00, + 0xF2,0xFF,0xF8,0xFF,0x08,0x00,0xF9,0xFF,0xEA,0xFF,0xFB,0xFF, + 0x04,0x00,0xEF,0xFF,0xEB,0xFF,0xFD,0xFF,0xFB,0xFF,0xEC,0xFF, + 0xF5,0xFF,0x09,0x00,0xFD,0xFF,0xF7,0xFF,0x0B,0x00,0x10,0x00, + 0xFE,0xFF,0xFF,0xFF,0x10,0x00,0x08,0x00,0xFA,0xFF,0x02,0x00, + 0x0D,0x00,0xFF,0xFF,0xFA,0xFF,0x09,0x00,0x05,0x00,0xF9,0xFF, + 0xFF,0xFF,0x0A,0x00,0x05,0x00,0xFD,0xFF,0x05,0x00,0x0A,0x00, + 0xFE,0xFF,0xFE,0xFF,0x07,0x00,0x05,0x00,0xFB,0xFF,0xFE,0xFF, + 0x03,0x00,0xFA,0xFF,0xF9,0xFF,0xFC,0xFF,0xFD,0xFF,0xF8,0xFF, + 0xFA,0xFF,0x00,0x00,0xFB,0xFF,0xF9,0xFF,0x00,0x00,0x02,0x00, + 0xFB,0xFF,0x00,0x00,0x05,0x00,0x00,0x00,0xFC,0xFF,0x02,0x00, + 0x05,0x00,0x00,0x00,0x03,0x00,0x05,0x00,0x05,0x00,0x01,0x00, + 0x01,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x03,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xFE,0xFF,0xFF,0xFF, + 0x00,0x00,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF, + 0xFF,0xFF,0x01,0x00,0xFF,0xFF,0xFE,0xFF,0x01,0x00,0x02,0x00, + 0x02,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x01,0x00, + 0x03,0x00,0x01,0x00,0xFB,0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF, + 0xFC,0xFF,0x00,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x04,0x00,0xFE,0xFF,0x02,0x00,0xFA,0xFF, + 0x07,0x00,0x09,0x00,0xF9,0xFF,0xFF,0xFF,0xF8,0xFF,0x0B,0x00, + 0x08,0x00,0xFB,0xFF,0xFA,0xFF,0xFE,0xFF,0x08,0x00,0x05,0x00, + 0xF8,0xFF,0xFB,0xFF,0x04,0x00,0x04,0x00,0xFF,0xFF,0xF7,0xFF, + 0x03,0x00,0x07,0x00,0xFE,0xFF,0xFD,0xFF,0xFD,0xFF,0x03,0x00, + 0x02,0x00,0xFE,0xFF,0x01,0x00,0x01,0x00,0x03,0x00,0x02,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0xFD,0xFF,0xFF,0xFF,0x00,0x00, + 0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x02,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0xFE,0xFF,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x02,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF, + 0xFE,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xFE,0xFF, + 0x00,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,0x02,0x00, + 0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x02,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0xFF,0xFF, + 0xFD,0xFF,0xFD,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFE,0xFF, + 0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x04,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0xFD,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x02,0x00,0xFF,0xFF,0xFF,0xFF,0x03,0x00, + 0x02,0x00,0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0x00,0x00,0x02,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0x02,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x02,0x00,0xFD,0xFF,0xFE,0xFF, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFE,0xFF,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x02,0x00, + 0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0xFD,0xFF,0x00,0x00,0x02,0x00,0xFF,0xFF,0x01,0x00,0xFE,0xFF, + 0xFD,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0x01,0x00,0x02,0x00,0x01,0x00,0xFF,0xFF,0xFE,0xFF,0x02,0x00, + 0x03,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFE,0xFF, + 0x00,0x00,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0x01,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0x01,0x00, + 0xFE,0xFF,0x01,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x01,0x00,0x01,0x00,0xFD,0xFF,0x01,0x00,0x01,0x00, + 0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFE,0xFF,0x00,0x00, + 0x01,0x00,0x01,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0xFF,0xFF, + 0x02,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x02,0x00,0x01,0x00,0x01,0x00, + 0xFF,0xFF,0xFE,0xFF,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFE,0xFF, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFE,0xFF,0xFE,0xFF,0xFF,0xFF, + 0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF, + 0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x02,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFE,0xFF,0x00,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0xFE,0xFF,0x01,0x00,0x02,0x00,0x02,0x00,0xFF,0xFF, + 0xFD,0xFF,0x01,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0xFE,0xFF, + 0xFE,0xFF,0xFF,0xFF,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x02,0x00,0x04,0x00,0x02,0x00,0x02,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0xFD,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFD,0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0x01,0x00, + 0xFC,0xFF,0xFF,0xFF,0x04,0x00,0x03,0x00,0x02,0x00,0x00,0x00, + 0xFA,0xFF,0xFE,0xFF,0x03,0x00,0x03,0x00,0x0A,0x00,0xFB,0xFF, + 0x06,0x00,0xEA,0xFF,0x02,0x00,0xED,0xFF,0x04,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x02,0x00,0x04,0x00,0x03,0x00,0x3B,0x00, + 0x86,0xFF,0x0E,0x00,0xB5,0xFF,0x70,0x02,0xF5,0x03,0x0D,0x00, + 0xAE,0xFB,0x56,0xF9,0x07,0xFC,0xFF,0x00,0x80,0x04,0x5D,0x04, + 0x8B,0x01,0x37,0xFE,0x7F,0xFD,0xF2,0xFE,0x78,0x01,0xA9,0x02, + 0xFE,0x01,0x49,0x00,0xDF,0xFE,0xD3,0xFE,0x6F,0xFF,0x58,0x00, + 0x68,0x00,0x26,0x00,0x4B,0xFF,0x14,0xFF,0x3C,0xFF,0xC1,0xFF, + 0x19,0x00,0x32,0x00,0x24,0x00,0xE2,0xFF,0x16,0x00,0x21,0x00, + 0x77,0x00,0x3D,0x00,0x0D,0x00,0xDF,0xFF,0xE4,0xFF,0x19,0x00, + 0x26,0x00,0x24,0x00,0xD7,0xFF,0xC6,0xFF,0xA4,0xFF,0xEE,0xFF, + 0x05,0x00,0x25,0x00,0x12,0x00,0xDF,0xFF,0xE0,0xFF,0xE2,0xFF, + 0x2B,0x00,0x21,0x00,0x56,0x00,0x42,0x00,0xFB,0xFF,0xC0,0xFF, + 0xBC,0xFF,0x07,0x00,0x39,0x00,0x46,0x00,0x0A,0x00,0xE0,0xFF, + 0xDD,0xFF,0x03,0x00,0xFA,0xFF,0x1C,0x00,0x06,0x00,0xEF,0xFF, + 0xDE,0xFF,0xE4,0xFF,0x1B,0x00,0x00,0x00,0xFB,0xFF,0xD5,0xFF, + 0xFF,0xFF,0x23,0x00,0x39,0x00,0x12,0x00,0xE8,0xFF,0xE9,0xFF, + 0xF4,0xFF,0x2C,0x00,0x07,0x00,0xD7,0xFF,0xC2,0xFF,0xEB,0xFF, + 0x1B,0x00,0x3B,0x00,0x36,0x00,0x13,0x00,0xE7,0xFF,0xC1,0xFF, + 0x0D,0x00,0x16,0x00,0xF0,0xFF,0x1F,0x00,0xEA,0xFF,0xA0,0xFF, + 0xD9,0xFF,0x05,0x00,0x2C,0x00,0xEE,0xFF,0xE0,0xFF,0x2A,0x00, + 0xE2,0xFF,0x3B,0x00,0x2C,0x00,0x11,0x00,0xF0,0xFF,0xCD,0xFF, + 0x41,0x00,0x00,0x00,0x1B,0x00,0xEC,0xFF,0x36,0x00,0x25,0x00, + 0x26,0xFF,0xDF,0xFF,0x61,0x00,0x4E,0x00,0xBE,0xFF,0x6A,0xFF, + 0x92,0x00,0x27,0x00,0xDB,0xFF,0x5B,0x00,0xD8,0xFF,0xF5,0xFF, + 0x03,0x00,0x1F,0x00,0x5A,0x00,0xA8,0xFF,0x67,0xFF,0x4D,0x00, + 0x1D,0x00,0xEB,0xFF,0x04,0x00,0x80,0xFF,0x3A,0x00,0x0F,0x00, + 0x33,0x00,0xFE,0xFF,0x81,0xFF,0x84,0x00,0x7F,0x00,0x9D,0x00, + 0xE2,0xFF,0xE5,0xFE,0x28,0x00,0x4E,0x00,0xCA,0xFF,0xFC,0xFF, + 0xB3,0xFF,0x60,0x00,0x12,0x00,0x98,0xFF,0x91,0xFF,0x70,0x00, + 0x1E,0x00,0x0C,0x00,0x74,0x00,0xC7,0xFF,0x0E,0x00,0xD3,0xFE, + 0x5E,0x00,0x5F,0x01,0xB4,0xFF,0x08,0xFF,0x05,0x00,0x2A,0x00, + 0xB2,0x00,0x32,0x00,0x0B,0xFF,0xF5,0x00,0x47,0xFF,0x12,0x00, + 0x15,0x01,0x0D,0xFF,0x83,0xFF,0x51,0x00,0x9C,0x00,0x2D,0xFF, + 0x9C,0xFF,0x03,0x00,0x9B,0xFF,0xEB,0x00,0x7F,0x00,0x7D,0xFF, + 0x0B,0xFF,0xE7,0x00,0x32,0x00,0x78,0x00,0x08,0x00,0x3B,0xFE, + 0x6B,0x02,0xA2,0xFF,0xC9,0xFE,0x36,0x01,0x76,0xFF,0xF5,0xFF, + 0xC2,0xFE,0xCD,0x00,0x63,0x00,0xA5,0xFE,0xC4,0x01,0xFA,0xFF, + 0x13,0x00,0x6D,0xFF,0x0B,0xFF,0x41,0x01,0x23,0x00,0x04,0x00, + 0x5B,0x00,0xF0,0xFD,0x7E,0x00,0x4E,0x02,0xB9,0xFE,0x60,0x00, + 0x02,0xFF,0x72,0xFF,0xE9,0xFF,0xF4,0x00,0x57,0x01,0x1E,0xFE, + 0x7D,0xFF,0x3B,0x00,0xE2,0x00,0x75,0x00,0x13,0xFF,0x8A,0xFF, + 0x77,0x01,0x5D,0xFF,0xAD,0xFF,0xAC,0x00,0x33,0xFF,0x91,0x01, + 0x17,0xFF,0x2A,0x00,0x5A,0x01,0x06,0xFE,0xFC,0xFF,0x2F,0x00, + 0x20,0x00,0xD4,0x00,0x8A,0xFE,0x7E,0xFF,0xD9,0x01,0x09,0xFE, + 0x64,0x00,0x71,0x02,0x96,0xFE,0x6C,0xFF,0x24,0x00,0xFC,0xFF, + 0xC4,0xFF,0xA6,0x01,0x4C,0xFF,0x5F,0xFF,0xB4,0x00,0xF1,0xFF, + 0xDF,0x00,0xD3,0xFE,0x73,0x00,0x67,0x00,0x34,0xFE,0xD1,0xFF, + 0x9E,0x02,0x6F,0xFE,0x7E,0xFF,0x7C,0x00,0x33,0xFF,0xD6,0x00, + 0xBE,0xFF,0x06,0x01,0xE8,0xFD,0x97,0x00,0xD9,0x00,0x52,0xFF, + 0x54,0x01,0xE5,0xFF,0xCC,0xFE,0xDB,0xFF,0xA7,0x01,0x04,0x00, + 0x20,0xFF,0x63,0xFF,0x96,0x00,0xC0,0xFE,0x26,0x01,0x22,0x01, + 0x00,0xFE,0xE7,0x00,0xE2,0xFF,0x95,0xFF,0x11,0x01,0xA5,0xFF, + 0xBA,0xFF,0xEB,0xFF,0xB8,0xFD,0xDA,0x01,0x4B,0x01,0x2D,0xFF, + 0x80,0x01,0x08,0xFD,0xD0,0x00,0xA7,0x02,0x6D,0xFE,0x3E,0xFF, + 0x36,0xFF,0x0E,0x02,0x35,0xFE,0x61,0x00,0x8B,0x01,0xF3,0xFD, + 0xB0,0x02,0xF8,0xFF,0x1B,0xFF,0xDE,0xFE,0x92,0x00,0x20,0x01, + 0x5F,0xFE,0x34,0x00,0x9A,0xFF,0x24,0xFF,0x0B,0x01,0x05,0x01, + 0xA3,0xFF,0xDD,0xFE,0x01,0x01,0x1C,0xFF,0x5C,0x00,0xA3,0x02, + 0xB2,0xFC,0x97,0x00,0x17,0x01,0x59,0x00,0x3F,0x00,0xDF,0xFE, + 0xDA,0xFF,0xD1,0xFF,0x7D,0x01,0x08,0xFF,0xA4,0xFD,0x88,0x00, + 0xB3,0x03,0x93,0xFD,0x14,0xFF,0xB3,0x00,0xAE,0xFF,0x4F,0x02, + 0x55,0xFF,0x21,0xFF,0x3C,0xFF,0x17,0x02,0x4C,0x00,0xBA,0xFE, + 0xD2,0xFD,0x3B,0x01,0xB3,0x02,0xC0,0xFC,0x26,0x01,0x57,0xFE, + 0x68,0x02,0xDB,0x00,0x6D,0xFC,0x98,0x02,0x89,0xFE,0x12,0x02, + 0x94,0xFF,0xD3,0xFE,0x6B,0x01,0x3A,0xFF,0xB9,0x00,0xE8,0xFF, + 0x01,0xFE,0xAE,0xFF,0x84,0x01,0x90,0x00,0x19,0x00,0x92,0xFD, + 0x3F,0x00,0x65,0x01,0x24,0x00,0x5B,0x00,0x44,0xFE,0x11,0x00, + 0xB6,0x02,0x24,0x00,0xC6,0xFE,0x81,0xFF,0xF3,0xFF,0x8B,0x00, + 0xC6,0xFF,0x4C,0x00,0x6D,0xFF,0x45,0xFF,0x40,0x01,0x9E,0x00, + 0xEF,0xFE,0x3E,0x00,0x1D,0xFF,0xEC,0xFF,0xA6,0x00,0x68,0x00, + 0x6A,0x00,0xF3,0xFE,0x5F,0x00,0xF6,0xFF,0x0E,0x00,0xAE,0xFF, + 0xF8,0x01,0x62,0xFC,0xA1,0xFF,0xDF,0x04,0x7E,0xFE,0x36,0x00, + 0xC6,0xFE,0x6E,0x00,0xB5,0xFF,0x5A,0xFF,0x8E,0x01,0x54,0xFC, + 0xAA,0x01,0x9B,0x02,0x9F,0xFD,0x09,0x00,0xE2,0x00,0x36,0xFF, + 0x91,0xFF,0x5D,0x02,0x21,0xFF,0xBA,0x00,0x8E,0xFE,0x41,0x01, + 0xDB,0x01,0xED,0xFB,0xAF,0x01,0x28,0xFE,0x7E,0xFF,0x44,0x03, + 0xE8,0xFD,0x3D,0x00,0x35,0x00,0x43,0xFF,0x9F,0x00,0xDE,0xFF, + 0x45,0x01,0xF9,0xFD,0xC2,0x01,0xF5,0x00,0x91,0xFD,0xA4,0x02, + 0xD0,0x00,0x12,0xFD,0x95,0xFF,0x6C,0x00,0xB4,0xFF,0x49,0x01, + 0x6E,0xFE,0xE2,0x00,0x5D,0x00,0xB6,0xFE,0x10,0x02,0x44,0xFE, + 0x25,0x01,0x20,0x01,0xFE,0xFD,0x06,0x00,0x25,0x02,0x16,0x01, + 0x82,0xFC,0xAA,0xFE,0x3D,0x00,0x04,0x03,0x4E,0xFF,0xBB,0x00, + 0x52,0xFE,0xC0,0xFF,0x6E,0x03,0x25,0xFD,0x67,0x00,0x0D,0xFE, + 0xFE,0x00,0x65,0x01,0x45,0xFF,0x33,0xFF,0xAB,0xFF,0xF8,0xFF, + 0x12,0x02,0xE5,0x00,0x7E,0xFD,0x88,0x00,0x25,0x00,0x0C,0x01, + 0x8C,0xFE,0xDE,0x00,0xF4,0xFF,0xC8,0xFF,0x2A,0x00,0xA7,0x00, + 0xA8,0xFF,0x9F,0xFE,0x42,0x00,0x79,0xFE,0xC3,0x02,0x77,0x00, + 0x94,0xFE,0xFF,0xFD,0x4E,0x03,0xBD,0xFE,0xF5,0xFE,0x1E,0x03, + 0x26,0xFE,0xA0,0x01,0x9A,0xFE,0x62,0x01,0x55,0xFE,0x51,0xFF, + 0xEE,0x01,0x78,0xFD,0x6F,0x01,0x99,0x00,0x6B,0xFF,0x25,0xFE, + 0x95,0x00,0xE2,0x00,0x6F,0xFE,0x79,0x02,0x46,0x00,0x8C,0xFE, + 0xC6,0x00,0xFF,0x00,0xE6,0xFF,0x47,0xFE,0x6E,0x01,0xD6,0xFF, + 0x6D,0xFF,0x2A,0x01,0x78,0xFD,0x46,0x01,0x53,0x00,0x1C,0xFF, + 0xC0,0xFF,0x5D,0x00,0x34,0x01,0x65,0xFE,0x60,0x00,0x74,0xFF, + 0xDD,0x00,0x9E,0x00,0x90,0x00,0xE0,0xFF,0xB1,0xFE,0xB0,0x01, + 0xAF,0xFF,0xB4,0xFD,0x22,0x01,0xA9,0xFF,0x8B,0x00,0xF6,0x01, + 0x55,0xFE,0x0E,0x01,0xD2,0xFD,0x40,0x00,0xB0,0x00,0x68,0xFE, + 0x70,0x00,0x8F,0xFE,0xFE,0x01,0xE8,0x00,0xB8,0x00,0xC9,0xFF, + 0xBB,0xFE,0x9F,0x01,0xED,0xFF,0xAC,0xFE,0xA5,0x00,0xF0,0x00, + 0x22,0xFF,0x98,0x00,0x5D,0x00,0x15,0xFD,0xA8,0x00,0x41,0xFF, + 0x3E,0xFF,0x45,0x02,0x0E,0xFD,0xF5,0x02,0x11,0x01,0x54,0xFF, + 0x23,0x01,0x85,0xFE,0x1F,0x00,0x98,0x00,0xB1,0xFF,0xB6,0xFE, + 0x3A,0x01,0xC6,0xFF,0x7D,0xFF,0x73,0x00,0x70,0x00,0x5D,0xFF, + 0xCF,0xFF,0x18,0x00,0x9D,0x00,0x0D,0xFF,0x35,0x01,0x4D,0xFF, + 0x49,0xFF,0xAC,0x01,0x44,0xFD,0xE8,0x02,0xD6,0xFF,0xC6,0xFE, + 0x66,0x01,0x45,0xFE,0x5F,0x01,0xE8,0xFE,0xD7,0xFE,0x74,0x01, + 0xF3,0xFE,0x35,0x00,0xCF,0xFF,0x5B,0x01,0xF7,0x00,0x85,0xFE, + 0x93,0x00,0x73,0xFF,0xF1,0xFF,0x9F,0xFF,0x49,0x00,0x25,0x00, + 0x2D,0x00,0x81,0x00,0x7A,0xFF,0x78,0x02,0x8D,0xFE,0x03,0xFE, + 0x46,0x01,0x54,0xFF,0xD8,0x00,0xB2,0xFE,0x05,0x00,0x32,0x01, + 0x2F,0xFE,0xB2,0x01,0x0D,0x01,0x93,0xFE,0xE2,0xFE,0x3C,0x02, + 0x0E,0x00,0xB8,0xFF,0xDA,0xFF,0x9E,0xFE,0x38,0x01,0x82,0xFF, + 0x43,0x00,0x5C,0xFF,0x9D,0xFE,0x4E,0x01,0x8B,0x01,0x40,0xFF, + 0x68,0xFF,0x9E,0xFF,0xA7,0xFF,0x69,0x01,0x86,0x00,0x9D,0xFE, + 0x5D,0x00,0x6D,0x00,0xCA,0x00,0x45,0xFF,0x55,0xFF,0xAF,0xFF, + 0x6D,0xFF,0x9C,0x00,0xC6,0x00,0x77,0x00,0x05,0xFE,0x6B,0x01, + 0x88,0x01,0xEE,0xFE,0xCD,0xFF,0xA1,0xFF,0x58,0xFF,0xCA,0x01, + 0x0E,0xFF,0xDC,0xFF,0xF2,0xFF,0x85,0x00,0x06,0x00,0xC4,0xFE, + 0x5B,0x01,0x72,0xFE,0x72,0x01,0x3B,0xFF,0x3D,0xFF,0x71,0x00, + 0x63,0x00,0x96,0xFF,0xEE,0xFF,0x96,0x01,0xDC,0xFE,0x15,0x01, + 0x3D,0xFF,0x08,0xFF,0xBD,0x00,0x8A,0x00,0x4D,0xFF,0x24,0x00, + 0xCF,0x00,0x87,0xFF,0xEC,0xFF,0x26,0x00,0x87,0x00,0x98,0xFE, + 0xD1,0x00,0xF3,0xFF,0x83,0xFF,0x26,0x00,0xF1,0xFD,0xCA,0x01, + 0xAB,0x00,0x55,0xFF,0x9B,0x00,0xB3,0xFF,0x1C,0x01,0xD1,0xFF, + 0x4B,0xFF,0xB8,0x00,0x7E,0xFF,0x8A,0x00,0x73,0xFF,0x12,0x00, + 0x90,0xFF,0x59,0xFF,0x1A,0xFF,0x66,0xFF,0xB5,0x02,0xD8,0xFE, + 0xE4,0xFF,0xE0,0x00,0x31,0x00,0xB4,0x00,0x38,0xFF,0xF0,0xFF, + 0xD9,0x00,0xA8,0xFF,0xA0,0x00,0xDE,0xFF,0x1A,0xFF,0x90,0xFF, + 0x92,0xFF,0x4E,0x00,0x23,0x00,0xE0,0xFE,0xD0,0xFF,0xA9,0x01, + 0xF9,0xFF,0x32,0x00,0x52,0xFF,0x6E,0x00,0x58,0x00,0xB9,0xFF, + 0x1A,0xFF,0xD6,0x01,0xBD,0xFE,0x70,0xFE,0x35,0x03,0x44,0xFF, + 0xB4,0x00,0xB5,0xFF,0x4E,0xFF,0xC7,0xFF,0xDC,0xFF,0xB4,0xFE, + 0x72,0xFF,0x71,0x01,0x1B,0xFF,0x9E,0x00,0x16,0x00,0x08,0x00, + 0xFC,0x00,0x07,0x00,0xF0,0xFF,0x3E,0xFF,0xDF,0x00,0xCC,0xFF, + 0x0E,0x01,0xB0,0xFF,0xCE,0xFD,0xA7,0x00,0xE0,0xFF,0x7F,0x00, + 0xBA,0xFF,0xBE,0xFF,0xAC,0x00,0x3E,0x00,0xFF,0xFF,0x1F,0x00, + 0x98,0xFF,0xC3,0x00,0x04,0xFF,0x5D,0x00,0x24,0x00,0x16,0x00, + 0x09,0x00,0x91,0xFE,0x0B,0x02,0x4C,0xFE,0x25,0x00,0x5A,0xFF, + 0xE7,0xFF,0x9C,0x01,0x5A,0xFE,0xE0,0x00,0xE1,0x00,0x61,0xFF, + 0x41,0x01,0xBE,0xFF,0x23,0xFF,0xF1,0x01,0x25,0xFE,0x52,0x00, + 0x3A,0xFF,0x5B,0x00,0x94,0x01,0xE8,0xFD,0x52,0x00,0xF7,0xFE, + 0x0A,0x01,0x22,0x01,0x13,0xFF,0x80,0xFF,0xC4,0xFF,0x73,0x00, + 0x6C,0x00,0xB8,0xFF,0xA3,0xFF,0x19,0x00,0x9E,0x00,0x13,0x00, + 0x27,0x00,0x9B,0x00,0x23,0xFE,0xB0,0x00,0xF4,0x00,0x00,0xFF, + 0xAC,0xFF,0xD9,0x00,0xD9,0xFF,0xDB,0xFF,0x1C,0x02,0xDD,0xFC, + 0x32,0x00,0xA6,0x00,0x2A,0xFF,0x45,0x02,0xE4,0xFD,0x88,0xFF, + 0x0E,0x01,0x94,0x00,0xD9,0xFF,0xE4,0xFF,0x3E,0x01,0x51,0xFE, + 0xFD,0x00,0xB0,0xFF,0x8E,0xFE,0x6C,0x01,0x88,0xFF,0x58,0x00, + 0xCA,0xFF,0x61,0x00,0x86,0x00,0x40,0xFF,0x33,0xFE,0x3D,0x01, + 0x22,0x00,0xE4,0xFF,0xB7,0x01,0xFE,0xFE,0x42,0x01,0xE8,0xFE, + 0xB8,0x00,0x1C,0xFE,0x23,0xFF,0x9E,0x01,0xF1,0xFE,0x84,0x02, + 0x78,0xFE,0x17,0x00,0x90,0xFF,0x60,0x00,0x39,0x00,0x88,0xFD, + 0xD6,0x01,0x80,0x00,0x85,0xFF,0x61,0x00,0x92,0x00,0xEB,0xFF, + 0xA0,0xFF,0xFB,0x00,0x5A,0xFF,0xD7,0xFF,0x87,0x00,0x96,0xFE, + 0x92,0x01,0xF3,0xFE,0xF8,0xFE,0x98,0x01,0x91,0xFE,0x46,0xFF, + 0x64,0x01,0xE4,0xFF,0x71,0x00,0x13,0x01,0x62,0xFF,0x1D,0x00, + 0x28,0x00,0x16,0x00,0x5C,0xFF,0x29,0x00,0x33,0x00,0xD0,0xFF, + 0x58,0xFF,0x1C,0x01,0x00,0xFF,0x54,0xFE,0xDB,0x01,0x3B,0xFF, + 0x56,0x00,0x74,0xFF,0x22,0x00,0xF2,0x01,0xCE,0xFE,0x33,0xFF, + 0xFD,0x00,0xFA,0x00,0x10,0x00,0xE1,0xFF,0x73,0xFF,0xC1,0xFE, + 0xA3,0x00,0xC5,0x00,0x1D,0xFF,0x09,0x00,0x13,0x00,0xB3,0xFF, + 0xCC,0x00,0x08,0x00,0xF5,0xFE,0x11,0x00,0xD1,0x00,0xB5,0x00, + 0xDD,0xFF,0x6A,0xFF,0xE2,0xFF,0x13,0x00,0x2D,0x00,0x43,0x01, + 0xFF,0xFE,0x69,0xFE,0x67,0x01,0x60,0xFF,0x60,0x00,0xCB,0xFF, + 0xF4,0xFE,0x93,0x00,0xF1,0xFF,0xA4,0x00,0x16,0xFF,0x8C,0x00, + 0xA6,0x00,0xA5,0xFF,0x4A,0xFF,0x50,0x00,0x71,0x00,0xD3,0xFF, + 0x12,0x00,0x1A,0x00,0x47,0x00,0x96,0xFF,0x3C,0x01,0x50,0xFE, + 0x0E,0x01,0x09,0xFF,0xAF,0xFF,0x3A,0x01,0x42,0xFF,0xE0,0x02, + 0x28,0xFE,0x9F,0xFF,0x65,0x00,0xB1,0xFF,0xE1,0xFF,0x5E,0xFF, + 0xAE,0x00,0x39,0xFF,0xF0,0xFF,0x90,0x01,0xEF,0xFD,0x5A,0x00, + 0x15,0x01,0x87,0xFE,0x6E,0x01,0xE9,0xFE,0xD3,0x00,0xF0,0xFF, + 0xAD,0xFF,0x0F,0x02,0x51,0xFE,0xA0,0xFF,0x7B,0x00,0x6C,0xFF, + 0xF1,0xFF,0x79,0xFF,0x7E,0x00,0x3E,0x00,0x61,0x00,0x63,0x00, + 0x83,0xFF,0x88,0x00,0xD0,0xFF,0xF3,0xFE,0x3D,0x00,0x63,0x00, + 0x07,0x00,0x47,0x00,0x46,0x00,0xB8,0x00,0x74,0xFF,0x3A,0xFF, + 0x34,0x00,0x20,0xFF,0x43,0x00,0x46,0x00,0x2D,0xFF,0x07,0x01, + 0x32,0x00,0xB1,0xFE,0xD7,0x00,0x1D,0x01,0x99,0xFF,0x08,0x00, + 0x97,0xFF,0xB5,0x00,0x80,0xFF,0x16,0x00,0xFE,0xFF,0xBC,0xFE, + 0xE6,0x00,0xAF,0xFF,0x9C,0xFF,0x89,0x00,0xC8,0x00,0x95,0xFF, + 0x18,0x00,0xEE,0xFF,0x9D,0xFF,0x28,0x00,0xA4,0xFF,0x64,0x00, + 0x1A,0x00,0x08,0x00,0x0B,0x00,0xB0,0xFF,0x01,0x00,0xE2,0xFF, + 0x1B,0x00,0x22,0x00,0xD0,0xFF,0xB2,0xFF,0x67,0x01,0xFE,0xFF, + 0x2D,0xFF,0x55,0x00,0x81,0xFE,0xCA,0x00,0x65,0x00,0xD3,0xFF, + 0xD5,0x00,0x54,0xFF,0x58,0x00,0xAA,0xFF,0x00,0xFF,0x1B,0x01, + 0xD0,0xFF,0x10,0x00,0x84,0xFF,0x15,0x00,0xD9,0x00,0xD5,0xFE, + 0x2E,0x01,0x40,0xFF,0x16,0x00,0x61,0x00,0x67,0xFF,0xD5,0x00, + 0x73,0xFF,0x9F,0x00,0x08,0x00,0xBA,0xFF,0x64,0xFF,0x18,0x00, + 0x4A,0x01,0x7E,0xFE,0xD4,0xFF,0x66,0x00,0xB6,0xFE,0x27,0x01, + 0x7B,0x00,0xD3,0xFF,0x4B,0x00,0x08,0x00,0xEA,0xFF,0x6D,0x00, + 0xA7,0xFF,0xB2,0xFF,0x53,0x00,0xDC,0xFF,0x0D,0x00,0x92,0xFF, + 0x75,0x00,0xD3,0xFF,0x23,0x00,0x9E,0xFF,0x30,0x00,0x43,0xFF, + 0xEC,0x00,0xDD,0xFF,0x07,0x00,0xF8,0xFF,0xBA,0xFE,0x28,0x02, + 0x54,0xFE,0x24,0x01,0xC0,0xFF,0xE7,0xFF,0xB2,0x00,0x17,0xFF, + 0xAD,0x00,0xF9,0xFE,0xAB,0x00,0xC1,0xFF,0xDD,0xFF,0xFC,0xFF, + 0x1C,0x00,0xB7,0xFF,0x7B,0x00,0xDC,0xFF,0x5D,0x00,0x87,0x00, + 0xD2,0xFE,0x85,0x01,0x4B,0xFF,0xB4,0xFF,0xEF,0xFF,0x0F,0x00, + 0x97,0xFF,0x30,0xFF,0x98,0x01,0xE8,0xFE,0xA1,0xFF,0xF2,0x00, + 0xB7,0xFF,0x82,0x00,0xC5,0xFF,0xCD,0xFF,0x38,0x00,0xE1,0xFF, + 0x6A,0x01,0x19,0xFF,0x41,0xFF,0xB8,0x00,0x98,0xFF,0xCB,0x00, + 0x77,0xFF,0x9A,0xFF,0x04,0x00,0xBC,0xFF,0xD0,0x00,0x01,0xFF, + 0x20,0x00,0x15,0x01,0x9B,0xFF,0xCE,0xFF,0xE5,0xFF,0x03,0x00, + 0x5D,0x00,0xBF,0xFF,0xF7,0xFF,0xB2,0x00,0x8C,0xFE,0x07,0x01, + 0xD9,0x00,0x37,0xFF,0xB6,0x00,0x08,0xFE,0xB0,0x00,0x5D,0x00, + 0x05,0xFF,0xA9,0x00,0x63,0xFF,0x06,0x01,0x8F,0xFF,0xFE,0xFF, + 0xDA,0x00,0x23,0xFF,0x75,0x00,0x2D,0x00,0xED,0xFF,0xDC,0xFF, + 0xE1,0xFF,0x5B,0x00,0x02,0x00,0x51,0xFF,0x95,0x00,0x4C,0x00, + 0x14,0xFF,0xA6,0x00,0xCC,0xFE,0xCD,0xFF,0xFB,0x01,0xD2,0xFE, + 0xE2,0xFF,0xA0,0x00,0x29,0xFF,0xB9,0x00,0xA6,0xFF,0x16,0x01, + 0x24,0x00,0xBD,0xFE,0xF5,0x01,0x44,0xFE,0x68,0x00,0x1F,0x01, + 0x2A,0xFD,0x9A,0x01,0x11,0xFF,0x4D,0x00,0x99,0x00,0x04,0xFF, + 0x48,0x02,0x00,0xFE,0x14,0x00,0x9D,0x00,0x58,0xFF,0x28,0x01, + 0x81,0xFF,0x3A,0xFF,0xC0,0x01,0x99,0xFE,0x2E,0x00,0x84,0x00, + 0xD6,0xFD,0x7E,0x02,0x4F,0xFE,0x13,0x01,0x19,0x00,0x85,0xFE, + 0xFA,0x02,0xFD,0xFD,0x24,0x00,0xAB,0x00,0x64,0xFE,0xE4,0x01, + 0xCE,0xFE,0xE2,0xFF,0xBA,0x01,0xAF,0xFD,0xEE,0x00,0x21,0x00, + 0xCE,0xFF,0x39,0x01,0xD9,0xFE,0xA1,0x00,0xCB,0xFF,0xC5,0xFE, + 0xE0,0x01,0xCD,0xFE,0x85,0xFF,0xE6,0x01,0x27,0xFE,0x3D,0x01, + 0x9E,0xFF,0x09,0xFF,0x6F,0x01,0x08,0xFE,0xAB,0x01,0x9B,0xFF, + 0x07,0xFF,0xC8,0x02,0xE0,0xFD,0x44,0x01,0xBF,0xFF,0x67,0xFE, + 0xDA,0x01,0x99,0xFE,0x73,0x00,0x4B,0x00,0x78,0xFF,0x63,0x00, + 0xF1,0xFF,0x17,0x00,0xF6,0xFF,0x53,0xFF,0x43,0x01,0x81,0xFF, + 0x54,0xFF,0x2A,0x01,0x11,0xFF,0x5F,0x00,0x1B,0x00,0xEA,0xFF, + 0x71,0x00,0x5C,0xFF,0xFB,0x00,0x25,0xFF,0x53,0xFF,0x20,0x01, + 0xC2,0xFE,0x51,0x01,0x5A,0xFF,0xBE,0xFF,0x81,0x00,0xFB,0xFE, + 0xEE,0x00,0xDE,0xFF,0xE5,0xFF,0x23,0x00,0x03,0x00,0x17,0x00, + 0x1F,0x00,0xD9,0xFF,0x49,0x00,0xD2,0xFF,0xC8,0xFF,0x1A,0x00, + 0xE4,0xFF,0x42,0x00,0xE1,0xFF,0x46,0x00,0x3D,0xFF,0xD5,0xFF, + 0xC8,0x00,0xDC,0xFF,0x8C,0x00,0xAC,0xFF,0x0E,0xFF,0xFC,0x00, + 0x56,0x00,0xCC,0xFE,0xA4,0x00,0x95,0xFF,0x47,0x00,0x49,0x00, + 0x4A,0xFF,0xC0,0x00,0x5A,0xFF,0x6B,0x00,0x4A,0x00,0x00,0xFF, + 0x55,0x00,0x9A,0x00,0xF2,0xFF,0x2B,0x00,0x25,0x00,0xCB,0xFF, + 0xE4,0xFF,0x68,0x00,0x77,0xFF,0x0B,0x00,0xA0,0xFF,0x4D,0xFF, + 0xEC,0x00,0xCD,0xFF,0x57,0x00,0x8E,0xFF,0x73,0x00,0x08,0x00, + 0x98,0xFF,0x0C,0x01,0xB1,0xFF,0xC3,0xFF,0x9B,0xFF,0x4E,0x00, + 0x0F,0x00,0x17,0x00,0x51,0x00,0xF7,0xFE,0xE5,0xFF,0x86,0x00, + 0xE6,0xFF,0xFD,0xFF,0xAE,0xFF,0xD5,0xFF,0x8E,0x00,0x98,0x00, + 0xDE,0xFF,0xD0,0xFF,0x35,0x00,0x36,0x00,0xA8,0xFF,0xF8,0xFF, + 0xDD,0xFF,0x9A,0xFF,0x71,0x00,0xC5,0xFF,0xE7,0xFF,0x71,0x00, + 0x6D,0xFF,0xA7,0xFF,0xDB,0x00,0xA3,0xFF,0x2B,0x00,0x2E,0x00, + 0x92,0xFF,0x04,0x00,0x11,0x00,0x14,0x01,0x8D,0xFF,0xFC,0xFE, + 0xC4,0x00,0xFB,0xFF,0x65,0x00,0xD8,0xFF,0xAE,0xFE,0xE9,0x00, + 0x8D,0xFF,0x7F,0x00,0xF1,0xFF,0xA6,0xFF,0xC7,0x00,0x84,0xFF, + 0x3A,0x00,0xE2,0xFF,0xE8,0xFF,0xD9,0xFF,0xDA,0xFF,0x7D,0x00, + 0x6A,0x00,0x5C,0xFF,0x52,0x00,0xFC,0xFF,0xEC,0xFF,0x3C,0x00, + 0x87,0xFF,0xE8,0xFF,0x1F,0x00,0xD4,0xFF,0x4B,0x00,0x01,0x00, + 0xD3,0xFF,0xB3,0xFF,0x1B,0x00,0x1B,0x01,0xBC,0xFE,0xDC,0x00, + 0x3D,0x00,0xB6,0xFE,0x25,0x01,0x2E,0xFF,0x19,0x00,0x5C,0x00, + 0xBF,0xFF,0xA8,0x00,0x26,0xFF,0xAB,0x00,0xE8,0xFF,0x73,0xFF, + 0xB9,0x00,0x79,0xFF,0xD3,0xFF,0x1F,0x00,0x0B,0x00,0x41,0x00, + 0xBA,0xFF,0x36,0x00,0x0E,0x00,0xA1,0xFF,0xF9,0x00,0xF1,0xFE, + 0x13,0x00,0xF8,0x00,0x2F,0xFF,0x44,0x00,0x13,0x00,0xE8,0xFF, + 0xD4,0xFF,0xEC,0xFF,0xAE,0x00,0xFB,0xFE,0x14,0x00,0x2E,0x01, + 0xD7,0xFE,0xA0,0x00,0x32,0x00,0x3E,0xFF,0x45,0x00,0x50,0x00, + 0xDB,0xFF,0x81,0xFF,0xD4,0x00,0xD1,0xFF,0x58,0xFF,0x29,0x00, + 0x16,0x00,0x01,0x00,0xB8,0xFF,0xDD,0x00,0xA8,0xFF,0xA2,0xFF, + 0x5C,0x00,0xD7,0xFF,0x1A,0x00,0xF8,0xFF,0x19,0x00,0x6E,0xFF, + 0x63,0x00,0x2C,0x00,0xC7,0xFF,0x2B,0x00,0x80,0x00,0x74,0xFF, + 0xB8,0xFF,0xD0,0x00,0x26,0xFF,0x38,0x00,0x78,0x00,0x4E,0xFF, + 0xAC,0x00,0x03,0x00,0x46,0xFF,0x2C,0x00,0xDC,0xFF,0xC5,0x00, + 0x1B,0x00,0x37,0xFF,0xF4,0xFF,0x75,0x00,0x29,0x00,0x0C,0x00, + 0xB8,0xFF,0x27,0x00,0xA5,0xFF,0x86,0xFF,0x50,0x01,0x1F,0xFF, + 0xC1,0xFF,0xE0,0x00,0x14,0xFF,0x4D,0x00,0x25,0x00,0xFF,0xFF, + 0x12,0x00,0xF9,0xFF,0x9C,0x00,0xFA,0xFE,0x24,0x00,0xAD,0x00, + 0xD6,0xFF,0x3B,0x00,0x03,0x00,0x2E,0xFF,0x2C,0x00,0x0D,0x00, + 0xFD,0xFF,0x13,0x00,0x70,0xFF,0xEB,0x00,0x7A,0xFF,0x31,0x00, + 0xF4,0xFF,0x5A,0xFF,0xCD,0x00,0xCF,0xFF,0xAB,0xFF,0x97,0x00, + 0x57,0x00,0x8E,0xFF,0x1A,0x00,0x2B,0x00,0x9D,0xFF,0x32,0x00, + 0xF7,0xFF,0xB2,0xFF,0x87,0x00,0x8F,0xFF,0xF4,0xFF,0x5A,0x00, + 0x87,0xFF,0xAE,0x00,0xE6,0xFF,0x7B,0xFF,0x6A,0x00,0xCA,0xFF, + 0xB3,0xFF,0x68,0x00,0x6D,0x00,0xAD,0xFF,0xFA,0xFF,0x00,0x00, + 0xBF,0xFF,0x23,0x00,0x64,0x00,0x78,0xFF,0x85,0xFF,0x82,0x00, + 0xE5,0xFF,0x1D,0x00,0x4F,0x00,0xB3,0xFF,0x88,0xFF,0xBB,0x00, + 0x34,0x00,0xA1,0xFF,0xD6,0xFF,0x1B,0x00,0xFA,0xFF,0x13,0x00, + 0x4F,0x00,0x7C,0xFF,0x62,0x00,0xE0,0xFF,0xE3,0xFF,0x61,0x00, + 0x83,0xFF,0xCB,0xFF,0x06,0x01,0x89,0xFF,0x48,0xFF,0x9B,0x00, + 0x28,0x00,0xBA,0xFF,0xEA,0xFF,0x58,0x00,0xD0,0xFF,0xFA,0xFF, + 0xEF,0xFF,0xAC,0xFF,0x54,0x00,0x65,0x00,0xC6,0xFF,0xD4,0xFF, + 0xA0,0xFF,0x6C,0x00,0x75,0x00,0x80,0xFF,0x51,0x00,0x20,0x00, + 0x80,0xFF,0x64,0x00,0x1E,0x00,0x5B,0xFF,0xF7,0xFF,0x5E,0x00, + 0x76,0xFF,0x78,0x00,0x12,0x00,0xE7,0xFF,0xF7,0xFF,0xF6,0xFF, + 0xC6,0x00,0x65,0xFF,0xA8,0x00,0xC2,0xFE,0x96,0x00,0x89,0x00, + 0xFB,0xFE,0xAF,0x00,0x2A,0xFF,0xB6,0x00,0xEA,0xFF,0xA7,0xFF, + 0x84,0x00,0xAF,0xFF,0x22,0x00,0xCF,0xFF,0x37,0x00,0x28,0x00, + 0xCD,0xFF,0xAE,0x00,0x65,0xFF,0xF4,0xFF,0x71,0x00,0xAC,0xFF, + 0xC1,0xFF,0xC2,0xFF,0x0F,0x00,0x1B,0x00,0x26,0x00,0xFD,0xFF, + 0x02,0x00,0xF9,0xFF,0x97,0x00,0xB3,0xFF,0x65,0xFF,0x79,0x00, + 0xD7,0xFF,0x3A,0x00,0xF3,0xFF,0x92,0xFF,0x50,0x00,0x61,0xFF, + 0x84,0x00,0xCD,0x00,0x28,0xFF,0x88,0x00,0xDF,0xFF,0x6B,0xFF, + 0xBC,0x00,0x2B,0xFF,0x55,0x00,0x96,0x00,0x57,0xFF,0x50,0x00, + 0xD3,0xFF,0x18,0x00,0xC2,0xFF,0x5C,0x00,0x1C,0x00,0x71,0xFF, + 0x40,0x00,0x35,0x00,0xF7,0xFF,0x3C,0x00,0x4F,0x00,0x5E,0xFF, + 0x42,0x00,0xB7,0xFF,0xDF,0xFF,0x5D,0x00,0x6F,0xFF,0x20,0x00, + 0x52,0x00,0x5B,0xFF,0x18,0x00,0x67,0x00,0x56,0x00,0xBC,0xFF, + 0x08,0x00,0xB7,0x00,0xCC,0xFE,0x45,0x00,0xAD,0x00,0x51,0xFF, + 0xF0,0xFF,0x1F,0x00,0x22,0x00,0x0D,0x00,0x2E,0x00,0xBC,0xFF, + 0x1D,0x00,0xFB,0xFF,0x6F,0xFF,0xC6,0x00,0xB9,0xFF,0x35,0x00, + 0xB4,0xFF,0x1D,0x00,0x71,0x00,0x21,0xFF,0x30,0x00,0x00,0x00, + 0x54,0x00,0x7B,0xFF,0x9B,0x00,0x02,0x00,0x9D,0xFF,0x38,0x00, + 0xBD,0xFF,0x4C,0x00,0x0D,0x00,0xFB,0xFF,0xB3,0xFF,0x2D,0x00, + 0x20,0x00,0xD0,0xFF,0x28,0x00,0x68,0x00,0x99,0xFF,0x0D,0x00, + 0x01,0x00,0x70,0xFF,0xA3,0x00,0xAC,0xFF,0x25,0x00,0x4E,0x00, + 0x2F,0xFF,0xD2,0x00,0x6B,0xFF,0x1B,0x00,0x22,0x00,0x86,0xFF, + 0xB0,0x00,0xB5,0xFF,0xDA,0xFF,0x6E,0x00,0x96,0x00,0x42,0xFF, + 0xA8,0xFF,0xB7,0x00,0x7D,0xFF,0xFF,0xFF,0x30,0x00,0xD4,0xFF, + 0x6E,0x00,0x3B,0xFF,0x6C,0x00,0x74,0xFF,0x2B,0x00,0xCC,0x00, + 0x35,0xFF,0x7F,0x00,0xA9,0xFF,0x61,0x00,0xF9,0xFF,0x1B,0x00, + 0xA7,0x00,0x41,0xFF,0xC4,0xFF,0x8F,0x00,0x89,0xFF,0x6D,0xFF, + 0xC4,0x00,0x86,0xFF,0x1B,0x00,0x2E,0x00,0x7A,0x00,0xDB,0xFF, + 0x85,0xFF,0x2C,0x00,0x84,0xFF,0x1D,0x01,0x62,0xFF,0xE4,0xFF, + 0x29,0x00,0xB2,0xFF,0x9B,0x00,0x1F,0x00,0xD7,0xFF,0x1C,0xFF, + 0x69,0x00,0x7F,0x00,0x7F,0xFF,0x33,0x00,0xDF,0xFF,0xD3,0xFF, + 0x20,0x00,0x19,0x00,0x3F,0x00,0xAE,0xFF,0xCE,0xFF,0x24,0x00, + 0x12,0x00,0x27,0x00,0x25,0x00,0xDE,0xFF,0x94,0xFF,0x50,0x00, + 0x46,0x00,0x02,0x00,0x90,0xFF,0x14,0x00,0x8C,0x00,0x80,0xFF, + 0x41,0x00,0xB3,0xFF,0x34,0x00,0x82,0x00,0x8F,0xFF,0x0E,0x00, + 0xCD,0xFF,0x8A,0xFF,0x8F,0x00,0x8F,0xFF,0x35,0x00,0x44,0x00, + 0xE7,0xFF,0x30,0x00,0x92,0xFF,0x8E,0x00,0xE4,0xFF,0xB6,0xFF, + 0xE5,0xFF,0x52,0x00,0x72,0xFF,0x73,0x00,0x24,0x00,0x55,0xFF, + 0xAC,0x00,0x11,0x00,0x9B,0xFF,0x53,0x00,0x91,0xFF,0x39,0x00, + 0xCF,0x00,0xF2,0xFE,0x2D,0x00,0x84,0xFF,0x13,0x00,0x21,0x01, + 0x4C,0xFF,0x28,0x00,0x30,0x00,0x59,0xFF,0x96,0x00,0xDD,0xFF, + 0xEA,0xFF,0xC1,0x00,0xD6,0xFE,0x08,0x00,0x0F,0x01,0x60,0xFF, + 0x74,0x00,0x45,0xFF,0xC8,0xFF,0x6A,0x00,0x5A,0xFF,0xE3,0x00, + 0xD0,0xFF,0xAE,0xFF,0x7B,0x00,0xF9,0xFF,0xDB,0xFF,0x86,0x00, + 0x7F,0xFF,0xC4,0xFF,0xB1,0x00,0xDA,0xFF,0x90,0xFF,0xD5,0xFF, + 0x3F,0x00,0x38,0x00,0xD7,0xFF,0xCE,0xFF,0x15,0x00,0xFB,0xFF, + 0xE8,0xFF,0x2E,0x00,0x27,0x00,0xF5,0xFF,0x03,0x00,0xBB,0xFF, + 0x89,0x00,0x9A,0xFF,0xA0,0xFF,0xD6,0x00,0x83,0xFF,0xE8,0xFF, + 0x62,0x00,0x96,0xFF,0xA9,0x00,0x47,0xFF,0xF3,0xFF,0xCC,0x00, + 0x89,0xFF,0x6F,0x00,0x8A,0xFF,0x0C,0x00,0xF7,0xFF,0xED,0xFF, + 0x2E,0x00,0xEE,0xFF,0x8D,0xFF,0x4F,0x00,0x4D,0x00,0xD7,0xFF, + 0x9E,0x00,0x87,0xFF,0xB5,0xFF,0x24,0x00,0xA5,0xFF,0x5B,0x00, + 0x89,0x00,0xA5,0xFF,0xEA,0xFF,0x91,0xFF,0x9A,0x00,0x96,0xFF, + 0xE5,0xFF,0x5A,0x00,0x4D,0xFF,0x79,0x00,0xE2,0xFF,0x25,0x00, + 0xE2,0xFF,0x88,0x00,0x0F,0x00,0x50,0xFF,0x31,0x00,0x35,0x00, + 0xF7,0xFF,0x1D,0x00,0x15,0x00,0xCC,0xFF,0x92,0x00,0x22,0xFF, + 0xAB,0xFF,0x16,0x01,0xF3,0xFE,0x45,0x00,0x99,0x00,0x55,0xFF, + 0x4D,0x00,0xE3,0xFF,0x2F,0x00,0x4E,0x00,0xAD,0xFF,0x1B,0x00, + 0xF1,0xFF,0xB3,0xFF,0x63,0x00,0xD6,0xFF,0x37,0x00,0x4E,0x00, + 0x00,0xFF,0xA0,0x01,0xE5,0x00,0xB4,0xFE,0x97,0x00,0x61,0xFF, + 0x96,0xFE,0xCB,0xFF,0xCA,0xFF,0x50,0x00,0xFA,0xFF,0xE1,0xFF, + 0xA0,0x00,0xEF,0xFE,0xF7,0xFF,0x3C,0x01,0x40,0x00,0x25,0x00, + 0x98,0x00,0xCB,0xFF,0xA1,0xFF,0x31,0x00,0x84,0xFF,0xF7,0xFF, + 0x9E,0xFF,0x0C,0x00,0xEA,0xFF,0x51,0x00,0x91,0x00,0xC1,0xFF, + 0x73,0x00,0x3D,0x00,0xA6,0xFF,0x1F,0x00,0xA9,0x00,0x80,0x00, + 0xBB,0xFF,0xCB,0xFF,0x50,0x00,0x33,0xFF,0x2B,0xFF,0x0A,0x00, + 0xFB,0xFF,0x55,0xFF,0x25,0x00,0x7F,0x00,0x82,0xFF,0x50,0x00, + 0x88,0x00,0xC6,0xFF,0x99,0xFF,0x2C,0x00,0xCA,0xFF,0x97,0xFF, + 0x9D,0x00,0x23,0x00,0x61,0xFF,0xC6,0xFF,0xD9,0xFF,0x33,0x00, + 0x53,0x00,0xAF,0xFF,0x30,0x00,0xDD,0xFF,0x22,0x00,0x87,0x00, + 0xC0,0xFF,0x2D,0x00,0x14,0x00,0xF7,0xFF,0x7A,0x00,0x5C,0x00, + 0xBF,0xFF,0x0E,0x00,0x57,0x00,0xE5,0xFF,0xC7,0xFF,0xEB,0xFF, + 0x77,0x00,0xD6,0xFF,0xEA,0xFF,0x92,0x00,0x44,0xFF,0x06,0x00, + 0x42,0x00,0x57,0xFF,0x2D,0x00,0x21,0x00,0x13,0x00,0xB5,0xFF, + 0xFA,0xFF,0x37,0x00,0xB3,0xFF,0xD9,0xFF,0x11,0x00,0xDD,0xFF, + 0x13,0x00,0x3A,0x00,0x99,0xFF,0x2E,0x00,0x25,0x00,0x00,0x00, + 0x38,0x00,0x70,0xFF,0xFC,0xFF,0x69,0x00,0xA6,0xFF,0x39,0x00, + 0xC2,0xFF,0x98,0xFF,0x71,0x00,0xDC,0xFF,0x26,0x00,0x2B,0x00, + 0xEF,0xFF,0x49,0x00,0xD1,0xFF,0xFA,0xFF,0x5D,0x00,0xBE,0xFF, + 0x72,0x00,0xE6,0xFF,0x6C,0xFF,0x4D,0x00,0x92,0xFF,0x29,0x00, + 0x29,0x00,0x2B,0x00,0xFA,0xFF,0x81,0xFF,0x5C,0x00,0x12,0x00, + 0xBC,0xFF,0x33,0x00,0x2A,0x00,0x9A,0xFF,0x50,0x00,0x10,0x00, + 0xC6,0xFF,0x2E,0x00,0xFB,0xFF,0x1D,0x00,0xCA,0xFF,0xB8,0xFF, + 0x33,0x00,0x36,0x00,0xE6,0xFF,0x32,0x00,0xF5,0xFF,0xC8,0xFF, + 0x03,0x00,0x07,0x00,0xF1,0xFF,0x0C,0x00,0x14,0x00,0x0E,0x00, + 0xFA,0xFF,0xE2,0xFF,0x1A,0x00,0xDB,0xFF,0x61,0x00,0xC0,0xFF, + 0xBE,0xFF,0x60,0x00,0xCF,0xFF,0x32,0x00,0x07,0x00,0x19,0x00, + 0x09,0x00,0xA9,0xFF,0x10,0x00,0x23,0x00,0xF6,0xFF,0xE9,0xFF, + 0xF3,0xFF,0x23,0x00,0xF6,0xFF,0xE1,0xFF,0x22,0x00,0xE0,0xFF, + 0x05,0x00,0x26,0x00,0xD7,0xFF,0x0E,0x00,0x2D,0x00,0xF9,0xFF, + 0xFA,0xFF,0xCE,0xFF,0x1A,0x00,0x3E,0x00,0xD8,0xFF,0xF8,0xFF, + 0xF9,0xFF,0xDF,0xFF,0xD2,0xFF,0x2E,0x00,0xE0,0xFF,0xDC,0xFF, + 0x17,0x00,0xFE,0xFF,0x0E,0x00,0xDD,0xFF,0x2A,0x00,0x11,0x00, + 0xF8,0xFF,0x10,0x00,0xF6,0xFF,0x01,0x00,0x02,0x00,0x08,0x00, + 0x25,0x00,0xCC,0xFF,0xDB,0xFF,0x00,0x00,0x10,0x00,0x22,0x00, + 0xE6,0xFF,0xF3,0xFF,0xFC,0xFF,0x01,0x00,0x1B,0x00,0x04,0x00, + 0xB7,0xFF,0x45,0x00,0x22,0x00,0xC3,0xFF,0xFB,0xFF,0x21,0x00, + 0x0E,0x00,0xCC,0xFF,0x30,0x00,0x20,0x00,0xE3,0xFF,0xF2,0xFF, + 0x2A,0x00,0xEB,0xFF,0xFC,0xFF,0x39,0x00,0xE7,0xFF,0xF5,0xFF, + 0xF7,0xFF,0x48,0x00,0xFA,0xFF,0xA1,0xFF,0x18,0x00,0x18,0x00, + 0xF1,0xFF,0xF6,0xFF,0x1A,0x00,0x11,0x00,0xDC,0xFF,0x0D,0x00, + 0x21,0x00,0xDD,0xFF,0x03,0x00,0x35,0x00,0xFE,0xFF,0xD2,0xFF, + 0x13,0x00,0xFA,0xFF,0xC9,0xFF,0x07,0x00,0x1E,0x00,0x07,0x00, + 0x95,0xFF,0xDF,0xFF,0x3D,0x00,0xF4,0xFF,0x0A,0x00,0x29,0x00, + 0xDF,0xFF,0xE2,0xFF,0x35,0x00,0x2C,0x00,0xE2,0xFF,0x03,0x00, + 0x50,0x00,0xD8,0xFF,0xDA,0xFF,0xFF,0xFF,0x0B,0x00,0x15,0x00, + 0xF7,0xFF,0x0E,0x00,0xCE,0xFF,0xEF,0xFF,0x30,0x00,0x16,0x00, + 0xFD,0xFF,0xFD,0xFF,0xF0,0xFF,0xF3,0xFF,0xFF,0xFF,0x25,0x00, + 0x06,0x00,0xC7,0xFF,0x00,0x00,0xED,0xFF,0xD5,0xFF,0x10,0x00, + 0x20,0x00,0xF3,0xFF,0xF8,0xFF,0x0D,0x00,0xED,0xFF,0xFC,0xFF, + 0x07,0x00,0x04,0x00,0x01,0x00,0xFB,0xFF,0x06,0x00,0xEC,0xFF, + 0xDC,0xFF,0x11,0x00,0x23,0x00,0x09,0x00,0xF8,0xFF,0xF5,0xFF, + 0x03,0x00,0x07,0x00,0x1A,0x00,0x25,0x00,0x21,0x00,0x08,0x00, + 0xEE,0xFF,0x04,0x00,0x12,0x00,0xF3,0xFF,0xF9,0xFF,0x0A,0x00, + 0xF1,0xFF,0xE6,0xFF,0xF3,0xFF,0xF7,0xFF,0xF4,0xFF,0x06,0x00, + 0x22,0x00,0x30,0x00,0x0E,0x00,0xE1,0xFF,0xEE,0xFF,0xFD,0xFF, + 0xF1,0xFF,0xF8,0xFF,0x07,0x00,0x0E,0x00,0xEC,0xFF,0xD4,0xFF, + 0x08,0x00,0x1E,0x00,0x0A,0x00,0x04,0x00,0x05,0x00,0xF4,0xFF, + 0xEA,0xFF,0x04,0x00,0x09,0x00,0x09,0x00,0xEF,0xFF,0xDF,0xFF, + 0xE5,0xFF,0xFA,0xFF,0x10,0x00,0x17,0x00,0x11,0x00,0xFC,0xFF, + 0x01,0x00,0x08,0x00,0x24,0x00,0x1A,0x00,0xF7,0xFF,0xFE,0xFF, + 0xF6,0xFF,0xF7,0xFF,0xFB,0xFF,0xF9,0xFF,0x09,0x00,0xFD,0xFF, + 0xF2,0xFF,0xF6,0xFF,0x00,0x00,0x0C,0x00,0x01,0x00,0xEC,0xFF, + 0x03,0x00,0x1E,0x00,0x17,0x00,0x0C,0x00,0x03,0x00,0xEF,0xFF, + 0xDB,0xFF,0xED,0xFF,0xFD,0xFF,0xF6,0xFF,0x06,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00,0x02,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFE,0xFF,0xFE,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0xFE,0xFF,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF, + 0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x01,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00, + 0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0xFE,0xFF, + 0x01,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFE,0xFF,0x00,0x00,0x02,0x00, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0xFD,0xFF,0x02,0x00,0x01,0x00,0x01,0x00,0x02,0x00, + 0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFD,0xFF, + 0x00,0x00,0x00,0x00,0xFD,0xFF,0x01,0x00,0xFE,0xFF,0x03,0x00, + 0xFD,0xFF,0xF7,0xFF,0x12,0x00,0xFC,0xFF,0xFC,0xFF,0x08,0x00, + 0xFB,0xFF,0x04,0x00,0xFC,0xFF,0x02,0x00,0x00,0x00,0xFD,0xFF, + 0x00,0x00,0xFF,0xFF,0xFE,0xFF,0xFD,0xFF,0x01,0x00,0xFF,0xFF, + 0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0x01,0x00,0x02,0x00,0x00,0x00, + 0x04,0x00,0xFC,0xFF,0x06,0x00,0xFB,0xFF,0x06,0x00,0xFC,0xFF, + 0x04,0x00,0x00,0x00,0xF9,0xFF,0x14,0x00,0xEC,0xFF,0x15,0x00, + 0xEA,0xFF,0x12,0x00,0xF6,0xFF,0x14,0x00,0xDD,0xFF,0x2D,0x00, + 0xD7,0xFF,0x51,0x00,0xA8,0xFF,0x47,0x00,0x8C,0xFF,0xB7,0xFF, + 0x3F,0x05,0xAE,0xFB,0x41,0xFF,0x17,0x01,0x6F,0xFC,0x1E,0x03, + 0xB0,0xFD,0x74,0x01,0x5A,0x00,0xB1,0xFE,0x97,0x01,0x8B,0xFE, + 0xB1,0x01,0xBC,0xFE,0xCB,0x01,0x94,0x01,0xCB,0xFC,0x5A,0x02, + 0x95,0xFE,0x01,0x00,0xF0,0xFF,0x2E,0xFF,0xED,0x01,0x8E,0xFE, + 0xB1,0x00,0x9B,0xFF,0x52,0x00,0xCF,0xFF,0x4C,0x00,0xF4,0xFE, + 0xD2,0x01,0xC8,0x01,0x3D,0xFC,0x51,0x01,0x5F,0xFE,0x42,0xFF, + 0xE8,0x00,0x4F,0xFE,0xBD,0x01,0xCD,0xFF,0x6F,0x00,0xEF,0x00, + 0xC3,0xFE,0x50,0x02,0x71,0xFE,0x37,0x02,0x50,0xFF,0x92,0xFF, + 0x63,0x01,0x7A,0xFD,0x71,0x02,0xB0,0xFC,0xEA,0x01,0x6E,0xFE, + 0x66,0x01,0x27,0xFE,0x50,0x00,0xDF,0x01,0x6B,0xFC,0x59,0x04, + 0x61,0xFB,0xE0,0x03,0xCE,0xFD,0xB1,0x00,0x98,0x00,0xB9,0xFE, + 0x36,0x03,0xB9,0xFB,0x5A,0x03,0x9F,0xFE,0x8D,0x00,0xFB,0xFF, + 0x9F,0xFF,0xA7,0x00,0xD7,0xFE,0x42,0x01,0xDF,0xFE,0xEB,0xFF, + 0x39,0x01,0x65,0xFE,0x33,0x01,0x66,0x00,0xA9,0xFE,0x9D,0x01, + 0xE0,0xFF,0x69,0x00,0x51,0xFD,0xDB,0x01,0x5A,0x00,0xE9,0xFE, + 0xAD,0x01,0x48,0xFC,0xB3,0x03,0xDA,0xFD,0xBB,0x00,0x9C,0x00, + 0xB8,0xFC,0xF1,0x05,0x3A,0xFA,0xFF,0x05,0xD1,0xFB,0x1E,0x00, + 0xD8,0x03,0xE3,0xF9,0xD2,0x06,0xC4,0xF8,0x52,0x05,0x80,0xFC, + 0x00,0x03,0x4F,0xFD,0x87,0xFE,0x93,0x06,0x0A,0xF8,0xD9,0x07, + 0x2C,0xF8,0xC9,0x06,0x1B,0xFD,0x82,0x00,0x99,0x01,0x97,0xFA, + 0x54,0x07,0x57,0xFB,0x9C,0x05,0x4B,0xFA,0x77,0x00,0xE5,0x01, + 0x4F,0xFE,0x1A,0xFB,0x60,0x02,0x50,0x01,0x96,0xFF,0x90,0x00, + 0x74,0xFD,0x8F,0x06,0x98,0xFC,0xB8,0x04,0x29,0xF9,0x18,0x06, + 0x6E,0xFF,0x2D,0xFE,0x27,0x02,0x8A,0xFA,0x98,0x05,0xB9,0xFC, + 0xE5,0x00,0xA5,0xFC,0xAC,0x03,0x38,0xFF,0xD2,0xFE,0xB4,0x00, + 0xB8,0xFD,0x56,0x03,0x1F,0x00,0xBA,0xFC,0xBA,0x01,0x2D,0x02, + 0xD3,0xFD,0xAC,0x00,0x78,0x00,0x9A,0xFD,0x68,0x02,0xB3,0x02, + 0x71,0xFB,0xBE,0xFE,0x2A,0x05,0x13,0xFE,0x50,0xFD,0x50,0x01, + 0x28,0xFE,0x81,0x04,0x06,0xFD,0x5C,0x02,0xA1,0xFB,0x91,0x03, + 0xF6,0x03,0x98,0xF6,0x5C,0x06,0xAC,0xFE,0x7F,0x00,0x24,0xFD, + 0x87,0x01,0xF3,0xFF,0xFC,0xFE,0x8D,0x06,0xBD,0xF9,0x36,0x01, + 0xF3,0x02,0x81,0xFE,0xB8,0xFE,0x2C,0xFF,0xEE,0x02,0x2C,0xFD, + 0xEC,0x01,0xC4,0xFD,0x9C,0xFE,0x4D,0x04,0xA9,0xFE,0x5C,0x00, + 0x65,0xFD,0xFF,0x02,0xEF,0xFF,0x3E,0xFE,0x6F,0x00,0x40,0xFE, + 0x4F,0x03,0xC0,0x00,0xC5,0xFC,0x6F,0x01,0x42,0xFF,0xB3,0x01, + 0x7D,0xFF,0x41,0xFD,0x03,0x03,0x4B,0xFC,0x0B,0x05,0x7D,0xFE, + 0x2D,0xFD,0x18,0x03,0x31,0xFE,0x02,0x02,0x26,0xFE,0x6F,0xFE, + 0x93,0x02,0xA6,0x00,0x2D,0xFE,0x2B,0x01,0x44,0xFD,0xC2,0x02, + 0x8D,0x00,0xB2,0xFB,0xF8,0x02,0xE7,0x00,0x44,0xFE,0xAD,0xFE, + 0x3D,0x02,0x0F,0x01,0xB7,0xFD,0x10,0x03,0x9F,0xFE,0x31,0xFD, + 0x67,0x07,0xD5,0xFA,0x71,0xFE,0xDC,0x02,0xC1,0xFF,0x45,0xFF, + 0x16,0xFD,0xEB,0x05,0x56,0xFA,0xFF,0x01,0xA7,0x04,0xC9,0xF6, + 0x9E,0x03,0xA2,0x03,0x5B,0xFE,0x77,0xFE,0x55,0x02,0x9C,0x02, + 0x50,0xFA,0xB4,0x06,0xB6,0xFD,0x9D,0xFA,0x83,0x08,0xDA,0xFB, + 0x0D,0xFE,0x98,0xFF,0x32,0x00,0x65,0xFF,0xBF,0xFD,0x93,0x03, + 0xA8,0xFB,0x53,0x01,0x88,0x03,0xD4,0xFC,0x84,0x02,0x58,0x00, + 0xAA,0x00,0xAD,0x02,0x9A,0xFE,0x23,0x02,0xC7,0xFC,0x49,0x00, + 0x28,0x03,0x2E,0xF9,0xAB,0x02,0x05,0x00,0x40,0xFE,0x3C,0x01, + 0xB7,0xFE,0xDF,0x00,0xB8,0xFB,0x94,0x05,0x27,0xFE,0x75,0xFE, + 0x72,0x06,0x30,0xF9,0x23,0x03,0x77,0xFF,0xA2,0xFF,0x43,0x01, + 0xC5,0xFD,0x48,0x03,0x42,0xFD,0xD1,0x02,0x0C,0x00,0x33,0xFD, + 0xBA,0xFF,0xEA,0x01,0xDA,0xFF,0x19,0xFB,0x5D,0x02,0x7E,0x06, + 0x3D,0xFC,0xD2,0xFB,0xE2,0x05,0xAD,0xFD,0x5E,0x05,0x1C,0xFC, + 0xDB,0xF9,0x85,0x07,0xDE,0xFF,0x3F,0xFE,0x67,0xF9,0x2E,0x04, + 0x59,0x04,0xE9,0xFA,0x3E,0xFF,0x16,0x03,0x9F,0x00,0x09,0x00, + 0x4B,0xFF,0xAD,0xFD,0x1C,0x04,0x14,0x02,0xDA,0xFC,0x18,0xFF, + 0xD7,0x01,0x9C,0x00,0x88,0xFE,0x5C,0x01,0x8E,0xFE,0x98,0xFD, + 0x19,0x04,0x27,0xFB,0x09,0xFF,0x17,0x05,0x19,0xFF,0xBC,0xF9, + 0x46,0x00,0x4A,0x09,0x2C,0xFD,0xDE,0xFD,0xE1,0x00,0xE4,0x00, + 0xF2,0x01,0x05,0x01,0xB8,0xFB,0xFF,0xFB,0x70,0x07,0x44,0x01, + 0x16,0xFA,0x37,0xFE,0x02,0x05,0xD5,0x00,0x68,0xFC,0xA0,0xFE, + 0xFF,0xFF,0xD1,0x02,0x6B,0x00,0x27,0xFE,0x13,0xFC,0x08,0x03, + 0x52,0x05,0x9D,0xFF,0x06,0xFB,0x1E,0x00,0x03,0x06,0xAB,0xFF, + 0x7B,0xFF,0x4E,0xFB,0x20,0x00,0xEC,0x03,0x6E,0x01,0x2D,0xFB, + 0x2E,0xFB,0x18,0x05,0xF0,0x00,0x7D,0xFE,0xF5,0xFC,0x5D,0x00, + 0xC7,0x03,0xD8,0x02,0xDB,0xFD,0xB3,0xFD,0xCA,0x03,0x89,0x02, + 0x9C,0xFE,0x2E,0xFB,0xBE,0x00,0xAC,0x03,0x2F,0xFF,0xD0,0xFD, + 0xB7,0xFE,0xB1,0xFF,0xA9,0x03,0x97,0x01,0x99,0xF9,0x90,0xFF, + 0x89,0x04,0x7C,0xFF,0x0D,0x00,0x0F,0xFF,0x55,0xFD,0xB4,0x02, + 0x2E,0x05,0x40,0xFC,0x0E,0xFC,0x09,0x04,0x2D,0xFF,0x44,0xFE, + 0xD0,0x00,0x44,0xFE,0x2F,0x00,0x25,0x02,0xF5,0x00,0x06,0xFE, + 0x16,0x01,0x73,0x03,0x9B,0xFC,0xAE,0xFF,0x4E,0x03,0xC6,0xFE, + 0xB4,0xFD,0x86,0x00,0xB8,0x00,0xA9,0xFD,0x99,0xFF,0xBB,0x00, + 0xDB,0xFD,0xE9,0x00,0x02,0x02,0x61,0xFE,0x29,0xFF,0xBC,0x01, + 0x03,0x01,0xA8,0xFE,0xED,0x02,0xEA,0xFF,0xAC,0xFE,0xD9,0x02, + 0x51,0x00,0x4B,0xFE,0xDA,0xFE,0x15,0x02,0x75,0xFF,0x13,0xFF, + 0x12,0x00,0xEB,0xFE,0x72,0xFE,0xC1,0x00,0x0D,0x01,0xB4,0xFD, + 0x8D,0x00,0x00,0x00,0x84,0x00,0x42,0x01,0x59,0xFF,0xEC,0xFD, + 0x39,0xFF,0x27,0x03,0xE8,0x00,0xB0,0xFD,0x2E,0xFE,0xBF,0x02, + 0x49,0x02,0xA3,0xFE,0x8C,0xFF,0x7A,0xFF,0x50,0x00,0x9B,0x02, + 0x68,0x00,0x4F,0xFD,0x14,0x00,0x92,0x01,0x61,0xFF,0x1C,0xFF, + 0x6F,0x00,0x05,0x00,0x1B,0xFF,0x9D,0x00,0x06,0x00,0xA4,0xFF, + 0x0B,0x02,0x2C,0x00,0x66,0xFE,0x4D,0x00,0x26,0x01,0x69,0x00, + 0xF0,0xFE,0x07,0xFF,0x6D,0xFF,0x81,0x00,0x97,0x00,0xB6,0xFE, + 0x0A,0xFF,0xDB,0x00,0xBC,0x00,0x2D,0xFF,0x17,0xFF,0xE1,0xFF, + 0x0A,0x00,0x64,0x00,0x50,0xFF,0x24,0xFD,0x13,0xFF,0xBF,0xFF, + 0x11,0xFF,0x4C,0xFE,0xB1,0xFD,0x69,0x00,0x22,0x01,0xE5,0x00, + 0x15,0x00,0x80,0x00,0x82,0x04,0xDE,0x04,0x21,0x02,0xEA,0x03, + 0x1A,0x07,0x0C,0x06,0x2D,0x03,0x24,0x04,0xD7,0x03,0x63,0xFF, + 0xCB,0xFF,0xD0,0xFD,0x7A,0xF9,0xFB,0xF9,0x42,0xFA,0x80,0xF7, + 0xF7,0xF3,0xEF,0xF6,0x04,0xFA,0xE7,0xF8,0xF6,0xF9,0x3B,0xFC, + 0x98,0xFE,0x72,0x01,0x1F,0x02,0x5B,0x02,0x32,0x04,0x5A,0x07, + 0x1E,0x09,0x33,0x03,0xDE,0x03,0x28,0x09,0x82,0x02,0x9C,0x01, + 0x67,0x0F,0x6B,0x10,0x21,0x02,0x15,0x04,0xFF,0x09,0xB1,0x05, + 0xA6,0x01,0x4A,0xFF,0xB0,0xFA,0x62,0xF5,0x71,0xFB,0xAA,0xF8, + 0x35,0xED,0xD8,0xEF,0xD2,0xF3,0x46,0xF3,0xF5,0xF3,0x85,0xF7, + 0x80,0xFA,0x2E,0xFC,0x35,0x04,0xDE,0x06,0x1C,0x04,0x76,0x09, + 0x72,0x0C,0x02,0x0B,0x83,0x09,0xFD,0x08,0x10,0x06,0x3B,0x02, + 0xD4,0xFF,0x59,0xFB,0x79,0xFA,0xF8,0xF7,0x3A,0xF8,0xD5,0xF9, + 0xAF,0x02,0x2F,0x0C,0x36,0xFF,0x6B,0x02,0x2A,0x0D,0x46,0x0D, + 0xAC,0x0B,0xCD,0x05,0xEE,0x07,0x95,0x01,0xD6,0x01,0x97,0x01, + 0x64,0xF3,0x06,0xF1,0x11,0xF4,0xC5,0xF3,0xB3,0xF0,0xC7,0xEF, + 0x39,0xF3,0xD5,0xF5,0x15,0xFA,0x5D,0xFF,0xEB,0xFE,0x68,0x03, + 0x12,0x0A,0xCC,0x0A,0xA2,0x09,0x06,0x0A,0x69,0x0B,0xA2,0x09, + 0x99,0x07,0x02,0x00,0x31,0xFA,0x5F,0xFD,0x49,0xF9,0xCA,0xF6, + 0x91,0x01,0x2D,0x06,0x62,0x01,0xDF,0xFE,0x29,0x08,0x0F,0x0B, + 0x0D,0x06,0x13,0x0B,0xEB,0x06,0xA7,0x01,0x88,0x03,0x77,0x03, + 0x20,0xFB,0x4F,0xF3,0xFD,0xF6,0x92,0xF4,0xE4,0xF0,0xFE,0xF4, + 0x78,0xF6,0xD3,0xF2,0xFB,0xF6,0xC6,0xFE,0xEA,0xFE,0x05,0x00, + 0x5D,0x05,0x5F,0x07,0x57,0x07,0xA7,0x0A,0x25,0x0A,0x03,0x06, + 0xEC,0x05,0xDC,0x04,0x3C,0x00,0x03,0xFE,0xA9,0xF9,0xBC,0xF4, + 0x9A,0xF9,0x6F,0x07,0xE7,0x07,0xED,0xFB,0x67,0x01,0x7A,0x09, + 0x84,0x09,0x88,0x0A,0x9B,0x08,0x4F,0x03,0x83,0x00,0xA7,0x06, + 0x39,0x03,0xC5,0xF6,0x39,0xF5,0x1B,0xF6,0x12,0xF4,0xF2,0xF4, + 0x24,0xF7,0xF3,0xF4,0x1D,0xF3,0xF3,0xFA,0x16,0x00,0x42,0xFE, + 0x85,0x01,0xFA,0x04,0xA2,0x05,0x55,0x08,0xD6,0x09,0xD6,0x06, + 0x66,0x04,0x50,0x05,0x6E,0x03,0x74,0xFF,0x87,0xFC,0x67,0xF5, + 0xB4,0xFC,0xC8,0x0C,0x1E,0x05,0xA7,0xFC,0xEE,0x00,0x24,0x06, + 0xC5,0x07,0x4F,0x08,0xD3,0x07,0x7A,0xFD,0xE7,0xFD,0xA8,0x06, + 0x07,0x01,0xB9,0xF7,0x1B,0xF6,0xA9,0xF6,0x30,0xF5,0x90,0xF8, + 0x4F,0xFC,0xF0,0xF6,0x1E,0xF5,0x6A,0xFD,0x25,0x01,0xB6,0x00, + 0x24,0x03,0xB9,0x03,0x78,0x03,0x49,0x06,0xB3,0x08,0x6C,0x04, + 0x3B,0x01,0x73,0x01,0x0B,0xFF,0x0A,0xFD,0x0B,0xF8,0x7E,0xFF, + 0x32,0x0A,0x5C,0x03,0x56,0x01,0x6A,0x03,0xB5,0x04,0x12,0x07, + 0xC1,0x08,0x87,0x07,0x53,0xFF,0x80,0xFF,0x6D,0x03,0x0B,0xFF, + 0x51,0xFA,0x0F,0xF8,0x3E,0xF5,0x08,0xF5,0x59,0xF8,0xB4,0xFA, + 0xAF,0xF8,0x02,0xF7,0x5E,0xFB,0xD5,0xFE,0xDF,0x01,0xE0,0x03, + 0x46,0x03,0xF2,0x03,0x67,0x05,0x25,0x07,0xAC,0x05,0x4B,0x02, + 0xAA,0xFF,0x95,0xFE,0xA2,0xFA,0x7D,0xFE,0x13,0x0B,0x48,0x06, + 0x2F,0xFF,0x5B,0x02,0xF7,0x03,0x26,0x05,0x7E,0x07,0xE3,0x06, + 0x6A,0xFE,0x92,0xFC,0xA0,0x02,0x64,0xFF,0xB8,0xF9,0x1B,0xF9, + 0x8B,0xF6,0xBD,0xF5,0x08,0xFA,0x4D,0xFD,0xBE,0xF9,0xFE,0xF7, + 0xBF,0xFD,0x7A,0xFF,0xB5,0x01,0x0D,0x05,0xA1,0x03,0x44,0x02, + 0x84,0x04,0x84,0x06,0x7A,0x03,0xF8,0xFF,0x56,0xFF,0x6B,0xFA, + 0xA4,0xF9,0xA3,0x08,0x66,0x0A,0x59,0x00,0x81,0x01,0xBD,0x03, + 0x49,0x03,0xC1,0x06,0xB9,0x0A,0x0F,0x02,0x1E,0xFB,0xEA,0x00, + 0x5A,0x01,0xB8,0xFB,0x14,0xFB,0x1D,0xF8,0x4A,0xF3,0x43,0xF7, + 0x47,0xFD,0x4E,0xFC,0xD9,0xF7,0xA6,0xFA,0x66,0xFD,0x56,0xFF, + 0xE0,0x05,0xA5,0x05,0x64,0x01,0x93,0x02,0xF6,0x05,0x8B,0x05, + 0x08,0x03,0x93,0x01,0x28,0xFB,0xAB,0xF7,0xF6,0x06,0x8F,0x0C, + 0x65,0x02,0x87,0x01,0x03,0x02,0x82,0x00,0x21,0x05,0x47,0x0B, + 0x2E,0x03,0x4E,0xFA,0xC9,0xFE,0x01,0x00,0x73,0xFC,0x50,0xFD, + 0x14,0xFA,0x02,0xF3,0x25,0xF6,0x61,0xFD,0xF7,0xFD,0x37,0xFA, + 0x78,0xFB,0x2F,0xFC,0x9F,0xFD,0xCB,0x05,0x85,0x06,0x26,0x02, + 0x55,0x01,0xDB,0x03,0xD5,0x03,0x9B,0x02,0xAB,0x00,0x35,0xF9, + 0x26,0xFF,0xA8,0x0A,0x28,0x08,0xE7,0x03,0x18,0x03,0x00,0x01, + 0x4F,0x01,0x01,0x08,0xF5,0x07,0x8D,0xFF,0x96,0xFC,0xF3,0xFD, + 0xFC,0xFB,0x1F,0xFC,0xFB,0xFC,0x2E,0xF6,0x9D,0xF3,0xDA,0xF8, + 0xD2,0xFC,0x63,0xFC,0x87,0xFC,0x96,0xFC,0xD3,0xFB,0xC8,0x01, + 0xAF,0x06,0x27,0x05,0x84,0x03,0x11,0x04,0x48,0x02,0x19,0x02, + 0xCC,0x01,0x93,0xFC,0xD8,0x00,0x23,0x08,0xBD,0x06,0x08,0x04, + 0xBB,0x03,0xEF,0x01,0xC0,0x00,0x51,0x05,0xE1,0x05,0x0D,0x00, + 0x8A,0xFD,0xCF,0xFD,0x26,0xFB,0x02,0xFB,0x3A,0xFC,0xD9,0xF7, + 0x9C,0xF5,0x34,0xF9,0x62,0xFC,0xAC,0xFC,0xAE,0xFD,0x67,0xFD, + 0x44,0xFD,0x88,0x01,0x40,0x05,0xC0,0x04,0x10,0x04,0x73,0x03, + 0xF7,0x00,0x5E,0x01,0x6D,0xFE,0xDA,0xFE,0x79,0x06,0xFC,0x07, + 0x3D,0x05,0xD8,0x03,0x97,0x03,0x6A,0x01,0xF7,0x03,0xC5,0x05, + 0x38,0x02,0xE6,0xFE,0x75,0xFD,0x82,0xFC,0xBB,0xFA,0xF8,0xFB, + 0xEF,0xF8,0x75,0xF5,0xA3,0xF7,0x67,0xFB,0x5A,0xFC,0xF3,0xFC, + 0x27,0xFE,0x6A,0xFC,0x02,0xFF,0x24,0x04,0x48,0x05,0x06,0x05, + 0x56,0x04,0x81,0x01,0xB2,0xFF,0xA8,0xFE,0x13,0x01,0x16,0x07, + 0x39,0x08,0xCC,0x05,0xFC,0x03,0x58,0x02,0x2B,0x02,0x53,0x04, + 0x1A,0x05,0x72,0x02,0xC0,0xFE,0x5E,0xFC,0x0E,0xFB,0xD6,0xFA, + 0x1E,0xFB,0xAF,0xF9,0x33,0xF7,0x8E,0xF7,0x95,0xF9,0xE4,0xFB, + 0x58,0xFE,0x51,0xFE,0xCB,0xFD,0xBF,0xFF,0xBE,0x02,0x8F,0x04, + 0xBB,0x05,0xAA,0x04,0xE4,0x01,0x04,0xFE,0xB6,0xFD,0x3C,0x04, + 0x16,0x09,0xDB,0x08,0x55,0x06,0xD6,0x02,0x48,0x00,0x06,0x02, + 0x7B,0x05,0x35,0x05,0x66,0x01,0x6B,0xFD,0x01,0xFA,0x00,0xF9, + 0xFC,0xFA,0x83,0xFB,0x56,0xF9,0x53,0xF7,0xB8,0xF7,0x84,0xF9, + 0xEB,0xFC,0xBC,0xFF,0x3A,0xFF,0x03,0xFF,0xAB,0x00,0xD7,0x02, + 0x3A,0x05,0x52,0x06,0xBB,0x03,0xFC,0xFE,0x5A,0xFD,0xD9,0x01, + 0x54,0x08,0x2C,0x0A,0x29,0x08,0xD7,0x03,0x00,0x00,0xD7,0x00, + 0x38,0x04,0x8E,0x05,0xD8,0x02,0x4C,0xFE,0xE1,0xF9,0x1E,0xF8, + 0xC0,0xF9,0x3A,0xFB,0x6D,0xFA,0xDE,0xF8,0x97,0xF7,0x5E,0xF8, + 0xF2,0xFB,0xF7,0xFE,0x0B,0x00,0x3E,0x00,0xEF,0x00,0xF5,0x01, + 0x40,0x04,0xEA,0x05,0x56,0x03,0x01,0x00,0xFD,0xFE,0x68,0x02, + 0x24,0x08,0xEF,0x09,0x39,0x08,0x29,0x04,0x96,0x00,0xA9,0x00, + 0x50,0x03,0x9B,0x04,0x45,0x02,0x58,0xFE,0xF7,0xF9,0xC2,0xF7, + 0xF6,0xF8,0x65,0xFA,0x3B,0xFA,0x5F,0xF9,0x6E,0xF8,0x08,0xF9, + 0xA3,0xFB,0x8C,0xFE,0x2E,0x00,0x25,0x01,0xEA,0x01,0x86,0x02, + 0x27,0x04,0xE0,0x03,0xF2,0x01,0x89,0x00,0x4F,0x01,0xF7,0x05, + 0x32,0x09,0xD8,0x08,0xB3,0x06,0x33,0x03,0xEE,0x00,0xE0,0x01, + 0xC8,0x03,0xE5,0x02,0x0B,0x00,0x86,0xFC,0xCD,0xF8,0xE2,0xF7, + 0x24,0xF9,0x9E,0xF9,0xA7,0xF9,0x0B,0xF9,0xD5,0xF8,0x5E,0xFA, + 0xBF,0xFC,0x42,0xFF,0xBA,0x00,0xD4,0x01,0xCA,0x02,0x80,0x03, + 0x46,0x04,0xE9,0x02,0xD9,0x00,0x05,0x01,0x2C,0x04,0x46,0x08, + 0x68,0x09,0x13,0x08,0xBA,0x04,0x6B,0x01,0x03,0x01,0x93,0x02, + 0x61,0x03,0x9C,0x01,0x3D,0xFE,0x1C,0xFA,0xB8,0xF7,0x26,0xF8, + 0x23,0xF9,0xF8,0xF9,0xF7,0xF9,0xE5,0xF8,0x82,0xF9,0x8E,0xFB, + 0x9A,0xFD,0x6E,0x00,0x1E,0x02,0x83,0x02,0x3B,0x03,0xED,0x03, + 0xD7,0x02,0x35,0x01,0x53,0x01,0xC5,0x02,0xAA,0x06,0x7E,0x09, + 0xA7,0x08,0x28,0x06,0x26,0x03,0x1D,0x01,0x93,0x01,0x31,0x03, + 0x84,0x02,0xE9,0xFF,0x48,0xFC,0xBE,0xF8,0x6B,0xF7,0x4E,0xF8, + 0x54,0xF9,0x0C,0xFA,0xC2,0xF9,0x42,0xF9,0x77,0xFA,0x4D,0xFC, + 0xDF,0xFE,0x52,0x01,0xA4,0x02,0x40,0x03,0xBB,0x03,0x13,0x03, + 0x82,0x01,0x26,0x01,0xB2,0x01,0xEB,0x04,0xE6,0x08,0x58,0x09, + 0xAF,0x07,0xFD,0x04,0xF6,0x01,0x08,0x01,0x9F,0x02,0x17,0x03, + 0x56,0x01,0x8D,0xFE,0x8E,0xFA,0x75,0xF7,0x52,0xF7,0x48,0xF8, + 0x43,0xF9,0x21,0xFA,0xFC,0xF9,0x0A,0xFA,0xDB,0xFA,0xB6,0xFC, + 0x64,0xFF,0xC5,0x01,0x8C,0x03,0x93,0x04,0x37,0x04,0x6E,0x02, + 0xC6,0x00,0x94,0x00,0x6C,0x02,0x07,0x07,0x32,0x0A,0x6D,0x09, + 0x1D,0x07,0x8B,0x03,0xBA,0x00,0x0F,0x01,0xF6,0x02,0xCF,0x02, + 0xF9,0x00,0x81,0xFD,0xEE,0xF8,0x81,0xF6,0xE6,0xF6,0x27,0xF8, + 0xB3,0xF9,0xC4,0xFA,0x60,0xFA,0x23,0xFA,0xEF,0xFA,0x20,0xFD, + 0xCF,0xFF,0xB0,0x02,0xA4,0x04,0x25,0x05,0x1F,0x04,0xE2,0x01, + 0x70,0x00,0x4A,0x00,0x0D,0x03,0x0A,0x08,0x53,0x0A,0x6C,0x09, + 0xE6,0x06,0xDD,0x02,0x4C,0x00,0x01,0x01,0x96,0x02,0x9A,0x02, + 0x1F,0x01,0x54,0xFD,0x97,0xF8,0x1C,0xF6,0x0A,0xF6,0x9C,0xF7, + 0xBE,0xF9,0x04,0xFB,0x2B,0xFB,0xAC,0xFA,0x14,0xFB,0xC8,0xFC, + 0x6C,0xFF,0xC7,0x02,0x48,0x05,0x1F,0x06,0x09,0x05,0x5F,0x02, + 0x01,0x00,0x7D,0xFF,0xB6,0x01,0xEB,0x06,0x43,0x0A,0x19,0x0A, + 0xDF,0x07,0x94,0x03,0x29,0x00,0xE0,0xFF,0x84,0x01,0x96,0x02, + 0x40,0x02,0x3F,0xFF,0x4E,0xFA,0x5A,0xF6,0x03,0xF5,0xE2,0xF5, + 0x9D,0xF8,0x3F,0xFB,0x39,0xFC,0x12,0xFC,0x49,0xFB,0xAE,0xFB, + 0xAF,0xFD,0x2B,0x01,0xBB,0x04,0xE2,0x06,0xB9,0x06,0x16,0x04, + 0xCF,0x00,0xA2,0xFE,0xE2,0xFE,0x67,0x03,0xA5,0x08,0x91,0x0A, + 0x35,0x0A,0xCA,0x06,0xCA,0x01,0x26,0xFF,0x93,0xFF,0x0D,0x01, + 0xAB,0x02,0x6A,0x02,0x88,0xFE,0x7A,0xF9,0xA1,0xF5,0xD4,0xF3, + 0x42,0xF5,0xE2,0xF8,0xC6,0xFB,0x82,0xFD,0x78,0xFD,0x41,0xFC, + 0x1C,0xFC,0xDE,0xFD,0x36,0x01,0xED,0x04,0x8D,0x07,0x4A,0x07, + 0x48,0x04,0xB4,0x00,0xB9,0xFD,0xB9,0xFD,0x96,0x02,0xC8,0x07, + 0x9B,0x0A,0x46,0x0B,0xE2,0x07,0x70,0x02,0x03,0xFF,0x55,0xFE, + 0x7D,0xFF,0xF6,0x01,0xF2,0x02,0x24,0x00,0x91,0xFB,0xCB,0xF6, + 0x38,0xF3,0x95,0xF3,0xBB,0xF6,0x6A,0xFA,0x1F,0xFE,0x66,0xFF, + 0x66,0xFE,0x66,0xFD,0x50,0xFD,0x01,0xFF,0x74,0x02,0x1B,0x06, + 0xA8,0x07,0x9F,0x06,0x92,0x03,0x5E,0xFF,0xEF,0xFC,0x17,0xFF, + 0x9D,0x03,0xF0,0x07,0x69,0x0B,0x20,0x0B,0xE7,0x06,0x15,0x02, + 0x7E,0xFE,0xE5,0xFC,0x4D,0xFE,0x8F,0x00,0x0D,0x01,0x8D,0xFF, + 0xDA,0xFB,0x10,0xF7,0xE2,0xF3,0xAD,0xF3,0xC0,0xF5,0xF1,0xF9, + 0x43,0xFE,0x78,0x00,0x2A,0x01,0x84,0x00,0x4D,0xFF,0x64,0xFF, + 0x2A,0x01,0xB9,0x03,0x10,0x06,0xA5,0x06,0xEC,0x04,0x8A,0x01, + 0xD0,0xFE,0x40,0xFF,0x80,0x01,0xCD,0x04,0x6A,0x08,0x7D,0x09, + 0xC4,0x07,0x88,0x04,0xA2,0x00,0x98,0xFD,0xB0,0xFC,0x22,0xFD, + 0xE2,0xFD,0x4F,0xFE,0x5B,0xFD,0x0C,0xFB,0xA8,0xF8,0xCF,0xF6, + 0x4F,0xF6,0x00,0xF8,0xFF,0xFA,0x70,0xFE,0x7E,0x01,0xFD,0x02, + 0xBC,0x02,0xB7,0x01,0x13,0x01,0x4B,0x01,0x90,0x02,0xE8,0x03, + 0xEE,0x03,0xED,0x02,0x46,0x01,0x46,0x00,0xA8,0x00,0xB6,0x01, + 0x9B,0x03,0x5E,0x05,0xE4,0x05,0x15,0x05,0x62,0x03,0x32,0x01, + 0x49,0xFF,0x42,0xFE,0xB6,0xFD,0x93,0xFD,0x8E,0xFD,0x24,0xFD, + 0x50,0xFC,0x6A,0xFB,0x74,0xFA,0xCE,0xF9,0x2F,0xFA,0x99,0xFB, + 0xD8,0xFD,0x54,0x00,0xB7,0x01,0xF0,0x01,0xA3,0x01,0xE9,0x00, + 0xE8,0x00,0xA6,0x01,0x20,0x02,0x1F,0x02,0xAE,0x01,0xE9,0x00, + 0x45,0x00,0x61,0x00,0xAC,0x00,0x59,0x01,0x86,0x02,0x64,0x03, + 0xC6,0x03,0x77,0x03,0x7A,0x02,0x44,0x01,0x57,0x00,0xA4,0xFF, + 0x38,0xFF,0x14,0xFF,0xEB,0xFE,0x9E,0xFE,0x58,0xFE,0xEB,0xFD, + 0x2B,0xFD,0x6F,0xFC,0xF6,0xFB,0x9C,0xFC,0x19,0xFE,0x31,0xFF, + 0xBE,0xFF,0x04,0x00,0xF4,0xFF,0x06,0x00,0x69,0x00,0x83,0x00, + 0x8D,0x00,0x6C,0x00,0xDC,0xFF,0x67,0xFF,0x26,0xFF,0x10,0xFF, + 0x62,0xFF,0x00,0x00,0xED,0x00,0x21,0x02,0x2A,0x03,0x9B,0x03, + 0x85,0x03,0x3F,0x03,0xE6,0x02,0x94,0x02,0x40,0x02,0xDC,0x01, + 0x50,0x01,0x9C,0x00,0xD5,0xFF,0x10,0xFF,0x7D,0xFE,0xB5,0xFD, + 0xD9,0xFC,0xC2,0xFC,0x19,0xFD,0x81,0xFD,0xE8,0xFD,0x33,0xFE, + 0x60,0xFE,0x71,0xFE,0x94,0xFE,0xB5,0xFE,0xC8,0xFE,0xCF,0xFE, + 0xC6,0xFE,0xB7,0xFE,0xBC,0xFE,0xEC,0xFE,0x37,0xFF,0xA1,0xFF, + 0x3C,0x00,0x15,0x01,0x1A,0x02,0x51,0x03,0x5E,0x04,0xCD,0x04, + 0xBF,0x04,0x5B,0x04,0xE1,0x03,0x67,0x03,0xD2,0x02,0x28,0x02, + 0x61,0x01,0x79,0x00,0x99,0xFF,0xD5,0xFE,0x09,0xFE,0x59,0xFD, + 0x01,0xFD,0xDB,0xFC,0xD5,0xFC,0xFD,0xFC,0x2B,0xFD,0x63,0xFD, + 0xB4,0xFD,0xEA,0xFD,0x12,0xFE,0x3E,0xFE,0x55,0xFE,0x62,0xFE, + 0x7D,0xFE,0xAA,0xFE,0xE5,0xFE,0x41,0xFF,0xAA,0xFF,0x0F,0x00, + 0x91,0x00,0x2A,0x01,0xDC,0x01,0xA9,0x02,0x71,0x03,0x15,0x04, + 0x79,0x04,0x88,0x04,0x4C,0x04,0xEE,0x03,0x7E,0x03,0xE2,0x02, + 0x2A,0x02,0x6D,0x01,0x8C,0x00,0xAC,0xFF,0xE7,0xFE,0x26,0xFE, + 0x83,0xFD,0x10,0xFD,0xAC,0xFC,0x79,0xFC,0x8F,0xFC,0xBA,0xFC, + 0xF9,0xFC,0x52,0xFD,0xA6,0xFD,0xDD,0xFD,0x18,0xFE,0x51,0xFE, + 0x76,0xFE,0xAB,0xFE,0xEB,0xFE,0x2F,0xFF,0x84,0xFF,0xE8,0xFF, + 0x49,0x00,0xAA,0x00,0x0E,0x01,0x6F,0x01,0xF0,0x01,0x93,0x02, + 0x33,0x03,0xC2,0x03,0x2E,0x04,0x5C,0x04,0x3C,0x04,0xF7,0x03, + 0x8C,0x03,0xEA,0x02,0x2E,0x02,0x5C,0x01,0x76,0x00,0x9D,0xFF, + 0xD8,0xFE,0x1E,0xFE,0x82,0xFD,0xFC,0xFC,0x90,0xFC,0x4B,0xFC, + 0x3B,0xFC,0x5C,0xFC,0xA8,0xFC,0x16,0xFD,0x84,0xFD,0xE7,0xFD, + 0x44,0xFE,0x90,0xFE,0xC8,0xFE,0x03,0xFF,0x3D,0xFF,0x7C,0xFF, + 0xCB,0xFF,0x26,0x00,0x84,0x00,0xD1,0x00,0x14,0x01,0x46,0x01, + 0x85,0x01,0xED,0x01,0x63,0x02,0xEE,0x02,0x73,0x03,0xCD,0x03, + 0xF4,0x03,0xDD,0x03,0x95,0x03,0x2F,0x03,0xA2,0x02,0xEE,0x01, + 0x27,0x01,0x54,0x00,0x82,0xFF,0xBE,0xFE,0x13,0xFE,0x71,0xFD, + 0xE9,0xFC,0x7F,0xFC,0x34,0xFC,0x2E,0xFC,0x5F,0xFC,0xBB,0xFC, + 0x39,0xFD,0xC0,0xFD,0x2F,0xFE,0x8B,0xFE,0xDE,0xFE,0x17,0xFF, + 0x40,0xFF,0x72,0xFF,0xB2,0xFF,0xFA,0xFF,0x56,0x00,0xAD,0x00, + 0xEE,0x00,0x1F,0x01,0x43,0x01,0x57,0x01,0x8F,0x01,0xF3,0x01, + 0x65,0x02,0xE8,0x02,0x5E,0x03,0xA5,0x03,0xA6,0x03,0x6F,0x03, + 0x0F,0x03,0x8A,0x02,0xE7,0x01,0x33,0x01,0x76,0x00,0xBC,0xFF, + 0x0D,0xFF,0x6A,0xFE,0xD8,0xFD,0x4E,0xFD,0xDB,0xFC,0x81,0xFC, + 0x5C,0xFC,0x77,0xFC,0xC0,0xFC,0x36,0xFD,0xBA,0xFD,0x32,0xFE, + 0x96,0xFE,0xE6,0xFE,0x25,0xFF,0x4C,0xFF,0x74,0xFF,0xA7,0xFF, + 0xEE,0xFF,0x44,0x00,0x9A,0x00,0xE4,0x00,0x15,0x01,0x2D,0x01, + 0x37,0x01,0x41,0x01,0x77,0x01,0xD4,0x01,0x47,0x02,0xC3,0x02, + 0x27,0x03,0x65,0x03,0x56,0x03,0x12,0x03,0xAE,0x02,0x23,0x02, + 0x88,0x01,0xE4,0x00,0x38,0x00,0x93,0xFF,0xF7,0xFE,0x62,0xFE, + 0xCB,0xFD,0x4D,0xFD,0xDF,0xFC,0x91,0xFC,0x8D,0xFC,0xB7,0xFC, + 0x14,0xFD,0x91,0xFD,0x0C,0xFE,0x70,0xFE,0xB9,0xFE,0xF9,0xFE, + 0x20,0xFF,0x42,0xFF,0x79,0xFF,0xBE,0xFF,0x14,0x00,0x73,0x00, + 0xCB,0x00,0x0B,0x01,0x2E,0x01,0x38,0x01,0x33,0x01,0x3F,0x01, + 0x73,0x01,0xD6,0x01,0x4D,0x02,0xC1,0x02,0x18,0x03,0x3D,0x03, + 0x14,0x03,0xB6,0x02,0x47,0x02,0xC6,0x01,0x3C,0x01,0xB7,0x00, + 0x31,0x00,0x9C,0xFF,0x0B,0xFF,0x70,0xFE,0xCB,0xFD,0x41,0xFD, + 0xD2,0xFC,0x8D,0xFC,0x93,0xFC,0xD8,0xFC,0x44,0xFD,0xC5,0xFD, + 0x3F,0xFE,0x8A,0xFE,0xC3,0xFE,0xF7,0xFE,0x10,0xFF,0x3D,0xFF, + 0x86,0xFF,0xDD,0xFF,0x45,0x00,0xB3,0x00,0x04,0x01,0x2E,0x01, + 0x40,0x01,0x32,0x01,0x25,0x01,0x37,0x01,0x6D,0x01,0xD8,0x01, + 0x56,0x02,0xCF,0x02,0x16,0x03,0x27,0x03,0xEE,0x02,0x71,0x02, + 0xF7,0x01,0x7C,0x01,0x08,0x01,0xA3,0x00,0x34,0x00,0xAB,0xFF, + 0x19,0xFF,0x6E,0xFE,0xBC,0xFD,0x22,0xFD,0xB6,0xFC,0x83,0xFC, + 0x95,0xFC,0xF4,0xFC,0x6B,0xFD,0xEC,0xFD,0x58,0xFE,0x93,0xFE, + 0xBA,0xFE,0xE1,0xFE,0x06,0xFF,0x40,0xFF,0xA1,0xFF,0x0F,0x00, + 0x81,0x00,0xEC,0x00,0x30,0x01,0x43,0x01,0x39,0x01,0x1C,0x01, + 0x0D,0x01,0x23,0x01,0x66,0x01,0xE1,0x01,0x62,0x02,0xCF,0x02, + 0x08,0x03,0x02,0x03,0xB9,0x02,0x37,0x02,0xC8,0x01,0x66,0x01, + 0x0D,0x01,0xBF,0x00,0x62,0x00,0xD2,0xFF,0x26,0xFF,0x62,0xFE, + 0x99,0xFD,0xFD,0xFC,0x99,0xFC,0x86,0xFC,0xAD,0xFC,0x1E,0xFD, + 0x9E,0xFD,0x06,0xFE,0x58,0xFE,0x79,0xFE,0x96,0xFE,0xB6,0xFE, + 0xF0,0xFE,0x48,0xFF,0xC1,0xFF,0x3D,0x00,0xAC,0x00,0x02,0x01, + 0x2B,0x01,0x2F,0x01,0x19,0x01,0x0E,0x01,0x0D,0x01,0x41,0x01, + 0x90,0x01,0xFE,0x01,0x7E,0x02,0xC6,0x02,0xE8,0x02,0xC6,0x02, + 0x76,0x02,0x01,0x02,0xA0,0x01,0x62,0x01,0x24,0x01,0xED,0x00, + 0x86,0x00,0xEC,0xFF,0x29,0xFF,0x54,0xFE,0x85,0xFD,0xF0,0xFC, + 0xA4,0xFC,0xA3,0xFC,0xE1,0xFC,0x40,0xFD,0xB0,0xFD,0xFA,0xFD, + 0x2E,0xFE,0x45,0xFE,0x5F,0xFE,0x9D,0xFE,0xF4,0xFE,0x6F,0xFF, + 0xF3,0xFF,0x6E,0x00,0xC8,0x00,0xFB,0x00,0x11,0x01,0x0B,0x01, + 0x05,0x01,0x0A,0x01,0x28,0x01,0x65,0x01,0xB1,0x01,0x08,0x02, + 0x63,0x02,0x92,0x02,0x9D,0x02,0x83,0x02,0x42,0x02,0xF2,0x01, + 0xAE,0x01,0x87,0x01,0x57,0x01,0x11,0x01,0xA0,0x00,0xF0,0xFF, + 0x26,0xFF,0x53,0xFE,0x94,0xFD,0x14,0xFD,0xD3,0xFC,0xDA,0xFC, + 0x08,0xFD,0x4D,0xFD,0x9C,0xFD,0xC7,0xFD,0xF1,0xFD,0x17,0xFE, + 0x4B,0xFE,0xA9,0xFE,0x19,0xFF,0x9C,0xFF,0x10,0x00,0x6F,0x00, + 0xB2,0x00,0xCE,0x00,0xE9,0x00,0xF5,0x00,0x00,0x01,0x21,0x01, + 0x44,0x01,0x77,0x01,0xB1,0x01,0xE6,0x01,0x25,0x02,0x53,0x02, + 0x61,0x02,0x64,0x02,0x4A,0x02,0x19,0x02,0xE1,0x01,0xAB,0x01, + 0x6F,0x01,0x11,0x01,0x97,0x00,0xF0,0xFF,0x2D,0xFF,0x71,0xFE, + 0xC6,0xFD,0x4A,0xFD,0x09,0xFD,0xF8,0xFC,0x19,0xFD,0x35,0xFD, + 0x7A,0xFD,0xC2,0xFD,0xC2,0xFD,0x0C,0xFE,0x54,0xFE,0xC3,0xFE, + 0x48,0xFF,0x86,0xFF,0xEA,0xFF,0x4E,0x00,0x90,0x00,0xAC,0x00, + 0xD0,0x00,0xF1,0x00,0xFE,0x00,0x21,0x01,0x40,0x01,0x69,0x01, + 0xAD,0x01,0xB8,0x01,0xF6,0x01,0x67,0x02,0x75,0x02,0xA1,0x02, + 0x79,0x02,0x09,0x02,0x1F,0x02,0xEA,0x01,0x4C,0x01,0xFB,0x00, + 0xAA,0x00,0xFD,0xFF,0x1A,0xFF,0x54,0xFE,0x93,0xFD,0xFF,0xFC, + 0xC4,0xFC,0xF1,0xFC,0x1E,0xFD,0x30,0xFD,0xD0,0xFD,0xE3,0xFD, + 0x2D,0xFE,0x77,0xFE,0xA3,0xFE,0x7A,0xFF,0xAE,0xFF,0x8E,0xFF, + 0x08,0xFF,0xF1,0xFF,0x06,0x00,0xE5,0xFF,0x77,0x00,0xED,0xFF, + 0xAD,0x00,0x27,0x00,0x37,0x00,0x7F,0x00,0x5D,0x01,0xD3,0x02, + 0x49,0x04,0x3C,0x06,0xF8,0x04,0x21,0x05,0xCD,0x03,0xCA,0x01, + 0x06,0x02,0x4E,0x01,0xA3,0x01,0x25,0x01,0xC1,0xFF,0x8E,0xFD, + 0x5B,0xFB,0xDC,0xFA,0x3C,0xFA,0x23,0xFB,0xE5,0xFC,0x31,0xFC, + 0xBF,0xFC,0xFE,0xFC,0xC4,0xFC,0xBD,0xFE,0x74,0xFF,0xCA,0x00, + 0x66,0x01,0x59,0x01,0xF7,0x00,0x9B,0x00,0x52,0x01,0x78,0x00, + 0x3B,0x01,0xB9,0x00,0x74,0xFF,0xE2,0xFE,0x39,0xFD,0x4D,0xFE, + 0x0C,0x00,0xA1,0x02,0xB6,0x06,0xC8,0x07,0x72,0x07,0x9C,0x06, + 0x58,0x03,0x09,0x02,0xBC,0x01,0x91,0x01,0xC3,0x01,0xA9,0x00, + 0x2D,0xFE,0x7A,0xFA,0xA5,0xF8,0x82,0xF7,0xA7,0xF8,0xD5,0xFA, + 0x30,0xFC,0x75,0xFD,0xF6,0xFC,0x61,0xFD,0x46,0xFE,0xD9,0xFF, + 0x5D,0x02,0xC7,0x03,0xEE,0x03,0x10,0x03,0x00,0x02,0xFD,0x00, + 0x40,0x01,0x0C,0x01,0x90,0x00,0x56,0xFF,0x89,0xFD,0xDD,0xFB, + 0xEF,0xFB,0x7C,0xFE,0xBF,0x01,0x43,0x07,0x51,0x08,0x32,0x08, + 0x86,0x06,0x1D,0x03,0x5D,0x02,0x0B,0x02,0x43,0x03,0x59,0x02, + 0x6C,0x01,0x5D,0xFD,0x07,0xF9,0x50,0xF7,0x7E,0xF5,0x40,0xF8, + 0xCD,0xFA,0xF6,0xFB,0xFA,0xFC,0xBB,0xFC,0x73,0xFC,0x35,0xFD, + 0x65,0x00,0x72,0x02,0x67,0x04,0x9F,0x05,0x3A,0x03,0x16,0x03, + 0x5D,0x01,0xBC,0x00,0x3F,0x01,0x25,0x00,0xCE,0xFF,0xE2,0xFC, + 0x1A,0xFF,0x4B,0x01,0xB4,0x04,0x5C,0x08,0x99,0x07,0xC3,0x06, + 0xCF,0x02,0x42,0x01,0x54,0x00,0x5E,0x01,0x79,0x02,0xEB,0x00, + 0xCC,0xFE,0xE6,0xF9,0x01,0xF7,0xC4,0xF5,0xD4,0xF6,0x3C,0xFA, + 0x2F,0xFC,0xD2,0xFD,0xEE,0xFD,0xAF,0xFC,0x6A,0xFD,0x07,0xFF, + 0xD3,0x01,0x8A,0x04,0x98,0x05,0x07,0x05,0x26,0x03,0x7F,0x01, + 0x39,0x00,0xB5,0xFF,0xE3,0xFF,0x1A,0xFF,0x3F,0xFD,0x74,0xFF, + 0x4C,0x02,0xB0,0x04,0x0E,0x08,0x1B,0x08,0xFB,0x05,0xFB,0x03, + 0x2D,0x02,0x0E,0x01,0x78,0x02,0x7E,0x02,0x7C,0x00,0x31,0xFE, + 0xAC,0xF9,0x31,0xF6,0xE9,0xF5,0x8E,0xF6,0x0A,0xF9,0xCC,0xFB, + 0x64,0xFC,0xE4,0xFC,0x03,0xFD,0x23,0xFD,0x56,0xFF,0x62,0x02, + 0x7A,0x04,0x1E,0x06,0xCF,0x05,0xC2,0x03,0x4C,0x02,0x0A,0x01, + 0x2E,0x00,0xB7,0x00,0x04,0x00,0xD9,0xFC,0xE4,0xFD,0x73,0x01, + 0xF2,0x02,0x62,0x07,0xD4,0x08,0xC7,0x05,0x79,0x04,0xEB,0x01, + 0x3C,0x00,0x23,0x02,0x45,0x03,0x8A,0x01,0xFB,0xFF,0x8B,0xFB, + 0x66,0xF6,0x12,0xF6,0xEE,0xF5,0xC0,0xF7,0xE7,0xFB,0x8E,0xFC, + 0x76,0xFC,0x39,0xFD,0x22,0xFC,0x99,0xFD,0x88,0x01,0x9A,0x03, + 0xBA,0x05,0x9F,0x06,0xF7,0x03,0x63,0x02,0x6A,0x01,0xE6,0xFF, + 0xED,0x00,0x25,0x01,0x74,0xFE,0x27,0xFD,0x43,0x01,0x7E,0x02, + 0x6E,0x05,0x89,0x09,0x04,0x06,0x46,0x05,0x40,0x03,0x6C,0x00, + 0x73,0x01,0xF8,0x02,0x7A,0x01,0xF2,0xFF,0x70,0xFD,0x3A,0xF7, + 0x78,0xF6,0x16,0xF6,0x7D,0xF6,0xB6,0xFA,0x6D,0xFC,0x23,0xFC, + 0x9A,0xFD,0xD2,0xFC,0xD3,0xFC,0xEE,0x00,0x82,0x02,0xCA,0x04, + 0xAE,0x06,0xB0,0x04,0xDC,0x02,0x5F,0x02,0xDB,0xFF,0x88,0x00, + 0x64,0x01,0xD9,0xFE,0x03,0xFD,0xC3,0xFF,0x80,0x02,0xBD,0x03, + 0xA6,0x09,0x16,0x07,0x33,0x05,0x87,0x04,0x6C,0x00,0x38,0x01, + 0xB7,0x02,0x3F,0x02,0x93,0x00,0x15,0xFF,0xDD,0xF8,0x95,0xF6, + 0x71,0xF6,0x84,0xF5,0x6D,0xF9,0x30,0xFC,0xD4,0xFB,0x3B,0xFD, + 0x54,0xFD,0x08,0xFC,0xD1,0xFF,0xED,0x01,0xA4,0x03,0x79,0x06, + 0x7C,0x05,0x07,0x03,0xFB,0x02,0xA5,0x00,0x19,0x00,0x0B,0x02, + 0x11,0x00,0xC5,0xFD,0x4D,0xFD,0x04,0x01,0x1E,0x02,0x2C,0x07, + 0x4F,0x09,0x14,0x06,0xF9,0x05,0xB8,0x01,0x70,0x00,0x89,0x01, + 0x97,0x02,0xB2,0x01,0xE4,0x00,0x85,0xFC,0x60,0xF7,0xAE,0xF6, + 0xF1,0xF4,0x11,0xF7,0x11,0xFB,0x58,0xFC,0x81,0xFC,0xDF,0xFD, + 0x1A,0xFC,0x58,0xFD,0xD7,0x00,0x45,0x02,0x96,0x05,0x88,0x06, + 0x76,0x04,0xCB,0x02,0x14,0x02,0x89,0xFF,0xC5,0x01,0x4B,0x01, + 0x20,0xFF,0xC1,0xFD,0xC6,0xFC,0x2B,0x01,0xD8,0x02,0xEB,0x07, + 0x76,0x08,0xC4,0x06,0xF8,0x04,0x17,0x01,0xF1,0x00,0x38,0x01, + 0xF7,0x02,0x19,0x02,0x85,0x00,0xEC,0xFB,0xC3,0xF7,0xF6,0xF5, + 0x4A,0xF5,0xD4,0xF7,0x48,0xFB,0xE2,0xFC,0x04,0xFD,0x94,0xFD, + 0xEF,0xFB,0xA5,0xFD,0x8B,0x00,0xDA,0x02,0xD1,0x05,0x30,0x06, + 0x26,0x04,0x90,0x02,0xE0,0x00,0xD7,0xFF,0x29,0x01,0x2A,0x01, + 0x34,0x00,0x70,0xFC,0x09,0xFE,0xD3,0x00,0xD4,0x02,0xD0,0x08, + 0x83,0x08,0xFB,0x06,0x92,0x04,0x4A,0x01,0x6C,0x00,0xA2,0x01, + 0xB9,0x02,0xE5,0x01,0x8A,0x00,0x64,0xFB,0x69,0xF7,0xDC,0xF5, + 0x31,0xF5,0xF1,0xF7,0xC0,0xFB,0xDD,0xFC,0x21,0xFD,0x83,0xFD, + 0xF7,0xFB,0xE9,0xFD,0x06,0x01,0x47,0x03,0x59,0x06,0x48,0x06, + 0x52,0x04,0x68,0x02,0xE5,0x00,0xD1,0xFF,0xCA,0x00,0x93,0x00, + 0xAB,0x00,0x33,0xFD,0x48,0xFC,0x9C,0x01,0x51,0x01,0x6B,0x07, + 0x51,0x09,0x15,0x06,0xB5,0x05,0xF2,0x01,0x0D,0x00,0x3B,0x01, + 0x0D,0x03,0x31,0x01,0x67,0x01,0xD1,0xFC,0x68,0xF7,0x01,0xF7, + 0x11,0xF5,0x25,0xF7,0xB3,0xFB,0xF8,0xFC,0xF8,0xFC,0x63,0xFE, + 0x27,0xFC,0x21,0xFD,0x16,0x01,0x97,0x02,0xD4,0x05,0x8C,0x06, + 0xF6,0x03,0x41,0x02,0x75,0x01,0xFE,0xFE,0xA5,0x00,0x69,0x00, + 0x66,0xFF,0xA5,0xFE,0x5D,0xFC,0xD0,0x01,0x73,0x02,0xBB,0x06, + 0x23,0x09,0x1E,0x06,0xBC,0x05,0xAF,0x01,0x02,0x01,0xD0,0x00, + 0x97,0x02,0xA6,0x01,0x26,0x00,0x24,0xFD,0xCA,0xF7,0xD5,0xF6, + 0xE0,0xF5,0x8A,0xF7,0x72,0xFB,0x31,0xFD,0x10,0xFD,0xF5,0xFD, + 0xEA,0xFC,0x8C,0xFD,0xF3,0x00,0xE2,0x02,0x0E,0x05,0x1F,0x06, + 0x09,0x04,0x04,0x02,0x14,0x01,0x73,0xFF,0x6F,0x00,0x61,0x00, + 0x0A,0xFF,0x27,0xFD,0x46,0xFD,0x54,0x01,0x32,0x03,0xA9,0x07, + 0x2E,0x09,0x7F,0x06,0x44,0x05,0xF3,0x01,0xD4,0x00,0x0D,0x02, + 0x8F,0x02,0xCA,0x01,0xF7,0xFF,0x9B,0xFB,0x2C,0xF7,0x38,0xF6, + 0xAC,0xF5,0xBB,0xF7,0xDA,0xFB,0xA6,0xFC,0x13,0xFD,0x94,0xFD, + 0xA8,0xFC,0x7E,0xFE,0xC0,0x01,0xDB,0x03,0xE7,0x05,0x3F,0x06, + 0xA5,0x03,0x1C,0x02,0x64,0x00,0x84,0xFF,0x8F,0x00,0xC5,0xFF, + 0xAB,0xFF,0x3E,0xFC,0x78,0xFD,0xF4,0x01,0x06,0x03,0xD8,0x08, + 0x06,0x09,0x36,0x06,0xCC,0x04,0x53,0x01,0x6B,0x00,0x29,0x02, + 0xCD,0x02,0xF4,0x00,0x7E,0xFF,0x6A,0xFA,0x34,0xF6,0x47,0xF6, + 0xC5,0xF5,0xBF,0xF8,0xE0,0xFC,0xCB,0xFC,0x75,0xFD,0xC9,0xFD, + 0xBC,0xFC,0x60,0xFF,0xBC,0x02,0x83,0x04,0x4E,0x06,0xC7,0x05, + 0x4C,0x02,0x77,0x01,0x01,0x00,0xEF,0xFF,0x74,0x00,0x2F,0xFF, + 0xCA,0xFD,0x1B,0xFB,0x74,0x00,0xFF,0x02,0x71,0x06,0xE3,0x09, + 0x34,0x07,0x0E,0x06,0x23,0x03,0xFE,0x00,0x1E,0x01,0x04,0x04, + 0x21,0x02,0x34,0x00,0x51,0xFC,0x27,0xF6,0x24,0xF5,0x87,0xF5, + 0x5D,0xF7,0x80,0xFB,0x19,0xFD,0x06,0xFC,0x32,0xFD,0x01,0xFD, + 0x0F,0xFF,0x87,0x03,0xC6,0x05,0x33,0x06,0xF6,0x05,0x37,0x02, + 0x42,0x01,0x5D,0x00,0xED,0xFF,0x1E,0x01,0x86,0xFE,0x6E,0xFC, + 0x14,0xF7,0x10,0xFD,0x06,0x04,0x99,0x07,0x0A,0x0E,0xD6,0x0A, + 0x71,0x05,0x48,0x03,0xEB,0x01,0xE1,0x02,0x36,0x07,0x11,0x04, + 0x9A,0xFE,0x5E,0xF9,0x8E,0xF2,0xD3,0xF1,0x59,0xF5,0x8A,0xF7, + 0x40,0xFA,0x89,0xFB,0x69,0xF9,0x10,0xFB,0x5F,0xFE,0x41,0x02, + 0x8E,0x07,0x8B,0x09,0xF9,0x06,0x89,0x05,0x44,0x02,0x71,0x01, + 0x9C,0x02,0xB0,0x01,0x9F,0xFF,0x13,0xFC,0xE5,0xF8,0x1B,0xF4, + 0xD2,0xFC,0x79,0x05,0x6B,0x09,0xA1,0x0E,0x59,0x09,0x5D,0x03, + 0xF3,0x02,0x9C,0x03,0xDC,0x05,0xA1,0x09,0xFA,0x03,0x79,0xFC, + 0xF4,0xF6,0x33,0xF1,0xB1,0xF2,0x6F,0xF7,0x75,0xF8,0x84,0xF9, + 0xEF,0xF8,0x50,0xF7,0x50,0xFB,0xC3,0x00,0x1A,0x05,0xD5,0x08, + 0xD3,0x08,0xF7,0x04,0x4D,0x04,0xDE,0x02,0xBE,0x02,0x0F,0x04, + 0x77,0x01,0xC2,0xFD,0x80,0xFA,0xE0,0xF5,0xB6,0xF5,0xF9,0x00, + 0x21,0x07,0x3C,0x0B,0x3D,0x0D,0xC3,0x05,0x54,0x02,0xF7,0x03, + 0x0A,0x05,0x67,0x08,0x10,0x09,0x7F,0x00,0xC9,0xF9,0xEB,0xF4, + 0x83,0xF1,0x9C,0xF5,0xF6,0xF8,0x32,0xF8,0x7F,0xF8,0xDF,0xF6, + 0x8F,0xF7,0xEF,0xFD,0x60,0x03,0xEF,0x06,0xDA,0x08,0x85,0x06, + 0x9F,0x03,0x44,0x04,0xCE,0x03,0xF4,0x03,0xB0,0x03,0xA5,0xFF, + 0x11,0xFB,0xC1,0xF7,0xBD,0xF5,0xBF,0xFB,0xAF,0x05,0x23,0x09, + 0x4F,0x0B,0x83,0x08,0xB4,0x02,0x03,0x03,0xA5,0x05,0x65,0x07, + 0xA3,0x08,0x64,0x04,0xAF,0xFB,0xD8,0xF6,0x0D,0xF4,0xA7,0xF4, + 0x85,0xF8,0x24,0xF9,0xC5,0xF7,0x35,0xF7,0x6E,0xF7,0x38,0xFB, + 0xD4,0x01,0xED,0x05,0x69,0x07,0xFC,0x06,0x28,0x04,0x4C,0x03, + 0x72,0x04,0x3B,0x04,0x4E,0x03,0x4C,0x01,0x0E,0xFC,0xB8,0xF8, + 0xBF,0xF6,0x47,0xF8,0xCA,0x02,0x86,0x08,0x68,0x0A,0x4E,0x0A, + 0xE0,0x04,0x5D,0x02,0x17,0x05,0x41,0x07,0x1C,0x08,0x91,0x06, + 0x67,0xFE,0xA6,0xF7,0xBF,0xF4,0x11,0xF4,0xDA,0xF6,0x4F,0xF9, + 0x38,0xF8,0x32,0xF7,0x96,0xF7,0x2A,0xFA,0xDE,0xFF,0x60,0x05, + 0x6A,0x07,0x34,0x07,0xAC,0x05,0x20,0x03,0x2D,0x04,0xB8,0x04, + 0x15,0x04,0x36,0x01,0xC1,0xFD,0xE3,0xF8,0x2E,0xF4,0x57,0xF7, + 0xB0,0xFE,0x15,0x07,0xEE,0x0A,0x34,0x0A,0xA1,0x05,0x68,0x03, + 0x40,0x05,0x6E,0x08,0x2D,0x0B,0xA5,0x08,0x83,0x01,0xC7,0xF9, + 0xE9,0xF4,0xCE,0xF3,0x6B,0xF6,0xB6,0xF7,0x9B,0xF6,0xD8,0xF4, + 0xCE,0xF4,0x2B,0xF7,0xBA,0xFD,0xA9,0x03,0x0C,0x07,0xED,0x07, + 0x2A,0x06,0x49,0x05,0x08,0x06,0x44,0x07,0xBC,0x06,0x7D,0x04, + 0x54,0xFF,0x18,0xFB,0x85,0xF8,0xB3,0xF7,0xA0,0xF8,0xB8,0xFF, + 0x10,0x05,0xC7,0x05,0xBC,0x07,0xB5,0x04,0xC0,0x03,0x0F,0x06, + 0x6C,0x07,0x7D,0x07,0xE9,0x05,0x54,0x00,0xEF,0xFA,0x97,0xF8, + 0x0A,0xF7,0xD5,0xF7,0xAD,0xF8,0x06,0xF8,0x21,0xF7,0x72,0xF8, + 0xBE,0xFA,0x81,0xFE,0xA1,0x02,0xFE,0x03,0x57,0x04,0x12,0x04, + 0xA8,0x03,0xF7,0x03,0x51,0x04,0x1D,0x03,0xD0,0x00,0x28,0xFE, + 0x4D,0xFA,0x1C,0xF8,0x17,0xFB,0x78,0x03,0x43,0x08,0x98,0x0A, + 0x9F,0x09,0x20,0x04,0x94,0x02,0x22,0x04,0x2B,0x06,0x3A,0x07, + 0x08,0x05,0xF1,0xFD,0x2C,0xF8,0xF1,0xF4,0xA9,0xF4,0x3D,0xF7, + 0xF4,0xF8,0x12,0xF8,0x19,0xF8,0x72,0xF8,0xC6,0xFA,0x97,0x00, + 0xB7,0x04,0x1B,0x07,0xFD,0x06,0xC4,0x05,0x17,0x04,0xAE,0x04, + 0xEF,0x04,0xFE,0x03,0x6A,0x01,0xC9,0xFD,0xD0,0xF9,0x24,0xF8, + 0xF0,0xF7,0xF4,0xFA,0xF1,0x03,0x85,0x06,0x21,0x08,0xE6,0x07, + 0x41,0x04,0x3B,0x04,0xB8,0x06,0x79,0x07,0xED,0x06,0x3A,0x04, + 0x5A,0xFD,0x0A,0xF9,0xE2,0xF6,0x7E,0xF6,0xB3,0xF7,0x01,0xF9, + 0xD3,0xF7,0x8C,0xF7,0x86,0xF9,0xC9,0xFB,0xFE,0xFF,0x78,0x03, + 0x5A,0x04,0x95,0x04,0x24,0x04,0xCC,0x03,0xEF,0x03,0x60,0x04, + 0x81,0x02,0x55,0x00,0xD9,0xFD,0x4B,0xF8,0x2A,0xF9,0xF4,0xFE, + 0x68,0x05,0x84,0x09,0x69,0x0A,0xF9,0x05,0x5C,0x02,0xDF,0x02, + 0x29,0x04,0x7F,0x07,0x25,0x07,0x54,0x02,0xE5,0xFB,0x0B,0xF7, + 0x71,0xF4,0x46,0xF6,0x92,0xF8,0xB7,0xF8,0x6D,0xF8,0xFC,0xF7, + 0x7C,0xF8,0xC9,0xFC,0xB5,0x01,0x00,0x05,0xDD,0x06,0xFF,0x05, + 0x82,0x04,0x13,0x04,0xC1,0x04,0xA3,0x04,0xE8,0x03,0xB7,0x00, + 0x23,0xFD,0xFD,0xF9,0x81,0xF8,0xB6,0xF8,0x84,0xFF,0xC7,0x05, + 0x0D,0x07,0xB5,0x08,0x6F,0x05,0x06,0x03,0x4B,0x04,0x21,0x06, + 0x8A,0x06,0x1B,0x06,0x25,0x01,0x54,0xFB,0x3D,0xF8,0x81,0xF6, + 0x39,0xF7,0x1C,0xF9,0x50,0xF9,0x36,0xF8,0x41,0xF9,0x81,0xFA, + 0x4A,0xFD,0x4A,0x01,0xA6,0x03,0x4C,0x04,0x5A,0x04,0xB2,0x03, + 0x21,0x03,0xE3,0x03,0x94,0x03,0x2C,0x01,0x00,0x01,0x67,0xFB, + 0xFE,0xF7,0x93,0xFB,0x5D,0x00,0x04,0x07,0x39,0x0A,0x49,0x09, + 0x9F,0x04,0xE7,0x02,0x6B,0x02,0x1E,0x05,0xB9,0x07,0xD3,0x05, + 0x08,0x01,0xF2,0xFA,0xEA,0xF5,0x94,0xF4,0xD7,0xF6,0x21,0xF8, + 0x37,0xF9,0xFF,0xF8,0x2F,0xF8,0x70,0xF9,0xBE,0xFD,0x79,0x01, + 0x4C,0x05,0xC4,0x06,0xC2,0x05,0x82,0x04,0x20,0x04,0x00,0x04, + 0x5F,0x04,0x83,0x03,0x94,0x00,0xC4,0xFD,0x2E,0xFA,0x80,0xF8, + 0xE8,0xF9,0x04,0x01,0xB0,0x05,0xC1,0x07,0x1F,0x08,0x80,0x04, + 0xAC,0x02,0xAA,0x03,0x66,0x05,0x2F,0x06,0x56,0x05,0x5A,0x00, + 0x29,0xFB,0xD3,0xF7,0x90,0xF6,0x9D,0xF7,0xA4,0xF9,0xE9,0xF9, + 0x70,0xF9,0x07,0xFA,0xD1,0xFA,0x37,0xFD,0x38,0x01,0x87,0x03, + 0x4C,0x04,0x9C,0x04,0x2D,0x03,0xE3,0x02,0x58,0x03,0x81,0x02, + 0xF9,0x01,0x99,0x00,0xD0,0xFA,0x42,0xF9,0xD9,0xFB,0x64,0x00, + 0x13,0x07,0x77,0x09,0x7C,0x08,0x9A,0x05,0x57,0x03,0xF4,0x02, + 0x60,0x05,0xB6,0x06,0x45,0x05,0x1D,0x01,0x54,0xFB,0xA0,0xF6, + 0x24,0xF5,0x2E,0xF6,0xA9,0xF7,0xF7,0xF8,0x16,0xF9,0xE3,0xF8, + 0xE5,0xF9,0x65,0xFD,0xCA,0x00,0x3B,0x04,0x57,0x06,0x2E,0x06, + 0x45,0x05,0xD9,0x04,0x3F,0x04,0xA8,0x03,0x2E,0x03,0xD0,0x00, + 0x8F,0xFE,0x5A,0xFC,0x8B,0xF9,0x48,0xF9,0x64,0xFE,0x84,0x03, + 0x2F,0x06,0xF5,0x07,0xE0,0x05,0x71,0x03,0x6F,0x03,0x08,0x04, + 0xE2,0x04,0x23,0x05,0x30,0x02,0xB4,0xFD,0x1E,0xFA,0x72,0xF7, + 0x1E,0xF7,0xBC,0xF8,0x1F,0xFA,0x72,0xFA,0x18,0xFB,0x42,0xFB, + 0xDC,0xFB,0x07,0xFF,0xD6,0x01,0x74,0x03,0xF1,0x04,0xB9,0x03, + 0x18,0x03,0x5C,0x02,0xF6,0x01,0xBC,0x01,0xCC,0x00,0x8C,0xFE, + 0x92,0xFA,0x70,0xFB,0x3C,0xFE,0x7C,0x03,0x11,0x08,0x54,0x09, + 0x86,0x07,0x7E,0x04,0xEC,0x02,0x16,0x03,0xF5,0x04,0x0D,0x05, + 0xED,0x02,0x8F,0xFE,0x90,0xF9,0x02,0xF6,0x93,0xF5,0xD7,0xF6, + 0xAD,0xF8,0x17,0xFA,0x70,0xFA,0x75,0xFA,0x04,0xFC,0x78,0xFE, + 0x89,0x01,0x19,0x05,0x98,0x06,0x3D,0x06,0x1C,0x05,0x93,0x03, + 0xA1,0x02,0xE6,0x02,0x6E,0x02,0x49,0x00,0xF7,0xFD,0x39,0xFB, + 0xD9,0xF9,0x5B,0xFB,0xF5,0xFF,0x56,0x04,0x2F,0x06,0x01,0x07, + 0x05,0x05,0x6E,0x03,0x4E,0x03,0xD3,0x03,0x42,0x04,0x8E,0x03, + 0xBD,0x00,0x0D,0xFD,0x10,0xFA,0x2B,0xF8,0x24,0xF8,0xAA,0xF9, + 0xAB,0xFA,0xD2,0xFA,0xEA,0xFB,0x13,0xFC,0x46,0xFD,0xE4,0xFF, + 0x85,0x01,0xEE,0x02,0x38,0x04,0x88,0x03,0x0B,0x03,0xFE,0x01, + 0xC1,0x01,0x4C,0x01,0xBF,0xFF,0xFA,0xFD,0x47,0xFB,0xA9,0xFC, + 0x0C,0xFF,0x32,0x03,0xEC,0x06,0x7C,0x07,0xB1,0x06,0x3F,0x05, + 0xCD,0x03,0x79,0x03,0x45,0x04,0x8A,0x03,0xBA,0x01,0xAE,0xFE, + 0xB0,0xFA,0x9C,0xF7,0xFB,0xF6,0x6D,0xF7,0xAC,0xF8,0x45,0xFA, + 0x0C,0xFB,0x6E,0xFB,0xE2,0xFC,0x5C,0xFE,0xC4,0x00,0x34,0x04, + 0x92,0x05,0x3C,0x05,0xD7,0x04,0xBA,0x03,0x90,0x02,0x26,0x02, + 0x8C,0x01,0x66,0x00,0xFB,0xFE,0x10,0xFD,0xC5,0xFB,0x1C,0xFC, + 0xA4,0xFD,0x03,0x02,0x1D,0x05,0xE3,0x05,0xDD,0x05,0x7D,0x04, + 0x04,0x03,0xBE,0x02,0x08,0x03,0x62,0x02,0x3B,0x01,0xFA,0xFE, + 0x1C,0xFC,0x4F,0xFA,0x40,0xF9,0x61,0xF9,0xAF,0xFA,0xAD,0xFB, + 0x6C,0xFC,0xDA,0xFC,0xDC,0xFD,0xC7,0xFE,0x86,0x00,0x38,0x02, + 0xE5,0x02,0xF2,0x02,0x46,0x02,0x44,0x02,0x4E,0x01,0x30,0xFF, + 0x8F,0xFE,0xE0,0xFE,0x25,0xFD,0xBB,0xFD,0x3D,0xFF,0x73,0x01, + 0x6B,0x05,0xC1,0x06,0x40,0x07,0xBA,0x06,0x52,0x05,0xDC,0x03, + 0x68,0x03,0xA0,0x02,0xD2,0x00,0xEE,0xFE,0x5F,0xFC,0xBA,0xF9, + 0x2F,0xF8,0x0A,0xF8,0x65,0xF8,0x21,0xF9,0x46,0xFA,0xC6,0xFB, + 0xAD,0xFD,0x65,0xFF,0xD9,0x00,0x68,0x02,0x9C,0x03,0xAB,0x04, + 0xB9,0x04,0x47,0x04,0x7D,0x03,0x80,0x02,0x9C,0x01,0xCB,0xFF, + 0x2E,0xFF,0x8C,0xFE,0xB5,0xFD,0x53,0xFD,0x3C,0xFD,0x31,0xFE, + 0xC5,0xFE,0xC9,0x01,0x53,0x04,0xB5,0x04,0x7E,0x05,0x35,0x04, + 0xB5,0x02,0xCA,0x02,0x9B,0x02,0x63,0x01,0x0A,0x00,0x7B,0xFE, + 0x9A,0xFC,0xAC,0xFB,0xC1,0xFB,0x7B,0xFB,0x92,0xFB,0xA7,0xFB, + 0x7D,0xFB,0x6A,0xFD,0x28,0xFF,0x4F,0xFF,0x00,0x00,0xBB,0x00, + 0x4F,0x01,0x20,0x01,0xA7,0x01,0xA1,0x02,0x18,0x01,0xA4,0x00, + 0x5B,0x00,0x1C,0x00,0x15,0x00,0x3B,0xFF,0x55,0xFF,0x70,0xFF, + 0xD2,0xFF,0x22,0x01,0xD7,0x03,0x2A,0x05,0x74,0x05,0xD8,0x04, + 0xCC,0x02,0x04,0x02,0x7C,0x01,0x58,0x00,0x88,0xFF,0x97,0xFE, + 0x72,0xFD,0x34,0xFC,0x33,0xFB,0xF3,0xFA,0x1C,0xFB,0xF5,0xFB, + 0xA1,0xFC,0xB4,0xFD,0xA7,0xFE,0x42,0xFF,0x83,0x00,0xF0,0x00, + 0x73,0x01,0x3D,0x02,0x36,0x02,0x8F,0x01,0x52,0x01,0x0F,0x01, + 0xBA,0x00,0x17,0x01,0xF9,0xFF,0x01,0xFF,0xA3,0xFF,0x6E,0xFF, + 0x39,0xFF,0x57,0x00,0xEC,0x00,0x39,0x01,0x6E,0x02,0x61,0x03, + 0x9F,0x03,0x8F,0x03,0x3F,0x03,0x73,0x01,0x15,0x00,0xD2,0xFF, + 0x18,0xFF,0xC3,0xFE,0x23,0xFE,0xF7,0xFC,0x76,0xFC,0x5F,0xFC, + 0x3A,0xFC,0xF8,0xFC,0x97,0xFD,0x21,0xFE,0x86,0xFE,0xD8,0xFE, + 0x62,0x00,0x80,0x00,0x85,0x00,0x11,0x01,0x40,0x00,0x68,0x01, + 0xF6,0x02,0x0A,0x02,0xC2,0xFF,0xF0,0xFD,0xAE,0xFF,0x7C,0x01, + 0xE9,0x00,0x21,0x01,0x59,0x00,0x50,0xFF,0x66,0x00,0x19,0x02, + 0xCB,0x03,0x16,0x04,0x4E,0x03,0xEA,0x01,0x93,0x00,0x85,0x00, + 0xE7,0xFF,0x43,0xFF,0x16,0xFF,0x4F,0xFE,0x7C,0xFD,0xF1,0xFC, + 0x99,0xFC,0x51,0xFD,0x60,0xFD,0x6F,0xFC,0x3D,0xFE,0x7F,0xFF, + 0x7F,0xFF,0x13,0x00,0xC1,0xFF,0x03,0x00,0xA7,0x00,0x4C,0x01, + 0xF3,0x00,0xF7,0x00,0xC1,0x01,0x10,0x00,0x41,0xFF,0x1F,0x01, + 0x92,0x01,0x0B,0x01,0x76,0x00,0x83,0xFF,0x0F,0x00,0x17,0x01, + 0xB1,0x01,0xBC,0x01,0x47,0x02,0x13,0x03,0xA2,0x01,0x00,0x00, + 0x9D,0xFF,0x02,0x00,0x1E,0x00,0x7F,0xFF,0x34,0xFF,0xA2,0xFE, + 0x52,0xFE,0x2D,0xFE,0xFC,0xFD,0x4D,0xFE,0xBE,0xFD,0x83,0xFD, + 0xCF,0xFE,0x14,0x00,0x9E,0xFF,0x7F,0xFE,0x1D,0xFF,0xEC,0xFF, + 0x58,0x00,0x52,0x00,0x71,0x00,0xA5,0x01,0xE4,0x00,0x62,0x00, + 0x92,0x00,0xD4,0xFF,0x82,0x00,0xA3,0x00,0x9D,0x01,0x7D,0x01, + 0x9C,0xFF,0x53,0x00,0xCE,0x00,0x4A,0x01,0x11,0x02,0xAD,0x01, + 0xE7,0x00,0x3F,0x01,0x17,0x01,0x7E,0xFF,0x90,0xFF,0x14,0x00, + 0x47,0xFF,0xAD,0xFE,0x46,0xFF,0x20,0xFF,0x66,0xFE,0x82,0xFE, + 0x66,0xFE,0xAB,0xFE,0x36,0xFF,0xD4,0xFE,0xD7,0xFE,0x7F,0xFF, + 0x8A,0xFF,0xFD,0xFE,0xDB,0xFE,0x85,0x00,0x4D,0x01,0xB6,0x00, + 0xF2,0xFF,0xAE,0xFE,0xB0,0x00,0x6E,0x01,0xF1,0xFF,0x3D,0x00, + 0x2E,0x01,0x0F,0x02,0x33,0x00,0xB7,0xFF,0xC3,0x00,0x09,0x01, + 0xF3,0x01,0x66,0x01,0xF6,0x00,0x9F,0x00,0xFF,0xFF,0xEC,0x00, + 0x63,0x01,0x40,0x00,0x4E,0xFF,0x79,0xFF,0x9C,0xFF,0x0F,0xFF, + 0x75,0xFE,0x60,0xFE,0xEE,0xFE,0x8B,0xFF,0x9F,0xFE,0x81,0xFE, + 0xBB,0xFF,0x02,0xFF,0x46,0xFF,0x99,0xFF,0x31,0xFF,0xEC,0xFF, + 0xCD,0xFF,0x6F,0x00,0xD0,0xFF,0x8F,0xFF,0x33,0x01,0x0E,0x00, + 0x11,0xFF,0x6F,0xFF,0x0E,0x02,0xBB,0x03,0x38,0x01,0x65,0xFD, + 0x67,0xFC,0x04,0x01,0x15,0x04,0x51,0x02,0xD5,0xFF,0xAD,0x00, + 0xD2,0x00,0x37,0xFF,0x0F,0x01,0x27,0x02,0x1F,0x01,0xA4,0x00, + 0xF0,0xFF,0x0D,0xFF,0xA3,0xFE,0x29,0xFF,0x03,0xFF,0x8C,0xFE, + 0xFC,0xFE,0xE1,0xFE,0x66,0xFF,0xAE,0xFF,0x47,0xFF,0xD8,0xFE, + 0x96,0xFE,0x5F,0xFF,0xE9,0x00,0x9B,0x00,0x39,0xFE,0x96,0xFE, + 0xCE,0x00,0x3F,0x01,0xD7,0xFF,0xB0,0xFF,0x20,0x01,0xF7,0x00, + 0x48,0x00,0xEC,0xFF,0x44,0x01,0x92,0x00,0x8D,0xFF,0xCD,0x01, + 0x05,0x01,0xDD,0x00,0x9F,0x00,0x41,0xFF,0x75,0x00,0x70,0x01, + 0xAE,0x00,0x8F,0xFF,0xD0,0xFF,0xB0,0xFF,0xBF,0xFF,0x8C,0xFF, + 0x65,0xFE,0x60,0x00,0x1B,0x00,0xCC,0xFE,0x37,0x00,0xFA,0xFE, + 0x8E,0xFE,0x92,0xFF,0x91,0x00,0xBD,0x00,0xAB,0xFE,0x3C,0xFF, + 0x56,0x00,0x99,0xFF,0xB1,0x00,0x2E,0xFF,0x4A,0xFF,0x6B,0x00, + 0x89,0xFF,0x4E,0x01,0x83,0x00,0x50,0xFF,0xAF,0x00,0x36,0x00, + 0xF1,0xFF,0x2E,0x01,0x0D,0x00,0x57,0x00,0xAE,0x00,0xD7,0xFF, + 0x08,0x00,0xF6,0x00,0x7E,0x00,0x79,0xFF,0xA6,0x00,0x7A,0xFF, + 0x70,0x00,0x82,0x00,0x7E,0xFE,0xAD,0x00,0x19,0x00,0xC6,0xFE, + 0x77,0x00,0xD4,0xFF,0x24,0xFF,0xEA,0xFF,0x67,0x00,0xDB,0xFF, + 0x2D,0xFF,0xF6,0xFF,0x7B,0x00,0x1A,0x00,0x51,0xFF,0x34,0xFF, + 0xCC,0xFF,0x95,0x00,0x4F,0x00,0x95,0xFF,0x8A,0xFF,0x32,0xFF, + 0x2C,0x00,0xBB,0x00,0x8F,0x00,0xB2,0xFF,0x4D,0xFF,0xAB,0x01, + 0x00,0x00,0x93,0xFF,0x78,0x01,0x5D,0x00,0xE5,0xFF,0x43,0x00, + 0xE4,0xFF,0x3A,0x00,0x19,0x00,0x84,0xFF,0xB0,0x00,0x2D,0xFF, + 0x9A,0xFF,0x08,0x00,0x21,0x00,0xCB,0x00,0x01,0xFF,0x16,0xFF, + 0xA0,0x00,0xE4,0x00,0x98,0xFF,0x62,0xFF,0x29,0x00,0x37,0x00, + 0x9A,0xFF,0xCF,0xFF,0xBF,0xFF,0x63,0x00,0xF7,0xFF,0x00,0xFF, + 0x81,0xFF,0x1D,0x01,0x39,0x00,0x88,0xFF,0xD6,0x00,0x38,0xFF, + 0xDD,0xFF,0xED,0x00,0x8D,0xFF,0xBC,0xFF,0x56,0x00,0xF8,0xFF, + 0x75,0x00,0xDE,0xFF,0x5B,0xFF,0x57,0xFF,0xB2,0x00,0xB1,0x00, + 0x9C,0xFF,0xAE,0x00,0xD5,0xFF,0xF8,0xFF,0x1B,0x00,0xA8,0xFF, + 0xF2,0x00,0x30,0x00,0xCD,0xFE,0x3B,0x00,0x8C,0x00,0x10,0xFF, + 0x5F,0x00,0x8C,0x00,0x66,0xFF,0xAA,0x00,0xE5,0xFF,0xE1,0xFF, + 0xE7,0xFF,0x75,0xFF,0xBA,0x00,0x00,0x00,0xAD,0xFF,0x6D,0x00, + 0xA4,0xFF,0x7A,0xFF,0xF0,0xFF,0x96,0xFF,0x91,0xFF,0x4F,0x00, + 0x71,0x00,0x86,0xFF,0x98,0x00,0x08,0x00,0xD2,0xFF,0xC4,0x00, + 0x9F,0xFF,0xDB,0xFF,0x48,0x00,0x74,0x00,0x24,0x00,0x95,0xFF, + 0x29,0xFF,0x14,0x00,0x9F,0x00,0xBA,0xFF,0xC3,0x00,0xC8,0xFE, + 0xF2,0xFE,0xEE,0x01,0x57,0xFF,0x90,0x00,0x72,0x01,0xE8,0xFE, + 0x0B,0xFF,0x05,0x00,0x18,0x01,0x0F,0x00,0x80,0xFF,0xE2,0xFF, + 0xAC,0xFF,0x79,0xFF,0x72,0x00,0x4F,0x00,0x04,0x00,0xA2,0xFF, + 0x36,0x00,0xA4,0x00,0xC6,0xFE,0xC0,0x00,0x48,0x00,0x7A,0xFF, + 0x05,0x00,0x4A,0xFF,0x9E,0x00,0x64,0x00,0x88,0xFF,0xD4,0xFF, + 0xE5,0x00,0xC0,0xFF,0x7E,0xFF,0xC3,0x00,0xC4,0xFF,0x52,0x00, + 0x47,0x00,0x60,0xFF,0xCB,0x00,0x9F,0xFF,0x2B,0xFF,0xB6,0x00, + 0xC1,0xFF,0xA0,0xFF,0xDF,0xFF,0xF3,0xFE,0x22,0x00,0x58,0x01, + 0xAC,0xFF,0x6C,0x00,0x67,0x00,0x84,0xFF,0x57,0x00,0x6B,0x00, + 0xFC,0xFF,0xAF,0xFF,0xE0,0xFF,0xD9,0xFF,0xE4,0xFF,0x5D,0xFF, + 0x77,0xFF,0x1E,0x00,0x97,0x00,0x5B,0xFF,0xB5,0xFF,0x02,0x01, + 0xF7,0xFF,0x4F,0x00,0x51,0x00,0x4F,0x00,0x27,0x00,0xB7,0xFF, + 0xFE,0xFF,0x3D,0x00,0xB4,0xFF,0x0E,0xFF,0xDF,0xFF,0x01,0x00, + 0x35,0x00,0x0C,0x00,0x68,0x00,0xA1,0x00,0x4C,0xFF,0x21,0x00, + 0x5D,0x00,0x0C,0xFF,0x89,0x00,0x2A,0x01,0xC5,0xFE,0xC3,0xFF, + 0xF2,0xFF,0xA8,0xFF,0x01,0x01,0x77,0xFF,0x15,0x00,0xFA,0xFF, + 0xC2,0xFF,0x98,0xFF,0x97,0x00,0xF1,0x00,0xC6,0xFF,0xC3,0x00, + 0x26,0xFF,0x3A,0xFF,0x06,0x01,0xE3,0xFF,0xE3,0xFE,0xD9,0xFF, + 0xD1,0xFF,0x9A,0x00,0x11,0xFF,0x27,0x00,0x70,0x01,0x7B,0xFF, + 0x27,0x00,0x6D,0x00,0xCD,0x00,0x85,0xFF,0x07,0x00,0xC4,0xFF, + 0xE4,0xFE,0xDE,0x00,0xB0,0xFF,0x0B,0xFF,0x6E,0x00,0xB9,0x00, + 0xE9,0xFF,0x29,0xFF,0x69,0x00,0x3C,0x00,0x79,0x00,0x82,0x00, + 0x4E,0xFF,0x4D,0x00,0x87,0x00,0x48,0xFF,0x48,0xFF,0x7A,0x00, + 0x4D,0xFF,0x54,0x00,0x8A,0x00,0x7D,0xFE,0xF1,0x00,0x98,0x00, + 0x0E,0xFF,0x1E,0x00,0x1C,0x00,0x6C,0x00,0x3A,0x00,0x93,0xFF, + 0xC0,0x00,0x4B,0x00,0xF7,0xFF,0xD0,0xFF,0x15,0xFF,0x70,0x00, + 0x26,0xFF,0x27,0x00,0x22,0x00,0xD3,0xFF,0x77,0x01,0xF2,0xFE, + 0x3E,0x00,0x5D,0x00,0xAA,0xFF,0xCC,0x00,0x32,0x00,0xBD,0xFF, + 0x24,0xFF,0x5C,0xFF,0x2D,0x00,0x70,0x00,0xC4,0xFF,0x62,0x00, + 0x5E,0x00,0x82,0xFF,0x8F,0xFF,0x56,0x00,0x55,0x01,0xEE,0xFF, + 0x06,0xFF,0x6A,0x00,0xCD,0xFF,0xA3,0xFF,0xE8,0xFF,0x39,0x00, + 0x15,0x00,0x30,0xFF,0x00,0x00,0xD0,0xFF,0x58,0x00,0x8D,0x00, + 0xA5,0xFF,0x8E,0x00,0x1D,0x01,0x35,0xFF,0x76,0xFF,0x85,0x00, + 0xA3,0xFF,0x8D,0xFF,0x93,0xFF,0x5D,0x00,0xFC,0xFF,0x6F,0xFF, + 0xD8,0x00,0x33,0x00,0xB6,0xFF,0xA1,0x00,0x12,0x00,0xB9,0xFF, + 0xA7,0xFF,0x56,0x00,0x44,0x00,0x57,0xFF,0x61,0x00,0xE7,0xFF, + 0x24,0xFF,0x6E,0x00,0xF9,0xFF,0x06,0x00,0x37,0x00,0xFF,0xFF, + 0x09,0x00,0x03,0x00,0x6B,0x00,0x1C,0x00,0xF6,0xFF,0xC2,0xFF, + 0xBB,0x00,0xC3,0xFF,0xDF,0xFE,0x2E,0x00,0x95,0x00,0x8D,0xFF, + 0x73,0xFF,0xC9,0x00,0xF2,0xFF,0x93,0xFF,0xF7,0xFF,0xB1,0x00, + 0x84,0x00,0x8C,0xFF,0xC2,0xFF,0xF8,0xFF,0x4C,0x00,0x73,0xFF, + 0xBE,0xFF,0x29,0x00,0x15,0x00,0x40,0x00,0x50,0xFF,0x4A,0x00, + 0x84,0x00,0x9B,0x00,0x19,0x00,0x9A,0xFE,0x9D,0x00,0x90,0x00, + 0x30,0xFF,0x3B,0x00,0xFF,0xFF,0x93,0xFF,0xB8,0xFF,0xD6,0xFF, + 0xD2,0x00,0x76,0x00,0x4A,0xFF,0x80,0x00,0xF3,0xFF,0xA5,0xFF, + 0xA4,0x00,0x9E,0xFF,0xD9,0xFF,0x51,0x00,0xE9,0xFF,0xC1,0xFF, + 0xFF,0xFF,0xCF,0xFF,0x03,0x00,0x09,0x00,0x35,0x00,0xDB,0xFF, + 0xE0,0xFF,0x5E,0x00,0x0F,0x00,0x25,0x00,0xCB,0xFF,0x6E,0x00, + 0x9F,0xFF,0x80,0xFF,0x93,0x00,0xD9,0xFF,0x61,0xFF,0xF5,0xFF, + 0xF3,0x00,0xAB,0x00,0x8B,0xFF,0xDB,0xFE,0x68,0xFF,0x45,0x00, + 0xF6,0x00,0xDF,0xFF,0x4D,0xFF,0x3A,0x00,0x90,0x00,0xA9,0x00, + 0x78,0xFF,0xFD,0xFF,0x8B,0x00,0x74,0xFF,0xD6,0xFF,0x64,0x00, + 0xE2,0xFF,0x4D,0x00,0x12,0x00,0x81,0xFF,0x2E,0x00,0xAD,0xFF, + 0xB0,0xFF,0x2A,0x00,0xFE,0xFF,0xEC,0xFF,0x17,0x00,0x01,0x00, + 0xF8,0xFF,0x24,0x00,0x00,0x00,0x3D,0x00,0x05,0x00,0xE7,0xFF, + 0xAE,0xFF,0x45,0x00,0xFE,0xFF,0xC7,0xFF,0x98,0x00,0xC2,0xFF, + 0xB4,0xFF,0x95,0xFF,0x0E,0x00,0x6D,0x00,0xE9,0xFF,0xA8,0xFF, + 0x64,0x00,0x92,0x00,0x00,0x00,0xE9,0xFF,0xF6,0xFF,0x18,0x00, + 0xC3,0xFF,0x19,0x00,0xCE,0xFF,0x1D,0x00,0x29,0xFF,0xAA,0xFF, + 0x08,0x01,0xFE,0xFF,0x9A,0xFF,0x16,0x00,0xA9,0x00,0xFD,0xFF, + 0xDF,0xFF,0xD8,0xFF,0xF2,0x00,0xA2,0xFF,0x1E,0xFF,0x4C,0x00, + 0x9F,0xFF,0x6B,0xFF,0x34,0x00,0xDD,0x00,0xF1,0xFE,0x51,0x00, + 0xD0,0x00,0x96,0xFF,0x38,0x00,0x0C,0x00,0x83,0x00,0x6C,0x00, + 0x77,0xFF,0x4A,0xFF,0x6D,0x00,0x32,0x00,0x0E,0xFF,0xED,0xFF, + 0x2B,0x00,0xBF,0xFF,0x5D,0x00,0x44,0x00,0x98,0xFF,0x31,0x00, + 0xB2,0x00,0x53,0x00,0xCD,0xFF,0x6D,0xFF,0x34,0x00,0x15,0x00, + 0xC2,0xFF,0x4A,0x00,0x81,0xFF,0xE0,0xFF,0x66,0x00,0x8D,0xFF, + 0x9E,0x00,0xC2,0xFF,0x9B,0xFF,0x29,0x00,0x81,0xFF,0x50,0x01, + 0xF0,0xFF,0x14,0xFF,0x41,0x00,0xF4,0xFF,0xFE,0xFF,0xE1,0xFF, + 0xD2,0xFF,0x4D,0x00,0xC8,0x00,0xD5,0xFF,0xC2,0xFF,0x87,0x00, + 0xEB,0xFF,0xE7,0xFF,0xC1,0xFF,0xCA,0xFF,0x91,0xFF,0xC8,0xFF, + 0x90,0x00,0x99,0xFF,0xC0,0xFF,0xC7,0xFF,0x51,0x00,0x7D,0x00, + 0xBB,0x00,0x19,0x00,0x43,0xFF,0xA1,0x00,0xCD,0xFF,0xDD,0xFF, + 0xF4,0xFF,0x3C,0x00,0x25,0x00,0x7C,0xFF,0xF9,0xFF,0x15,0x00, + 0x0F,0x00,0xAB,0xFE,0x28,0x00,0xE2,0x00,0x6C,0xFF,0xA9,0x00, + 0xEE,0xFF,0xE6,0xFF,0x90,0x00,0xB4,0xFF,0xCF,0xFF,0x39,0x00, + 0x15,0x00,0xB1,0xFF,0x39,0x00,0xE9,0xFF,0x20,0x00,0x39,0x00, + 0x8B,0xFF,0xE3,0xFF,0xB1,0x00,0xEE,0xFF,0xA2,0xFF,0xF3,0xFF, + 0xA7,0xFF,0x73,0x00,0x46,0xFF,0xD3,0xFF,0xBA,0x00,0xD8,0xFF, + 0xED,0xFF,0x1B,0x00,0x2A,0x00,0x1A,0x00,0xF8,0xFF,0xEC,0xFF, + 0xA5,0x00,0xB7,0xFF,0xB7,0xFF,0x75,0x00,0x1B,0x00,0x1C,0x00, + 0xD0,0xFF,0x95,0xFF,0x4E,0xFF,0xDD,0xFF,0x76,0x00,0x00,0x00, + 0x9E,0xFF,0x3C,0x00,0x74,0x00,0x4E,0x00,0x8F,0xFF,0xAE,0xFF, + 0x00,0x01,0xA3,0xFF,0xE9,0xFF,0x98,0x00,0x71,0xFF,0xA1,0xFF, + 0x1A,0x00,0x0D,0x00,0x16,0x00,0x01,0x00,0xF6,0xFF,0x32,0x00, + 0x9F,0xFF,0x30,0x00,0x5B,0x00,0x95,0xFF,0xE6,0xFF,0x9B,0xFF, + 0x00,0x00,0xB3,0x00,0x4F,0xFF,0x40,0x00,0xAF,0x00,0x36,0xFF, + 0xCC,0xFF,0xE4,0x00,0x95,0x00,0x01,0xFF,0xEC,0xFF,0xC8,0x00, + 0xAB,0xFF,0xCA,0xFF,0xF3,0x00,0x34,0x00,0x2E,0xFF,0x2A,0xFF, + 0x9D,0xFF,0xB1,0x00,0xB0,0xFF,0x71,0xFF,0x9F,0x00,0xED,0xFF, + 0x00,0x00,0xC4,0x00,0x0C,0x00,0xAD,0xFF,0x52,0x00,0x7A,0xFF, + 0x99,0x00,0xAA,0x00,0xDC,0xFE,0x8A,0x00,0xBC,0xFF,0xFA,0xFF, + 0x2E,0x00,0x6B,0xFF,0x8D,0x00,0x3A,0x00,0xC4,0xFF,0x89,0xFF, + 0xA2,0xFF,0x8A,0xFF,0x5E,0x00,0x99,0x00,0xEE,0xFF,0x6F,0xFF, + 0x0B,0x00,0x41,0x00,0x0B,0x00,0x97,0x00,0x7C,0xFF,0x6E,0x00, + 0xD0,0x00,0x89,0xFF,0xCE,0xFF,0x98,0x00,0xC8,0xFF,0x32,0xFF, + 0x60,0x00,0x75,0xFF,0xE8,0xFF,0x0D,0x00,0xD5,0xFF,0xBE,0x00, + 0x2C,0xFF,0xF5,0xFF,0x7B,0x00,0xDB,0xFF,0x32,0x00,0x0F,0x00, + 0xC8,0x00,0x0A,0x00,0xEA,0xFF,0x6E,0xFF,0xB9,0xFF,0x94,0x00, + 0xB5,0xFE,0x1F,0x00,0x6A,0x00,0xAC,0xFF,0xD9,0x00,0x31,0xFF, + 0x48,0x00,0x58,0x01,0xE8,0xFE,0xA3,0xFF,0x06,0x01,0x6A,0xFF, + 0xE1,0xFF,0x91,0x00,0x63,0xFF,0x34,0x00,0x1D,0x00,0x72,0xFF, + 0xE0,0xFF,0x24,0x00,0xED,0x00,0xE7,0xFF,0x7A,0xFF,0xAD,0x00, + 0x77,0xFF,0x07,0x00,0xDF,0xFF,0x21,0x00,0x1D,0x00,0x24,0xFF, + 0x93,0x00,0x4D,0x00,0x7C,0xFF,0x95,0xFF,0xEC,0x00,0x74,0xFF, + 0x31,0x00,0x42,0x00,0x43,0xFF,0xA9,0x00,0x38,0x00,0xC7,0x00, + 0x23,0xFF,0x9B,0xFF,0xF6,0xFF,0x32,0x00,0x9A,0x00,0xA4,0xFF, + 0xEB,0xFF,0xC8,0xFF,0xBE,0x00,0x7B,0xFF,0xFA,0xFE,0xC8,0x00, + 0xFF,0xFF,0x94,0xFF,0x49,0x01,0x1B,0x00,0xDD,0xFE,0x4C,0x00, + 0x3A,0x01,0x26,0x00,0x6A,0xFE,0xD3,0xFE,0xE0,0x00,0xB0,0x00, + 0x86,0xFF,0x75,0xFF,0xD4,0xFF,0xCE,0x00,0xAC,0xFF,0x32,0x00, + 0xDA,0x00,0xBF,0xFF,0x72,0x00,0xE1,0xFF,0xFC,0xFF,0x61,0x00, + 0x22,0xFF,0x85,0xFF,0xF4,0x00,0x0D,0x00,0x0C,0xFF,0xF8,0xFF, + 0xEF,0xFF,0x88,0xFF,0xA5,0x00,0x94,0x00,0x50,0xFF,0x49,0x00, + 0x40,0x00,0xC0,0x00,0x43,0x00,0x3F,0xFE,0x04,0x01,0x0F,0x00, + 0x05,0xFF,0xB7,0x00,0x0F,0x00,0x80,0x00,0xE0,0xFE,0xDA,0xFF, + 0xF0,0x00,0x5A,0xFF,0xD0,0xFF,0x8A,0xFF,0xE1,0xFF,0xBF,0x00, + 0x95,0x00,0x8C,0x00,0x83,0xFF,0x6A,0xFF,0x2B,0x00,0x08,0x00, + 0x6E,0x00,0x34,0x00,0x48,0xFF,0x9B,0xFF,0x35,0x01,0xC3,0xFF, + 0x23,0xFF,0x81,0xFF,0x98,0x00,0x7C,0x00,0x2D,0xFF,0x9C,0x00, + 0x7E,0xFF,0x13,0x01,0x6E,0x00,0xB4,0xFE,0xF1,0xFF,0x96,0x00, + 0x10,0x00,0x04,0xFF,0x4C,0x01,0xB5,0x00,0x8B,0xFF,0x02,0xFF, + 0x1A,0x00,0x79,0x00,0xB6,0xFF,0xA6,0xFF,0x8B,0xFE,0x06,0x01, + 0xF5,0xFF,0x0F,0x00,0x0B,0x00,0x5A,0x00,0x53,0x01,0x30,0xFF, + 0xAE,0x00,0xCC,0xFF,0xC9,0xFF,0xCF,0xFF,0xAE,0xFF,0x83,0xFF, + 0x47,0xFF,0x46,0x00,0x31,0x00,0xA6,0x00,0xC6,0x00,0x5D,0xFF, + 0xF1,0xFE,0xC7,0x01,0x05,0x01,0x92,0xFE,0xBB,0xFF,0xE2,0x01, + 0xB9,0xFE,0x0C,0xFE,0xA0,0x00,0x87,0xFF,0xD8,0xFF,0x98,0x00, + 0xF5,0xFF,0x50,0xFF,0x4C,0x02,0x30,0x00,0x06,0xFF,0x78,0x00, + 0x19,0x00,0x05,0x01,0xA7,0xFE,0xB3,0x00,0x00,0x01,0x7C,0xFE, + 0x50,0xFE,0x44,0xFF,0x37,0x00,0xC9,0xFF,0x2D,0x00,0x84,0x00, + 0x4C,0x00,0xC3,0x00,0xCF,0x00,0xF8,0xFF,0x28,0x00,0xE3,0xFF, + 0xC0,0xFF,0x3F,0x00,0xB3,0xFF,0xE1,0xFF,0x71,0x01,0x76,0xFF, + 0x4E,0xFF,0x97,0xFF,0xBD,0xFE,0x79,0x00,0x03,0x00,0xFC,0xFE, + 0x88,0x00,0x4F,0x00,0x12,0x00,0x77,0x01,0xB5,0xFF,0xDD,0xFF, + 0xF0,0x00,0x9A,0x00,0x04,0xFF,0xB4,0xFF,0xE8,0xFF,0x89,0xFF, + 0xBA,0xFF,0xCD,0xFF,0xF6,0x00,0x5F,0xFF,0xC8,0xFF,0xCA,0xFF, + 0x30,0x00,0x05,0x00,0xA0,0xFF,0xD4,0xFF,0xF6,0xFF,0x2C,0x01, + 0x70,0x00,0xD9,0xFF,0x92,0xFF,0xBD,0x00,0xFC,0xFF,0x7E,0xFF, + 0xB5,0x00,0xA5,0xFF,0xE4,0xFF,0xB7,0xFF,0xD7,0xFF,0xE2,0xFF, + 0x8F,0xFF,0x88,0x00,0x5E,0xFF,0x9C,0xFF,0xB8,0x00,0x53,0x00, + 0x72,0xFF,0xF1,0xFF,0x46,0x01,0x70,0xFF,0xBA,0xFF,0x9D,0x00, + 0xD5,0xFF,0x4B,0x00,0xDA,0xFF,0x66,0xFF,0xF3,0xFF,0xC3,0x00, + 0xA6,0xFF,0xF5,0xFF,0x96,0xFF,0x7D,0xFF,0x08,0x01,0xD4,0xFF, + 0xAB,0xFF,0xB7,0xFF,0x8B,0x00,0xC8,0xFF,0x02,0x00,0x64,0x00, + 0x5C,0xFF,0x88,0x00,0xB9,0xFF,0x2F,0x00,0x58,0x00,0x1E,0x00, + 0x30,0x00,0x46,0xFF,0x1E,0x00,0x87,0x00,0xF5,0xFF,0x94,0xFF, + 0x27,0x00,0x5B,0x00,0x85,0xFF,0x6D,0xFF,0x4D,0x00,0x19,0x00, + 0x1D,0x00,0xC0,0xFF,0x6A,0xFF,0x7D,0x00,0x2C,0x00,0xF5,0xFF, + 0xE9,0xFF,0xEE,0xFF,0x20,0x00,0x5E,0x00,0xB3,0xFF,0xBC,0xFF, + 0xB4,0x00,0x2C,0x00,0xAB,0xFF,0xAD,0xFF,0x73,0x00,0x4C,0x00, + 0x13,0x00,0x01,0x00,0x88,0xFF,0xD1,0xFF,0x32,0x00,0x99,0x00, + 0xAA,0xFF,0x5F,0xFF,0x1A,0x00,0x0A,0x00,0x37,0x00,0xE8,0xFF, + 0x94,0xFF,0xAC,0xFF,0xF8,0xFF,0x54,0x00,0xC4,0xFF,0x63,0xFF, + 0x08,0x00,0x17,0x00,0x23,0x00,0x4A,0x00,0xE1,0xFF,0x2C,0x00, + 0x69,0x00,0x7A,0x00,0x96,0x00,0x42,0x00,0x05,0x00,0x3E,0x00, + 0xF2,0xFF,0x37,0x00,0x86,0x00,0x1A,0x00,0x25,0x00,0xC5,0xFF, + 0x0B,0x00,0x05,0x00,0xBC,0xFF,0xAF,0xFF,0x55,0xFF,0x56,0xFF, + 0x33,0xFF,0x4B,0xFF,0x77,0xFF,0xE3,0xFE,0xB1,0xFE,0xE1,0xFE, + 0xC0,0xFE,0x5B,0xFF,0x1C,0xFF,0x7B,0xFF,0x53,0x01,0x9D,0x01, + 0x38,0x01,0xD6,0x00,0x1F,0x03,0x48,0x05,0x13,0x03,0xE5,0x01, + 0x14,0x02,0xE4,0x01,0x9A,0x00,0xB4,0xFF,0x96,0xFF,0xD7,0xFD, + 0x0C,0xFD,0x05,0xFD,0xDC,0xFC,0x58,0xFC,0x8E,0xFC,0x72,0xFD, + 0x35,0xFE,0x36,0xFF,0x48,0xFF,0xBE,0xFF,0x47,0x00,0xB0,0x00, + 0xF4,0x00,0x16,0x01,0x92,0x01,0x17,0x01,0xED,0xFF,0xBF,0xFF, + 0xA2,0x00,0x5C,0x00,0x2A,0x00,0xBC,0xFF,0x1D,0x01,0x4D,0x05, + 0x80,0x05,0x85,0x02,0x42,0x01,0xC7,0x03,0xC6,0x03,0x60,0x00, + 0x81,0xFF,0x28,0xFF,0x33,0xFE,0x84,0xFC,0x23,0xFD,0xFE,0xFB, + 0xF1,0xF8,0xAE,0xFB,0x17,0xFE,0x04,0xFD,0x59,0xFD,0x0D,0x00, + 0x99,0x00,0xB4,0xFF,0x5F,0x01,0x74,0x02,0x66,0x01,0xCB,0x00, + 0xAB,0x01,0xDC,0x00,0x2E,0x00,0xD1,0x00,0x38,0xFD,0xE0,0xFB, + 0xAE,0xFB,0x16,0x00,0x06,0x05,0x4E,0x02,0xB3,0x08,0x8A,0x08, + 0x97,0x05,0xB9,0x05,0xB1,0x05,0xEB,0x06,0x35,0xFF,0xAB,0xFF, + 0x02,0xFD,0xB4,0xF9,0x39,0xF8,0x36,0xF6,0xFB,0xF6,0x40,0xF4, + 0xCE,0xF9,0xED,0xFB,0x8C,0xFD,0xBF,0xFE,0x37,0x01,0xE7,0x05, + 0x99,0x04,0x93,0x06,0xB0,0x05,0xEB,0x05,0xEC,0x05,0x08,0x04, + 0x67,0x01,0x39,0xFE,0x3D,0xFF,0x13,0xFD,0x5B,0xFB,0x69,0xFA, + 0xB5,0xFA,0xA1,0xFA,0x68,0xFB,0xDC,0xFE,0x63,0xFF,0x8D,0xFF, + 0x84,0x08,0x39,0x12,0x00,0x09,0xAF,0x03,0x4C,0x09,0x99,0x0B, + 0x3F,0x04,0xF6,0xFC,0x75,0xFD,0x38,0xF8,0x50,0xF7,0x5A,0xF6, + 0x88,0xF2,0xD0,0xF0,0x5A,0xF6,0xB0,0xFD,0x4B,0xFA,0xBB,0xFB, + 0xCE,0x03,0xBF,0x07,0x82,0x06,0xC1,0x07,0x10,0x0A,0x5E,0x08, + 0x2D,0x06,0x34,0x04,0x4A,0x00,0xCD,0xFD,0xD1,0xFD,0x08,0xFA, + 0xDF,0xF6,0x64,0xF8,0xD5,0xFA,0xDE,0xF3,0x1C,0xF3,0x82,0x03, + 0x4B,0x0B,0x9B,0x0E,0x51,0x0A,0x1D,0x0A,0x55,0x12,0xE3,0x11, + 0x14,0x0D,0xDB,0xFF,0xAA,0xFF,0x4F,0xFF,0x61,0xF8,0x6D,0xEF, + 0x81,0xE9,0xDC,0xEE,0x01,0xEF,0xB2,0xF1,0xFF,0xF0,0xD8,0xF7, + 0x55,0x02,0xC4,0x07,0x30,0x0A,0x56,0x0A,0x31,0x10,0x7B,0x11, + 0x9D,0x10,0xB8,0x0A,0xB7,0x04,0x55,0x03,0x2B,0x00,0xDC,0xF8, + 0x03,0xF3,0xCE,0xF3,0x4F,0xF3,0x0A,0xF3,0xAB,0xF4,0xCE,0xF7, + 0x5F,0xF9,0x50,0xFA,0xA8,0x01,0x57,0x07,0xA8,0x16,0xEA,0x1C, + 0x62,0x0D,0x17,0x0E,0x11,0x16,0x61,0x12,0x1D,0x00,0x4C,0xF9, + 0xC8,0xF9,0xBA,0xF1,0x68,0xEE,0x53,0xE7,0xB0,0xE5,0x86,0xEA, + 0x14,0xF5,0xF5,0xF4,0xEF,0xF4,0x79,0x03,0xE8,0x0D,0xB3,0x12, + 0xF7,0x0C,0xA1,0x10,0xCA,0x14,0x89,0x11,0x03,0x0D,0x96,0x02, + 0xDE,0xFD,0xCC,0xFA,0x13,0xF8,0x5D,0xEF,0x92,0xED,0x97,0xF2, + 0xB6,0xF3,0xCA,0xF3,0xC0,0xF5,0x3B,0xFB,0x5A,0xF9,0x5C,0x06, + 0x1D,0x11,0x2B,0x1C,0xBA,0x1A,0x29,0x0E,0xC7,0x18,0xF5,0x15, + 0xEB,0x0D,0x06,0xFC,0x4B,0xF8,0x82,0xF6,0xD9,0xEC,0x3A,0xE9, + 0x92,0xDF,0x5F,0xE6,0x76,0xEB,0x40,0xF3,0x16,0xF3,0x26,0xFB, + 0x35,0x0A,0x3B,0x10,0xDE,0x12,0xFF,0x14,0x24,0x18,0xA5,0x12, + 0xAE,0x12,0x6B,0x0A,0x28,0x02,0x9B,0xF9,0xFE,0xF7,0x7E,0xF2, + 0x05,0xEA,0x2A,0xEE,0xFB,0xEE,0x73,0xF2,0x2F,0xF5,0x67,0xFB, + 0xF0,0xFD,0xCE,0xFE,0xED,0x00,0x57,0x0D,0x37,0x1C,0x5C,0x21, + 0x2E,0x13,0x42,0x0C,0xE2,0x19,0x04,0x11,0x47,0x00,0x2B,0xF3, + 0xAF,0xF4,0xDB,0xF0,0x65,0xE9,0x86,0xE3,0xD5,0xDF,0x1D,0xED, + 0x97,0xF4,0xC6,0xF5,0x07,0xF6,0x09,0x07,0x14,0x14,0x4D,0x13, + 0x6B,0x13,0x1D,0x16,0xEE,0x14,0xA9,0x10,0xBD,0x0B,0xB2,0xFE, + 0xD3,0xF8,0xF8,0xF8,0x54,0xF3,0xCE,0xE9,0xF8,0xEC,0x7B,0xF3, + 0x03,0xF3,0xA3,0xF5,0x82,0xFB,0xF3,0xFF,0x14,0x03,0x40,0x00, + 0xCB,0x06,0xF6,0x12,0xB2,0x20,0x9B,0x1D,0xF1,0x05,0xCE,0x10, + 0x57,0x16,0x57,0x08,0xC1,0xF4,0xE5,0xF0,0xDE,0xF4,0xBF,0xEC, + 0x20,0xEA,0x07,0xDF,0x74,0xE7,0xEF,0xF4,0x34,0xFA,0x4B,0xF5, + 0x3B,0xFD,0x99,0x11,0x5E,0x15,0x8E,0x13,0xD2,0x10,0xA1,0x14, + 0x24,0x11,0x36,0x0E,0xBF,0x01,0x15,0xF8,0x13,0xF9,0x0C,0xF6, + 0xFC,0xEE,0x46,0xEA,0xB3,0xF2,0x1C,0xF5,0x72,0xF6,0xF5,0xF9, + 0xAF,0x00,0x7E,0x04,0x55,0x04,0x48,0x00,0xCC,0x05,0x85,0x19, + 0x44,0x21,0xB0,0x10,0x7E,0x02,0x22,0x14,0x6C,0x12,0xBF,0xFE, + 0x6C,0xF1,0x8E,0xF1,0x40,0xF5,0xEB,0xEE,0x50,0xE7,0x53,0xE0, + 0x7C,0xF0,0x3D,0xFC,0xAC,0xF8,0xDA,0xF5,0xFD,0x04,0x5E,0x15, + 0x69,0x13,0xA8,0x10,0xA4,0x0F,0x10,0x11,0x80,0x0F,0xDE,0x08, + 0x21,0xFA,0x34,0xF6,0x6F,0xFA,0x94,0xF4,0xA1,0xEB,0x42,0xEE, + 0x6E,0xF7,0x6D,0xF8,0xAE,0xF8,0xEC,0xFC,0x2D,0x02,0xDE,0x05, + 0x39,0x02,0xAB,0x01,0x76,0x0B,0xAE,0x1B,0x77,0x1F,0x52,0x05, + 0x2C,0x07,0x11,0x16,0x31,0x0B,0x34,0xF8,0x02,0xEF,0x5B,0xF5, + 0x3B,0xF2,0xCE,0xEE,0xC2,0xE2,0x33,0xE5,0x9F,0xF7,0x39,0xFD, + 0x5C,0xF7,0x47,0xF9,0x11,0x0E,0x19,0x15,0xCC,0x12,0x57,0x0F, + 0xD2,0x0E,0xB3,0x0F,0xFE,0x0D,0xBF,0x01,0x09,0xF5,0x38,0xF8, + 0x1C,0xF9,0xB1,0xF0,0x5F,0xEB,0x67,0xF3,0x2D,0xF9,0xBF,0xF9, + 0x48,0xFB,0xDE,0xFF,0xED,0x04,0xE7,0x05,0x42,0xFF,0xCB,0x04, + 0x08,0x14,0xED,0x1D,0xA1,0x13,0xFC,0x00,0xD7,0x0F,0x7D,0x11, + 0x20,0x02,0x67,0xF2,0x59,0xF0,0x46,0xF6,0xFD,0xF0,0x86,0xEA, + 0x80,0xE1,0x0C,0xF0,0x4D,0xFC,0x41,0xFB,0x84,0xF7,0x7F,0x02, + 0x7B,0x13,0x2D,0x14,0x75,0x11,0x9B,0x0C,0xB1,0x0D,0xFC,0x0E, + 0x7C,0x08,0x25,0xF9,0xF7,0xF3,0xA1,0xF9,0x6F,0xF6,0x7A,0xED, + 0x90,0xEE,0x40,0xF8,0x7B,0xFB,0x2C,0xFB,0xE5,0xFD,0xED,0x00, + 0xD1,0x07,0xCA,0x01,0xBE,0xFC,0x52,0x10,0xB6,0x20,0x40,0x17, + 0x92,0x00,0x47,0x0D,0x38,0x15,0x44,0x06,0x80,0xF7,0x0F,0xEE, + 0x02,0xF5,0x39,0xF5,0x04,0xED,0x02,0xDF,0x9C,0xEA,0x64,0xFC, + 0x02,0xFB,0xFA,0xF6,0xF6,0xFD,0xFB,0x0F,0x9F,0x15,0xFA,0x12, + 0xBC,0x0C,0xB1,0x0D,0x5E,0x11,0xCE,0x09,0x5C,0xFB,0x78,0xF5, + 0x43,0xF8,0xD8,0xF6,0xF2,0xEE,0x33,0xED,0xC2,0xF5,0xD7,0xFB, + 0x84,0xFB,0x3B,0xFC,0xFD,0x01,0x32,0x06,0x3B,0x06,0xDA,0xFD, + 0x7C,0x05,0x8C,0x1E,0xBA,0x1E,0xEA,0x02,0xA2,0x05,0x62,0x16, + 0xC2,0x07,0x8B,0xFA,0xBA,0xF1,0x15,0xF1,0x42,0xF5,0xEF,0xF2, + 0x14,0xE4,0xA3,0xE4,0x1F,0xFB,0x0C,0xFE,0xF6,0xF7,0xE2,0xFB, + 0x1F,0x0B,0xDA,0x13,0xC1,0x13,0xCE,0x0D,0xC2,0x09,0x12,0x0F, + 0x1C,0x0C,0xA7,0xFD,0x2B,0xF5,0xE4,0xF7,0xB0,0xF7,0xA8,0xF1, + 0x9B,0xEE,0x51,0xF4,0x08,0xFC,0xC7,0xFD,0x8A,0xFC,0x68,0x00, + 0xFF,0x05,0x52,0x05,0x0E,0x00,0xC4,0x02,0xCF,0x16,0x34,0x20, + 0x77,0x08,0x4A,0x01,0x96,0x12,0x38,0x0E,0x59,0xFD,0x75,0xF2, + 0x55,0xEF,0xEC,0xF4,0x72,0xF6,0xDB,0xE6,0x19,0xE3,0x27,0xF6, + 0x12,0x00,0x7A,0xFA,0x34,0xFA,0x06,0x07,0xFD,0x12,0xDC,0x15, + 0x25,0x0F,0x1B,0x08,0x90,0x0C,0x9E,0x0E,0x61,0x00,0x08,0xF4, + 0x95,0xF5,0x3D,0xF9,0x68,0xF3,0x56,0xEE,0x46,0xF3,0x4D,0xFB, + 0xCA,0xFE,0x88,0xFD,0xD0,0xFD,0x36,0x06,0x9E,0x04,0x31,0xFC, + 0x37,0x09,0x64,0x1A,0xA6,0x19,0x3F,0x06,0x59,0x07,0xB0,0x11, + 0x97,0x0A,0xD2,0xFE,0x0D,0xF1,0xC4,0xF3,0xD5,0xF7,0xC8,0xF1, + 0x59,0xE5,0x20,0xE8,0xC5,0xF7,0xFE,0xFA,0x6C,0xF9,0x05,0xFB, + 0xD5,0x07,0x72,0x12,0x61,0x12,0x86,0x0C,0x70,0x0B,0xC0,0x10, + 0xA4,0x09,0x58,0xFE,0xE9,0xF8,0xD9,0xF7,0xA0,0xF7,0x39,0xF2, + 0x3E,0xF0,0xE3,0xF4,0x41,0xFC,0x6C,0xFC,0xA5,0xFC,0x6D,0x00, + 0x2B,0x04,0x6D,0x05,0x60,0xFE,0x56,0x04,0xE0,0x18,0x6A,0x1E, + 0x48,0x08,0xB8,0x02,0x1E,0x0F,0xF7,0x0C,0xEF,0xFD,0x3B,0xEF, + 0xF1,0xF1,0xB9,0xF6,0x26,0xF4,0x94,0xE7,0x47,0xE7,0xD8,0xF7, + 0x30,0xFF,0x17,0xFC,0x1F,0xFB,0x0E,0x08,0x2A,0x13,0xB1,0x14, + 0x16,0x0C,0xAC,0x05,0x54,0x0D,0x25,0x0C,0xAB,0xFC,0x2C,0xF3, + 0x21,0xF8,0xEA,0xF8,0x3D,0xF3,0x66,0xF1,0x8E,0xF5,0x70,0xFD, + 0xB6,0xFF,0xE4,0xFE,0x55,0xFC,0xBF,0x04,0x11,0x04,0x9B,0xFC, + 0xC4,0x09,0x7E,0x1A,0x7B,0x16,0x9B,0x04,0xE2,0x0C,0xA8,0x10, + 0x2A,0x08,0x0B,0xFF,0xB2,0xF1,0xC5,0xF3,0xA7,0xF6,0xA0,0xEF, + 0xC1,0xE4,0x58,0xEC,0xD8,0xF6,0x3B,0xF8,0xC8,0xFA,0xA4,0xFD, + 0x97,0x08,0xAA,0x11,0xAE,0x13,0x60,0x0B,0x31,0x09,0x76,0x10, + 0x50,0x09,0x5B,0xFD,0x78,0xF7,0x43,0xF9,0x08,0xF8,0x61,0xF3, + 0x24,0xF2,0x6E,0xF6,0x45,0xFD,0x4A,0xFD,0xCD,0xFC,0xE1,0xFE, + 0x63,0x06,0x93,0x00,0xF8,0xFF,0xA0,0x0B,0x63,0x13,0xAF,0x15, + 0x33,0x05,0x7B,0x07,0xF0,0x0E,0xE9,0x07,0x88,0xFC,0xD3,0xF4, + 0x1D,0xF8,0x66,0xF6,0x1D,0xF3,0x45,0xEB,0xED,0xEE,0x5D,0xF9, + 0x6B,0xFA,0xF4,0xF9,0xAA,0xFD,0x30,0x07,0x60,0x0D,0xB1,0x0D, + 0x92,0x05,0xFD,0x07,0x22,0x0E,0x1B,0x04,0xB0,0xFC,0xB9,0xFB, + 0x88,0xFB,0xB3,0xF9,0x78,0xF7,0x10,0xF6,0xE5,0xF9,0xAB,0xFF, + 0x0C,0xFF,0x88,0xFA,0x35,0xFC,0xCD,0x02,0xB3,0xFD,0x73,0xFF, + 0xE6,0x0B,0xAB,0x15,0x6B,0x10,0xF5,0x07,0xDD,0x0E,0xF8,0x0C, + 0x1B,0x08,0x74,0xFE,0xFE,0xF5,0xB5,0xF7,0x5D,0xF5,0x0C,0xEF, + 0x07,0xEA,0x37,0xF0,0xFE,0xF4,0x0B,0xF7,0x1F,0xFA,0x8A,0xFE, + 0x99,0x07,0x1E,0x0E,0x9C,0x0B,0xB3,0x07,0xE5,0x0E,0x11,0x0C, + 0xE0,0x03,0x3C,0x01,0xBC,0xFC,0xE4,0xFB,0xA0,0xF9,0x90,0xF6, + 0x89,0xF5,0x47,0xFA,0x17,0xFE,0xC3,0xFA,0x2C,0xF7,0x0F,0xFF, + 0xA0,0x01,0xF4,0xFA,0x09,0x03,0x8F,0x0F,0xDD,0x17,0x81,0x0D, + 0x68,0x09,0x60,0x11,0xDE,0x0C,0x42,0x06,0x42,0xFB,0x81,0xF6, + 0x33,0xF7,0x7E,0xF4,0x88,0xEB,0x73,0xEA,0xCD,0xF2,0xF4,0xF4, + 0x5F,0xF7,0x5E,0xFA,0xCA,0x00,0x13,0x0A,0x0D,0x0E,0x7B,0x07, + 0xF1,0x09,0x49,0x0F,0xC3,0x07,0xA8,0x04,0x73,0xFF,0x8B,0xFC, + 0x6D,0xFD,0x88,0xF9,0x67,0xF5,0xD6,0xF9,0xDE,0xFD,0x44,0xF7, + 0x0E,0xF8,0x88,0xFD,0x4D,0xFF,0xE9,0xFC,0xDE,0xFD,0xE2,0x06, + 0xB5,0x16,0x57,0x14,0x9F,0x05,0x60,0x0F,0xD0,0x11,0x8B,0x09, + 0x61,0x01,0x25,0xF8,0x37,0xF8,0x00,0xF8,0x91,0xF0,0x0A,0xE9, + 0xF7,0xEF,0xC2,0xF5,0x2B,0xF5,0x47,0xF8,0xA9,0xFC,0x4A,0x04, + 0xE4,0x0C,0xD9,0x08,0x0C,0x05,0x8C,0x0D,0x09,0x0B,0x5B,0x06, + 0x6E,0x01,0x49,0xFE,0x28,0x01,0x10,0xFC,0x69,0xF7,0xA8,0xF7, + 0x32,0xFC,0x7B,0xF9,0x35,0xF6,0x5C,0xFB,0x61,0xFE,0x95,0xFE, + 0x19,0xFD,0x5D,0x02,0x3D,0x14,0x5F,0x15,0x4E,0x07,0xAD,0x0D, + 0x64,0x10,0xB7,0x0A,0x4D,0x05,0x69,0xF9,0xFB,0xF7,0x17,0xFB, + 0xAB,0xF2,0xAA,0xEB,0x19,0xF1,0x38,0xF4,0x3F,0xF5,0x84,0xF7, + 0x5F,0xFA,0xFD,0x01,0xEB,0x09,0xBB,0x07,0x31,0x04,0x39,0x0B, + 0xD5,0x0A,0x8A,0x06,0xA8,0x02,0xCA,0xFF,0xDE,0x01,0xBC,0xFD, + 0x2D,0xF9,0x3C,0xF9,0x9C,0xFB,0xC6,0xF9,0xA7,0xF6,0x45,0xFB, + 0x89,0xFE,0x70,0xFE,0x5F,0xFE,0x30,0x00,0x36,0x12,0x62,0x13, + 0x50,0x04,0x44,0x0E,0x4E,0x0E,0xF7,0x08,0xC8,0x06,0xA2,0xFA, + 0x62,0xFA,0xB3,0xFD,0x8B,0xF4,0xC6,0xED,0x50,0xF4,0x0F,0xF5, + 0xE2,0xF4,0x3B,0xF8,0x57,0xF9,0xB9,0x00,0x58,0x06,0xED,0x04, + 0x73,0x04,0x31,0x08,0xD5,0x08,0xA8,0x06,0x15,0x03,0x53,0x01, + 0x0B,0x02,0xEA,0xFD,0xEB,0xFA,0xE4,0xFA,0x13,0xFB,0x90,0xFA, + 0x11,0xF9,0x42,0xFC,0xD5,0xFF,0x47,0xFF,0x70,0xFF,0x34,0xFF, + 0xEC,0x0B,0x6F,0x13,0x6D,0x05,0x22,0x08,0x68,0x0D,0xAE,0x08, + 0x2F,0x05,0xC0,0xFC,0x27,0xFB,0xE8,0xFB,0x46,0xF8,0xB2,0xF3, + 0x65,0xF3,0x27,0xF7,0x74,0xF7,0x6A,0xF8,0x65,0xFA,0xF5,0xFE, + 0x99,0x04,0x49,0x04,0x87,0x03,0xA9,0x05,0x3E,0x07,0x92,0x04, + 0x3E,0x02,0xE6,0x01,0x99,0x00,0x86,0xFD,0x8F,0xFD,0x74,0xFC, + 0x78,0xFA,0x8B,0xFD,0xA6,0xFA,0x40,0xFE,0xC6,0x00,0xBF,0xFE, + 0x06,0x02,0x3A,0x00,0xEA,0x03,0xF8,0x0E,0x3F,0x0A,0x19,0x02, + 0x1D,0x0A,0xBE,0x07,0xA8,0x03,0xBB,0x01,0x0B,0xFA,0xFC,0xFB, + 0xFB,0xFC,0x3A,0xF7,0x93,0xF5,0xA8,0xF9,0x38,0xF9,0xD5,0xF9, + 0xCF,0xFB,0x87,0xFC,0xF0,0x01,0xA2,0x03,0xC8,0x01,0x3C,0x01, + 0xA5,0x04,0xEE,0x04,0xD6,0x00,0x3D,0x01,0xA9,0xFE,0xFF,0x00, + 0xB2,0xFF,0xC6,0xFA,0x89,0xFD,0xDD,0xFF,0x90,0xFD,0x89,0xFC, + 0xB7,0x03,0x02,0xFE,0xC4,0x01,0xAD,0x04,0x12,0xFE,0x63,0x06, + 0x1C,0x0B,0x17,0x04,0x74,0x01,0xFB,0x09,0x44,0x01,0xF8,0x01, + 0x86,0x02,0xB9,0xF8,0xEB,0xFE,0x5B,0xFD,0x89,0xF8,0x32,0xF8, + 0xC1,0xFC,0x03,0xFB,0x2A,0xFB,0xF2,0xFE,0xD4,0xFB,0x98,0x02, + 0x0E,0x02,0x10,0xFE,0xDC,0x03,0x8F,0x00,0x7F,0x00,0x07,0x03, + 0x3F,0xFD,0xA8,0x01,0x8A,0x01,0x76,0xF9,0x77,0x04,0x0C,0xFD, + 0xD4,0xFA,0x0D,0x0A,0x10,0xF8,0xAC,0x02,0xA6,0x05,0x10,0xFC, + 0xFC,0x03,0x36,0x03,0xA8,0x02,0x92,0x00,0x28,0x09,0xB1,0xFF, + 0x02,0x05,0xEB,0x01,0xDA,0xFF,0x8B,0x03,0x9C,0xF9,0x97,0x01, + 0x8A,0xFA,0x70,0xFE,0xC6,0xFB,0x7A,0xFA,0xEC,0xFE,0x41,0xFC, + 0x71,0xFE,0x9E,0xFD,0x80,0x01,0x84,0xFC,0x88,0x02,0x18,0x00, + 0x88,0xFD,0x38,0x04,0x4B,0xFD,0xE1,0xFF,0xC8,0x00,0xD5,0xFD, + 0x5E,0x03,0x27,0xFE,0x51,0xFC,0xE7,0x07,0xA9,0xFD,0x3B,0x00, + 0xBD,0x02,0x3E,0x01,0xFC,0x02,0x0B,0xFC,0x10,0x07,0x67,0x00, + 0xF8,0xFE,0xEF,0x03,0x5A,0x02,0xAC,0xFF,0x79,0x03,0x5F,0x02, + 0xC5,0xFA,0x9E,0x06,0xFE,0xFB,0xE1,0xFD,0x2C,0x01,0x62,0xF8, + 0x01,0x02,0x34,0xFF,0xA8,0xF7,0x5D,0x02,0x37,0xFE,0x23,0xFE, + 0x32,0xFF,0x05,0xF9,0x34,0x08,0x12,0xFB,0x00,0xFD,0xAF,0x02, + 0xB3,0x00,0xB2,0xFC,0x87,0x04,0xCA,0x01,0xF6,0xFA,0x33,0x06, + 0xCD,0x00,0x4D,0xFF,0xA0,0xFD,0x32,0x0D,0x6A,0xF5,0xEF,0x02, + 0x72,0x0B,0x51,0xF5,0x64,0x08,0x0A,0xFF,0x84,0xFD,0xB5,0x03, + 0xD8,0x01,0x51,0xF9,0xB8,0x03,0x75,0x07,0x3B,0xEF,0x41,0x0C, + 0x41,0x00,0x88,0xF0,0x91,0x10,0x9D,0xF9,0xBF,0xF2,0x54,0x0F, + 0xE0,0xFA,0x3C,0xF1,0x0D,0x16,0x4B,0xED,0xF6,0x02,0x97,0x0B, + 0x79,0xEC,0xB0,0x0A,0x25,0x01,0x0C,0xFD,0xC0,0xF9,0xBB,0x0B, + 0xCD,0xFB,0x4C,0xF9,0x67,0x0F,0xC2,0xF4,0xA9,0x03,0x76,0x09, + 0x88,0xF0,0xEF,0x0E,0xA8,0xF9,0x03,0x00,0xDB,0x05,0x6C,0xF9, + 0x46,0x0A,0x06,0xF4,0xBC,0x0E,0x92,0xF2,0xEE,0x09,0xB6,0xFA, + 0xA0,0xFE,0xF9,0x08,0xCC,0xEC,0x17,0x18,0xCC,0xE7,0xD9,0x0D, + 0xA8,0xFC,0xA5,0xF9,0x1E,0x0C,0x45,0xF2,0x0D,0x09,0xDF,0xFA, + 0x39,0x04,0xA3,0xF9,0xA5,0x06,0xF0,0xFA,0x59,0x01,0xCC,0x01, + 0x21,0xFC,0x67,0x04,0x88,0xF9,0x70,0x06,0x78,0xFA,0xA9,0x05, + 0xAB,0xFB,0xF3,0x01,0xD8,0x00,0x73,0xFF,0xC8,0x00,0x49,0xFD, + 0x1A,0x08,0x52,0xF5,0xF8,0x09,0x43,0xFB,0x7F,0xFF,0x1C,0x09, + 0x47,0xF3,0xB9,0x06,0x3A,0x01,0x4C,0xFB,0xCA,0x04,0xDB,0xFC, + 0x9D,0xFF,0xC8,0x03,0x26,0xFD,0x46,0xFF,0x56,0x02,0x1E,0xFD, + 0x8F,0x00,0x10,0x03,0x6E,0xFA,0xBC,0x02,0x47,0x02,0x75,0xF9, + 0x79,0x07,0xBB,0xFA,0xB3,0x00,0xE0,0x01,0xC1,0xFB,0xCC,0x08, + 0x55,0xF2,0x1B,0x0E,0x56,0xF8,0xA9,0xFC,0x8E,0x08,0xB1,0xF9, + 0xE1,0x02,0xAA,0xFC,0x7C,0x0A,0x87,0xEF,0xB5,0x0D,0xDE,0xFD, + 0x00,0xF7,0x99,0x0D,0x6D,0xF4,0xF9,0x07,0x42,0xFB,0xCA,0x01, + 0x47,0x03,0xB1,0xF8,0x8A,0x04,0x93,0x01,0x64,0xFD,0xC1,0xFD, + 0xBD,0x07,0x98,0xF7,0xDF,0x05,0x09,0xFE,0x64,0xFD,0x57,0x05, + 0x84,0xF9,0x16,0x06,0x0A,0xFB,0x45,0x03,0xBD,0x00,0x3B,0xFB, + 0x2B,0x04,0x97,0xFE,0xD1,0xFF,0xFF,0x00,0x98,0xFD,0x5E,0x04, + 0xC4,0xF9,0xD4,0x05,0xF5,0xFC,0xB0,0xFE,0xDA,0x04,0xC9,0xF8, + 0x47,0x08,0x59,0xF8,0xAD,0x02,0x6E,0x05,0x23,0xF7,0x94,0x05, + 0x83,0xFF,0x7D,0xFE,0xC1,0xFF,0x74,0x02,0x5F,0xFE,0x06,0xFE, + 0x82,0x08,0x9A,0xF2,0x72,0x0B,0x8D,0xFB,0xA6,0xFE,0xBD,0x03, + 0xD6,0xFC,0x42,0x02,0xCF,0xFC,0xC6,0x04,0xD5,0xF8,0x5D,0x0A, + 0x53,0xF4,0xC3,0x08,0xCA,0xFA,0xCC,0x02,0x76,0x01,0x58,0xF9, + 0x0D,0x08,0xAF,0xFA,0xF8,0x04,0xB7,0xF8,0x48,0x08,0x01,0xF9, + 0xC1,0x06,0xD3,0xF9,0xF1,0x00,0x29,0x04,0x74,0xF9,0x79,0x05, + 0xD9,0xFA,0xC1,0x04,0xF1,0xFF,0x4F,0xFD,0x8E,0x02,0xA8,0xFE, + 0x43,0xFC,0xE1,0x0B,0x27,0xF1,0xCF,0x07,0xEA,0x04,0x63,0xF3, + 0x41,0x0B,0x30,0xF9,0x90,0x00,0x74,0x03,0x8E,0xFD,0x98,0xFF, + 0x55,0x01,0x5A,0x02,0xC3,0xFA,0x66,0x03,0xA1,0x01,0x8B,0xF6, + 0xF2,0x0E,0xEA,0xF3,0xC7,0x02,0x73,0x09,0x4A,0xEE,0xCB,0x0F, + 0x36,0xF9,0x7B,0xFD,0x07,0x04,0x13,0x02,0x56,0xFA,0x9B,0x03, + 0xAF,0x02,0xAF,0xF5,0x92,0x0D,0x0D,0xF6,0xBB,0x02,0x4F,0x02, + 0xB3,0xFC,0xB4,0x00,0x3C,0x02,0xE8,0xFD,0x83,0x00,0x28,0x03, + 0x1D,0xF7,0x4C,0x0B,0x0D,0xF7,0xAD,0x03,0x51,0x01,0x49,0xFB, + 0xF8,0x06,0x14,0xF8,0x65,0x07,0xE9,0xFC,0x40,0xFD,0xBD,0x04, + 0x5B,0xFB,0x5A,0x04,0x7C,0xFC,0x78,0x04,0xA4,0xFD,0xCA,0xFB, + 0x08,0x09,0xC4,0xF5,0x33,0x08,0xEF,0xF8,0x18,0x07,0x7E,0xFB, + 0x01,0x00,0x4A,0x07,0x87,0xF1,0x60,0x10,0xC2,0xF3,0x04,0x05, + 0x2D,0xFF,0xE1,0x00,0xA9,0xFC,0xE8,0x03,0xBD,0x00,0x1D,0xF7, + 0xEF,0x0F,0xCB,0xED,0xA1,0x0F,0x86,0xF8,0x1A,0xFC,0x27,0x0C, + 0xED,0xF0,0x69,0x0D,0x7D,0xF7,0x28,0x03,0x13,0x01,0xA4,0xFE, + 0x46,0x01,0x33,0xFA,0x6E,0x0A,0x6B,0xF2,0x4C,0x0F,0x25,0xF4, + 0xA4,0xFF,0x5E,0x0F,0x5B,0xE9,0x9C,0x14,0xFF,0xF4,0x0D,0x00, + 0x05,0x08,0x2F,0xF5,0xBD,0x07,0xAC,0xFC,0x8A,0x02,0x2E,0xFA, + 0x7B,0x0A,0x74,0xF4,0xC0,0x02,0xCF,0x08,0x09,0xEE,0xB4,0x17, + 0xE9,0xEB,0x53,0x08,0x0F,0x04,0xF6,0xF4,0x55,0x0C,0x55,0xF5, + 0xD0,0x07,0xF3,0xF8,0x75,0x08,0x3C,0xF7,0x8B,0x06,0x51,0xFF, + 0x37,0xF9,0xB3,0x0C,0x76,0xF2,0xDB,0x07,0xD5,0xFE,0x45,0xFE, + 0x21,0x02,0x56,0x00,0xBF,0xFB,0xB9,0x05,0x63,0xFE,0x0F,0xF9, + 0xE6,0x0B,0xF4,0xF3,0x32,0x09,0xE5,0xFD,0xFA,0xFB,0xA8,0x07, + 0x18,0xF6,0xA4,0x09,0x53,0xF6,0xBA,0x08,0xF9,0xFA,0x1C,0x00, + 0x6B,0x04,0xBD,0xF7,0x26,0x0A,0x55,0xF6,0xD4,0x08,0x53,0xF8, + 0x54,0x06,0xDC,0xFB,0x07,0x00,0xC7,0x04,0x46,0xF8,0xB1,0x09, + 0x0F,0xF4,0x4C,0x0D,0x0F,0xF7,0xE1,0xFE,0x81,0x08,0xC3,0xF4, + 0x82,0x0A,0x6F,0xF9,0x45,0x02,0xE2,0xFF,0xB6,0xFD,0xEA,0x05, + 0x60,0xF8,0x46,0x06,0x6A,0xFD,0x3A,0x00,0x0D,0x01,0x44,0xFC, + 0x42,0x06,0xE4,0xF9,0xEA,0x01,0xE5,0x02,0x9F,0xFA,0x0D,0x06, + 0x3D,0xFB,0xB7,0x00,0x71,0x05,0xC7,0xF5,0x3F,0x0C,0x2A,0xF4, + 0xE4,0x06,0xFF,0x01,0xD1,0xF7,0x37,0x08,0x47,0xF9,0x6E,0x06, + 0x37,0xF9,0x30,0x07,0xAC,0xF8,0x60,0x05,0x59,0x00,0xDB,0xFB, + 0xC5,0x03,0x42,0xFD,0x55,0x04,0xDF,0xF9,0x09,0x05,0xC3,0xFB, + 0xE5,0x02,0x8C,0xFF,0x28,0xFE,0xC5,0x02,0xFC,0xFC,0x6B,0x02, + 0xAA,0xFF,0x3D,0xFF,0xBF,0xFF,0x39,0x03,0x83,0xFB,0xC4,0x01, + 0xDF,0x02,0xF0,0xFA,0xA1,0x04,0xBD,0xFD,0xF6,0xFE,0x73,0x02, + 0x06,0xFE,0x02,0x01,0x07,0xFF,0x2C,0x01,0xB3,0xFE,0xA8,0x00, + 0xA8,0x01,0xFA,0xFB,0x79,0x04,0x3F,0xFC,0x99,0x00,0x05,0x02, + 0x65,0xFF,0x8F,0x00,0x5A,0xFE,0xEC,0x02,0x1A,0xF9,0x77,0x09, + 0x19,0xF9,0x64,0x01,0x5E,0x04,0x78,0xF8,0xE5,0x07,0x60,0xF9, + 0xB5,0x05,0xC9,0xF9,0xC5,0x05,0x10,0xFB,0x3B,0x03,0x95,0xFF, + 0x82,0xFC,0x4B,0x08,0x6D,0xF3,0xD1,0x0E,0x35,0xF2,0xC9,0x0A, + 0x2F,0xFB,0x76,0xFE,0xAD,0x06,0x3F,0xF6,0xD3,0x09,0xF6,0xF6, + 0x75,0x09,0x99,0xF5,0x0F,0x09,0xDA,0xF9,0xD3,0x00,0x33,0x05, + 0xF7,0xF7,0xF5,0x08,0x23,0xF7,0x7D,0x06,0x2F,0xFC,0xA8,0x01, + 0xDD,0xFE,0xE2,0x03,0x77,0xFA,0x1F,0x03,0x59,0x02,0x3B,0xF8, + 0xE1,0x07,0x7A,0xFA,0xE4,0x02,0xAC,0x00,0x90,0xFE,0x5B,0xFF, + 0x55,0x04,0x42,0xF8,0xED,0x07,0xAA,0xFD,0x71,0xFA,0x44,0x0B, + 0x8B,0xF4,0x4E,0x08,0x51,0xFA,0x1E,0x02,0xCF,0x00,0xBA,0xFD, + 0xC9,0x02,0x3C,0xFC,0xA7,0x05,0xC5,0xF8,0x93,0x08,0x80,0xF7, + 0x44,0x04,0x8C,0x02,0xD6,0xF8,0xC7,0x07,0x78,0xFA,0x0F,0x03, + 0xF5,0xFD,0xF7,0x01,0x7C,0xFD,0x48,0x02,0xD6,0xFF,0xCE,0xFE, + 0xBA,0x00,0x95,0xFD,0xD9,0x05,0x98,0xF9,0x61,0x03,0x31,0x01, + 0x62,0xFC,0x95,0x03,0x9D,0xFF,0x57,0xFB,0xCF,0x04,0x58,0x00, + 0xFF,0xFA,0xD8,0x06,0x74,0xFA,0xBA,0x01,0xAF,0x01,0xBD,0xFC, + 0xBD,0x02,0xB4,0xFD,0x33,0x03,0x8F,0xFC,0x97,0x01,0x72,0x01, + 0xD0,0xFC,0xCF,0x03,0x4E,0xFD,0xF2,0x00,0x19,0xFF,0xDB,0x01, + 0x4B,0xFD,0x50,0x00,0xCD,0x03,0x35,0xF9,0x6C,0x07,0x4F,0xFB, + 0x41,0x00,0x87,0x03,0x2F,0xFC,0x9A,0x02,0x3F,0xFE,0xC5,0x00, + 0x6F,0xFE,0x81,0x03,0x48,0xFD,0x18,0x00,0x70,0x02,0xD2,0xFC, + 0x60,0x00,0xE4,0x01,0x0E,0xFE,0xF6,0xFF,0x80,0x02,0xBF,0xFD, + 0x59,0x00,0xA3,0x00,0x2F,0xFF,0xC9,0xFE,0x62,0x04,0xBA,0xFC, + 0x6B,0xFF,0x16,0x04,0xE9,0xFA,0x5B,0x02,0xDE,0x01,0x51,0xFC, + 0xE7,0x01,0x47,0x03,0x39,0xF9,0xC1,0x03,0xA0,0x00,0x87,0xFC, + 0x70,0x03,0xE1,0xFD,0xA9,0x01,0xBB,0xFD,0x5C,0x02,0x54,0xFD, + 0xDC,0x03,0xD7,0xFD,0x02,0x00,0x50,0x03,0x57,0xF9,0xAF,0x07, + 0xD7,0xF8,0xFC,0x05,0x34,0xFC,0x57,0xFF,0xCB,0x05,0xE4,0xF7, + 0x10,0x07,0x61,0xF9,0x49,0x06,0x00,0xFB,0xD5,0x01,0x26,0x00, + 0x44,0xFD,0x22,0x07,0xCB,0xF7,0x89,0x06,0x8F,0xFA,0x64,0x04, + 0x91,0x00,0x16,0xFA,0xD0,0x05,0x07,0xFE,0x8D,0xFF,0x0F,0x02, + 0x19,0xFD,0x19,0x02,0x92,0xFF,0x30,0xFF,0x37,0xFF,0xEF,0x00, + 0x58,0x02,0xE0,0xFB,0x88,0x04,0x4C,0xFA,0xD6,0x04,0xE6,0xFF, + 0x83,0xFC,0x7A,0x05,0xEA,0xF9,0x2D,0x03,0x8B,0x01,0x19,0xF9, + 0xC1,0x06,0xB2,0xFE,0xF2,0xFD,0x2D,0x02,0xE3,0xFC,0x4B,0x05, + 0x98,0xFA,0x16,0x04,0x3D,0xFE,0x8C,0xFD,0xE7,0x04,0x19,0xFD, + 0x21,0x01,0x30,0xFE,0x7E,0x00,0x12,0x04,0xC6,0xFA,0x9C,0x01, + 0x0E,0x02,0x9E,0xFB,0xC1,0x05,0xD7,0xF9,0xAA,0x03,0x90,0xFF, + 0x69,0x00,0xDB,0xFF,0xFF,0xFC,0x3B,0x05,0xB0,0xFA,0xE7,0x04, + 0x37,0xFC,0x7C,0x00,0xAF,0x02,0x70,0xFC,0xB8,0x03,0x37,0xFE, + 0x4B,0xFF,0x92,0x02,0xA0,0xFD,0x59,0x00,0x8F,0x00,0xB4,0xFF, + 0x97,0xFF,0x65,0x00,0x95,0xFE,0x7B,0x01,0xD2,0xFF,0x0D,0xFF, + 0xF0,0x01,0xEB,0xFC,0xAE,0x03,0xF9,0xFC,0xF7,0x02,0x37,0xFD, + 0xD3,0x01,0x02,0x00,0xA2,0xFE,0xCC,0x01,0xD5,0xFD,0x7C,0x02, + 0xCB,0xFD,0x36,0x02,0x3A,0xFD,0xDD,0x01,0xFC,0xFF,0x8E,0x00, + 0x7B,0xFD,0x4F,0x02,0x77,0xFF,0x5D,0xFE,0x43,0x02,0x27,0xFF, + 0x5F,0xFF,0x64,0x00,0x2B,0x01,0xFB,0xFD,0x04,0x01,0x52,0xFF, + 0x4B,0x01,0xE1,0xFE,0xEF,0x00,0x17,0x00,0x02,0x00,0x6B,0x00, + 0x97,0xFE,0xF3,0x00,0x69,0xFF,0xBA,0xFF,0x13,0x01,0xBE,0xFD, + 0x70,0x02,0xE8,0xFE,0xA8,0xFF,0xFE,0x01,0x5C,0xFD,0xA9,0x02, + 0xFE,0xFE,0xBC,0xFE,0x73,0x02,0xEB,0xFD,0xB8,0xFF,0x14,0x02, + 0x05,0xFD,0x75,0x02,0xDF,0xFD,0xC3,0x01,0x28,0xFF,0xD1,0xFF, + 0x63,0x00,0x7B,0xFF,0x93,0x03,0x9B,0xFA,0x10,0x06,0xD0,0xFA, + 0x4E,0x01,0xB1,0x02,0x9A,0xFB,0x75,0x03,0x70,0xFF,0xE1,0xFD, + 0xBD,0x01,0x25,0x00,0x21,0xFD,0x1F,0x04,0xD5,0xFC,0xC9,0x01, + 0xF5,0xFE,0x28,0x01,0x98,0xFF,0x89,0x00,0x8D,0x00,0x99,0xFC, + 0x68,0x05,0x81,0xFA,0xCB,0x02,0xC0,0x00,0xE2,0xFC,0x92,0x02, + 0x89,0xFE,0xB1,0x00,0xB8,0xFF,0xDD,0x00,0x08,0xFF,0xB9,0x00, + 0x77,0x00,0x7F,0xFF,0xEA,0xFF,0x39,0x00,0x68,0xFF,0x3C,0x00, + 0x16,0x00,0x55,0xFF,0x7B,0x00,0x2D,0xFF,0x66,0x01,0xEC,0xFE, + 0xE2,0x00,0xF6,0xFF,0x56,0x00,0x91,0xFF,0x14,0x00,0x21,0x00, + 0x5C,0xFF,0xF8,0x00,0x40,0xFE,0xA0,0x01,0x98,0xFF,0x7A,0xFF, + 0xC5,0x00,0x06,0xFF,0xA8,0x00,0x87,0xFF,0x50,0x00,0xCD,0x00, + 0xC7,0xFE,0xA9,0x01,0xCB,0xFD,0x04,0x02,0xDC,0xFE,0x2E,0xFF, + 0x5E,0x02,0x9C,0xFE,0x0C,0x00,0x8C,0xFF,0x55,0x02,0x43,0xFC, + 0x4A,0x02,0x32,0xFF,0x78,0xFE,0xC2,0x02,0x6A,0xFE,0x8A,0x00, + 0x02,0x00,0xB3,0xFF,0x1A,0x01,0xA9,0xFF,0xDC,0xFF,0xFE,0x00, + 0x58,0xFE,0x19,0x01,0x07,0xFF,0x44,0x01,0xF6,0xFF,0x2B,0xFE, + 0x1B,0x02,0x9B,0xFD,0x5A,0x01,0xAD,0x00,0xF1,0xFD,0xEA,0x01, + 0x90,0xFF,0x0B,0xFF,0x87,0x02,0x7D,0xFD,0x85,0x00,0xAA,0x00, + 0x50,0xFF,0x59,0x00,0xE2,0xFF,0x39,0x00,0xCE,0xFE,0xB3,0x02, + 0x03,0xFC,0x73,0x03,0xAD,0xFE,0xB9,0x00,0x40,0x00,0xB6,0xFE, + 0x5A,0x01,0xD8,0xFD,0x69,0x03,0x8B,0xFB,0xAB,0x03,0x8E,0xFD, + 0x33,0x01,0xDB,0x00,0x03,0xFF,0x2E,0x01,0xEF,0xFC,0x9C,0x03, + 0xAB,0xFC,0xE6,0x02,0xE7,0xFE,0xA1,0xFE,0x27,0x04,0xD9,0xFA, + 0x19,0x03,0xBA,0xFE,0x7C,0xFF,0x1D,0x03,0x1A,0xFD,0xF6,0x01, + 0x11,0xFE,0xBE,0x01,0x1A,0xFE,0x3C,0x01,0x42,0x00,0xC1,0xFD, + 0x0C,0x02,0xB1,0xFF,0x06,0x00,0x22,0x00,0x92,0xFE,0xA6,0x00, + 0x23,0x02,0xB4,0xFC,0x5F,0x03,0x5B,0xFD,0xF8,0x00,0x90,0x01, + 0x45,0xFD,0x39,0x02,0xF0,0xFD,0xC2,0x01,0x53,0xFF,0x4A,0xFF, + 0x4A,0x00,0xCB,0xFF,0xE5,0x01,0x3C,0xFE,0x6E,0x00,0xFA,0xFE, + 0xB2,0x00,0xDA,0x00,0x1B,0x00,0x18,0xFF,0xEA,0xFF,0xB9,0x00, + 0x32,0xFF,0xC4,0x01,0x9A,0xFD,0xAE,0x01,0xE5,0xFF,0x65,0xFF, + 0x67,0x00,0x75,0xFF,0x8F,0x00,0xE2,0xFE,0xD0,0x01,0xD1,0xFE, + 0x01,0xFF,0xF4,0x01,0x3F,0xFE,0xF5,0x00,0xA7,0x00,0x41,0xFE, + 0x08,0x01,0xEC,0x00,0x09,0xFF,0x4A,0x00,0x6F,0xFF,0x22,0x00, + 0x0B,0x02,0x40,0xFD,0x7C,0x01,0xD0,0xFF,0x27,0x00,0xA7,0x00, + 0xA6,0xFD,0x99,0x01,0xB1,0xFE,0x2B,0x01,0x84,0x00,0xC4,0xFC, + 0x9C,0x03,0x9D,0xFE,0x97,0xFF,0x5F,0x02,0x17,0xFC,0x32,0x03, + 0x47,0xFF,0x4C,0xFF,0x63,0x01,0x42,0xFD,0xF1,0x02,0x6A,0xFF, + 0xE5,0xFE,0x0D,0x02,0x30,0xFE,0x6A,0x00,0x90,0xFF,0xD1,0x00, + 0x41,0xFD,0xB9,0x04,0x5F,0xFD,0x70,0xFE,0x2D,0x04,0xCF,0xF9, + 0xF7,0x06,0xEE,0xFA,0xC1,0x01,0xD8,0xFF,0x38,0xFF,0x14,0x03, + 0x7B,0xFC,0x92,0x02,0xE1,0xFD,0xBC,0x01,0xA3,0xFF,0x4A,0x00, + 0xBA,0xFE,0x58,0x02,0x81,0xFD,0x07,0x02,0xB8,0xFE,0xE7,0xFD, + 0xC2,0x04,0xE1,0xF9,0xAF,0x04,0x01,0xFE,0xB7,0xFF,0xCD,0x01, + 0x97,0xFE,0xCF,0x00,0x93,0xFF,0xAE,0x00,0x30,0x00,0x31,0x00, + 0xF1,0x00,0xDD,0xFD,0x01,0x01,0x9F,0x00,0xA1,0xFD,0xCF,0x02, + 0x66,0xFB,0x18,0x05,0x3F,0xFC,0x13,0x02,0xFC,0xFE,0xD9,0xFF, + 0x61,0x00,0x6C,0xFF,0x25,0x03,0x12,0xFB,0xEA,0x05,0x8A,0xFA, + 0x58,0x04,0x62,0xFD,0x8B,0x01,0x45,0xFE,0x1D,0x00,0x23,0x02, + 0x39,0xFD,0x90,0x03,0x77,0xFB,0xC3,0x03,0x07,0xFD,0xC1,0x01, + 0x08,0xFF,0xF7,0xFF,0x70,0x01,0xDA,0xFE,0x35,0x01,0x71,0xFF, + 0x5C,0x00,0xA3,0xFE,0x0E,0x02,0x9A,0xFE,0x49,0xFF,0x76,0x02, + 0x1E,0xFD,0xC3,0x01,0x9A,0xFF,0xC5,0xFF,0x4C,0xFF,0xDC,0xFF, + 0x77,0x03,0xC5,0xF9,0x6D,0x05,0x33,0xFD,0x92,0xFF,0x18,0x05, + 0x54,0xFA,0x08,0x03,0x86,0x00,0xB3,0xFC,0xED,0x02,0x84,0xFF, + 0x34,0xFE,0xB3,0x02,0xFF,0xFC,0x49,0x03,0x0E,0xFD,0x81,0x02, + 0xF3,0xFD,0xC7,0xFD,0xA7,0x06,0xEE,0xF8,0xFB,0x04,0x6B,0xFE, + 0x30,0xFF,0x32,0x02,0x05,0xFF,0x7E,0xFE,0x68,0x00,0xB5,0x02, + 0xD7,0xFB,0x49,0x04,0x3C,0xFB,0xD7,0x03,0xBD,0xFE,0x91,0xFE, + 0x2A,0x03,0x3A,0xFA,0x95,0x07,0xED,0xFA,0x1B,0x03,0xE2,0xFF, + 0x11,0xFC,0x4A,0x04,0x11,0xFE,0x15,0x00,0x3F,0x00,0x5C,0xFF, + 0x03,0x01,0x13,0x00,0xF3,0xFC,0x74,0x04,0xE1,0xFA,0x09,0x05, + 0xE7,0xFD,0x0A,0xFF,0xCE,0x04,0xD2,0xF7,0xC5,0x08,0xF9,0xF9, + 0x8C,0x01,0x10,0x01,0xAE,0xFA,0x28,0x0A,0xF2,0xF6,0x02,0x05, + 0xA9,0xFF,0xB9,0xFA,0x61,0x09,0x33,0xF6,0x67,0x07,0xFE,0xFA, + 0x13,0x01,0x5E,0x03,0xBD,0xF8,0x8B,0x09,0x02,0xF7,0xBD,0x07, + 0xF2,0xFA,0x92,0x00,0xDC,0x03,0x2A,0xFA,0xCD,0x06,0xF6,0xF8, + 0x74,0x05,0x33,0xFC,0xA8,0x01,0x32,0x01,0xCC,0xFB,0x69,0x06, + 0x8A,0xF9,0x84,0x04,0xAA,0xFE,0x76,0xFD,0xB8,0x05,0x23,0xFA, + 0x16,0x03,0xD0,0xFE,0x3B,0x01,0xA7,0xFF,0x24,0xFE,0x8F,0x03, + 0xFA,0xF9,0xFE,0x07,0xF2,0xF9,0x8C,0x01,0xDF,0x04,0x9E,0xF6, + 0x3D,0x07,0x8C,0xFD,0xA7,0xFF,0xD4,0x02,0xC5,0xFC,0xD9,0x00, + 0xAF,0x00,0x29,0xFE,0x75,0x03,0x5E,0xFC,0xEF,0x02,0x97,0xFE, + 0x9C,0xFC,0x3C,0x09,0x78,0xF6,0xA9,0x03,0x5E,0x02,0x43,0xF9, + 0x1F,0x06,0xAA,0xFF,0x97,0xFB,0x30,0x06,0x4E,0xFC,0xA8,0xFD, + 0x2C,0x07,0xA8,0xF6,0x06,0x08,0xC6,0xFD,0x5E,0xFC,0x22,0x06, + 0xE3,0xF6,0xD3,0x0A,0x86,0xF9,0x95,0xFF,0x2C,0x05,0x09,0xF6, + 0x80,0x0E,0x18,0xF5,0x49,0x02,0x59,0x07,0x3D,0xF2,0xFB,0x0D, + 0x11,0xF6,0x29,0x01,0x14,0x07,0x13,0xF5,0x3D,0x0A,0xDD,0xF8, + 0xDA,0x01,0x66,0x04,0x3D,0xF8,0xB5,0x07,0x48,0xF9,0xAE,0x03, + 0x6F,0x03,0xCC,0xF7,0x0C,0x07,0x26,0xFC,0x48,0x02,0x80,0x00, + 0xCE,0xFB,0x2C,0x03,0x8D,0xFF,0x67,0x00,0xC1,0xFF,0x6E,0x00, + 0x02,0xFC,0x0A,0x05,0x0B,0xFE,0x74,0x01,0x6E,0xFF,0xFA,0xFA, + 0xF1,0x05,0xF7,0xFD,0xAE,0x02,0x81,0xFB,0xD4,0x02,0x71,0x00, + 0xFE,0xFB,0xF9,0x05,0x3F,0xFC,0x5A,0xFF,0xBD,0x02,0x3D,0xFD, + 0x46,0x01,0x1F,0x01,0xDE,0xFE,0x2F,0x00,0xED,0xFE,0x84,0x04, + 0x45,0xF9,0x34,0x03,0xB2,0x05,0x71,0xF5,0xC4,0x07,0xB4,0xFC, + 0x95,0xFC,0xB2,0x07,0xAB,0xFA,0xF8,0x00,0x93,0x00,0x9C,0xFF, + 0x64,0x00,0x30,0x01,0xCF,0xFD,0x6B,0x01,0x80,0x01,0x5C,0xFC, + 0xA4,0x04,0xEB,0xF9,0x5A,0x05,0x6A,0xFE,0x39,0xFB,0xE6,0x07, + 0x0B,0xF7,0x79,0x07,0x70,0xFE,0x14,0xFA,0xC1,0x0A,0xC4,0xF8, + 0x51,0x01,0x07,0x04,0xB3,0xF9,0xDC,0x03,0x13,0x00,0x06,0xFD, + 0x21,0x03,0x05,0xFF,0xAB,0xFD,0x63,0x04,0xC9,0xFC,0x6C,0xFF, + 0x64,0x02,0x1F,0xFD,0x61,0x02,0x9E,0xFD,0x31,0x02,0x02,0xFF, + 0xB7,0xFE,0xA0,0x04,0x6D,0xFE,0xEA,0xFC,0xAC,0x02,0x40,0x00, + 0x3C,0xFC,0x24,0x05,0x9D,0xFD,0x19,0xFF,0x3F,0x03,0xFE,0xFA, + 0x1A,0x03,0x7A,0x00,0x00,0xFC,0x42,0x06,0x2D,0xFC,0xD2,0xFD, + 0x66,0x05,0x9E,0xFC,0x49,0x01,0xC6,0xFF,0x07,0xFF,0x53,0x01, + 0x0A,0x00,0x3F,0x00,0x9A,0xFE,0x0C,0xFF,0x9E,0x01,0x7C,0x02, + 0x49,0xFD,0xC4,0xFE,0xAC,0x01,0xD7,0xFE,0x02,0xFF,0x3E,0x05, + 0xD6,0xFD,0xCD,0xFA,0x98,0x05,0x6F,0xFC,0x33,0x00,0x2D,0x06, + 0xA3,0xFB,0x19,0xFD,0x57,0x01,0xEE,0x02,0xB0,0xFD,0x49,0x01, + 0x2C,0x04,0xD4,0xF7,0x95,0x01,0x43,0x06,0x2F,0xF9,0xA8,0x01, + 0x4F,0x03,0xAC,0xFC,0x41,0xFF,0x52,0x02,0x13,0x01,0xB6,0xFB, + 0xA7,0x03,0xCF,0x01,0x55,0xF8,0xE9,0x03,0xF2,0x03,0xAC,0xFA, + 0x02,0x04,0xA6,0x00,0x3A,0xFC,0xBF,0x00,0xA8,0x01,0x21,0x00, + 0x37,0xFB,0x16,0x03,0xD8,0x02,0xFB,0xFD,0x3D,0xFF,0x1E,0x01, + 0xD6,0xFD,0x29,0xFF,0x91,0x06,0x9A,0xFB,0xCF,0xFB,0x35,0x05, + 0x8B,0x00,0x94,0xFD,0x14,0x02,0x7F,0x00,0x2C,0xFC,0x01,0x01, + 0xC9,0x03,0x87,0xFD,0xF8,0xFD,0x28,0x05,0x67,0xFE,0xA5,0xFC, + 0x82,0x03,0xD0,0xFE,0x01,0xFC,0xA4,0x01,0xEE,0x02,0xFD,0xFE, + 0x23,0xFF,0x0E,0x02,0x8E,0xFE,0x73,0xFD,0xA5,0x03,0x0B,0x01, + 0x50,0xFE,0x32,0x00,0x53,0x00,0x50,0xFE,0x15,0xFE,0xA5,0x04, + 0x6C,0x00,0x2A,0xFD,0xC4,0x00,0x3B,0xFE,0xC3,0xFF,0xC0,0x00, + 0x63,0x00,0x8C,0x01,0x63,0xFF,0xB0,0xFF,0xEB,0x00,0x61,0xFE, + 0xCB,0x00,0xD4,0x02,0x42,0xFE,0x57,0xFE,0x80,0x00,0xDA,0xFE, + 0x86,0x00,0x30,0x01,0x23,0x00,0x06,0x00,0x20,0xFE,0x33,0x01, + 0xC8,0xFF,0x6A,0xFE,0x33,0x02,0x55,0x00,0x42,0xFF,0xF3,0xFF, + 0xDB,0x00,0xE9,0xFF,0x55,0xFF,0xFD,0xFF,0x97,0x00,0xC2,0xFF, + 0x99,0xFD,0xA2,0x01,0x80,0xFF,0x58,0xFF,0x96,0x04,0xDC,0xFC, + 0x7B,0xFD,0x8C,0x02,0xB1,0x00,0xD9,0x00,0x4B,0xFE,0x07,0x00, + 0x42,0x00,0x8C,0xFF,0x5F,0x01,0xA5,0xFF,0xAD,0x00,0x06,0xFE, + 0xC4,0xFF,0x6E,0x01,0x33,0xFE,0x80,0x02,0x01,0x00,0x4E,0xFD, + 0xAB,0x00,0xCB,0x00,0xBE,0xFF,0x67,0x00,0xA2,0x00,0xBA,0xFE, + 0x44,0xFF,0x0A,0x01,0x30,0x01,0x20,0x00,0x07,0x00,0x91,0xFF, + 0x3A,0xFE,0x2F,0x00,0x00,0x01,0x4F,0x00,0xA9,0x00,0x67,0xFF, + 0xFF,0xFE,0x0A,0xFF,0x46,0x00,0x90,0x01,0xBF,0xFF,0xAD,0xFF, + 0xD1,0x00,0xAA,0xFF,0xEA,0xFE,0xCC,0xFF,0x13,0x01,0xEA,0x00, + 0xB6,0xFF,0x66,0xFF,0xAC,0xFF,0x1E,0xFF,0xAB,0xFF,0x4F,0x01, + 0xB0,0x00,0x74,0x00,0x4E,0xFF,0xE5,0xFE,0x81,0x00,0x2F,0x00, + 0xE8,0x00,0x5F,0x00,0x76,0xFF,0xF3,0xFF,0x3B,0xFF,0x14,0x00, + 0xD9,0x00,0x38,0x00,0xBC,0xFF,0x40,0xFF,0xA9,0xFF,0x7C,0x00, + 0x52,0x00,0x42,0x00,0xD7,0xFF,0xEB,0xFF,0x25,0x00,0x23,0xFF, + 0xC8,0xFF,0x2A,0x00,0x59,0x00,0x67,0x00,0x4C,0xFF,0x33,0xFF, + 0xBD,0xFF,0x64,0x00,0xD4,0x00,0x06,0x00,0xE9,0xFF,0x72,0x00, + 0xC5,0xFF,0x3A,0x00,0x49,0x00,0x94,0xFF,0xF8,0xFF,0x85,0x00, + 0x6A,0x00,0x82,0xFF,0x14,0xFF,0xC3,0xFF,0x6B,0x00,0xC3,0xFF, + 0xC8,0xFF,0x24,0x00,0xBD,0xFF,0xCB,0xFF,0x27,0x00,0x31,0x00, + 0xEE,0xFF,0x53,0x00,0xF6,0xFF,0x09,0x00,0x67,0x00,0x1A,0x00, + 0x3F,0x00,0xEC,0xFF,0x23,0x00,0x29,0x00,0x28,0x00,0x0C,0x00, + 0x86,0xFF,0x10,0x00,0x5B,0x00,0x3D,0x00,0x28,0x00,0xDA,0xFF, + 0x1A,0x00,0x17,0x00,0xF6,0xFF,0x38,0x00,0xF9,0xFF,0x1A,0x00, + 0xE0,0xFF,0xE5,0xFF,0x19,0x00,0xD3,0xFF,0xE9,0xFF,0xA4,0xFF, + 0xED,0xFF,0xE3,0xFF,0x95,0xFF,0xC9,0xFF,0xC9,0xFF,0xF9,0xFF, + 0xE0,0xFF,0xC3,0xFF,0xC3,0xFF,0xB5,0xFF,0xF4,0xFF,0xEE,0xFF, + 0xC9,0xFF,0xF1,0xFF,0xEE,0xFF,0xDA,0xFF,0xC3,0xFF,0xE7,0xFF, + 0x08,0x00,0x99,0xFF,0xE3,0xFF,0x68,0x00,0x47,0x00,0x88,0x00, + 0x9D,0x00,0x61,0x00,0x8E,0x00,0xD1,0x00,0x3D,0x01,0xA9,0x01, + 0xBC,0x01,0xAB,0x01,0x5C,0x01,0x95,0x00,0xBF,0xFF,0xF5,0xFE, + 0x51,0xFE,0x40,0xFE,0x3E,0xFE,0x3A,0xFE,0x21,0xFE,0x1D,0xFE, + 0x73,0xFE,0x7B,0xFE,0xC6,0xFE,0x62,0xFF,0xA9,0xFF,0x0E,0x00, + 0x5D,0x00,0x56,0x00,0xCA,0x00,0x01,0x01,0xC8,0x00,0x11,0x01, + 0x1B,0x01,0x0B,0x01,0x0C,0x01,0xB1,0x00,0x76,0x00,0x55,0x00, + 0x2B,0x00,0x0D,0x00,0xDD,0xFF,0x30,0x00,0x22,0x00,0xB8,0xFF, + 0x3C,0x00,0x48,0x00,0xE3,0x00,0x08,0x02,0x60,0x02,0x43,0x03, + 0x6C,0x03,0xBA,0x02,0x10,0x02,0x93,0x00,0xFC,0xFE,0x7C,0xFD, + 0xCB,0xFB,0x27,0xFB,0x9F,0xFB,0x81,0xFC,0x60,0xFD,0x87,0xFD, + 0x83,0xFD,0x98,0xFD,0xBC,0xFD,0x74,0xFE,0x51,0xFF,0x3F,0x00, + 0x1B,0x01,0x9F,0x01,0x07,0x02,0x26,0x02,0x2C,0x02,0x1A,0x02, + 0xDE,0x01,0xB3,0x01,0x6A,0x01,0x1F,0x01,0xE7,0x00,0x94,0x00, + 0x62,0x00,0x4B,0x00,0x22,0x00,0x20,0x00,0x12,0x00,0x01,0x00, + 0x0E,0x00,0xF8,0xFF,0xE4,0xFF,0xC9,0xFF,0x8F,0xFF,0x47,0xFF, + 0x05,0xFF,0xBE,0xFE,0xB0,0xFE,0xBB,0xFE,0xD7,0xFE,0xB2,0xFF, + 0x8C,0x00,0xBD,0x01,0x45,0x03,0xEB,0x03,0x0E,0x04,0x3B,0x03, + 0xA5,0x01,0x41,0x00,0xD0,0xFE,0x7D,0xFD,0x6F,0xFC,0x8A,0xFB, + 0x3D,0xFB,0xDA,0xFB,0x2A,0xFD,0x2B,0xFE,0x9B,0xFE,0x0A,0xFF, + 0x4C,0xFF,0xB7,0xFF,0x5C,0x00,0xEA,0x00,0x70,0x01,0xCF,0x01, + 0xFF,0x01,0x19,0x02,0x31,0x02,0x40,0x02,0x31,0x02,0x0D,0x02, + 0xC2,0x01,0x48,0x01,0xC7,0x00,0x48,0x00,0xE8,0xFF,0xAB,0xFF, + 0x7C,0xFF,0x60,0xFF,0x56,0xFF,0x52,0xFF,0x56,0xFF,0x67,0xFF, + 0x77,0xFF,0x76,0xFF,0x56,0xFF,0x28,0xFF,0xE3,0xFE,0xC4,0xFE, + 0xAA,0xFE,0xE5,0xFE,0x8B,0xFF,0x62,0x00,0xCE,0x01,0x10,0x03, + 0xF6,0x03,0xB5,0x03,0x4C,0x02,0x51,0x01,0x73,0x00,0x93,0xFF, + 0xBE,0xFE,0xE5,0xFD,0xFA,0xFC,0xFE,0xFB,0xED,0xFB,0x93,0xFC, + 0x29,0xFD,0xDE,0xFD,0x7D,0xFE,0xFC,0xFE,0x8F,0xFF,0xFA,0xFF, + 0x63,0x00,0xD9,0x00,0x15,0x01,0x49,0x01,0x82,0x01,0xA4,0x01, + 0xC2,0x01,0xD7,0x01,0xEB,0x01,0xE4,0x01,0xDB,0x01,0xC9,0x01, + 0x81,0x01,0x20,0x01,0xB1,0x00,0x4B,0x00,0xF9,0xFF,0xB7,0xFF, + 0x80,0xFF,0x50,0xFF,0x38,0xFF,0x2E,0xFF,0x2B,0xFF,0x24,0xFF, + 0x0A,0xFF,0xDE,0xFE,0xC5,0xFE,0xB0,0xFE,0xB5,0xFE,0x11,0xFF, + 0x9B,0xFF,0x6F,0x00,0xCA,0x01,0x20,0x03,0xCA,0x02,0xE3,0x01, + 0xEF,0x01,0xA3,0x01,0x00,0x01,0x4C,0x00,0x88,0xFF,0xB9,0xFE, + 0xD9,0xFD,0x2E,0xFD,0xA6,0xFC,0xBC,0xFC,0x54,0xFD,0xCB,0xFD, + 0x3D,0xFE,0xD0,0xFE,0x50,0xFF,0xC1,0xFF,0x2E,0x00,0x80,0x00, + 0xC6,0x00,0x13,0x01,0x4E,0x01,0x61,0x01,0x7F,0x01,0x8E,0x01, + 0x8A,0x01,0x97,0x01,0x9C,0x01,0x93,0x01,0x76,0x01,0x48,0x01, + 0xF8,0x00,0x9E,0x00,0x49,0x00,0xF1,0xFF,0xAA,0xFF,0x73,0xFF, + 0x48,0xFF,0x2B,0xFF,0x0F,0xFF,0xF4,0xFE,0xD3,0xFE,0xB3,0xFE, + 0xA8,0xFE,0x9A,0xFE,0xB1,0xFE,0x1E,0xFF,0xC4,0xFF,0xE6,0x00, + 0x09,0x02,0x35,0x02,0xE9,0x01,0xDF,0x01,0xDB,0x01,0x8E,0x01, + 0x09,0x01,0x5D,0x00,0x8E,0xFF,0xAD,0xFE,0x01,0xFE,0x91,0xFD, + 0x39,0xFD,0x35,0xFD,0x83,0xFD,0xE0,0xFD,0x50,0xFE,0xDF,0xFE, + 0x58,0xFF,0xC0,0xFF,0x18,0x00,0x5E,0x00,0xAA,0x00,0xF4,0x00, + 0x27,0x01,0x3C,0x01,0x5D,0x01,0x71,0x01,0x77,0x01,0x8C,0x01, + 0x8F,0x01,0x90,0x01,0x78,0x01,0x4D,0x01,0x1A,0x01,0xD2,0x00, + 0x88,0x00,0x1B,0x00,0xB9,0xFF,0x75,0xFF,0x3A,0xFF,0x16,0xFF, + 0xFB,0xFE,0xDF,0xFE,0xBC,0xFE,0x9C,0xFE,0x90,0xFE,0x89,0xFE, + 0xA7,0xFE,0x0E,0xFF,0xAA,0xFF,0xD9,0x00,0xE8,0x01,0x05,0x02, + 0xE0,0x01,0xEB,0x01,0xF2,0x01,0xB4,0x01,0x3B,0x01,0x94,0x00, + 0xC8,0xFF,0xE9,0xFE,0x3D,0xFE,0xD8,0xFD,0x8D,0xFD,0x69,0xFD, + 0x84,0xFD,0xCA,0xFD,0x38,0xFE,0xC5,0xFE,0x33,0xFF,0x91,0xFF, + 0xE9,0xFF,0x33,0x00,0x76,0x00,0xB9,0x00,0xF3,0x00,0x17,0x01, + 0x38,0x01,0x5A,0x01,0x65,0x01,0x79,0x01,0x8E,0x01,0x87,0x01, + 0x78,0x01,0x5F,0x01,0x34,0x01,0x03,0x01,0xCD,0x00,0x72,0x00, + 0xF8,0xFF,0x92,0xFF,0x4D,0xFF,0x18,0xFF,0xF7,0xFE,0xDC,0xFE, + 0xB6,0xFE,0x90,0xFE,0x7C,0xFE,0x74,0xFE,0x7C,0xFE,0xD0,0xFE, + 0x59,0xFF,0x62,0x00,0x07,0x02,0x8E,0x02,0xE1,0x01,0xDD,0x01, + 0x13,0x02,0xD0,0x01,0x63,0x01,0xBE,0x00,0x02,0x00,0x1B,0xFF, + 0x4D,0xFE,0xDD,0xFD,0x8C,0xFD,0x5B,0xFD,0x5D,0xFD,0x93,0xFD, + 0x08,0xFE,0xA3,0xFE,0x27,0xFF,0x8B,0xFF,0xE1,0xFF,0x32,0x00, + 0x6A,0x00,0xA8,0x00,0xE1,0x00,0x03,0x01,0x25,0x01,0x42,0x01, + 0x55,0x01,0x5F,0x01,0x77,0x01,0x80,0x01,0x75,0x01,0x6C,0x01, + 0x53,0x01,0x2C,0x01,0xFB,0x00,0xB0,0x00,0x35,0x00,0xAB,0xFF, + 0x4F,0xFF,0x0C,0xFF,0xEB,0xFE,0xCF,0xFE,0xA6,0xFE,0x77,0xFE, + 0x5C,0xFE,0x57,0xFE,0x5F,0xFE,0x83,0xFE,0x1A,0xFF,0xD1,0xFF, + 0xC2,0x01,0x5F,0x04,0x24,0x03,0x65,0x01,0x0E,0x02,0xEA,0x01, + 0x50,0x01,0xAF,0x00,0xFF,0xFF,0x2A,0xFF,0x21,0xFE,0x95,0xFD, + 0x45,0xFD,0x0D,0xFD,0x1D,0xFD,0x55,0xFD,0xBB,0xFD,0x7B,0xFE, + 0x47,0xFF,0xCE,0xFF,0x14,0x00,0x52,0x00,0x8B,0x00,0xB6,0x00, + 0xF1,0x00,0x0D,0x01,0x23,0x01,0x49,0x01,0x67,0x01,0x79,0x01, + 0x8F,0x01,0xA3,0x01,0x92,0x01,0x80,0x01,0x6F,0x01,0x33,0x01, + 0xF2,0x00,0x99,0x00,0xFE,0xFF,0x4A,0xFF,0xE6,0xFE,0xCB,0xFE, + 0xAC,0xFE,0xB2,0xFE,0xAF,0xFE,0x88,0xFE,0x49,0xFE,0x3D,0xFE, + 0x29,0xFE,0x45,0xFE,0xE9,0xFE,0x46,0x00,0x74,0x02,0x2C,0x05, + 0xB3,0x06,0xE0,0x03,0x5E,0x01,0xA8,0x01,0xDD,0x00,0xE7,0xFF, + 0x20,0xFF,0x2B,0xFE,0x08,0xFD,0xE2,0xFB,0x60,0xFB,0x60,0xFB, + 0x0A,0xFC,0x04,0xFD,0xE6,0xFD,0x0A,0xFF,0x4A,0x00,0x17,0x01, + 0x7F,0x01,0xA0,0x01,0x7F,0x01,0x32,0x01,0x18,0x01,0x15,0x01, + 0x0D,0x01,0x46,0x01,0x9D,0x01,0xD8,0x01,0x04,0x02,0x33,0x02, + 0x1F,0x02,0xDA,0x01,0x5F,0x01,0x78,0x00,0x5B,0xFF,0x18,0xFE, + 0xF5,0xFC,0xAE,0xFC,0xE7,0xFD,0xA7,0xFF,0x62,0x00,0x25,0x00, + 0x56,0xFF,0x80,0xFE,0xD2,0xFD,0xB7,0xFD,0x94,0xFD,0x32,0xFE, + 0x80,0x00,0xFD,0x02,0x08,0x06,0x9C,0x08,0xFF,0x09,0xEB,0x08, + 0x87,0x05,0xC5,0x01,0xF2,0xFD,0x1E,0xFB,0x9F,0xF8,0x35,0xF6, + 0xFF,0xF4,0xD7,0xF5,0xAC,0xF7,0x29,0xFA,0x81,0xFD,0x77,0x00, + 0xA8,0x02,0x08,0x04,0xA1,0x04,0x45,0x04,0x99,0x03,0x21,0x03, + 0x8C,0x02,0x54,0x02,0xB1,0x02,0xF7,0x02,0x42,0x03,0x52,0x03, + 0xD1,0x02,0xAA,0x01,0x08,0x00,0x1C,0xFE,0xEE,0xFB,0xE8,0xFA, + 0xE7,0xFA,0x87,0xFB,0x10,0xFD,0xE0,0xFE,0x74,0x00,0x91,0x01, + 0x24,0x02,0xF6,0x01,0x90,0x01,0xDC,0x00,0x52,0xFF,0xFC,0xFC, + 0x75,0xFB,0x59,0xFB,0xDA,0xFC,0x71,0x02,0xAC,0x08,0x9E,0x0D, + 0xD6,0x10,0x73,0x10,0x80,0x0C,0x82,0x04,0x4C,0xFC,0x1E,0xF4, + 0x68,0xED,0xDC,0xEB,0xC3,0xED,0x3D,0xF1,0xA2,0xF6,0xB8,0xFC, + 0xD5,0x00,0xD4,0x03,0x34,0x05,0x74,0x04,0xC4,0x03,0x5D,0x04, + 0x6F,0x05,0x29,0x07,0x8E,0x09,0x42,0x0A,0x52,0x08,0x12,0x05, + 0x5D,0x00,0xA0,0xFA,0xAF,0xF6,0x52,0xF5,0x8F,0xF6,0xFD,0xF9, + 0xE6,0xFE,0x3C,0x03,0xAF,0x05,0x02,0x06,0xD2,0x03,0xEC,0x00, + 0xE1,0xFE,0x06,0xFE,0x4A,0xFE,0x22,0x00,0xFE,0x01,0xE3,0x02, + 0x0A,0x02,0xD1,0xFF,0x83,0xFB,0x51,0xF5,0xF3,0xF2,0xD9,0xF5, + 0xD6,0x00,0x50,0x0D,0x49,0x16,0xD5,0x1C,0xB0,0x1A,0xA7,0x0F, + 0x19,0xFE,0x76,0xEE,0x35,0xE5,0x61,0xE3,0xAA,0xE9,0x3B,0xF3, + 0x14,0xFC,0xED,0x00,0x46,0x01,0xD5,0xFE,0x79,0xFD,0xCD,0xFF, + 0x5A,0x06,0x6C,0x0F,0xBD,0x16,0x14,0x17,0x50,0x0F,0xFE,0x01, + 0xFE,0xF2,0xC8,0xE8,0x46,0xE8,0x3A,0xF0,0x37,0xFC,0x35,0x07, + 0xC4,0x0C,0xF9,0x0A,0x04,0x04,0x2D,0xFE,0x0A,0xFD,0x15,0x01, + 0xAF,0x07,0x3F,0x0C,0xDC,0x0A,0xDA,0x02,0xFA,0xF7,0xF9,0xEF, + 0x05,0xEF,0xC8,0xF5,0x96,0xFF,0x5A,0x07,0xCA,0x05,0x67,0xFC, + 0x13,0xF5,0x6B,0xF7,0x4C,0x09,0x2F,0x1B,0x64,0x25,0xD4,0x22, + 0x21,0x0F,0xE7,0xF4,0xB0,0xDE,0x40,0xD9,0x92,0xE1,0x13,0xF2, + 0x95,0x01,0x4F,0x05,0x07,0xFF,0xD2,0xF6,0x1B,0xF5,0x20,0xFE, + 0xF6,0x0F,0x16,0x1F,0xDB,0x20,0x0B,0x14,0xD5,0xFE,0xD6,0xEA, + 0x30,0xE3,0x83,0xEB,0x6C,0xFA,0x50,0x06,0x04,0x0A,0x4E,0x03, + 0x50,0xF9,0xD5,0xF5,0xCA,0xFD,0xDD,0x0A,0x96,0x15,0x37,0x17, + 0x98,0x0B,0x47,0xFB,0x74,0xEF,0xD9,0xED,0xAB,0xF5,0x69,0x00, + 0x33,0x06,0x43,0x03,0xAA,0xFC,0x99,0xF8,0xF8,0xF8,0x5A,0xFF, + 0x3C,0x01,0xF5,0xFD,0x7C,0x00,0x3F,0x0D,0xDF,0x1A,0x8E,0x1A, + 0x3A,0x14,0xD0,0x04,0x85,0xF1,0x8A,0xE8,0x3A,0xEA,0xFD,0xF0, + 0x32,0xF5,0x89,0xF7,0x85,0xF4,0xBD,0xF2,0x03,0xFB,0x34,0x08, + 0x45,0x12,0x84,0x16,0xE8,0x11,0xFD,0x04,0x02,0xFB,0x47,0xFA, + 0xB3,0xFC,0x2C,0xFD,0xE3,0xFB,0x8B,0xF6,0x46,0xF1,0xD3,0xF5, + 0x6D,0x01,0x0A,0x0B,0xCA,0x0E,0x82,0x0C,0x48,0x05,0x07,0xFF, + 0x94,0xFF,0x76,0x03,0x24,0x05,0x85,0x01,0x71,0xF9,0xEE,0xF2, + 0x07,0xF4,0xF1,0xFA,0x97,0x03,0x1F,0x07,0x1A,0x05,0x4C,0x00, + 0x4C,0xFC,0xC0,0xFA,0x57,0xF7,0x33,0xF9,0xF4,0x0C,0x12,0x23, + 0x29,0x1D,0x26,0x0B,0x8B,0xFC,0x7A,0xF0,0x42,0xEF,0x92,0xF7, + 0x5F,0xFA,0xFF,0xEE,0xF1,0xE9,0xDB,0xF0,0xE2,0xFA,0x9D,0x08, + 0xE6,0x11,0xC3,0x0B,0x0F,0x01,0x96,0x02,0xDC,0x08,0xF4,0x08, + 0x4E,0x06,0x94,0xFD,0x93,0xEF,0x38,0xED,0xD8,0xF8,0xDD,0x02, + 0x4A,0x04,0x8A,0x03,0x3B,0x00,0x81,0xFF,0xDD,0x08,0x6D,0x0F, + 0x34,0x09,0xB9,0xFE,0x6B,0xFB,0x0C,0xFC,0x63,0xFC,0x5D,0xFE, + 0xB9,0xFB,0x11,0xF7,0xD0,0xFA,0xB0,0x02,0x52,0x07,0x84,0x05, + 0x34,0xFD,0x42,0xF1,0xB0,0xF4,0x08,0x02,0xB6,0x0D,0xD3,0x24, + 0xC2,0x20,0xA0,0x03,0xEB,0xF5,0x73,0xF8,0xFA,0xFB,0x73,0xF4, + 0x5A,0xF0,0xDC,0xE8,0xCE,0xE6,0x8C,0xFA,0x19,0x0B,0x75,0x08, + 0x61,0x01,0xA8,0x02,0x70,0x05,0x1B,0x0A,0x49,0x10,0xC0,0x07, + 0x66,0xF6,0xF2,0xF3,0x0D,0xFB,0x62,0xFB,0xBA,0xF9,0xE1,0xFA, + 0x2D,0xFA,0x05,0xFF,0x81,0x0B,0x10,0x10,0x88,0x07,0x59,0x01, + 0xB7,0x03,0x61,0x03,0xFC,0xFE,0xE6,0xFB,0xF0,0xF9,0x54,0xF9, + 0x32,0xFC,0xF3,0xFF,0xBF,0xFF,0x9B,0xFF,0xD5,0x01,0x3C,0x03, + 0xB6,0x02,0x97,0x00,0x34,0xFC,0x9A,0xF7,0x10,0xF4,0xAB,0xFB, + 0x32,0x1D,0x8C,0x28,0xEC,0x09,0x00,0xF7,0xB4,0xFB,0xA7,0xFF, + 0xB3,0xF7,0xFA,0xF0,0x9F,0xE9,0xFB,0xE7,0xAD,0xFC,0x41,0x0C, + 0xE2,0x02,0x99,0xF9,0x3A,0x02,0xDD,0x0A,0x7A,0x0B,0xF9,0x0A, + 0x1E,0x02,0x45,0xF8,0x03,0xFD,0x97,0x03,0x18,0xFB,0xC6,0xF0, + 0x12,0xF6,0xF0,0xFF,0x53,0x05,0x35,0x08,0xBD,0x05,0xAA,0x02, + 0x34,0x07,0xB0,0x0A,0xEE,0x02,0x63,0xF9,0xBE,0xFA,0x45,0xFD, + 0x47,0xFB,0x6C,0xFC,0x16,0xFD,0xD4,0xFC,0x09,0x01,0xCE,0x06, + 0x0D,0x02,0x75,0xFB,0x77,0xF7,0x62,0xF6,0x7E,0xFE,0x52,0x1A, + 0xA3,0x2C,0x3C,0x0B,0x43,0xF3,0x35,0xFD,0xA7,0x00,0x25,0xF5, + 0x2C,0xEC,0x54,0xEC,0x80,0xED,0x09,0xFE,0xB0,0x0B,0xB6,0x00, + 0x49,0xF9,0x31,0x05,0x4D,0x0C,0x65,0x05,0x7A,0x02,0xD2,0x03, + 0x44,0x00,0x48,0xFF,0xD5,0xFE,0x41,0xF6,0xD6,0xF2,0x25,0xFC, + 0x44,0x02,0xCA,0x00,0xE4,0x03,0x9C,0x09,0xF9,0x07,0xE8,0x05, + 0xCD,0x05,0x1A,0x00,0xA5,0xFA,0x63,0xFB,0x95,0xFD,0xAA,0xFC, + 0x3D,0xFD,0x38,0xFF,0x7D,0xFF,0xD7,0x00,0x52,0x02,0x94,0x01, + 0xDE,0xFF,0x9F,0xFE,0x32,0xFA,0xCC,0xF1,0x5B,0xF5,0x3C,0x1A, + 0x69,0x31,0x40,0x0D,0xDB,0xEF,0x8D,0xFC,0x8A,0x06,0x47,0xF8, + 0x66,0xE9,0x3E,0xE9,0x7C,0xF0,0x29,0x02,0xD5,0x0A,0x43,0xFC, + 0xCD,0xF5,0x04,0x06,0x9D,0x0F,0xA5,0x05,0x49,0xFF,0xAC,0x03, + 0xC1,0x04,0x44,0x02,0x9E,0xFD,0xE7,0xF3,0xD5,0xF1,0xDA,0xFB, + 0x4B,0x02,0x7A,0x00,0x27,0x03,0xB6,0x09,0xBE,0x09,0x71,0x07, + 0xAD,0x04,0xCF,0xFE,0x25,0xFA,0xE1,0xFA,0xED,0xFD,0x20,0xFD, + 0x4C,0xFD,0x6B,0xFF,0x18,0x00,0x0D,0x00,0x6D,0x01,0x76,0x02, + 0xB2,0xFF,0xAF,0xFC,0xD3,0xF4,0x05,0xF0,0x37,0x05,0x13,0x2C, + 0xAC,0x26,0x48,0xF9,0x8C,0xF2,0x6C,0x05,0xA9,0x00,0x3F,0xED, + 0x8A,0xE7,0x50,0xEF,0x60,0xFB,0x1A,0x08,0x7B,0x02,0xB4,0xF5, + 0xE3,0xFE,0xC2,0x0D,0xFD,0x07,0x14,0xFD,0x0D,0x02,0xE2,0x09, + 0x37,0x06,0x80,0xFD,0x69,0xF5,0xAC,0xF2,0x93,0xF9,0x9C,0xFF, + 0x69,0xFD,0x38,0xFF,0x11,0x0A,0x9E,0x0F,0x35,0x08,0x32,0x01, + 0xB3,0x00,0xE7,0xFE,0x4D,0xFA,0x57,0xF8,0x93,0xFC,0x56,0x01, + 0x47,0x02,0x56,0xFF,0xBF,0xFD,0x02,0x00,0xD0,0x02,0x48,0x01, + 0x92,0xFF,0xC2,0xFB,0x39,0xF9,0x0F,0xF9,0xAF,0xFB,0x3D,0x21, + 0x65,0x2A,0x7C,0xFA,0xF7,0xEC,0x43,0x03,0x04,0x06,0x03,0xEF, + 0xC0,0xE8,0xB2,0xF4,0x29,0xFC,0x61,0x06,0xE6,0x02,0x48,0xF5, + 0xBA,0xFB,0xA7,0x0C,0x92,0x09,0x01,0xFC,0xD7,0x01,0x32,0x0C, + 0x9B,0x05,0x52,0xFB,0x28,0xF6,0xD0,0xF4,0xA0,0xF9,0x46,0x00, + 0x27,0x01,0x99,0xFE,0x30,0x05,0xD4,0x0E,0x22,0x0A,0x2D,0xFF, + 0xD1,0xFA,0x3C,0xFF,0x6B,0x01,0x38,0xFC,0x58,0xF9,0x00,0xFD, + 0xE4,0x00,0x1A,0x01,0x20,0xFD,0xB6,0xFC,0x53,0xFC,0x75,0xF5, + 0x69,0xFB,0xEC,0x0B,0x01,0x28,0xD0,0x24,0xA0,0xFA,0xB9,0xF4, + 0x4A,0x02,0x5C,0xFA,0x4B,0xE7,0x21,0xE7,0x6C,0xF8,0xAA,0x01, + 0x2C,0x04,0xA9,0xFD,0x27,0xFA,0xBE,0x05,0xFC,0x0B,0x7F,0x02, + 0x93,0xFB,0x0F,0x04,0xAA,0x0A,0x8E,0x02,0xA9,0xF8,0x06,0xF5, + 0x54,0xF6,0x80,0xFB,0xA8,0xFE,0x45,0xFE,0xD8,0x02,0xDA,0x0B, + 0xB6,0x0E,0x72,0x08,0x73,0xFE,0xC8,0xFB,0xBF,0xFE,0xEC,0xFB, + 0x32,0xF7,0x73,0xFA,0xD7,0x01,0xD7,0x05,0x4D,0x06,0x30,0x00, + 0xBC,0xFB,0xCC,0x00,0xC6,0x03,0x1D,0xFE,0xCE,0xFB,0x00,0xFC, + 0x79,0xF9,0xD5,0xF3,0xA5,0x04,0x36,0x2C,0x66,0x19,0x6E,0xEE, + 0x6B,0xF8,0xA2,0x0A,0x5E,0xFE,0x4D,0xEB,0xB8,0xEE,0xC0,0xF8, + 0x9C,0x00,0x81,0x03,0x4D,0xF6,0xF3,0xF4,0x76,0x07,0x96,0x0D, + 0x45,0x02,0x8D,0x00,0x17,0x0B,0x0C,0x0A,0xF9,0xFE,0x47,0xF7, + 0x5B,0xF3,0xE3,0xF7,0xD6,0xFF,0xDD,0xFB,0xC6,0xFA,0x86,0x07, + 0x25,0x0E,0x90,0x07,0x89,0x00,0x99,0x00,0x0D,0x02,0xC4,0x00, + 0x5C,0xFB,0xCD,0xF6,0xB7,0xFC,0xB9,0x02,0x69,0xFE,0x01,0xF9, + 0x33,0xF8,0x90,0xFC,0x69,0xF9,0x86,0x0C,0x4F,0x34,0x88,0x1B, + 0xD2,0xF0,0x07,0xFB,0x23,0x06,0x30,0xF4,0x3C,0xE5,0x4F,0xED, + 0x39,0xF7,0x7F,0x01,0x65,0x07,0x72,0xFB,0x39,0xFA,0x60,0x0A, + 0x26,0x0C,0xC4,0xFE,0xB2,0xFD,0x75,0x07,0x7F,0x07,0xFC,0xFD, + 0xA6,0xF4,0xF7,0xF2,0x12,0xFA,0x71,0xFF,0x48,0xFD,0xA9,0xFF, + 0x11,0x0C,0x96,0x0E,0xE5,0x04,0xF3,0x00,0xE4,0xFF,0x45,0xFD, + 0x96,0xFA,0x54,0xFA,0x23,0xFE,0x33,0x00,0x99,0x00,0xEB,0xFE, + 0xC8,0xFD,0x18,0x00,0xF9,0xFF,0x26,0xFF,0xF3,0xF9,0x98,0xF1, + 0x0E,0x11,0xC3,0x35,0x38,0x11,0x9C,0xEA,0xB7,0xFA,0xF5,0x05, + 0x58,0xF5,0x17,0xE9,0x40,0xF0,0x65,0xFE,0xEF,0x09,0xF6,0x01, + 0x4F,0xF1,0xAC,0xFA,0x52,0x0C,0xB7,0x06,0x3B,0xFA,0xB6,0xFE, + 0x7C,0x0A,0x64,0x0C,0xE1,0xFF,0x55,0xF2,0xFF,0xF4,0x34,0xFD, + 0x1C,0xFE,0x0E,0xFC,0xA5,0x00,0x59,0x0B,0xCA,0x0B,0x87,0x04, + 0xBB,0xFF,0x2E,0xFD,0x5E,0xFD,0xCC,0xFB,0xB3,0xFA,0xEB,0xFD, + 0xD3,0x02,0xDC,0x04,0xBA,0xFF,0x08,0xFC,0x66,0xFE,0x1E,0xFF, + 0x20,0xFB,0x93,0xF2,0x89,0x03,0x07,0x2C,0x13,0x22,0x04,0xF6, + 0x6B,0xF2,0x32,0x03,0x41,0xFD,0x2D,0xED,0x3E,0xEB,0x6B,0xF7, + 0x84,0x08,0x91,0x09,0xCA,0xF6,0xD4,0xF3,0xCE,0x05,0x92,0x0A, + 0x5B,0xFE,0x79,0xFA,0xD4,0x05,0x8A,0x0D,0x2D,0x04,0x4A,0xF6, + 0x45,0xF4,0x31,0xFB,0x67,0xFE,0xB9,0xFC,0x66,0xFF,0xB5,0x07, + 0x53,0x0C,0x9C,0x05,0xD6,0xFB,0x33,0xFC,0x39,0x00,0x9C,0xFE, + 0xC8,0xFA,0xED,0xFB,0xF8,0x04,0xF2,0x07,0x45,0xFF,0x8E,0xF9, + 0xB5,0xFD,0x49,0xFF,0x53,0xF2,0xFD,0xF5,0xC1,0x1D,0xEB,0x2C, + 0x58,0x08,0x5F,0xF1,0x87,0xFC,0x45,0x01,0xBF,0xF6,0xF5,0xEC, + 0x4D,0xEF,0x3E,0xFF,0xD7,0x0A,0xE3,0xFF,0x15,0xF3,0x90,0xFC, + 0x9B,0x08,0x95,0x04,0x23,0xFD,0x47,0x00,0x20,0x0A,0x4E,0x09, + 0x76,0xFB,0xC5,0xF2,0xA1,0xF7,0x02,0xFF,0x40,0xFE,0x80,0xFD, + 0xCF,0x03,0x55,0x09,0x84,0x09,0x0F,0x03,0x7D,0xFC,0xDC,0xFC, + 0xB5,0xFE,0xAE,0xFD,0x18,0xFB,0xD2,0xFD,0xA8,0x04,0x4F,0x04, + 0x57,0xFD,0x16,0xFD,0xFA,0xFD,0x12,0xFB,0x76,0xF5,0x18,0x07, + 0xEA,0x2E,0x12,0x1B,0x22,0xF0,0x68,0xF6,0xFA,0x01,0xF8,0xF9, + 0xC3,0xEE,0x8F,0xEE,0xB1,0xF8,0x3D,0x08,0x88,0x08,0x33,0xF6, + 0xCA,0xF6,0x31,0x07,0xA3,0x08,0x56,0xFE,0x08,0xFD,0xD1,0x06, + 0xEA,0x08,0xF6,0xFE,0xE4,0xF4,0xE2,0xF4,0xCB,0xFD,0x57,0x01, + 0x2D,0xFF,0x70,0xFF,0x99,0x05,0x25,0x0B,0x14,0x05,0x59,0xFD, + 0x8A,0xFD,0xDD,0xFF,0x3A,0xFD,0xF3,0xF9,0x17,0xFC,0xAB,0x02, + 0xD4,0x04,0x4D,0xFE,0x15,0xF8,0x2B,0xF0,0x27,0xFA,0x56,0x1F, + 0x2C,0x2E,0x66,0x0C,0x88,0xF1,0xE9,0xFD,0x9C,0x02,0x33,0xF4, + 0x84,0xEA,0xCE,0xEE,0x0B,0xFF,0x50,0x07,0x16,0xFE,0xE6,0xF6, + 0x8F,0x00,0x6B,0x09,0x90,0x04,0x59,0xFE,0x20,0x00,0x06,0x08, + 0x9B,0x08,0x69,0xF9,0xD6,0xEE,0x00,0xF6,0xFD,0xFE,0xA2,0x00, + 0x04,0x00,0x86,0x03,0x1D,0x0A,0x9A,0x0B,0x8E,0x04,0xE5,0xFB, + 0x0F,0xFB,0x6D,0xFD,0xDE,0xFC,0x02,0xFC,0x1B,0xFD,0x4B,0x02, + 0x62,0x05,0x22,0x00,0x5A,0xFC,0x71,0xFA,0x15,0xFD,0x72,0xFC, + 0xE6,0x05,0xA1,0x29,0x60,0x1C,0xA0,0xF1,0xC1,0xF3,0x51,0xFE, + 0x04,0xFA,0x81,0xF2,0xC9,0xF0,0xB7,0xF7,0xBC,0x07,0x4E,0x0B, + 0xCE,0xF8,0x25,0xF5,0x53,0x02,0x2C,0x07,0x99,0x03,0xD8,0xFF, + 0x4C,0xFF,0x3E,0x03,0xCE,0x03,0x2B,0xFA,0x66,0xF5,0xB2,0xFC, + 0x41,0x00,0x79,0xFE,0x89,0x00,0x61,0x04,0x9E,0x07,0xE7,0x06, + 0x09,0xFF,0xE9,0xFA,0x36,0xFD,0x76,0xFC,0x69,0xFB,0x07,0xFF, + 0xAE,0x01,0x1C,0x00,0x1E,0xF8,0xD2,0xEF,0xE5,0x15,0x88,0x3C, + 0x1F,0x10,0xA6,0xE8,0x2B,0xF8,0xFD,0x02,0x17,0xFC,0x77,0xEF, + 0xFD,0xE9,0x37,0xF8,0x45,0x0C,0x3D,0x03,0x8C,0xF0,0x84,0xFA, + 0xBE,0x0C,0xD5,0x0D,0xC8,0x01,0x2B,0xFC,0xB9,0x04,0xD6,0x07, + 0x71,0xFA,0x70,0xED,0xA7,0xF0,0x6C,0xFD,0x04,0x06,0x06,0x05, + 0xAC,0x01,0x8A,0x06,0xF0,0x0A,0x6E,0x04,0x5C,0xFC,0x63,0xFB, + 0xA9,0xFD,0xFC,0xFD,0xB3,0xFC,0xDF,0xFC,0x92,0x01,0x40,0x03, + 0xCD,0xFB,0x47,0xF7,0x24,0xF6,0x05,0xFB,0xC2,0x1D,0x9D,0x34, + 0x57,0x0E,0x48,0xEE,0x67,0xF7,0xFD,0xFC,0xEC,0xF6,0xB3,0xEE, + 0x50,0xED,0x8A,0xFB,0x1D,0x0A,0x8F,0x03,0x51,0xF8,0x13,0xFD, + 0x0E,0x05,0xF5,0x06,0x3E,0x02,0x85,0xFF,0xA0,0x05,0xDC,0x04, + 0x69,0xF9,0x12,0xF2,0x44,0xF5,0x91,0xFC,0x11,0x03,0x6B,0x04, + 0xD7,0x00,0x61,0x06,0x27,0x0C,0x38,0x05,0xAE,0xFB,0xD8,0xF9, + 0xBE,0xFD,0xD8,0xFE,0x53,0xFD,0xF4,0xFD,0xAE,0x00,0x80,0x03, + 0x91,0xFE,0x20,0xF6,0xF2,0xF9,0x21,0xFD,0x30,0x1A,0xD4,0x32, + 0xE8,0x07,0xF4,0xEB,0x77,0xF8,0xBB,0xFD,0x61,0xF9,0xEF,0xF0, + 0x60,0xEE,0xF4,0xF9,0xCA,0x0A,0x5E,0x04,0xD1,0xF7,0x8C,0xFC, + 0xA0,0x03,0xB7,0x07,0x2E,0x07,0x1B,0x00,0xD3,0xFC,0x23,0x01, + 0x27,0xFF,0x7C,0xF6,0x96,0xF5,0x8B,0xFC,0xE6,0x01,0x5E,0x03, + 0xE4,0x01,0x11,0x04,0x56,0x09,0x39,0x06,0xEC,0xFC,0x2A,0xF9, + 0xB6,0xFB,0x55,0xFF,0xEF,0xFF,0xFB,0xFC,0xD9,0xFC,0xF9,0xF7, + 0xDC,0xF1,0x9F,0x02,0xDA,0x2C,0x3F,0x31,0x7B,0x00,0x87,0xEE, + 0xC7,0xF9,0xBF,0xFD,0x69,0xF9,0xD4,0xEB,0x39,0xEB,0x1D,0xFE, + 0x61,0x0A,0x3B,0xFE,0xB7,0xF4,0xE0,0xFE,0xB7,0x0B,0x40,0x0E, + 0xEF,0x02,0xE8,0xFC,0x98,0x04,0xFF,0x02,0x4A,0xF6,0x78,0xEE, + 0xC9,0xF0,0xF0,0xFC,0x21,0x08,0x4D,0x07,0x6D,0x03,0xE7,0x06, + 0xF1,0x08,0x23,0x04,0x19,0xFD,0x60,0xFA,0x29,0xFC,0x6D,0xFE, + 0x6F,0xFF,0xBA,0xFE,0x67,0xFF,0x45,0x00,0x27,0xFD,0x5C,0xF9, + 0x52,0xFB,0x16,0xFD,0x86,0x18,0x70,0x31,0xF5,0x0E,0x5B,0xF2, + 0xAC,0xF2,0xA9,0xF3,0x44,0xF8,0x04,0xF5,0x75,0xEF,0x79,0xF7, + 0x97,0x08,0x6C,0x09,0xE2,0xFE,0x76,0xFB,0xB8,0xFD,0x19,0x07, + 0x00,0x0B,0x9B,0x00,0x70,0xFA,0x1A,0xFE,0x37,0xFE,0xE4,0xF9, + 0x01,0xF7,0x1F,0xF8,0x31,0xFF,0x79,0x05,0xA7,0x05,0x3A,0x07, + 0xD5,0x07,0x37,0x03,0x1E,0xFE,0xE4,0xFA,0xEE,0xF9,0x65,0xFC, + 0xC7,0xFE,0x44,0xFF,0x45,0xFB,0xA5,0xF4,0x4E,0xF7,0x62,0x0C, + 0x6A,0x30,0xFB,0x28,0x1D,0xFB,0xF5,0xED,0x28,0xF9,0x34,0x00, + 0xC1,0xF7,0x93,0xEB,0x7C,0xED,0xD6,0xFD,0x73,0x09,0x04,0xFF, + 0x5F,0xF6,0xCC,0xFD,0xCE,0x0B,0xD9,0x0E,0x1E,0x04,0x67,0xFF, + 0xE1,0xFF,0x69,0xFD,0x6E,0xF7,0xBB,0xF0,0x33,0xF2,0xA5,0xFD, + 0x19,0x08,0x7D,0x07,0xAA,0x05,0x55,0x06,0xB8,0x04,0x41,0x03, + 0x09,0x00,0xB9,0xFB,0x6C,0xFA,0x9E,0xFD,0xBD,0xFF,0x36,0x00, + 0x57,0x00,0xE4,0xFE,0x6B,0xFA,0xAE,0xF9,0x52,0xF8,0x6F,0x03, + 0x28,0x2C,0xF6,0x29,0x91,0xFE,0x41,0xF0,0xE1,0xF2,0xC6,0xF9, + 0xE2,0xFC,0x2F,0xF2,0x18,0xEA,0xB3,0xF9,0x0B,0x0B,0xE1,0x05, + 0xC1,0xFD,0xDE,0xF9,0xC6,0xFE,0xB7,0x0C,0xA1,0x0B,0x6D,0xFD, + 0x08,0xFA,0xC7,0xFD,0x92,0xFD,0xEC,0xFB,0xB6,0xF6,0x5A,0xF4, + 0xA4,0xFF,0xE5,0x07,0x43,0x07,0x31,0x07,0xCB,0x04,0x41,0x02, + 0x15,0x01,0x95,0xFD,0x06,0xF8,0xDC,0xFA,0x25,0xFE,0xE6,0xFD, + 0xAA,0xFB,0x5E,0xF0,0x61,0xF8,0xFC,0x21,0x7D,0x36,0x13,0x14, + 0xAB,0xF5,0x16,0xF5,0xD2,0xFB,0x58,0x01,0x00,0xF5,0x9B,0xE4, + 0x5F,0xEC,0xCD,0x01,0x42,0x06,0xA1,0xFC,0x65,0xF8,0xFC,0xFE, + 0x8F,0x0D,0x13,0x11,0xAF,0x05,0x70,0xFE,0x39,0xFD,0x8C,0xFB, + 0x37,0xF8,0xBA,0xF1,0xB3,0xF1,0xCA,0xFD,0x0D,0x08,0x70,0x08, + 0x97,0x06,0x9C,0x04,0xBC,0x03,0xD2,0x04,0x50,0x02,0x82,0xFB, + 0xBD,0xF9,0x53,0xFE,0x5C,0x00,0x2C,0x00,0xE6,0xFD,0x5A,0xFA, + 0x8E,0xF8,0x2D,0xFD,0xF0,0xFE,0x2C,0x10,0xE7,0x2D,0x33,0x1B, + 0xDC,0xF8,0xA1,0xF1,0x8F,0xF3,0xA3,0xF8,0x56,0xF9,0xFF,0xF0, + 0x97,0xEC,0xF9,0xFC,0xF7,0x09,0x2D,0x05,0x2A,0xFE,0x77,0xFB, + 0x9C,0x03,0x65,0x0C,0xC5,0x08,0xBF,0xFD,0x89,0xF8,0x56,0xFC, + 0x2B,0xFE,0x01,0xFA,0xE8,0xF4,0x20,0xF6,0x10,0x01,0xCA,0x0A, + 0x28,0x09,0x9B,0x04,0xF3,0x02,0xE1,0x01,0x6D,0xFF,0x4F,0xFC, + 0xC1,0xF8,0x22,0xF9,0x78,0xFF,0x0F,0xF7,0x20,0xF0,0x69,0x0C, + 0x02,0x30,0xC2,0x28,0x52,0x04,0x6E,0xF0,0x86,0xF3,0x3D,0x02, + 0x29,0x02,0xF4,0xEE,0x95,0xE4,0x67,0xF1,0xCA,0x04,0xD1,0x06, + 0x43,0xFD,0xD6,0xF6,0xF8,0xFE,0xEE,0x0F,0x2C,0x14,0x86,0x08, + 0x5C,0xFA,0xBA,0xF5,0x01,0xF9,0x73,0xF9,0xF1,0xF5,0xDA,0xF4, + 0xC2,0xFA,0x42,0x05,0x8C,0x0B,0xD6,0x09,0x80,0x03,0x75,0x00, + 0x7B,0x03,0x62,0x03,0x2C,0xFE,0xFF,0xF9,0xD6,0xFA,0xAB,0xFF, + 0x68,0x02,0x52,0xFD,0xB5,0xF5,0x8E,0xF5,0x1E,0xF8,0xD9,0x15, + 0x87,0x35,0xF2,0x1C,0x1C,0xFA,0x6C,0xF0,0xB1,0xF5,0x85,0xFD, + 0x1D,0xFB,0x94,0xEC,0x87,0xE4,0x4E,0xF7,0x22,0x09,0x5B,0x09, + 0xCC,0x00,0xDE,0xF9,0xDB,0xFE,0xED,0x0D,0x03,0x13,0xB3,0x03, + 0x27,0xF6,0x0D,0xF5,0x10,0xFB,0x09,0xFE,0x51,0xF9,0x0F,0xF5, + 0xA2,0xF8,0x3B,0x03,0x7B,0x0B,0x19,0x0B,0x1D,0x05,0x23,0x01, + 0xDE,0x00,0xAC,0xFF,0xF0,0xFC,0x3C,0xF9,0x90,0xFA,0x07,0xFE, + 0x41,0xF1,0x9A,0xF1,0xF5,0x17,0xB2,0x30,0x07,0x1E,0xBD,0x00, + 0xE2,0xF3,0x54,0xF7,0xB2,0x02,0x77,0x01,0xC5,0xED,0x93,0xE4, + 0xA7,0xF1,0x38,0x01,0xBF,0x04,0xE5,0xFE,0x67,0xF9,0xCF,0xFE, + 0xEC,0x0C,0x33,0x13,0x79,0x0B,0x6C,0xFD,0x9B,0xF5,0x23,0xF7, + 0xB6,0xF9,0xB3,0xF9,0xC9,0xF7,0x57,0xF8,0x05,0xFF,0x5F,0x08, + 0x8A,0x0A,0xA6,0x04,0xEC,0x01,0xD4,0x02,0xEA,0x02,0x78,0x01, + 0xAC,0xFD,0x5A,0xFB,0x9F,0xFC,0xC0,0xFE,0x32,0xFC,0x1D,0xF8, + 0xB2,0xF5,0x32,0x02,0x3F,0x22,0xB7,0x27,0x68,0x0E,0x6E,0xF9, + 0x9A,0xF3,0x7F,0xF9,0x01,0xFE,0xC0,0xFA,0xB1,0xEC,0x03,0xE8, + 0xE5,0xF4,0x72,0x02,0x8E,0x08,0x6D,0x03,0xA9,0xFD,0x4A,0x00, + 0x34,0x0A,0xBF,0x0F,0x37,0x08,0xCD,0xFC,0x96,0xF6,0xEE,0xF6, + 0xD8,0xF9,0xE4,0xFB,0x2F,0xFA,0x95,0xF8,0x5E,0xFD,0x3A,0x04, + 0x76,0x08,0xDD,0x07,0x91,0x03,0xC9,0xFF,0xFF,0xFE,0xCC,0x00, + 0xB8,0x00,0x24,0xFB,0x57,0xF3,0xF5,0xF6,0xB4,0x0C,0x0F,0x1F, + 0x35,0x19,0x49,0x07,0x82,0xFB,0x35,0xFA,0x02,0xFF,0xA9,0x01, + 0x6A,0xFC,0x5A,0xF2,0x42,0xEF,0x6D,0xF4,0x8B,0xFA,0x2E,0xFE, + 0x13,0xFF,0xAD,0xFF,0x26,0x01,0x88,0x04,0x1C,0x07,0xE1,0x05, + 0xC8,0x03,0xA5,0x00,0xCF,0xFC,0x73,0xFB,0x08,0xFD,0xE4,0xFE, + 0x7D,0xFE,0x2A,0xFE,0x97,0xFD,0x51,0xFC,0x6B,0xFE,0x7C,0x02, + 0x3B,0x04,0x22,0x03,0xB4,0x01,0xB8,0x01,0x33,0x02,0x68,0x02, + 0xF4,0x00,0x47,0xFE,0xFE,0xFB,0x3A,0xFE,0x49,0x07,0x2E,0x0C, + 0xAF,0x07,0x7E,0x00,0x2A,0xFE,0x22,0x00,0x17,0x00,0x0E,0x00, + 0x56,0xFF,0x16,0xFC,0xF9,0xF9,0xAE,0xFB,0x65,0xFE,0x42,0xFE, + 0x4B,0xFE,0xFC,0xFE,0x24,0xFE,0xDF,0xFC,0x42,0xFC,0x7B,0xFC, + 0xD3,0xFD,0x45,0x00,0xF9,0x01,0x5B,0x02,0x5B,0x02,0x8B,0x01, + 0xBA,0x00,0x43,0x01,0x0C,0x02,0x23,0x01,0x97,0xFF,0xF0,0xFE, + 0x4C,0xFE,0xD9,0xFD,0xB2,0xFE,0xE7,0xFF,0xCC,0xFD,0x0B,0xFB, + 0xC2,0xFC,0xEB,0x02,0xFF,0x07,0x8F,0x06,0x0B,0x04,0x1D,0x04, + 0x30,0x06,0x8A,0x07,0x22,0x07,0xF6,0x05,0xF6,0x01,0x42,0xFE, + 0x84,0xFC,0x0D,0xFC,0xD0,0xFB,0xE8,0xFB,0x45,0xFC,0x74,0xFA, + 0x8B,0xF8,0x9D,0xF7,0x35,0xF8,0x97,0xFA,0x3B,0xFD,0x58,0xFF, + 0xE5,0xFF,0x43,0x00,0xBB,0x00,0x04,0x02,0x3B,0x04,0xCE,0x04, + 0xCC,0x03,0x37,0x02,0x36,0x01,0x9B,0x00,0x4F,0x00,0xA7,0x00, + 0x59,0x00,0xDF,0xFF,0x2C,0xFF,0x1E,0xFE,0x7A,0xFD,0xF2,0xFC, + 0x07,0x01,0xE2,0x06,0xCD,0x06,0x4E,0x03,0xBC,0x02,0x8A,0x06, + 0x2F,0x07,0x96,0x05,0x3F,0x04,0x9C,0x00,0x3B,0xFD,0xAD,0xFC, + 0xA0,0xFD,0xFC,0xFB,0x9C,0xFA,0x49,0xFA,0x95,0xF9,0x7F,0xF9, + 0x91,0xF9,0xD4,0xF9,0x93,0xFA,0x52,0xFD,0xDF,0xFE,0x50,0xFF, + 0xF0,0x00,0xEE,0x01,0x78,0x02,0x51,0x03,0x52,0x04,0xFE,0x02, + 0x78,0x01,0x93,0x01,0xE5,0x00,0x28,0x00,0x63,0x00,0xA1,0x00, + 0x00,0xFF,0xE3,0xFC,0x39,0xFC,0x11,0xFF,0x39,0x05,0x0E,0x07, + 0x8D,0x03,0x11,0x02,0x52,0x05,0x02,0x08,0x6E,0x07,0x9C,0x06, + 0xA7,0x03,0x77,0xFF,0x02,0xFE,0x4D,0xFE,0x31,0xFD,0x47,0xFB, + 0xA0,0xFA,0x34,0xF9,0xF3,0xF7,0x4B,0xF8,0x09,0xF9,0xA7,0xF9, + 0xD7,0xFA,0x86,0xFC,0x85,0xFD,0x65,0xFF,0x8B,0x01,0x45,0x02, + 0x1F,0x03,0x48,0x04,0x51,0x04,0x08,0x03,0x98,0x02,0x85,0x02, + 0x78,0x01,0x57,0x01,0x6F,0x01,0xBD,0x00,0xAC,0xFF,0x9F,0xFF, + 0xF6,0xFE,0xDB,0xFD,0xB5,0xFD,0x32,0xFE,0x48,0x03,0xBF,0x06, + 0x47,0x05,0xE1,0x02,0x26,0x04,0x0A,0x07,0xF6,0x04,0xC2,0x03, + 0x19,0x02,0xD9,0xFE,0x0F,0xFD,0x8B,0xFD,0x40,0xFD,0x5F,0xFA, + 0x36,0xFA,0xE3,0xF9,0x87,0xF9,0x23,0xFA,0x3A,0xFA,0x29,0xFA, + 0xE8,0xFA,0x04,0xFE,0x6E,0xFF,0xB0,0x00,0x98,0x02,0x90,0x02, + 0x9E,0x02,0xAA,0x03,0x3E,0x04,0x52,0x02,0x65,0x01,0xC3,0x01, + 0xDA,0x00,0x98,0x00,0x7B,0x00,0x30,0x00,0x2C,0xFE,0x4D,0xFC, + 0xB2,0xFC,0x96,0xFF,0x46,0x05,0x8E,0x05,0xC7,0x02,0x1B,0x03, + 0x61,0x06,0x56,0x08,0x89,0x06,0x3F,0x05,0xDA,0x01,0x1F,0xFF, + 0x1A,0xFF,0x0D,0xFF,0x44,0xFD,0xC3,0xFA,0x44,0xFA,0x09,0xF9, + 0xF8,0xF8,0x7F,0xF9,0x45,0xF9,0xA6,0xF9,0x73,0xFA,0x4C,0xFC, + 0xA0,0xFD,0x1A,0x00,0x0B,0x02,0x43,0x02,0x27,0x03,0xB2,0x03, + 0xC8,0x03,0xF8,0x02,0xCB,0x02,0x74,0x02,0x7C,0x01,0xA8,0x01, + 0x46,0x01,0xC7,0x00,0xB5,0xFF,0x2C,0xFF,0x65,0xFE,0xFA,0xFD, + 0x23,0xFE,0x5B,0xFE,0xAC,0x03,0x73,0x06,0xE6,0x04,0x30,0x03, + 0xC5,0x04,0xF3,0x06,0x40,0x04,0x7A,0x03,0x55,0x01,0x54,0xFE, + 0x7A,0xFD,0x14,0xFE,0x59,0xFD,0x60,0xFA,0x65,0xFA,0x79,0xF9, + 0x64,0xF9,0xC5,0xFA,0x8B,0xFA,0x55,0xFA,0x22,0xFB,0x21,0xFE, + 0x6D,0xFF,0x06,0x01,0x00,0x03,0x43,0x02,0x5D,0x02,0x6B,0x03, + 0xC9,0x03,0x0C,0x02,0x75,0x01,0xCC,0x01,0xC6,0x00,0xD0,0x00, + 0xB3,0x00,0xAD,0xFF,0x7C,0xFE,0x63,0xFD,0xC3,0xFB,0x56,0xFF, + 0x37,0x06,0xCE,0x05,0x21,0x02,0x32,0x03,0x90,0x07,0x45,0x07, + 0x87,0x05,0xF3,0x04,0xD8,0x00,0x65,0xFE,0xC4,0xFF,0xE6,0xFF, + 0x9D,0xFC,0xE6,0xFA,0x89,0xFA,0xDB,0xF8,0xBA,0xF9,0xA4,0xFA, + 0x69,0xF9,0x1D,0xF9,0xE6,0xFA,0x58,0xFC,0x9D,0xFD,0x1A,0x01, + 0x49,0x02,0x64,0x01,0x98,0x02,0xDC,0x03,0x22,0x03,0x5B,0x02, + 0xD7,0x02,0xF3,0x01,0x34,0x01,0x5A,0x02,0x08,0x02,0xBA,0x00, + 0xDE,0xFF,0x74,0xFF,0x57,0xFE,0x19,0xFE,0x08,0xFF,0x33,0xFE, + 0x07,0x02,0x19,0x06,0x3C,0x05,0x73,0x03,0x4D,0x04,0xE7,0x06, + 0x46,0x04,0xD5,0x02,0xAC,0x01,0x7C,0xFE,0xA0,0xFD,0x60,0xFE, + 0x06,0xFE,0x97,0xFA,0x2D,0xFA,0x03,0xFA,0x3E,0xF9,0xCC,0xFA, + 0xD1,0xFA,0x25,0xFA,0x9F,0xFA,0xD3,0xFD,0x81,0xFF,0x59,0x00, + 0xD9,0x02,0x61,0x02,0xFC,0x01,0x4A,0x03,0x1A,0x04,0x5F,0x02, + 0x39,0x01,0x28,0x02,0x0B,0x01,0xE8,0x00,0x3A,0x01,0xEE,0xFF, + 0xEC,0xFD,0x76,0xFC,0x88,0xFC,0x8F,0xFF,0x4E,0x05,0x7A,0x05, + 0x56,0x02,0xC7,0x03,0xC5,0x07,0x11,0x08,0x56,0x05,0x26,0x04, + 0x0F,0x01,0xE1,0xFE,0x65,0x00,0x28,0x00,0xA9,0xFC,0xFB,0xF9, + 0x17,0xFA,0x6D,0xF9,0xAB,0xF9,0x78,0xFA,0xFB,0xF8,0x88,0xF8, + 0x2A,0xFA,0x6D,0xFC,0x1E,0xFE,0x9E,0x00,0x26,0x02,0x7A,0x01, + 0xB9,0x02,0x20,0x04,0x8A,0x03,0x84,0x02,0x74,0x02,0x4F,0x02, + 0xA0,0x01,0x9C,0x02,0x71,0x02,0xC7,0x00,0xE0,0xFF,0x46,0xFF, + 0xD2,0xFE,0xFE,0xFD,0xE2,0xFE,0x0D,0xFE,0xBE,0xFF,0x58,0x05, + 0xCE,0x05,0x2A,0x04,0xA6,0x03,0x72,0x06,0xBC,0x05,0xB5,0x02, + 0x3D,0x02,0x59,0xFF,0xF1,0xFD,0x53,0xFE,0x84,0xFE,0xAC,0xFB, + 0x98,0xF9,0x29,0xFA,0x07,0xF9,0x0D,0xFA,0xEE,0xFA,0xFC,0xF9, + 0xFC,0xF9,0x74,0xFC,0x83,0xFF,0xF6,0xFF,0xE6,0x01,0xF4,0x02, + 0x0A,0x02,0x21,0x03,0x64,0x04,0x99,0x03,0x58,0x01,0xB7,0x01, + 0xFA,0x01,0x3B,0x01,0xB3,0x01,0x85,0x00,0xA7,0xFE,0x39,0xFD, + 0x85,0xFC,0xB3,0xFC,0xF8,0x00,0xE3,0x05,0x28,0x04,0x81,0x02, + 0x73,0x05,0x88,0x08,0x16,0x07,0x97,0x04,0x1E,0x03,0xE9,0xFF, + 0x93,0xFF,0x03,0x01,0x2D,0xFF,0x46,0xFB,0x91,0xF9,0xC4,0xF9, + 0x65,0xF9,0x52,0xFA,0x0D,0xFA,0x1F,0xF8,0x83,0xF8,0xE7,0xFA, + 0x34,0xFD,0x1F,0xFF,0x61,0x01,0xDA,0x01,0xC9,0x01,0xB9,0x03, + 0x9A,0x04,0x4B,0x03,0x5E,0x02,0x5B,0x02,0xFC,0x01,0x2E,0x02, + 0x20,0x03,0xF3,0x01,0xEF,0xFF,0x6A,0xFF,0x2F,0xFF,0xA7,0xFE, + 0x41,0xFE,0x9C,0xFE,0x7F,0xFD,0x9C,0x00,0x26,0x06,0xB8,0x05, + 0xFB,0x03,0x3A,0x04,0xB2,0x06,0x3C,0x05,0xBF,0x02,0xE3,0x01, + 0xC1,0xFE,0xCD,0xFD,0x9B,0xFE,0xCD,0xFD,0xE2,0xFA,0xB1,0xFA, + 0x46,0xF9,0x83,0xF7,0x6E,0xFB,0xB5,0xFA,0x21,0xF8,0xB9,0xF9, + 0x30,0xFD,0x36,0x00,0xC8,0x01,0xDB,0x03,0xFF,0x01,0xDB,0x02, + 0x38,0x06,0x3E,0x05,0x60,0x02,0x1B,0x00,0xFF,0x00,0x5D,0x00, + 0xF9,0xFF,0x3D,0xFE,0x9A,0xFB,0x97,0xFC,0x8E,0xFB,0xB1,0xF7, + 0xAE,0xFE,0x4E,0x10,0x98,0x0E,0xB6,0x06,0x01,0x0A,0xB1,0x0C, + 0x02,0x0F,0x82,0x08,0x3E,0xFC,0xFC,0xF6,0x20,0xFD,0x7E,0xFB, + 0x66,0xF2,0x30,0xEF,0x36,0xEF,0x73,0xF7,0x76,0xFB,0x4A,0xF8, + 0x24,0xF9,0xB5,0x02,0x43,0x08,0x7C,0x08,0x06,0x06,0xE7,0x01, + 0x9D,0x09,0x79,0x0B,0x9A,0x02,0x29,0xFC,0xEA,0xFB,0xC8,0xFD, + 0x68,0xFC,0x9D,0xF7,0x0F,0xF5,0xD7,0xFC,0x61,0x01,0xF0,0xFF, + 0x5D,0xFF,0x87,0x02,0xAE,0x06,0x02,0x07,0x56,0x01,0x5F,0xFF, + 0xA0,0x05,0x6C,0x01,0x8E,0x0B,0xB8,0x0F,0x77,0x02,0x82,0x06, + 0x83,0x06,0xEE,0x00,0x0D,0xFD,0x3C,0xF5,0x39,0xF2,0x1E,0xFA, + 0x2A,0xF7,0xDC,0xF2,0xC8,0xF7,0xC2,0xF9,0x4D,0xFF,0x67,0x01, + 0xD1,0xFD,0x8D,0x04,0x68,0x0B,0xDC,0x05,0xA2,0x05,0xDE,0x03, + 0x16,0x01,0x01,0x03,0x64,0xFD,0x4A,0xF9,0xC7,0xFB,0x5D,0xFB, + 0x21,0xFB,0xAB,0xFB,0x5F,0xFB,0x89,0x00,0xB1,0x03,0xBD,0x00, + 0x44,0x02,0x4A,0x03,0x7B,0x02,0x46,0x00,0x08,0xF8,0x65,0x00, + 0xE2,0x15,0x98,0x11,0x5E,0x04,0x79,0x07,0x26,0x0A,0x57,0x0A, + 0xF5,0xFD,0x0F,0xEF,0xD6,0xF6,0xD2,0xFC,0x7A,0xF4,0x2B,0xF0, + 0x62,0xF1,0xD1,0xFA,0x41,0x03,0xAE,0xFA,0xFA,0xF9,0x56,0x07, + 0x6B,0x0C,0xFB,0x09,0xE8,0x01,0xCD,0xFE,0xC1,0x07,0x58,0x06, + 0x96,0xFB,0x08,0xF8,0x5E,0xFB,0x43,0xFF,0x63,0xFB,0x84,0xF5, + 0x6F,0xFA,0x74,0x03,0x57,0x03,0x71,0x00,0x1A,0x01,0xC7,0x06, + 0xD0,0x08,0xF3,0x01,0x05,0xFD,0xCB,0xFE,0x25,0x04,0xFE,0xFD, + 0x20,0x02,0xAC,0x0D,0xE1,0x08,0xC1,0x07,0x90,0x04,0x1E,0x02, + 0x2D,0x04,0x39,0xFB,0xFF,0xF4,0xFD,0xF7,0x16,0xF7,0x15,0xF8, + 0x3E,0xF8,0x78,0xF5,0x50,0xFC,0x1A,0x00,0xE7,0xFD,0xEE,0x01, + 0x5B,0x04,0x8E,0x05,0x14,0x08,0x6C,0x03,0x71,0x00,0xA2,0x02, + 0x95,0x00,0xEC,0xFD,0x0C,0xFB,0x84,0xFA,0x34,0xFE,0x0C,0xFD, + 0x38,0xFB,0x78,0xFE,0xC4,0x00,0x2B,0x02,0xFD,0x01,0x36,0x00, + 0x7B,0x01,0xD7,0xFD,0x35,0xFC,0xC1,0x03,0x1D,0x0D,0x4D,0x10, + 0xB2,0x0A,0x57,0x09,0x95,0x0B,0xEF,0x08,0xB7,0xFF,0xF2,0xF6, + 0x74,0xF6,0x2C,0xF8,0xF1,0xF4,0xAE,0xF0,0xAD,0xF1,0xE3,0xF7, + 0xA7,0xFC,0x82,0xFB,0x6B,0xFC,0x47,0x03,0xBF,0x09,0x5C,0x09, + 0xDB,0x03,0xD9,0x02,0x53,0x06,0x17,0x06,0x36,0x00,0xB7,0xFA, + 0x43,0xFC,0x68,0xFE,0xCF,0xFA,0xBF,0xF7,0x7E,0xF9,0x27,0xFF, + 0xA1,0x01,0x2A,0x00,0xF6,0x00,0x0C,0x05,0xDD,0x06,0x21,0x04, + 0x10,0x00,0x11,0xFF,0xBA,0x03,0x84,0xFF,0x29,0x02,0x2E,0x0D, + 0xFD,0x08,0xC3,0x06,0x5B,0x05,0xA4,0x02,0xD6,0x03,0xF3,0xFB, + 0x19,0xF5,0xE7,0xF7,0xC1,0xF7,0xB7,0xF7,0x12,0xF8,0xF8,0xF5, + 0x78,0xFB,0xBD,0xFF,0x8B,0xFD,0x38,0x00,0x2D,0x03,0x92,0x04, + 0xF3,0x06,0xF6,0x03,0x40,0x01,0xB8,0x02,0x08,0x02,0x13,0x00, + 0x5B,0xFD,0x98,0xFB,0xF0,0xFD,0x9D,0xFD,0x76,0xFB,0xEE,0xFC, + 0xF3,0xFE,0xCC,0x00,0xC6,0x01,0x1E,0x01,0xE1,0x00,0x72,0x00, + 0xBD,0xFE,0xB8,0xFE,0xE8,0x05,0x27,0x0E,0x68,0x0C,0x6A,0x08, + 0x79,0x08,0x65,0x09,0xE5,0x06,0x1A,0xFE,0xD9,0xF7,0x53,0xF8, + 0xC1,0xF8,0x8F,0xF6,0x44,0xF3,0x47,0xF3,0xE5,0xF8,0x3E,0xFC, + 0x45,0xFB,0xBE,0xFC,0x0C,0x01,0x79,0x05,0x12,0x06,0xAB,0x02, + 0xFE,0x01,0x13,0x05,0xAD,0x06,0xBA,0x03,0xBE,0xFF,0xBE,0xFE, + 0x7E,0xFF,0x09,0xFE,0xB1,0xFA,0x01,0xFA,0x85,0xFC,0x3A,0xFF, + 0x86,0x00,0x8E,0x00,0xBF,0x01,0xCC,0x03,0x82,0x03,0x6D,0x01, + 0x18,0x00,0x30,0x01,0x77,0x00,0xAE,0x02,0xDF,0x07,0x10,0x07, + 0xE3,0x04,0x14,0x04,0x96,0x04,0xAF,0x03,0xD7,0xFE,0xFF,0xFA, + 0x30,0xFA,0x06,0xFB,0xFD,0xFB,0x7E,0xFA,0xE4,0xF8,0xB7,0xFA, + 0x9B,0xFC,0x00,0xFD,0x42,0xFD,0x69,0xFD,0xA7,0xFE,0xCD,0x00, + 0xC3,0x01,0x50,0x01,0x30,0x01,0xA7,0x02,0x4A,0x04,0x86,0x03, + 0x3E,0x01,0x63,0x00,0x20,0x00,0x71,0xFF,0x1E,0xFF,0x93,0xFE, + 0xEC,0xFE,0x46,0x00,0x65,0x00,0xE4,0xFF,0x50,0xFF,0x02,0xFE, + 0x49,0xFD,0x49,0xFE,0x3D,0x01,0x86,0x04,0x20,0x05,0xDA,0x04, + 0x1E,0x06,0xF6,0x06,0xAB,0x05,0x48,0x03,0x1C,0x01,0x2C,0x00, + 0x99,0x00,0xB8,0xFF,0x58,0xFD,0x29,0xFC,0xD0,0xFB,0x82,0xFB, + 0x7C,0xFB,0xA2,0xFA,0xB3,0xF9,0xFE,0xF9,0x8F,0xFA,0xFA,0xFA, + 0x2F,0xFC,0xFB,0xFD,0x20,0x00,0x99,0x02,0x99,0x03,0x6D,0x03, + 0x12,0x03,0x69,0x02,0x52,0x02,0x34,0x02,0x86,0x01,0x84,0x01, + 0xE6,0x01,0x9D,0x01,0x06,0x01,0xEC,0xFF,0xCA,0xFE,0x8D,0xFE, + 0x60,0xFE,0x90,0xFE,0x89,0xFE,0x45,0xFF,0x62,0x03,0xC1,0x05, + 0xFB,0x03,0x3C,0x05,0x38,0x07,0x30,0x05,0xD9,0x03,0xD3,0x01, + 0xDE,0xFE,0xED,0xFF,0xFB,0xFF,0x07,0xFD,0x26,0xFC,0x01,0xFB, + 0xC8,0xF9,0xE1,0xFA,0x29,0xFA,0x7D,0xF8,0x58,0xF9,0xA1,0xFA, + 0x5B,0xFC,0x16,0xFE,0x0B,0xFE,0xB5,0xFF,0xC3,0x02,0x66,0x03, + 0x79,0x03,0x45,0x03,0xFF,0x01,0xA6,0x02,0x69,0x03,0x2E,0x02, + 0xCC,0x01,0xA7,0x01,0x21,0x01,0x04,0x01,0xA4,0xFF,0xDB,0xFD, + 0xEE,0xFC,0xE4,0xFC,0xF5,0xFF,0xAB,0x03,0x95,0x03,0xC5,0x03, + 0xA4,0x06,0xE6,0x07,0xEA,0x06,0xE5,0x04,0x14,0x02,0x6A,0x01, + 0x0B,0x02,0x06,0x00,0x27,0xFD,0x65,0xFB,0x00,0xFA,0x15,0xFA, + 0x44,0xFA,0x90,0xF8,0x5A,0xF7,0x0D,0xF8,0x9C,0xF9,0xCB,0xFA, + 0x48,0xFB,0xCC,0xFC,0x09,0x00,0xC0,0x02,0xFC,0x03,0x2F,0x04, + 0xAC,0x03,0xAF,0x03,0x20,0x04,0xB0,0x03,0xE0,0x02,0x8C,0x02, + 0x93,0x02,0xB9,0x02,0xF8,0x01,0x5E,0x00,0x57,0xFF,0x23,0xFF, + 0xF0,0xFE,0x95,0xFE,0x3B,0xFE,0x96,0xFD,0xB3,0xFF,0x4B,0x04, + 0x4E,0x04,0xB6,0x02,0x72,0x05,0x38,0x06,0x55,0x04,0x77,0x03, + 0x54,0x00,0xB1,0xFE,0xA4,0x00,0x1C,0xFF,0x83,0xFC,0xEB,0xFB, + 0xE5,0xF9,0xB7,0xF9,0x0B,0xFB,0x50,0xF9,0x95,0xF8,0x02,0xFA, + 0xB1,0xFA,0xD0,0xFC,0x9E,0xFE,0x72,0xFE,0xA8,0x00,0x90,0x03, + 0x13,0x04,0x5F,0x04,0xB8,0x03,0x8E,0x02,0x42,0x03,0x6F,0x03, + 0x7B,0x02,0x24,0x02,0x7C,0x01,0x1D,0x01,0x25,0x01,0x7B,0xFF, + 0xEF,0xFD,0xE4,0xFD,0x07,0xFD,0x08,0xFD,0xA8,0x00,0x94,0x03, + 0xFC,0x02,0xB4,0x03,0x87,0x06,0x34,0x07,0x17,0x06,0x22,0x04, + 0x8F,0x01,0x39,0x01,0x8B,0x01,0x68,0xFF,0x21,0xFD,0x63,0xFB, + 0xDD,0xF9,0x60,0xFA,0x6A,0xFA,0x6F,0xF8,0x98,0xF7,0x70,0xF8, + 0xD3,0xF9,0x4F,0xFB,0x09,0xFC,0x79,0xFD,0x7F,0x00,0xD4,0x02, + 0xF2,0x03,0x9E,0x04,0x20,0x04,0x98,0x03,0x34,0x04,0x00,0x04, + 0x0C,0x03,0xC2,0x02,0x80,0x02,0x34,0x02,0xB0,0x01,0x42,0x00, + 0x25,0xFF,0xE7,0xFE,0x61,0xFE,0x44,0xFE,0x1B,0xFE,0x50,0xFD, + 0x31,0x00,0x61,0x04,0x42,0x03,0x17,0x03,0x7D,0x06,0x91,0x05, + 0xDE,0x03,0xBF,0x03,0x2E,0x00,0x0E,0xFF,0xD5,0x00,0x5B,0xFE, + 0x9A,0xFC,0x70,0xFC,0xBF,0xF9,0xD8,0xF9,0x1A,0xFB,0x14,0xF9, + 0xFB,0xF8,0x54,0xFA,0x6B,0xFA,0x82,0xFC,0x55,0xFE,0x9D,0xFE, + 0xFD,0x00,0x2E,0x03,0xF2,0x03,0xCD,0x04,0xDC,0x03,0xCE,0x02, + 0x76,0x03,0x08,0x03,0x73,0x02,0x9C,0x02,0xAA,0x01,0x39,0x01, + 0x4D,0x01,0xCE,0xFF,0x61,0xFE,0x06,0xFE,0xC5,0xFD,0x95,0xFD, + 0x3F,0xFE,0x49,0x01,0xB5,0x03,0xED,0x02,0x0D,0x04,0xC4,0x06, + 0x1D,0x06,0xE1,0x04,0xAD,0x03,0x0A,0x01,0xBF,0x00,0xEA,0x00, + 0x43,0xFE,0x7C,0xFC,0x7B,0xFB,0xFE,0xF9,0x5E,0xFA,0x2F,0xFA, + 0x3D,0xF8,0x1E,0xF8,0x37,0xF9,0x41,0xFA,0xDF,0xFB,0xF3,0xFC, + 0x85,0xFE,0x45,0x01,0xE1,0x02,0xF2,0x03,0xE5,0x04,0x14,0x04, + 0xB2,0x03,0x5C,0x04,0xAA,0x03,0x05,0x03,0xE9,0x02,0x12,0x02, + 0xD3,0x01,0x8B,0x01,0x25,0x00,0x54,0xFF,0xDC,0xFE,0x23,0xFE, + 0x52,0xFE,0xD8,0xFD,0x87,0xFD,0x24,0x01,0xC1,0x03,0x57,0x02, + 0x9A,0x03,0x02,0x06,0x02,0x05,0x5E,0x04,0xFC,0x02,0xF0,0xFF, + 0x1F,0x00,0x51,0x00,0xC0,0xFD,0xB4,0xFC,0x88,0xFB,0xA9,0xF9, + 0x93,0xFA,0xD1,0xFA,0x3E,0xF9,0x84,0xF9,0x3D,0xFA,0xD8,0xFA, + 0xE2,0xFC,0x28,0xFE,0xF5,0xFE,0x2B,0x01,0x0B,0x03,0x38,0x04, + 0xDA,0x04,0xF3,0x03,0x5B,0x03,0xA9,0x03,0x2C,0x03,0xB0,0x02, + 0x61,0x02,0x7C,0x01,0x24,0x01,0x08,0x01,0xE3,0xFF,0x9F,0xFE, + 0x17,0xFE,0xE3,0xFD,0x80,0xFD,0x5F,0xFE,0x63,0x01,0xB2,0x02, + 0x1B,0x02,0x1D,0x04,0x3B,0x06,0x98,0x05,0x00,0x05,0x7F,0x03, + 0x1A,0x01,0x15,0x01,0x96,0x00,0x04,0xFE,0x86,0xFC,0x3C,0xFB, + 0x17,0xFA,0xCA,0xFA,0x7D,0xFA,0xD2,0xF8,0xC1,0xF8,0x9B,0xF9, + 0x91,0xFA,0xF0,0xFB,0xE0,0xFC,0x6E,0xFE,0xE1,0x00,0x93,0x02, + 0xE9,0x03,0xD0,0x04,0x55,0x04,0x04,0x04,0x52,0x04,0xD2,0x03, + 0x30,0x03,0xC4,0x02,0xFB,0x01,0xB4,0x01,0x76,0x01,0x7C,0x00, + 0xB8,0xFF,0x36,0xFF,0x77,0xFE,0x78,0xFE,0x63,0xFE,0x4A,0xFD, + 0x05,0xFF,0x79,0x02,0x30,0x02,0xF5,0x01,0xC8,0x04,0x28,0x05, + 0x18,0x04,0xE3,0x03,0x5F,0x01,0xAC,0xFF,0x61,0x00,0xB7,0xFE, + 0xD1,0xFC,0x89,0xFC,0xAB,0xFA,0x1B,0xFA,0x96,0xFB,0xC1,0xFA, + 0xEB,0xF9,0xE3,0xFA,0xFF,0xFA,0xFA,0xFB,0xFD,0xFD,0x86,0xFE, + 0xC9,0xFF,0x0C,0x02,0x25,0x03,0x4D,0x04,0xC0,0x04,0x9B,0x03, + 0x78,0x03,0x87,0x03,0x8E,0x02,0x58,0x02,0xFE,0x01,0x02,0x01, + 0xFD,0x00,0xCA,0x00,0x9F,0xFF,0xED,0xFE,0x63,0xFE,0x97,0xFD, + 0x25,0xFE,0x0F,0x00,0x2A,0x01,0x40,0x01,0x4D,0x02,0x1B,0x04, + 0xF7,0x04,0xD4,0x04,0xBD,0x03,0xF9,0x01,0x1D,0x01,0xC9,0x00, + 0x6C,0xFF,0x99,0xFD,0x2F,0xFC,0x51,0xFB,0x76,0xFB,0xD0,0xFB, + 0x1F,0xFB,0x3C,0xFA,0x32,0xFA,0xD9,0xFA,0xC1,0xFB,0x7A,0xFC, + 0x5C,0xFD,0xE3,0xFE,0xA1,0x00,0x5B,0x02,0x8F,0x03,0xC8,0x03, + 0xBA,0x03,0xCA,0x03,0xB4,0x03,0x72,0x03,0xDC,0x02,0x19,0x02, + 0xC4,0x01,0xAE,0x01,0x51,0x01,0xC3,0x00,0x3C,0x00,0xC4,0xFF, + 0x75,0xFF,0x01,0xFF,0xA9,0xFE,0x28,0xFE,0x1D,0xFE,0x38,0x00, + 0x16,0x02,0x96,0x01,0x28,0x02,0xF9,0x03,0xAA,0x03,0x04,0x03, + 0x74,0x02,0x57,0x00,0x44,0xFF,0x6B,0xFF,0x24,0xFE,0xF9,0xFC, + 0x4F,0xFC,0x1E,0xFB,0x44,0xFB,0x43,0xFC,0xF7,0xFB,0x89,0xFB, + 0xF3,0xFB,0x48,0xFC,0x53,0xFD,0xA4,0xFE,0x5B,0xFF,0x42,0x00, + 0xD4,0x01,0x21,0x03,0x1B,0x04,0x1A,0x04,0x7A,0x03,0x21,0x03, + 0x97,0x02,0x88,0x02,0xE7,0x00,0x81,0x02,0x9D,0x02,0xFF,0xFE, + 0x24,0xFF,0x9C,0xFE,0x26,0xFE,0x57,0xFD,0x44,0xFC,0x73,0xFE, + 0x83,0x02,0x8B,0x04,0x39,0x03,0x1E,0x02,0x53,0x04,0x97,0x07, + 0xC4,0x07,0xCD,0x03,0x41,0xFF,0x7D,0xFE,0x01,0xFF,0xD8,0xFD, + 0x58,0xFA,0x3A,0xF6,0xD5,0xF5,0xD4,0xF8,0xEF,0xFA,0x1E,0xFB, + 0x9F,0xFA,0xE1,0xFB,0x2A,0x00,0x67,0x03,0x3C,0x03,0xED,0x02, + 0x3E,0x04,0x04,0x06,0xD6,0x06,0xBD,0x04,0x83,0x01,0x3C,0x00, + 0x7B,0xFF,0x3A,0xFE,0xBB,0xFC,0x64,0xFB,0xE7,0xFB,0x4F,0xFE, + 0x1D,0x00,0x9F,0x00,0x53,0x01,0x53,0x02,0xA4,0x03,0x7C,0x03, + 0x86,0x01,0x29,0xFF,0xBB,0xFC,0xB1,0xFF,0x7C,0x07,0xBE,0x08, + 0xB6,0x03,0x61,0x01,0x3A,0x02,0x00,0x05,0x65,0x05,0xCD,0xFE, + 0x24,0xF9,0x99,0xF9,0xCF,0xFA,0xA9,0xFA,0xDE,0xF7,0x78,0xF4, + 0x32,0xF7,0x36,0xFD,0xCD,0xFF,0x3A,0x00,0x8C,0x00,0x72,0x02, + 0x90,0x06,0x1A,0x07,0x9A,0x03,0x02,0x02,0x61,0x02,0xB2,0x02, + 0xDB,0x01,0x7A,0xFE,0x87,0xFC,0xC5,0xFD,0x60,0xFE,0xD3,0xFD, + 0x2A,0xFD,0x7E,0xFD,0xFB,0xFF,0x90,0x02,0xA0,0x02,0xF6,0x01, + 0x73,0x02,0x42,0x03,0x40,0x03,0x86,0x01,0xAD,0xFE,0x58,0xFD, + 0xF1,0xFB,0xB6,0xFC,0x89,0x05,0x7D,0x09,0xD3,0x04,0xCD,0x03, + 0x2C,0x04,0xB6,0x04,0x83,0x05,0xA7,0xFF,0xC6,0xF8,0xB1,0xF8, + 0xEB,0xF8,0xE0,0xF7,0x16,0xF7,0xAB,0xF4,0xD1,0xF6,0x75,0xFD, + 0x14,0x00,0x8B,0x01,0x51,0x04,0xF4,0x04,0xDB,0x06,0x44,0x08, + 0xF5,0x04,0xFB,0x02,0x62,0x02,0xDF,0xFF,0x0D,0xFF,0x67,0xFD, + 0x97,0xFA,0x53,0xFC,0xC4,0xFD,0xE9,0xFC,0xED,0xFD,0x39,0xFF, + 0x2F,0x01,0xEC,0x03,0x8C,0x03,0x1E,0x02,0xD9,0x02,0xD1,0x00, + 0xE5,0x00,0xE0,0xFF,0x9B,0xFA,0xD2,0xFC,0x39,0x04,0xE6,0x0A, + 0xEA,0x09,0xF9,0x03,0xEC,0x02,0xE7,0x05,0xE9,0x06,0xF0,0x01, + 0x3C,0xFA,0x80,0xF6,0x43,0xF8,0xDE,0xF8,0x6C,0xF5,0x3F,0xF2, + 0xBD,0xF3,0xE1,0xF9,0x87,0xFF,0x4B,0x01,0x6B,0x01,0xE0,0x04, + 0x43,0x09,0xAC,0x09,0xA5,0x07,0x44,0x04,0x9C,0x02,0x22,0x03, + 0x8A,0x00,0x5C,0xFC,0x9D,0xFA,0x49,0xFA,0xE9,0xFB,0x7C,0xFD, + 0x9D,0xFC,0x7B,0xFD,0xBA,0x00,0x0E,0x03,0x70,0x04,0xA0,0x04, + 0xDA,0x03,0x0B,0x04,0xF1,0x03,0x1A,0x01,0xA8,0xFE,0x8A,0xFC, + 0x03,0xFA,0x09,0xFB,0xE6,0x01,0x73,0x0B,0xB8,0x09,0x1E,0x02, + 0xB0,0x02,0x83,0x05,0x51,0x06,0x71,0x02,0xAA,0xF9,0xF0,0xF5, + 0x23,0xF9,0x52,0xF9,0xD7,0xF5,0x76,0xF3,0x50,0xF4,0xF8,0xFA, + 0xE3,0x00,0x4F,0x01,0xC0,0x02,0x62,0x05,0xE4,0x07,0x5C,0x0A, + 0xF3,0x07,0x79,0x03,0x63,0x02,0xF9,0x01,0x75,0xFF,0x05,0xFC, + 0x69,0xF9,0x8D,0xFA,0xFC,0xFC,0xDD,0xFC,0x02,0xFD,0x33,0xFF, + 0xCD,0x01,0xE8,0x03,0x17,0x04,0x83,0x02,0x9B,0x02,0x02,0x02, + 0xB7,0x00,0xFF,0xFC,0xD3,0xF9,0x1C,0xFD,0xA0,0x05,0x6F,0x0E, + 0xF5,0x0A,0x1B,0x04,0x8D,0x05,0x2F,0x08,0x18,0x07,0x4A,0x00, + 0xC0,0xF6,0x41,0xF4,0xEE,0xF7,0xBD,0xF6,0xF3,0xF1,0x30,0xF0, + 0x23,0xF3,0x21,0xFB,0xB1,0x00,0x52,0x00,0xF5,0x01,0x21,0x07, + 0x14,0x0C,0x27,0x0C,0xCE,0x07,0xC8,0x04,0xB1,0x04,0x86,0x04, + 0x13,0x00,0xD9,0xFA,0x70,0xF9,0x16,0xFA,0x73,0xFB,0xC8,0xFB, + 0x29,0xFB,0xDE,0xFC,0xC4,0x00,0x56,0x03,0x15,0x04,0x0B,0x04, + 0x70,0x04,0x3A,0x05,0x55,0x04,0x5B,0x00,0x31,0xFE,0xA4,0xFF, + 0xB5,0xFB,0x88,0xF8,0x84,0xFD,0x16,0x06,0x8E,0x0A,0x45,0x07, + 0xD1,0x03,0xBC,0x04,0x37,0x07,0xBA,0x05,0xA6,0xFF,0x46,0xF9, + 0x64,0xF7,0x7C,0xF8,0xFA,0xF6,0x23,0xF3,0x12,0xF2,0x64,0xF5, + 0x89,0xFA,0x16,0xFE,0xA3,0xFF,0x5A,0x03,0x49,0x07,0x4A,0x09, + 0x4C,0x0A,0x6F,0x09,0xEF,0x07,0x18,0x06,0xA0,0x03,0x2A,0x00, + 0x50,0xFC,0xBE,0xFA,0x8E,0xFA,0xE7,0xF9,0x84,0xF9,0x14,0xFB, + 0xD7,0xFD,0x2A,0x00,0xAB,0x01,0xF5,0x02,0xDF,0x03,0x13,0x04, + 0x77,0x03,0x51,0x02,0xAA,0x00,0xCC,0xFC,0xA5,0xFB,0xC1,0xFE, + 0x99,0x07,0xAC,0x0D,0xEC,0x06,0x49,0x03,0xCC,0x05,0xDF,0x05, + 0xA8,0x04,0x3B,0xFE,0x5B,0xF6,0x5A,0xF7,0xEE,0xF8,0x3F,0xF5, + 0x27,0xF3,0x5C,0xF2,0x99,0xF5,0x88,0xFC,0x6B,0xFE,0x4D,0xFE, + 0xEF,0x02,0xFB,0x07,0xBA,0x09,0xB2,0x09,0x2B,0x07,0xDF,0x06, + 0x13,0x08,0xFE,0x03,0x89,0xFF,0xDF,0xFC,0xE0,0xFA,0x2C,0xFC, + 0xCE,0xFB,0xCE,0xF8,0x48,0xFA,0x2A,0xFE,0x03,0x00,0x2A,0x01, + 0xB5,0x01,0x7A,0x02,0x09,0x05,0x31,0x05,0x24,0x01,0xB5,0xFF, + 0x70,0x00,0xB2,0xFD,0xFC,0xFB,0x26,0xFC,0x9E,0x04,0x79,0x0E, + 0x0D,0x09,0x43,0x04,0x3E,0x05,0x36,0x05,0x6B,0x06,0x50,0x01, + 0xA1,0xF7,0x75,0xF6,0x87,0xF8,0x17,0xF6,0x57,0xF4,0x0B,0xF2, + 0x2B,0xF3,0xBF,0xFA,0x6A,0xFD,0x6A,0xFD,0xB2,0x01,0x05,0x06, + 0x1C,0x09,0x43,0x0A,0xE7,0x07,0xC5,0x07,0x4A,0x09,0x9B,0x05, + 0x70,0x01,0xA2,0xFE,0xBD,0xFB,0xB0,0xFC,0x2F,0xFC,0x7F,0xF8, + 0xBE,0xF9,0xC1,0xFC,0x32,0xFE,0xFC,0xFF,0xB7,0x00,0xF8,0x01, + 0x1E,0x05,0x06,0x04,0xD8,0x00,0xD0,0x00,0x55,0x01,0x69,0x01, + 0xAE,0xFE,0xCF,0xFA,0x85,0xFE,0x75,0x0B,0xFA,0x0C,0xB0,0x04, + 0x5B,0x03,0x18,0x03,0x82,0x05,0x62,0x05,0x81,0xFB,0x45,0xF6, + 0xF2,0xF8,0xC6,0xF8,0x4E,0xF7,0x65,0xF4,0x0A,0xF2,0x32,0xF8, + 0x19,0xFD,0x45,0xFC,0x82,0xFE,0x19,0x02,0xE8,0x05,0x1E,0x09, + 0x04,0x07,0xAD,0x05,0xCB,0x08,0xC4,0x07,0xE6,0x03,0x8E,0x01, + 0x17,0xFE,0x2F,0xFE,0x0A,0xFF,0x1E,0xFB,0x4A,0xFA,0x4C,0xFC, + 0xBB,0xFC,0x9A,0xFE,0x6D,0xFF,0x24,0xFF,0x1D,0x02,0x91,0x03, + 0x56,0x01,0x90,0x01,0xB2,0x01,0xE9,0x01,0x85,0x03,0x4A,0xFF, + 0xD2,0xFB,0x53,0xFE,0xF6,0x05,0x22,0x0B,0x54,0x05,0xA9,0x00, + 0xB4,0x01,0x01,0x04,0xD7,0x04,0x78,0xFF,0xF0,0xF8,0x7C,0xF9, + 0xF6,0xFB,0x8A,0xFA,0xAF,0xF7,0x65,0xF5,0x3B,0xF7,0xDB,0xFB, + 0x91,0xFC,0x23,0xFC,0x10,0xFF,0x9D,0x02,0x40,0x05,0x4F,0x05, + 0x0A,0x04,0xD2,0x05,0x4E,0x07,0x28,0x05,0x05,0x03,0x19,0x01, + 0xF8,0xFF,0xBE,0x00,0xF8,0xFE,0x77,0xFC,0x04,0xFD,0x28,0xFE, + 0xD9,0xFD,0xA8,0xFE,0x05,0x00,0x85,0x00,0x21,0x02,0x0E,0x01, + 0xCC,0xFF,0xC5,0x00,0x45,0x00,0xE2,0x01,0xF1,0x01,0x54,0xFF, + 0x52,0xFF,0xB7,0xFE,0x03,0x00,0xC4,0x04,0x82,0x05,0xFC,0x01, + 0x23,0x01,0x09,0x02,0xD2,0x01,0x54,0x01,0x16,0xFE,0x9D,0xFB, + 0x44,0xFD,0x5D,0xFD,0xF9,0xFB,0xF8,0xFA,0x17,0xFA,0xB2,0xFB, + 0xB4,0xFD,0x05,0xFD,0x33,0xFE,0xAD,0xFF,0x9F,0x00,0x97,0x02, + 0x50,0x01,0xA5,0x01,0x9E,0x02,0x58,0x02,0x5C,0x02,0x49,0x01, + 0x30,0x01,0x7F,0x01,0x1E,0x01,0xC4,0x00,0x4A,0x00,0x49,0x00, + 0x56,0x00,0x74,0x00,0x9F,0x00,0x21,0x00,0xAE,0x00,0x2C,0x00, + 0xD5,0xFF,0xA2,0x00,0xE8,0xFF,0x12,0x00,0xBB,0x00,0x57,0xFF, + 0xAD,0xFF,0x43,0x00,0x6E,0xFF,0x11,0x00,0xCD,0xFF,0x9C,0xFF, + 0xEB,0xFF,0xE8,0xFF,0x2B,0x00,0x14,0x00,0xE4,0xFF,0x7F,0xFF, + 0xBA,0xFF,0xC3,0xFF,0x9E,0xFF,0xCF,0xFF,0x6B,0xFF,0x89,0xFF, + 0xB0,0xFF,0x92,0xFF,0xA9,0xFF,0x99,0xFF,0x60,0xFF,0x65,0xFF, + 0x7B,0xFF,0x6F,0xFF,0xA3,0xFF,0x90,0xFF,0x80,0xFF,0xB2,0xFF, + 0xCF,0xFF,0xE1,0xFF,0xF5,0xFF,0x10,0x00,0x33,0x00,0x6E,0x00, + 0x6F,0x00,0x87,0x00,0xAD,0x00,0xB0,0x00,0xC9,0x00,0xC7,0x00, + 0x95,0x00,0xBA,0x00,0xB5,0x00,0xAA,0x00,0xAE,0x00,0x5F,0x00, + 0x86,0x00,0x4A,0x00,0x94,0x00,0x34,0x00,0xD0,0xFF,0x2D,0x00, + 0xB5,0xFF,0xD8,0xFF,0xBA,0xFF,0x8F,0xFF,0x8C,0xFF,0x9A,0xFF, + 0x96,0xFF,0x9B,0xFF,0x97,0xFF,0xA0,0xFF,0xCC,0xFF,0xB5,0xFF, + 0xDA,0xFF,0xC2,0xFF,0xC0,0xFF,0xD3,0xFF,0xCB,0xFF,0xC8,0xFF, + 0xBE,0xFF,0xBE,0xFF,0xC7,0xFF,0xCB,0xFF,0xC8,0xFF,0xD1,0xFF, + 0xDF,0xFF,0xF0,0xFF,0xFC,0xFF,0xFC,0xFF,0x07,0x00,0x1D,0x00, + 0x22,0x00,0x20,0x00,0x27,0x00,0x33,0x00,0x3F,0x00,0x45,0x00, + 0x44,0x00,0x46,0x00,0x4C,0x00,0x55,0x00,0x53,0x00,0x50,0x00, + 0x44,0x00,0x3B,0x00,0x3B,0x00,0x2D,0x00,0x19,0x00,0x0C,0x00, + 0x02,0x00,0xF7,0xFF,0xF0,0xFF,0xDC,0xFF,0xD7,0xFF,0xD6,0xFF, + 0xD0,0xFF,0xD7,0xFF,0xD7,0xFF,0xD0,0xFF,0xD1,0xFF,0xDA,0xFF, + 0xDB,0xFF,0xD7,0xFF,0xE9,0xFF,0xEA,0xFF,0xEF,0xFF,0xF7,0xFF, + 0xF5,0xFF,0xFE,0xFF,0x03,0x00,0x07,0x00,0x06,0x00,0x0A,0x00, + 0x08,0x00,0x0B,0x00,0x08,0x00,0x04,0x00,0x06,0x00,0x04,0x00, + 0x04,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0xFF,0xFF,0x02,0x00,0x07,0x00,0x07,0x00,0x08,0x00,0x09,0x00, + 0x0A,0x00,0x0C,0x00,0x0A,0x00,0x0A,0x00,0x09,0x00,0x08,0x00, + 0x08,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0xFD,0xFF,0xFA,0xFF, + 0xFA,0xFF,0xFA,0xFF,0xF8,0xFF,0xF5,0xFF,0xF6,0xFF,0xF6,0xFF, + 0xF8,0xFF,0xFA,0xFF,0xFB,0xFF,0xFB,0xFF,0xFE,0xFF,0x00,0x00, + 0x01,0x00,0x02,0x00,0x04,0x00,0x05,0x00,0x03,0x00,0x05,0x00, + 0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x03,0x00, + 0x03,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0xFE,0xFF,0x00,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0x01,0x00,0x02,0x00,0xFB,0xFF,0x04,0x00,0xF3,0xFF, + 0x03,0x00,0x10,0x00,0x0E,0x00,0xD1,0xFF,0xC8,0xFF,0x22,0x00, + 0x01,0x00,0x1A,0x00,0xF9,0xFF,0x18,0x00,0x27,0x00,0x9F,0xFF, + 0x06,0x00,0x2D,0x00,0xF7,0xFF,0x08,0x00,0xF7,0xFF,0x05,0x00, + 0xF7,0xFF,0x08,0x00,0x15,0x00,0xCC,0xFF,0x06,0x00,0x19,0x00, + 0xF1,0xFF,0x0E,0x00,0xFE,0xFF,0x08,0x00,0x01,0x00,0xF8,0xFF, + 0x04,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0xFB,0xFF,0x02,0x00,0x02,0x00, + 0xFD,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0xFE,0xFF,0x03,0x00,0xFE,0xFF,0x08,0x00,0xFC,0xFF,0xE4,0xFF, + 0x14,0x00,0x06,0x00,0xF5,0xFF,0x04,0x00,0x02,0x00,0x02,0x00, + 0x01,0x00,0xFE,0xFF,0xFF,0xFF,0x0C,0x00,0xF3,0xFF,0xFD,0xFF, + 0x0F,0x00,0xF8,0xFF,0xFC,0xFF,0x05,0x00,0x00,0x00,0x02,0x00, + 0xFF,0xFF,0xFE,0xFF,0x00,0x00,0xFE,0xFF,0x02,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00, + 0x03,0x00,0x02,0x00,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x04,0x00,0x04,0x00,0x00,0x00,0xFF,0xFF,0xFD,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00,0x02,0x00, + 0xFF,0xFF,0x01,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00,0x01,0x00, + 0x00,0x00,0xFE,0xFF,0x02,0x00,0x03,0x00,0x01,0x00,0xFE,0xFF, + 0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xF7,0xFF,0x03,0x00, + 0x06,0x00,0xF7,0xFF,0x03,0x00,0x03,0x00,0xFF,0xFF,0x01,0x00, + 0xFF,0xFF,0x02,0x00,0xFF,0xFF,0x00,0x00,0x03,0x00,0x00,0x00, + 0xFF,0xFF,0xFB,0xFF,0xFC,0xFF,0x03,0x00,0x04,0x00,0x02,0x00, + 0xFE,0xFF,0xFB,0xFF,0xFE,0xFF,0x02,0x00,0x02,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00,0xFE,0xFF, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFB,0xFF,0x04,0x00,0x05,0x00,0xF6,0xFF,0x04,0x00,0x06,0x00, + 0xFA,0xFF,0x00,0x00,0xFF,0xFF,0x01,0x00,0x02,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x03,0x00, + 0xFF,0xFF,0xFE,0xFF,0x00,0x00,0x01,0x00,0x03,0x00,0x02,0x00, + 0x09,0x00,0xF0,0xFF,0xF5,0xFF,0x04,0x00,0xFF,0xFF,0x0D,0x00, + 0x02,0x00,0xFD,0xFF,0x00,0x00,0xFF,0xFF,0xFE,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00, + 0xFF,0xFF,0xFD,0xFF,0x01,0x00,0x03,0x00,0xFE,0xFF,0xFD,0xFF, + 0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x02,0x00,0xFF,0xFF, + 0x01,0x00,0xFE,0xFF,0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00, + 0x00,0x00,0x01,0x00,0xFF,0xFF,0x04,0x00,0xF7,0xFF,0x0A,0x00, + 0xEF,0xFF,0x13,0x00,0xE1,0xFF,0x20,0x00,0x1D,0x00,0xA9,0xFF, + 0x34,0x00,0xEF,0xFF,0xFF,0xFF,0x0E,0x00,0xF8,0xFF,0x14,0x00, + 0xF0,0xFF,0x0A,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0x04,0x00, + 0xFF,0xFF,0xFD,0xFF,0xFD,0xFF,0x00,0x00,0xFC,0xFF,0xFD,0xFF, + 0x01,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xFD,0xFF,0xFC,0xFF,0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x07,0x00,0xF5,0xFF, + 0x0C,0x00,0xF5,0xFF,0x08,0x00,0xF7,0xFF,0x03,0x00,0xFC,0xFF, + 0x06,0x00,0xFF,0xFF,0xF9,0xFF,0x0A,0x00,0xF5,0xFF,0x42,0x00, + 0xA8,0xFF,0x92,0x00,0xEC,0xFE,0x70,0x01,0x6F,0x02,0x9C,0xFE, + 0x79,0xFF,0x9E,0xFD,0x5B,0xFF,0x19,0x00,0x94,0xFF,0xF4,0x00, + 0xC7,0xFF,0x01,0x00,0x6C,0x00,0xC1,0x00,0xF2,0xFF,0x72,0x00, + 0xBC,0xFF,0x9B,0x00,0xFD,0x02,0x7D,0xFE,0x4B,0x01,0x47,0xFF, + 0xF9,0xFB,0x19,0x00,0xDF,0xFD,0x89,0x00,0xA6,0x00,0xA2,0xFF, + 0x38,0x01,0xB9,0x00,0x18,0xFF,0xC1,0x01,0x66,0x01,0x6A,0xFF, + 0x96,0x01,0x8A,0xFE,0x8C,0xFF,0x69,0x00,0x28,0xFF,0x84,0x00, + 0x7C,0x00,0xDA,0xFF,0xE7,0xFF,0x34,0x00,0x3D,0xFF,0xFB,0xFF, + 0xB4,0xFF,0xD7,0xFF,0x8B,0x00,0x8E,0xFE,0x9F,0x00,0x8F,0xFF, + 0x5C,0x00,0x78,0xFF,0x00,0x00,0x46,0x01,0x1B,0xFF,0xE4,0xFF, + 0x6B,0x00,0x60,0x00,0xAB,0xFE,0x0E,0x01,0xD2,0xFF,0x20,0xFF, + 0x7E,0x00,0x45,0x00,0x51,0xFF,0x38,0x01,0x14,0x00,0x2B,0xFE, + 0xCC,0x01,0xA7,0xFF,0xE5,0xFF,0xC7,0x01,0x80,0xFD,0x40,0x01, + 0x1B,0x00,0xFE,0xFD,0x2D,0x02,0x76,0xFE,0xCA,0x00,0xB8,0x00, + 0xA5,0xFF,0x15,0x00,0x07,0x01,0x4F,0x00,0x9A,0xFE,0x3F,0x01, + 0x3D,0xFF,0xBC,0x00,0x27,0x00,0x32,0xFE,0x25,0x01,0xB6,0xFF, + 0x0D,0xFF,0xC1,0x00,0xB5,0xFF,0x98,0xFF,0x51,0x01,0x12,0xFF, + 0x7F,0xFE,0x3D,0x02,0x13,0xFF,0x8F,0xFF,0xE0,0x01,0xE3,0xFD, + 0x32,0x00,0x50,0x02,0xE2,0xFD,0x47,0x00,0xCB,0x00,0xF6,0xFD, + 0xC4,0x00,0xF5,0xFE,0xCE,0x00,0xFC,0xFF,0x8A,0xFF,0xC0,0x01, + 0xED,0xFF,0xFD,0xFD,0x9B,0x03,0xFE,0xFE,0x38,0xFD,0x6B,0x04, + 0x66,0xFC,0x27,0x01,0xC0,0x00,0x48,0x00,0xF6,0xFD,0xD9,0x01, + 0xFE,0xFE,0xAD,0xFD,0x83,0x04,0x49,0xFB,0xD1,0x02,0xA6,0xFE, + 0xFE,0xFF,0x84,0x02,0xD0,0xFC,0x33,0x02,0x88,0x02,0x0A,0xFA, + 0xA8,0x02,0x42,0x04,0x1F,0xFA,0x8F,0x02,0x7C,0xFF,0x90,0x00, + 0x5D,0xFF,0xA5,0x00,0x7D,0x00,0x2A,0x00,0x69,0xFE,0x15,0xFD, + 0xAE,0x02,0x6A,0xFD,0x47,0x02,0x95,0xFE,0x1F,0x00,0xC4,0x03, + 0xA2,0xFE,0x0F,0x00,0x03,0x03,0xE8,0xFC,0xAA,0x01,0x7B,0x01, + 0xBE,0xFC,0xE4,0x02,0x7B,0xFB,0x1C,0x00,0x1F,0x02,0x8F,0xFB, + 0x68,0x00,0xCC,0x06,0x6F,0xFB,0xCB,0x02,0x56,0x04,0x68,0xF8, + 0x3C,0x07,0x89,0xFE,0xFF,0xFA,0x5E,0x03,0xB9,0xFF,0xFC,0xFC, + 0x8E,0x01,0x4A,0x01,0x56,0xFA,0xE3,0x04,0xD1,0xFB,0xC7,0xFD, + 0x93,0x03,0x6B,0xFC,0x07,0x00,0xD9,0x01,0x30,0xFF,0x62,0x00, + 0x1E,0x05,0x05,0xFC,0xE5,0x00,0x00,0x04,0x39,0xFD,0xFA,0xFE, + 0x79,0x03,0x4F,0xFC,0x4C,0x01,0x72,0x01,0x4A,0xFC,0xD7,0x04, + 0x71,0xFF,0xBD,0xFD,0xA3,0x03,0x97,0x00,0x12,0xFE,0x0F,0x02, + 0xF6,0xFE,0xE6,0xFF,0x39,0x01,0xCA,0xFD,0x59,0x00,0xC5,0xFF, + 0x7E,0xFC,0xAC,0x01,0x2C,0x00,0x92,0xFD,0xDC,0x00,0x2A,0x00, + 0x1E,0x00,0x1E,0x00,0xC1,0xFF,0x0A,0x00,0xB0,0x01,0x1F,0xFE, + 0x21,0x01,0x55,0x01,0x55,0xFD,0x64,0x02,0xA2,0xFD,0xC8,0xFF, + 0x1B,0x02,0x15,0xFD,0xFF,0x00,0xA2,0x01,0xF6,0xFD,0xD4,0xFF, + 0xE4,0x02,0x29,0xFE,0xD1,0x00,0x89,0x01,0x22,0xFE,0x0F,0x03, + 0x3C,0x00,0x62,0xFD,0x87,0x02,0xAE,0x00,0x88,0xFC,0xC6,0x02, + 0x15,0xFE,0xEF,0xFD,0x09,0x02,0x9A,0xFE,0x5C,0xFF,0xF3,0x00, + 0x72,0x00,0xDA,0xFE,0x7C,0x03,0xAA,0xFC,0x65,0x00,0x60,0x03, + 0xDA,0xFC,0x3D,0x00,0x51,0x01,0x29,0xFF,0x60,0xFF,0xD1,0xFF, + 0x53,0xFE,0x5C,0x02,0xB5,0xFE,0x68,0xFF,0x3F,0x02,0x5E,0x00, + 0xB6,0xFE,0x9D,0xFF,0xE5,0x01,0x54,0x00,0x6C,0xFF,0xDE,0xFF, + 0x5C,0x01,0xDE,0xFD,0xF0,0xFF,0x7F,0x00,0xF3,0xFD,0x09,0x02, + 0x1E,0xFF,0x08,0xFF,0xDA,0x03,0x09,0xFE,0x5B,0xFF,0x76,0x02, + 0x57,0xFE,0x71,0xFF,0x56,0x01,0xBB,0xFE,0x53,0xFE,0x3A,0x01, + 0xCA,0xFF,0x88,0xFF,0x46,0x00,0x63,0x01,0x88,0x00,0xC0,0xFF, + 0x5B,0x00,0x0A,0x00,0xC8,0xFE,0xAD,0xFF,0xB7,0xFF,0x1D,0xFE, + 0x3E,0x01,0x04,0xFF,0x5E,0xFF,0xAB,0x01,0x4E,0x00,0x2F,0x01, + 0xD8,0x00,0xBC,0xFF,0x45,0x00,0xF0,0x00,0xF2,0xFE,0x78,0xFF, + 0x82,0x00,0x42,0xFE,0xD9,0xFF,0xC9,0x00,0x6D,0xFE,0xC1,0x00, + 0xB4,0x00,0xC9,0xFE,0x05,0x01,0x78,0x00,0x7A,0xFF,0x1A,0x01, + 0x22,0x00,0xF1,0xFE,0xA1,0x00,0x6D,0xFF,0x96,0xFF,0xE1,0x00, + 0xD9,0xFE,0x0D,0x01,0x4E,0x00,0x59,0xFE,0x08,0x02,0x3B,0x01, + 0x5A,0xFE,0xC4,0x00,0x2F,0x01,0xE9,0xFE,0x03,0x00,0x55,0xFE, + 0xBA,0xFE,0xAD,0x01,0x58,0xFF,0x16,0xFF,0x53,0x00,0xCB,0xFF, + 0x5E,0x01,0x93,0x00,0xC4,0xFE,0x48,0x01,0x90,0x01,0xDD,0xFE, + 0xE7,0xFF,0x31,0x00,0x6D,0xFF,0xB4,0x00,0x2E,0xFE,0x9C,0xFF, + 0xB5,0x02,0x0D,0xFF,0x8D,0xFD,0x09,0x01,0x11,0x01,0xAC,0xFE, + 0x04,0xFF,0xB5,0xFF,0xC1,0x01,0x4D,0x00,0x43,0xFF,0x70,0x00, + 0x80,0x00,0x96,0xFF,0x41,0xFF,0x70,0x00,0x6C,0xFF,0x46,0x00, + 0xE4,0x00,0xCC,0xFF,0xB9,0x00,0x8A,0x01,0xEE,0x00,0x06,0x00, + 0x6D,0xFF,0x4F,0x00,0x1D,0x01,0xBF,0xFF,0x3F,0xFF,0x25,0x00, + 0x49,0xFF,0xBA,0xFE,0x76,0xFE,0x2C,0xFF,0x0E,0x00,0x13,0x00, + 0xD0,0xFF,0x85,0xFF,0x32,0x00,0xE7,0xFF,0xF5,0xFE,0x8B,0xFE, + 0x85,0xFE,0x9A,0xFF,0xE8,0xFF,0x61,0xFD,0xE7,0xFE,0xE2,0x01, + 0x65,0x01,0x6E,0x00,0x7F,0x02,0xF3,0x04,0xBE,0x01,0xD2,0xFF, + 0x00,0x04,0x41,0x04,0x30,0x00,0xF6,0x01,0x35,0x01,0xF0,0xFE, + 0xD6,0xFF,0x9B,0xFE,0x71,0x00,0x93,0x00,0x4F,0xFD,0x6F,0xFE, + 0x75,0xFF,0x0F,0xFC,0x0A,0xFB,0xBE,0xFC,0xC3,0xFB,0x1F,0xFB, + 0x54,0xFD,0xA3,0xFE,0x8F,0xFF,0xBF,0xFF,0xFB,0xFE,0x2F,0x02, + 0x83,0x02,0x39,0x00,0x8E,0x02,0x42,0x02,0xC8,0xFF,0x50,0x01, + 0xE6,0x00,0x6D,0x00,0x81,0x02,0x2A,0x02,0x6E,0x01,0xD2,0x03, + 0x55,0x07,0x54,0x03,0x58,0x07,0x74,0x0C,0x6D,0x02,0x5E,0x01, + 0x04,0x02,0x6D,0xFB,0x14,0xFA,0x72,0xF9,0x9E,0xF5,0x27,0xF8, + 0x08,0xFC,0x91,0xFB,0xCC,0xFE,0xAD,0xFE,0xBF,0xFA,0xAC,0xFD, + 0x12,0x00,0x2B,0xFC,0x42,0xFD,0x55,0xFF,0x67,0xFE,0x0C,0xFF, + 0xCC,0xFE,0x23,0xFF,0xFE,0x00,0x33,0x02,0xE5,0x01,0x63,0x03, + 0x2B,0x04,0x93,0x03,0x0B,0x03,0xF0,0x00,0xBC,0x00,0x32,0x04, + 0x3A,0x03,0xA1,0x02,0x16,0x07,0x7D,0x06,0x99,0x0C,0x17,0x10, + 0x6B,0x03,0x6B,0xFF,0xB0,0x02,0xBC,0xF9,0x55,0xF4,0xFC,0xF6, + 0x2D,0xF3,0x23,0xF5,0xB5,0xFA,0xD2,0xF8,0xE7,0xFA,0xF8,0x00, + 0x5F,0x02,0x85,0x01,0xD7,0x00,0x38,0xFF,0x51,0xFF,0xE9,0xFE, + 0x5F,0xF9,0x77,0xF7,0x7C,0xFC,0xB6,0xFE,0x1D,0xFE,0x9B,0x00, + 0x6F,0x03,0x0F,0x06,0x7B,0x07,0x11,0x04,0xF1,0x02,0x84,0x05, + 0x55,0x02,0x48,0xFE,0xAB,0xFF,0xA7,0xFF,0xDC,0x00,0xA2,0x0C, + 0x0D,0x15,0xEE,0x09,0xAC,0x07,0x6B,0x0D,0xB7,0x01,0x99,0xF9, + 0x4F,0xF7,0x19,0xF2,0x3C,0xF2,0x20,0xF5,0xFE,0xF4,0x3F,0xF7, + 0x0A,0xFC,0x62,0xFC,0x4D,0xFE,0xD2,0x00,0xF7,0x02,0x46,0x05, + 0x46,0x05,0x28,0x02,0x50,0xFC,0xDB,0xFA,0x36,0xFA,0xF7,0xF8, + 0xAA,0xFA,0x44,0xFE,0x8C,0x02,0x0E,0x04,0x36,0x05,0x20,0x05, + 0xA3,0x01,0x88,0x00,0x39,0x02,0x16,0x01,0x4B,0x01,0x8C,0x02, + 0x26,0x01,0x73,0x00,0xAE,0xF9,0xE6,0x08,0x9B,0x1E,0x9A,0x0D, + 0x3F,0x04,0x6D,0x0E,0x78,0x07,0xF8,0xF8,0x45,0xF3,0x88,0xEE, + 0xB5,0xF0,0x94,0xF6,0x93,0xF2,0x79,0xF5,0x5A,0x00,0x3E,0x01, + 0xFB,0xFC,0x89,0xFF,0x60,0x02,0x19,0x06,0x5E,0x06,0x93,0xFE, + 0xC3,0xFD,0x0D,0x00,0x14,0xFC,0xE7,0xF8,0xB8,0xFB,0x7B,0xFF, + 0xBC,0x01,0x2B,0x02,0x31,0x03,0x94,0x05,0xE8,0x03,0x8D,0xFF, + 0xE3,0xFE,0x1E,0xFD,0x2B,0xFD,0x81,0x02,0xAD,0x04,0xA2,0x00, + 0xA9,0xFE,0x3F,0x00,0xA0,0xF4,0xF9,0x0B,0xB8,0x28,0xC9,0x0A, + 0x3A,0x01,0x3C,0x10,0xEF,0x06,0x4F,0xF7,0x20,0xEF,0x92,0xEC, + 0xE1,0xF3,0xBB,0xF7,0xB9,0xF0,0x8E,0xF8,0x92,0x04,0xF3,0xFF, + 0x17,0xFC,0x5B,0x00,0x6E,0x04,0x92,0x07,0xEE,0x04,0xF0,0xFC, + 0x98,0xFC,0x43,0x00,0x68,0xFB,0x20,0xF9,0xC5,0xFC,0xAC,0xFF, + 0xB2,0x04,0xF9,0x03,0xCE,0x01,0xA0,0x05,0x50,0x04,0xA5,0xFD, + 0x22,0xFD,0xCB,0xFE,0x4A,0xFD,0xBF,0xFD,0x5E,0x00,0x40,0x03, + 0xAE,0xFF,0x99,0xFC,0x72,0xF5,0xE3,0x04,0x92,0x2B,0x7D,0x19, + 0xCC,0xFA,0x80,0x09,0x8A,0x0F,0xC4,0xFA,0x17,0xEA,0x17,0xEB, + 0x33,0xF4,0xA9,0xF9,0xF9,0xF3,0xCC,0xF4,0x54,0x02,0x86,0x05, + 0x7D,0xFE,0x52,0xFD,0x1D,0x03,0x9D,0x09,0xA5,0x07,0xB2,0xFC, + 0xEF,0xF8,0xFC,0xFD,0x26,0xFE,0xB4,0xF8,0xAE,0xF8,0x47,0x00, + 0xC0,0x05,0x66,0x04,0x8C,0x03,0x41,0x06,0xC9,0x05,0xE5,0x00, + 0xFE,0xFB,0x72,0xFC,0x64,0x00,0x3D,0x00,0x28,0xFB,0x57,0xFB, + 0x62,0x01,0x9B,0xFF,0x00,0xFE,0x67,0xF5,0x53,0xFF,0x21,0x2A, + 0x60,0x21,0x35,0xFC,0x97,0x04,0x5A,0x10,0xF9,0xFD,0xF6,0xEA, + 0xD9,0xE8,0xDC,0xF0,0x8A,0xFB,0x95,0xF8,0x59,0xF2,0x41,0xFD, + 0xD5,0x07,0x0A,0x04,0x06,0xFE,0x2E,0x01,0xCF,0x09,0x4B,0x0A, + 0xC1,0xFE,0x17,0xF7,0xA9,0xFB,0x3B,0xFF,0x09,0xF9,0x9D,0xF5, + 0xE0,0xFE,0x94,0x07,0x80,0x05,0x75,0x01,0x41,0x03,0x0A,0x07, + 0xBC,0x05,0xFF,0xFE,0xBE,0xFB,0x38,0xFF,0xE1,0x02,0x59,0x00, + 0x65,0xFC,0xF0,0xFA,0x00,0xFB,0x15,0xFE,0xB9,0xFD,0xE5,0xF4, + 0xFD,0xFA,0x41,0x21,0x99,0x28,0xA6,0x03,0x8A,0xFE,0x3D,0x0F, + 0xB4,0x04,0x5E,0xED,0x33,0xE7,0xB5,0xF0,0x0D,0xFC,0xD6,0xFA, + 0xC4,0xF0,0xD6,0xF7,0x6C,0x07,0xE8,0x06,0x22,0xFE,0xEB,0xFF, + 0xD7,0x09,0xF3,0x0C,0x9C,0x03,0x95,0xF7,0x44,0xFA,0x07,0x00, + 0x0B,0xF8,0x37,0xF4,0x74,0xFD,0xC4,0x05,0xD1,0x05,0xB8,0x02, + 0x7A,0x02,0xDE,0x05,0x12,0x06,0x88,0xFF,0x94,0xFB,0xE5,0xFF, + 0x72,0x04,0xF7,0x00,0x86,0xFC,0xFD,0xFD,0xA5,0x00,0xBC,0xFE, + 0x27,0xFA,0xFD,0xF7,0x18,0xF7,0xC7,0xFF,0x0E,0x18,0x87,0x1D, + 0x76,0x07,0xA4,0x03,0xC1,0x0C,0x52,0x01,0x06,0xF0,0xDC,0xED, + 0x4C,0xF5,0x2B,0xFA,0x47,0xF7,0x47,0xF4,0x74,0xFB,0xC5,0x03, + 0xFE,0x01,0x35,0xFE,0x4F,0x02,0xF8,0x09,0xF1,0x0A,0xAC,0x02, + 0x1C,0xFE,0x29,0xFE,0xD8,0xF9,0x0B,0xF7,0x10,0xF9,0x3D,0xFE, + 0xB3,0x01,0xB3,0x02,0xB1,0x03,0x41,0x04,0x43,0x05,0x2E,0x03, + 0x5F,0xFF,0x04,0xFF,0x89,0x00,0x1C,0x01,0xA7,0x00,0x4F,0x00, + 0xBB,0xFF,0x60,0xFE,0x68,0xFD,0x62,0xFA,0x8B,0xF9,0x63,0xFA, + 0xF8,0x01,0xD9,0x1C,0x82,0x1D,0x99,0xFB,0x44,0xFA,0xC9,0x0C, + 0x6C,0x00,0x44,0xEB,0x19,0xEE,0xA9,0xFB,0x06,0x01,0xBF,0xFA, + 0xF6,0xF3,0xE4,0xFC,0x2C,0x08,0xE2,0x02,0xB2,0xFA,0xC0,0x00, + 0x2E,0x0B,0x19,0x0A,0xDF,0xFF,0x42,0xF8,0xC7,0xFA,0xFD,0xFE, + 0xBF,0xFA,0x61,0xF8,0x1C,0xFF,0x23,0x06,0x7D,0x04,0xFE,0xFF, + 0x0F,0x02,0x4C,0x05,0x07,0x03,0x5B,0xFD,0x05,0xFD,0xB5,0x02, + 0xB7,0x03,0xE3,0xFE,0x0D,0xFD,0x09,0xFF,0x0B,0xFD,0xBD,0xF9, + 0xB7,0xF8,0x1D,0xFA,0xEA,0x10,0x56,0x22,0x63,0x08,0xD2,0xF9, + 0xCE,0x0B,0xC9,0x09,0xBA,0xF2,0x54,0xEB,0x6F,0xF5,0x3E,0xFD, + 0x93,0xFB,0x19,0xF5,0x8E,0xF8,0xAC,0x04,0xD1,0x05,0x3B,0xFD, + 0x07,0xFE,0xD1,0x08,0xA6,0x0B,0x4C,0x02,0xE9,0xF9,0xF8,0xFC, + 0x97,0x00,0x7A,0xF9,0x73,0xF4,0x1C,0xFC,0x97,0x05,0x72,0x04, + 0x93,0x00,0x3B,0x03,0x70,0x06,0x78,0x04,0x3E,0xFF,0xE1,0xFC, + 0x35,0x00,0xA1,0x02,0x2B,0xFF,0xC4,0xFC,0x3F,0x00,0x68,0x02, + 0xCB,0xFF,0x98,0xFD,0x9E,0xFB,0x7A,0xFB,0xEF,0xF9,0x59,0xFF, + 0xAF,0x18,0x09,0x1B,0x65,0x01,0xEA,0xFF,0xA7,0x08,0x22,0xFD, + 0x4D,0xEE,0x96,0xEF,0xC8,0xF8,0xA9,0xFC,0x97,0xF9,0x3A,0xF7, + 0x02,0xFF,0x4C,0x06,0x52,0x02,0x56,0xFD,0xA5,0x02,0xF4,0x0A, + 0xC4,0x08,0xA2,0x00,0x62,0xFC,0x57,0xFB,0x6B,0xFA,0xD7,0xF8, + 0x0C,0xFA,0xB4,0xFE,0xD1,0x02,0xD3,0x04,0xA6,0x03,0x1D,0x03, + 0xC4,0x04,0x34,0x03,0x7E,0xFF,0x40,0xFE,0x5D,0xFF,0x9F,0x00, + 0x2C,0x01,0x2B,0xFF,0x5A,0xFD,0x73,0xFE,0xC6,0xFC,0xE3,0xF8, + 0xB2,0xF7,0x31,0xFE,0x36,0x13,0x17,0x1F,0xAE,0x0B,0x65,0xFE, + 0x50,0x06,0xB7,0x02,0x50,0xF2,0xA2,0xEB,0x90,0xF3,0x4A,0xFD, + 0x15,0xFD,0x9F,0xF6,0x19,0xFA,0xBA,0x05,0x2E,0x06,0xE0,0xFD, + 0x4B,0xFF,0x20,0x09,0x60,0x0B,0x59,0x02,0xD8,0xFA,0x63,0xFC, + 0x8C,0xFC,0x76,0xF7,0xBF,0xF6,0x3A,0xFE,0xE1,0x04,0x47,0x03, + 0xEB,0x01,0xB2,0x05,0x32,0x06,0x70,0x02,0x73,0xFF,0x8E,0xFE, + 0x67,0x00,0x1F,0x01,0x4F,0xFE,0x7E,0xFD,0x9F,0x00,0xB8,0x00, + 0x21,0xFD,0xE6,0xFE,0x9C,0x00,0x50,0xFC,0x98,0xF7,0x8E,0xFC, + 0xB1,0x14,0x7D,0x1C,0xA4,0x04,0x32,0xFE,0xA7,0x09,0x26,0x01, + 0x8C,0xEE,0xD4,0xED,0xCE,0xF8,0x0D,0xFD,0x9A,0xF8,0x92,0xF5, + 0xCA,0xFD,0x59,0x07,0x88,0x03,0x17,0xFC,0x74,0x01,0xF3,0x0B, + 0x30,0x0A,0xD5,0x00,0x3C,0xFD,0x17,0xFD,0xE7,0xFA,0x69,0xF7, + 0x14,0xF8,0xBC,0xFE,0xC0,0x02,0xA1,0x02,0x7D,0x03,0xAE,0x04, + 0x4E,0x05,0x88,0x03,0x09,0x00,0x8F,0xFF,0x69,0x00,0x33,0xFF, + 0x36,0xFF,0x31,0x00,0xDA,0xFE,0x8B,0xFD,0xA7,0xFD,0xB0,0xFC, + 0x44,0xF9,0x22,0xF8,0x46,0x02,0x06,0x18,0xE4,0x19,0x8C,0x04, + 0xAB,0x03,0x5B,0x0B,0xBD,0xFC,0xE3,0xEB,0x5D,0xEE,0xDB,0xF8, + 0x3F,0xFB,0x71,0xF6,0x0E,0xF6,0xC7,0x00,0x95,0x07,0x06,0x01, + 0x51,0xFD,0xE5,0x05,0xAF,0x0C,0xE2,0x07,0x75,0xFE,0xA6,0xFC, + 0x24,0x00,0x03,0xFA,0xAB,0xF2,0x36,0xF8,0xEF,0x01,0xC5,0x03, + 0xFF,0xFF,0x5D,0x02,0x9A,0x09,0xE5,0x07,0xE1,0xFF,0x81,0xFE, + 0xCE,0x01,0x49,0x01,0xAB,0xFD,0x63,0xFC,0x82,0xFF,0xFA,0x00, + 0x56,0xFE,0x92,0xFD,0x74,0x00,0x00,0x02,0xC0,0xFD,0x19,0xF9, + 0x5A,0xF7,0x88,0x0B,0x5F,0x20,0x45,0x09,0x0C,0xFA,0xDE,0x0A, + 0x78,0x07,0x34,0xF0,0x3B,0xEC,0xE9,0xF8,0x1D,0xFD,0xFD,0xF7, + 0x23,0xF4,0x30,0xFC,0x9B,0x07,0xD9,0x03,0xA8,0xFA,0x86,0x00, + 0x2C,0x0C,0x21,0x0B,0xF4,0x00,0x64,0xFD,0x22,0x01,0x6D,0xFD, + 0x4C,0xF5,0xB8,0xF5,0xD1,0xFE,0x88,0x03,0x73,0xFF,0x51,0x00, + 0x02,0x08,0x2D,0x08,0x6C,0x01,0xA2,0xFF,0xA2,0x01,0x99,0x01, + 0x18,0xFF,0x65,0xFD,0x6E,0xFF,0xE9,0x00,0xF1,0xFD,0x57,0xFC, + 0xF4,0xFE,0x89,0x00,0x2D,0xFE,0xC8,0xF8,0x78,0xF6,0x38,0x0B, + 0xFD,0x20,0x54,0x0C,0x83,0xFB,0x99,0x0B,0xC1,0x08,0x13,0xF0, + 0xCA,0xEA,0x4E,0xF8,0xF6,0xFC,0x32,0xF6,0xEA,0xF2,0x91,0xFC, + 0x0E,0x08,0xB3,0x03,0xF7,0xFA,0x50,0x01,0x1C,0x0D,0xD8,0x0A, + 0xA1,0x00,0x73,0xFD,0xE4,0x00,0xBE,0xFE,0xB5,0xF4,0x11,0xF4, + 0xAD,0xFE,0x90,0x03,0xE9,0xFF,0xD6,0xFF,0x6B,0x06,0x2C,0x0A, + 0x6E,0x04,0x13,0xFE,0xEF,0x00,0xFB,0x02,0x03,0xFE,0x0C,0xFC, + 0xAF,0xFF,0xE4,0x00,0x3B,0xFE,0x61,0xFC,0x07,0xFF,0x35,0x02, + 0x06,0x02,0x88,0xFD,0x51,0xFD,0x83,0xFB,0xBF,0xFB,0x35,0x17, + 0xF5,0x17,0x7D,0xFA,0xEF,0x01,0xDA,0x0C,0xA5,0xF9,0x82,0xED, + 0xF7,0xF5,0xAD,0xFA,0xFF,0xF8,0x92,0xF6,0xD5,0xF7,0xF1,0x02, + 0xE9,0x06,0xA0,0xFD,0x51,0xFD,0x0F,0x09,0x3C,0x0B,0x48,0x04, + 0x36,0xFF,0x21,0xFF,0xCE,0x00,0x15,0xFA,0x22,0xF4,0x49,0xFA, + 0x2B,0x02,0xAF,0x01,0xC4,0xFE,0xE8,0x02,0x51,0x09,0xC8,0x06, + 0xAB,0xFF,0x8B,0xFF,0x79,0x02,0xD0,0x00,0x96,0xFD,0xC8,0xFD, + 0xDD,0xFF,0x73,0xFF,0xC9,0xFC,0x74,0xFD,0xF4,0x00,0x63,0x02, + 0xDE,0xFE,0x37,0xFC,0x5D,0xF8,0x94,0xFB,0xB7,0x17,0xF4,0x18, + 0xFF,0xFB,0x0D,0x03,0xFB,0x0F,0x17,0xFB,0x8E,0xEB,0x13,0xF5, + 0x9D,0xFB,0xD1,0xF7,0x21,0xF4,0x6C,0xF7,0xAC,0x03,0x16,0x07, + 0xD3,0xFC,0xC2,0xFC,0xC5,0x09,0xF2,0x0B,0x7C,0x03,0x0E,0x00, + 0x0D,0x01,0x11,0xFF,0x6D,0xFA,0x8D,0xF6,0xD0,0xF8,0x81,0x00, + 0x80,0x00,0x99,0xFE,0x98,0x04,0x51,0x08,0xF1,0x04,0x02,0x03, + 0x8F,0x03,0x67,0x00,0xAC,0xFE,0xB3,0xFE,0x8D,0xFD,0x2F,0xFE, + 0xBE,0xFE,0xE4,0xFD,0x26,0xFF,0x0C,0x01,0x0D,0x00,0xCE,0x00, + 0x00,0x02,0xA1,0x01,0xC3,0xFD,0xB8,0xFE,0x22,0xFB,0x8C,0xFC, + 0xD4,0x16,0x08,0x0E,0x65,0xF6,0x2A,0x07,0x58,0x0D,0xCB,0xF5, + 0x1F,0xEE,0xD1,0xFA,0x99,0xFC,0x0B,0xF7,0x80,0xF5,0x35,0xFB, + 0x42,0x05,0xFD,0x03,0x64,0xFB,0x15,0x01,0x2C,0x0C,0xC3,0x07, + 0xE2,0xFF,0xC9,0x01,0x62,0x02,0xCE,0xFD,0x00,0xF9,0xAF,0xF6, + 0xAE,0xFD,0xC7,0x01,0xC3,0xFD,0xAC,0x00,0x15,0x07,0xA6,0x05, + 0x87,0x02,0x2E,0x03,0x21,0x02,0xD8,0x00,0x5E,0xFF,0x12,0xFD, + 0x70,0xFE,0x55,0xFF,0xD3,0xFC,0xF7,0xFC,0x76,0x00,0x4D,0x01, + 0xBE,0xFF,0xC0,0x01,0x10,0x02,0x74,0xFE,0xBA,0xF8,0xF4,0xF5, + 0x48,0x0B,0x33,0x1A,0xEA,0x02,0xCD,0xFC,0x3A,0x10,0x00,0x07, + 0x60,0xEF,0x20,0xF1,0x29,0xFD,0xB2,0xFA,0x7D,0xF2,0x90,0xF4, + 0x2E,0x01,0x40,0x06,0xC5,0xFC,0x22,0xFB,0x84,0x07,0x69,0x0C, + 0xC9,0x04,0x54,0x00,0x03,0x04,0x56,0x03,0x49,0xFA,0x9D,0xF5, + 0x60,0xFA,0x8B,0x00,0x73,0xFF,0x18,0xFB,0x45,0x01,0x4B,0x09, + 0x8A,0x04,0xF8,0x00,0x55,0x05,0x87,0x05,0xA3,0x00,0x44,0xFE, + 0x2F,0xFF,0x77,0xFE,0xFB,0xFB,0x58,0xFB,0x80,0xFD,0x9A,0x00, + 0x46,0x01,0xDF,0x00,0xF6,0x01,0xBB,0x02,0xB8,0x01,0x0C,0x00, + 0x38,0x00,0xD7,0xFF,0x6A,0xFE,0xF0,0xFA,0xC3,0xFB,0xA5,0xFC, + 0x39,0x00,0x43,0x0F,0x96,0x09,0x01,0xFF,0x86,0x08,0xC6,0x06, + 0xBC,0xF7,0x4B,0xF5,0x4A,0xFB,0x46,0xF9,0x21,0xF6,0x33,0xF8, + 0x1F,0xFE,0x1F,0x02,0xE7,0xFF,0xBD,0xFF,0x19,0x06,0xD4,0x08, + 0x77,0x04,0xC8,0x02,0x1C,0x04,0x53,0x00,0xCF,0xFB,0x00,0xFB, + 0xC2,0xFA,0x5B,0xFD,0x98,0xFE,0x95,0xFD,0xF7,0x01,0x6F,0x05, + 0x81,0x03,0x09,0x03,0x9F,0x03,0x5E,0x02,0xDF,0x00,0xD7,0xFE, + 0xFE,0xFD,0x8B,0xFE,0x01,0xFE,0xA8,0xFC,0xD0,0xFE,0x79,0x01, + 0x86,0xFF,0xA1,0xFF,0x5A,0xFF,0xA2,0xFF,0xF7,0xF8,0x0E,0xFA, + 0x03,0x02,0x2B,0x0A,0x93,0x16,0x85,0x05,0x45,0x02,0x4F,0x10, + 0x5E,0xFF,0x72,0xEE,0x57,0xF7,0xFE,0xFC,0xE5,0xF1,0x5F,0xF1, + 0x0B,0xFB,0xC1,0x00,0x11,0xFF,0xA7,0xFC,0xEF,0x02,0xCE,0x0A, + 0xE7,0x07,0x94,0x03,0x81,0x06,0x3A,0x05,0xBF,0xFC,0x95,0xF8, + 0x0C,0xFB,0x95,0xFB,0x72,0xFA,0xA7,0xFB,0xDF,0xFF,0x76,0x03, + 0x81,0x03,0xC3,0x03,0x30,0x06,0x53,0x07,0x7A,0x03,0xD8,0xFF, + 0xA8,0x01,0x84,0x00,0x35,0xFB,0x16,0xFC,0xD7,0xFF,0xDB,0xFE, + 0xB4,0xFD,0xFA,0xFF,0x3E,0x02,0x00,0x01,0x25,0xFF,0x0E,0x01, + 0x7F,0x02,0x8D,0xFF,0x34,0xFE,0x76,0xFF,0x96,0xFE,0x34,0xFD, + 0x6F,0xFE,0xBC,0x00,0x68,0x00,0x64,0xFF,0xA4,0x00,0xD1,0x00, + 0x90,0xFF,0x47,0xFF,0x68,0x00,0x80,0xFF,0x77,0xFF,0x27,0x02, + 0xB9,0xFE,0xF4,0x03,0x70,0x06,0xFB,0xFC,0x29,0x02,0x1E,0x05, + 0x5E,0xFC,0x76,0xFB,0x1D,0x00,0x1B,0xFD,0x26,0xFA,0x1A,0xFD, + 0xCE,0xFE,0x3A,0xFF,0x2F,0xFF,0xF1,0xFF,0x35,0x02,0xFC,0x02, + 0x71,0x01,0x68,0x02,0x06,0x03,0x61,0x00,0x7C,0xFE,0xAB,0xFE, + 0x1B,0xFE,0x92,0xFD,0x5C,0xFE,0x04,0xFF,0x6D,0x00,0x29,0x01, + 0xDD,0x00,0xF4,0x01,0x77,0x02,0x59,0x00,0x77,0x01,0x72,0xFF, + 0xEE,0x00,0x4D,0xFD,0xA1,0xFE,0x45,0xF9,0x6A,0xF6,0x54,0x1E, + 0x23,0x0A,0x11,0xF1,0x0B,0x1A,0xAE,0x11,0x61,0xE9,0x78,0xF5, + 0x56,0x09,0xF1,0xF1,0xA3,0xE9,0xB3,0xFA,0x89,0x00,0x46,0xFB, + 0x36,0xF9,0x86,0x01,0xFF,0x09,0xED,0x03,0xF8,0xFF,0x5F,0x0B, + 0x1C,0x0A,0x65,0xFB,0x0E,0xFB,0xB9,0x01,0x50,0xFB,0x64,0xF6, + 0xBB,0xFC,0xB4,0x00,0x7E,0xFE,0xAF,0xFE,0xC5,0x03,0xC8,0x06, + 0xD4,0x04,0x52,0x03,0x98,0x05,0xBB,0x05,0xD8,0xFF,0x62,0xFD, + 0xBC,0xFF,0xA6,0xFD,0xEE,0xFA,0xCA,0xFE,0xB5,0x00,0x2F,0xFF, + 0xA8,0x00,0x16,0x01,0xF4,0x00,0x61,0x01,0xCC,0xFF,0x92,0xFF, + 0x7C,0x00,0x17,0xFF,0x8D,0xFD,0xAF,0xFD,0x07,0xFF,0xCE,0xFE, + 0xF9,0xFC,0xD9,0xFE,0x5C,0x01,0xE2,0xFE,0x71,0xFE,0xD0,0x00, + 0xBD,0x00,0x43,0xFC,0x39,0xFD,0x55,0xFD,0x80,0x00,0x47,0xFE, + 0xA1,0xFE,0xA6,0x19,0xC2,0x0A,0x67,0xFA,0x59,0x14,0x90,0x0A, + 0x42,0xEE,0xDA,0xF8,0xAD,0x03,0x70,0xEF,0x2B,0xEE,0x3C,0xFE, + 0xEC,0xFD,0xB3,0xF8,0x8F,0xFE,0x5D,0x06,0xC1,0x06,0xE5,0x03, + 0xF3,0x05,0x0E,0x0A,0xB5,0x03,0x88,0xFB,0x56,0xFE,0xC0,0xFF, + 0x66,0xF8,0x64,0xF8,0x54,0xFF,0x79,0xFE,0xAB,0xFB,0xC8,0x00, + 0xFA,0x04,0x3C,0x03,0x93,0x03,0x6F,0x06,0x8E,0x05,0x28,0x02, + 0xAA,0x00,0xED,0xFF,0x23,0xFE,0x49,0xFC,0xD4,0xFC,0x4D,0xFF, + 0x36,0xFF,0x92,0xFE,0xE5,0x00,0xD8,0x01,0x72,0x00,0x27,0x01, + 0x28,0x02,0x01,0x01,0xE0,0xFF,0x30,0xFF,0xD0,0xFE,0x7E,0xFE, + 0x10,0xFE,0xCE,0xFD,0x32,0xFE,0xB7,0xFE,0x81,0xFE,0x93,0xFE, + 0x6F,0xFF,0xE0,0xFF,0xAE,0xFF,0x78,0x00,0x78,0x01,0x5B,0x00, + 0x82,0x00,0x99,0x01,0xE3,0xFF,0x12,0x00,0x7F,0x01,0x8E,0x00, + 0x3F,0x00,0x40,0x01,0xBB,0x00,0x6B,0x00,0x45,0x00,0x8D,0xFF, + 0x79,0x00,0xD6,0xFF,0x24,0xFF,0x85,0xFF,0x2B,0x00,0x16,0x01, + 0x01,0x00,0xF6,0xFF,0x73,0x02,0xBB,0x02,0xA9,0xFF,0x6A,0x00, + 0x4E,0x02,0x79,0xFE,0x60,0xFC,0xF1,0xFE,0x18,0xFE,0x6E,0xFB, + 0xA1,0xFC,0x07,0xFF,0xC9,0xFE,0xF1,0xFD,0x80,0x00,0xFD,0x01, + 0xED,0xFF,0x5A,0x00,0xBE,0x02,0xAA,0x01,0x1F,0x00,0x71,0x01, + 0xA3,0x01,0x19,0x00,0x6C,0x00,0xF6,0x00,0xB8,0x00,0xF6,0xFF, + 0xC4,0x00,0xB2,0x00,0x23,0x00,0xCE,0x00,0x85,0xFF,0x58,0x00, + 0xD0,0x00,0xDA,0xFE,0x84,0xFE,0x9B,0x04,0x94,0x04,0xA0,0xFE, + 0xF1,0x03,0x0A,0x07,0x28,0xFD,0xFF,0xFA,0x1D,0x02,0xE1,0xFB, + 0x16,0xF5,0xF1,0xFB,0x31,0xFE,0x67,0xF8,0x76,0xFB,0xBA,0x01, + 0x9A,0xFF,0xDA,0xFE,0x19,0x04,0x87,0x05,0x3F,0x02,0x6E,0x02, + 0xE0,0x03,0x5E,0x01,0x81,0xFE,0x7A,0xFF,0xC5,0xFF,0xE5,0xFD, + 0x21,0xFE,0x6A,0xFF,0x88,0xFF,0x91,0xFF,0xCD,0x00,0xA5,0x01, + 0x83,0x02,0x63,0x03,0x9E,0x02,0xD5,0x02,0x6C,0x02,0x3C,0x00, + 0x77,0xFF,0xA1,0xFF,0x71,0xFE,0xA1,0xFD,0xD4,0xFE,0x59,0xFE, + 0xCB,0xFD,0x6B,0xFE,0x74,0xFE,0xBD,0xFD,0x02,0xFF,0xE2,0xFE, + 0x27,0xFF,0x47,0xFF,0x30,0x00,0xC7,0x03,0xFD,0xFE,0x73,0x08, + 0x3E,0x0C,0x7F,0xFE,0x39,0x06,0xD2,0x09,0x2D,0xF8,0xF5,0xF6, + 0x22,0x02,0x51,0xF6,0x93,0xEF,0x97,0xFE,0x6A,0xFE,0x9C,0xF5, + 0xCA,0xFF,0x12,0x07,0x3D,0xFF,0xC4,0x01,0x88,0x0A,0x3E,0x06, + 0xF9,0x00,0xC0,0x04,0xA8,0x03,0x7D,0xFD,0x92,0xFD,0xAF,0xFF, + 0x0E,0xFD,0x4A,0xFB,0xA7,0xFD,0x98,0xFE,0x9C,0xFD,0x6E,0xFF, + 0x86,0x02,0xE2,0x02,0xFE,0x02,0xE0,0x04,0xB8,0x04,0x59,0x02, + 0xA1,0x01,0x47,0x01,0x38,0xFF,0x55,0xFE,0xE2,0xFE,0x14,0xFE, + 0x60,0xFD,0x2A,0xFE,0x7E,0xFE,0x42,0xFE,0x27,0xFF,0x29,0x00, + 0x1A,0x00,0x44,0x00,0x1F,0x01,0xDC,0x00,0x6F,0x00,0xF5,0x00, + 0x32,0x00,0x45,0xFF,0x56,0xFF,0xB6,0xFE,0xA9,0xFD,0xFA,0xFD, + 0xB8,0xFE,0x2D,0xFE,0x38,0xFF,0xD8,0x00,0x1A,0x00,0xF2,0x00, + 0xC8,0x01,0xD2,0x00,0x17,0x01,0x56,0x01,0xA0,0x00,0x80,0x00, + 0xB3,0x00,0xF9,0xFF,0x33,0x00,0x36,0x00,0x57,0xFF,0xEF,0xFF, + 0x0C,0x00,0xDC,0xFE,0x5F,0xFF,0x68,0x00,0x9A,0xFF,0xA3,0xFF, + 0xFA,0x00,0xBB,0x00,0xB7,0xFF,0x9B,0x00,0xB8,0x00,0x5F,0xFF, + 0xF0,0xFF,0x5C,0x00,0x4F,0xFF,0xCA,0xFF,0x49,0x00,0x98,0xFF, + 0xC5,0xFF,0xEF,0xFF,0xC0,0xFF,0x73,0xFF,0xF4,0xFF,0xE1,0xFF, + 0x5A,0xFE,0x76,0x00,0x8E,0x02,0xCD,0x00,0x04,0x02,0xFA,0x05, + 0xE1,0x02,0x42,0xFF,0x7A,0x03,0x2F,0x01,0x48,0xFA,0x45,0xFD, + 0x13,0xFF,0xFC,0xF8,0x7F,0xFA,0x9C,0xFF,0x0C,0xFC,0x9C,0xFB, + 0xAA,0x01,0x43,0x01,0x02,0xFF,0x46,0x03,0x1E,0x04,0x9E,0x00, + 0x5F,0x02,0xF8,0x03,0xC0,0x00,0x97,0x00,0x3F,0x02,0x9C,0xFF, + 0x44,0xFE,0xE5,0xFF,0xAA,0xFE,0x51,0xFD,0x3B,0xFF,0xDD,0xFF, + 0x47,0xFF,0xFC,0x00,0x05,0x02,0x35,0x01,0xB0,0x01,0x5D,0x02, + 0x78,0x01,0xE9,0x00,0x0A,0x01,0x23,0x00,0x42,0xFF,0x42,0xFF, + 0xD7,0xFE,0x2D,0xFE,0x52,0xFE,0x5E,0xFE,0x26,0xFE,0x59,0xFE, + 0x9F,0xFE,0xAA,0xFE,0x9A,0xFE,0x44,0xFF,0x6C,0xFF,0xB5,0xFF, + 0xE1,0xFF,0xAD,0x00,0x9E,0x00,0x90,0x00,0x25,0x04,0x52,0x03, + 0xC2,0x02,0x44,0x06,0x52,0x03,0x63,0xFF,0xF1,0x01,0x12,0x00, + 0x14,0xFA,0x4B,0xFC,0xFA,0xFD,0x60,0xF9,0x10,0xFB,0x66,0xFF, + 0x9F,0xFC,0x25,0xFD,0x36,0x02,0x7B,0x01,0x62,0x00,0xD0,0x03, + 0x84,0x03,0xAE,0x00,0xD1,0x02,0x59,0x03,0x54,0x00,0x44,0x01, + 0x11,0x02,0xD5,0xFE,0x56,0xFE,0xA8,0xFF,0x7F,0xFD,0xDD,0xFC, + 0x4D,0xFF,0x29,0xFF,0xE5,0xFE,0x77,0x01,0x02,0x02,0xF4,0x00, + 0x36,0x02,0xA9,0x02,0x33,0x01,0x66,0x01,0xAE,0x01,0x2D,0x00, + 0xC4,0xFF,0x12,0x00,0x0D,0xFF,0xA4,0xFE,0x2E,0xFF,0xA4,0xFE, + 0x2E,0xFE,0xC7,0xFE,0xA9,0xFE,0x72,0xFE,0x27,0xFF,0x75,0xFF, + 0x7F,0xFF,0x18,0x00,0x5B,0x00,0x2F,0x00,0x55,0x00,0x40,0x00, + 0xED,0xFF,0x09,0x00,0xF6,0xFF,0xD4,0xFF,0x12,0x00,0x05,0x00, + 0x03,0x00,0x34,0x00,0x20,0x00,0x1D,0x00,0x4E,0x00,0x30,0x00, + 0x12,0x00,0x4B,0x00,0x59,0x00,0x44,0x00,0x72,0x00,0x95,0x00, + 0x72,0x00,0x7E,0x00,0x8A,0x00,0x41,0x00,0x19,0x00,0x11,0x00, + 0xD1,0xFF,0xA6,0xFF,0xBE,0xFF,0xAA,0xFF,0x8F,0xFF,0xBD,0xFF, + 0xC7,0xFF,0xB7,0xFF,0xDE,0xFF,0xF0,0xFF,0xE3,0xFF,0xF2,0xFF, + 0x04,0x00,0x09,0x00,0x16,0x00,0x1C,0x00,0x19,0x00,0x1F,0x00, + 0x18,0x00,0x0E,0x00,0x06,0x00,0xF1,0xFF,0xED,0xFF,0xFB,0xFF, + 0xF0,0xFF,0xEA,0xFF,0x07,0x00,0x11,0x00,0x0D,0x00,0x24,0x00, + 0x31,0x00,0x17,0x00,0x11,0x00,0x23,0x00,0x1C,0x00,0x0F,0x00, + 0x08,0x00,0xE0,0xFF,0xBD,0xFF,0xB8,0xFF,0x94,0xFF,0x86,0xFF, + 0xA9,0xFF,0xB3,0xFF,0xBA,0xFF,0xF0,0xFF,0x0F,0x00,0x18,0x00, + 0x40,0x00,0x4B,0x00,0x43,0x00,0x52,0x00,0x30,0x00,0xB7,0xFF, + 0xF0,0xFF,0xD6,0x00,0x29,0x01,0x60,0x01,0xD8,0x01,0xE4,0x01, + 0x8B,0x01,0xDE,0x00,0xFA,0xFF,0x67,0xFF,0xAC,0xFE,0xAF,0xFD, + 0x83,0xFD,0x79,0xFD,0xF6,0xFC,0x52,0xFD,0x3B,0xFE,0x8D,0xFE, + 0x26,0xFF,0x18,0x00,0x4B,0x00,0x74,0x00,0x16,0x01,0x38,0x01, + 0x59,0x01,0xF3,0x01,0xF5,0x01,0xB1,0x01,0xE0,0x01,0x81,0x01, + 0xA8,0x00,0x63,0x00,0xFB,0xFF,0x3F,0xFF,0x3C,0xFF,0x63,0xFF, + 0x1F,0xFF,0x57,0xFF,0xD6,0xFF,0xE4,0xFF,0x2A,0x00,0xAC,0x00, + 0xAC,0x00,0xA9,0x00,0xD4,0x00,0x8C,0x00,0x49,0x00,0x57,0x00, + 0x12,0x00,0xC1,0xFF,0xD7,0xFF,0xA8,0xFF,0x4B,0xFF,0x4C,0xFF, + 0x2B,0xFF,0xD2,0xFE,0xE0,0xFE,0xFA,0xFE,0xD7,0xFE,0x0E,0xFF, + 0x54,0xFF,0x5E,0xFF,0xB5,0xFF,0x0F,0x00,0x1E,0x00,0x6B,0x00, + 0xCF,0x00,0xD1,0x00,0xD1,0x00,0xE8,0x00,0xBE,0x00,0x8D,0x00, + 0x6E,0x00,0x26,0x00,0xEA,0xFF,0xD4,0xFF,0xB0,0xFF,0xA9,0xFF, + 0xCD,0xFF,0xDC,0xFF,0xEE,0xFF,0x19,0x00,0x2C,0x00,0x2B,0x00, + 0x41,0x00,0x34,0x00,0x27,0x00,0x42,0x00,0x49,0x00,0x80,0x00, + 0xE5,0x00,0x04,0x01,0x1A,0x01,0x1A,0x01,0xFF,0x00,0xBC,0x00, + 0x3A,0x00,0xB9,0xFF,0x4A,0xFF,0xF7,0xFE,0x3A,0xFE,0x0F,0xFE, + 0x32,0xFE,0xC2,0xFD,0xE3,0xFD,0x69,0xFE,0xA7,0xFE,0x1A,0xFF, + 0xEA,0xFF,0x51,0x00,0xAF,0x00,0x2B,0x01,0x4A,0x01,0x59,0x01, + 0x6C,0x01,0x3A,0x01,0x02,0x01,0xE8,0x00,0x9E,0x00,0x58,0x00, + 0x3A,0x00,0x06,0x00,0xE5,0xFF,0x06,0x00,0x0D,0x00,0x03,0x00, + 0x1C,0x00,0x19,0x00,0x09,0x00,0x22,0x00,0x32,0x00,0x2C,0x00, + 0x37,0x00,0x27,0x00,0xFF,0xFF,0xED,0xFF,0xCD,0xFF,0x9A,0xFF, + 0x88,0xFF,0x80,0xFF,0x6A,0xFF,0x73,0xFF,0x86,0xFF,0x7E,0xFF, + 0x88,0xFF,0xA2,0xFF,0xA3,0xFF,0xB3,0xFF,0xCE,0xFF,0xCE,0xFF, + 0xD5,0xFF,0xE8,0xFF,0xE5,0xFF,0xEA,0xFF,0x09,0x00,0x1E,0x00, + 0x2C,0x00,0x46,0x00,0x59,0x00,0x61,0x00,0x6F,0x00,0x72,0x00, + 0x69,0x00,0x69,0x00,0x61,0x00,0x49,0x00,0x3D,0x00,0x32,0x00, + 0x15,0x00,0x08,0x00,0x04,0x00,0xF7,0xFF,0xF6,0xFF,0xF7,0xFF, + 0xE8,0xFF,0xE5,0xFF,0xE9,0xFF,0xDD,0xFF,0xDE,0xFF,0xE7,0xFF, + 0xE1,0xFF,0xE1,0xFF,0xEE,0xFF,0xEE,0xFF,0xF0,0xFF,0xFB,0xFF, + 0xF7,0xFF,0xFA,0xFF,0x02,0x00,0xFF,0xFF,0xFC,0xFF,0x00,0x00, + 0xFE,0xFF,0xF9,0xFF,0x00,0x00,0x02,0x00,0xFF,0xFF,0x08,0x00, + 0x0D,0x00,0x0B,0x00,0x10,0x00,0x14,0x00,0x11,0x00,0x0E,0x00, + 0x11,0x00,0x09,0x00,0x02,0x00,0x01,0x00,0xF8,0xFF,0xF1,0xFF, + 0xF0,0xFF,0xEB,0xFF,0xE8,0xFF,0xEF,0xFF,0xEC,0xFF,0xEC,0xFF, + 0xF4,0xFF,0xF8,0xFF,0xF8,0xFF,0xFE,0xFF,0x01,0x00,0x00,0x00, + 0x05,0x00,0x06,0x00,0x08,0x00,0x0B,0x00,0x08,0x00,0x07,0x00, + 0x07,0x00,0x03,0x00,0xFD,0xFF,0xFC,0xFF,0xFE,0xFF,0x00,0x00, + 0x01,0x00,0xFC,0xFF,0xF8,0xFF,0xF7,0xFF,0xF6,0xFF,0xEF,0xFF, + 0xEF,0xFF,0xF8,0xFF,0xFC,0xFF,0x00,0x00,0x04,0x00,0x07,0x00, + 0x09,0x00,0x09,0x00,0x09,0x00,0x08,0x00,0x07,0x00,0x07,0x00, + 0x02,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x00, + 0x03,0x00,0x05,0x00,0x05,0x00,0x06,0x00,0x05,0x00,0x01,0x00, + 0x03,0x00,0x03,0x00,0x03,0x00,0x05,0x00,0x05,0x00,0x03,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFD,0xFF,0xFD,0xFF,0xFD,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF, + 0x03,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0x01,0x00,0xFF,0xFF,0x01,0x00,0x02,0x00,0xFF,0xFF, + 0x00,0x00,0xFE,0xFF,0xFD,0xFF,0xFE,0xFF,0xFD,0xFF,0xFD,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE,0xFF, + 0x01,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0xFA,0xFF, + 0x03,0x00,0x09,0x00,0xF8,0xFF,0x01,0x00,0x07,0x00,0xFE,0xFF, + 0xFD,0xFF,0x05,0x00,0x04,0x00,0xFF,0xFF,0x03,0x00,0x04,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0xFE,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x02,0x00,0xFF,0xFF, + 0x02,0x00,0x07,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0xFD,0xFF, + 0xF7,0xFF,0xFC,0xFF,0xFB,0xFF,0xF1,0xFF,0xF5,0xFF,0xF8,0xFF, + 0xF3,0xFF,0xF9,0xFF,0x00,0x00,0x01,0x00,0x02,0x00,0x08,0x00, + 0x08,0x00,0x07,0x00,0x0E,0x00,0x0D,0x00,0x08,0x00,0x0A,0x00, + 0x0A,0x00,0x04,0x00,0x03,0x00,0x04,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0xFB,0xFF,0xF8,0xFF,0xFE,0xFF,0xFB,0xFF,0xF6,0xFF, + 0xFC,0xFF,0xFC,0xFF,0xF9,0xFF,0xFE,0xFF,0xFE,0xFF,0xFB,0xFF, + 0xFE,0xFF,0x00,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x02,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x01,0x00, + 0x01,0x00,0x03,0x00,0x03,0x00,0x01,0x00,0x03,0x00,0x01,0x00, + 0xFF,0xFF,0x01,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x04,0x00, + 0x01,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0xFE,0xFF,0xFE,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0x01,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0x00,0x00, + 0x01,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0xFF,0xFF,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xFF,0xFF,0x01,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x01,0x00,0xFF,0xFF,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x01,0x00,0xFF,0xFF, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x02,0x00,0xFB,0xFF,0xFF,0xFF, + 0x06,0x00,0xFA,0xFF,0xFB,0xFF,0x03,0x00,0x02,0x00,0xFE,0xFF, + 0xFD,0xFF,0x07,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x04,0x00, + 0xFD,0xFF,0x05,0x00,0x00,0x00,0xFE,0xFF,0x08,0x00,0xF7,0xFF, + 0x07,0x00,0xF2,0xFF,0x11,0x00,0xF0,0xFF,0x0F,0x00,0xEC,0xFF, + 0x22,0x00,0xD4,0xFF,0x28,0x00,0xEC,0xFF,0x2F,0x00,0xDA,0xFF, + 0xCA,0xFF,0xA4,0x00,0x98,0xFE,0xD1,0x05,0x98,0xFF,0x26,0xF6, + 0xDD,0x02,0xEB,0x04,0x6D,0xFC,0xB1,0xFD,0x48,0x01,0x56,0x02, + 0xB1,0x02,0xFB,0xFC,0xC8,0xFC,0x7D,0x03,0x3C,0x02,0x31,0xFD, + 0x3E,0xFF,0xD6,0x02,0x05,0x00,0xD8,0xFD,0x7C,0x00,0x73,0x01, + 0x76,0xFE,0xD4,0xFF,0xD5,0x00,0x1C,0x00,0x96,0xFE,0x6D,0x00, + 0xE8,0x04,0xAB,0xFD,0x44,0xFC,0xA0,0x01,0x52,0x00,0x02,0xFE, + 0x8E,0xFF,0x9A,0x01,0xB0,0xFF,0x53,0xFF,0x69,0x00,0x84,0x00, + 0x14,0x00,0x22,0x01,0x01,0xFF,0xD5,0xFE,0x87,0x03,0x90,0xFF, + 0xEA,0xFE,0xAF,0x03,0x1B,0xFF,0x8E,0xFB,0xE4,0xFF,0xF5,0x00, + 0xF1,0xFD,0x6E,0xFF,0x12,0x02,0x09,0x00,0x51,0xFE,0xD5,0x00, + 0x98,0x01,0xC9,0xFF,0x56,0x00,0x1C,0x01,0x07,0x00,0xBA,0xFF, + 0xB7,0x00,0xA2,0xFF,0x03,0xFF,0x56,0x00,0x82,0xFF,0x11,0xFF, + 0x52,0x00,0x67,0x00,0x03,0xFF,0xCC,0xFF,0x40,0x01,0x62,0x00, + 0xD7,0xFF,0x59,0x00,0x4D,0x00,0xEB,0xFF,0x15,0x00,0x34,0x00, + 0xA1,0xFF,0xBD,0xFF,0xC3,0xFF,0x4F,0xFF,0xB7,0xFF,0x35,0x00, + 0x22,0x00,0x80,0xFF,0xEC,0xFF,0xA9,0x00,0xE9,0xFF,0x59,0x00, + 0x8C,0x00,0x99,0xFF,0x3C,0x00,0x43,0x00,0x06,0x00,0x80,0xFF, + 0x14,0x00,0xF3,0xFF,0xFA,0xFE,0x41,0x00,0x4C,0x00,0x96,0xFF, + 0xCC,0xFF,0x9E,0x00,0x57,0x00,0xFA,0xFF,0x5B,0x00,0x1A,0x00, + 0x0E,0x00,0x0C,0x00,0xE2,0xFF,0x16,0x00,0xE0,0xFF,0xED,0xFF, + 0x0F,0x00,0x6F,0xFF,0xD5,0xFF,0x6B,0x00,0x1F,0x00,0x85,0xFF, + 0x3D,0x00,0x83,0x00,0x7B,0xFF,0xDF,0xFF,0xAF,0x00,0xFE,0xFF, + 0x99,0xFF,0x28,0x00,0xE2,0xFF,0xF3,0xFF,0x1B,0x00,0xD8,0xFF, + 0x02,0x00,0xF0,0xFF,0x13,0x00,0xE4,0xFF,0xF6,0xFF,0x5C,0x00, + 0xC0,0xFF,0xE1,0xFF,0x10,0x00,0x56,0x00,0x03,0x00,0x5F,0xFF, + 0x35,0x00,0xF2,0xFF,0x17,0x00,0x19,0x01,0xE0,0xFF,0xFE,0xFF, + 0xFD,0xFF,0xDB,0xFE,0xC7,0xFF,0xF0,0xFF,0xFA,0xFF,0xFB,0xFF, + 0x24,0x00,0x09,0x00,0x83,0xFF,0xF0,0xFF,0x34,0x00,0x30,0x00, + 0x01,0x00,0xA6,0x00,0x63,0x00,0x38,0x00,0x1C,0x00,0x07,0x00, + 0x3F,0x00,0x3B,0x00,0xDF,0xFF,0xF0,0xFE,0x73,0x00,0xBB,0xFF, + 0x03,0xFF,0x0C,0x00,0x79,0x00,0x47,0x00,0x6C,0xFF,0xBA,0x00, + 0xB1,0x00,0xBB,0xFF,0xDD,0xFF,0x29,0x00,0x1E,0x00,0xA8,0xFF, + 0xCE,0xFF,0x6E,0x00,0xA4,0xFF,0x2A,0xFF,0xC4,0xFF,0x16,0x00, + 0xE6,0xFF,0x4B,0xFF,0xDD,0x00,0x98,0x00,0x09,0xFF,0x92,0x00, + 0xFC,0x00,0xCC,0xFF,0x56,0xFF,0xBF,0x00,0x97,0x00,0xAB,0xFE, + 0x16,0x00,0xB4,0x00,0x86,0xFF,0x87,0xFF,0x8D,0x00,0x05,0x00, + 0x18,0xFF,0xDD,0x00,0x95,0x00,0x2F,0xFF,0x18,0x00,0xCC,0x00, + 0xF9,0xFF,0xAA,0xFF,0x40,0x00,0x2B,0x00,0x79,0xFF,0xFA,0xFF, + 0xF6,0xFF,0x5E,0xFF,0x7E,0x00,0xD5,0xFF,0xD0,0xFF,0x0F,0x00, + 0xC4,0xFF,0x63,0x00,0x78,0x00,0xD4,0xFF,0xB9,0xFE,0xFB,0x00, + 0xE0,0x00,0xF2,0xFE,0x1D,0x00,0xCB,0x00,0x33,0x00,0x13,0xFF, + 0xF3,0xFF,0x74,0x00,0xBF,0xFF,0xBE,0xFF,0xE2,0xFF,0xE6,0xFF, + 0x43,0x00,0xDB,0x00,0x73,0xFF,0x48,0xFF,0x4C,0x01,0xBE,0xFF, + 0x4B,0xFF,0xD8,0x00,0x88,0xFF,0x6A,0xFF,0x7E,0x00,0x60,0x00, + 0x16,0xFF,0x70,0x00,0xA2,0x00,0x4C,0x49,0x53,0x54,0x12,0x00, + 0x00,0x00,0x49,0x4E,0x46,0x4F,0x49,0x47,0x4E,0x52,0x06,0x00, + 0x00,0x00,0x4F,0x74,0x68,0x65,0x72,0x00 +}; + diff --git a/xrGameSpy/gamespy/changelog.txt b/xrGameSpy/gamespy/changelog.txt new file mode 100644 index 00000000000..5909c2c0f73 --- /dev/null +++ b/xrGameSpy/gamespy/changelog.txt @@ -0,0 +1,151 @@ +Changelog for: GameSpy Common Code +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.06.00 RMV RELEASE Released to Developer Site +11-27-2007 2.05.01 SAH CLEANUP Removed extern "c" block in nonport.h to prevent linker errors +08-06-2007 2.05.00 RMV RELEASE Released to Developer Site *Note - fixed version number to match other common changelog +06-22-2007 2.01.02 SAH FIX Fixed MD5Print to null terminate the output string. +05-16-2007 2.01.01 DES CLEANUP Changed MD5Print to non use sprintf, to avoid security warnings +12-15-2006 2.01.00 MJW RELEASE Releasing to developer site. +05-26-2005 2.00.00 BED RELEASE Releasing to developer site. +05-16-2005 2.00.00 BED OTHER Moved common code into /common directory. + BED OTHER Stubbed nonport.h and nonport.c to include new common files. +04-28-2005 1.11.02 SN RELEASE Releasing to developer site. +04-27-2005 1.11.02 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 1.11.02 DES FIX Nitro updates + DES FEATURE Addition categories and types added to gsiDebug +04-08-2005 1.11.01 SN FIX Fixed SN Systems bug where a socket was shown to be readable even when an error was recorded for it. +04-08-2005 1.11.00 DES FEATURE Changes for XBox support. +04-04-2005 1.10.72 SN RELEASE Releasing to developer site. +04-04-2005 1.10.72 DES CLEANUP Removed unused GS_BIG_ENDIAN define. + DES FEATURE Added gsi_is_false() and gsi_is_true() defines. + DES CLEANUP Removed unused PATHCHAR define. + DES CLEANUP Removed old _NITRO code from SetSockBlocking. +03-31-2005 1.10.71 BED FIX Removed some CodeWarrior strict compile warnings. +03-31-2005 1.10.70 SN FIX Fixed build problem by moving defines that had dependancies +03-14-2005 1.10.69 DES FEATURE Nintendo DS support +02-18-2005 1.10.68 BED FIX Added timeout for gsoap recv so it could recover from a hosed server + BED FIX Explicit __cdecl for hashtable and darray are used on Win32 only + BED FIX Switched gsimemory to track peak memory usage rather than total num allocs. +01-27-2005 1.10.67 DES FIX Added GSI_NO_THREADS for platforms without thread support + DES FIX Fixed custom SN sendto and moved it to nonport +01-04-2005 1.10.66 DDW FIX Added malloc cast in XXTEA encryption code +12-21-2004 1.10.65 SN FIX Added code to register the hostname resolution thread with SN_SYSTEMS +12-07-2004 1.10.64 BED FIX Added explicit __cdecl in darray.c and gsidebug.c +11-18-2004 1.10.63 SN RELEASE Releasing to developer site. +11-18-2004 1.10.63 SN FIX Fixed conversion warnings for XXTEA algorithm +11-17-2004 1.10.62 SN FIX Modified the XXTEA headers and renamed global key size +11-16-2004 1.10.62 BED FEATURE Added Thread/Semaphore common functions + BED FEATURE Added AD sdk to common debugger code. + BED FEATURE Common debug functions and memory manager are now thread safe + BED FEATURE Added core task processor (see core.h) + BED FEATURE Added common gsoap task (see soap.h) +11-16-2004 1.10.61 SN FEATURE Added URL-safe Base64 encoding and XXTEA encrypt and decrypt +09-21-2004 1.10.60 SN FIX Added the directories for MacOS X and Win32 common to goacommon.bat +09-16-2004 1.10.59 SN RELEASE Releasing to developer site. +09-16-2004 1.10.59 SN FIX Modified header define of NOFILE to avoid conflict with MacOS X +09-03-2004 1.10.58 BED CLEANUP Removed misc compiler warnings. +08-27-2004 1.10.57 BED FEATURE Added memory diagnostic functions to memory manager. +08-27-2004 1.10.56 DES CLEANUP Changed UNDER_UNIX to _UNIX, and define it if _LINUX or _MACOSX are defined. + DES OTHER Generate an error if _WIN32, _PS2, or _UNIX are not defined. + DES CLEANUP General Unicode cleanup + DES CLEANUP Fixed minor warnings under OSX + BED FIX Fixed typo in SN Systems version of GOAGetLastError. +08-25-2004 1.10.55 BED FEATURE Added common debug utilities to nonport. (See gsiDebug.h) + BED FEATURE Added memory pool manager to nonport. (See top of nonport.h) +08-24-2004 1.10.54 DES CLEANUP Removed references to MacOS. +08-20-2004 1.10.53 SN FIX Changed the way errors are obtained from the SN Systems network stack. +08-05-2004 1.10.52 SN RELEASE Releasing to developer site. +08-04-2004 1.10.51 SN FIX Fixed a function prototype causing compiler warnings for codewarrior +08-02-2004 1.10.50 SN FEATURE Added support for developers to use winsock 2 +07-13-2004 1.10.49 DES FEATURE Added GSIStartResolvingHostname() for doing async hostname lookups. +07-12-2004 1.10.48 SN FIX Cleared warnings when warnings are treated as errors for gamspy common code. +07-09-2004 1.10.47 SN FIX Updated portions of code to eliminate warnings for PS2 +07-08-2004 1.10.46 SN FIX Commented an include line +07-01-2004 1.10.46 SN FIX Includeded for ps2 +06-29-2004 1.10.45 BED RELEASE Releasing to developer site. +06-28-2004 1.10.45 DES FEATURE Added gsimemalign to the list of memory functions. +06-24-2004 1.10.44 BED FEATURE Util_Rand functions no longer static. + BED FEATURE Added B64 encode and decode from matrix source. +06-22-2004 1.10.43 BED RELEASE Releasing with updated PS2Common code +06-18-2004 1.10.42 BED RELEASE Releasing to developer site. +06-01-2004 1.10.42 BED FEATURE Phase 1 of PS2 Insock integration. (needs further testing) + BED FIX Found case where unsigned long was used on Ps2 instead of gsi_time. +04-27-2004 1.10.41 DES FEATURE Added current_time_hires(), returns time in microseconds. +03-10-2004 1.10.40 BED FEATURE Added some more types to nonport.h + FIX Undefine socket types to workaround SNSys bug. (They plan to patch in march 04) +12-03-2003 1.10.39 BED FEATURE Added "GameSpy Help.chm" to goapackage.bat +11-10-2003 1.10.38 DES RELEASE Releasing to developer site. +11-10-2003 1.10.38 BED FIX Remove misc compiler warnings. +11-07-2003 1.10.37 DES FIX Added linux support for the common integers datatypes. + FIX Added a newline to the bottom of available.h. + FEATURE The available check now uses .available.gamespy.com. +10-29-2003 1.10.36 DES FEATURE Added available.h,.c for doing backend services availability checks. +10-09-2003 1.10.35 BED FEATURE Added gsi_time type for PS2 compatibility +10-08-2003 1.10.34 JED FEATURE Added common integer datatypes +08-25-2003 1.10.33 JED CLEANUP Added some sanity checks in hashtable.c +07-24-2003 1.10.32 DES RELEASE Releasing to developer site. +07-23-2003 1.10.32 DES FIX Moved EENet includes in nonport.h to fix CW PS2 warnings. + DES FEATURE Added memory tracking. Use GSI_MEM_TRACK to enable. +07-22-2203 1.10.31 BED CLEANUP General cleanup to remove CodeWarrior compiler warnings. +07-16-2003 1.10.30 DES CLEANUP Removed support for Cisco NFT for the PS2. + FIX Changed some __mips64 checks to _PS2 checks in nonport.c + BED FIX Changed nonport.c to not use #pragma comment when _PS2 if defined +07-10-2003 1.10.29 BED CLEANUP Added GSI_UNUSED to nonport.h to silence unused variable warnings. +05-09-2003 1.10.28 DES CLEANUP Removed Dreamcast support. + CLEANUP Changed nonport.h to use EENet if no network stack is defined for the PS2. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +05-07-2003 1.10.27 DES RELEASE Releasing to developer site. + FIX Rewrote EENet GetMAC to be 2.7.x compatibile. +04-28-2003 1.10.26 DES RELEASE Releasing to developer site. + FIX Changed malloc/free in new EENet getlocalhost to gsimalloc/gsifree. +04-28-2003 1.10.25 DES RELEASE Releasing to developer site. +04-17-2003 1.10.25 DES FIX Rewrote EENet getlocalhost again, to be compatible with the 2.7.0.1 release. +04-15-2003 1.10.24 DES FIX Rewrote the EENet implementation of getlocalhost to build its own HOSTENT. +04-15-2003 1.10.23 JED CLEANUP Corrected DevStudio Level4 warnings for use of FD_SET +04-08-2003 1.10.22 JED FIX converted md5 function parameter type declarations from K&R C to ANSI C +03-27-2003 1.10.21 DES FIX IsPrivateIP no longer flips the source IP's byte order. +03-26-2003 1.10.20 DES RELEASE Releasing to developer site. +03-25-2003 1.10.20 DES FIX The EENet version of getlocalhost() wasn't checking all possible local IPs. +03-24-2003 1.10.19 DES FEATURE Added IsPrivateIP() for checking if an IP is a private network IP. + DES FIX GetTicks() no longer causes a compiler warning. +03-10-2003 1.10.18 DES RELEASE Releasing to developer site. +02-25-2003 1.10.18 DES CLEANUP Added headers to nonport.h for 2.6.1 EENet compatibility. + EENET_260 can be defined for 2.6.0 compatibility. +02-05-2003 1.10.17 DES RELEASE Releasing to developer site. +02-05-2003 1.10.17 DES FEATURE Added CanReceiveOnSocket and CanSendOnSocket as wrappers for select. + Needed because the SN stack for the PS2 has non-standard behavior. +01-23-2003 1.10.16 DES FEATURE Added the ability to just get the gsi*() memory function defines + by defining GSI_MEM_ONLY before including nonport.h. +01-07-2003 1.10.15 DES RELEASE Releasing to developer site. +01-07-2003 1.10.15 DES CLEANUP Removed a comment and a printf that were no longer needed. +01-02-2003 1.10.14 DES CLEANUP Removed the typedef for PSOCKADDR + It doesn't appear to be used anywhere, and was causing compile problems. +12-20-2002 1.10.13 DES FEATURE Implemented new code from SN Systems to get the MAC for the unique ID. +12-19-2002 1.10.12 DES RELEASE Releasing to developer site. +12-19-2002 1.10.12 DES CLEANUP Removed assert.h include from darray.h and hashtable.h. +12-18-2002 1.10.11 DES CLEANUP Put in a stub function fr getting the unique ID when using the SN stack. +12-16-2002 1.10.10 DES FEATURE Defined NOFILE when _PS2 is defined to exclude all file writing code. + FEATURE Defined SOMAXCONN to 5 when not defined. This is used as the backlog + parameter in calls to listen(). 5 is the max for SN Systems. + FEATURE gethostbyaddr() is not supported by SN Systems, defined it to NULL. + CLEANUP Changed GOAGetLastError() to clear the error for SN Systems. + Also removed GOAClearSocketError(), which was only needed for SN Systems. +12-13-2002 1.10.09 DES FEATURE Added EENet specific code for getting the MAC address for the Unique ID. +12-11-2002 1.10.08 DES FEATURE Additional eenet support. + FEATURE Added getlocalhost() for getting the local machine's hostent struct. + FEATURE Added SetSendBufferSize(), GetSendBufferSize(), and GetReceiveBufferSize(). +12-05-2002 1.10.07 DES CLEANUP General cleanup + FEATURE Initial PS2 eenet stack support +11-22-2002 1.10.06 DES RELEASE Releasing to developer site. +11-22-2002 1.10.06 DES FIX Fixed bug with checking the current time on the PS2. +11-20-2002 1.10.05 DES FEATURE Switched to using the MAC address for the Unique ID on the PS2. + CLEANUP Cleaned up to compile without warnings on the PS2. +11-18-2002 1.10.04 JED FIX nonport.c now using ansi registry funcs for WIN32/unicode +11-14-2002 1.10.03 DES FEATURE Added assert.h include to nonport.h. +11-13-2002 1.10.02 DDW FEATURE Changed GOAGetUniqueID to use redefinable function pointer. + Made Cisco the default stack for PS2. +11-13-2002 1.10.01 DES FIX Removed Reference to unsupported non-blocking CISCO stack +09-25-2002 1.10.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/common/changelog.txt b/xrGameSpy/gamespy/common/changelog.txt new file mode 100644 index 00000000000..5b92b94b971 --- /dev/null +++ b/xrGameSpy/gamespy/common/changelog.txt @@ -0,0 +1,321 @@ +Changelog for: GameSpy Common Code +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.06.00 RMV RELEASE Released to Developer Site +12-12-2007 2.05.14 SN FIX Fixed getlocalhost for revolution +12-10-2007 2.05.13 SN FIX Added limits.h for PS2 +11-27-2007 2.05.12 SAH FIX Removed tm struct and added SB_NO_ICMP define for revolution + SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +11-21-2007 2.05.11 SAH FIX Added include for Nitro/Revolution +11-16-2007 2.05.10 SAH FIX Fixed mem leak in gsCore from not freeing the dynamic array + SAH CLEANUP Changed async DNS code to set the handle pointer to null after freeing +11-09-2007 2.05.09 SAH CLEANUP Added wchar_t typecasts to goawstrdup to remove warnings +11-05-2007 2.05.08 SAH FIX Removed GP_NP_BUDDY_SYNC define, NP modules load now regardless +10-31-2007 2.05.07 SAH FIX Fixed to be included regardless of GSI_UNICODE define +10-19-2007 2.05.06 SAH OTHER Added goawstrdup function for wchar strdup operations +10-09-2007 2.05.05 SAH FIX Fixed compiler errors with gsiInt64ToString functions +10-08-2007 2.05.04 BED RELEASE Limited release +10-04-2007 2.05.04 DES FEATURE The task list can now grow dynamically +09-26-2007 2.05.03 SAH FIX Removed overrided PS3 time() function +09-18-2007 2.05.02 SAH OTHER Added two PS3 modules to ps3common for GP-NP support +08-16-2007 2.05.01 SAH FIX Removed unnecessary len > 0 assert in gsXmlWriteBase64BinaryElement +08-14-2007 2.05.01 SN FEATURE Added 64 bit integer function gsiStringToInt64 + SN FEATURE Added 64 bit versions of gsXml read and write functions +08-06-2007 2.05.00 RMV RELEASE Released to Developer Site +07-19-2007 2.04.07 SAH FIX Added explicit typecasting to UdpEngine to get rid of compiler warnings +07-16-2007 2.04.06 RMV FIX Defined SB_NO_ICMP_SUPPORT for Mac and Linux. +06-07-2007 2.04.05 SN RELEASE Releasing to developer site +06-01-2007 2.04.05 DES FIX Fixed warning under Win32 due to using a pointer to malloc functions +05-18-2007 2.04.04 SAH FIX Fixed memory leak from unfreed string in gsiXxteaAlg + 2.04.04 SAH FIX Fixed trashed memory bug in gsiXxteaAlg from null char overwrite +05-16-2007 2.04.03 DES FIX Wrapped gsPlatform.h in extern "C" if C++ + DES CLEANUP Cleaned up #undefs of common string funcs + DES CLEANUP Removed CE support from common code +04-17-2007 2.04.02 SAH OTHER Added gsiFloatSwap and Unswap byte reversal functions +03-15-2007 2.04.01 SN FIX Fixed some compiler warnings and errors for other platforms. +03-05-2007 2.04.00 SAH RELEASE Released to Developer Site +03-02-2007 2.03.10 SN FIX Fixed gsi common debug printing for Revolution + SN FIX Switched printf for nitro to properly print common debug logs + SN FIX Fixed warnings for code warrior +03-02-2007 2.03.09 SAH FIX Fixed MACOSX endian-ness to default to GSI_LITTLE_ENDIAN +03-02-2007 2.03.08 SN FIX Fixed declaration warning in gsXml.c +02-22-2007 2.03.07 SN FIX Fixed prototypes for extern aligned mem functions +01-30-2007 2.03.06 DES FIX Fixed compile error in gsXml.c +01-24-2007 2.03.05 SN FIX Fixed some Visual Studio 2005 warnings +01-23-2007 2.03.04 SAH FIX Added generalized UNICODE support for gsXML + 2.03.04 BED FIX Added UTF8ToUCS2StringLength for gsXML changes +01-17-2007 2.03.03 DES RELEASE Limited Release +01-16-2007 2.03.03 DES FEATURE Added X360 support +01-04-2007 2.03.02 BED FIX Added 2 new functions used in large int to ensure proper endian-ness for encryption + 2.03.02 BED FIX Fixed EncryptBuffer function to fix PS3 byte-order bug +12-20-2006 2.03.01 SN FIX Added code to free allocated memory for memory manager +12-15-2006 2.03.00 MJW RELEASE Released to Developer Site +12-13-2006 2.02.23 SN FIX Fixed issue where PSP uses the wrong FD_SETSIZE +12-11-2006 2.02.22 SN FIX Fixed VS 2005 warnings of deprecated CRT function itoa using a define +12-05-2006 2.02.21 SN FIX Made changes to the memory manager getting rid of unnamed union warnings +11-29-2006 2.02.20 SN FIX Small changes made to remove implicit cast warnings +11-10-2006 2.02.19 JR RELEASE Limited Release +11-08-2006 2.02.19 DES FIX Fixed so Core code will work managed C++ +11-06-2006 2.02.18 BED FEATURE Encryption clean up and speed up + Implemented RSA signatures. + Replaced Montgomery Multiplication with faster algorithm. + Fixed some bugs with 16bit compatability. +11-02-2006 2.02.17 SAH FIX Added CloseHandle to free Win32 thread resources +11-01-2006 2.02.16 BED FIX Added const keyword to various encrytion and large integer functions +10-31-2006 2.02.15 SN FIX Added a line to have system determine DST for all platforms supporting localtime and mktime +10-23-2006 2.02.14 DES RELEASE Limited release +10-11-2006 2.02.14 SAH OTHER Added gsThreadMacOSX.c and Mac OSX Asynchronous DNS Threading Support (uses pthreads) +10-11-2006 2.02.13 DES FIX Soap works with Unicode +10-05-2006 2.02.12 SAH FIX Added MacOSXCommon.c, updated gsDebug and Makefile.common to get rid of Mac compiler warnings +09-28-2006 2.02.11 SAH FIX Fixed ps3common.c to work with PS3 095.00x SDK. Must now explicitly load modules prior to initializing + the network since these libraries were made into stub libraries. +09-21-2006 2.02.10 SAH FIX Fixed a memory leak in Linux threads from not detaching a thread before exiting. +09-15-2006 2.02.09 DES FEATURE Added GS_ASSERT_NO_MESSAGEBOX define +09-13-2006 2.02.08 SN FIX Added recommended fix for broadcast IP +09-13-2006 2.02.07 SN FIX Updated Revolution CW Projects + Fixed some impclicit type casts + Miscalaneous Fixes for Revolution +09-05-2006 2.02.06 SN FIX Updated Revolution support + Added a revolutionCommon.c file for testing sample applications +08-24-2006 2.02.05 SAH FIX Removed GSI_NO_THREADS define around func prototypes +08-23-2006 2.02.04 SAH FIX Added #ifdef around the gsi time functions to get rid of warnings on unsupported plats +08-17-2006 2.02.03 SAH FIX Cleaned up the gsi threaded/nonthreaded DNS lookup calls in gsPlatformUtil.c + SAH OTHER GSI_NO_ASYNC_DNS can now be defined to turn off threaded lookups +08-04-2006 2.02.02 SN FIX Fixed XML date and time read function to use time_t +08-04-2006 2.02.02 SN FIX Fixed the resolve host name thread function for Nintendo Wii +08-04-2006 2.02.01 SAH OTHER Added gsi time utility functions as wrappers for gmtime, ctime, mktime + SAH FIX Added gsXmlReadChildAsDateTimeElement function to fix SAKE readTimeDate + SAH OTHER Removed function definitions/prototypes for NITRO ctime/gtime, now uses gsi versions +08-03-2006 2.02.00 SN OTHER Completed port for the Nintendo Revolution platform +08-02-2006 2.01.02 SAH RELEASE Releasing to developer site +08-01-2006 2.01.02 SAH FIX Removed PS2-asychronous DNS lookup calls - unsupported in current version + SAH FIX Changed Increment/Decrement functions for Linux - unsupported currently, throws assert +07-24-2006 2.01.01 SAH FIX Removed #ifdef _PS3 for socket calls in gsPlatformSocket.c and gsAvailable.c + SAH FIX Added typecasts to PS3 socket calls in gsPlatformSocket.h + SAH FIX Fixed a variable in gsThreadWin32.c used for gsiExitThread + SAH FIX Added GSI_UNUSED call for unused variable in gsPlatformUtil.c + SAH FIX Added typecast to get rid of NITRO warnings +07-21-2006 2.01.00 SN FEATURE Added initial support for the Nintendo Revolution +07-17-2006 2.00.50 SAH FIX Added gsiExitThread() to explicitly cleanup threads and free resources +07-07-2006 2.00.49 SAH FIX Changed debug statements to make note of asynch vs. synch DNS lookups +06-30-2006 2.00.48 SAH FIX Added _NITRO && _LINUX common debug call. added #ifndef _NITRO for file logging +06-26-2006 2.00.47 SAH FIX Changed timeout value for PS2 Insock socket calls to 3ms. +06-20-2006 2.00.46 SAH FEATURE Added gsLinuxThreads.c (Linux pthreads support) for ghttp asynch DNS + SAH FEATURE Added Linux implementation of gsiResolveHostnameThread +06-09-2006 2.00.45 SAH OTHER threaded asynch DNS code - explicitly set freed vars to NULL +06-02-2006 2.00.44 SAH FIX Added (void *) typecasts to function call in gsMemory.c + SAH FIX Added __cdecl to "main" function in Win32common.c +05-31-2006 2.00.43 SAH RELEASE Releasing to developer site + SAH FIX Added LinuxCommon.c for linux projects +05-30-2006 2.00.42 SAH FIX #include "time.h" for PS3 time support in gsPlatform.h + SAH FIX Added newlines to end of files, couple GSI_UNUSED calls + SAH FIX Added PS3 Threads stub in gsPlatformThreads +05-25-2006 2.00.41 SAH FIX added GSI_UNUSED call to gsAssert to get rid of Nitro warning +05-24-2006 2.00.40 SAH FIX moved GSI_UNUSED call below #endif in win32common.c +05-23-2006 2.00.39 SAH FIX Got rid of month/week arrays in gsXML.c - they are declared in nitroThread +05-22-2006 2.00.38 SAH FIX added GSI_UNUSED call to win32common.c - to get rid of warning +05-19-2006 2.00.37 SAH FIX added #define GS_STATIC_CALLBACK __cdecl if (_WIN32) +05-18-2006 2.00.36 DES RELEASE Limited developer release +05-17-2006 2.00.36 DES FIX Updates to fix DS compiler errors + DES FEATURE Added gmtime and ctime for DS + DES FEATURE Added gsiInterlockedIncrement/Decrement for the DS + DES FIX Changed call to strftime to sprintf +05-17-2006 2.00.35 SAH FIX Got rid of comma in MEMTAG enum causing codewarrior error +05-17-2006 2.00.34 DES FIX gsXmlReadChildAsBase64Binary now correctly handles empty data +05-15-2006 2.00.33 DES FEATURE Added Xml support for reading Base64 binary + DES FEATURE Added B64DecodeLen for getting the unencoded length of a Base64 string +04-28-2006 2.00.32 SAH FIX Got rid of unnecessary #include ../gsoap/stdsoap2.h in gsSoap.c +04-25-2006 2.00.31 SAH RELEASE Releasing to developer site +04-24-2006 2.00.31 SAH FIX Added/fixed some typecasts, manually defined gmtime in gsPlatform.h - DS doesn't support time +04-24-2006 2.00.30 SAH FIX Added prototype definition for _gsi_memalign (codewarrior warning) +04-20-2006 2.00.29 SAH FIX commented out unused variables, changed psp path to /usr/local/devkit +04-20-2006 2.00.28 SAH FIX Added newline to end of gsSHA1.h to get rid of error + SAH FIX Added #include to gsXML.c + SAH FIX Added _PS3 wrapper typecast to socket calls + SAH FIX Changed gsi_64 variables to long long - PS3 now uses 32 bit + SAH FIX added _tstrncpy defines for UNICODE && WIN32 + SAH FIX made a returned local variable static in gsUtilPS3 + SAH FIX Added a (char *) typecast ot gsSocketPS3 +04-18-2006 2.00.27 SAH FIX Added newline to end of gsXML.h to get rid of error +04-13-2006 2.00.26 SAH FIX Added #ifdef UNICODE, #include to platform.h +04-13-2006 2.00.26 SAH FIX Added #ifdef UNICODE headers around functions that call wcslen +04-05-2006 2.00.25 DDW OTHER Replace __asm int 3 with DebugBreak() call in gsAssert for x64 support +03-20-2006 2.00.24 DES FIX Fixed cross-platform string function undefines +03-15-2006 2.00.23 SN FIX Removed old __WINSOCK_2__ in preference to GSI_WINSOCK2 +03-02-2006 2.00.22 DES FEATURE Added encoding of Base64 as a stream + DES FEATURE Added writing Base64Binary and DateTime to XML streams +02-23-2006 2.00.21 DES FEATURE Added reading and writing functionality to the Xml code. +01-27-2006 2.00.20 SN RELEASE Releasing to developer site +01-11-2006 2.00.20 SN FIX Fixed function to return value for insock +01-09-2006 2.00.19 SN FIX Separated code for WIN32 and WIN32 Console in the assert function + Added platform checks around types and function pointers for memory code +10-08-2005 2.00.18 DES FIX Don't assert when freeing NULL, just ignore it. + DES CLEANUP Cleaned up assert code. +12-06-2005 2.00.17 SN FEATURE Temporarily added an Xbox assert function +11-15-2005 2.00.16 DES FIX Updated cross-platform compatibility. +11-14-2005 2.00.15 DES FEATURE Added GSI_DOMAIN_NAME to define "gamespy.com". +11-14-2005 2.00.14 MJ FEATURE Replaced memory management code. + Added stubbed files for cross platform rendering, input, and fileio +11-14-2005 2.00.13 DES CLEANUP Cleanup for Nitro and OSX. +11-11-2005 2.00.12 DES FIX Changes to crypt code for OSX compiler. + DES FIX added GSI_UNUSED for OSX. + BED FIX Fixed length check in gsLargeInt.c +10-12-2005 2.00.11 SN FIX Modified the INSOCK shutdown alias to use internal function +10-12-2005 2.00.10 BED RELEASE Releasing to developer site. +10-12-2005 2.00.09 DES FEATURE Updated to use SOC_ instead of SO_ prefixes for DS. +09-21-2005 2.00.08 DES FEATURE Updated DS support + DES FEATURE Added GS_WIRELESS_DEVICE for PSP and Nitro +08-12-2005 2.00.07 DES FIX Made changes to gsLargeInt.c for DS compatibility. +08-11-2005 2.00.06 BED FEATURE Added gsiCoreTaskThink so tasks could be pumped invidiually. +07-28-2005 2.00.05 SN RELEASE Releasing to developer site +07-28-2005 2.00.05 SN FIX Added an Extern C that was missing +07-27-2005 2.00.05 SN OTHER Removed include file until Xbox threading is implemented. +07-27-2005 2.00.04 SN FIX Fixed backwards IP address problem for Insock +06-23-2005 2.00.03 BED FEATURE Added PSP support. +06-03-2005 2.00.02 SN RELEASE Releasing to developer site. +05-26-2005 2.00.02 BED RELEASE Releasing to developer site. +05-26-2005 2.00.02 BED FIX Added missing extern "C" brace to end of gsMemory.h +05-26-2005 2.00.01 BED RELEASE Releasing to developer site. +05-26-2005 2.00.01 BED FIX Added old header stubs for new common code compatability with old sdks +05-26-2005 2.00.00 BED RELEASE Releasing to developer site. +05-16-2005 2.00.00 BED OTHER Moved common code into /common folder. + BED OTHER Split nonport.c and nonport.h into multiple files. +04-28-2005 1.11.02 SN RELEASE Releasing to developer site. +04-27-2005 1.11.02 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 1.11.02 DES FIX Nitro updates + DES FEATURE Addition categories and types added to gsiDebug +04-08-2005 1.11.01 SN FIX Fixed SN Systems bug where a socket was shown to be readable even when an error was recorded for it. +04-08-2005 1.11.00 DES FEATURE Changes for XBox support. +04-04-2005 1.10.72 SN RELEASE Releasing to developer site. +04-04-2005 1.10.72 DES CLEANUP Removed unused GS_BIG_ENDIAN define. + DES FEATURE Added gsi_is_false() and gsi_is_true() defines. + DES CLEANUP Removed unused PATHCHAR define. + DES CLEANUP Removed old _NITRO code from SetSockBlocking. +03-31-2005 1.10.71 BED FIX Removed some CodeWarrior strict compile warnings. +03-31-2005 1.10.70 SN FIX Fixed build problem by moving defines that had dependancies +03-14-2005 1.10.69 DES FEATURE Nintendo DS support +02-18-2005 1.10.68 BED FIX Added timeout for gsoap recv so it could recover from a hosed server + BED FIX Explicit __cdecl for hashtable and darray are used on Win32 only + BED FIX Switched gsimemory to track peak memory usage rather than total num allocs. +01-27-2005 1.10.67 DES FIX Added GSI_NO_THREADS for platforms without thread support + DES FIX Fixed custom SN sendto and moved it to nonport +01-04-2005 1.10.66 DDW FIX Added malloc cast in XXTEA encryption code +12-21-2004 1.10.65 SN FIX Added code to register the hostname resolution thread with SN_SYSTEMS +12-07-2004 1.10.64 BED FIX Added explicit __cdecl in darray.c and gsidebug.c +11-18-2004 1.10.63 SN RELEASE Releasing to developer site. +11-18-2004 1.10.63 SN FIX Fixed conversion warnings for XXTEA algorithm +11-17-2004 1.10.62 SN FIX Modified the XXTEA headers and renamed global key size +11-16-2004 1.10.62 BED FEATURE Added Thread/Semaphore common functions + BED FEATURE Added AD sdk to common debugger code. + BED FEATURE Common debug functions and memory manager are now thread safe + BED FEATURE Added core task processor (see core.h) + BED FEATURE Added common gsoap task (see soap.h) +11-16-2004 1.10.61 SN FEATURE Added URL-safe Base64 encoding and XXTEA encrypt and decrypt +09-21-2004 1.10.60 SN FIX Added the directories for MacOS X and Win32 common to goacommon.bat +09-16-2004 1.10.59 SN RELEASE Releasing to developer site. +09-16-2004 1.10.59 SN FIX Modified header define of NOFILE to avoid conflict with MacOS X +09-03-2004 1.10.58 BED CLEANUP Removed misc compiler warnings. +08-27-2004 1.10.57 BED FEATURE Added memory diagnostic functions to memory manager. +08-27-2004 1.10.56 DES CLEANUP Changed UNDER_UNIX to _UNIX, and define it if _LINUX or _MACOSX are defined. + DES OTHER Generate an error if _WIN32, _PS2, or _UNIX are not defined. + DES CLEANUP General Unicode cleanup + DES CLEANUP Fixed minor warnings under OSX + BED FIX Fixed typo in SN Systems version of GOAGetLastError. +08-25-2004 1.10.55 BED FEATURE Added common debug utilities to nonport. (See gsiDebug.h) + BED FEATURE Added memory pool manager to nonport. (See top of nonport.h) +08-24-2004 1.10.54 DES CLEANUP Removed references to MacOS. +08-20-2004 1.10.53 SN FIX Changed the way errors are obtained from the SN Systems network stack. +08-05-2004 1.10.52 SN RELEASE Releasing to developer site. +08-04-2004 1.10.51 SN FIX Fixed a function prototype causing compiler warnings for codewarrior +08-02-2004 1.10.50 SN FEATURE Added support for developers to use winsock 2 +07-13-2004 1.10.49 DES FEATURE Added GSIStartResolvingHostname() for doing async hostname lookups. +07-12-2004 1.10.48 SN FIX Cleared warnings when warnings are treated as errors for gamspy common code. +07-09-2004 1.10.47 SN FIX Updated portions of code to eliminate warnings for PS2 +07-08-2004 1.10.46 SN FIX Commented an include line +07-01-2004 1.10.46 SN FIX Includeded for ps2 +06-29-2004 1.10.45 BED RELEASE Releasing to developer site. +06-28-2004 1.10.45 DES FEATURE Added gsimemalign to the list of memory functions. +06-24-2004 1.10.44 BED FEATURE Util_Rand functions no longer static. + BED FEATURE Added B64 encode and decode from matrix source. +06-22-2004 1.10.43 BED RELEASE Releasing with updated PS2Common code +06-18-2004 1.10.42 BED RELEASE Releasing to developer site. +06-01-2004 1.10.42 BED FEATURE Phase 1 of PS2 Insock integration. (needs further testing) + BED FIX Found case where unsigned long was used on Ps2 instead of gsi_time. +04-27-2004 1.10.41 DES FEATURE Added current_time_hires(), returns time in microseconds. +03-10-2004 1.10.40 BED FEATURE Added some more types to nonport.h + FIX Undefine socket types to workaround SNSys bug. (They plan to patch in march 04) +12-03-2003 1.10.39 BED FEATURE Added "GameSpy Help.chm" to goapackage.bat +11-10-2003 1.10.38 DES RELEASE Releasing to developer site. +11-10-2003 1.10.38 BED FIX Remove misc compiler warnings. +11-07-2003 1.10.37 DES FIX Added linux support for the common integers datatypes. + FIX Added a newline to the bottom of available.h. + FEATURE The available check now uses .available.gamespy.com. +10-29-2003 1.10.36 DES FEATURE Added available.h,.c for doing backend services availability checks. +10-09-2003 1.10.35 BED FEATURE Added gsi_time type for PS2 compatibility +10-08-2003 1.10.34 JED FEATURE Added common integer datatypes +08-25-2003 1.10.33 JED CLEANUP Added some sanity checks in hashtable.c +07-24-2003 1.10.32 DES RELEASE Releasing to developer site. +07-23-2003 1.10.32 DES FIX Moved EENet includes in nonport.h to fix CW PS2 warnings. + DES FEATURE Added memory tracking. Use GSI_MEM_TRACK to enable. +07-22-2203 1.10.31 BED CLEANUP General cleanup to remove CodeWarrior compiler warnings. +07-16-2003 1.10.30 DES CLEANUP Removed support for Cisco NFT for the PS2. + FIX Changed some __mips64 checks to _PS2 checks in nonport.c + BED FIX Changed nonport.c to not use #pragma comment when _PS2 if defined +07-10-2003 1.10.29 BED CLEANUP Added GSI_UNUSED to nonport.h to silence unused variable warnings. +05-09-2003 1.10.28 DES CLEANUP Removed Dreamcast support. + CLEANUP Changed nonport.h to use EENet if no network stack is defined for the PS2. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +05-07-2003 1.10.27 DES RELEASE Releasing to developer site. + FIX Rewrote EENet GetMAC to be 2.7.x compatibile. +04-28-2003 1.10.26 DES RELEASE Releasing to developer site. + FIX Changed malloc/free in new EENet getlocalhost to gsimalloc/gsifree. +04-28-2003 1.10.25 DES RELEASE Releasing to developer site. +04-17-2003 1.10.25 DES FIX Rewrote EENet getlocalhost again, to be compatible with the 2.7.0.1 release. +04-15-2003 1.10.24 DES FIX Rewrote the EENet implementation of getlocalhost to build its own HOSTENT. +04-15-2003 1.10.23 JED CLEANUP Corrected DevStudio Level4 warnings for use of FD_SET +04-08-2003 1.10.22 JED FIX converted md5 function parameter type declarations from K&R C to ANSI C +03-27-2003 1.10.21 DES FIX IsPrivateIP no longer flips the source IP's byte order. +03-26-2003 1.10.20 DES RELEASE Releasing to developer site. +03-25-2003 1.10.20 DES FIX The EENet version of getlocalhost() wasn't checking all possible local IPs. +03-24-2003 1.10.19 DES FEATURE Added IsPrivateIP() for checking if an IP is a private network IP. + DES FIX GetTicks() no longer causes a compiler warning. +03-10-2003 1.10.18 DES RELEASE Releasing to developer site. +02-25-2003 1.10.18 DES CLEANUP Added headers to nonport.h for 2.6.1 EENet compatibility. + EENET_260 can be defined for 2.6.0 compatibility. +02-05-2003 1.10.17 DES RELEASE Releasing to developer site. +02-05-2003 1.10.17 DES FEATURE Added CanReceiveOnSocket and CanSendOnSocket as wrappers for select. + Needed because the SN stack for the PS2 has non-standard behavior. +01-23-2003 1.10.16 DES FEATURE Added the ability to just get the gsi*() memory function defines + by defining GSI_MEM_ONLY before including nonport.h. +01-07-2003 1.10.15 DES RELEASE Releasing to developer site. +01-07-2003 1.10.15 DES CLEANUP Removed a comment and a printf that were no longer needed. +01-02-2003 1.10.14 DES CLEANUP Removed the typedef for PSOCKADDR + It doesn't appear to be used anywhere, and was causing compile problems. +12-20-2002 1.10.13 DES FEATURE Implemented new code from SN Systems to get the MAC for the unique ID. +12-19-2002 1.10.12 DES RELEASE Releasing to developer site. +12-19-2002 1.10.12 DES CLEANUP Removed assert.h include from darray.h and hashtable.h. +12-18-2002 1.10.11 DES CLEANUP Put in a stub function fr getting the unique ID when using the SN stack. +12-16-2002 1.10.10 DES FEATURE Defined NOFILE when _PS2 is defined to exclude all file writing code. + FEATURE Defined SOMAXCONN to 5 when not defined. This is used as the backlog + parameter in calls to listen(). 5 is the max for SN Systems. + FEATURE gethostbyaddr() is not supported by SN Systems, defined it to NULL. + CLEANUP Changed GOAGetLastError() to clear the error for SN Systems. + Also removed GOAClearSocketError(), which was only needed for SN Systems. +12-13-2002 1.10.09 DES FEATURE Added EENet specific code for getting the MAC address for the Unique ID. +12-11-2002 1.10.08 DES FEATURE Additional eenet support. + FEATURE Added getlocalhost() for getting the local machine's hostent struct. + FEATURE Added SetSendBufferSize(), GetSendBufferSize(), and GetReceiveBufferSize(). +12-05-2002 1.10.07 DES CLEANUP General cleanup + FEATURE Initial PS2 eenet stack support +11-22-2002 1.10.06 DES RELEASE Releasing to developer site. +11-22-2002 1.10.06 DES FIX Fixed bug with checking the current time on the PS2. +11-20-2002 1.10.05 DES FEATURE Switched to using the MAC address for the Unique ID on the PS2. + CLEANUP Cleaned up to compile without warnings on the PS2. +11-18-2002 1.10.04 JED FIX nonport.c now using ansi registry funcs for WIN32/unicode +11-14-2002 1.10.03 DES FEATURE Added assert.h include to nonport.h. +11-13-2002 1.10.02 DDW FEATURE Changed GOAGetUniqueID to use redefinable function pointer. + Made Cisco the default stack for PS2. +11-13-2002 1.10.01 DES FIX Removed Reference to unsupported non-blocking CISCO stack +09-25-2002 1.10.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/common/gsAssert.c b/xrGameSpy/gamespy/common/gsAssert.c new file mode 100644 index 00000000000..c4c56861c63 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsAssert.c @@ -0,0 +1,182 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCommon.h" +#include "gsDebug.h" + + + +// This is the platform specific default assert condition handler +extern void _gsDebugAssert (const char * string); + +static gsDebugAssertCallback gsDebugAssertHandler = _gsDebugAssert; + +// Call this function to override the default assert handler +// New function should render message / log message based on string passed +void gsDebugAssertCallbackSet(gsDebugAssertCallback theCallback) +{ + if (theCallback) + gsDebugAssertHandler = theCallback; + else + gsDebugAssertHandler = _gsDebugAssert; +} + + +// This is the default assert condition handler +void gsDebugAssert (const char *szError,const char *szText, const char *szFile, int line) +{ + char String[256]; + // format into buffer + sprintf(&String[0], szError,szText,szFile,line); + + // call plat specific handler + (*gsDebugAssertHandler)(String); + +} + + +// **************************************************** +// Todo: move to platform specific modules +#ifdef _XBOX + // ErrorMessage: Displays message and goes into an infinite loop + // continues rendering + void _gsDebugAssert (const char *string) + { + //DebugBreak(); + OutputDebugString( string); + exit(0); + } + +#elif defined _WIN32 + #include + #pragma warning(disable: 4127) // disable warnings from "conditional expression is constant" + + // ErrorMessage: Displays message and goes into an infinite loop + // continues rendering + void _gsDebugAssert (const char *string) + { + + //DebugBreak(); + + + #ifdef _CONSOLE //,_MBCS + + printf("%s",string); + while(1) + { + }; + + #else + { + OutputDebugStringA( string); + + #ifndef GS_ASSERT_NO_MESSAGEBOX + { + int rcode = MessageBoxA(NULL,string,"Assert Failed",MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); + + if(rcode == IDABORT) + { + exit(0); + } + if(rcode == IDRETRY) + { + DebugBreak(); + return; + } + } + #else + DebugBreak(); + #endif + } + #endif + } + +#elif defined _PSP + // ToDo: + // ErrorMessage: Displays message and goes into an infinite loop + // continues rendering + void _gsDebugAssert (const char *string) + { + printf(string); + + while(1) + { + }; + + } + + +#elif defined _PS2 + + // already included in gsPlatform.h + /* + #include + #include + */ + + // ErrorMessage: Displays message and goes into an infinite loop + // continues rendering + void _gsDebugAssert (const char *string) + { + + scePrintf(string); + while(1);; + } + + + +#elif defined _MACOSX + void _gsDebugAssert (const char *string) + { + printf(string); + + while(1) + { + }; + + } + + +#elif defined _LINUX + void _gsDebugAssert (const char *string) + { + printf(string); + + while(1) + { + }; + + } + + +#elif defined _NITRO + void _gsDebugAssert (const char *string) + { +#if SDK_FINALROM != 1 + OS_TPanic("%s",string); +#else + GSI_UNUSED(string); +#endif + } + +#elif defined(_REVOLUTION) + void _gsDebugAssert(const char *string) + { + OSHalt(string); + + } +#else + // ErrorMessage: Displays message and goes into an infinite loop + // continues rendering + void _gsDebugAssert (const char *string) + { + + printf(string); + while(1);; + + } + +#endif + + + + diff --git a/xrGameSpy/gamespy/common/gsAssert.h b/xrGameSpy/gamespy/common/gsAssert.h new file mode 100644 index 00000000000..ee5f5b0eedf --- /dev/null +++ b/xrGameSpy/gamespy/common/gsAssert.h @@ -0,0 +1,86 @@ +#ifndef __GSIASSERT_H__ +#define __GSIASSERT_H__ + +#if defined(__LANGUAGE_C_PLUS_PLUS)||defined(__cplusplus)||defined(c_plusplus) +extern "C" { +#endif +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Assert for GameSpy SDKs +// +// Usage: +// 1) #define _DEBUG to enable assert. This should be set by compiler configuration. +// +// Todo: +// Allow user to specify IP to send debug output to (remote log for PS2) + + +// GS_ASSERT Use this to trap any programming bugs, such as range checks, invalid parameters +// use at start of each function to check all parameters +// also check all assumptions, ex// assume module is init. +// + +// GS_FAIL() Use instead of GS_ASSERT(0) when reaching an illegal area of code +// ex// the default: in a case statement that should be completely handled. + + +/* + ***The reason for using a GameSpy assert or custom assert*** + + although assert is handled very gracefully on the windows platform, most consoles do very little of real use during assert. + Furthermore, the program counter is lost, along with the callstack sometimes. + By having a custom critical error function, an asm "break" can be set in it, or a debugger break point. a call stack is + immediately available. The error can be drawn onto the screen. And the choice to ignore can also be given, in order + to continue stepping through code and further debug. + +*/ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +extern void gsDebugAssert (const char *format,const char *szError,const char *szFile, int line); +#ifndef _DEBUG + // On non-debug builds, release builds, ignore all of this. + // be carefull never to have function calls within one of these macros, as they will + // be ignored. + // ex// BAD: GS_ASSERT( i== FN()) // FN() will never be called, i will never be set in release builds + + #define GS_ASSERT(x) {}; // ex// GS_ASSERT( result == GS_OK ) + #define GS_ASSERT_STR(x, t) {}; // ex// GS_ASSERT_STR( result == GS_OK ,"GSFunction failed") + #define GS_ASSERT_ALIGN_16(x) {}; + #define GS_FAIL() + #define GS_FAIL_STR(x) + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#else + + #define GS_ASSERT(x) { if(!(x)) { gsDebugAssert("ASSERT on '" #x "' [%s] in %s line:%d\n", "", __FILE__,__LINE__); } }; + #define GS_ASSERT_STR(x,t) { if(!(x)) { gsDebugAssert("ASSERT on '" #x "' [%s] in %s line:%d\n", t, __FILE__,__LINE__); } }; + #define GS_ASSERT_ALIGN_16(x) { if(((U32)(x))%16) { gsDebugAssert("ASSERT on '" #x "' [%s] in %s line:%d\n","16 byte misalign", __FILE__,__LINE__); } }; + #define GS_FAIL() { gsDebugAssert("FAIL [%s] ln %s line:%d\n", "", __FILE__,__LINE__); }; + #define GS_FAIL_STR(t) { gsDebugAssert("FAIL [%s] ln %s line:%d\n", t, __FILE__,__LINE__); }; + + + +#endif // GSI_COMMON_DEBUG + + +// This is the default assert condition handler +typedef void (*gsDebugAssertCallback) (const char *string); + +// Call this function to override the default assert handler +// New function should render message / log message based on string passed +// calling this with NULL is restores the default setting. +void gsDebugAssertCallbackSet(gsDebugAssertCallback theCallback); + + +// This is like an assert, but test at compile, not run time. +// ex use STATIC_CHECK(DIM(array) == enumArrayCount) +#define GS_STATIC_CHECK(expr, msg) { CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } + + +#if defined(__LANGUAGE_C_PLUS_PLUS)||defined(__cplusplus)||defined(c_plusplus) +} +#endif + +#endif // __GSIDEBUG_H__ diff --git a/xrGameSpy/gamespy/common/gsAvailable.c b/xrGameSpy/gamespy/common/gsAvailable.c new file mode 100644 index 00000000000..00d5a526de8 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsAvailable.c @@ -0,0 +1,215 @@ +#include "gsCommon.h" +#include "gsAvailable.h" + +#define PACKET_TYPE 0x09 +#define MASTER_PORT 27900 +#define MAX_RETRIES 1 +#define TIMEOUT_TIME 2000 + +// this is the global var that the SDKs check +// to see if they should communicate with the backend +GSIACResult __GSIACResult = GSIACWaiting; + +// this makes the gamename available to all of the SDKs +char __GSIACGamename[64] = {0}; + +// this allows devs to do their own hostname resolution +char GSIACHostname[64] = {0}; + +// used to keep state during the check +static struct +{ + SOCKET sock; + SOCKADDR_IN address; + char packet[64]; + int packetLen; + gsi_time sendTime; + int retryCount; +} AC; + +static int get_sockaddrin(const char * hostname, int port, SOCKADDR_IN * saddr) +{ + GS_ASSERT(hostname) + GS_ASSERT(saddr) + + saddr->sin_family = AF_INET; + saddr->sin_port = htons((unsigned short)port); + saddr->sin_addr.s_addr = inet_addr(hostname); + + if(saddr->sin_addr.s_addr == INADDR_NONE) + { + HOSTENT * host = gethostbyname(hostname); + if(!host) + return 0; + saddr->sin_addr.s_addr = *(unsigned int *)host->h_addr_list[0]; + } + + return 1; +} + +static void SendPacket(void) +{ + sendto(AC.sock, AC.packet, AC.packetLen, 0, (SOCKADDR *)&AC.address, sizeof(AC.address)); + AC.sendTime = current_time(); +} + +void GSIStartAvailableCheckA(const char * gamename) +{ + char hostname[64]; + int override; + int rcode; + int len; + + GS_ASSERT(gamename) + + // store the gamename + strcpy(__GSIACGamename, gamename); + + // clear the sock + AC.sock = INVALID_SOCKET; + + // startup sockets + SocketStartUp(); + + // setup the hostname + override = GSIACHostname[0]; + if(!override) + sprintf(hostname, "%s.available." GSI_DOMAIN_NAME, gamename); + + // get the master address + rcode = get_sockaddrin(override?GSIACHostname:hostname, MASTER_PORT, &AC.address); + if(!rcode) + return; + + // create the socket + AC.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(AC.sock == INVALID_SOCKET) + return; + + // setup our packet + AC.packet[0] = PACKET_TYPE; + len = (int)strlen(gamename); + memcpy(AC.packet + 5, gamename, (size_t)len + 1); + AC.packetLen = (len + 6); + + // send it + SendPacket(); + + // no retries yet + AC.retryCount = 0; +} +#ifdef GSI_UNICODE +void GSIStartAvailableCheckW(const unsigned short * gamename) +{ + char gamename_A[32]; + GS_ASSERT(gamename) + + UCS2ToAsciiString(gamename, gamename_A); + + GSIStartAvailableCheckA(gamename_A); +} +#endif + +static int HandlePacket(char * packet, int len, SOCKADDR_IN * address, int * disabledservices) +{ + int bitfield; + + // check the length + if(len < 7) + return 1; + + // check the IP + if(memcmp(&address->sin_addr, &AC.address.sin_addr, sizeof(IN_ADDR)) != 0) + return 1; + + // check the port + if(address->sin_port != AC.address.sin_port) + return 1; + + // check the header + if(memcmp(packet, "\xFE\xFD\x09", 3) != 0) + return 1; + + // read out the bitfield + // read byte-by-byte to avoid alignment issues + bitfield = (int)((packet[3] << 24) & 0xFF000000); + bitfield |= ((packet[4] << 16) & 0x00FF0000); + bitfield |= ((packet[5] << 8) & 0x0000FF00); + bitfield |= (packet[6] & 0x000000FF); + + // set it + *disabledservices = bitfield; + + return 0; +} + +GSIACResult GSIAvailableCheckThink(void) +{ + char packet[64]; + SOCKADDR_IN address; + int len = sizeof(address); + int rcode; + int disabledservices; + + // if we don't have a sock, possibly because of an initialization error, default to available + if(AC.sock == INVALID_SOCKET) + { + __GSIACResult = GSIACAvailable; + return __GSIACResult; + } + + // did we get a response? + if(CanReceiveOnSocket(AC.sock)) + { + // read it from the socket + rcode = (int)recvfrom(AC.sock, packet, (int)sizeof(packet), 0, (SOCKADDR *)&address, &len); + + // verify the packet + rcode = HandlePacket(packet, rcode, &address, &disabledservices); + if(rcode == 0) + { + // we got a valid response, clean up + closesocket(AC.sock); + + // set the result based on the bit flags + if(disabledservices & 1) + __GSIACResult = GSIACUnavailable; + else if(disabledservices & 2) + __GSIACResult = GSIACTemporarilyUnavailable; + else + __GSIACResult = GSIACAvailable; + + // return it + return __GSIACResult; + } + } + + // check for a timeout + if(current_time() > (AC.sendTime + TIMEOUT_TIME)) + { + // check for too many retries + if(AC.retryCount == MAX_RETRIES) + { + // default to available + closesocket(AC.sock); + __GSIACResult = GSIACAvailable; + return __GSIACResult; + } + + // send a retry + SendPacket(); + AC.retryCount++; + } + + return GSIACWaiting; +} + +void GSICancelAvailableCheck(void) +{ + if(AC.sock != INVALID_SOCKET) + { + closesocket(AC.sock); + AC.sock = INVALID_SOCKET; + __GSIACResult = GSIACWaiting; + } +} diff --git a/xrGameSpy/gamespy/common/gsAvailable.h b/xrGameSpy/gamespy/common/gsAvailable.h new file mode 100644 index 00000000000..73bddfb9329 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsAvailable.h @@ -0,0 +1,54 @@ +#ifndef _AVAILABLE_H_ +#define _AVAILABLE_H_ + +#include "gsStringUtil.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GSI_UNICODE +#define GSIStartAvailableCheck GSIStartAvailableCheckA +#else +#define GSIStartAvailableCheck GSIStartAvailableCheckW +#endif + +// the available check contacts a backend server at ".available.gamespy.com" +// an app can resolve the hostname itself and store the IP here before starting the check +extern char GSIACHostname[64]; + +// these are possible return types for GSIAvailableCheckThink +typedef enum +{ + GSIACWaiting, // still waiting for a response from the backend + GSIACAvailable, // the game's backend services are available + GSIACUnavailable, // the game's backend services are unavailable + GSIACTemporarilyUnavailable // the game's backend services are temporarily unavailable +} GSIACResult; + +// start an available check for a particular game +// return 0 if no error starting up, non-zero if there's an error +void GSIStartAvailableCheck(const gsi_char * gamename); + +// let the available check think +// continue to call this while it returns GSIACWaiting +// if it returns GSIACAvailable, use the GameSpy SDKs as normal +// if it returns GSIACUnavailable or GSIACTemporarilyUnavailable, do NOT +// continue to use the GameSpy SDKs. the backend services are not available +// for the game. in this case, you can show the user a +// message based on the particular result. +GSIACResult GSIAvailableCheckThink(void); + +// this should only be used if the availability check needs to be aborted +// for example, if the player leaves the game's multiplayer area before the check completes +void GSICancelAvailableCheck(void); + +// internal use only +extern GSIACResult __GSIACResult; +extern char __GSIACGamename[64]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/common/gsCommon.h b/xrGameSpy/gamespy/common/gsCommon.h new file mode 100644 index 00000000000..40e840b2cfe --- /dev/null +++ b/xrGameSpy/gamespy/common/gsCommon.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSCOMMON_H__ +#define __GSCOMMON_H__ + +// Common is more like "all" + +// Build settings (set by developer project) +//#define GS_MEM_MANAGED // use GameSpy memory manager for SDK allocations +//#define GS_COMMON_DEBUG // use GameSpy debug utilities for SDK debug output +//#define GS_WINSOCK2 // use winsock2 +//#define GS_UNICODE // Use widechar (UCS2) SDK interface. +//#define GS_NO_FILE // disable file storage (on by default for PS2/DS) +//#define GS_NO_THREAD // no multi-thread support +//#define GS_PEER // MUST be defined if you are using Peer SDK + + +#ifdef GS_PEER + #define UNIQUEID // enable unique id support +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsPlatform.h" +#include "gsPlatformSocket.h" +#include "gsPlatformThread.h" +#include "gsPlatformUtil.h" + +// platform independent +#include "gsMemory.h" +#include "gsDebug.h" +#include "gsAssert.h" +#include "gsStringUtil.h" + +//#include "md5.h" +//#include "darray.h" +//#include "hashtable.h" + + +#define GSI_MIN(a,b) (((a) < (b)?(a):(b))) +#define GSI_MAX(a,b) (((a) > (b)?(a):(b))) +#define GSI_LIMIT(x, minx, maxx) (((x) < (minx)? (minx) : ((x) > (maxx)? (maxx) : (x)))) +#define GSI_WRAP(x, minx, maxx) (((x) < (minx)? (maxx-1 ) : ((x) >= (maxx)? (minx) : (x)))) +#define GSI_DIM( x ) ( sizeof( x ) / sizeof((x)[ 0 ])) + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __GSCOMMON_H__ diff --git a/xrGameSpy/gamespy/common/gsCore.c b/xrGameSpy/gamespy/common/gsCore.c new file mode 100644 index 00000000000..d23f8f19605 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsCore.c @@ -0,0 +1,446 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Core task/callback manager +#include "gsPlatform.h" +#include "gsPlatformThread.h" + +#include "gsCommon.h" +#include "gsCore.h" +#include "gsAssert.h" +#include "../ghttp/ghttp.h" + + + + +// This defines how long the core will wait if there is a thread synchronization +// problem when initializing or shutting down the core. +#define GSI_CORE_INIT_YIELD_MS 100 +#define GSI_CORE_SHUTDOWN_YIELD_MS 50 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static GSCoreMgr* gsiGetStaticCore() +{ + static GSCoreMgr gStaticCore; + return &gStaticCore; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This is registered with the ANSI atexit() function +// - don't do anything that might fail +// - don't do anything that won't complete instantly +// - don't do anything that requires other objects/resources to exist +static void gsiCoreAtExitShutdown(void) +{ + // delete queue critical section + GSCoreMgr * aCore = gsiGetStaticCore(); + gsiDeleteCriticalSection(&aCore->mQueueCrit); + GSI_UNUSED(aCore); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment core ref count, initialize the core if necessary +// - WARNING: This code is a bit tricky do to multithread issues +void gsCoreInitialize() +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + + // Is someone else shutting down the core? + while(gsi_is_true(aCore->mIsShuttingDown)) + msleep(GSI_CORE_INIT_YIELD_MS); // yield to other thread + + // If we're the first reference, initialize the core + if (gsiInterlockedIncrement(&aCore->mRefCount) == 1) + { + // Are we the first ever? + if (gsi_is_false(aCore->mIsStaticInitComplete)) + { + // perform one-time initialization of core critical section + gsiInitializeCriticalSection(&aCore->mQueueCrit); + + // register function to destroy critical section at program termination + #ifndef _MANAGED + atexit(gsiCoreAtExitShutdown); + #endif + + // one time init completed + aCore->mIsStaticInitComplete = gsi_true; + } + + // take the critical section to begin initialization + // this is necessary in case another thread began shutdown before we incremented ref count + gsiEnterCriticalSection(&aCore->mQueueCrit); + gsiLeaveCriticalSection(&aCore->mQueueCrit); + + // wait here if another thread is concurrently shutting down the core + // we may need to wait a few times if the shutdown does not complete immediately + while(gsi_is_true(aCore->mIsShuttingDown)) + msleep(GSI_CORE_INIT_YIELD_MS); + + // Setup the task array + #ifdef GSICORE_DYNAMIC_TASK_LIST + aCore->mTaskArray = ArrayNew(sizeof(GSTask*), 10, NULL); + GS_ASSERT(aCore->mTaskArray); + #else + memset(aCore->mTaskArray, 0, sizeof(aCore->mTaskArray)); + #endif + + // Init http sdk (ghttp is ref counted) + ghttpStartup(); + + // release other threads that may have blocked during init + // - this must be the last thing done at end of init + aCore->mIsInitialized = gsi_true; + } + else + { + // Core is already initialized -OR- another thread will initialize the core + + // make sure critical section has been initialized + while(gsi_is_false(aCore->mIsStaticInitComplete)) + msleep(GSI_CORE_INIT_YIELD_MS); + + // take the critical section + // this is necessary in case another thread began shutdown before we incremented ref count + gsiEnterCriticalSection(&aCore->mQueueCrit); + gsiLeaveCriticalSection(&aCore->mQueueCrit); + + // wait for other thread to initial core + while(gsi_is_false(aCore->mIsInitialized)) + msleep(GSI_CORE_INIT_YIELD_MS); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void gsiCoreTaskDispatchCallback(GSTask *theTask, GSTaskResult theResult) +{ + if (theTask->mIsCallbackPending) + { + theTask->mIsCallbackPending = 0; + if (theTask->mCallbackFunc) + (theTask->mCallbackFunc)(theTask->mTaskData, theResult); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Return values: +// GSTaskResult_InProgress - Keep calling gsCoreTaskThink +// GSTaskResult_Finished - Task memory freed; task object is now invalid +GSTaskResult gsCoreTaskThink(GSTask* theTask) +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + GSTaskResult aResult = GSTaskResult_None; + + if (theTask == NULL) + return GSTaskResult_Finished; + + // If the task is running let it think (it may be cancelled and still running) + if (theTask->mIsRunning && theTask->mThinkFunc) + aResult = (theTask->mThinkFunc)(theTask->mTaskData); + + // Check for time out + if ((!theTask->mIsCanceled) && (aResult == GSTaskResult_InProgress)) + { + if ((theTask->mTimeout != 0) && (current_time() - theTask->mStartTime > theTask->mTimeout)) + { + // Cancel the task... + gsiCoreCancelTask(theTask); + + // ...but trigger callback immediately with "Timed Out" + gsiCoreTaskDispatchCallback(theTask, GSTaskResult_TimedOut); + } + //else + // continue processing it + } + else if (aResult != GSTaskResult_InProgress) + { + // Note: This section may be triggered multiple times if the cleanup + // function fails. (possibly due to lack of memory) + int i=0; + gsi_bool removeTask = gsi_true; + + // Call the callback if we haven't already + if (theTask->mIsRunning) + { + gsiCoreTaskDispatchCallback(theTask, aResult); + theTask->mIsRunning = 0; + } + + // Call Cleanup hook and remove task + if (theTask->mCleanupFunc) + removeTask = (theTask->mCleanupFunc)(theTask->mTaskData); + + // Remove the task + if (gsi_is_true(removeTask)) + { + gsiEnterCriticalSection(&aCore->mQueueCrit); + #ifdef GSICORE_DYNAMIC_TASK_LIST + { + int len = ArrayLength(aCore->mTaskArray); + for (i=0; i < len; i++) + { + if(*(GSTask**)ArrayNth(aCore->mTaskArray, i) == theTask) + { + ArrayRemoveAt(aCore->mTaskArray, i); + gsifree(theTask); + break; + } + } + } + #else + for (i=0; i < GSICORE_MAXTASKS; i++) + { + if (aCore->mTaskArray[i] == theTask) + { + aCore->mTaskArray[i] = NULL; + gsifree(theTask); + break; + } + } + #endif + gsiLeaveCriticalSection(&aCore->mQueueCrit); + return GSTaskResult_Finished; + } + } + + // Note: This function should always return InProgress until + // the task has been removed from the TaskArray. + // The developer may have already received a completed callback + // while this continue to return InProgress meaning "still needs to be pumped" + return GSTaskResult_InProgress; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Optional maximum processing time +// - Pass in 0 to process each task once +void gsCoreThink(gsi_time theMS) +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + int i=0; + gsi_time aStartTime = 0; + gsi_i32 allTasksAreDead = 1; + + if (gsi_is_false(aCore->mIsInitialized)) + return; + + // enter queue critical section + gsiEnterCriticalSection(&aCore->mQueueCrit); + + // start timing + aStartTime = current_time(); + + // process all tasks in the queue, dispatch callbacks + // cancelled tasks continue processing until the cancel is acknowledge by the task + #ifdef GSICORE_DYNAMIC_TASK_LIST + { + int len = ArrayLength(aCore->mTaskArray); + if(len > 0) + allTasksAreDead = 0; + for(i=(len-1); i>=0; i--) + { + GSTask* task = *(GSTask**)ArrayNth(aCore->mTaskArray, i); + if(gsi_is_true(task->mAutoThink)) + gsCoreTaskThink(task); + if (theMS != 0 && (current_time()-aStartTime > theMS)) + break; + } + } + #else + for (i=0; imTaskArray[i] != NULL) + { + allTasksAreDead = 0; + + if (aCore->mTaskArray[i]->mAutoThink == gsi_true) + gsCoreTaskThink(aCore->mTaskArray[i]); + } + // Enough time to process another? (if not, break) + if (theMS != 0 && (current_time()-aStartTime > theMS)) + break; + } + #endif + + // shutting down? + if (aCore->mIsShuttingDown && allTasksAreDead) + { + ghttpCleanup(); + +#ifdef GSICORE_DYNAMIC_TASK_LIST + if(aCore->mTaskArray) + { + ArrayFree(aCore->mTaskArray); + aCore->mTaskArray = NULL; + } +#endif + + aCore->mIsShuttingDown = 0; + } + + // leave queue critical section + gsiLeaveCriticalSection(&aCore->mQueueCrit); + + GSI_UNUSED(theMS); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsCoreShutdown() +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + int i=0; + + // If not initialized, just bail + if (gsi_is_false(aCore->mIsInitialized)) + return; + + // Take the critical section to prevent anyone from re-initializing while + // we decide if we need to shutdown + gsiEnterCriticalSection(&aCore->mQueueCrit); + + // If there are other references, just return + if (gsiInterlockedDecrement(&aCore->mRefCount)>0) + { + gsiLeaveCriticalSection(&aCore->mQueueCrit); + return; + } + else + { + // we released the final reference, begin shutdown + // no other thread will begin using the core until + // mIsShuttingDown has been set back to false + aCore->mIsShuttingDown = gsi_true; + + // Cancel all tasks + #ifdef GSICORE_DYNAMIC_TASK_LIST + { + int len = ArrayLength(aCore->mTaskArray); + for(i=0; imTaskArray, i)); + } + } + #else + for (i=0; imTaskArray[i] != NULL) + { + gsiCoreCancelTask(aCore->mTaskArray[i]); + } + } + #endif + gsiLeaveCriticalSection(&aCore->mQueueCrit); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +GSCoreValue gsCoreIsShutdown() +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + + if (gsi_is_true(aCore->mIsShuttingDown)) + return GSCore_SHUTDOWN_PENDING; + if (aCore->mRefCount == 0) + return GSCore_SHUTDOWN_COMPLETE; + + // The core isn't shutting down, and ref count > 0, + // therefore the core is in use + return GSCore_IN_USE; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Adds a GSCoreTask to the execution array +// - Tasks may come from multiple threads +void gsiCoreExecuteTask(GSTask* theTask, gsi_time theTimeoutMs) +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + + // Bail, if the task has already started + GS_ASSERT(!theTask->mIsRunning); + + // Mark it as started and running + theTask->mIsCallbackPending = 1; + theTask->mIsStarted = 1; + theTask->mIsRunning = 1; + theTask->mTimeout = theTimeoutMs; + theTask->mStartTime = current_time(); + + // Execute the task + if (theTask->mExecuteFunc) + (theTask->mExecuteFunc)(theTask->mTaskData); + + gsiEnterCriticalSection(&aCore->mQueueCrit); + // add it to the process list + #ifdef GSICORE_DYNAMIC_TASK_LIST + ArrayAppend(aCore->mTaskArray, &theTask); + #else + { + int anInsertPos = -1; + int i=0; + for (i=0; imTaskArray[i] == NULL) + { + anInsertPos = i; + break; + } + } + GS_ASSERT(anInsertPos != -1); // make sure it got in + aCore->mTaskArray[anInsertPos] = theTask; + } + #endif + gsiLeaveCriticalSection(&aCore->mQueueCrit); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// cancelling a task is an *async request* +// A task that doesn't support cancelling, such as a blocking socket operation, +// may complete normally even though it was cancelled. +void gsiCoreCancelTask(GSTask* theTask) +{ + GSCoreMgr* aCore = gsiGetStaticCore(); + + // Enter critical secction here so the developer + // may cancel a task from any thread. (e.g. The task thread has blocked) + gsiEnterCriticalSection(&aCore->mQueueCrit); + if (theTask->mIsRunning && !theTask->mIsCanceled) + { + theTask->mIsCanceled = 1; + if (theTask->mCancelFunc) + (theTask->mCancelFunc)(theTask->mTaskData); + } + gsiLeaveCriticalSection(&aCore->mQueueCrit); + GSI_UNUSED(aCore); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +GSTask* gsiCoreCreateTask() +{ + GSTask* aTask = (GSTask*)gsimalloc(sizeof(GSTask)); + if (aTask == NULL) + return NULL; + + memset(aTask, 0, sizeof(GSTask)); + aTask->mAutoThink = gsi_true; + return aTask; +} diff --git a/xrGameSpy/gamespy/common/gsCore.h b/xrGameSpy/gamespy/common/gsCore.h new file mode 100644 index 00000000000..5d092b4e1d0 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsCore.h @@ -0,0 +1,128 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __CORE_H__ +#define __CORE_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Core task/callback manager +#include "gsCommon.h" +#include "../darray.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define GSICORE_DYNAMIC_TASK_LIST +#define GSICORE_MAXTASKS 40 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef enum +{ + GSCore_IN_USE, + GSCore_SHUTDOWN_PENDING, + GSCore_SHUTDOWN_COMPLETE +} GSCoreValue; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef enum +{ + GSTaskResult_None, + GSTaskResult_InProgress, + GSTaskResult_Canceled, + GSTaskResult_TimedOut, + GSTaskResult_Finished +} GSTaskResult; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// delegates (optional, may be NULL) +typedef void(*GSTaskExecuteFunc) (void* theTaskData); +typedef void(*GSTaskCallbackFunc)(void* theTaskData, GSTaskResult theResult); +typedef void(*GSTaskCancelFunc) (void* theTaskData); +typedef gsi_bool(*GSTaskCleanupFunc) (void* theTaskData); // post run cleanup +typedef GSTaskResult(*GSTaskThinkFunc)(void* theTaskData); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// "Private" struct for dispatching tasks. Once tasks have been put in the queue +// they should only be modified from the think thread. +// - When creating a task, you should set only the task data and delegates +typedef struct +{ + int mId; + gsi_time mTimeout; + gsi_time mStartTime; + gsi_bool mAutoThink; + + // These are not exclusive states (use bit flags?) + gsi_i32 mIsStarted; + gsi_i32 mIsRunning; + gsi_i32 mIsCanceled; + gsi_i32 mIsCallbackPending; // does the task require a callback? + + // delegates + void* mTaskData; + GSTaskExecuteFunc mExecuteFunc; + GSTaskCallbackFunc mCallbackFunc; + GSTaskCancelFunc mCancelFunc; + GSTaskCleanupFunc mCleanupFunc; + GSTaskThinkFunc mThinkFunc; +} GSTask; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct +{ + gsi_u32 mRefCount; + + gsi_bool volatile mIsStaticInitComplete; // once per application init + gsi_bool volatile mIsInitialized; // gsi_true when ready to use + gsi_bool volatile mIsShuttingDown; // gsi_true when shutting down + + GSICriticalSection mQueueCrit; + #ifdef GSICORE_DYNAMIC_TASK_LIST + DArray mTaskArray; + #else + GSTask* mTaskArray[GSICORE_MAXTASKS]; + #endif + +} GSCoreMgr; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsCoreInitialize (void); +void gsCoreThink (gsi_time theMS); +void gsCoreShutdown (void); +GSCoreValue gsCoreIsShutdown(void); + +GSTaskResult gsCoreTaskThink(GSTask* theTask); +void gsiCoreExecuteTask (GSTask* theTask, gsi_time theTimeoutMs); +void gsiCoreCancelTask (GSTask* theTask); + +GSTask* gsiCoreCreateTask(void); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __CORE_H__ diff --git a/xrGameSpy/gamespy/common/gsCrypt.c b/xrGameSpy/gamespy/common/gsCrypt.c new file mode 100644 index 00000000000..0ac8de8c593 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsCrypt.c @@ -0,0 +1,509 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCrypt.h" +#include "gsLargeInt.h" +#include "gsSHA1.h" + +// **Please refer to gsCrypt.h for public interface functions** + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef GS_CRYPT_RSA_ES_OAEP + static gsi_i32 gsCryptRSAOAEPEncryptBuffer(const gsCryptRSAKey *publicKey, const unsigned char *plainText, gsi_u32 len, unsigned char buffer[GS_CRYPT_RSA_BYTE_SIZE]); + static gsi_i32 gsCryptRSAOAEPDecryptBuffer(const gsCryptRSAKey *privateKey, const unsigned char cipherText[GS_CRYPT_RSA_BYTE_SIZE], unsigned char *plainText, gsi_u32 *lenout); + + static void gsiCryptRSAGenerateSeed(unsigned char *buffer, gsi_u32 len); + static gsi_bool gsiCryptRSAMaskData(unsigned char *data, gsi_u32 len, const unsigned char *maskSeed, gsi_u32 maskLen); +#else + static gsi_i32 gsCryptRSAPKCS1EncryptBuffer(const gsCryptRSAKey *publicKey, const unsigned char *plainText, gsi_u32 len, unsigned char buffer[GS_CRYPT_RSA_BYTE_SIZE]); + static gsi_i32 gsCryptRSAPKCS1DecryptBuffer(const gsCryptRSAKey *privateKey, const unsigned char ciperText[GS_CRYPT_RSA_BYTE_SIZE], unsigned char *plainTextOut, gsi_u32 *lenOut); + + static void gsiCryptRSAGeneratePad(unsigned char *buffer, gsi_u32 len); +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef GS_CRYPT_RSA_ES_OAEP + // generate a random seed for OAEP + void gsiCryptRSAGenerateSeed(unsigned char *buffer, gsi_u32 len) + { + unsigned int i=0; + + Util_RandSeed(current_time()); + for (i=0; i < len; i++) + { + //buffer[i] = 0x0c; + buffer[i] = (unsigned char)(Util_RandInt(0x00, 0xFF)+1); + GS_ASSERT(buffer[i] != 0x00); + } + } + + // PKCS#1 v2.1, B.2.1 MGF1, mask generation function + // modification: generates mask and applies in place + gsi_bool gsiCryptRSAMaskData(unsigned char *data, gsi_u32 dataLen, const unsigned char* seed, gsi_u32 seedLen) + { + int i=0; + int k=0; + + // The datablock may be used as the seed + unsigned char hashValue[GS_CRYPT_HASHSIZE]; // in integer form, NOT HEXSTRING + + // seed should never be larger than the data block size (but it may be less) + if (seedLen > GS_CRYPT_RSA_DATABLOCKSIZE) + return gsi_false; + + for (i=0; (gsi_u32)i= dataLen) + return gsi_true; + + data[i+k] ^= (gsi_u8)hashValue[k]; + } + } + return gsi_true; + } +#else + // generate a random pad for PKCS1 + // [0x01 - 0xFF] + void gsiCryptRSAGeneratePad(unsigned char *buffer, gsi_u32 len) + { + unsigned int i=0; + + Util_RandSeed(current_time()); + for (i=0; i < len; i++) + { + #if defined(GS_CRYPT_NO_RANDOM) + #pragma message("GS_CRYPT_NO_RANDOM defined, SSL is NOT SECURE!!!!\r\n") + buffer[i] = 0x0c; + #else + buffer[i] = (unsigned char)(Util_RandInt(0x00, 0xFF)+1); + #endif + GS_ASSERT(buffer[i] != 0x00); + } + } +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// RSA Packet = encrypt(lhash, pad, 0x01, plainText) +// lhash is constant, since labels are not supported +// pad is variable length, depending on plainText length +gsi_i32 gsCryptRSAEncryptBuffer(const gsCryptRSAKey *publicKey, const unsigned char *plainText, gsi_u32 len, unsigned char buffer[GS_CRYPT_RSA_BYTE_SIZE]) +{ + #ifdef GS_CRYPT_RSA_ES_OAEP + return gsCryptRSAOAEPEncryptBuffer(publicKey, plainText, len, buffer); + #else + return gsCryptRSAPKCS1EncryptBuffer(publicKey, plainText, len, buffer); + #endif +} + +#ifdef GS_CRYPT_RSA_ES_OAEP + gsi_i32 gsCryptRSAOAEPEncryptBuffer(const gsCryptRSAKey *publicKey, const unsigned char *plainText, gsi_u32 len, unsigned char buffer[GS_CRYPT_RSA_BYTE_SIZE]) + { + gsLargeInt_t lintRSAPacket; + gsCryptRSAOAEPPacket* packet = (gsCryptRSAOAEPPacket*)lintRSAPacket.mData; + + #if (GS_CRYPT_HASHSIZE==GS_CRYPT_MD5_HASHSIZE) + const gsi_u8 lhash[GS_CRYPT_HASHSIZE] = {0xd4,0x1d,0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,0x7e}; // hash of "" + #else + const gsi_u8 lhash[GS_CRYPT_HASHSIZE] = {0xda,0x39,0xa3,0xee,0x5e,0x6b,0x4b,0x0d,0x32,0x55,0xbf,0xef,0x95,0x60,0x18,0x90,0xaf,0xd8,0x07,0x09}; // hash of "" + #endif + const unsigned int maxPlainTextLen = GS_CRYPT_RSA_BYTE_SIZE-2*GS_CRYPT_HASHSIZE-2; + const unsigned int padSize = maxPlainTextLen-len; + + // The steps below are taken from PKCS#1, section 7.1.1 "Encryption Operation" + // 1. check length + if (len > maxPlainTextLen) + return -1; + + // 2. EME-OAEP encoding (pad & pad format) + // a. precalculated above (const lhash) + + // b. create pad + // c. concatenate hash+pad+0x01+plainText + memcpy(packet->maskedData, lhash, GS_CRYPT_HASHSIZE); + memset(&packet->maskedData[GS_CRYPT_HASHSIZE], 0, padSize); // pad with zero bytes + packet->maskedData[GS_CRYPT_HASHSIZE+padSize] = 0x01; // RSA encoding format ID (EME-OAEP) + memcpy(&packet->maskedData[GS_CRYPT_HASHSIZE+padSize+1], plainText, len); + + // d. generate random seed (seed isn't masked until h.) + gsiCryptRSAGenerateSeed(packet->maskedSeed, GS_CRYPT_HASHSIZE); + + // e. use (still unmasked) seed to generate a mask for the datablock + // f. apply it with xor + gsiCryptRSAMaskData(packet->maskedData, GS_CRYPT_RSA_DATABLOCKSIZE, packet->maskedSeed, GS_CRYPT_HASHSIZE); + + // g. use the masked datablock to generate a mask for the seed + // h. apply it with xor + gsiCryptRSAMaskData(packet->maskedSeed, GS_CRYPT_HASHSIZE, packet->maskedData, GS_CRYPT_RSA_DATABLOCKSIZE); + + // i. set first byte to 0x00 + packet->headerByte = 0x00; + + // 3. Encryptitize + /* + lintRSAPacket.mLength = GS_CRYPT_RSA_BYTE_SIZE/sizeof(gsi_u32); + gsLargeIntReverseBytes(&lintRSAPacket); + gsLargeIntPowerMod(&lintRSAPacket, &publicKey->exponent, &publicKey->modulus, &lintRSAPacket); + gsLargeIntReverseBytes(&lintRSAPacket); + + // 4. return cipher text + memcpy(buffer, lintRSAPacket.mData, GS_CRYPT_RSA_BYTE_SIZE); + */ + GS_ASSERT(0); // Section above needs revision due to byte order issues + + return 0; + } +#else + gsi_i32 gsCryptRSAPKCS1EncryptBuffer(const gsCryptRSAKey *publicKey, const unsigned char *plainText, gsi_u32 len, unsigned char buffer[GS_CRYPT_RSA_BYTE_SIZE]) + { + gsi_u8 buf[GS_CRYPT_RSA_BYTE_SIZE]; + gsCryptRSAPKCS1Packet* packet = (gsCryptRSAPKCS1Packet*)buf; + gsLargeInt_t lintRSAPacket; + + if (len > (GS_CRYPT_RSA_BYTE_SIZE-11)) // 2 byte header, 8 byte pad minimum, 1 byte separator + return -1; + + // form the packet + packet->headerByte[0] = 0x00; + packet->headerByte[1] = 0x02; + + gsiCryptRSAGeneratePad(packet->data, GS_CRYPT_RSA_BYTE_SIZE-len-3); + packet->data[GS_CRYPT_RSA_BYTE_SIZE-len-3] = 0x00; // separator + memcpy(&packet->data[GS_CRYPT_RSA_BYTE_SIZE-len-3+1], plainText, len); + + if (gsi_is_false(gsLargeIntSetFromMemoryStream(&lintRSAPacket, (const gsi_u8*)buf, GS_CRYPT_RSA_BYTE_SIZE)) || + gsi_is_false(gsLargeIntPowerMod(&lintRSAPacket, &publicKey->exponent, &publicKey->modulus, &lintRSAPacket)) || + gsi_is_false(gsLargeIntWriteToMemoryStream(&lintRSAPacket, buffer)) ) + { + return -1; + } + + return 0; + } +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_i32 gsCryptRSADecryptBuffer(const gsCryptRSAKey *privateKey, const unsigned char cipherText[GS_CRYPT_RSA_BYTE_SIZE], unsigned char *plainText, gsi_u32 *lenout) +{ + #ifdef GS_CRYPT_RSA_ES_OAEP + return gsCryptRSAOAEPDecryptBuffer(privateKey, cipherText, plainText, lenout); + #else + return gsCryptRSAPKCS1DecryptBuffer(privateKey, cipherText, plainText, lenout); + #endif +} + +// Since decryption requires the privatekey, it is usually done by the server. +// Decryption is also much slower than encryption. +// This is included here as a testing utility but should probably not be used in a game client. +#ifndef GS_CRYPT_RSA_ES_OAEP + static gsi_i32 gsCryptRSAPKCS1DecryptBuffer(const gsCryptRSAKey *privateKey, const unsigned char cipherText[GS_CRYPT_RSA_BYTE_SIZE], unsigned char *plainText, gsi_u32 *lenout) + { + int i=0; + char* temp; + gsLargeInt_t lintRSAPacket; + lintRSAPacket.mLength = GS_CRYPT_RSA_BYTE_SIZE/GS_LARGEINT_DIGIT_SIZE_BYTES; + memcpy(lintRSAPacket.mData, cipherText, GS_CRYPT_RSA_BYTE_SIZE); + + if (gsi_is_false(gsLargeIntReverseBytes(&lintRSAPacket)) || // reverse from bytebuffer to lint format + gsi_is_false(gsLargeIntPowerMod(&lintRSAPacket, &privateKey->exponent, &privateKey->modulus, &lintRSAPacket)) || + gsi_is_false(gsLargeIntReverseBytes(&lintRSAPacket)) // reverse back into a bytebuffer + ) + { + return -1; + } + + // check post exponentiation length + if (lintRSAPacket.mLength < (GS_CRYPT_RSA_BYTE_SIZE/GS_LARGEINT_DIGIT_SIZE_BYTES)) + return -1; + + // Check the packet for legality + // 1. first byte must be 0x00 + // 2. send byte must be 0x02 + // 3. pad must be at least 8 bytes and end with 0x00 + // 4. payload must be at least 1 byte + temp = (char*)lintRSAPacket.mData; + if (temp[0] != 0x00) + return -1; + if (temp[1] != 0x02) + return -2; + + // find the start of the data (first 0x00 byte after the 1st) + temp = (char*)lintRSAPacket.mData; + for (i=2; iexponent, &privateKey->modulus, &lintRSAPacket); + gsLargeIntReverseBytes(&lintRSAPacket); // reverse back into a bytebuffer + + // check post exponentiation length + if (lintRSAPacket.mLength < (GS_CRYPT_RSA_BYTE_SIZE/4)) + return -1; + + // Check the packet for legality + // 1. "un-mask" the maskedSeed, using the maskedData + gsiCryptRSAMaskData(packet->maskedSeed, GS_CRYPT_HASHSIZE, packet->maskedData, GS_CRYPT_RSA_DATABLOCKSIZE); + // 2. "un-mask" the maskedData, using the previously unmasked maskedSeed + gsiCryptRSAMaskData(packet->maskedData, GS_CRYPT_RSA_DATABLOCKSIZE, packet->maskedSeed, GS_CRYPT_HASHSIZE); + // 3. datablock = [lhash][0x00...][0x01][M] + if (0 != memcmp(packet->maskedData, lhash, GS_CRYPT_HASHSIZE)) + return -2; // label has doesn't match (mismatched hash algorithms?) + i = 33; + while(imaskedData[i] == 0x00) + i++; // may be zero bytes pad + if (i==GS_CRYPT_RSA_BYTE_SIZE || packet->maskedData[i] != 0x01) + return -3; // must be a 0x01 following the pad + i++; + if (i == GS_CRYPT_RSA_BYTE_SIZE) + return -4; // founnd the separator, but no message! + + memcpy(plainText, &packet->maskedData[i], (size_t)(GS_CRYPT_RSA_DATABLOCKSIZE-i)); + *lenout = (gsi_u32)(GS_CRYPT_RSA_DATABLOCKSIZE-i); // final length = blocksize - pad + return 0; + } +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_i32 gsCryptRSASignData(const gsCryptRSAKey *privateKey, const unsigned char *plainText, gsi_u32 plainTextLen, unsigned char *signedDataOut, gsi_u32 *lenOut) +{ + const unsigned char * hash = NULL; + + GSI_UNUSED(privateKey); + GSI_UNUSED(plainText); + GSI_UNUSED(plainTextLen); + GSI_UNUSED(signedDataOut); + GSI_UNUSED(lenOut); + + // 1) hash data + // hash = MD5(plainText); + //GS_ASSERT(0); // not implemented yet + + + // 2) Sign + return gsCryptRSASignHash(privateKey, hash, GS_CRYPT_MD5_HASHSIZE, signedDataOut, lenOut); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// The more usual use of RSA signatures +// Constructs a PKCS1 signature form of type { [0x00][0x01][0xFF..FF][0x00][hash oid][hash] } = RSA key length +gsi_i32 gsCryptRSASignHash(const gsCryptRSAKey *privateKey, const unsigned char *hash, gsi_u32 hashLen, unsigned char *signedDataOut, gsi_u32 *lenOut) +{ + // Encode to PKCS1 signature form + gsi_u32 aKeyByteLength = privateKey->modulus.mLength * GS_LARGEINT_DIGIT_SIZE_BYTES; // key length in bytes + gsi_u32 aReservedLength = 3; + gsi_u32 anOidLen; + + gsLargeInt_t dataToSign; + char * writeBuf = (char*)dataToSign.mData; + + // Microsoft PKCS #1 headers for various hash algorithms. + gsi_u8 md5Header[18] = {0x30,0x20,0x30,0x0C,0x06,0x08,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05,0x05,0x00,0x04,0x10}; + gsi_u8 sha1Header[15] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; + + if (hashLen == GS_CRYPT_MD5_HASHSIZE) + anOidLen = sizeof(md5Header); + else if (hashLen == GS_CRYPT_SHA1_HASHSIZE) + anOidLen = sizeof(sha1Header); + else + return -1; // hash algorithm could not be identified from hashLen + + // Make sure the key is large enough to sign this hash + GS_ASSERT(hashLen + anOidLen + aReservedLength <= aKeyByteLength); + if (hashLen + anOidLen + aReservedLength > aKeyByteLength) + return -2; // key is too small or hash is too large + + // fill in header bytes + writeBuf[0] = 0x00; + writeBuf[1] = 0x01; + + // pad with 0xFF + memset(&writeBuf[2], 0xFF, aKeyByteLength - hashLen - anOidLen - aReservedLength); + + // set a 0x00 at the end of the 0xFF pad + writeBuf[aKeyByteLength - hashLen - anOidLen - 1] = 0x00; + + // copy in the oid + if (hashLen == GS_CRYPT_MD5_HASHSIZE) + memcpy(&writeBuf[aKeyByteLength-hashLen-anOidLen], md5Header, sizeof(md5Header)); + else if (hashLen == GS_CRYPT_SHA1_HASHSIZE) + memcpy(&writeBuf[aKeyByteLength-hashLen-anOidLen], sha1Header, sizeof(sha1Header)); + else + return -1; // should probably assert here + + // copy in the hash + memcpy(&writeBuf[aKeyByteLength-hashLen], hash, hashLen); + + // fix byte order for large int + dataToSign.mLength = privateKey->modulus.mLength; + gsLargeIntReverseBytes(&dataToSign); + + // sign (a.k.a. encrypt) + gsLargeIntPowerMod(&dataToSign, &privateKey->exponent, &privateKey->modulus, &dataToSign); + + // length of output data is always the length of the private key's modulus + GS_ASSERT(dataToSign.mLength == privateKey->modulus.mLength); + gsLargeIntReverseBytes(&dataToSign); // switch back to rawbuffer byte order + memcpy(signedDataOut, dataToSign.mData, aKeyByteLength); + *lenOut = aKeyByteLength; + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// "data" is the text that was signed, encrypted or plaintext +// "sig" is the signature value attached to the msg (BIG-endian) +// Signature format: +// [ 0x00 0x01 0xFF ... 0x00 HashHeader Hash(Data) ] +gsi_i32 gsCryptRSAVerifySignedHash(const gsCryptRSAKey *publicKey, const unsigned char *hash, gsi_u32 hashLen, const unsigned char *sig, gsi_u32 sigLen) +{ + gsLargeInt_t lintRSASignature; + gsi_u8* packet = (gsi_u8*)lintRSASignature.mData; + int i=0; + + // Microsoft PKCS #1 headers for various hash algorithms. + gsi_u8 md5Header[18] = {0x30,0x20,0x30,0x0C,0x06,0x08,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05,0x05,0x00,0x04,0x10}; + gsi_u8 sha1Header[15] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; + + // check parameters for common errors + if (hash==NULL || sig==NULL) + return -1; + if (sigLen != publicKey->modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES) + return -1; + if (hashLen != GS_CRYPT_MD5_HASHSIZE && hashLen != GS_CRYPT_SHA1_HASHSIZE) + return -1; // invalid hashsize + + // "decrypt" the signature + lintRSASignature.mLength = (l_word)(sigLen / GS_LARGEINT_DIGIT_SIZE_BYTES); + memcpy(lintRSASignature.mData, sig, sigLen); + gsLargeIntReverseBytes(&lintRSASignature); + gsLargeIntPowerMod(&lintRSASignature, &publicKey->exponent, &publicKey->modulus, &lintRSASignature); + gsLargeIntReverseBytes(&lintRSASignature); + + // Check format, first by 0x00, second byte 0x01 + if (packet[0] != 0x00 || packet[1] != 0x01) + return -2; + + // Loop through the 0xFF's + for (i=2; i +//#include + + +// THIS FILE ONLY INCLUDED WHEN USING GAMESPY DEBUG FUNCTIONS +// (don't put this above the header includes or VC will whine +#ifdef GSI_COMMON_DEBUG + +#if defined(_NITRO) +#include "../../common/nitro/screen.h" +#define printf Printf +#define vprintf VPrintf +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Static debug data +static struct GSIDebugInstance gGSIDebugInstance; // simple singleton "class" + +// Line prefixes, e.g. "[ cat][type][ lev] text" +char* gGSIDebugCatStrings[GSIDebugCat_Count] = +{ + " APP", " GP ", "PEER", " QR2", " SB", " V2", " AD", " NN", "HTTP", "CDKY", " CMN" +}; +char* gGSIDebugTypeStrings[GSIDebugType_Count] = +{ + " NET", "FILE", " MEM", "STAT", "MISC" +}; +char* gGSIDebugLevelStrings[GSIDebugLevel_Count] = +{ + "*ERR", "****", "----", " ", " ", " ", " ->" +}; +char* gGSIDebugLevelDescriptionStrings[8] = +{ + "None", "", "", "", "", "", "", "" +}; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// utility to convert bit flag back to base (e.g. 1<<2 returns 2) +static gsi_u32 gsiDebugLog2(gsi_u32 theInt) +{ + gsi_u32 total = 0; + while (theInt > 1) + { + theInt = theInt >> 1; + total++; + } + return total; +} + + +// default supplied debug function, will receive debug text +// this is platform specific +static void gsiDebugCallback(GSIDebugCategory category, GSIDebugType type, + GSIDebugLevel level, const char * format, va_list params) +{ + #if defined(_PSP) + // Output line prefix + vprintf(format, params); + //gsDebugTTyPrint(string); + #elif defined(_PS2) + // Output line prefix + vprintf(format, params); + + #elif defined(_PS3) + // Output line prefix + vprintf(format, params); + + #elif defined(_WIN32) + static char string[256]; + vsprintf(string, format, params); + OutputDebugStringA(string); + + #elif defined(_LINUX) || defined(_MACOSX) + //static char string[256]; + //vsprintf(string, format, params); + vprintf(format, params); + #elif defined(_NITRO) + VPrintf(format, params); + #elif defined(_REVOLUTION) + static char string[256]; + vsprintf(string, format, params); + OSReport(string); + #else + va_list argptr; + static char string[256]; + va_start(argptr, format); + vsprintf(string, format, argptr); + va_end(argptr); + gsDebugTTyPrint(string); + #endif + + GSI_UNUSED(category); + GSI_UNUSED(type); + GSI_UNUSED(level); +} + + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// process debug output +void gsDebugVaList(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char* theTokenStr, + va_list theParamList) +{ + // Retrieve the current debug level + GSIDebugLevel aCurLevel; + + // Verify Parameters + assert(theCat <= GSIDebugCat_Count); + assert(theType <= GSIDebugType_Count); + assert(theLevel <= (1< 0) + { + gsi_i32 aBytesToRead = min(aBytesLeft, 16); + + HexEncode16(aReadPos, aHexStr, (unsigned int)aBytesToRead); + gsDebugFormat(theCat, theType, theLevel, " %s\r\n", aHexStr); + + aReadPos += aBytesToRead; + aBytesLeft -= aBytesToRead; + }; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsSetDebugLevel(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel) +{ + // Verify Parameters + assert(theCat <= GSIDebugCat_Count); + assert(theType <= GSIDebugType_Count); + + // Set for all categories? + if (theCat == GSIDebugCat_Count) + { + int i=0; + for (; i + +#if defined(__LANGUAGE_C_PLUS_PLUS)||defined(__cplusplus)||defined(c_plusplus) +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Input levels (text is reported at one of these levels) +typedef gsi_u8 GSIDebugLevel; +#define GSIDebugLevel_HotError (GSIDebugLevel)(1<<0) // 1 Unexpected Error +#define GSIDebugLevel_WarmError (GSIDebugLevel)(1<<1) // 2 Expected Error +#define GSIDebugLevel_Warning (GSIDebugLevel)(1<<2) // 4 Warnings and Errors +#define GSIDebugLevel_Notice (GSIDebugLevel)(1<<3) // 8 Usefull debug info +#define GSIDebugLevel_Comment (GSIDebugLevel)(1<<4) // 16 Debug spam +#define GSIDebugLevel_RawDump (GSIDebugLevel)(1<<5) // 32 e.g. MemoryBuffer +#define GSIDebugLevel_StackTrace (GSIDebugLevel)(1<<6) // 64 Important function entries +// add new ones here (update string table in gsiDebug.c!) +#define GSIDebugLevel_Count 7 // 7 reporting levels + +// Output levels (a mask for the levels you want to receive) +// (update string table in gsiDebug.c!) +#define GSIDebugLevel_None (GSIDebugLevel)(0) // No output +#define GSIDebugLevel_Normal (GSIDebugLevel)(0x07) // Warnings and above +#define GSIDebugLevel_Debug (GSIDebugLevel)(0x0F) // Notice and above +#define GSIDebugLevel_Verbose (GSIDebugLevel)(0x1F) // Comment and above +#define GSIDebugLevel_Hardcore (GSIDebugLevel)(0xFF) // Recv all + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Output types +typedef enum +{ + GSIDebugType_Network, // Network activity + GSIDebugType_File, // File output + GSIDebugType_Memory, // Memory allocations + GSIDebugType_State, // State update + GSIDebugType_Misc, // None of the above + // add new ones here (update string table in gsiDebug.c!) + + GSIDebugType_Count, + GSIDebugType_All = GSIDebugType_Count +} GSIDebugType; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Debug categories (SDKs) +typedef enum +{ + GSIDebugCat_App, + GSIDebugCat_GP, + GSIDebugCat_Peer, + GSIDebugCat_QR2, + GSIDebugCat_SB, + GSIDebugCat_Voice, + GSIDebugCat_AD, + GSIDebugCat_NatNeg, + GSIDebugCat_HTTP, + GSIDebugCat_CDKey, + // Add new ones here (update string table in gsiDebug.c!) + + + GSIDebugCat_Common, // Common should be last to prevent display weirdness + // resulting from initialization order + GSIDebugCat_Count, + GSIDebugCat_All = GSIDebugCat_Count +} GSIDebugCategory; + +extern char* gGSIDebugCatStrings[GSIDebugCat_Count]; +extern char* gGSIDebugTypeStrings[GSIDebugType_Count]; +extern char* gGSIDebugLevelStrings[GSIDebugLevel_Count]; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Only include static data and functions if GSI_COMMON_DEBUG is defined +#ifndef GSI_COMMON_DEBUG + // not using GSI debug! Define functions to + // (put these here so VisualAssist will resolve the definitions below) + #if !defined(_WIN32) && !defined(__MWERKS__) + // WIN32 doesn't like "..." in a macro + #define gsDebugFormat(c,t,l,f,...) + #define gsDebugVaList(c,t,l,f,v) + #define gsDebugBinary(c,t,l,b,n) + #define gsSetDebugLevel(c,t,l) + #define gsSetDebugFile(f) + #define gsOpenDebugFile(f) + #define gsGetDebugFile + #define gsSetDebugCallback(c) + #elif defined(_NITRO) + #define gsDebugFormat(...) + #define gsDebugVaList(c,t,l,f,v) + #define gsDebugBinary(c,t,l,b,n) + #define gsSetDebugLevel(c,t,l) + #define gsSetDebugFile(f) + #define gsOpenDebugFile(f) + #define gsGetDebugFile + #define gsSetDebugCallback(c) + #else + #define gsDebugFormat + #define gsDebugVaList + #define gsDebugBinary + #define gsSetDebugLevel + #define gsSetDebugFile + #define gsOpenDebugFile + #define gsGetDebugFile + #define gsSetDebugCallback + #endif +#else + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// User supplied debug function, will receive debug text +typedef void (*GSIDebugCallback)(GSIDebugCategory,GSIDebugType,GSIDebugLevel, + const char*, va_list); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Global debug instance +typedef struct GSIDebugInstance +{ +#if !defined(_NITRO) + FILE* mGSIDebugFile; +#endif + GSIDebugCallback mDebugCallback; + gsi_i32 mInitialized; + +#if !defined(GSI_NO_THREADS) + GSICriticalSection mDebugCrit; +#endif + + GSIDebugLevel mGSIDebugLevel[GSIDebugCat_Count][GSIDebugType_Count]; +} GSIDebugInstance; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Logging functions +void gsDebugFormat(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char* theTokenStr, ...); + +void gsDebugVaList(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char* theTokenStr, + va_list theParams); + +void gsDebugBinary(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char* theBuffer, gsi_i32 theLength); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Output functions +void gsSetDebugLevel(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel); + +#if !defined(_NITRO) + +// Set the output file (NULL for no file) +void gsSetDebugFile(FILE* theFile); + +// Open and set the debug file +FILE* gsOpenDebugFile(const char* theFileName); + +// Retrieve the debug file +FILE* gsGetDebugFile(); + +#endif + +// Set a callback to be triggered with debug output +void gsSetDebugCallback(GSIDebugCallback theCallback); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // GSI_COMMON_DEBUG + +#if defined(__LANGUAGE_C_PLUS_PLUS)||defined(__cplusplus)||defined(c_plusplus) +} +#endif + +#endif // __GSIDEBUG_H__ diff --git a/xrGameSpy/gamespy/common/gsLargeInt.c b/xrGameSpy/gamespy/common/gsLargeInt.c new file mode 100644 index 00000000000..9b778eae96c --- /dev/null +++ b/xrGameSpy/gamespy/common/gsLargeInt.c @@ -0,0 +1,1904 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsLargeInt.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Many parameters are gsi_u32* instead of gsLargeInt_t*. +// This was done to allow easy conversion of databuffer to gsLargeInt_t +// Raw buffer destinations must have enough space to store the result +static gsi_bool gsiLargeIntPrint(FILE* logFile, const l_word *data, l_word length); +static gsi_bool gsiLargeIntResize(gsLargeInt_t *lint, l_word length); +static gsi_bool gsiLargeIntStripLeadingZeroes(gsLargeInt_t* lint); +static gsi_bool gsiLargeIntSizePower2(const gsLargeInt_t *src1, const gsLargeInt_t *src2, l_word *lenout); +static gsi_i32 gsiLargeIntCompare(const l_word *data1, l_word len1, const l_word *data2, l_word len2); + +static gsi_bool gsiLargeIntKMult(const l_word *data1, const l_word *data2, l_word length, l_word *dest, l_word *lenout, l_word maxlen); +static gsi_bool gsiLargeIntMult (const l_word *data1, l_word length1, const l_word *data2, l_word length2, l_word *dest, l_word *lenout, l_word maxlen); +static gsi_bool gsiLargeIntDiv (const l_word *src1, l_word length1, const gsLargeInt_t *divisor, gsLargeInt_t *dest, gsLargeInt_t *remainder); + +// Dest may be data1 or data2 to support in-place arithmetic +static gsi_bool gsiLargeIntAdd (const l_word *data1, l_word length1, const l_word *data2, l_word length2, l_word *dest, l_word *lenout, l_word maxlen); +static gsi_bool gsiLargeIntSub (const l_word *amount, l_word length1, const l_word *from, l_word length2, l_word *dest, l_word *lenout); + +// Special division, removes divisor directly from src1, leaving remainder +static gsi_bool gsiLargeIntSubDivide(l_word *src1, l_word length, const l_word *divisor, l_word dlen, gsi_u32 highbit, l_word *quotient); + +// Montgomery utilities +//gsi_bool gsiLargeIntSquareM(const gsLargeInt_t *src, const gsLargeInt_t *mod, gsi_u32 modPrime, gsi_u32 R, gsLargeInt_t *dest); +//gsi_bool gsiLargeIntMultM(gsLargeInt_t *src1, gsLargeInt_t *src2, const gsLargeInt_t *mod, gsi_u32 modPrime, gsLargeInt_t *dest); +gsi_bool gsiLargeIntMultM(gsLargeInt_t *src1, gsLargeInt_t *src2, const gsLargeInt_t *mod, gsi_u32 modPrime, gsLargeInt_t *dest); +gsi_bool gsiLargeIntInverseMod(const gsLargeInt_t *mod, l_word *modPrimeOut); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + // execution timing/profiling +#define GS_LINT_TIMING +#ifdef GS_LINT_TIMING + +typedef enum +{ + GSLintTimerMult, // "regular" multiplication + GSLintTimerMultM, // montgomery + GSLintTimerKMult, // karatsuba + GSLintTimerAdd, + GSLintTimerSub, // subtract + GSLintTimerDiv, + GSLintTimerSubDivide, // atomic divide + GSLintTimerSquareMod, + GSLintTimerPowerMod, // modular exponentiation + + GSLintTimerCount +} GSLintTimerID; + +typedef struct GSLintTimer +{ + gsi_time started; + gsi_time total; + gsi_u32 entries; + gsi_u32 running; // already entered? +} GSLintTimer; +static struct GSLintTimer gTimers[GSLintTimerCount]; + +static void gsiLargeIntTimerEnter(GSLintTimerID id) +{ + if (gTimers[id].running==0) + { + gTimers[id].entries++; + gTimers[id].started = current_time_hires(); + gTimers[id].running = 1; + } +} +static void gsiLargeIntTimerExit(GSLintTimerID id) +{ + if (gTimers[id].running==1) + { + gTimers[id].total += current_time_hires()-gTimers[id].started; + gTimers[id].running = 0; + } +} + +#define GSLINT_ENTERTIMER(id) gsiLargeIntTimerEnter(id) +#define GSLINT_EXITTIMER(id) gsiLargeIntTimerExit(id) + +#else +#define GSLINT_ENTERTIMER(id) +#define GSLINT_EXITTIMER(id) +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsLargeIntSetValue(gsLargeInt_t *lint, l_word value) +{ + lint->mLength = 1; + lint->mData[0] = value; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Resize by: +// Padding a GSLINT with leading zeroes. +// or stripping lead zeroes. +// This function will not strip digits other than zero. +gsi_bool gsiLargeIntResize(gsLargeInt_t *lint, l_word length) +{ + if (length > GS_LARGEINT_MAX_DIGITS) + return gsi_false; + + // strip leading zeroes until length is reached + if (lint->mLength >= length) + { + while(lint->mLength > length && lint->mData[lint->mLength-1]==0) + lint->mLength--; // check each digit to make sure it's zero + if (lint->mLength == length) + return gsi_true; + else + return gsi_false; + } + + // otherwise, add zeroes until length is reached + else + { + memset(&lint->mData[lint->mLength], 0, (length-lint->mLength)*sizeof(l_word)); + lint->mLength = length; + return gsi_true; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Makes two GSLINT the same size, the size being a power of 2 +// NOTE: Testing next multiple of two, not power of 2 +gsi_bool gsiLargeIntSizePower2(const gsLargeInt_t *src1, const gsLargeInt_t *src2, l_word *lenout) +{ + unsigned int i = 0; + + int len1 = (int)src1->mLength; + int len2 = (int)src2->mLength; + + // strip leading zeroes + while(len1>0 && src1->mData[len1-1] == 0) + len1--; + while(len2>0 && src2->mData[len2-1] == 0) + len2--; + + // set to longer length + *lenout = (l_word)max(len1, len2); + + // search for power of two >= length + // (this length is in digits, not bits) + i=1; + while(i < *lenout) + i = i<<1; + *lenout = (l_word)i; + + if (*lenout > GS_LARGEINT_MAX_DIGITS) + return gsi_false; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Compare two integers +// -1 = data1 < data2 +// 0 = data1 = data2 +// 1 = data1 > data2 +static gsi_i32 gsiLargeIntCompare(const l_word *data1, l_word len1, const l_word *data2, l_word len2) +{ + // skip leading whitespace, if any + while(data1[len1-1] == 0 && len1>0) + len1--; + while(data2[len2-1] == 0 && len2>0) + len2--; + if (len1len2) + return 1; + else + { + // same size, compare digits + while(len1 > 0) + { + if (data1[len1-1] < data2[len1-1]) + return -1; + else if (data1[len1-1] > data2[len1-1]) + return 1; + len1--; + } + } + return 0; // equal! +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiLargeIntStripLeadingZeroes(gsLargeInt_t* lint) +{ + while(lint->mLength >0 && lint->mData[lint->mLength-1]==0) + lint->mLength--; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Addition may cause overflow +gsi_bool gsLargeIntAdd(const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest) +{ + gsi_bool result = gsiLargeIntAdd(src1->mData, src1->mLength, src2->mData, src2->mLength, dest->mData, &dest->mLength, GS_LARGEINT_MAX_DIGITS); + if (gsi_is_false(result)) + memset(dest, 0, sizeof(gsLargeInt_t)); // overflow + return result; +} + +// len: In value = maxsize +// Out value = actual size +static gsi_bool gsiLargeIntAdd(const l_word *data1, l_word length1, const l_word *data2, l_word length2, l_word *dest, l_word *lenout, l_word maxlen) +{ + gsi_u32 i=0; + l_dword carry = 0; // to hold overflow + + gsi_u32 shorterLen = 0; + gsi_u32 longerLen = 0; + //const gsi_u32 *shorterSrc = NULL; + const l_word *longerSrc = NULL; + + GSLINT_ENTERTIMER(GSLintTimerAdd); + + if (maxlen < length1 || maxlen < length2) + return gsi_false; // dest not large enough, OVERFLOW + + if (length1 < length2) + { + shorterLen = length1; + //shorterSrc = data1; + longerLen = length2; + longerSrc = data2; + } + else + { + shorterLen = length2; + //shorterSrc = data2; + longerLen = length1; + longerSrc = data1; + } + + // Add digits until the shorterSrc's length is reached + while(i < shorterLen) + { + carry += (l_dword)data1[i] + data2[i]; + dest[i] = (l_word)carry; + carry = carry >> GS_LARGEINT_DIGIT_SIZE_BITS; //32; + i++; + } + + // Continue adding until carry is zero + while((carry > 0) && (i < longerLen)) + { + carry += (l_dword)longerSrc[i]; + dest[i] = (l_word)carry; + carry = carry >> GS_LARGEINT_DIGIT_SIZE_BITS; //32; + i++; + } + + // Is there still a carry? + // do not perform length check here, so that we can support oversized buffers + if (carry > 0) // && i < GS_LARGEINT_INT_SIZE) + { + if (maxlen <= i) + return gsi_false; // OVERFLOW, no room for extra digit + dest[i++] = (l_word)carry; + carry = 0; + } + + // Copy the rest of the bytes straight over (careful of memory overlap) + // this can't happen if there was a carry (see above carry>0 check) + if (i < longerLen) + { + // check overlap + if (&dest[i] != &longerSrc[i]) + memcpy(&dest[i], &longerSrc[i], (longerLen-i)*sizeof(l_word)); + i = longerLen; + } + *lenout = (l_word)i; + + GSLINT_EXITTIMER(GSLintTimerAdd); + + if (carry) + return gsi_false; // overflow + else + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Subtraction may cause underflow +// subtracts src1 FROM src2 +// strips leading zeroes (gsiLargeIntSub doesn't strip for compatability with karatsuba fixed size numbers) +gsi_bool gsLargeIntSub(const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest) +{ + gsi_bool result = gsiLargeIntSub(src1->mData, src1->mLength, src2->mData, src2->mLength, dest->mData, &dest->mLength); + if (gsi_is_true(result)) + gsiLargeIntStripLeadingZeroes(dest); + return result; +} + +gsi_bool gsiLargeIntSub(const l_word *src1, l_word length1, const l_word *src2, l_word length2, l_word *dest, l_word *lenout) +{ + l_dword borrow = 0; // to hold overflow + gsi_u32 shorterLen = min(length1, length2); + gsi_u32 i=0; + + GSLINT_ENTERTIMER(GSLintTimerSub); + + //printf("--From: "); + //gsiLargeIntPrint(src2, length2); + //printf("--Subtracting: "); + //gsiLargeIntPrint(src1, length1); + + // Subtract digits + while(i < shorterLen) + { + borrow = (l_dword)src2[i] - src1[i] - borrow; + dest[i] = (l_word)borrow; + borrow = borrow>>63; // shift to last bit. This will be 1 if negative, 0 if positive + i++; + } + while(i < length2) + { + borrow = (l_dword)src2[i]-borrow; + dest[i] = (l_word)borrow; + borrow = borrow>>63; + i++; + } + + // check for underflow + if (borrow != 0) + { + GSLINT_EXITTIMER(GSLintTimerSub); + return gsi_false; + } + while(length1 > i) // make sure remaining digits are only leading zeroes + { + if (src1[i] != 0) + { + GSLINT_EXITTIMER(GSLintTimerSub); + return gsi_false; + } + i++; + } + + // Don't reduce length from subtraction, instead keep leading zeroes + // (do this for ease of use with Karatsuba which requires Power2 length) + *lenout = length2; + + GSLINT_EXITTIMER(GSLintTimerSub); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Multiply using normal method (use KMult when working with LargeInt*LargeInt) +gsi_bool gsLargeIntMult(const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest) +{ + gsi_bool result = gsiLargeIntMult(src1->mData, src1->mLength, src2->mData, src2->mLength, dest->mData, &dest->mLength, GS_LARGEINT_MAX_DIGITS); + if (gsi_is_false(result)) + memset(dest, 0, sizeof(gsLargeInt_t)); // overflow + return result; +} + +static gsi_bool gsiLargeIntMult(const l_word *data1, l_word length1, const l_word *data2, l_word length2, l_word *dest, l_word *lenout, l_word maxlen) +{ + unsigned int i=0; + unsigned int k=0; + + gsLargeInt_t temp; + memset(&temp, 0, sizeof(temp)); + *lenout = 0; + + GSLINT_ENTERTIMER(GSLintTimerMult); + + for(i=0; i= maxlen) + { + GSLINT_EXITTIMER(GSLintTimerMult); + return gsi_false; // overflow + } + while(carry) + { + carry += temp.mData[digit]; + temp.mData[digit] = (l_word)carry; + carry = carry >> GS_LARGEINT_DIGIT_SIZE_BITS; + digit++; + if ((digit > maxlen) || + (digit == maxlen && carry>0)) + { + GSLINT_EXITTIMER(GSLintTimerMult); + return gsi_false; // overflow + } + } + if (digit > (gsi_i32)temp.mLength) + temp.mLength = (l_word)digit; + } + } + } + // copy into destination (calculate length at this time) + while(temp.mLength>0 && temp.mData[temp.mLength-1] == 0) + temp.mLength--; // strip leading zeroes + *lenout = temp.mLength; + memcpy(dest, temp.mData, (*lenout)*sizeof(l_word)); + + GSLINT_EXITTIMER(GSLintTimerMult); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// divide src1 by divisor +gsi_bool gsLargeIntDiv(const gsLargeInt_t *src1, const gsLargeInt_t *divisor, gsLargeInt_t *dest, gsLargeInt_t *remainder) +{ + // call the free-buffer version + return gsiLargeIntDiv(src1->mData, src1->mLength, divisor, dest, remainder); +} + +// length1 can be, at most, 2*GS_LARGEINT_INT_SIZE +static gsi_bool gsiLargeIntDiv(const l_word *src, l_word len, const gsLargeInt_t *div, gsLargeInt_t *dest, gsLargeInt_t *remainder) +{ + gsi_i32 result = 0; // temp, to store compare result + gsi_i32 divisorHighBit = GS_LARGEINT_DIGIT_SIZE_BITS-1; // pre-calculate this + + // Bytes used from src1 + int readIndex = 0; + int readLength = 0; + + // setup scratch copies + gsLargeInt_t quotient; + + l_word scopy[GS_LARGEINT_MAX_DIGITS*2]; // we support double length source for division, when dest is null + l_word scopyLen = len; + + const l_word* divisorData = div->mData; + l_word divisorLen = div->mLength; + + gsi_bool endLoop = gsi_false; + + GSLINT_ENTERTIMER(GSLintTimerDiv); + + memset(scopy, 0, sizeof(scopy)); + + // we only support oversized sources for calculating a remainder + // e.g. dest must be null + if (scopyLen > GS_LARGEINT_MAX_DIGITS && dest != NULL) + return gsi_false; + + // strip leading zeroes (from our scratch copies) + while(scopyLen>0 && src[scopyLen-1]==0) + scopyLen--; + while(divisorLen>0 && divisorData[divisorLen-1]==0) + divisorLen--; + + memcpy(scopy, src, scopyLen*sizeof(l_word)); + memset("ient, 0, sizeof(quotient)); + + // check the unusual cases + if (scopyLen==0 || divisorLen==0) + { + if (dest) + { + dest->mData[0] = 0; + dest->mLength = 0; + } + if (remainder) + { + remainder->mData[0] = 0; + remainder->mLength = 0; + } + + GSLINT_EXITTIMER(GSLintTimerDiv); + + if (divisorLen == 0) + return gsi_false; // division by zero + else + return gsi_true; // zero divided, this is legal + } + if (gsiLargeIntCompare(scopy, scopyLen, divisorData, divisorLen)==-1) + { + // divisor is larger than source + if (dest) + { + dest->mLength = 0; + dest->mData[0] = 0; + } + remainder->mLength = scopyLen; + memcpy(remainder->mData, scopy, scopyLen*sizeof(l_word)); + GSLINT_EXITTIMER(GSLintTimerDiv); + return gsi_true; + } + + // calculate the divisor high bit + while((divisorData[divisorLen-1]&(1<<(gsi_u32)divisorHighBit))==0 && divisorHighBit>=0) + divisorHighBit--; + if (divisorHighBit == -1) + { + GSLINT_EXITTIMER(GSLintTimerDiv); + return gsi_false; // divide by zero + } + divisorHighBit += (divisorLen-1)*GS_LARGEINT_DIGIT_SIZE_BITS; + + // position "sliding" window for first interation + // 41529 / [71389]2564 + // WARNING: digits are indexed [2][1][0], first byte to read is index[2] + readIndex = (int)(scopyLen - divisorLen); + readLength = (int)divisorLen; + + //if (readIndex < 0) + // _asm {int 3}; // overflow readIndex + + do + { + result = gsiLargeIntCompare(&scopy[readIndex], (l_word)readLength, divisorData, divisorLen); + if (result == -1) + { + // scopy window is smaller, we'll need an extra digit + if (readIndex > 0) + { + readIndex--; + readLength++; + } + else + { + // no more digits! + endLoop = gsi_true; + } + } + else if (result == 0) + { + // not likely! set digits to zero and slide window + memset(&scopy[readIndex], 0, readLength*sizeof(l_word)); + quotient.mData[readIndex] += 1; + if (quotient.mLength < (l_word)(readIndex+readLength)) + quotient.mLength = (l_word)(readIndex+readLength); + readIndex -= readLength; + readLength = 1; + + if (readIndex < 0) + endLoop = gsi_true;; // no more digits + } + else + { + // subtract directly onto our temp copy, so we don't have to worry about carry values + l_word quotientTemp = 0; + //if (readLength > 0xffff) + // _asm {int 3} + if (gsi_is_false(gsiLargeIntSubDivide(&scopy[readIndex], (l_word)readLength, divisorData, divisorLen, (gsi_u32)divisorHighBit, "ientTemp))) + { + // overflow + GSLINT_EXITTIMER(GSLintTimerDiv); + return gsi_false; + } + quotient.mData[readIndex] = (l_word)(quotient.mData[readIndex] + quotientTemp); + if (quotient.mLength < (l_word)(readIndex+readLength)) + quotient.mLength = (l_word)(readIndex+readLength); + // remove new leading zeroes + while(scopy[readIndex+readLength-1] == 0 && readLength>1) + readLength--; + while(scopy[readIndex+readLength-1] == 0 && readIndex>1) + readIndex--; + } + } + while(gsi_is_false(endLoop)); + + // no more digits, leftover is remainder + if (readIndex >= 0) + { + memcpy(remainder->mData, &scopy[readIndex], readLength*sizeof(l_word)); + remainder->mLength = (l_word)readLength; + } + else + { + remainder->mData[0] = 0; + remainder->mLength = 0; + } + + // save off quotient, if desired + if (dest) + { + memcpy(dest->mData, quotient.mData, quotient.mLength*sizeof(l_word)); + dest->mLength = quotient.mLength; + } + GSLINT_EXITTIMER(GSLintTimerDiv); + return gsi_true; +} + + +// atomic divide. +// Subtract divisor directly from src. +// Leave remainder in src. +static gsi_bool gsiLargeIntSubDivide(l_word *src, l_word length, const l_word *divisor, l_word dlen, + gsi_u32 highbit, l_word *quotient) +{ + l_dword aboveBits = 0; + gsLargeInt_t temp; // stores temporary product before subtraction + gsLargeInt_t quotientCopy; // copy of quotient, length padded for multiplication + + GSLINT_ENTERTIMER(GSLintTimerSubDivide); + // assert(src > divisor) + // assert(src < (MAX_DIGIT_VALUE * divisor)) + //if(dlen==1 && *divisor==0) + // _asm {int 3} // division by zero + + // Q: how many times to subtract? + // A: we estimate by taking the bits in src above the highest bit in divisor + if (length > dlen) + aboveBits = (src[length-2]&divisor[dlen-1]) | ((l_dword)src[length-1]<>GS_LARGEINT_DIGIT_SIZE_BITS); + + // We only support quotients up to MAX_INT + if (quotientCopy.mData[1] != 0) + { + quotientCopy.mData[0] = (l_word)(-1); + quotientCopy.mData[1] = 0; + } + quotientCopy.mLength = 1; + + // multiply this value by divisor, and that's how much to subtract + if (gsi_is_false(gsiLargeIntMult(divisor, dlen, quotientCopy.mData, quotientCopy.mLength, temp.mData, &temp.mLength, GS_LARGEINT_MAX_DIGITS))) + { + GSLINT_EXITTIMER(GSLintTimerSubDivide); + return gsi_false; // overflow + } + + // while subtraction amount is larger than src, reduce it + while(gsiLargeIntCompare(temp.mData, temp.mLength, src, length)==1) + { + // divide by two + quotientCopy.mData[0] = (l_word)(quotientCopy.mData[0]>>1); + //if (quotientCopy.mData[0] == 0) + // _asm {int 3} + if (gsi_is_false(gsiLargeIntMult(divisor, dlen, quotientCopy.mData, quotientCopy.mLength, temp.mData, &temp.mLength, GS_LARGEINT_MAX_DIGITS))) + { + GSLINT_EXITTIMER(GSLintTimerSubDivide); + return gsi_false; // overflow + } + } + //if (gsiLargeIntCompare(temp.mData, temp.mLength, src, length)==1) + // _asm {int 3} // temp > src, subtraction will cause underflow! + + // subtract it + gsiLargeIntSub(temp.mData, temp.mLength, src, length, src, &length); + + *quotient = quotientCopy.mData[0]; + //if (quotientCopy.mData[1] != 0) + // _asm {int 3} + GSLINT_EXITTIMER(GSLintTimerSubDivide); + + GSI_UNUSED(highbit); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Multiply using Karatsuba +// Karatsuba requires that the sizes be equal and a power of two +gsi_bool gsLargeIntKMult(const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest) +{ + l_word len = 0; + gsi_bool result = gsi_false; + + gsLargeInt_t temp; // to prevent issues if (src1 == src2 == dest) + + // quick check for multiplication by 0 + if (src1->mLength == 0 || src2->mLength == 0) + { + dest->mLength = 0; + return gsi_true; + } + + // when length is small it's faster to use "normal" multiplication + if (max(src1->mLength,src2->mLength) < GS_LARGEINT_KARATSUBA_CUTOFF) + return gsLargeIntMult(src1, src2, dest); + + // Check for size/length restrictions + result = gsiLargeIntSizePower2(src1, src2, &len); + if (gsi_is_false(result) || len>(GS_LARGEINT_MAX_DIGITS/2)) + { + // try regular multiplication + return gsLargeIntMult(src1, src2, dest); + } + + // (don't time above section since it defers to Mult) + GSLINT_ENTERTIMER(GSLintTimerKMult); + + // clear the temporary dest + memset(&temp, 0, sizeof(gsLargeInt_t)); + temp.mLength = 0; + + // resize if necessary + if (src1->mLength != len || src2->mLength != len) + { + // size is not correct, make a copy then multiply + gsLargeInt_t src1Copy; + gsLargeInt_t src2Copy; + memcpy(&src1Copy, src1, sizeof(gsLargeInt_t)); + memcpy(&src2Copy, src2, sizeof(gsLargeInt_t)); + gsiLargeIntResize(&src1Copy, len); + gsiLargeIntResize(&src2Copy, len); + + result = gsiLargeIntKMult(src1Copy.mData, src2Copy.mData, len, temp.mData, &temp.mLength, GS_LARGEINT_MAX_DIGITS); + } + else + { + // size is correct, perform multiplication + result = gsiLargeIntKMult(src1->mData, src2->mData, len, temp.mData, &temp.mLength, GS_LARGEINT_MAX_DIGITS); + } + if (gsi_is_true(result)) + { + // strip leading zeroes and copy into dest + gsiLargeIntStripLeadingZeroes(&temp); + memcpy(dest, &temp, sizeof(gsLargeInt_t)); + } + GSLINT_EXITTIMER(GSLintTimerKMult); + return result; +} + + +// Utility for Karasuba +static gsi_bool gsiLargeIntKMult(const l_word *data1, const l_word *data2, l_word length, + l_word *dest, l_word *lenout, l_word maxlen) +{ + // No timer here, this function is only called from GSLINTKMult + //GSLINT_ENTERTIMER(GSLintTimerKMult); + + // "normal" multiplication is faster when length is small + if (length <= GS_LARGEINT_KARATSUBA_CUTOFF) + return gsiLargeIntMult(data1, length, data2, length, dest, lenout, maxlen); + else + { + gsLargeInt_t temp1, temp2, temp3; + l_word halfLen = (l_word)(length>>1); + + temp1.mLength = 0; + temp2.mLength = 0; + temp3.mLength = 0; + + //printf("Karasuba splitting at %d (1/2 = %d)\r\n", length, halfLen); + + // Karatsuba: k = 12*34 + // a = (1*3) + // b = (1+2)*(3+4)-a-c + // c = (2*4) + // k = a*B^N+b*B^(N/2)+c = a*100+b*10+c + + // Enter the recursive portion + // TH = top half + // BH = bottom half + + // Note that since (a*B^N + c) cannot overlap, we can immediately store both in dest + + // Compute a. (TH of data1 * TH of data2) + // Stores in TH of dest, so later *B^N isn't necessary + // For the example, this puts 1*3 into the high half 03xx + gsiLargeIntKMult(&data1[halfLen], &data2[halfLen], halfLen, &dest[length], lenout, (l_word)(maxlen-length)); + //printf("Calculated A (%d) = ", *lenout); + //gsiLargeIntPrint(&dest[length], *lenout); + + // Compute c. (BH of data1 * BH of data2) + // For the example, this puts 2*4 into the low half xx08 + gsiLargeIntKMult(data1, data2, halfLen, dest, lenout, maxlen); + //printf("Calculated C (%d) = ", *lenout); + //gsiLargeIntPrint(dest, *lenout); + + // Compute b1. (TH of data1 + BH of data1) + gsiLargeIntAdd(&data1[halfLen], halfLen, data1, halfLen, temp1.mData, &temp1.mLength, GS_LARGEINT_MAX_DIGITS); + //printf("Calculated B1 (%d) = ", temp1.mLength); + //gsiLargeIntPrint(temp1.mData, temp1.mLength); + + // Compute b2. (TH of data2 + BH of data2) + gsiLargeIntAdd(&data2[halfLen], halfLen, data2, halfLen, temp2.mData, &temp2.mLength, GS_LARGEINT_MAX_DIGITS); + //printf("Calculated B2 (%d) = ", temp2.mLength); + //gsiLargeIntPrint(temp2.mData, temp2.mLength); + + // Compute b3. (b1*b2) (*B^N) + // For the example, (1+2)(3+4)*B^N = 21*B^N = 0210 + memset(&temp3, 0, sizeof(gsLargeInt_t)); + + // May require resizing, but don't go above halfLen + if (temp1.mLength > halfLen || temp2.mLength > halfLen) + gsiLargeIntMult(temp1.mData, temp1.mLength, temp2.mData, temp2.mLength, &temp3.mData[halfLen], &temp3.mLength, (l_word)(GS_LARGEINT_MAX_DIGITS-halfLen)); + else + { + gsi_bool result = gsiLargeIntSizePower2(&temp1, &temp2, lenout); + if (gsi_is_false(result)) + return gsi_false; // could not resize + gsiLargeIntResize(&temp1, *lenout); // pad to new size + gsiLargeIntResize(&temp2, *lenout); // pad to new size + gsiLargeIntKMult(temp1.mData, temp2.mData, *lenout, &temp3.mData[halfLen], &temp3.mLength, (l_word)(GS_LARGEINT_MAX_DIGITS-halfLen)); + } + temp3.mLength = (l_word)(temp3.mLength + halfLen); // fix length for temp3 + //if (temp3.mLength > GS_LARGEINT_INT_SIZE) + // _asm {int 3} // this should be at most temp1.mLength+temp2.mLength + memset(temp3.mData, 0, halfLen*sizeof(l_word)); + //printf("Calculated B3 (%d) = ", temp3.mLength); + //gsiLargeIntPrint(&temp3.mData[halfLen], temp3.mLength-halfLen); + + // Compute final b. (b3-a-c) (*B^N) + // Note: The subtraction is in terms of (*B^N) + // For the example, 021x - 03x - 08x = 0100 + gsiLargeIntSub(&dest[length], length, &temp3.mData[halfLen], (l_word)(temp3.mLength-halfLen), &temp3.mData[halfLen], &temp3.mLength); + temp3.mLength = (l_word)(temp3.mLength + halfLen); + gsiLargeIntSub( dest , length, &temp3.mData[halfLen], (l_word)(temp3.mLength-halfLen), &temp3.mData[halfLen], &temp3.mLength); + temp3.mLength = (l_word)(temp3.mLength + halfLen); + //printf("Calculated B (%d) = ", temp3.mLength); + //gsiLargeIntPrint(temp3.mData, temp3.mLength); + + // Add em up + // Dest already contains A+C, so Add B + // For the example, 0308 + 0100 = 0408 (the correct answer) + gsiLargeIntAdd(dest, (l_word)(length*2), temp3.mData, temp3.mLength, dest, lenout, maxlen); + } + // strip leading zeroes from dest + while(*lenout > 0 && dest[*lenout-1] == 0) + *lenout = (l_word)(*lenout-1); + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsLargeIntSquareMod(const gsLargeInt_t *lint, const gsLargeInt_t *mod, gsLargeInt_t *dest) +{ + int i = 0; + int k = 0; + int len = (int)lint->mLength; // signed version + l_dword carry = 0; + int oldShiftBit = 0; + int newShiftBit = 0; + gsi_bool result = gsi_false; + unsigned int mask = (unsigned int)1<<(GS_LARGEINT_DIGIT_SIZE_BITS-1); + + l_word squareSums[GS_LARGEINT_MAX_DIGITS*2]; // temp dest for square sums + l_word otherSums[GS_LARGEINT_MAX_DIGITS*2]; // temp dest for other sums + l_word squareLen = 0; + l_word otherLen = 0; + + GSLINT_ENTERTIMER(GSLintTimerSquareMod); + + memset(&squareSums, 0, sizeof(squareSums)); + memset(&otherSums, 0, sizeof(otherSums)); + + // Go through each digit, multiplying with each other digit + // (only do this once per pair, since AB == BA) + // Ex: ABC * ABC, we want AB,AC,BC only + for (i=1; i < len; i++) + { + for(k=0; k < i; k++) + { + carry += (l_dword)lint->mData[i]*lint->mData[k] + otherSums[i+k]; + otherSums[i+k] = (l_word)carry; + carry = carry >> GS_LARGEINT_DIGIT_SIZE_BITS; + } + if(carry) + { + otherSums[i+k] = (l_word)carry; + carry = carry >> GS_LARGEINT_DIGIT_SIZE_BITS; + } + } + + // Multiply by 2 (because each internal pair appears twice) + for (i=0; i < (2*len); i++) + { + newShiftBit = (otherSums[i] & mask)==mask?1:0; // calc next carry 1 or 0 + otherSums[i] = (l_word)((otherSums[i] << 1) + oldShiftBit); // do the shift + oldShiftBit = newShiftBit; + } + // don't worry about left-overy carry because this can't overflow + // maxlen N-digit*N-digit = 2n-digit + + // Go through each digit, multiplying with itself + for (i=0; i mData[i] * lint->mData[i]; + squareSums[i*2] = (l_word)carry; + squareSums[i*2+1] = (l_word)(carry >> GS_LARGEINT_DIGIT_SIZE_BITS); + } + squareLen = (l_word)(2*len); + otherLen = (l_word)(2*len); + + // Add the two together + result = gsiLargeIntAdd(otherSums, otherLen, squareSums, squareLen, squareSums, &squareLen, GS_LARGEINT_MAX_DIGITS*2); + result = gsiLargeIntDiv(squareSums, squareLen, mod, NULL, dest); + + GSLINT_EXITTIMER(GSLintTimerSquareMod); + return result; +} + +//#define NEWEXP +#ifdef NEWEXP + +//#define printf + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Montgomery exponentiation (see HAC 14.94) +// +// SPECIAL NOTE: +// A small public exponent will reduce the load on client encryption. +// (below 65535 is a security risk, so don't go too small) +gsi_bool gsLargeIntPowerMod(const gsLargeInt_t *b, const gsLargeInt_t *p, const gsLargeInt_t *m, gsLargeInt_t *dest) +{ + gsLargeInt_t base; + gsLargeInt_t power; + gsLargeInt_t mod; + gsLargeInt_t one; + + gsi_u32 expHighBit; // highest bit set in exponent; + + int i = 0; // temp / counter + int k = 0; // binary size of our subdigits + int pow2k = 0; // 2^k + int kmask = 0; // 2^k-1 + int kdigits = 0; // number of k-sized digits in p + //int leadingZeroBits = 0; // to make p evenly divisible by k + + l_word modPrime; + gsLargeInt_t R; // "R" as used in the montgomery exponentiation algorithm. + //gsLargeInt_t Rmod; // R mod n + //gsLargeInt_t R2mod; // R^2 mod n + + gsLargeInt_t * lut = NULL; + + GSLINT_ENTERTIMER(GSLintTimerPowerMod); + + memcpy(&base, b, sizeof(base)); + memcpy(&power, p, sizeof(power)); + memcpy(&mod, m, sizeof(mod)); + memset(&R, 0, sizeof(R)); + + gsLargeIntSetValue(&one, 1); + + // Catch the unusual cases + if (mod.mLength == 0) + { + // mod 0 = undefined + dest->mLength = 0; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + else if (mod.mLength==1 && mod.mData[0]==1) + { + // mod 1 = 0 + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_true; + } + else if (power.mLength == 0) + { + // x^0 = 1 + dest->mLength = 1; + dest->mData[0] = 1; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_true; + } + else if ((mod.mData[0]&1) == 0) + { + // Montgomery only works with odd modulus! + // (rsa modulus is prime1*prime2, which must be odd) + dest->mLength = 0; + dest->mData[0] = 0; + //_asm {int 3} + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + // If base is larger than mod, we can (must) reduce it + if (gsiLargeIntCompare(base.mData, base.mLength, mod.mData, mod.mLength)!=-1) + { + gsLargeIntDiv(&base, &mod, NULL, &base); + } + if (base.mLength == 0) + { + // 0^e = 0 + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_true; + } + + // find the highest bit set in power + expHighBit=GS_LARGEINT_DIGIT_SIZE_BITS; + while(((1<<(expHighBit-1))&power.mData[power.mLength-1]) == 0) + expHighBit--; + expHighBit += ((power.mLength-1) * GS_LARGEINT_DIGIT_SIZE_BITS); // add in 32 bits for each extra byte + + // The previous algorithm used 1-bit digits + // This algorithm uses k-bit digits + // Determine the optimal size for k + k=8; // this will support up to 4096 bit encryption (and probably higher) + while ( (k > 1) && + (gsi_u32)((k - 1) * (k << ((k - 1) << 1)) / ((1 << k) - k - 1)) >= expHighBit - 1 + ) + { + --k; + } + pow2k = 1 << k; + kmask = pow2k-1; + kdigits = (expHighBit+(k-1)) / k; // ceiling(expHighBit/k) + + // calculate "R" (if mod=5678, R=10000 e.g. One digit higher) + memset(&R, 0, sizeof(R)); + R.mLength = (l_word)(mod.mLength+1); + if (R.mLength > GS_LARGEINT_MAX_DIGITS) + return gsi_false; // you need to increase the large int capacity + R.mData[R.mLength-1] = 1; // set first bit one byte higher than mod + + // find the multiplicative inverse of mod + gsiLargeIntInverseMod(&mod, &modPrime); + +/* + // calculate Rmod (R%mod) + if (gsi_is_false(gsLargeIntDiv(&R, &mod, NULL, &Rmod))) + { + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + + // calculate R2mod (R^2%mod = (Rmod*Rmod)%mod) + if (gsi_is_false(gsLargeIntSquareMod(&Rmod, &mod, &R2mod))) + { + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } +*/ + // Allocate space for a table of values that will come up repeatedly + // xwiggle is (br mod n) + // These are the odd powers of xwiggle, x^3, x^5 and so on + // We generate these by repeated multiplications by xwiggle + //if (k >= 3) + { + // no no no[0] = xwiggle^3 (montgomery multiply [2]*[1]) + // no no no[1] = xwiggle^5 (montgomery multiply [2]*[3]) + // no no no[2] = xwiggle^7 (montgomery multiply [2]*[5]) + + // allocate space + // ~1k for typical small RSA public exponents (e.g. 65537) + // ~16k for 1024-bit RSA exponent + // ~32k for 2048-bit RSA exponent + // ~64k for 4096-bit RSA exponent + int i=0; + int valuesNeeded = pow2k;//((pow2k/2)-1); + int spaceneeded = sizeof(gsLargeInt_t) * valuesNeeded; + + lut = (gsLargeInt_t*)gsimalloc(spaceneeded); + if (lut == NULL) + return gsi_false; // out of memory + memset(lut, 0x00, spaceneeded); + + // set first values + // [0] = 1 + // [1] = br mod n (normal multiplication) + // [i] = mont([1] * [i-1]) + gsLargeIntSetValue(&lut[0], 1); + if (gsi_is_false(gsLargeIntMult(&base, &R, &lut[1])) || + gsi_is_false(gsLargeIntDiv(&lut[1], &mod, NULL, &lut[1])) ) + { + gsifree(lut); + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + + // fill in the values + for (i=2; i < valuesNeeded; i++) + { + if (gsi_is_false(gsiLargeIntMultM(&lut[1], &lut[i-1], &mod, modPrime, &lut[i])) ) + { + gsifree(lut); + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + } + } + + // set starting point + if (gsi_is_false(gsLargeIntMult(&base, &R, dest)) || // Normal multiply + gsi_is_false(gsLargeIntDiv(dest, &mod, NULL, dest)) ) // A mod operation + { + gsifree(lut); + return gsi_false; + } + + // loop through the k-sized digits + for (i=0; i < kdigits; i++) + { + int bitReadIndex = expHighBit - (i*k); // index of the bit we're reading + int l_index; // = ((bitReadIndex-1)/GS_LARGEINT_DIGIT_SIZE_BITS); // -1 to use zero based indexes + int l_firstbit; + l_dword twodigits; + l_dword mask; + l_word digitval; + + l_index = ((bitReadIndex-1)/GS_LARGEINT_DIGIT_SIZE_BITS); // -1 to use zero based indexes + + // for first digit, use leading zeroes when necessary + if ((bitReadIndex % k) != 0) + bitReadIndex += k - (bitReadIndex % k); // round up to next k + if (i != 0) + { + if (bitReadIndex - (l_index*GS_LARGEINT_DIGIT_SIZE_BITS)> GS_LARGEINT_DIGIT_SIZE_BITS) + l_index++; + } + + if (i==0) + { + // first digit + l_firstbit = l_index * GS_LARGEINT_DIGIT_SIZE_BITS; // first bit of this digit + twodigits = p->mData[l_index]; + } + else if (l_index > 0) + { + // middle digits + l_firstbit = (l_index-1) * GS_LARGEINT_DIGIT_SIZE_BITS; // first bit of this digit + twodigits = (l_dword)((l_dword)p->mData[l_index] << GS_LARGEINT_DIGIT_SIZE_BITS) | p->mData[l_index-1]; + } + else if (l_index == 0 && p->mLength > 1) + { + // final digit, when there are proceeding digits + l_firstbit = 0; + twodigits = (l_dword)(p->mData[l_index+1] << GS_LARGEINT_DIGIT_SIZE_BITS) | p->mData[l_index]; + } + else + { + // final digit, no proceeding digits + l_firstbit = l_index * GS_LARGEINT_DIGIT_SIZE_BITS; // first bit of this digit + twodigits = p->mData[l_index]; + } + mask = (l_dword)kmask << (bitReadIndex-l_firstbit-k); + digitval = (l_word)((twodigits & mask) >> (bitReadIndex-l_firstbit-k)); + + // use digitval to determine how many squaring and multiplication operations we need to perform + { + static int twotab[] = + {0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; + + + static USHORT oddtab[] = + {0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1, 17, 9, 19, 5, 21, 11, 23, 3, 25, 13, 27, 7, 29, 15, 31, 1, + 33, 17, 35, 9, 37, 19, 39, 5, 41, 21, 43, 11, 45, 23, 47, 3, 49, 25, 51, 13, 53, 27, 55, 7, 57, 29, 59, 15, + 61, 31, 63, 1, 65, 33, 67, 17, 69, 35, 71, 9, 73, 37, 75, 19, 77, 39, 79, 5, 81, 41, 83, 21, 85, 43, 87, 11, + 89, 45, 91, 23, 93, 47, 95, 3, 97, 49, 99, 25, 101, 51, 103, 13, 105, 53, 107, 27, 109, 55, 111, 7, 113, + 57, 115, 29, 117, 59, 119, 15, 121, 61, 123, 31, 125, 63, 127, 1, 129, 65, 131, 33, 133, 67, 135, 17, + 137, 69, 139, 35, 141, 71, 143, 9, 145, 73, 147, 37, 149, 75, 151, 19, 153, 77, 155, 39, 157, 79, 159, + 5, 161, 81, 163, 41, 165, 83, 167, 21, 169, 85, 171, 43, 173, 87, 175, 11, 177, 89, 179, 45, 181, 91, + 183, 23, 185, 93, 187, 47, 189, 95, 191, 3, 193, 97, 195, 49, 197, 99, 199, 25, 201, 101, 203, 51, 205, + 103, 207, 13, 209, 105, 211, 53, 213, 107, 215, 27, 217, 109, 219, 55, 221, 111, 223, 7, 225, 113, + 227, 57, 229, 115, 231, 29, 233, 117, 235, 59, 237, 119, 239, 15, 241, 121, 243, 61, 245, 123, 247, 31, + 249, 125, 251, 63, 253, 127, 255}; + + + //printf("[gsint] Digit %d = %d\r\n", i, digitval); + if (i==0) + { + int counter = 0; + + memcpy(dest, &lut[oddtab[digitval]], sizeof(gsLargeInt_t)); + //printf("[gsint] Set start to %d\r\n", dest->mData[0]); + + for (counter = twotab[digitval]; counter> 0; counter--) + { + if (gsi_is_false(gsiLargeIntMultM(dest,dest, &mod, modPrime, dest))) + { + gsifree(lut); + return gsi_false; + } + //printf("[gsint] First digit, squared to %d\r\n", dest->mData[0]); + } + } + else if (digitval != 0) + { + int counter = 0; + int lutindex = oddtab[digitval]; // we only precalculate the odd powers + //int lutindex = (oddtab[digitval]+1)/2; // we only precalculate the odd powers + + for (counter = (int)(k-twotab[digitval]); counter> 0; counter--) + { + if (gsi_is_false(gsiLargeIntMultM(dest,dest, &mod, modPrime, dest))) + { + gsifree(lut); + return gsi_false; + } + //printf("[gsint] Squared to %d\r\n", dest->mData[0]); + } + + if (gsi_is_false(gsiLargeIntMultM(dest, &lut[lutindex], &mod, modPrime, dest))) + { + gsifree(lut); + return gsi_false; + } + //printf("[gsint] Mult by [%d](%d) to %d\r\n", lutindex, lut[lutindex].mData[0], dest->mData[0]); + for (counter = twotab[digitval]; counter> 0; counter--) + { + if (gsi_is_false(gsiLargeIntMultM(dest,dest, &mod, modPrime, dest))) + { + gsifree(lut); + return gsi_false; + } + //printf("[gsint] Squared to %d\r\n", dest->mData[0]); + } + } + else + { + int counter = 0; + for (counter = k; counter > 0; counter--) + { + if (gsi_is_false(gsiLargeIntMultM(dest,dest, &mod, modPrime, dest))) + { + gsifree(lut); + return gsi_false; + } + //printf("[gsint] Squared to %d\r\n", dest->mData[0]); + } + } + } + } + + // normalize (MultM by 1) + if (gsi_is_false(gsiLargeIntMultM(dest, &one, &mod, modPrime, dest))) + return gsi_false; + + gsifree(lut); + return gsi_true; +} + +#else + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Montgomery exponentiation (see HAC 14.94) +// +// SPECIAL NOTE: +// A small public exponent will reduce the load on client encryption. +// (below 65535 is a security risk, so don't go too small) +gsi_bool gsLargeIntPowerMod(const gsLargeInt_t *b, const gsLargeInt_t *p, const gsLargeInt_t *m, gsLargeInt_t *dest) +{ + int i=0; // temp/counter + int digitNum=0; // temp/counter + int digitBit=0; + + l_word modPrime; + + gsi_u32 expHighBit; // highest bit set in exponent; + + gsLargeInt_t R; // "R" as used in the montgomery exponentiation algorithm. + gsLargeInt_t Rmod; // R%mod + gsLargeInt_t R2mod; // R^2%mod + gsLargeInt_t temp; + gsLargeInt_t xwiggle; // montgomery mult of (x,R2mod) + + gsLargeInt_t base; + gsLargeInt_t power; + gsLargeInt_t mod; + + GSLINT_ENTERTIMER(GSLintTimerPowerMod); + + memset(&R, 0, sizeof(R)); + memset(&Rmod, 0, sizeof(Rmod)); + memset(&R2mod, 0, sizeof(R2mod)); + memset(&temp, 0, sizeof(temp)); + memset(&xwiggle, 0, sizeof(xwiggle)); + + memcpy(&base, b, sizeof(base)); + memcpy(&power, p, sizeof(power)); + memcpy(&mod, m, sizeof(mod)); + + gsiLargeIntStripLeadingZeroes(&base); + gsiLargeIntStripLeadingZeroes(&power); + gsiLargeIntStripLeadingZeroes(&mod); + + // Catch the unusual cases + if (mod.mLength == 0) + { + // mod 0 = undefined + dest->mLength = 0; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + else if (mod.mLength==1 && mod.mData[0]==1) + { + // mod 1 = 0 + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_true; + } + else if (power.mLength == 0) + { + // x^0 = 1 + dest->mLength = 1; + dest->mData[0] = 1; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_true; + } + else if ((mod.mData[0]&1) == 0) + { + // Montgomery only works with odd modulus! + // (rsa modulus is prime1*prime2, which must be odd) + dest->mLength = 0; + dest->mData[0] = 0; + //_asm {int 3} + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + // If base is larger than mod, we can (must) reduce it + if (gsiLargeIntCompare(base.mData, base.mLength, mod.mData, mod.mLength)!=-1) + { + gsLargeIntDiv(&base, &mod, NULL, &base); + } + if (base.mLength == 0) + { + // 0^e = 0 + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_true; + } + + // find the highest bit set in power + expHighBit=GS_LARGEINT_DIGIT_SIZE_BITS; + while(((1<<(expHighBit-1))&power.mData[power.mLength-1]) == 0) + expHighBit--; + expHighBit += ((power.mLength-1) * GS_LARGEINT_DIGIT_SIZE_BITS); // add in 32 bits for each extra byte + + // On to the tricky tricky! + // 1) We can't compute B^P and later apply the mod; B^P is just too big + // So we have to make modular reductions along the way + // 2) Since modular reduction is essentially a division, we would like + // to use a mod 2^E so that division is just a bit strip. + // ex. (1383 mod 16) = binary(0000010101100111 mod 00010000) = 00000111 = dec 7 + + // Precalculate some values that will come up repeatedly + + // calculate "R" (if mod=5678, R=10000 e.g. One digit higher) + memset(&R, 0, sizeof(R)); + R.mLength = (l_word)(mod.mLength+1); + if (R.mLength > GS_LARGEINT_MAX_DIGITS) + return gsi_false; // you need to increase the large int capacity + R.mData[R.mLength-1] = 1; // set first bit one byte higher than mod + + // find the multiplicative inverse of mod + gsiLargeIntInverseMod(&mod, &modPrime); + + // calculate Rmod (R%mod) + if (gsi_is_false(gsLargeIntDiv(&R, &mod, NULL, &Rmod))) + { + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + + // calculate R2mod (R^2%mod = (Rmod*Rmod)%mod) + if (gsi_is_false(gsLargeIntSquareMod(&Rmod, &mod, &R2mod))) + { + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + + // calculate xwiggle + if (gsi_is_false(gsiLargeIntMultM(&base, &R2mod, &mod, modPrime, &xwiggle))) + { + GSLINT_EXITTIMER(GSLintTimerPowerMod); + return gsi_false; + } + + // loop through the BITS of power + // if the bit is 1, perform a multiplication by xwiggle? (11/2/2006) + // TODO: THIS DOESN'T WORK IF THE HIGHBIT IS EVER ABOVE GS_LARGEINT_DIGIT_SIZE_BITS + memcpy(dest, &Rmod, sizeof(gsLargeInt_t)); // start dest at Rmod + for (i=(int)(expHighBit-1); i>=0; i--) + { + // mont square the current total + gsiLargeIntMultM(dest, dest, &mod, modPrime, dest); + digitNum = (gsi_i32)(i/GS_LARGEINT_DIGIT_SIZE_BITS); // which digit to extract a bit from? + digitBit = (gsi_i32)(i % GS_LARGEINT_DIGIT_SIZE_BITS); // which bit to extract from that digit? + //if ((power.mData[k] & (1<mLength; + + memset(temp, 0, sizeof(temp)); + + if (gsi_is_false(gsiLargeIntMult(x->mData, x->mLength, y->mData, y->mLength, temp, &tempLen, GS_LARGEINT_MAX_DIGITS*2))) + return gsi_false; + + lasttnptr = &temp[m->mLength-1]; + lastnptr = &m->mData[m->mLength-1]; + + if (tempLen < m->mLength*2) + { + memset(&temp[tempLen], 0, (m->mLength*2 - tempLen) * GS_LARGEINT_DIGIT_SIZE_BYTES); + //memset(&temp[tempLen], 0, sizeof(temp) - tempLen * GS_LARGEINT_DIGIT_SIZE_BYTES); // safer to clear out the whole thing? + tempLen = (l_word)(m->mLength*2); + } + + for (tptr = &temp[0]; tptr <= lasttnptr; tptr++) + { + carry = 0; + mi = (l_word)((l_dword)modPrime * (l_dword)*tptr); + tiptr = tptr; + for (nptr = &m->mData[0]; nptr <= lastnptr; nptr++, tiptr++) + { + carry = (l_dword)mi * (l_dword)*nptr + + (l_dword)*tiptr + (l_dword)(l_word)(carry >> GS_LARGEINT_DIGIT_SIZE_BITS); + *tiptr = (l_word)(carry); + } + + // apply the carry value + for (; ((carry >> GS_LARGEINT_DIGIT_SIZE_BITS) > 0) && tiptr <= &temp[tempLen-1]; tiptr++) + { + *tiptr = (l_word)(carry = (l_dword)*tiptr + (l_dword)(l_word)(carry >> GS_LARGEINT_DIGIT_SIZE_BITS)); + } + + // If we still have a carry, increase the length of temp + if (((carry >> GS_LARGEINT_DIGIT_SIZE_BITS) > 0)) + { + *tiptr = (l_word)(carry >> GS_LARGEINT_DIGIT_SIZE_BITS); + tempLen++; + } + } + + // **WARNING** + // Bytes from the plain text message may appear within the temporary buffer. + // These bytes should be cleared to prevent bugs where that data may be exposed. (buffer overrun?) + if (gsiLargeIntCompare(&temp[logB_r], tempLen - logB_r, m->mData, m->mLength) != -1) + { + if (gsi_is_false(gsiLargeIntSub(m->mData, m->mLength, &temp[logB_r], tempLen - logB_r, dest->mData, &dest->mLength))) + { + memset(temp, 0, sizeof(temp)); + memset(dest, 0, sizeof(gsLargeInt_t)); + return gsi_false; + } + } + else + { + memset(dest, 0, sizeof(gsLargeInt_t)); + dest->mLength = m->mLength; + memcpy(dest->mData, &temp[logB_r], (tempLen - logB_r)*GS_LARGEINT_DIGIT_SIZE_BYTES); + memset(temp, 0, sizeof(temp)); + } + + return gsi_true; +} + +#else + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Montgomery multiplication +// Computes (src1*src2*r^-1)%mod +// Note: +// This implementation is based on HAC14.36 which has a lot of room for improvement +// FLINT algorithm runs approx 30 times faster. +gsi_bool gsiLargeIntMultM(gsLargeInt_t *x, gsLargeInt_t *y, const gsLargeInt_t *m, gsi_u32 modPrime, gsLargeInt_t *dest) +{ + int i=0; + l_dword xiy0; + l_word u = 0; + + gsLargeInt_t A; + gsLargeInt_t xiy; + gsLargeInt_t temp; + + GSLINT_ENTERTIMER(GSLintTimerMultM); + + gsiLargeIntStripLeadingZeroes(x); + gsiLargeIntStripLeadingZeroes(y); + + // Check inputs + i=(int)(m->mLength); + while(i>0 && m->mData[i-1]==0) + i--; + if (i==0) + { + // modulus is zero, answer undefined + dest->mData[0] = 0; + dest->mLength = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_false; + } + if (x->mLength==0) + { + // x == 0 + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_true; + } + if (y->mLength==0) + { + // y == 0 + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_true; + } + + // We pad with zeroes so that we don't have to check for overruns in the loop below + // (note: resize will not remove non-zero digits from x or y) + gsiLargeIntResize(x, m->mLength); + gsiLargeIntResize(y, m->mLength); + + // Continue with the Multiplication + memset(&A, 0, sizeof(A)); + memset(&temp, 0, sizeof(temp)); + memset(&xiy, 0, sizeof(xiy)); + + for (i=0; (gsi_u32)i < m->mLength; i++) + { + xiy0 = (l_dword)x->mData[i]*y->mData[0]; // y[0], NOT y[i] !! + u = (l_word)((xiy0+A.mData[0])*modPrime); // strip bits over the first digit + + // A = (A+x[i]*y + u[i]*m)/b + // compute x[i]*y + memset(temp.mData, 0, y->mLength*sizeof(l_word)); // clear out a portion of temp + temp.mData[0] = x->mData[i]; + temp.mLength = y->mLength; // xi padded with zeroes + if (gsi_is_false(gsiLargeIntMult(temp.mData, temp.mLength, y->mData, y->mLength, xiy.mData, &xiy.mLength, GS_LARGEINT_MAX_DIGITS))) + { + // overflow + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_false; + } + // compute u[i]*m + memset(temp.mData, 0, m->mLength*sizeof(l_word)); // clear out a portion of temp + temp.mData[0] = u; + temp.mLength = m->mLength; + //if (gsi_is_false(gsiLargeIntMult(temp.mData, temp.mLength, m->mData, m->mLength, temp.mData, &temp.mLength))) + if (gsi_is_false(gsLargeIntKMult(&temp, m, &temp))) + { + // overflow + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_false; + } + // Add both to A + if (gsi_is_false(gsiLargeIntAdd(xiy.mData, xiy.mLength, A.mData, A.mLength, A.mData, &A.mLength, GS_LARGEINT_MAX_DIGITS))) + { + // overflow + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_false; + } + if (gsi_is_false(gsiLargeIntAdd(temp.mData, temp.mLength, A.mData, A.mLength, A.mData, &A.mLength, GS_LARGEINT_MAX_DIGITS))) + { + // overflow + dest->mLength = 0; + dest->mData[0] = 0; + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_false; + } + // Divide by b (e.g. Remove first digit from A) + if (A.mLength > 1) + { + memmove(&A.mData[0], &A.mData[1], (A.mLength-1)*sizeof(l_word)); + A.mData[A.mLength-1] = 0; + A.mLength--; + } + else + { + A.mLength = 0; + A.mData[0] = 0; + } + } + + //if (A >= m then subtract another m) + if (gsiLargeIntCompare(A.mData, A.mLength, m->mData, m->mLength)!=-1) + gsiLargeIntSub(m->mData, m->mLength, A.mData, A.mLength, dest->mData, &dest->mLength); + else + memcpy(dest, &A, sizeof(A)); + GSLINT_EXITTIMER(GSLintTimerMultM); + return gsi_true; +} + +#endif +/* +// Computes (src*src*r^-1)%mod +static gsi_bool gsiLargeIntSquareM(const gsLargeInt_t *src, const gsLargeInt_t *mod, gsi_u32 modPrime, gsi_u32 R, gsLargeInt_t *dest) +{ + GSI_UNUSED(src); + GSI_UNUSED(mod); + GSI_UNUSED(modPrime); + GSI_UNUSED(R); + GSI_UNUSED(dest); + assert(0); + return gsi_true; +}*/ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Calculate multiplicative inverse of mod, (-mod^-1 mod 2^R) +// ala. Dusse and Kaliski, extended Euclidean algorithm +gsi_bool gsiLargeIntInverseMod(const gsLargeInt_t *mod, l_word *dest) +{ + l_dword x=2; + l_dword y=1; + l_dword check = 0; + + gsi_u32 i; + for (i = 2; i <= GS_LARGEINT_DIGIT_SIZE_BITS; i++) + { + check = (l_dword)mod->mData[0] * (l_dword)y; + if (x < (check & ((x<<1)-1))) + y += x; + x = x << 1; + } + *dest = (l_word)(x-y); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsLargeIntPrint(FILE* logFile, const gsLargeInt_t *lint) +{ + return gsiLargeIntPrint(logFile, lint->mData, lint->mLength); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsiLargeIntPrint(FILE* logFile, const l_word *data, l_word length) +{ +// this is only specific to NITRO since for other platforms the fprintf will +// resolve to a STDOUT +#if !defined(_NITRO) + while(length >0) + { + fprintf(logFile, "%08X", data[length-1]); + length--; + } + fprintf(logFile, "\r\n"); + return gsi_true; +#else + GSI_UNUSED(logFile); + GSI_UNUSED(data); + GSI_UNUSED(length); + return gsi_false; +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// stream of bytes, big endian. (first byte = most significant digit) +gsi_bool gsLargeIntSetFromHexString(gsLargeInt_t *lint, const char* hexstream) +{ + l_word* writePos = lint->mData; + gsi_u32 temp; + int len = 0; + int byteIndex = 0; + + GS_ASSERT(hexstream != NULL); + + len = (int)strlen(hexstream); + if (len == 0) + { + lint->mLength = 0; + lint->mData[0] = 0; + return gsi_true; + } + if ((len/2) > (GS_LARGEINT_MAX_DIGITS*GS_LARGEINT_DIGIT_SIZE_BYTES)) + return gsi_false; + + // 2 characters per byte, 4 bytes per integer + lint->mLength = (l_word)((len+(2*GS_LARGEINT_DIGIT_SIZE_BYTES-1))/(2*GS_LARGEINT_DIGIT_SIZE_BYTES)); + lint->mData[lint->mLength-1] = 0; // set last byte to zero for left over characters + + while(len > 0) + { + if(len >= 2) + sscanf((char*)(hexstream+len-2), "%02x", &temp); // sscanf requires a 4 byte dest + else + sscanf((char*)(hexstream+len-1), "%01x", &temp); // sscanf requires a 4 byte dest + if(byteIndex == 0) + *writePos = 0; + *writePos |= (temp << (byteIndex * 8)); + if(++byteIndex == GS_LARGEINT_DIGIT_SIZE_BYTES) + { + writePos++; + byteIndex = 0; + } + len-=min(2,len); + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Reverse bytes in a LINT, which are LittleEndian +// ex: Packing an RSA message of which the first bytes are 0x00 0x02 +// The first bytes of the packet must become the MSD of the LINT +gsi_bool gsLargeIntReverseBytes(gsLargeInt_t *lint) +{ +#if defined(GSI_LITTLE_ENDIAN) + char *left = (char*)&lint->mData[0]; + char *right = ((char*)&lint->mData[lint->mLength])-1; + char temp; +#else + l_word *left = lint->mData; + l_word *right = lint->mData + (lint->mLength - 1); + l_word temp; +#endif + + + if (lint->mLength == 0) + return gsi_true; + + while(left < right) + { + temp = *left; + (*left++) = (*right); + (*right--) = temp; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// hashing is made complicated by differing byte orders +void gsLargeIntAddToMD5(const gsLargeInt_t * _lint, MD5_CTX * md5) +{ + int byteLength = 0; + gsi_u8 * dataStart = NULL; + + // Create a non-const copy so we can reverse bytes to add to the MD5 hash + gsLargeInt_t lint; + memcpy(&lint, _lint, sizeof(lint)); + + // first, calculate the byte length + byteLength = (int)gsLargeIntGetByteLength(&lint); + if (byteLength == 0) + return; // no data + + dataStart = (gsi_u8*)lint.mData; + if ((byteLength % GS_LARGEINT_DIGIT_SIZE_BYTES) != 0) + dataStart += GS_LARGEINT_DIGIT_SIZE_BYTES - (byteLength % GS_LARGEINT_DIGIT_SIZE_BYTES); + + // reverse to big-endian (MS) then hash + gsLargeIntReverseBytes(&lint); + MD5Update(md5, dataStart, (unsigned int)byteLength); + gsLargeIntReverseBytes(&lint); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Length in bytes so leading zeroes can be dropped from hex strings +gsi_u32 gsLargeIntGetByteLength(const gsLargeInt_t *lint) +{ + int intSize = (int)lint->mLength; + int byteSize = 0; + int i=0; + l_word mask = 0xFF; + + // skip leading zeroes + while(intSize > 0 && lint->mData[intSize-1] == 0) + intSize --; + if (intSize == 0) + return 0; // no data + + byteSize = intSize * (gsi_i32)sizeof(l_word); + + // subtract bytes for each leading 0x00 byte + mask = 0xFF; + for (i=1; i < GS_LARGEINT_DIGIT_SIZE_BYTES; i++) + { + if (lint->mData[intSize-1] <= mask) + { + byteSize -= sizeof(l_word)-i; + break; + } + mask = (l_word)((mask << 8) | 0xFF); + } + + return (gsi_u32)byteSize; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Creates a large int from a byte buffer +// Essentially, constructs the array of digits in appropriate byte order +gsi_bool gsLargeIntSetFromMemoryStream(gsLargeInt_t *lint, const gsi_u8* data, gsi_u32 len) +{ + lint->mData[0] = 0; + memcpy(((char*)lint->mData)+(4-len%4)%4, data, len); + + // Set length to ceiling of len/digit_size + lint->mLength = (unsigned int)((len+(GS_LARGEINT_DIGIT_SIZE_BYTES-1))/GS_LARGEINT_DIGIT_SIZE_BYTES); + + return gsLargeIntReverseBytes(lint); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsLargeIntWriteToMemoryStream(const gsLargeInt_t *lint, gsi_u8* data) +{ + gsLargeInt_t copy; + memcpy(©, lint, sizeof(gsLargeInt_t)); + + gsLargeIntReverseBytes(©); + + memcpy(data, copy.mData, copy.mLength * GS_LARGEINT_DIGIT_SIZE_BYTES); + return gsi_true; +} diff --git a/xrGameSpy/gamespy/common/gsLargeInt.h b/xrGameSpy/gamespy/common/gsLargeInt.h new file mode 100644 index 00000000000..2ca665c75aa --- /dev/null +++ b/xrGameSpy/gamespy/common/gsLargeInt.h @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Large Integer Library +#ifndef __GSLARGEINT_H__ +#define __GSLARGEINT_H__ + +#include "gsCommon.h" +#include "gsXML.h" +#include "../md5.h" + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// for simplicity, set the binary size to a value > gsCrypt.h binary size +#ifndef GS_LARGEINT_BINARY_SIZE +#define GS_LARGEINT_BINARY_SIZE (2048) // *BIT* size (divide by 8 for byte size) +#endif + + // !!!!!!WARNING!!!!!! Encryption is fastest when digit type is the default system type, (ex: gsi_u32 on 32bit processor) +#define GS_LARGEINT_DIGIT_TYPE gsi_u32 +#define GS_LARGEINT_DIGIT_LONG_TYPE gsi_u64 + +#define GS_LARGEINT_DIGIT_SIZE_BYTES (sizeof(GS_LARGEINT_DIGIT_TYPE)) +#define GS_LARGEINT_DIGIT_SIZE_BITS (GS_LARGEINT_DIGIT_SIZE_BYTES*8) + +// short forms for legibility +#define l_word GS_LARGEINT_DIGIT_TYPE +#define l_dword GS_LARGEINT_DIGIT_LONG_TYPE + +//#define GS_LARGEINT_BYTE_SIZE 32 // binary size of system data type +//#define GS_LARGEINT_INT_SIZE (GS_LARGEINT_BINARY_SIZE/GS_LARGEINT_BYTE_SIZE) // size in values +#define GS_LARGEINT_MAX_DIGITS (GS_LARGEINT_BINARY_SIZE / GS_LARGEINT_DIGIT_SIZE_BITS) + +#define GS_LARGEINT_KARATSUBA_CUTOFF 32 + +typedef struct gsLargeInt_s +{ + GS_LARGEINT_DIGIT_TYPE mLength; + GS_LARGEINT_DIGIT_TYPE mData[GS_LARGEINT_MAX_DIGITS]; +} gsLargeInt_t; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Commonly used functions +void gsLargeIntAddToMD5(const gsLargeInt_t * lint, MD5_CTX * md5); +gsi_bool gsLargeIntSetFromHexString(gsLargeInt_t *lint, const char* hexstring); +gsi_bool gsLargeIntPrint (FILE* logFile, const gsLargeInt_t *lint); +gsi_u32 gsLargeIntGetByteLength(const gsLargeInt_t *lint); + + // Modular exponentiation (and helpers) + // -- uses Montgomery exponentiation, reduction, multiplication +gsi_bool gsLargeIntPowerMod(const gsLargeInt_t *base, const gsLargeInt_t *power, const gsLargeInt_t *mod, gsLargeInt_t *dest); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsLargeIntSquareMod(const gsLargeInt_t *lint, const gsLargeInt_t *mod, gsLargeInt_t *dest); +gsi_bool gsLargeIntAdd (const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest); +gsi_bool gsLargeIntSub (const gsLargeInt_t *src1, const gsLargeInt_t *fromsrc2, gsLargeInt_t *dest); +gsi_bool gsLargeIntMult (const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest); +gsi_bool gsLargeIntDiv (const gsLargeInt_t *src1, const gsLargeInt_t *divisor, gsLargeInt_t *dest, gsLargeInt_t *remainder); + + //Karatsuba requires that the sizes be equal and a power of two +gsi_bool gsLargeIntKMult(const gsLargeInt_t *src1, const gsLargeInt_t *src2, gsLargeInt_t *dest); + + //This is useful when packing a BigEndian message directly into a LittleEndian lint buffer. +gsi_bool gsLargeIntReverseBytes(gsLargeInt_t *lint); +gsi_bool gsLargeIntSetValue(gsLargeInt_t *lint, l_word value); + + //These are necessary to preserve byte order when copying from array-of-int to char* +gsi_bool gsLargeIntSetFromMemoryStream(gsLargeInt_t *lint, const gsi_u8* data, gsi_u32 len); +gsi_bool gsLargeIntWriteToMemoryStream(const gsLargeInt_t *lint, gsi_u8* data); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} +#endif + +#endif // __GSLARGEINT_H__ diff --git a/xrGameSpy/gamespy/common/gsMemory.c b/xrGameSpy/gamespy/common/gsMemory.c new file mode 100644 index 00000000000..8b615607b0b --- /dev/null +++ b/xrGameSpy/gamespy/common/gsMemory.c @@ -0,0 +1,1774 @@ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsPlatform.h" +#include "gsPlatformUtil.h" +#include "gsMemory.h" +#include "gsAssert.h" +#include "gsDebug.h" + +#ifdef _PSP + #include +#endif + +// toDo: move some of this to platform.h +#ifdef _PS3 + #if(0) + typedef gsi_u64 gsi_uint; + #define PTR_ALIGNMENT 32 + #define GSI_64BIT (1) + #define GS_BIG_ENDIAN + #else + // changed as of SDK 0.8 Sony moved back to using 32 bit pointers + typedef gsi_u32 gsi_uint; + #define PTR_ALIGNMENT 16 + #define GSI_64BIT (0) + #define GS_BIG_ENDIAN + #endif +#else + typedef gsi_u32 gsi_uint; + #define PTR_ALIGNMENT 16 + #define GSI_64BIT (0) +#endif + + + +// To Do: +// Small block optimization using fixed size mempool. +// add multi-threaded support + +#define MEM_PROFILE (1) // if on additional memprofiling code will be enabled for such things as high water mark calcs +#if defined(MEM_PROFILE) + #define IF_MEM_PROFILE_ISON(a) a +#else + #define IF_MEM_PROFILE_ISON(a) +#endif + +// Disable compiler warnings for issues that are unavoidable. +///////////////////////////////////////////////////////////// +#if defined(_MSC_VER) // DevStudio + // Level4, "conditional expression is constant". + // Occurs with use of the MS provided macro FD_SET + #pragma warning ( disable: 4127 ) +#include +#endif // _MSC_VER + +#ifdef _WIN32 + #define MEM_MANAGER_CALL _cdecl +#else + #define MEM_MANAGER_CALL +#endif + +//#if !defined(_WIN32) +// #define MEM_MANAGER_DIRECT +//#endif + +typedef struct +{ + void* (MEM_MANAGER_CALL *malloc )(size_t size); + void (MEM_MANAGER_CALL *free )(void* ptr); + void* (MEM_MANAGER_CALL *realloc )(void* ptr, size_t size); + void* (MEM_MANAGER_CALL *memalign)(size_t boundary, size_t size); +}MemManagerCallbacks; + +static void* MEM_MANAGER_CALL _gsi_malloc(size_t size) +{ + return malloc(size); +} + +static void MEM_MANAGER_CALL _gsi_free(void* ptr) +{ + free(ptr); +} + +static void* MEM_MANAGER_CALL _gsi_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + +#if defined(_PS2) || defined(_PSP) || defined(_PS3) + static void* _gsi_memalign(size_t boundary, size_t size) + { + return memalign(boundary, size); + } +#elif defined (_WIN32) + #if (_MSC_VER < 1300) + //extern added for vc6 compatability. + extern void* __cdecl _aligned_malloc(size_t size, int boundary); + #endif + static void* __cdecl _gsi_memalign(size_t boundary, size_t size) + { + return _aligned_malloc(size, (int)boundary); + } +#else + // no built in system memalign + static void* _gsi_memalign(size_t boundary, size_t size) + { + void *ptr = calloc((size)/(boundary), (boundary)); + // check alignment + GS_ASSERT((((gsi_u32)ptr)% boundary)==0); + return ptr; + } +#endif + +static MemManagerCallbacks memmanagercallbacks = +{ +#ifdef MEM_MANAGER_DIRECT + &malloc, + &free, + &realloc, + #if defined(_PS2) || defined(_PSP) || defined(_PS3) + &memalign, // a version already exists on this platform + #else + &_gsi_memalign, //wrote our own + #endif +#else + &_gsi_malloc, + &_gsi_free, + &_gsi_realloc, + &_gsi_memalign +#endif +}; + + +void gsiMemoryCallbacksSet(gsMallocCB p_malloc, gsFreeCB p_free, gsReallocCB p_realloc, gsMemalignCB p_memalign) +{ + + memmanagercallbacks.malloc = p_malloc; + memmanagercallbacks.free = p_free; + memmanagercallbacks.realloc = p_realloc; + memmanagercallbacks.memalign = p_memalign; +} + + + + + + +// These functions shunt to virtual function pointer +void* gsimalloc (size_t size) +{ + return (*memmanagercallbacks.malloc)(size); +} +void* gsirealloc (void* ptr, size_t size) +{ + return (*memmanagercallbacks.realloc)(ptr,size); +} +void gsifree (void* ptr) +{ + if(ptr == NULL) + return; + (*memmanagercallbacks.free)(ptr); +} +void* gsimemalign (size_t boundary, size_t size) +{ + return (*memmanagercallbacks.memalign)(boundary,size); +} + + + +#ifdef GSI_MEM_MANAGED + + + + +/***************************************************************************/ +/* + + Random Access Memory Pool + +*/ +/***************************************************************************/ + + +// Context Stack +#define MEM_CONTEXT_STACK_MAX 10 // max stack depth +static gsMemMgrContext MemTypeStack [MEM_CONTEXT_STACK_MAX] = {gsMemMgrContext_Default}; +static gsi_u32 MemTypeStackIndex = 0; +extern gsMemMgrContext gsMemMgrContextCurrent; + +// Memtype Tag stack +#define MEM_TAG_STACK_MAX 10 // max stack depth +static gsi_u8 MemTagStack [MEM_TAG_STACK_MAX] = {0}; +static gsi_u32 MemTagStackIndex = 0; + + +// ToDo: +// - Add 64 bit pointer support + + + +// Default pointer alignment. Must be 16, 32, 64, 128, or 256 bytes. +// i.e. malloc (x) = memalign(default alignment,x); + + + +#define MEM_IS_POWER_OF_2(x) (((x) & ((x)-1)) == 0) +#define MEMALIGN_POWEROF2(x,a) (((gsi_uint)(x)+(a-1)) &~ ( ((gsi_uint)(a)) -1)) + +#if(1) // enable assert, otherwise this runs faster + #define MP_ASSERT(x) GS_ASSERT(x) +#else + #define MP_ASSERT(x) +#endif + + +#define MEM_TYPES_MAX 127 + + +typedef struct +{ + gsi_u32 MemTotal; + gsi_u32 MemAvail; + gsi_u32 MemUsed; + gsi_u32 MemUsed_At_HighWater; + gsi_u32 MemWasted; // overhead memory + memory lost due to fragmentation. + + gsi_u32 ChunksCount; // number of ChunkHeaders in linked list. + gsi_u32 ChunksFreeCount; // number of free ChunkHeaders in linked list. + gsi_u32 ChunksFreeLargestAvail; + // these are the same as handles + gsi_u32 ChunksUsedCount; // number of ChunkHeaders which are in use. + gsi_u32 ChunksUsedCount_At_HighWater; // the most handles used at any one time + + // memtype specifics + gsi_u32 MemType_ChunksCount [MEM_TYPES_MAX]; + gsi_u32 MemType_MemUsed [MEM_TYPES_MAX]; + gsi_u32 MemType_MemUsed_At_HighWater [MEM_TYPES_MAX]; + + +} MEM_STATS; + +void MEM_STATSAddAll (MEM_STATS *_this, const MEM_STATS *ms); +void MEM_STATSClear (MEM_STATS *_this); +// except HW +void MEM_STATSClearAll (MEM_STATS *_this); + + +// RA_MEM_CHUNK +typedef struct tMEM_CHUNK +{ + + // private + union + { + gsi_uint MemUsed; // size used by application. ex// malloc(size) + #ifdef GS_BIG_ENDIAN + struct + { + #if (GSI_64BIT) + char pad[7],MemType; + #else + char pad[3],MemType; + #endif + }MEM_TypeStruct; + #else + struct + { + #if (GSI_64BIT) + char MemType,pad[7]; + #else + char MemType,pad[3]; + #endif + } MEM_TypeStruct; + #endif + } MEM_UsageStat; + + // public: + // double linked list of all chunks + struct tMEM_CHUNK *prev; + struct tMEM_CHUNK *next; // next chunk + // single linked list of free chunks + struct tMEM_CHUNK *NextFree; // next free chunk +} MEM_CHUNK; + + + +/***************************************/ +// flag as in use, set size, memtype +void MEM_CHUNKAlloc (MEM_CHUNK *_this, gsi_u8 _MemType, size_t _UsedSize) +{ + _UsedSize = MEMALIGN_POWEROF2(_UsedSize,4); //The lower 2 bits are zero, so we don't store them. + GS_ASSERT_STR(_UsedSize < 0x3FFFFFC, "Alloc Memory size is too big."); + _this->MEM_UsageStat.MemUsed = _UsedSize<<6; + _this->MEM_UsageStat.MEM_TypeStruct.MemType = _MemType; +} +void MEM_CHUNKFree (MEM_CHUNK *_this) +{ + _this->MEM_UsageStat.MemUsed = 0; +} + +/***************************************/ +// returns true if not in use +gsi_bool MEM_CHUNKIsFree (MEM_CHUNK *_this) +{ + return (_this->MEM_UsageStat.MemUsed == 0); +} + +/***************************************/ +gsi_u32 MEM_CHUNKTotalSizeGet(MEM_CHUNK *_this) +// Total size chunk is using up, including header. +{ + if (!_this->next) + { + return PTR_ALIGNMENT + sizeof(MEM_CHUNK)/*Nub*/; + } + return (gsi_uint) _this->next - (gsi_uint) _this; +} + +/***************************************/ +gsi_u32 MEM_CHUNKChunkSizeGet(MEM_CHUNK *_this) +// size of chunk, without header. "Available memory" +{ + if (!_this->next) + return PTR_ALIGNMENT;/*Nub*/; + return (gsi_uint) _this->next - (gsi_uint) _this - sizeof(MEM_CHUNK); +} + +gsi_u32 MEM_CHUNKMemUsedGet (MEM_CHUNK *_this) +{ + return (_this->MEM_UsageStat.MemUsed & ~0xFF)>>6; +} + +void MEM_CHUNKMemUsedSet (MEM_CHUNK *_this, gsi_u32 size) +{ + _this->MEM_UsageStat.MemUsed = (MEMALIGN_POWEROF2(size,4)<<6) + _this->MEM_UsageStat.MEM_TypeStruct.MemType; +} + +gsi_u32 MEM_CHUNKMemAvailGet(MEM_CHUNK *_this) +{ + return MEM_CHUNKChunkSizeGet(_this) - MEM_CHUNKMemUsedGet(_this); +} + +char MEM_CHUNKMemTypeGet (MEM_CHUNK *_this) +{ + return _this->MEM_UsageStat.MEM_TypeStruct.MemType; +} + +void MEM_CHUNKMemTypeSet (MEM_CHUNK *_this, char _MemType) +{ + GS_ASSERT(_MemType < MEM_TYPES_MAX); + _this->MEM_UsageStat.MEM_TypeStruct.MemType = _MemType; +} + +void* MEM_CHUNKMemPtrGet (MEM_CHUNK *_this) +{ + return (void*)((gsi_uint) _this + sizeof(MEM_CHUNK)); +} + +/*inline */MEM_CHUNK *Ptr_To_MEM_CHUNK(void *ptr) +{ + return ((MEM_CHUNK *)ptr)-1; +} + +/***************************************/ +/***************************************/ +typedef struct MEM_CHUNK_POOL +{ + // public: + char Name[20]; // name of this pool. Used for debug purposes + // private: + MEM_CHUNK *HeaderStart; + MEM_CHUNK *HeaderEnd; + MEM_CHUNK *pFirstFree; + gsi_u32 HeapSize; + #if MEM_PROFILE + gsi_u32 HWMemUsed; + gsi_u32 MemUsed; + #endif +} MEM_CHUNK_POOL; + +// private +MEM_CHUNK *MEM_CHUNK_POOLFindPreviousFreeChunk (MEM_CHUNK_POOL *_this, MEM_CHUNK *header); +MEM_CHUNK *MEM_CHUNK_POOLFindNextFreeChunk (MEM_CHUNK_POOL *_this, MEM_CHUNK *header); +void MEM_CHUNK_POOLSplitChunk (MEM_CHUNK_POOL *_this, MEM_CHUNK *header,gsi_bool ReAlloc); +void MEM_CHUNK_POOLFreeChunk (MEM_CHUNK_POOL *_this, MEM_CHUNK *header); +MEM_CHUNK *MEM_CHUNK_POOLAllocChunk (MEM_CHUNK_POOL *_this, size_t Size,int Alignment , gsi_bool Backwards );//int Alignment = PTR_ALIGNMENT, gsi_bool Backwards = gsi_false); + +// move a chunk within the limits of prev + prev_size and next - this_size +void MEM_CHUNK_POOLChunkMove (MEM_CHUNK_POOL *_this, MEM_CHUNK *oldpos, MEM_CHUNK *newpos); + +// public +/***************************************/ +void MEM_CHUNK_POOLCreate (MEM_CHUNK_POOL *_this, const char *szName, char *ptr, gsi_u32 _size); +void MEM_CHUNK_POOLDestroy (MEM_CHUNK_POOL *_this) ; +gsi_bool MEM_CHUNK_POOLIsValid (MEM_CHUNK_POOL *_this) +{ + return _this->HeapSize > 0; +} + + +/***************************************/ +void *MEM_CHUNK_POOLmalloc (MEM_CHUNK_POOL *_this, size_t Size, gsi_i32 Alignment );//= PTR_ALIGNMENT); +// allocated backwards from top of heap +void *MEM_CHUNK_POOLmalloc_backwards (MEM_CHUNK_POOL *_this, size_t Size, gsi_i32 Alignment );//= PTR_ALIGNMENT); +void *MEM_CHUNK_POOLrealloc (MEM_CHUNK_POOL *_this, void *oldmem, size_t newSize); +void MEM_CHUNK_POOLfree (MEM_CHUNK_POOL *_this, void *mem); + +/***************************************/ +void MEM_CHUNK_POOLCheckValidity (MEM_CHUNK_POOL *_this ); +void MEM_CHUNK_POOLMemStatsGet (MEM_CHUNK_POOL *_this, MEM_STATS *stats); +gsi_u32 MEM_CHUNK_POOLWalkForType (MEM_CHUNK_POOL *_this, int _MemType, gsi_bool _LogUse); + +// returns true if this is a valid heap ptr +gsi_bool MEM_CHUNK_POOLIsHeapPtr (MEM_CHUNK_POOL *_this, void * mem); + +/***************************************/ +// add to table, filling in memtype . +void MEM_CHUNK_POOLFillMemoryTable (MEM_CHUNK_POOL *_this, char *Table, const int TableSize, gsi_u32 _HeapStart, gsi_u32 _HeapSize); + +/***************************************/ +// returns true if mem handle is in range of heap +gsi_bool MEM_CHUNK_POOLItemIsInPoolMemory (MEM_CHUNK_POOL *_this, void *ptr) +{ + GS_ASSERT(MEM_CHUNK_POOLIsValid(_this)); + return (((gsi_uint)ptr >= (gsi_uint)MEM_CHUNKMemPtrGet(_this->HeaderStart)) &&((gsi_uint)ptr <= (gsi_uint)MEM_CHUNKMemPtrGet(_this->HeaderEnd))); +} + + + + + + + + + + +void MEM_STATSAddAll(MEM_STATS *_this, const MEM_STATS *ms) +{ + int i; + _this->MemTotal += ms->MemTotal ; + _this->MemAvail += ms->MemAvail ; + _this->MemUsed += ms->MemUsed ; + _this->MemUsed_At_HighWater += ms->MemUsed_At_HighWater ; + _this->MemWasted += ms->MemWasted ; + _this->ChunksCount += ms->ChunksCount ; + _this->ChunksFreeCount += ms->ChunksFreeCount ; + _this->ChunksFreeLargestAvail += ms->ChunksFreeLargestAvail ; + _this->ChunksUsedCount += ms->ChunksUsedCount ; + _this->ChunksUsedCount_At_HighWater += ms->ChunksUsedCount_At_HighWater; + for (i =0; iMemType_ChunksCount[i] +=ms->MemType_ChunksCount[i]; + _this->MemType_MemUsed[i] +=ms->MemType_MemUsed[i] ; + } + +} + +void MEM_STATSClear(MEM_STATS *_this ) +// except HW +{ + _this->MemTotal = 0; + _this->MemAvail = 0; + _this->MemUsed = 0; + _this->MemWasted = 0; + _this->ChunksCount = 0; + _this->ChunksFreeCount = 0; + _this->ChunksFreeLargestAvail = 0; + _this->ChunksUsedCount = 0; + + memset(_this->MemType_ChunksCount, 0,4 * MEM_TYPES_MAX); + memset(_this->MemType_MemUsed, 0,4 * MEM_TYPES_MAX); + +} + +void MEM_STATSClearAll(MEM_STATS *_this ) +{ + int i; + MEM_STATSClear(_this); + _this->MemUsed_At_HighWater = 0; + for (i=0;i< MEM_TYPES_MAX;i++ ) + _this->MemType_MemUsed_At_HighWater[i] = 0; + _this->ChunksUsedCount_At_HighWater = 0; +} + + + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLChunkMove (MEM_CHUNK_POOL *_this, MEM_CHUNK *oldpos, MEM_CHUNK *newpos) +//-------------------------------------------------------------------------- +{ + MEM_CHUNK *firstfree; + //todo!!! + MEM_CHUNK temp = *oldpos; + + // can not be end/start chunk + MP_ASSERT(oldpos->prev) + MP_ASSERT(oldpos->next) + + // check if within movement limits + MP_ASSERT((gsi_uint) newpos <= (gsi_uint)oldpos->next - MEM_CHUNKMemUsedGet(oldpos) - sizeof(MEM_CHUNK)) + MP_ASSERT((gsi_uint) newpos >= (gsi_uint)oldpos->prev + MEM_CHUNKMemUsedGet(oldpos->prev) + sizeof(MEM_CHUNK)) + + // check if alignment is valid + MP_ASSERT((((gsi_uint) newpos) % sizeof(MEM_CHUNK)) == 0) + + *newpos = temp; + + // link into chunk list + newpos->prev->next = newpos; + newpos->next->prev = newpos; + + // Fix links in free chunk list + if (MEM_CHUNKIsFree(newpos)) + { + + if (_this->pFirstFree == oldpos) + _this->pFirstFree = newpos; + else + { + firstfree = MEM_CHUNK_POOLFindPreviousFreeChunk(_this,newpos->prev); + if (firstfree != newpos) + firstfree->NextFree = newpos; + else + { + // first in list. + _this->pFirstFree = newpos; + } + + MP_ASSERT((newpos->NextFree==NULL) || ((gsi_uint)newpos->NextFree > (gsi_uint)newpos)) + } + } + + +} + +void MEM_CHUNK_POOLDestroy(MEM_CHUNK_POOL *_this) +{ + memset(_this, 0, sizeof (MEM_CHUNK_POOL)); +} +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLCreate(MEM_CHUNK_POOL *_this, const char * szNameIn, char *ptr, gsi_u32 size) +//-------------------------------------------------------------------------- +{ + int len; + MEM_CHUNK *HeaderMid; + MP_ASSERT(((gsi_uint)ptr & 15 )==0) // ensure 16 byte alignment + + //Copy limited length name + len = strlen(szNameIn)+1; + if (len > 20) len = 20; + memcpy(_this->Name,szNameIn, len); + _this->Name[19]='\0'; // in case str is too long. + + // create two nubs, at start, and end, with a chunk in between + MP_ASSERT(size > 48 + 3 * sizeof(MEM_CHUNK)) + + _this->HeaderStart = (MEM_CHUNK *) (ptr); + HeaderMid = (MEM_CHUNK *) (ptr + 2 * sizeof(MEM_CHUNK)); + _this->HeaderEnd = (MEM_CHUNK *) (ptr + size - 2 * sizeof(MEM_CHUNK)); + + // Bogus nub which is never freed. + _this->HeaderStart->prev = NULL; + _this->HeaderStart->next = HeaderMid; + _this->HeaderStart->NextFree = HeaderMid; + MEM_CHUNKAlloc (_this->HeaderStart,0,sizeof(MEM_CHUNK)); // don't mark as free + + // Here is our real heap, after before and after overhead + HeaderMid->prev = _this->HeaderStart; + HeaderMid->next = _this->HeaderEnd; + HeaderMid->NextFree = 0; + MEM_CHUNKFree(HeaderMid); + + // Bogus nub which is never freed. + _this->HeaderEnd->prev = HeaderMid; + _this->HeaderEnd->next = NULL; + _this->HeaderEnd->NextFree = NULL; + MEM_CHUNKAlloc (_this->HeaderEnd,0,sizeof(MEM_CHUNK)); // don't mark as free + + _this->HeapSize = size; + _this->pFirstFree = HeaderMid; + +} + + +//-------------------------------------------------------------------------- +MEM_CHUNK *MEM_CHUNK_POOLFindPreviousFreeChunk(MEM_CHUNK_POOL *_this, MEM_CHUNK *header) +// find previous free chunk +// return NULL if start header is not free, and there is nothing free before it. +// return header if start header is first free chunk +{ + while ((header) && (!MEM_CHUNKIsFree(header))) + { + //GS_ASSERT(header->prev == NULL || (header->prev >= _this->HeaderStart && header->prev <= _this->HeaderEnd)); + header = header->prev; + } + + GSI_UNUSED(_this); + return header; +} + +//-------------------------------------------------------------------------- +MEM_CHUNK *MEM_CHUNK_POOLFindNextFreeChunk(MEM_CHUNK_POOL *_this, MEM_CHUNK *header_in) +// find previous free chunk +// return NULL if no next free chunk. +{ + MEM_CHUNK *header = header_in; + while ((header) && (!MEM_CHUNKIsFree(header))) + { + header = header->next; + } + if (header == header_in) + return NULL; + + GSI_UNUSED(_this); + return header; +} + + + + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLSplitChunk(MEM_CHUNK_POOL *_this, MEM_CHUNK *header, gsi_bool ReAlloc) +// split a used chunk into two if the UsedSize is smaller then the ChunkSize +//-------------------------------------------------------------------------- +{ + MEM_CHUNK *next; + MEM_CHUNK *PrevFree; + MEM_CHUNK *NewHeader; + + // calc new position at end of used mem + NewHeader = (MEM_CHUNK *) ((gsi_u8*)header + MEM_CHUNKMemUsedGet(header) + sizeof(MEM_CHUNK)); + NewHeader = (MEM_CHUNK *)MEMALIGN_POWEROF2(NewHeader,sizeof(MEM_CHUNK)); + + //assert we have enough room for this new chunk + MP_ASSERT ((gsi_uint)NewHeader + 2 * sizeof(MEM_CHUNK) <= (gsi_uint)header->next) + + // update some stats + #if (MEM_PROFILE) + if(ReAlloc) + { + //09-OCT-07 BED: Since we're splitting the chunk, it seems more accurate + // to use the full size of the chunk, not just the used portion + _this->MemUsed -= MEM_CHUNKChunkSizeGet(header); + //_this->MemUsed -= MEM_CHUNKMemUsedGet(header); + GS_ASSERT(_this->MemUsed >= 0); + } + #endif + + // Can this new chunk fit in the current one? + // create a new chunk header, at the end of used space, plus enough to align us to 16 bytes + + // Splice into linked list + NewHeader->prev = header; + NewHeader->next = header->next; + MEM_CHUNKFree(NewHeader); + + if (NewHeader->next) + { + NewHeader->next->prev = NewHeader; + } + + header->next = NewHeader; + + // Splice into free chunks linked list + + // this need to merge can happen on a realloc before a free chunk + if (MEM_CHUNKIsFree(NewHeader->next)) + { + MP_ASSERT(ReAlloc) + + // merge and splice + next = NewHeader->next->next; + next->prev = NewHeader; + + NewHeader->NextFree = NewHeader->next->NextFree; + NewHeader->next = next; + } + else + { + if (ReAlloc) + { + // on a realloc, this next value is useless + NewHeader->NextFree = MEM_CHUNK_POOLFindNextFreeChunk(_this,NewHeader->next); + } + else + NewHeader->NextFree = header->NextFree; + } + + if (_this->pFirstFree == header) + { + // this is first free chunk + _this->pFirstFree = NewHeader; + } + else + { + // link previous free chunk to this one. + PrevFree = MEM_CHUNK_POOLFindPreviousFreeChunk(_this,header); + if (PrevFree) + PrevFree->NextFree = NewHeader; + else + // this is first free chunk + _this->pFirstFree = NewHeader; + } + + #if (MEM_PROFILE) + if(ReAlloc) + { + _this->MemUsed += MEM_CHUNKMemUsedGet(header); + // update highwater mark + if(_this->MemUsed > _this->HWMemUsed) + _this->HWMemUsed = _this->MemUsed; + + GS_ASSERT(_this->MemUsed <= _this->HeapSize); + } + #endif + +#ifdef _DEBUG_ + header->NextFree = NULL; +#endif + +} + + +//-------------------------------------------------------------------------- +gsi_bool MEM_CHUNK_POOLIsHeapPtr(MEM_CHUNK_POOL *_this, void * mem) +// returns true if this is a valid heap ptr +{ + MEM_CHUNK *headertofind = Ptr_To_MEM_CHUNK(mem); + MEM_CHUNK *header = _this->HeaderStart; + + while (header) + { + header = header->next; + if (headertofind == header) + return gsi_true; + } + + return gsi_false; + +} + + + + + + + +//-------------------------------------------------------------------------- +MEM_CHUNK *MEM_CHUNK_POOLAllocChunk(MEM_CHUNK_POOL *_this,size_t Size, gsi_i32 Alignment, gsi_bool Backwards) +// size = requested size from app. + +// Find first chunk that will fit, +// allocate from it, splitting it +// merge split with next free chunk, if next chunk is free +//-------------------------------------------------------------------------- +{ + gsi_u32 Ptr ; + gsi_u32 AlignedPtr ; + int delta ; + MEM_CHUNK *PrevFree ; + int total_size ; + int MemRemain ; + MEM_CHUNK *alignedheader; + + + MEM_CHUNK *header; + gsi_u32 SizeNeeded = Size + sizeof(MEM_CHUNK); + SizeNeeded = MEMALIGN_POWEROF2(SizeNeeded,sizeof(MEM_CHUNK)); // must be aligned to this at least!!! + + MP_ASSERT(Size) + MP_ASSERT(MEM_IS_POWER_OF_2(Alignment)) // must be power of two!!! + MP_ASSERT(Alignment >= PTR_ALIGNMENT) + + +// Backwards = gsi_false; + + if(Backwards) + header = MEM_CHUNK_POOLFindPreviousFreeChunk(_this,_this->HeaderEnd); + else + header = _this->pFirstFree; + + + // should all be free chunks linked from here in. + while (header) + { + // is this chunk available + MP_ASSERT (MEM_CHUNKIsFree(header)) + + // Calc memory left in this chunk after we alloc + total_size = MEM_CHUNKTotalSizeGet(header); + MemRemain = total_size - SizeNeeded; + + // can we fit? + if (MemRemain >= 0 ) + { + // are we aligned properly? + Ptr = (gsi_uint)MEM_CHUNKMemPtrGet(header); + AlignedPtr = MEMALIGN_POWEROF2(Ptr,Alignment); + delta = AlignedPtr - Ptr; + if (delta) + { + // we need to move free chunk over by ptr. + if (MemRemain < delta) + { + // not enough space in this chunk + header = header->NextFree; + continue; + } + + // move the chunk over so that the pointer is aligned. + alignedheader = Ptr_To_MEM_CHUNK((void*)(gsi_uint)AlignedPtr); + MEM_CHUNK_POOLChunkMove (_this,header,alignedheader); + header = alignedheader; + MemRemain -= delta; + + } + + + // at this point we've taken this chunk, and need to split off the unused part + // in theory, there should be no other free chunk ahead of us. + + MEM_CHUNKAlloc(header,MemTagStack[MemTagStackIndex],Size); + + // split as needed + if (MemRemain > sizeof(MEM_CHUNK)*2) + { + + // split chunk, this will handle free chunk pointer list + MEM_CHUNK_POOLSplitChunk(_this,header, gsi_false); + } + else + { + // remove from free list + if (_this->pFirstFree == header) + { + // this is first free chunk + _this->pFirstFree = header->NextFree; + + } + else + { + // link previous free chunk to this one. + PrevFree = MEM_CHUNK_POOLFindPreviousFreeChunk(_this,header); + if (PrevFree) + PrevFree->NextFree = header->NextFree; + else + _this->pFirstFree = header->NextFree; + + } + } + { + #if (MEM_PROFILE) + _this->MemUsed += MEM_CHUNKMemUsedGet(header); + // update highwater mark + if(_this->MemUsed > _this->HWMemUsed) + _this->HWMemUsed = _this->MemUsed; + + GS_ASSERT(_this->MemUsed <= _this->HeapSize); + #endif + } + return header; + + } + if (Backwards) + header = MEM_CHUNK_POOLFindPreviousFreeChunk(_this,header); + else + header = header->NextFree; + } + // not crashing here. + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice," Could not allocate %i bytes\n", Size); + GS_ASSERT_STR(0,"Out of memory");//(_this->Name); + + + return NULL; + +} + + + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLFreeChunk(MEM_CHUNK_POOL *_this,MEM_CHUNK *header) +// set chunk as free +// merge if possible with prev and next +// adding chunk to free chunks list. +//-------------------------------------------------------------------------- +{ + + MEM_CHUNK *prev = header; + MEM_CHUNK *next = header; + MEM_CHUNK *PrevFree; + + #if (MEM_PROFILE) + _this->MemUsed -= MEM_CHUNKMemUsedGet(header); + GS_ASSERT(_this->MemUsed >= 0); + #endif + + while (next->next && (MEM_CHUNKIsFree(next->next))) + { + next = next->next; + } + + while (prev->prev && (MEM_CHUNKIsFree(prev->prev))) + { + prev = prev->prev; + } + + if (prev != next) + { + // merge + // prev becomes the new chunk. + prev->next = next->next; + + if (next->next) + next->next->prev = prev; + + } + + // since this is now a free chunk, we must add it to the free chunk list + + // find previous free + PrevFree = MEM_CHUNK_POOLFindPreviousFreeChunk(_this,prev); + if (PrevFree == NULL) + { + // this is first free chunk + _this->pFirstFree = prev; + + } + else + { + // link previous free chunk to this one. + PrevFree->NextFree = prev; + } + + // find and set next free chunk + if(next->next) + prev->NextFree = MEM_CHUNK_POOLFindNextFreeChunk(_this,next->next); + else + prev->NextFree = NULL; + + MEM_CHUNKFree(prev); + + +#if(0) + //ToDo: steal unused memory from previous used chunk + gsi_u32 destptr = (gsi_u32)prev->prev + prev->prev->MemAvailGet() + sizeof(MEM_CHUNK); + destptr = MEMALIGN_POWEROF2(destptr,sizeof(MEM_CHUNK)); + + // we can move back to this ptr. Is it worth it? + if (destptr < (gsi_u32)prev ) + ChunkMove(prev,(MEM_CHUNK *)destptr); +#endif +} + + + + +//-------------------------------------------------------------------------- +void *MEM_CHUNK_POOLmalloc(MEM_CHUNK_POOL *_this,size_t Size, gsi_i32 Alignment) +//-------------------------------------------------------------------------- +{ + void *mem; + + // return ptr to the first block big enough + MEM_CHUNK *header = MEM_CHUNK_POOLAllocChunk( _this,Size, Alignment, gsi_false); + + if (header) + { + // alloc new chunk + mem = MEM_CHUNKMemPtrGet(header); + return mem; + } + + return NULL; +} + + +//-------------------------------------------------------------------------- +void *MEM_CHUNK_POOLmalloc_backwards(MEM_CHUNK_POOL *_this,size_t Size, gsi_i32 Alignment) +//-------------------------------------------------------------------------- +{ + void *mem; + + // return ptr to the first block big enough + MEM_CHUNK *header = MEM_CHUNK_POOLAllocChunk( _this,Size, Alignment, gsi_true); + + if (header) + { + // alloc new chunk + mem = MEM_CHUNKMemPtrGet(header); + return mem; + } + + return NULL; +} + + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLfree(MEM_CHUNK_POOL *_this,void *mem) +// return 0 if memory freed in this call +// else return mem value passed in +//-------------------------------------------------------------------------- +{ + MEM_CHUNK *header = Ptr_To_MEM_CHUNK(mem); + MEM_CHUNK_POOLFreeChunk(_this,header); +} + + +//-------------------------------------------------------------------------- +void *MEM_CHUNK_POOLrealloc(MEM_CHUNK_POOL *_this,void *oldmem, size_t newSize) +//-------------------------------------------------------------------------- +{ + MEM_CHUNK *oldheader; + MEM_CHUNK *NewHeader; + gsi_u32 OldSize; + char MemType; + + MP_ASSERT(newSize) + + if (!oldmem) + { + return MEM_CHUNK_POOLmalloc( _this, newSize,PTR_ALIGNMENT); + } + + + oldheader = Ptr_To_MEM_CHUNK(oldmem); + OldSize = MEM_CHUNKMemUsedGet(oldheader); + + if (newSize == OldSize) + return oldmem; + + if (newSize < OldSize ) + { + + if ((newSize + 2 * sizeof(MEM_CHUNK))> OldSize ) + { + // not enough room to create another chunk, can't shrink + return oldmem; + } + + // shrink it + MEM_CHUNKMemUsedSet(oldheader,newSize); + MEM_CHUNK_POOLSplitChunk(_this,oldheader, gsi_true); + return MEM_CHUNKMemPtrGet(oldheader); + } + else + { + // get a new chunk + MemType = MEM_CHUNKMemTypeGet(oldheader); + MEM_CHUNK_POOLFreeChunk(_this,oldheader); + NewHeader = MEM_CHUNK_POOLAllocChunk( _this,newSize,PTR_ALIGNMENT,gsi_false); + MEM_CHUNKMemTypeSet(NewHeader,MemType); + + memmove(MEM_CHUNKMemPtrGet(NewHeader),oldmem,OldSize); + + return MEM_CHUNKMemPtrGet(NewHeader); + } + +} + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLMEM_CHUNK_POOL(MEM_CHUNK_POOL *_this) +//-------------------------------------------------------------------------- +{ + _this->Name[0] = 0; + _this->HeaderEnd = NULL; + _this->HeaderStart = NULL; + _this->HeapSize = 0; + _this->pFirstFree = NULL; +} + + + + + +//-------------------------------------------------------------------------- +gsi_u32 MEM_CHUNK_POOLWalkForType(MEM_CHUNK_POOL *_this,int type, gsi_bool _LogUse) +//-------------------------------------------------------------------------- +{ + MEM_CHUNK *header; + gsi_u32 Total = 0; + header = _this->HeaderStart; + + while (header) + { + MP_ASSERT((header->next == NULL) || ((gsi_uint)header < (gsi_uint)header->next )) // infinite loop or out of place + MP_ASSERT((header->prev == NULL) || ((gsi_uint)header->prev < (gsi_uint)header )) // infinite loop or out of place + MP_ASSERT((header->prev == NULL) || (header->prev->next == header)) // previous linked correctly to us + MP_ASSERT((header->next == NULL) || (header->next->prev == header)) // next linked correctly to us + MP_ASSERT( MEM_CHUNKMemUsedGet(header) <= MEM_CHUNKChunkSizeGet(header) ) // using too much mem + + if (!MEM_CHUNKIsFree(header) && (MEM_CHUNKMemTypeGet(header) == type)) + { + //Don't log a message for the HeaderStart and HeaderEnd blocks. + if ((header != _this->HeaderStart) && (header != _this->HeaderEnd)) + { + // Used Chunk + Total += MEM_CHUNKTotalSizeGet(header); + if (_LogUse) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice,"MemFound ptr:0x%8x size:%8u %s\n", MEM_CHUNKMemPtrGet(header), + MEM_CHUNKMemUsedGet(header),MemMgrBufferGetName((gsMemMgrContext) type)); + } + } + + } + + // make sure we hit the correct end + MP_ASSERT (header->next || (header == _this->HeaderEnd)) + header = header->next; + + } + return Total; +} + + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLMemStatsGet(MEM_CHUNK_POOL *_this,MEM_STATS *pS) +{ + int ChunksFreeLostCount ; + int i,type; + MEM_CHUNK *header ; + MEM_CHUNK *NextFree; + MEM_STATSClear(pS); + + // check free chunk linked list + header = _this->HeaderStart; + NextFree = _this->pFirstFree; + + + + /*** Test validity of all chunks chain ***/ + while (header) + { + MP_ASSERT((header->next == NULL) || ((gsi_uint)header < (gsi_uint)header->next )) // infinite loop or out of place + MP_ASSERT((header->prev == NULL) || ((gsi_uint)header->prev < (gsi_uint)header )) // infinite loop or out of place + MP_ASSERT((header->prev == NULL) || (header->prev->next == header)) // previous linked correctly to us + MP_ASSERT((header->next == NULL) || (header->next->prev == header)) // next linked correctly to us + MP_ASSERT( MEM_CHUNKMemUsedGet(header) <= MEM_CHUNKChunkSizeGet(header) ) // using too much mem + + pS->MemTotal += MEM_CHUNKTotalSizeGet(header); + if (!MEM_CHUNKIsFree(header)) + { + // Used Chunk + pS->ChunksUsedCount++; + if (pS->ChunksUsedCount_At_HighWater < pS->ChunksUsedCount) + pS->ChunksUsedCount_At_HighWater = pS->ChunksUsedCount; + + // calc overhead and waste + pS->MemWasted += MEM_CHUNKTotalSizeGet(header) - MEM_CHUNKMemUsedGet(header); + pS->MemUsed += MEM_CHUNKTotalSizeGet(header); + + type = MEM_CHUNKMemTypeGet(header); + pS->MemType_MemUsed[type] += MEM_CHUNKTotalSizeGet(header); + pS->MemType_ChunksCount[type]++; + + } + else + { + // free chunk + MP_ASSERT((header->NextFree == NULL) || ((gsi_uint)header < (gsi_uint)header->NextFree )) // infinite loop or out of place + + // make sure we aren't fragmented, as this ruins some algorithm assumptions + MP_ASSERT((header->next == NULL) || (!MEM_CHUNKIsFree(header->next))) // infinite loop or out of place + MP_ASSERT((header->prev == NULL) || (!MEM_CHUNKIsFree(header->prev))) // infinite loop or out of place + + // previous free chunk linked correctly to us, we aren't a lost chunk + MP_ASSERT(header == NextFree) + NextFree = header->NextFree; + + // calc overhead and waste (in this case, the same value...sizeof(MEM_CHUNK) header) + pS->MemWasted += MEM_CHUNKTotalSizeGet(header) - MEM_CHUNKChunkSizeGet(header); + pS->MemUsed += MEM_CHUNKTotalSizeGet(header) - MEM_CHUNKChunkSizeGet(header); + + pS->ChunksFreeCount++; + if (pS->ChunksFreeLargestAvail < MEM_CHUNKChunkSizeGet(header)) + pS->ChunksFreeLargestAvail = MEM_CHUNKChunkSizeGet(header); + } + + pS->ChunksCount++; + + // make sure we hit the correct end + MP_ASSERT (header->next || (header == _this->HeaderEnd)) + header = header->next; + + } + + // Check free chunks + header = _this->HeaderStart; + + + /*** Test validity of free chunks chain ***/ + // Walk heap looking for first free chunk, + while(header && (!MEM_CHUNKIsFree(header))) + header = header->next; + + // make sure the first free one is linked correctly + MP_ASSERT(_this->pFirstFree == header) + + ChunksFreeLostCount = pS->ChunksFreeCount; + while (header) + { + // add up sizes + ChunksFreeLostCount --; + pS->MemAvail +=MEM_CHUNKChunkSizeGet(header); + header = header->NextFree; + + } + + + // Update stats + if (pS->MemUsed_At_HighWater < pS->MemUsed) + pS->MemUsed_At_HighWater = pS->MemUsed; + + for ( i=0;i< MEM_TYPES_MAX;i++ ) + { + if (pS->MemType_MemUsed_At_HighWater[i] < pS->MemType_MemUsed[i] ) + pS->MemType_MemUsed_At_HighWater[i] = pS->MemType_MemUsed[i]; + } + + MP_ASSERT(ChunksFreeLostCount == 0) // lost free blocks +} + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLCheckValidity(MEM_CHUNK_POOL *_this) +{ + MEM_STATS stats; + MEM_CHUNK_POOLMemStatsGet(_this,&stats); + +} + + +//-------------------------------------------------------------------------- +void MEM_CHUNK_POOLFillMemoryTable(MEM_CHUNK_POOL *_this,char *Table, const int TableSize, gsi_u32 _HeapStart, gsi_u32 _HeapSize) +//-------------------------------------------------------------------------- +{ + int s,e,j; + gsi_u32 start_address; + gsi_u32 end_address ; + MEM_CHUNK *pChunk = _this->HeaderStart; + MP_ASSERT(_this->HeapSize) + + + while (pChunk) + { + if (!MEM_CHUNKIsFree(pChunk)) + { + start_address = (gsi_uint)pChunk; + end_address = ((gsi_uint)pChunk->next)-1; + + // translate address into table positions + s= ((start_address - _HeapStart) * (TableSize>>4)) / (_HeapSize>>4); + MP_ASSERT(s < TableSize) + MP_ASSERT(s >= 0) + + e= (( end_address - _HeapStart) * (TableSize>>4)) / (_HeapSize>>4); + MP_ASSERT(e < TableSize) + MP_ASSERT(e >= 0) + + for ( j= s; j<= e; j++) + { + // if(Table[j] != -2) + // Table[j] = -1; + // else + Table[j] = MEM_CHUNKMemTypeGet(pChunk); + } + + } + pChunk = pChunk->next; + } + + +} + + + +static MEM_CHUNK_POOL gChunkPool [gsMemMgrContext_Count] ; + + + +// Use this to determine which pool and subsequent allocations will be taken from. +gsMemMgrContext gsMemMgrContextCurrent = gsMemMgrContext_Default; + +//static GSICriticalSection gMemCrit; + +//-------------------------------------------------------------------------- +gsMemMgrContext gsMemMgrContextFind (void *ptr) +// find pool corresponding to mem ptr. +{ + int i; + // find which pool owns this pointer!!!!, this is kind of a hack.... but here goes. + for (i=0; i< gsMemMgrContext_Count;i++) + { + if ( + MEM_CHUNK_POOLIsValid(&gChunkPool[i]) && + MEM_CHUNK_POOLItemIsInPoolMemory(&gChunkPool[i],ptr) + ) + { + return (gsMemMgrContext) i; + } + + } + return gsMemMgrContext_Invalid; +} + +void *gs_malloc(size_t size) +{ + GS_ASSERT(size) + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[gsMemMgrContextCurrent]),"malloc: context is invalid mempool"); + + return MEM_CHUNK_POOLmalloc(&gChunkPool[gsMemMgrContextCurrent], size,PTR_ALIGNMENT); +} + +void *gs_calloc(size_t size,size_t size2) +{ + GS_ASSERT(size) + GS_ASSERT(size2) + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[gsMemMgrContextCurrent]),"calloc: context is invalid mempool"); + + return MEM_CHUNK_POOLmalloc(&gChunkPool[gsMemMgrContextCurrent], size*size2,PTR_ALIGNMENT); +} + +void *gs_realloc(void* ptr,size_t size) +{ + GS_ASSERT(size) + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[gsMemMgrContextCurrent]),"realloc: context is invalid mempool"); + + return MEM_CHUNK_POOLrealloc(&gChunkPool[gsMemMgrContextCurrent],ptr, size); +} + +void *gs_memalign(size_t boundary,size_t size) +{ + GS_ASSERT(size) + GS_ASSERT(boundary) + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[gsMemMgrContextCurrent]),"memalign: context is invalid mempool"); + + return MEM_CHUNK_POOLmalloc(&gChunkPool[gsMemMgrContextCurrent], size,boundary); +} + +void gs_free(void *ptr) +{ + gsMemMgrContext context; + + context = gsMemMgrContextFind(ptr); + GS_ASSERT_STR(context != gsMemMgrContext_Invalid,"Attempt to free invalid ptr") + + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context]),"free: ptr context is invalid mempool"); + MEM_CHUNK_POOLfree(&gChunkPool[context],ptr); +} + +//-------------------------------------------------------------------------- +const char *MemMgrBufferGetName(gsMemMgrContext context) +{ + GS_ASSERT_STR(context != gsMemMgrContext_Invalid, "Invalid Context"); + GS_ASSERT_STR(context < gsMemMgrContext_Count, "Context out of range"); + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context ]),"Invalid mempool"); + + return gChunkPool[context].Name; +} + + +void gsMemMgrContextSet(gsMemMgrContext context) +{ + GS_ASSERT_STR(context != gsMemMgrContext_Invalid, "Invalid Context"); + GS_ASSERT_STR(context < gsMemMgrContext_Count, "Context out of range"); + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context]),"Setting context to invalid mempool"); + + gsMemMgrContextCurrent = context; +} + + + +//-------------------------------------------------------------------------- +// call this to enable GameSpy's provided memory manager +// Create a mem pool for the given context. If that context is in use, it will return the next available +// if none are available it will return gsMemMgrContext_Invalid +// ex use: gQR2MemContext = gsMemMgrCreate (0,0,16 * 1024); +// will find the first avaiable spot, create a mem pool of 16k, and return the context handle. +// then later in your API +// enter an API function +// gsMemMgrContextPush(gQR2MemContext); +// do some allocs +// gQR2MemContextPop() +// return from function. +gsMemMgrContext gsMemMgrCreate (gsMemMgrContext context, const char *PoolName,void* thePoolBuffer, size_t thePoolSize) +{ + char *ptr = (char *)thePoolBuffer; + + GS_ASSERT_STR(thePoolSize,"Cannnot create a pool of size 0") + GS_ASSERT_STR(thePoolSize,"thePoolBuffer ptr is inivalid"); + GS_ASSERT_STR(((((gsi_uint)thePoolSize) &15) ==0) ,"PoolSize must be aligned to 16 bytes"); + GS_ASSERT_STR(((((gsi_uint)thePoolBuffer)&15) ==0) ,"thePoolBuffer must be aligned to 16 bytes"); + + + while (MEM_CHUNK_POOLIsValid(&gChunkPool[context])) + { + context = (gsMemMgrContext)(context + 1); + } + if (context == gsMemMgrContext_Count) + { + // Warn!!!! + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "Out of memory context handles!\n"); + GS_ASSERT(0); + return gsMemMgrContext_Invalid; // ran out of context slots + } + + MEM_CHUNK_POOLCreate(&gChunkPool[context],PoolName,ptr,thePoolSize); + // Set call backs. + gsiMemoryCallbacksSet(gs_malloc, gs_free, gs_realloc, gs_memalign); + return context; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsMemMgrDestroy(gsMemMgrContext context) +{ + GS_ASSERT(gChunkPool[context].HeapSize != 0); + MEM_CHUNK_POOLDestroy(&gChunkPool[context]); + + // if this is the last one, +#if(0) + { + // Set call backs. + gsiMemoryCallbacksSet(malloc,free,realloc,memalign); + + // Reset memmgr + gsiDeleteCriticalSection(&gMemCrit); + + // #ifdef _GSI_MULTI_THREADED_ + // gsiLeaveCriticalSection(&gMemCrit); + // gsiEnterCriticalSection(&gMemCrit); + // #endif + } +#endif +} + + +//-------------------------------------------------------------------------- +void gsMemMgrTagPush (gsi_u8 tag) +{ + GS_ASSERT(MemTagStackIndex < MEM_TAG_STACK_MAX-1) + MemTagStackIndex++; + MemTagStack[MemTagStackIndex] = tag; +} +//-------------------------------------------------------------------------- +void gsMemMgrTagPop () +{ + GS_ASSERT(MemTagStackIndex > 0) + MemTagStackIndex--; +} +//-------------------------------------------------------------------------- +gsi_u8 gsMemMgrTagGet (void *ptr) +{ + GS_ASSERT(ptr); + return MEM_CHUNKMemTypeGet( Ptr_To_MEM_CHUNK(ptr)); +} +//-------------------------------------------------------------------------- +gsi_u32 gsMemMgrMemUsedByTagGet(gsi_u8 tag) +{ + int i; + gsi_u32 used = 0; + for ( i=0;i< gsMemMgrContext_Count;i++) + { + used+= MEM_CHUNK_POOLWalkForType(&gChunkPool[i] ,tag, gsi_false); + } + return used; + +} + +//-------------------------------------------------------------------------- +void gsMemMgrContextPush(gsMemMgrContext NewType) +{ +// PARANOID_MemProfilerCheck(); + GS_ASSERT(MemTypeStackIndex < MEM_CONTEXT_STACK_MAX) + GS_ASSERT(NewType < gsMemMgrContext_Count) + +// gsDebugFormat(GSIDebugCat_App, GSIDebugType_State, GSIDebugLevel_Comment,"MemProfilerStart: %s\n",MemProfiler.MemPool[NewType].Name); + MemTypeStack[MemTypeStackIndex++] = gsMemMgrContextCurrent; + gsMemMgrContextCurrent = NewType; +} + +//-------------------------------------------------------------------------- +gsMemMgrContext gsMemMgrContextPop() +{ +// PARANOID_MemProfilerCheck(); + GS_ASSERT(MemTypeStackIndex > 0) +// gsDebugFormat(GSIDebugCat_App, GSIDebugType_State, GSIDebugLevel_Comment,"MemProfilerEnd: %s\n",MemProfiler.MemPool[OldType].Name); + gsMemMgrContextCurrent = MemTypeStack[--MemTypeStackIndex]; + return gsMemMgrContextCurrent; +} + + +//-------------------------------------------------------------------------- +// return total available memory for the given memory pool +gsi_u32 gsMemMgrMemAvailGet (gsMemMgrContext context) +{ + MEM_STATS stats; + MEM_STATSClearAll(&stats); + GS_ASSERT_STR(context < gsMemMgrContext_Count, "gsMemMgrMemAvailGet: context out of range"); + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context]), "gsMemMgrMemAvailGet: context is invalid mempool"); + MEM_CHUNK_POOLMemStatsGet (&gChunkPool[context], &stats); + return stats.MemAvail; +} + +//-------------------------------------------------------------------------- +// return total used memory for the given memory pool +gsi_u32 gsMemMgrMemUsedGet (gsMemMgrContext context) +{ + MEM_STATS stats; + MEM_STATSClearAll(&stats); + GS_ASSERT_STR(context < gsMemMgrContext_Count, "gsMemMgrMemUsedGet: context out of range"); + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context]), "gsMemMgrMemUsedGet: context is invalid mempool"); + MEM_CHUNK_POOLMemStatsGet (&gChunkPool[context], &stats); + return stats.MemUsed; +} + + +//-------------------------------------------------------------------------- +// return largest allocatable chunk the given memory pool. This +// will be the same or probably smaller then the value returned by gsMemMgrMemAvailGet +// depending on degree of memory fragmentation. +gsi_u32 gsMemMgrMemLargestAvailGet (gsMemMgrContext context) +{ + MEM_STATS stats; + MEM_STATSClearAll(&stats); + GS_ASSERT_STR(context < gsMemMgrContext_Count, "gsMemMgrMemLargestAvailGet: context out of range"); + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context]), "gsMemMgrMemLargestAvailGet: context is invalid mempool"); + MEM_CHUNK_POOLMemStatsGet (&gChunkPool[context], &stats); + return stats.ChunksFreeLargestAvail; +} + +//-------------------------------------------------------------------------- +gsi_u32 gsMemMgrMemHighwaterMarkGet (gsMemMgrContext context) +{ + GS_ASSERT_STR(context < gsMemMgrContext_Count, "gsMemMgrMemLargestAvailGet: context out of range"); + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[context]), "gsMemMgrMemLargestAvailGet: context is invalid mempool"); + + #if(MEM_PROFILE) + return gChunkPool[context].HWMemUsed; + #else + // Display info - App type b/c it was requested by the app + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "gsMemMgrMemHighwaterMarkGet called without MEM_PROFILE enabled."); + return 0; + #endif +} + +//-------------------------------------------------------------------------- +void gsMemMgrValidateMemoryPool() +{ + GS_ASSERT_STR(MEM_CHUNK_POOLIsValid(&gChunkPool[gsMemMgrContextCurrent]),"memalign: context is invalid mempool"); + MEM_CHUNK_POOLCheckValidity(&gChunkPool[gsMemMgrContextCurrent]); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Show allocated, free, total memory, num blocks +void gsMemMgrDumpStats() +{ +#if(0) + int numUsed = 0; + int numFree = 0; + + struct GSIMemoryBlock* aTempPtr = NULL; + + gsiEnterCriticalSection(&gMemCrit); + + // Display the number of free blocks + // TODO: dump size statistics + aTempPtr = gMemoryMgr->mFirstFreeBlock; + while(aTempPtr != NULL) + { + numFree++; + aTempPtr = aTempPtr->mNext; + } + + // Display the number of used blocks + // TODO: dump size statistics + aTempPtr = gMemoryMgr->mFirstUsedBlock; + while(aTempPtr != NULL) + { + numUsed++; + aTempPtr = aTempPtr->mNext; + } + + // Display info - App type b/c it was requested by the app + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "BytesUsed: %d, BlocksUsed: %d, BlocksFree: %d\r\n", + gMemoryMgr->mMemUsed, numUsed, numFree); + + gsiLeaveCriticalSection(&gMemCrit); +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsMemMgrDumpAllocations() +{ +#if(0) + struct GSIMemoryBlock* aBlockPtr = NULL; + gsi_time aStartTime = 0; + gsi_i32 aNumAllocations = 0; + gsi_i32 aNumBytesAllocated = 0; + + gsiEnterCriticalSection(&gMemCrit); + + aStartTime = current_time(); + aBlockPtr = (GSIMemoryBlock*)gMemoryMgr->mPoolStart; + + // Announce start + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "Dumping allocations from pool - [0x%08x] %d bytes.\r\n", + gMemoryMgr->mPoolStart, gMemoryMgr->mPoolSize); + + // Dump information about each allocated block + // - Do this in linear order, not list order + while(aBlockPtr != NULL) + { + // If it's in use, verify contents and dump info + if (gsiMemBlockIsFlagged(aBlockPtr, BlockFlag_Used)) + { + int anObjectSize = gsiMemBlockGetObjectSize(aBlockPtr); + aNumAllocations++; + aNumBytesAllocated += anObjectSize; + + if (aBlockPtr == gMemoryMgr->mPoolStart) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "\t[0x%08x] Size: %d (memmgr instance)\r\n", (gsi_u32)aBlockPtr, anObjectSize); + } + else + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "\t[0x%08x] Size: %d\r\n", (gsi_u32)(gsiMemBlockGetObjectPtr(aBlockPtr)), anObjectSize); + } + } + else + { + // Verify that the block has the correct memory fill + } + // Get linear next (not list next!) + aBlockPtr = gsiMemBlockGetLinearNext(aBlockPtr); + } + + // Announce finish + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "\t--%d allocations, %d bytes allocated.\r\n", aNumAllocations, aNumBytesAllocated); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "\t--%d peak memory usage\r\n", gMemoryMgr->mPeakMemoryUsage); + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Memory, GSIDebugLevel_Comment, + "Memory dump complete. (%d ms)\r\n", current_time() - aStartTime); + + gsiLeaveCriticalSection(&gMemCrit); + + GSI_UNUSED(aStartTime); // may be unused if common debug is not defined +#endif +} + + + +#if (1) // test stuff + +#define PTR_TABLE_SIZE 2048 +static int PtrTableCount = 0; +static void *PtrTable[2048]; + +int Random(int x) +{ + return Util_RandInt(0,x); +} +//-------------------------------------------------------------------------- +void gsMemMgrSelfText() +//-------------------------------------------------------------------------- +{ + + + static MEM_CHUNK_POOL gChunkPool; + int size = 32 * 1024 * 1024; + int c= 0; + int i,j,k; + + char *ptr = (char *) ( ((gsi_uint)malloc(size-PTR_ALIGNMENT)+(PTR_ALIGNMENT-1))&~ (PTR_ALIGNMENT-1) ) ; + MEM_CHUNK_POOLCreate(&gChunkPool,"",ptr,size); + + while(1) + { + + i= Random(4); + if ((i==0) &&(PtrTableCount < 1024)) + { + // malloc + j = Random(1024)+1; + k = 32<< (Random(4)); + + if (c&1) + PtrTable[PtrTableCount] = MEM_CHUNK_POOLmalloc(&gChunkPool, j,k); + else + PtrTable[PtrTableCount] = MEM_CHUNK_POOLmalloc_backwards(&gChunkPool, j,k); + + if(PtrTable[PtrTableCount]) + { + PtrTableCount++; + } + else + { + GS_ASSERT(0); + } + + } + else + if ((i==1) &&(PtrTableCount)) + { + // free + j = Random(PtrTableCount); + MP_ASSERT(j < PtrTableCount) + + + MEM_CHUNK_POOLfree(&gChunkPool,PtrTable[j]); + + // swap with last. + PtrTableCount--; + PtrTable[j] = PtrTable[PtrTableCount]; + + } + else + if ((i==2) &&(PtrTableCount)) + { + j = Random(PtrTableCount); + MP_ASSERT(j < PtrTableCount) + + // realloc + k = Random(1024) +1; + #if(1) + PtrTable[j] = MEM_CHUNK_POOLrealloc(&gChunkPool,PtrTable[j], k); + #else + // skip + PtrTable[j] = PtrTable[j]; + #endif + + if(PtrTable[j]) + { + } + else + { + GS_ASSERT(0); + } + + } + else + continue; // skip count + + c++; + MEM_CHUNK_POOLCheckValidity(&gChunkPool); + } + +} + + +#endif + + + + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // GSI_MEM_MANAGED + diff --git a/xrGameSpy/gamespy/common/gsMemory.h b/xrGameSpy/gamespy/common/gsMemory.h new file mode 100644 index 00000000000..c68e0eda214 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsMemory.h @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSIMEMORY_H__ +#define __GSIMEMORY_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCommon.h" + +// GameSpy allocation wrappers. Used for quickly adding pre-post allocation functionality such as +// - routing to a specific mempool +// - collecting mem usage stats +// (x) is a enumerated type for the specific module +#if(1) + #define GSI_PRE_ALLOC(x) + #define GSI_POST_ALLOC() +#elif(0) + // - collecting mem usage stats + #define GSI_PRE_ALLOC(x) gsMemMgrTagPush (x); + #define GSI_POST_ALLOC() gsMemMgrTagPop (); +#elif(0) + // - routing to a specific mempool + #define GSI_PRE_ALLOC(x) gsMemMgrContextPush (x); + #define GSI_POST_ALLOC() gsMemMgrContextPop (); +#endif + +#if defined (__cplusplus) +extern "C" +{ +#endif + + +typedef enum +{ + MEMTAG_DEFAULT, + MEMTAG_SERVER_BROWSER, + MEMTAG_PEER, + MEMTAG_GP, + MEMTAG_QR2, + MEMTAG_NN, + MEMTAG_GT2, + MEMTAG_COUNT +} MEMTAG_SDK; + +//-------------------------------------------------------------------------- +// GameSpy specific memory functions. By default these will route to system malloc +// calls. Use gsiMemoryCallbacksSet or gsiMemoryCallbacksGameSpySet to change this. +void* gsimalloc (size_t size); +void* gsirealloc (void* ptr, size_t size); +void gsifree (void* ptr); +void* gsimemalign (size_t boundary, size_t size); // TODO + +//-------------------------------------------------------------------------- +// Customer supplied memory manager customization interface +// call this to replace the Gamespy specific memory functions with your own. +#ifdef WIN32 +typedef void *(__cdecl *gsMallocCB) (size_t size); +typedef void (__cdecl *gsFreeCB) (void* ptr); +typedef void *(__cdecl *gsReallocCB) (void* ptr, size_t size); +typedef void *(__cdecl *gsMemalignCB)(size_t boundary, size_t size); +#else +typedef void *(*gsMallocCB) (size_t size); +typedef void (*gsFreeCB) (void* ptr); +typedef void *(*gsReallocCB) (void* ptr, size_t size); +typedef void *(*gsMemalignCB)(size_t boundary, size_t size); +#endif +// call this to override above gsi.... calls with your own. +void gsiMemoryCallbacksSet(gsMallocCB p_malloc, gsFreeCB p_free, gsReallocCB p_realloc, gsMemalignCB p_memalign); + +//-------------------------------------------------------------------------- +// GameSpy Built in Memory Manager +// call this to override above gsi.... calls with GameSpy's built in memory manager +// *** You must have GSI_MEM_MANAGED defined, otherwise, you will have a link error ***/ + +// This is a list of memory pools used. API specific values determined at run time. +// the gsi mem manager uses the concept of multiple memory pools or contexts. +// use pop and push commands to pop and push the current context off of the stack + +typedef enum +{ + gsMemMgrContext_Invalid= -1, + gsMemMgrContext_Default= 0, + gsMemMgrContext_Count = 16 // max number of mempools +}gsMemMgrContext; + + +// call this to enable GameSpy's provided memory manager +// Create a mempool for the given context. If that context is in use, it will return the next available +// if none are avaible it will return gsMemMgrContext_Invalid +// exx use: gQR2MemContext = gsMemMgrCreate (0,0,16 * 1024); +// will find the first avaiable spot, create a mempool of 16k, and return the context handle. +// then later in your API +// enter an API function +// gsMemMgrContextPush(gQR2MemContext); +// do some allocs +// gQR2MemContextPop() +// return from function. +// PoolName is purely for debugging and stats feedback purposes only. +// If you want your api to use the current, or the default pool, then don't bother creating one +// just always set the context to 0, and make sure int your app init, the default (0) pool is created. +/* + Recommended usage: + Call gsMemMgrCreate once at app start with a static buffer. Make all calls to this. + Alternatively, call it once per API to sue a seperate pool per API. +*/ +gsMemMgrContext gsMemMgrCreate (gsMemMgrContext context, const char *PoolName,void* thePoolBuffer, size_t thePoolSize); + +// Use this to determine which pool and subsequent allocations will be taken from. +//exx use +/* + fn() + { + gsMemMgrContextPush(thisAPIContext); + + make allocations. + + //restore settings + gsMemMgrContextPop(thisAPIContext); + + } +*/ +// note, this is not neccessary for "free". +void gsMemMgrContextPush (gsMemMgrContext context); +gsMemMgrContext gsMemMgrContextPop (); + + +// clear contents, original mempool ptr must still be freed by app. +void gsMemMgrDestroy(gsMemMgrContext context); + +// -------------Diagnostics------------------------ +// These functions all run on the current mempool context. +void gsMemMgrDumpStats(); +void gsMemMgrDumpAllocations(); +void gsMemMgrValidateMemoryPool(); // walk heap and check integrity + +// -------------Tool use ------------------------ +// find which mempool context this ptr is part of, if any. +// returns gsMemMgrContext_Invalid otherwise. +gsMemMgrContext gsMemMgrContextFind (void *ptr); +const char *MemMgrBufferGetName(gsMemMgrContext context); + + +// -------------Memory Use Profiling ------------------------ +// this tag is added to each concurrent alloc. Use this to reference allocations. +// For example, you can find out the mem used by all ptr with a given tag +// in order to find out how much mem a module or set of allocs use. +void gsMemMgrTagPush (gsi_u8 tag); +void gsMemMgrTagPop (); +gsi_u8 gsMemMgrTagGet (void *ptr); +gsi_u32 gsMemMgrMemUsedByTagGet(gsi_u8 tag); + +// return total available memory for the given memory pool context +gsi_u32 gsMemMgrMemAvailGet (gsMemMgrContext context); +// return total used memory for the given memory pool context +gsi_u32 gsMemMgrMemUsedGet (gsMemMgrContext context); +// return largest allocatable chunk within the given memory pool context. This +// will be the same or probably smaller then the value returned by gsMemMgrMemAvailGet +// depending on degree of memory fragmentation. +gsi_u32 gsMemMgrMemLargestAvailGet (gsMemMgrContext context); + +// The Highwater mark for memory used is the highest memory usage ever gets to for this +// given heap. It is the most important stat, as your mempool must be at least this big. +// Exactly how big your pool needs to be depends on fragmentation. So it may need to be slightly +// bigger then this amount. +gsi_u32 gsMemMgrMemHighwaterMarkGet (gsMemMgrContext context); + + +// -------------Self Test, not for production use ------------------------ +void gsMemMgrSelfText(); + +#if defined (__cplusplus) +} +#endif + +#endif // __GSIMEMORY_H__ + diff --git a/xrGameSpy/gamespy/common/gsPlatform.c b/xrGameSpy/gamespy/common/gsPlatform.c new file mode 100644 index 00000000000..ee4888f8d52 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatform.c @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsPlatform.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Include standard network lib +#if defined(_WIN32) && !defined(_XBOX) + #if defined(GSI_WINSOCK2) + #pragma comment(lib, "ws2_32") + #else + #pragma comment(lib, "wsock32") + #endif + #pragma comment(lib, "advapi32") +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Floating point specific byte reversal functions +// stores the result in a 4-byte character array +unsigned char * gsiFloatSwap(unsigned char buf[4], float f) +{ + unsigned char *dst = (unsigned char *)buf; + unsigned char *src = (unsigned char *)&f; + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + + return buf; +} + +// unswap using char pointers +float gsiFloatUnswap(unsigned char buf[4]) +{ + float f; + unsigned char *src = (unsigned char *)buf; + unsigned char *dst = (unsigned char *)&f; + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + + return f; +} + +gsi_u16 gsiByteOrderSwap16(gsi_u16 _in) +{ + gsi_u16 t; + const char *in = (char *)&_in; + char *out = (char *)&t; + out[0] = in[1]; + out[1] = in[0]; + return t; +} + +gsi_u32 gsiByteOrderSwap32(gsi_u32 _in) +{ + gsi_u32 t; + const char *in = (char *)&_in; + char *out = (char *)&t; + out[0] = in[3]; + out[1] = in[2]; + out[2] = in[1]; + out[3] = in[0]; + return t; +} + +gsi_u64 gsiByteOrderSwap64(gsi_u64 _in) +{ + gsi_u64 t; + const char *in = (char *)&_in; + char *out = (char *)&t; + out[0] = in[7]; + out[1] = in[6]; + out[2] = in[5]; + out[3] = in[4]; + out[4] = in[3]; + out[5] = in[2]; + out[6] = in[1]; + out[7] = in[0]; + return t; +} + diff --git a/xrGameSpy/gamespy/common/gsPlatform.h b/xrGameSpy/gamespy/common/gsPlatform.h new file mode 100644 index 00000000000..a4daf16ebb4 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatform.h @@ -0,0 +1,487 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSPLATFORM_H__ +#define __GSPLATFORM_H__ + +// GameSpy platform definition and headers + +// Windows: _WIN32 +// Xbox: _WIN32 + _XBOX +// Xbox360: _WIN32 + _XBOX + _X360 +// MacOSX: _MACOSX + _UNIX +// Linux: _LINUX + _UNIX +// Nintendo DS: _NITRO +// PSP: _PSP +// PS3: _PS3 + +// PlayStation2: _PS2 +// w/ EENET: EENET (set by developer project) +// w/ INSOCK: INSOCK (set by developer project) +// w/ SNSYSTEMS: SN_SYSTEMS (set by developer project) +// Codewarrior: __MWERKS__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Set the platform define +#ifdef __mips64 + #ifndef _PS2 + #define _PS2 + #endif + + // Make sure a network stack was defined + #if !defined(SN_SYSTEMS) && !defined(EENET) && !defined(INSOCK) + #error "PlayStation2 network stack was not defined!" + #endif +#endif + +#if defined(_LINUX) || defined(_MACOSX) + #define _UNIX +#endif + +#if defined(_XBOX) || defined (_X360) +#if _XBOX_VER >= 200 + #define _X360 +#endif +#endif + +// WIN32, set by OS headers +// _XBOX, set by OS headers +// __MWERKS__, set by compiler +// _NITRO, set by OS headers + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Include common OS headers +#include +#include +#include +#include + + +// XBOX/X360 +#if defined(_XBOX) + #include + +// WIN32 +#elif defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include + #include + #include + + #if defined(GSI_WINSOCK2) + #include + #else + #include + #endif + + #if (_MSC_VER > 1300) + #define itoa(v, s, r) _itoa(v, s, r) + #endif +// PS2 +#elif defined(_PS2) + // EENet headers must be included before common PS2 headers + #ifdef EENET + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #endif // EENET + + // Common PS2 headers + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #ifdef SN_SYSTEMS + // undefine socket defines from sys/types.h + // This is to workaround sony now automatically including sys/types.h + // and SNSystems having not produce a patch yet (they'll likely do the same since + // the SNSystems fd_set is a slightly different size than the sys/types.h. + #undef FD_CLR + #undef FD_ZERO + #undef FD_SET + #undef FD_ISSET + #undef FD_SETSIZE + #undef fd_set + #include "snskdefs.h" + #include "sntypes.h" + #include "snsocket.h" + #include "sneeutil.h" + #include "sntcutil.h" + #endif // SN_SYSTEMS + + #ifdef INSOCK + #include "libinsck.h" + #include "libnet.h" + #include "sys/errno.h" + //#include "libmrpc.h" + #endif // INSOCK + +// LINUX and MACOSX +#elif defined(_UNIX) + #include + #include + #include + #include + #include + #include + #include + #include + + // MACOSX Warning!! netdb.h has it's own NOFILE define. + // GameSpy uses NOFILE to determine if an HD is available + #ifndef NOFILE + // Since GameSpy NOFILE is not defined, include netdb.h then undef NOFILE + #include + #undef NOFILE + #else + // Otherwise leave NOFILE defined + #include + #endif + + #include + #include + #include + #include + //#include + #include + + // ICMP ping support is unsupported on Linux/MacOSX due to needing super-user access for raw sockets + #define SB_NO_ICMP_SUPPORT + +// Nintendo DS +#elif defined(_NITRO) + #include + #define NINET_NWBASE_MD5_H_ // resolves md5 conflicts + #include + #include // mwerks + #include + + // Raw sockets are undefined on Nitro + #define SB_NO_ICMP_SUPPORT + +// Sony PSP +#elif defined(_PSP) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include +// PS3 +#elif defined(_PS3) +#include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +// #include + #include + #include + +// Nintendo Wii +#elif defined(_REVOLUTION) + #include + #include + #include + #include + + // Raw sockets are undefined on Revolution + #define SB_NO_ICMP_SUPPORT + +// Unsupported platform or no platform defined! +#else + #error "The GameSpy SDKs do not support this operating system" + +#endif //(platform switch) + + + +//---------- __cdecl fix for __fastcall conventions ---------- +#if defined(_WIN32) + #define GS_STATIC_CALLBACK __cdecl +#else + #define GS_STATIC_CALLBACK +#endif + + +//---------- Handle Endianess ---------------------- +#if defined(_PS3) || defined(_REVOLUTION) || defined(_X360) //defined(_MACOSX) + #define GSI_BIG_ENDIAN +#endif +#ifndef GSI_BIG_ENDIAN + #define GSI_LITTLE_ENDIAN +#endif + + + +#include + +#if defined(_MACOSX) + #undef _T +#endif + +#include + +#if defined(GS_NO_FILE) || defined(_PS2) || defined(_PS3) || defined(_NITRO) || defined(_PSP) || defined(_XBOX) + #define NOFILE +#endif + +#if defined(_PSP) || defined(_NITRO) + #define GS_WIRELESS_DEVICE +#endif + +#if !defined(GSI_DOMAIN_NAME) + #define GSI_DOMAIN_NAME "gamespy.com" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Define GameSpy types + +// common base type defines, please refer to ranges below when porting +typedef char gsi_i8; +typedef unsigned char gsi_u8; +typedef short gsi_i16; +typedef unsigned short gsi_u16; +typedef int gsi_i32; +typedef unsigned int gsi_u32; +typedef unsigned int gsi_time; // must be 32 bits + +// decprecated +typedef gsi_i32 goa_int32; // 2003.Oct.04.JED - typename deprecated +typedef gsi_u32 goa_uint32; // these types will be removed once all SDK's are updated + +typedef int gsi_bool; +#define gsi_false ((gsi_bool)0) +#define gsi_true ((gsi_bool)1) +#define gsi_is_false(x) ((x) == gsi_false) +#define gsi_is_true(x) ((x) != gsi_false) + +// Max integer size +#if defined(_INTEGRAL_MAX_BITS) && !defined(GSI_MAX_INTEGRAL_BITS) + #define GSI_MAX_INTEGRAL_BITS _INTEGRAL_MAX_BITS +#else + #define GSI_MAX_INTEGRAL_BITS 32 +#endif + +// Platform dependent types +#ifdef _PS2 + typedef signed long gsi_i64; + typedef unsigned long gsi_u64; +#elif defined(_WIN32) + #if (!defined(_M_IX86) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64)) + typedef __int64 gsi_i64; + typedef unsigned __int64 gsi_u64; + #endif +#elif defined(_NITRO) + typedef s64 gsi_i64; + typedef u64 gsi_u64; +#elif defined (_PSP) + typedef long long gsi_i64; + typedef unsigned long long gsi_u64; +#elif defined (_PS3) + typedef int64_t gsi_i64; + typedef uint64_t gsi_u64; +#elif defined (_REVOLUTION) + typedef signed long long gsi_i64; + typedef unsigned long long gsi_u64; +#else /* _UNIX */ + typedef long long gsi_i64; + typedef unsigned long long gsi_u64; +#endif // 64 bit types + +#ifndef GSI_UNICODE + #define gsi_char char +#else + #define gsi_char unsigned short +#endif // goa_char + + +// expected ranges for integer types +#define GSI_MIN_I8 CHAR_MIN +#define GSI_MAX_I8 CHAR_MAX +#define GSI_MAX_U8 UCHAR_MAX + +#define GSI_MIN_I16 SHRT_MIN +#define GSI_MAX_I16 SHRT_MAX +#define GSI_MAX_U16 USHRT_MAX + +#define GSI_MIN_I32 INT_MIN +#define GSI_MAX_I32 INT_MAX +#define GSI_MAX_U32 UINT_MAX + +#if (GSI_MAX_INTEGRAL_BITS >= 64) +#define GSI_MIN_I64 (-9223372036854775807 - 1) +#define GSI_MAX_I64 9223372036854775807 +#define GSI_MAX_U64 0xffffffffffffffffui64 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Common platform string functions +#undef _vftprintf +#undef _ftprintf +#undef _stprintf +#undef _tprintf +#undef _tcscpy +#undef _tcsncpy +#undef _tcscat +#undef _tcslen +#undef _tcschr +#undef _tcscmp +#undef _tfopen +#undef _T +#undef _tsnprintf + +#ifdef GSI_UNICODE + #define _vftprintf vfwprintf + #define _ftprintf fwprintf + #define _stprintf swprintf + #define _tprintf wprintf + #define _tcscpy wcscpy + #define _tcsncpy(d, s, l) wcsncpy((wchar_t *)d, (wchar_t *)s, l) + #define _tcscat wcscat + #define _tcslen wcslen + #define _tcschr wcschr + #define _tcscmp(s1, s2) wcscmp((wchar_t *)s1, (wchar_t *)s2) + #define _tfopen _wfopen + #define _T(a) L##a + + #if defined(_WIN32) || defined(_PS2) + #define _tsnprintf _snwprintf + #else + #define _tsnprintf swprintf + #endif +#else + #define _vftprintf vfprintf + #define _ftprintf fprintf + #define _stprintf sprintf + #define _tprintf printf + #define _tcscpy strcpy + #define _tcsncpy strncpy + #define _tcscat strcat + #define _tcslen strlen +#if defined (_MSC_VER) +#if (_MSC_VER < 1400) + #define _tcschr strchr +#endif +#else + #define _tcschr strchr +#endif + #define _tcscmp strcmp + #define _tfopen fopen +#ifndef _T + #define _T(a) a +#endif + + #if defined(_WIN32) + #define _tsnprintf _snprintf + #else + #define _tsnprintf snprintf + #endif +#endif // GSI_UNICODE + +#if defined(_WIN32) + #define snprintf _snprintf +#endif // _WIN32 + +#if defined(_WIN32) + #define strcasecmp _stricmp + #define strncasecmp _strnicmp +#endif + +#if !defined(_WIN32) + char *_strlwr(char *string); + char *_strupr(char *string); +#endif + +char * goastrdup(const char *src); +unsigned short * goawstrdup(const unsigned short *src); + + +// ------ Cross Plat Alignment macros ------------ +/* ex use +PRE_ALIGN(16) struct VECTOR +{ + float x,y,z,_unused; +} POST_ALIGN(16); + +// another example when defining a variable: +PRE_ALIGN(16); +static char _mempool[MEMPOOL_SIZE] POST_ALIGN(16); + +*/ +#if defined _WIN32 + #define PRE_ALIGN(x) __declspec(align(x)) // ignore Win32 directive + #define POST_ALIGN(x) // ignore +#elif defined (_PS2) || defined (_PSP) || defined (_PS3) + #define PRE_ALIGN(x) // ignored this on psp/ps2 + #define POST_ALIGN(x) __attribute__((aligned (x))) // +#elif defined (_REVOLUTION) + #define PRE_ALIGN(x) // not needed + #define POST_ALIGN(x) __attribute__((aligned(32))) +#else + // #warning "Platform not supported" + #define PRE_ALIGN(x) // ignore + #define POST_ALIGN(x) // ignore +#endif + +#define DIM( x ) ( sizeof( x ) / sizeof((x)[ 0 ])) + +unsigned char * gsiFloatSwap(unsigned char buf[4], float); +float gsiFloatUnswap(unsigned char buf[4]); +extern gsi_u16 gsiByteOrderSwap16(gsi_u16); +extern gsi_u32 gsiByteOrderSwap32(gsi_u32); +extern gsi_u64 gsiByteOrderSwap64(gsi_u64); + + +#ifdef __cplusplus +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __GSPLATFORM_H__ + diff --git a/xrGameSpy/gamespy/common/gsPlatformSocket.c b/xrGameSpy/gamespy/common/gsPlatformSocket.c new file mode 100644 index 00000000000..a5b2aff877a --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatformSocket.c @@ -0,0 +1,684 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsPlatformSocket.h" +#include "gsPlatformUtil.h" +#include "gsMemory.h" + +// mj-ToDo: remove these and include the files int the linker instead. +// removing reference to other platforms. +// remove all plat specific code from here, move it to the platspecific files. + +// Include platform separated functions +#if defined(_X360) + #include "x360/gsSocketX360.c" +#elif defined(_XBOX) + #include "xbox/gsSocketXBox.c" +#elif defined(_WIN32) + #include "win32/gsSocketWin32.c" +#elif defined(_LINUX) + //#include "linux/gsSocketLinux.c" +#elif defined(_MACOSX) + //#include "macosx/gsSocketMacOSX.c" +#elif defined(_NITRO) + #include "nitro/gsSocketNitro.c" +#elif defined(_PS2) + #include "ps2/gsSocketPs2.c" +#elif defined(_PS3) + #include "ps3/gsSocketPs3.c" + #include +#elif defined(_PSP) + #include "psp/gsSocketPSP.c" +#elif defined(_REVOLUTION) + #include "revolution/gsSocketRevolution.c" +#else + #error "Missing or unsupported platform" +#endif + + +// Disable compiler warnings for issues that are unavoidable. +///////////////////////////////////////////////////////////// +#if defined(_MSC_VER) // DevStudio + // Level4, "conditional expression is constant". + // Occurs with use of the MS provided macro FD_SET + #pragma warning ( disable: 4127 ) +#endif // _MSC_VER + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int SetSockBlocking(SOCKET sock, int isblocking) +{ + int rcode; + +#if defined(_REVOLUTION) + int val; + + val = SOFcntl(sock, SO_F_GETFL, 0); + + if(isblocking) + val &= ~SO_O_NONBLOCK; + else + val |= SO_O_NONBLOCK; + + rcode = SOFcntl(sock, SO_F_SETFL, val); +#elif defined(_NITRO) + int val; + + val = SOC_Fcntl(sock, SOC_F_GETFL, 0); + + if(isblocking) + val &= ~SOC_O_NONBLOCK; + else + val |= SOC_O_NONBLOCK; + + rcode = SOC_Fcntl(sock, SOC_F_SETFL, val); +#else + #if defined(_PS2) || defined(_PS3) + // EENet requires int + // SNSystems requires int + // Insock requires int + // PS3 requires int + gsi_i32 argp; + #else + unsigned long argp; + #endif + + if(isblocking) + argp = 0; + else + argp = 1; + + #ifdef _PS2 + #ifdef SN_SYSTEMS + rcode = setsockopt(sock, SOL_SOCKET, (isblocking) ? SO_BIO : SO_NBIO, &argp, sizeof(argp)); + #endif + + #ifdef EENET + rcode = setsockopt(sock, SOL_SOCKET, SO_NBIO, &argp, sizeof(argp)); + #endif + + #ifdef INSOCK + if (isblocking) + argp = -1; + else + argp = 5; //added longer timeout to 5ms + sceInsockSetRecvTimeout(sock, argp); + sceInsockSetSendTimeout(sock, argp); + sceInsockSetShutdownTimeout(sock, argp); + GSI_UNUSED(sock); + rcode = 0; + #endif + #elif defined(_PSP) + rcode = setsockopt(sock, SCE_NET_INET_SOL_SOCKET, SCE_NET_INET_SO_NBIO, &argp, sizeof(argp)); + #elif defined(_PS3) + rcode = setsockopt(sock, SOL_SOCKET, SO_NBIO, &argp, sizeof(argp)); + #else + rcode = ioctlsocket(sock, FIONBIO, &argp); + #endif +#endif + + if(rcode == 0) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "SetSockBlocking: Set socket %d to %s\r\n", (unsigned int)sock, isblocking ? "blocking":"non-blocking"); + return 1; + } + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "SetSockBlocking failed: tried to set socket %d to %s\r\n", (unsigned int)sock, isblocking ? "blocking":"non-blocking"); + return 0; +} + +int SetSockBroadcast(SOCKET sock) +{ +#if !defined(INSOCK) && !defined(_NITRO) && !defined(_REVOLUTION) + int optval = 1; + if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0) + return 0; +#else + GSI_UNUSED(sock); +#endif + + return 1; +} + +int DisableNagle(SOCKET sock) +{ +#if defined(_WIN32) || defined(_UNIX) + int rcode; + int noDelay = 1; + + rcode = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(int)); + return gsiSocketIsError(rcode); +#else + GSI_UNUSED(sock); + + // not supported + return 0; +#endif // moved this to here to silence VC warning +} + + +#ifndef INSOCK + int SetReceiveBufferSize(SOCKET sock, int size) + { + int rcode; + rcode = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char *)&size, sizeof(int)); + return gsiSocketIsNotError(rcode); + } + + int SetSendBufferSize(SOCKET sock, int size) + { + int rcode; + rcode = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char *)&size, sizeof(int)); + return gsiSocketIsNotError(rcode); + } + + int GetReceiveBufferSize(SOCKET sock) + { + int rcode; + int size; + int len; + + len = sizeof(size); + + rcode = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, &len); + + if(gsiSocketIsError(rcode)) + return -1; + + return size; + } + + int GetSendBufferSize(SOCKET sock) + { + int rcode; + int size; + int len; + + len = sizeof(size); + + rcode = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, &len); + + if(gsiSocketIsError(rcode)) + return -1; + + return size; + } + + // Formerly known as ghiSocketSelect +#ifdef SN_SYSTEMS + #undef FD_SET + #define FD_SET(s,p) ((p)->array[((s) - 1) >> SN_FD_SHR] |= \ + (unsigned int)(1 << (((s) - 1) & SN_FD_BITS)) ) + +#endif +#endif + +#if !defined(_NITRO) && !defined(INSOCK) && !defined(_REVOLUTION) + int GSISocketSelect(SOCKET theSocket, int* theReadFlag, int* theWriteFlag, int* theExceptFlag) + { + fd_set aReadSet; + fd_set aWriteSet; + fd_set aExceptSet; + fd_set * aReadFds = NULL; + fd_set * aWriteFds = NULL; + fd_set * aExceptFds = NULL; + int aResult; +// 04-13-2005, Saad Nader +// Added case for SN Systems that would +// handle errors after performing selects. +#ifdef SN_SYSTEMS + int aOut, aOutLen = sizeof(aOut); +#endif + + struct timeval aTimeout = { 0, 0 }; + + assert(theSocket != INVALID_SOCKET); + + // Setup the parameters. + //////////////////////// + if(theReadFlag != NULL) + { + FD_ZERO(&aReadSet); + FD_SET(theSocket,&aReadSet); + aReadFds = &aReadSet; + } + if(theWriteFlag != NULL) + { + FD_ZERO(&aWriteSet); + FD_SET(theSocket, &aWriteSet); + aWriteFds = &aWriteSet; + } + if(theExceptFlag != NULL) + { + FD_ZERO(&aExceptSet); + FD_SET(theSocket, &aExceptSet); + aExceptFds = &aExceptSet; + } +#ifdef _PS3 + // to do, port what is below in the else +//int socketselect(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); + aResult = socketselect(FD_SETSIZE, aReadFds, aWriteFds, aExceptFds, &aTimeout); +#else + // Perform the select + aResult = select(FD_SETSIZE, aReadFds, aWriteFds, aExceptFds, &aTimeout); +#endif + if(gsiSocketIsError(aResult)) + return -1; + +// 04-13-2005, Saad Nader +// Added case for SN Systems that would +// handle errors after performing selects. +#ifdef SN_SYSTEMS + getsockopt(theSocket, SOL_SOCKET, SO_ERROR, (char *)&aOut, &aOutLen); + if (aOut != 0) + { + return 0; + } +#endif + // Check results. + ///////////////// + if(theReadFlag != NULL) + { + if((aResult > 0) && FD_ISSET(theSocket, aReadFds)) + *theReadFlag = 1; + else + *theReadFlag = 0; + } + if(theWriteFlag != NULL) + { + if((aResult > 0) && FD_ISSET(theSocket, aWriteFds)) + *theWriteFlag = 1; + else + *theWriteFlag = 0; + } + if(theExceptFlag != NULL) + { + if((aResult > 0) && FD_ISSET(theSocket, aExceptFds)) + *theExceptFlag = 1; + else + *theExceptFlag = 0; + } + return aResult; // 0 or 1 at this point + } +#endif // !nitro && !revolution && !insock + + +// Return 1 for immediate recv, otherwise 0 +int CanReceiveOnSocket(SOCKET sock) +{ + int aReadFlag = 0; + if (1 == GSISocketSelect(sock, &aReadFlag, NULL, NULL)) + return aReadFlag; + + // SDKs expect 0 on SOCKET_ERROR + return 0; +} + +// Return 1 for immediate send, otherwise 0 +int CanSendOnSocket(SOCKET sock) +{ + int aWriteFlag = 0; + if (1 == GSISocketSelect(sock, NULL, &aWriteFlag, NULL)) + return aWriteFlag; + + // SDKs expect 0 on SOCKET_ERROR + return 0; +} + + +#if defined(_PS3) || defined (_PSP) + +#else + +HOSTENT * getlocalhost(void) +{ +#ifdef EENET + #define MAX_IPS 5 + + static HOSTENT localhost; + static char * aliases = NULL; + static char * ipPtrs[MAX_IPS + 1]; + static unsigned int ips[MAX_IPS]; + + struct sceEENetIfname * interfaces; + struct sceEENetIfname * interface; + int num; + int i; + int count; + int len; + u_short flags; + IN_ADDR address; + + // initialize the host + localhost.h_name = "localhost"; + localhost.h_aliases = &aliases; + localhost.h_addrtype = AF_INET; + localhost.h_length = 0; + localhost.h_addr_list = ipPtrs; + + // get the local interfaces + sceEENetGetIfnames(NULL, &num); + interfaces = (struct sceEENetIfname *)gsimalloc(num * sizeof(struct sceEENetIfname)); + if(!interfaces) + return NULL; + sceEENetGetIfnames(interfaces, &num); + + // loop through the interfaces + count = 0; + for(i = 0 ; i < num ; i++) + { + // the next interface + interface = &interfaces[i]; + //printf("eenet%d: %s\n", i, interface->ifn_name); + + // get the flags + len = sizeof(flags); + if(sceEENetGetIfinfo(interface->ifn_name, sceEENET_IFINFO_IFFLAGS, &flags, &len) != 0) + continue; + //printf("eenet%d flags: 0x%X\n", i, flags); + + // check for up, running, and non-loopback + if(!(flags & (IFF_UP|IFF_RUNNING)) || (flags & IFF_LOOPBACK)) + continue; + //printf("eenet%d: up and running, non-loopback\n", i); + + // get the address + len = sizeof(address); + if(sceEENetGetIfinfo(interface->ifn_name, sceEENET_IFINFO_ADDR, &address, &len) != 0) + continue; + //printf("eenet%d: %s\n", i, inet_ntoa(address)); + + // add this address + ips[count] = address.s_addr; + ipPtrs[count] = (char *)&ips[count]; + count++; + } + + // free the interfaces + gsifree(interfaces); + + // check that we got at least one IP + if(!count) + return NULL; + + // finish filling in the host struct + localhost.h_length = (gsi_u16)sizeof(ips[0]); + ipPtrs[count] = NULL; + + return &localhost; + + //////////////////// + // INSOCK +#elif defined(INSOCK) + // Global storage + #define MAX_IPS sceLIBNET_MAX_INTERFACE + static HOSTENT localhost; + static char * aliases = NULL; + static char * ipPtrs[MAX_IPS + 1]; + static unsigned int ips[MAX_IPS]; + + // Temp storage + int aInterfaceIdArray[MAX_IPS]; + int aNumInterfaces = 0; + int aInterfaceNum = 0; + int aCount = 0; + + // Get the list of interfaces + aNumInterfaces = sceInetGetInterfaceList(&gGSIInsockClientData, + &gGSIInsockSocketBuffer, aInterfaceIdArray, MAX_IPS); + if (aNumInterfaces < 1) + return NULL; + + // initialize the HOSTENT + localhost.h_name = "localhost"; + localhost.h_aliases = &aliases; + localhost.h_addrtype = AF_INET; + localhost.h_addr_list = ipPtrs; + + // Look up each address and copy into the HOSTENT structure + aCount = 0; // count of valid interfaces + for (aInterfaceNum = 0; aInterfaceNum < aNumInterfaces; aInterfaceNum++) + { + sceInetAddress_t anAddr; + int result = sceInetInterfaceControl(&gGSIInsockClientData, &gGSIInsockSocketBuffer, + aInterfaceIdArray[aInterfaceNum], sceInetCC_GetAddress, + &anAddr, sizeof(anAddr)); + if (result == 0) + { + // Add this interface to the array + memcpy(&ips[aCount], anAddr.data, sizeof(ips[aCount])); + ips[aCount] = htonl(ips[aCount]); + ipPtrs[aCount] = (char*)&ips[aCount]; + aCount++; + } + } + + // Set the final hostent data, then return + localhost.h_length = (gsi_u16)sizeof(ips[0]); + ipPtrs[aCount] = NULL; + return &localhost; + +#elif defined(_NITRO) + #define MAX_IPS 5 + + static HOSTENT localhost; + static char * aliases = NULL; + static char * ipPtrs[MAX_IPS + 1]; + static unsigned int ips[MAX_IPS]; + + int count = 0; + + localhost.h_name = "localhost"; + localhost.h_aliases = &aliases; + localhost.h_addrtype = AF_INET; + localhost.h_length = 0; + localhost.h_addr_list = (u8 **)ipPtrs; + + ips[count] = 0; + IP_GetAddr(NULL, (u8*)&ips[count]); + if(ips[count] == 0) + return NULL; + ipPtrs[count] = (char *)&ips[count]; + count++; + + localhost.h_length = (gsi_u16)sizeof(ips[0]); + ipPtrs[count] = NULL; + + return &localhost; + +#elif defined(_REVOLUTION) + #define MAX_IPS 5 + static HOSTENT aLocalHost; + static char * aliases = NULL; + int aNumOfIps, i; + int aSizeNumOfIps; + static IPAddrEntry aAddrs[MAX_IPS]; + int aAddrsSize, aAddrsSizeInitial; + static u8 * ipPtrs[MAX_IPS + 1]; + static unsigned int ips[MAX_IPS]; + int ret; + aSizeNumOfIps = sizeof(aNumOfIps); + ret = SOGetInterfaceOpt(NULL, SO_SOL_CONFIG, SO_CONFIG_IP_ADDR_NUMBER, &aNumOfIps, &aSizeNumOfIps); + if (ret != 0) + return NULL; + + aAddrsSize = (int)(MAX_IPS * sizeof(IPAddrEntry)); + aAddrsSizeInitial = aAddrsSize; + ret = SOGetInterfaceOpt(NULL, SO_SOL_CONFIG, SO_CONFIG_IP_ADDR_TABLE, &aAddrs, &aAddrsSize); + if (ret != 0) + return NULL; + + if (aAddrsSize != aAddrsSizeInitial) + { + aNumOfIps = aAddrsSize / (int)sizeof(IPAddrEntry); + } + + aLocalHost.h_name = "localhost"; + aLocalHost.h_aliases = &aliases; + aLocalHost.h_addrtype = AF_INET; + aLocalHost.h_length = SO_IP4_ALEN; + + for (i = 0; i < MAX_IPS; i++) + { + if (i < aNumOfIps) + { + memcpy(&ips[i], &aAddrs[i].addr, sizeof(aAddrs[i].addr)); + ipPtrs[i] = (u8 *)&ips[i]; + } + else + ipPtrs[i] = NULL; + } + aLocalHost.h_addr_list = ipPtrs; + + return &aLocalHost; + +#elif defined(_X360) + XNADDR addr; + DWORD rcode; + static HOSTENT localhost; + static char * ipPtrs[2]; + static IN_ADDR ip; + + while((rcode = XNetGetTitleXnAddr(&addr)) == XNET_GET_XNADDR_PENDING) + msleep(1); + + if((rcode == XNET_GET_XNADDR_NONE) || (rcode == XNET_GET_XNADDR_TROUBLESHOOT)) + return NULL; + + localhost.h_name = "localhost"; + localhost.h_aliases = NULL; + localhost.h_addrtype = AF_INET; + localhost.h_length = (gsi_u16)sizeof(IN_ADDR); + localhost.h_addr_list = (gsi_i8 **)ipPtrs; + + ip = addr.ina; + ipPtrs[0] = (char *)&ip; + ipPtrs[1] = NULL; + + return &localhost; + +#elif defined(_XBOX) + return NULL; + + +#else + char hostname[256] = ""; + + // get the local host's name + gethostname(hostname, sizeof(hostname)); + + // return the host for that name + return gethostbyname(hostname); +#endif +} +#endif + +int IsPrivateIP(IN_ADDR * addr) +{ + int b1; + int b2; + unsigned int ip; + + // get the first 2 bytes + ip = ntohl(addr->s_addr); + b1 = (int)((ip >> 24) & 0xFF); + b2 = (int)((ip >> 16) & 0xFF); + + // 10.X.X.X + if(b1 == 10) + return 1; + + // 172.16-31.X.X + if((b1 == 172) && ((b2 >= 16) && (b2 <= 31))) + return 1; + + // 192.168.X.X + if((b1 == 192) && (b2 == 168)) + return 1; + + return 0; +} + +gsi_u32 gsiGetBroadcastIP(void) +{ +#if defined(_NITRO) + gsi_u32 ip; + IP_GetBroadcastAddr(NULL, (u8*)&ip); + return ip; + +#elif defined(_REVOLUTION) + /* + int length; + gsi_u32 ip; + + length = (gsi_u32)sizeof(ip); + + // IP_GetBroadcastAddr replaced by SOGetInterfaceOpt + // IP_GetBroadcastAddr(NULL, (u8*)&ip); + SOGetInterfaceOpt(NULL, SO_SOL_IP, SO_INADDR_BROADCAST, (u8*)&ip, &length); + */ + IPAddrEntry* addrtbl; + int addrnum; + int ret; + int length; + gsi_u32 ip; + length = (int)sizeof( addrnum ); + + ret = SOGetInterfaceOpt(NULL, + SO_SOL_CONFIG, + SO_CONFIG_IP_ADDR_NUMBER, + (u8*)&addrnum, &length); + + if( ret >= 0 ) + return 0xFFFFFFFF; + + + length = (int)(sizeof( IPAddrEntry ) * addrnum); + + addrtbl = (IPAddrEntry*)gsimalloc( (u32)length ); + + if( addrtbl == NULL ) + return 0xFFFFFFFF; + + ret = SOGetInterfaceOpt(NULL, + SO_SOL_CONFIG, + SO_CONFIG_IP_ADDR_TABLE, + (u8*)addrtbl, + &length); + + if( ret < 0 ) + { + gsifree( addrtbl ); + return 0xFFFFFFFF; + } + + ip = (u32)(addrtbl->bcastAddr[3] + | (addrtbl->bcastAddr[2] << 8) + | (addrtbl->bcastAddr[1] << 16) + | (addrtbl->bcastAddr[0] << 24)); + + gsifree( addrtbl ); + + + return ip; + + return ip; + +#else + return 0xFFFFFFFF; +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// Re-enable previously disabled compiler warnings +/////////////////////////////////////////////////// +#if defined(_MSC_VER) +#pragma warning ( default: 4127 ) +#endif // _MSC_VER + diff --git a/xrGameSpy/gamespy/common/gsPlatformSocket.h b/xrGameSpy/gamespy/common/gsPlatformSocket.h new file mode 100644 index 00000000000..ab7f2e0792c --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatformSocket.h @@ -0,0 +1,654 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSSOCKET_H__ +#define __GSSOCKET_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsPlatform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + + + +// GSI Cross Platform Socket Wrapper + +// this should all inline and optimize out... I hope +// if they somehow get really complex, we need to move the implementation into the .c file. +#if defined _PS3 || defined _PSP + #define gsiSocketIsError(theReturnValue) ((theReturnValue) < 0) + #define gsiSocketIsNotError(theReturnValue) ((theReturnValue) >= 0) +#else + #define gsiSocketIsError(theReturnValue) ((theReturnValue) == -1) + #define gsiSocketIsNotError(theReturnValue) ((theReturnValue) != -1) +#endif + + +#if (0) +// to do for Saad and Martin, move towards this and phase out the #define jungle. +// we will trade a little speed for a lot of portability, and stability +// also out debug libs will assert all params comming in. +typedef enum +{ + GS_SOCKERR_NONE = 0, + GS_SOCKERR_EWOULDBLOCK, + GS_SOCKERR_EINPROGRESS, + GS_SOCKERR_EALREADY, + GS_SOCKERR_ENOTSOCK, + GS_SOCKERR_EDESTADDRREQ, + GS_SOCKERR_EMSGSIZE, + GS_SOCKERR_EPROTOTYPE, + GS_SOCKERR_ENOPROTOOPT , + GS_SOCKERR_EPROTONOSUPPORT , + GS_SOCKERR_ESOCKTNOSUPPORT, + GS_SOCKERR_EOPNOTSUPP , + GS_SOCKERR_EPFNOSUPPORT, + GS_SOCKERR_EAFNOSUPPORT, + GS_SOCKERR_EADDRINUSE , + GS_SOCKERR_EADDRNOTAVAIL , + GS_SOCKERR_ENETDOWN , + GS_SOCKERR_ENETUNREACH , + GS_SOCKERR_ENETRESET, + GS_SOCKERR_ECONNABORTED, + GS_SOCKERR_ECONNRESET , + GS_SOCKERR_ENOBUFS , + GS_SOCKERR_EISCONN , + GS_SOCKERR_ENOTCONN, + GS_SOCKERR_ESHUTDOWN, + GS_SOCKERR_ETOOMANYREFS , + GS_SOCKERR_ETIMEDOUT, + GS_SOCKERR_ECONNREFUSED, + GS_SOCKERR_ELOOP, + GS_SOCKERR_ENAMETOOLONG, + GS_SOCKERR_EHOSTDOWN , + GS_SOCKERR_EHOSTUNREACH , + GS_SOCKERR_ENOTEMPTY , + GS_SOCKERR_EPROCLIM , + GS_SOCKERR_EUSERS , + GS_SOCKERR_EDQUOT , + GS_SOCKERR_ESTALE , + GS_SOCKERR_EREMOTE , + GS_SOCKERR_EINVAL , + GS_SOCKERR_COUNT , +} GS_SOCKET_ERROR; + +#define gsiSocketIsError(theReturnValue) ((theReturnValue) != GS_SOCKERR_NONE) +#define gsiSocketIsNotError(theReturnValue) ((theReturnValue) == GS_SOCKERR_NONE) + +typedef int GSI_SOCKET; + +// mj - may need to pragma pack this, otherwise, it will pad after u_short +typedef struct +{ + // this is the same as the "default" winsocks + u_short sa_family; /* address family */ + char sa_data[14]; /* up to 14 bytes of direct address */ +} GS_SOCKADDR; + +GSI_SOCKET gsiSocketAccept (GSI_SOCKET sock, GS_SOCKADDR* addr, int* len); +GS_SOCKET_ERROR gsiSocketSocket (int pf, int type, int protocol); +GS_SOCKET_ERROR gsiSocketClosesocket(GSI_SOCKET sock); +GS_SOCKET_ERROR gsiSocketShutdown (GSI_SOCKET sock, int how); +GS_SOCKET_ERROR gsiSocketBind (GSI_SOCKET sock, const GS_SOCKADDR* addr, int len); +GS_SOCKET_ERROR gsiSocketConnect (GSI_SOCKET sock, const GS_SOCKADDR* addr, int len); +GS_SOCKET_ERROR gsiSocketListen (GSI_SOCKET sock, int backlog); +GS_SOCKET_ERROR gsiSocketRecv (GSI_SOCKET sock, char* buf, int len, int flags); +GS_SOCKET_ERROR gsiSocketRecvfrom (GSI_SOCKET sock, char* buf, int len, int flags, GS_SOCKADDR* addr, int* fromlen); +GS_SOCKET_ERROR gsiSocketSend (GSI_SOCKET sock, const char* buf, int len, int flags); +GS_SOCKET_ERROR gsiSocketSendto (GSI_SOCKET sock, const char* buf, int len, int flags, const GS_SOCKADDR* addr, int tolen); +GS_SOCKET_ERROR gsiSocketGetsockopt (GSI_SOCKET sock, int level, int optname, char* optval, int* optlen); +GS_SOCKET_ERROR gsiSocketSetsockopt (GSI_SOCKET sock, int level, int optname, const char* optval, int optlen); +GS_SOCKET_ERROR gsiSocketGetsockname(GSI_SOCKET sock, GS_SOCKADDR* addr, int* len); +GS_SOCKET_ERROR GOAGetLastError (GSI_SOCKET sock); + +gsiSocketGethostbyaddr(a,l,t) SOC_GetHostByAddr(a,l,t) +gsiSocketGethostbyname(n) SOC_GetHostByName(n) + + +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Types + + +#ifndef INADDR_NONE + #define INADDR_NONE 0xffffffff +#endif + +#ifndef INVALID_SOCKET + #define INVALID_SOCKET (-1) +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Platform socket types +#if defined(_PSP) + #define AF_INET SCE_NET_INET_AF_INET + #define SOCK_STREAM SCE_NET_INET_SOCK_STREAM + #define SOCK_DGRAM SCE_NET_INET_SOCK_DGRAM + #define SOCK_RAW SCE_NET_INET_SOCK_RAW + #define INADDR_ANY SCE_NET_INET_INADDR_ANY + #define SOL_SOCKET SCE_NET_INET_SOL_SOCKET + #define SO_SNDBUF SCE_NET_INET_SO_SNDBUF + #define SO_RCVBUF SCE_NET_INET_SO_RCVBUF + #define SO_NBIO SCE_NET_INET_SO_NBIO + #define SO_BROADCAST SCE_NET_INET_SO_BROADCAST + #define SO_KEEPALIVE SCE_NET_INET_SO_KEEPALIVE + #define SO_REUSEADDR SCE_NET_INET_SO_REUSEADDR + + #define IPPROTO_TCP SCE_NET_INET_IPPROTO_TCP // protocol defined by SOCK_STREAM + #define IPPROTO_UDP SCE_NET_INET_IPPROTO_UDP // protocol defined by SOCK_DGRAM + #define IPPROTO_ICMP SCE_NET_INET_IPPROTO_ICMP // protocol for ICMP pings + + // structures + #define in_addr SceNetInetInAddr + #define sockaddr_in SceNetInetSockaddrIn + #define sockaddr SceNetInetSockaddr + + // Remove FD types set in sys/types.h + // Replace with types in pspnet/sys/select.h + #if defined(_SYS_TYPES_H) && defined(FD_SET) + #undef fd_set + #undef FD_SET + #undef FD_CLR + #undef FD_ZERO + #undef timeval + #undef FD_SETSIZE + #endif + #define fd_set SceNetInetFdSet + #define timeval SceNetInetTimeval + #define FD_SET SceNetInetFD_SET + #define FD_CLR SceNetInetFD_CLR + #define FD_ZERO SceNetInetFD_ZERO + #define FD_SETSIZE SCE_NET_INET_FD_SETSIZE + + // functions + #define htonl sceNetHtonl + #define ntohl sceNetNtohl + #define htons sceNetHtons + #define ntohs sceNetNtohs + #define socket sceNetInetSocket + #define shutdown sceNetInetShutdown + #define closesocket sceNetInetClose + + #define setsockopt sceNetInetSetsockopt + #define getsockopt(s, l, on, ov, ol) sceNetInetGetsockopt(s, l, on, ov, (SceNetInetSocklen_t *)ol) + + #define bind sceNetInetBind + #define select sceNetInetSelect + + #define connect sceNetInetConnect + #define listen sceNetInetListen + #define accept(s,a,l) sceNetInetAccept(s, a, (SceNetInetSocklen_t *)l) + + #define send sceNetInetSend + #define recv sceNetInetRecv + #define sendto sceNetInetSendto + #define recvfrom(s, b, l, f, fr, fl) sceNetInetRecvfrom(s, b, l, f, fr, (SceNetInetSocklen_t *)fl) + + + #define inet_addr sceNetInetInetAddr + // This is not the correct function for gethostname, it should get the string name of the local host + // not the sockaddr_in struct + #define gethostname // sceNetInetGetsockname + #define getsockname(s,n,l) sceNetInetGetsockname(s, n, (SceNetInetSocklen_t *)l) + + #define GOAGetLastError(s) sceNetInetGetErrno() + + // hostent support + struct hostent + { + char* h_name; + char** h_aliases; + gsi_u16 h_addrtype; // AF_INET + gsi_u16 h_length; + char** h_addr_list; + }; + + #define gethostbyname gsSocketGetHostByName + #define inet_ntoa gsSocketInetNtoa + + #define GSI_RESOLVER_TIMEOUT (5*1000*1000) // 5 seconds + #define GSI_RESOLVER_RETRY (2) + + struct hostent* gsSocketGetHostByName(const char* name); // gsSocketPSP.c + const char* gsSocketInetNtoa(struct in_addr in); + + +#endif // _PSP + +// XBOX doesn't have host lookup +#if defined(_XBOX) + #if defined(_X360) + // hostent support + struct hostent + { + char* h_name; + char** h_aliases; + gsi_u16 h_addrtype; // AF_INET + gsi_u16 h_length; + char** h_addr_list; + }; + + typedef struct hostent HOSTENT; + struct hostent * gethostbyname(const char* name); + #else + typedef int HOSTENT; + #endif + + char * inet_ntoa(IN_ADDR in_addr); +#endif + +#if defined(SN_SYSTEMS) + #define IPPROTO_TCP PF_INET + #define IPPROTO_UDP PF_INET + #define FD_SETSIZE SN_MAX_SOCKETS +#endif + +// SOCKET ERROR CODES +#if defined(_REVOLUTION) //not sure if Wii uses this or _REV + #define WSAEWOULDBLOCK SO_EWOULDBLOCK + #define WSAEINPROGRESS SO_EINPROGRESS + #define WSAEALREADY SO_EALREADY + #define WSAENOTSOCK SO_ENOTSOCK + #define WSAEDESTADDRREQ SO_EDESTADDRREQ + #define WSAEMSGSIZE SO_EMSGSIZE + #define WSAEPROTOTYPE SO_EPROTOTYPE + #define WSAENOPROTOOPT SO_ENOPROTOOPT + #define WSAEPROTONOSUPPORT SO_EPROTONOSUPPORT + #define WSAEOPNOTSUPP SO_EOPNOTSUPP + #define WSAEAFNOSUPPORT SO_EAFNOSUPPORT + #define WSAEADDRINUSE SO_EADDRINUSE + #define WSAEADDRNOTAVAIL SO_EADDRNOTAVAIL + #define WSAENETDOWN SO_ENETDOWN + #define WSAENETUNREACH SO_ENETUNREACH + #define WSAENETRESET SO_ENETRESET + #define WSAECONNABORTED SO_ECONNABORTED + #define WSAECONNRESET SO_ECONNRESET + #define WSAENOBUFS SO_ENOBUFS + #define WSAEISCONN SO_EISCONN + #define WSAENOTCONN SO_ENOTCONN + #define WSAETIMEDOUT SO_ETIMEDOUT + #define WSAECONNREFUSED SO_ECONNREFUSED + #define WSAELOOP SO_ELOOP + #define WSAENAMETOOLONG SO_ENAMETOOLONG + #define WSAEHOSTUNREACH SO_EHOSTUNREACH + #define WSAENOTEMPTY SO_ENOTEMPTY + #define WSAEDQUOT SO_EDQUOT + #define WSAESTALE SO_ESTALE + #define WSAEINVAL SO_EINVAL +#elif defined(_NITRO) + #define WSAEWOULDBLOCK SOC_EWOULDBLOCK + #define WSAEINPROGRESS SOC_EINPROGRESS + #define WSAEALREADY SOC_EALREADY + #define WSAENOTSOCK SOC_ENOTSOCK + #define WSAEDESTADDRREQ SOC_EDESTADDRREQ + #define WSAEMSGSIZE SOC_EMSGSIZE + #define WSAEPROTOTYPE SOC_EPROTOTYPE + #define WSAENOPROTOOPT SOC_ENOPROTOOPT + #define WSAEPROTONOSUPPORT SOC_EPROTONOSUPPORT + #define WSAEOPNOTSUPP SOC_EOPNOTSUPP + #define WSAEAFNOSUPPORT SOC_EAFNOSUPPORT + #define WSAEADDRINUSE SOC_EADDRINUSE + #define WSAEADDRNOTAVAIL SOC_EADDRNOTAVAIL + #define WSAENETDOWN SOC_ENETDOWN + #define WSAENETUNREACH SOC_ENETUNREACH + #define WSAENETRESET SOC_ENETRESET + #define WSAECONNABORTED SOC_ECONNABORTED + #define WSAECONNRESET SOC_ECONNRESET + #define WSAENOBUFS SOC_ENOBUFS + #define WSAEISCONN SOC_EISCONN + #define WSAENOTCONN SOC_ENOTCONN + #define WSAETIMEDOUT SOC_ETIMEDOUT + #define WSAECONNREFUSED SOC_ECONNREFUSED + #define WSAELOOP SOC_ELOOP + #define WSAENAMETOOLONG SOC_ENAMETOOLONG + #define WSAEHOSTUNREACH SOC_EHOSTUNREACH + #define WSAENOTEMPTY SOC_ENOTEMPTY + #define WSAEDQUOT SOC_EDQUOT + #define WSAESTALE SOC_ESTALE + #define WSAEINVAL SOC_EINVAL +#elif defined(_PS3) + #define WSAEWOULDBLOCK SYS_NET_EWOULDBLOCK + #define WSAEINPROGRESS SYS_NET_EINPROGRESS //SYS_NET_ERROR_EINPROGRESS + #define WSAEALREADY SYS_NET_EALREADY + #define WSAENOTSOCK SYS_NET_ENOTSOCK + #define WSAEDESTADDRREQ SYS_NET_EDESTADDRREQ + #define WSAEMSGSIZE SYS_NET_EMSGSIZE + #define WSAEPROTOTYPE SYS_NET_EPROTOTYPE + #define WSAENOPROTOOPT SYS_NET_ENOPROTOOPT + #define WSAEPROTONOSUPPORT SYS_NET_EPROTONOSUPPORT + #define WSAESOCKTNOSUPPORT SYS_NET_ESOCKTNOSUPPORT + #define WSAEOPNOTSUPP SYS_NET_EOPNOTSUPP + #define WSAEPFNOSUPPORT SYS_NET_EPFNOSUPPORT + #define WSAEAFNOSUPPORT SYS_NET_EAFNOSUPPORT + #define WSAEADDRINUSE SYS_NET_EADDRINUSE + #define WSAEADDRNOTAVAIL SYS_NET_EADDRNOTAVAIL + #define WSAENETDOWN SYS_NET_ENETDOWN + #define WSAENETUNREACH SYS_NET_ENETUNREACH + #define WSAENETRESET SYS_NET_ENETRESET + #define WSAECONNABORTED SYS_NET_ECONNABORTED + #define WSAECONNRESET SYS_NET_ECONNRESET // SYS_NET_ERROR_ECONNRESET + #define WSAENOBUFS SYS_NET_ENOBUFS // SYS_NET_ERROR_ENOBUFS + #define WSAEISCONN SYS_NET_EISCONN + #define WSAENOTCONN SYS_NET_ENOTCONN + #define WSAESHUTDOWN SYS_NET_ESHUTDOWN + #define WSAETOOMANYREFS SYS_NET_ETOOMANYREFS + #define WSAETIMEDOUT SYS_NET_ERROR_ETIMEDOUT + #define WSAECONNREFUSED SYS_NET_ECONNREFUSED + #define WSAELOOP SYS_NET_ELOOP + #define WSAENAMETOOLONG SYS_NET_ENAMETOOLONG + #define WSAEHOSTDOWN SYS_NET_EHOSTDOWN + #define WSAEHOSTUNREACH SYS_NET_EHOSTUNREACH + #define WSAENOTEMPTY SYS_NET_ENOTEMPTY + #define WSAEPROCLIM SYS_NET_EPROCLIM + #define WSAEUSERS SYS_NET_EUSERS + #define WSAEDQUOT SYS_NET_EDQUOT + #define WSAESTALE SYS_NET_ESTALE + #define WSAEREMOTE SYS_NET_EREMOTE + #define WSAEINVAL SYS_NET_EINVAL +#elif !defined(_WIN32) + #define WSAEWOULDBLOCK EWOULDBLOCK + #define WSAEINPROGRESS EINPROGRESS + #define WSAEALREADY EALREADY + #define WSAENOTSOCK ENOTSOCK + #define WSAEDESTADDRREQ EDESTADDRREQ + #define WSAEMSGSIZE EMSGSIZE + #define WSAEPROTOTYPE EPROTOTYPE + #define WSAENOPROTOOPT ENOPROTOOPT + #define WSAEPROTONOSUPPORT EPROTONOSUPPORT + #define WSAESOCKTNOSUPPORT ESOCKTNOSUPPORT + #define WSAEOPNOTSUPP EOPNOTSUPP + #define WSAEPFNOSUPPORT EPFNOSUPPORT + #define WSAEAFNOSUPPORT EAFNOSUPPORT + #define WSAEADDRINUSE EADDRINUSE + #define WSAEADDRNOTAVAIL EADDRNOTAVAIL + #define WSAENETDOWN ENETDOWN + #define WSAENETUNREACH ENETUNREACH + #define WSAENETRESET ENETRESET + #define WSAECONNABORTED ECONNABORTED + #define WSAECONNRESET ECONNRESET + #define WSAENOBUFS ENOBUFS + #define WSAEISCONN EISCONN + #define WSAENOTCONN ENOTCONN + #define WSAESHUTDOWN ESHUTDOWN + #define WSAETOOMANYREFS ETOOMANYREFS + #define WSAETIMEDOUT ETIMEDOUT + #define WSAECONNREFUSED ECONNREFUSED + #define WSAELOOP ELOOP + #define WSAENAMETOOLONG ENAMETOOLONG + #define WSAEHOSTDOWN EHOSTDOWN + #define WSAEHOSTUNREACH EHOSTUNREACH + #define WSAENOTEMPTY ENOTEMPTY + #define WSAEPROCLIM EPROCLIM + #define WSAEUSERS EUSERS + #define WSAEDQUOT EDQUOT + #define WSAESTALE ESTALE + #define WSAEREMOTE EREMOTE + #define WSAEINVAL EINVAL +#endif + +// make caps types interchangeable on all platforms +#if !defined(_WIN32) && !defined(_NITRO) && !defined(_REVOLUTION) // necessary for Wii?? + typedef int SOCKET; + typedef struct sockaddr SOCKADDR; + typedef struct sockaddr_in SOCKADDR_IN; + typedef struct in_addr IN_ADDR; + typedef struct hostent HOSTENT; + typedef struct timeval TIMEVAL; +#endif + +#ifdef EENET + #define GOAGetLastError(s) sceEENetErrno + #define closesocket sceEENetClose +#endif + +#ifdef INSOCK + //#define NETBUFSIZE (sceLIBNET_BUFFERSIZE) + #define NETBUFSIZE (32768) // buffer size for our samples + +// used in place of shutdown function to avoid blocking shutdown call +int gsiShutdown(SOCKET s, int how); + + #define GOAGetLastError(s) sceInsockErrno // not implemented + #define closesocket(s) gsiShutdown(s,SCE_INSOCK_SHUT_RDWR) + #undef shutdown + #define shutdown(s,h) gsiShutdown(s,h) +#endif + +#ifdef _UNIX + #define GOAGetLastError(s) errno + #define closesocket close //on unix +#endif + +#if !defined(_WIN32) + #define ioctlsocket ioctl +#endif + +#if defined(_WIN32) + #define GOAGetLastError(s) WSAGetLastError() +#endif + +#if defined(_REVOLUTION) + #define AF_INET SO_PF_INET + #define SOCK_DGRAM SO_SOCK_DGRAM + #define SOCK_STREAM SO_SOCK_STREAM + #define IPPROTO_UDP SO_IPPROTO_UDP + #define IPPROTO_TCP SO_IPPROTO_TCP + #define INADDR_ANY SO_INADDR_ANY + #define SOL_SOCKET SO_SOL_SOCKET + #define SO_SNDBUF SO_SO_SNDBUF + #define SO_RCVBUF SO_SO_RCVBUF + #define SO_REUSEADDR SO_SO_REUSEADDR + + typedef int SOCKET; + typedef struct SOSockAddr SOCKADDR; + #define sockaddr SOSockAddr + typedef struct SOSockAddrIn SOCKADDR_IN; + #define sockaddr_in SOSockAddrIn + #define sin_family family + #define sin_port port + #define sin_addr addr + typedef struct SOInAddr IN_ADDR; + #define in_addr SOInAddr + #define s_addr addr + typedef struct SOHostEnt HOSTENT; + #define hostent SOHostEnt + #define h_name name + #define h_aliases aliases + #define h_addrtype addrType + #define h_length length + #define h_addr_list addrList + #define h_addr addrList[0] + + int socket(int pf, int type, int protocol); + int closesocket(SOCKET sock); + int shutdown(SOCKET sock, int how); + int bind(SOCKET sock, const SOCKADDR* addr, int len); + + int connect(SOCKET sock, const SOCKADDR* addr, int len); + int listen(SOCKET sock, int backlog); + SOCKET accept(SOCKET sock, SOCKADDR* addr, int* len); + + int recv(SOCKET sock, char* buf, int len, int flags); + int recvfrom(SOCKET sock, char* buf, int len, int flags, SOCKADDR* addr, int* fromlen); + int send(SOCKET sock, const char* buf, int len, int flags); + int sendto(SOCKET sock, const char* buf, int len, int flags, const SOCKADDR* addr, int tolen); + + int getsockopt(SOCKET sock, int level, int optname, char* optval, int* optlen); + int setsockopt(SOCKET sock, int level, int optname, const char* optval, int optlen); + + #define gethostbyaddr(a,l,t) SOGetHostByAddr(a,l,t) + #define gethostbyname(n) SOGetHostByName(n) + + // thread safe DNS lookups + #define getaddrinfo(n,s,h,r) SOGetAddrInfo(n,s,h,r) + #define freeaddrinfo(a) SOFreeAddrInfo(a) + + + int getsockname(SOCKET sock, SOCKADDR* addr, int* len); + + #define htonl(l) SOHtoNl((u32)l) + #define ntohl(l) SONtoHl((u32)l) + #define htons(s) SOHtoNs((u16)s) + #define ntohs(s) SONtoHs((u16)s) + + #define inet_ntoa(n) SOInetNtoA(n) + unsigned long inet_addr(const char * name); + + int GOAGetLastError(SOCKET sock); +#endif + +#if defined(_NITRO) + #define AF_INET SOC_PF_INET + #define SOCK_DGRAM SOC_SOCK_DGRAM + #define SOCK_STREAM SOC_SOCK_STREAM + #define IPPROTO_UDP 0 + #define IPPROTO_TCP 0 + #define INADDR_ANY SOC_INADDR_ANY + #define SOL_SOCKET SOC_SOL_SOCKET + #define SO_SNDBUF SOC_SO_SNDBUF + #define SO_RCVBUF SOC_SO_RCVBUF + #define SO_REUSEADDR SOC_SO_REUSEADDR + + typedef int SOCKET; + typedef struct SOSockAddr SOCKADDR; + #define sockaddr SOSockAddr + typedef struct SOSockAddrIn SOCKADDR_IN; + #define sockaddr_in SOSockAddrIn + #define sin_family family + #define sin_port port + #define sin_addr addr + typedef struct SOInAddr IN_ADDR; + #define in_addr SOInAddr + #define s_addr addr + typedef struct SOHostEnt HOSTENT; + #define hostent SOHostEnt + #define h_name name + #define h_aliases aliases + #define h_addrtype addrType + #define h_length length + #define h_addr_list addrList + #define h_addr addrList[0] + + int socket(int pf, int type, int protocol); + int closesocket(SOCKET sock); + int shutdown(SOCKET sock, int how); + int bind(SOCKET sock, const SOCKADDR* addr, int len); + + int connect(SOCKET sock, const SOCKADDR* addr, int len); + int listen(SOCKET sock, int backlog); + SOCKET accept(SOCKET sock, SOCKADDR* addr, int* len); + + int recv(SOCKET sock, char* buf, int len, int flags); + int recvfrom(SOCKET sock, char* buf, int len, int flags, SOCKADDR* addr, int* fromlen); + int send(SOCKET sock, const char* buf, int len, int flags); + int sendto(SOCKET sock, const char* buf, int len, int flags, const SOCKADDR* addr, int tolen); + + int getsockopt(SOCKET sock, int level, int optname, char* optval, int* optlen); + int setsockopt(SOCKET sock, int level, int optname, const char* optval, int optlen); + + #define gethostbyaddr(a,l,t) SOC_GetHostByAddr(a,l,t) + #define gethostbyname(n) SOC_GetHostByName(n) + + int getsockname(SOCKET sock, SOCKADDR* addr, int* len); + + #define htonl(l) SOC_HtoNl(l) + #define ntohl(l) SOC_NtoHl(l) + #define htons(s) SOC_HtoNs(s) + #define ntohs(s) SOC_NtoHs(s) + + #define inet_ntoa(n) SOC_InetNtoA(n) + unsigned long inet_addr(const char * name); + + int GOAGetLastError(SOCKET sock); +#endif + +#if defined(_PS3) + #define accept(s,a,al) accept(s,a,(socklen_t*)(al)) + #define bind(s,a,al) bind(s,a,(socklen_t)(al)) + #define connect(s,a,al) connect(s,a,(socklen_t)(al)) + #define getpeername(s,a,al) getpeername(s,a,(socklen_t*)(al)) + #define getsockname(s,a,al) getsockname(s,a,(socklen_t*)(al)) + #define getsockopt(s,l,o,v,vl) getsockopt(s,l,o,v,(socklen_t*)(vl)) + #define recvfrom(s,b,l,f,a,al) recvfrom(s,b,l,f,a,(socklen_t*)(al)) + #define sendto(s,b,l,f,a,al) sendto(s,b,l,f,a,(socklen_t)(al)) + #define setsockopt(s,l,o,v,vl) setsockopt(s,l,o,v,(socklen_t)(vl)) + #define closesocket socketclose + #define GOAGetLastError(s) sys_net_errno + #define EWOULDBLOCK sceNET_EWOULDBLOCK +#endif + +#if defined(_MACOSX) + #define accept(s,a,al) accept(s,a,(socklen_t*)(al)) + #define bind(s,a,al) bind(s,a,(socklen_t)(al)) + #define connect(s,a,al) connect(s,a,(socklen_t)(al)) + #define getpeername(s,a,al) getpeername(s,a,(socklen_t*)(al)) + #define getsockname(s,a,al) getsockname(s,a,(socklen_t*)(al)) + #define getsockopt(s,l,o,v,vl) getsockopt(s,l,o,v,(socklen_t*)(vl)) + #define recvfrom(s,b,l,f,a,al) recvfrom(s,b,l,f,a,(socklen_t*)(al)) + #define sendto(s,b,l,f,a,al) sendto(s,b,l,f,a,(socklen_t)(al)) + #define setsockopt(s,l,o,v,vl) setsockopt(s,l,o,v,(socklen_t)(vl)) +#endif + +#if defined(SN_SYSTEMS) + int GOAGetLastError(SOCKET s); + + #if !defined(__MWERKS__) + #define send(s,b,l,f) (int)send(s,b,(unsigned long)l,f) + #define recv(s,b,l,f) (int)recv(s,b,(unsigned long)l,f) + #define sendto(s,b,l,f,a,al) (int)sendto(s,b,(unsigned long)l,f,a,al) + #define recvfrom(s,b,l,f,a,al) (int)recvfrom(s,b,(unsigned long)l,f,a,al) + #endif +#endif + +// SN Systems doesn't support gethostbyaddr +#if defined(SN_SYSTEMS) + #define gethostbyaddr(a,b,c) NULL +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Functions +int SetSockBlocking(SOCKET sock, int isblocking); +int SetSockBroadcast(SOCKET sock); +int DisableNagle(SOCKET sock); +int SetReceiveBufferSize(SOCKET sock, int size); +int SetSendBufferSize(SOCKET sock, int size); +int GetReceiveBufferSize(SOCKET sock); +int GetSendBufferSize(SOCKET sock); +int CanReceiveOnSocket(SOCKET sock); +int CanSendOnSocket(SOCKET sock); +int GSISocketSelect(SOCKET theSocket, int* theReadFlag, int* theWriteFlag, int* theExceptFlag); +void SocketStartUp(); +void SocketShutDown(); + +HOSTENT * getlocalhost(void); + +int IsPrivateIP(IN_ADDR * addr); +gsi_u32 gsiGetBroadcastIP(void); + + +#if defined(_PSP) + #define gethostbyaddr(a,b,c) NULL +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} +#endif + +#endif // __GSSOCKET_H__ + diff --git a/xrGameSpy/gamespy/common/gsPlatformThread.c b/xrGameSpy/gamespy/common/gsPlatformThread.c new file mode 100644 index 00000000000..fd32935039a --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatformThread.c @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if !defined(GSI_NO_THREADS) +#include "gsCommon.h" + + +// Include platform separated functions +#if defined(_X360) + #include "x360/gsThreadX360.c" +#elif defined(_XBOX) + //#include "xbox/gsThreadXBox.c" +#elif defined(_WIN32) + #include "win32/gsThreadWin32.c" +#elif defined(_MACOSX) + #include "macosx/gsThreadMacOSX.c" +#elif defined (_LINUX) + #include "linux/gsThreadLinux.c" +#elif defined(_NITRO) + #include "nitro/gsThreadNitro.c" +#elif defined(_PS2) + #include "ps2/gsThreadPs2.c" +#elif defined(_PS3) +// #include "ps3/gsThreadPS3.c" +#elif defined(_PSP) +// #include "psp/gsThreadPSP.c" +#elif defined(_REVOLUTION) + #include "revolution/gsThreadRevoulution.c" +#else + #error "Missing or unsupported platform" +#endif + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} +#endif + +#endif // GSI_NO_THREADS diff --git a/xrGameSpy/gamespy/common/gsPlatformThread.h b/xrGameSpy/gamespy/common/gsPlatformThread.h new file mode 100644 index 00000000000..85421ea86e1 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatformThread.h @@ -0,0 +1,197 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSPLATFORMTHREAD_H__ +#define __GSPLATFORMTHREAD_H__ + + +#include "gsPlatform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Thread types +#if defined(_WIN32) + typedef CRITICAL_SECTION GSICriticalSection; + typedef HANDLE GSISemaphoreID; + typedef HANDLE GSIThreadID; + typedef DWORD (WINAPI *GSThreadFunc)(void *arg); + +#elif defined(_PS2) + typedef int GSIThreadID; + typedef int GSISemaphoreID; + typedef struct + { + // A critical section is a re-entrant semaphore + GSISemaphoreID mSemaphore; + GSIThreadID mOwnerThread; + gsi_u32 mEntryCount; // track re-entry + gsi_u32 mPad; // make 16bytes + } GSICriticalSection; + typedef void (*GSThreadFunc)(void *arg); + +#elif defined(_NITRO) + typedef OSMutex GSICriticalSection; + typedef struct + { + OSMutex mLock; + gsi_i32 mValue; + gsi_i32 mMax; + } GSISemaphoreID; + typedef struct + { + OSThread mThread; + void * mStack; + } GSIThreadID; + typedef void (*GSThreadFunc)(void *arg); + +#elif defined(_REVOLUTION) + typedef OSMutex GSICriticalSection; + typedef OSSemaphore GSISemaphoreID; + typedef struct + { + OSThread mThread; + void * mStack; + } GSIThreadID; + typedef void *(*GSThreadFunc)(void *arg); + +#elif defined(_PSP) + // Todo: Test PSP thread code, then remove this define + #define GSI_NO_THREADS + typedef int GSIThreadID; + typedef int GSISemaphoreID; + typedef struct + { + // A critical section is a re-entrant semaphore + GSISemaphoreID mSemaphore; + GSIThreadID mOwnerThread; + gsi_u32 mEntryCount; // track re-entry + gsi_u32 mPad; // make 16bytes + } GSICriticalSection; + typedef void (*GSThreadFunc)(void *arg); + +#elif defined(_PS3) + // Todo: Test PS3 ppu thread code, then remove this define + #define GSI_NO_THREADS + typedef int GSIThreadID; + typedef int GSISemaphoreID; + typedef struct + { + // A critical section is a re-entrant semaphore + GSISemaphoreID mSemaphore; + GSIThreadID mOwnerThread; + gsi_u32 mEntryCount; // track re-entry + gsi_u32 mPad; // make 16bytes + } GSICriticalSection; + typedef void (*GSThreadFunc)(void *arg); + +#elif defined(_UNIX) //_LINUX || _MACOSX + typedef pthread_mutex_t GSICriticalSection; + typedef struct + { + pthread_mutex_t mLock; + gsi_i32 mValue; + gsi_i32 mMax; + } GSISemaphoreID; + typedef struct + { + pthread_t thread; + pthread_attr_t attr; + } GSIThreadID; + typedef void (*GSThreadFunc)(void *arg); + +#else + #define GSI_NO_THREADS +#endif + +#if defined(WIN32) + #define GSI_INFINITE INFINITE +#else + #define GSI_INFINITE (gsi_u32)(-1) +#endif + + +#if !defined(GSI_NO_THREADS) + // The increment/read operations must not be preempted + #if defined(_WIN32) + #define gsiInterlockedIncrement(a) InterlockedIncrement((long*)a) + #define gsiInterlockedDecrement(a) InterlockedDecrement((long*)a) + #elif defined(_PS2) + gsi_u32 gsiInterlockedIncrement(gsi_u32* num); + gsi_u32 gsiInterlockedDecrement(gsi_u32* num); + #elif defined(_PS3) + // TODO - threading in PS3 uses pthreads, just like Linux + #elif defined(_NITRO) + gsi_u32 gsiInterlockedIncrement(gsi_u32* num); + gsi_u32 gsiInterlockedDecrement(gsi_u32* num); + #elif defined(_REVOLUTION) + gsi_u32 gsiInterlockedIncrement(gsi_u32* num); + gsi_u32 gsiInterlockedDecrement(gsi_u32* num); + #elif defined(_UNIX) + gsi_u32 gsiInterlockedIncrement(gsi_u32* num); + gsi_u32 gsiInterlockedDecrement(gsi_u32* num); + #endif + +#else + // Don't worry about concurrancy when GSI_NO_THREADS is defined + #define gsiInterlockedIncrement(a) (++(*a)) + #define gsiInterlockedDecrement(a) (--(*a)) +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if !defined(GSI_NO_THREADS) + int gsiStartThread(GSThreadFunc aThreadFunc, gsi_u32 theStackSize, void *arg, GSIThreadID* theThreadIdOut); + void gsiCancelThread(GSIThreadID theThreadID); + void gsiExitThread(GSIThreadID theThreadID); + void gsiCleanupThread(GSIThreadID theThreadID); + + // Thread Synchronization - Startup/Shutdown + gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID); + + // Thread Synchronization - Critical Section + void gsiInitializeCriticalSection(GSICriticalSection *theCrit); + void gsiEnterCriticalSection(GSICriticalSection *theCrit); + void gsiLeaveCriticalSection(GSICriticalSection *theCrit); + void gsiDeleteCriticalSection(GSICriticalSection *theCrit); + + // Thread Synchronization - Semaphore + GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName); + gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs); + void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount); + void gsiCloseSemaphore(GSISemaphoreID theSemaphore); + +#else + // NO THREADS - stub everything to unused + #define gsiStartThread(a, b, c, d) (-1) // must return something + #define gsiCancelThread(a) + #define gsiExitThread(a) + #define gsiCleanupThread(a) + + #define gsiHasThreadShutdown(a) (1) // must return something + + #define gsiInitializeCriticalSection(a) + #define gsiEnterCriticalSection(a) + #define gsiLeaveCriticalSection(a) + #define gsiDeleteCriticalSection(a) + + #define gsiCreateSemaphore(a,b,c) (-1) + #define gsiWaitForSemaphore(a,b) (0) + #define gsiReleaseSemaphore(a,b) + #define gsiCloseSemaphore(a) + +#endif // GSI_NO_THREADS + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} +#endif + +#endif // __GSPLATFORMTHREAD_H__ diff --git a/xrGameSpy/gamespy/common/gsPlatformUtil.c b/xrGameSpy/gamespy/common/gsPlatformUtil.c new file mode 100644 index 00000000000..f528c5a13d1 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatformUtil.c @@ -0,0 +1,1903 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCommon.h" +#include "gsPlatformUtil.h" + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 1368, 1372 +#pragma warning(disable: 4267) //lines: 1861 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +// Include platform separated functions +#if defined(_X360) + //#include "x360/gsUtilX360.c" +#elif defined(_XBOX) + //#include "xbox/gsUtilXBox.c" +#elif defined(_WIN32) + #include "win32/gsUtilWin32.c" +#elif defined(_LINUX) + #include "linux/gsUtilLinux.c" +#elif defined(_MACOSX) + #include "macosx/gsUtilMacOSX.c" +#elif defined(_NITRO) + #include "nitro/gsUtilNitro.c" +#elif defined(_PS2) + #include "ps2/gsUtilPs2.c" +#elif defined(_PS3) + #include "ps3/gsUtilPs3.c" +#elif defined(_PSP) + #include "psp/gsUtilPSP.c" +#elif defined(_REVOLUTION) + #include "revolution/gsUtilRevolution.c" +#else + #error "Missing or unsupported platform" +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// ********** ASYNC DNS ********** // + +//struct is used in both threaded and non-threaded versions +typedef struct GSIResolveHostnameInfo +{ + char * hostname; + unsigned int ip; + +#if defined(_WIN32) /*|| defined(_PS2)*/ || defined(_UNIX) || defined (_REVOLUTION) + int finishedResolving; + GSIThreadID threadID; +#endif + +/*#if defined(_PSP) + int finishedResolving; + GSIThreadID threadID; +#endif*/ +} GSIResolveHostnameInfo; + +//////////////////////////////////////////////////////////////////////////////// +// for asynch DNS, must have: +// * platform that supports threaded lookup AND +// * threading enabled +// * and async lookup enabled +//////////////////////////////////////////////////////////////////////////////// +#if (defined(_WIN32) || /*defined(_PS2) ||*/ defined(_UNIX) || defined (_REVOLUTION)) && !defined(GSI_NO_THREADS) && !defined(GSI_NO_ASYNC_DNS) + +//////////////////////////////////////////////////////////////////////////////// +#if defined(_WIN32) /*|| defined(_PS2)*/ + #if defined(_WIN32) + DWORD WINAPI gsiResolveHostnameThread(void * arg) + /*#elif defined(_PS2) + static void gsiResolveHostnameThread(void * arg)*/ + #endif + { + HOSTENT * hostent; + GSIResolveHostnameHandle handle = (GSIResolveHostnameHandle)arg; + + SocketStartUp(); + + #ifdef SN_SYSTEMS + sockAPIregthr(); + #endif + + // do the gethostbyname + hostent = gethostbyname(handle->hostname); + if(hostent) + { + // got the ip + handle->ip = *(unsigned int *)hostent->h_addr_list[0]; + } + else + { + // didn't resolve + handle->ip = GSI_ERROR_RESOLVING_HOSTNAME; + } + + SocketShutDown(); + + // finished resolving + handle->finishedResolving = 1; + + #ifdef SN_SYSTEMS + sockAPIderegthr(); + #endif + + // explicitly exit the thread to free resources + gsiExitThread(handle->threadID); + + #if defined(_WIN32) + return 0; + #endif +} +#endif //defined _WIN32 +//////////////////////////////////////////////////////////////////////////////// + + +#ifdef _REVOLUTION +/////////////////////////////////////////////////////////////////////////////// +static void *gsiResolveHostnameThread(void * arg) +{ + static GSICriticalSection aHostnameCrit; + static int aInitialized = 0; + //SOAddrInfo *aHostAddr; + HOSTENT *aHostAddr; + //int retval; + GSIResolveHostnameHandle handle = (GSIResolveHostnameHandle)arg; + + if (!aInitialized) + { + gsiInitializeCriticalSection(&aHostnameCrit); + aInitialized = 1; + } + gsiEnterCriticalSection(&aHostnameCrit); + + //retval = getaddrinfo(handle->hostname, NULL, NULL, &aHostAddr); + aHostAddr = gethostbyname(handle->hostname); + if (aHostAddr != 0) + { + char * ip; + // first convert to character string for debug output + ip = inet_ntoa(*(in_addr *)aHostAddr->addrList[0]); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, + "Resolved host '%s' to ip '%s'\n", handle->hostname, ip); + + handle->ip = inet_addr(ip); + //freeaddrinfo(aHostAddr); + } + else + { + // couldnt reach host - debug output is printed later + handle->ip = GSI_ERROR_RESOLVING_HOSTNAME; + } + + + // finished resolving + handle->finishedResolving = 1; + + gsiLeaveCriticalSection(&aHostnameCrit); +} +#endif // _REVOLUTION +//////////////////////////////////////////////////////////////////////////////// + +// +// Linux/MacOSX implementation of multithreaded DNS lookup +// Uses getaddrinfo instead of gethostbyname - since the latter +// has static declarations and is thus un-safe for pthreads +// +// NOTE: The compiler option "-lpthread" must used for this +#if defined(_UNIX) +//////////////////////////////////////////////////////////////////////////////// +static void gsiResolveHostnameThread(void * arg) +{ + GSIResolveHostnameHandle handle = (GSIResolveHostnameHandle)arg; + struct addrinfo hints, *result = NULL; + int error; + char *ip; + + SocketStartUp(); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + // DNS lookup (works with pthreads) + error = getaddrinfo(handle->hostname, "http", &hints, &result); + + if (!error) + { + // first convert to character string for debug output + ip = inet_ntoa((*(struct sockaddr_in*)result->ai_addr).sin_addr); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, + "Resolved host '%s' to ip '%s'\n", handle->hostname, ip); + + // now convert to unsigned int and store it + handle->ip = inet_addr(ip); + + // free the memory used + freeaddrinfo(result); + } + else + { + // couldnt reach host - debug output is printed later + handle->ip = GSI_ERROR_RESOLVING_HOSTNAME; + } + + SocketShutDown(); + + // finished resolving + handle->finishedResolving = 1; + + // explicitly exit the thread to free resources + gsiExitThread(handle->threadID); +} +#endif //_UNIX +//////////////////////////////////////////////////////////////////////////////// + + +int gsiStartResolvingHostname(const char * hostname, GSIResolveHostnameHandle * handle) +{ + GSIResolveHostnameInfo * info; + + //PS2 Threading unsupported in current build - this should never be reached +#if defined(_PS2) + GS_ASSERT_STR(gsi_false, "PS2 Threading unsupported in current version of the SDK\n"); +#endif + + // allocate a handle + info = (GSIResolveHostnameInfo *)gsimalloc(sizeof(GSIResolveHostnameInfo)); + if(!info) + return -1; + + // make a copy of the hostname so the thread has access to it + info->hostname = goastrdup(hostname); + if(!info->hostname) + { + gsifree(info); + return -1; + } + + // not resolved yet + info->finishedResolving = 0; + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_State, GSIDebugLevel_Comment, + "(Asynchrounous) DNS lookup starting\n"); + + // start the thread + if(gsiStartThread(gsiResolveHostnameThread, (0x1000), info, &info->threadID) == -1) + { + gsifree(info->hostname); + info->hostname = NULL; + gsifree(info); + info = NULL; + return -1; + } + + // set the handle to the info + *handle = info; + + return 0; +} + +void gsiCancelResolvingHostname(GSIResolveHostnameHandle handle) +{ + // cancel the thread + gsiCancelThread(handle->threadID); + + if (handle->hostname) + { + gsifree(handle->hostname); + handle->hostname = NULL; + } + gsifree(handle); + handle = NULL; +} + +unsigned int gsiGetResolvedIP(GSIResolveHostnameHandle handle) +{ + unsigned int ip; + + // check if we haven't finished + if(!handle->finishedResolving) + return GSI_STILL_RESOLVING_HOSTNAME; + + // save the ip + ip = handle->ip; + + // free resources + gsiCleanupThread(handle->threadID); + gsifree(handle->hostname); + gsifree(handle); + handle = NULL; + + return ip; +} + + +#else // if * not a supported platform OR * no threads allowed OR * no async lookup allowed + /////////////////////////////////////////////////////////////////////////////////// + // if !(_WIN32 ||_PS2 || _LINUX || _MACOSX || _REVOLUTION) || GSI_NO_THREADS || GSI_NO_ASYNC_DNS + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// ********** NON-ASYNC DNS ********** // +// +// These are the non-threaded version of the above functions. +// The following platforms have synchronous DNS lookups: +// _NITRO || _XBOX || _X360 || _PS3 || _PS2 || _PSP +/////////////////////////////////////////////////////////////////////////////// + +int gsiStartResolvingHostname(const char * hostname, GSIResolveHostnameHandle * handle) +{ + GSIResolveHostnameInfo * info; + HOSTENT * hostent; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, + "(NON-Asynchrounous) DNS lookup starting\n"); + + // do the lookup now + hostent = gethostbyname(hostname); + if(hostent == NULL) + return -1; + + // allocate info to store the result + info = (GSIResolveHostnameHandle)gsimalloc(sizeof(GSIResolveHostnameInfo)); + if(!info) + return -1; + + // we already have the ip + info->ip = *(unsigned int *)hostent->h_addr_list[0]; + + // set the handle to the info + *handle = info; + + return 0; +} + +void gsiCancelResolvingHostname(GSIResolveHostnameHandle handle) +{ + gsifree(handle); + handle = NULL; +} + +unsigned int gsiGetResolvedIP(GSIResolveHostnameHandle handle) +{ + // we always do the resolve in the initial call for systems without + // an async version, so we'll always have the IP at this point + unsigned int ip = handle->ip; + gsifree(handle); + handle = NULL; + return ip; +} + +/////////////////////////////////////////////////////////////////////////////// +#endif // synch DNS lookup + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +char * goastrdup(const char *src) +{ + char *res; + if(src == NULL) //PANTS|02.11.00|check for NULL before strlen + return NULL; + res = (char *)gsimalloc(strlen(src) + 1); + if(res != NULL) //PANTS|02.02.00|check for NULL before strcpy + strcpy(res, src); + return res; +} + +unsigned short * goawstrdup(const unsigned short *src) +{ + unsigned short *res; + if(src == NULL) + return NULL; + res = (unsigned short *)gsimalloc((wcslen((wchar_t*)src) + 1) * sizeof(unsigned short)); + if(res != NULL) + wcscpy((wchar_t*)res, (const wchar_t*)src); + return res; +} + +#if !defined(_WIN32) + +char *_strlwr(char *string) +{ + char *hold = string; + while (*string) + { + *string = (char)tolower(*string); + string++; + } + + return hold; +} + +char *_strupr(char *string) +{ + char *hold = string; + while (*string) + { + *string = (char)toupper(*string); + string++; + } + + return hold; +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void SocketStartUp() +{ +#if defined(_WIN32) + WSADATA data; + + #if defined(_X360) + XNetStartupParams xnsp; + memset(&xnsp,0,sizeof(xnsp)); + xnsp.cfgSizeOfStruct=sizeof(xnsp); + xnsp.cfgFlags=XNET_STARTUP_BYPASS_SECURITY; + if(0 != XNetStartup(&xnsp)) + { + OutputDebugString("XNetStartup failed\n"); + } + #endif + + // added support for winsock2 + #if (!defined(_XBOX) || defined(_X360)) && (defined(GSI_WINSOCK2) || defined(_X360)) + WSAStartup(MAKEWORD(2,2), &data); + #else + WSAStartup(MAKEWORD(1,1), &data); + #endif + // end added +#endif +} + +void SocketShutDown() +{ +#if defined(_WIN32) + WSACleanup(); + #if defined(_X360) + XNetCleanup(); + #endif +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef _PS2 +extern int sceCdReadClock(); + +#if !defined(__MWERKS__) && !defined(_PS2) +typedef unsigned char u_char; +#endif + +typedef struct { + u_char stat; /* status */ + u_char second; /* second */ + u_char minute; /* minute */ + u_char hour; /* hour */ + + u_char pad; /* pad */ + u_char day; /* day */ + u_char month; /* month */ + u_char year; /* year */ +} sceCdCLOCK; + +static unsigned long GetTicks() +{ + unsigned long ticks; + asm volatile (" mfc0 %0, $9 " : "=r" (ticks)); + return ticks; +} + +#define DEC(x) (10*(x/16)+(x%16)) +#define _BASE_YEAR 70L +#define _MAX_YEAR 138L +#define _LEAP_YEAR_ADJUST 17L +int _days[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}; + +static time_t _gmtotime_t ( + int yr, /* 0 based */ + int mo, /* 1 based */ + int dy, /* 1 based */ + int hr, + int mn, + int sc + ) +{ + int tmpdays; + long tmptim; + struct tm tb; + + if ( ((long)(yr -= 1900) < _BASE_YEAR) || ((long)yr > _MAX_YEAR) ) + return (time_t)(-1); + + tmpdays = dy + _days[mo - 1]; + if ( !(yr & 3) && (mo > 2) ) + tmpdays++; + + tmptim = (long)yr - _BASE_YEAR; + + tmptim = ( ( ( ( tmptim ) * 365L + + ((long)(yr - 1) >> 2) - (long)_LEAP_YEAR_ADJUST + + (long)tmpdays ) + * 24L + (long)hr ) + * 60L + (long)mn ) + * 60L + (long)sc; + + tb.tm_yday = tmpdays; + tb.tm_year = yr; + tb.tm_mon = mo - 1; + tb.tm_hour = hr; + + return (tmptim >= 0) ? (time_t)tmptim : (time_t)(-1); +} + +time_t time(time_t *timer) +{ + time_t tim; + sceCdCLOCK clocktime; /* defined in libcdvd.h */ + + sceCdReadClock(&clocktime); /* libcdvd.a */ + + tim = _gmtotime_t ( DEC(clocktime.year)+2000, + DEC(clocktime.month), + DEC(clocktime.day), + DEC(clocktime.hour), + DEC(clocktime.minute), + DEC(clocktime.second)); + + if(timer) + *timer = tim; + + return tim; +} + +#endif /* _PS2 */ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_time current_time() //returns current time in milliseconds +{ +#if defined(_WIN32) + return (GetTickCount()); + +#elif defined(_PS2) + unsigned int ticks; + static unsigned int msec = 0; + static unsigned int lastticks = 0; + sceCdCLOCK lasttimecalled; /* defined in libcdvd.h */ + + if(!msec) + { + sceCdReadClock(&lasttimecalled); /* libcdvd.a */ + msec = (unsigned int)(DEC(lasttimecalled.day) * 86400000) + + (unsigned int)(DEC(lasttimecalled.hour) * 3600000) + + (unsigned int)(DEC(lasttimecalled.minute) * 60000) + + (unsigned int)(DEC(lasttimecalled.second) * 1000); + } + + ticks = (unsigned int)GetTicks(); + if(lastticks > ticks) + msec += (unsigned int)(((unsigned int)(-1) - lastticks) + ticks) / 300000; + else + msec += (unsigned int)(ticks-lastticks) / 300000; + lastticks = ticks; + + return msec; + +#elif defined(_UNIX) + struct timeval time; + + gettimeofday(&time, NULL); + return (time.tv_sec * 1000 + time.tv_usec / 1000); + +#elif defined(_NITRO) + assert(OS_IsTickAvailable() == TRUE); + return (gsi_time)OS_TicksToMilliSeconds(OS_GetTick()); + +#elif defined(_PSP) + struct SceRtcTick ticks; + int result = 0; + + result = sceRtcGetCurrentTick(&ticks); + if (result < 0) + { + ScePspDateTime time; + result = sceRtcGetCurrentClock(&time, 0); + if (result < 0) + return 0; // um...error handling? //Nope, should return zero since time cannot be zero + result = sceRtcGetTick(&time, &ticks); + if (result < 0) + return 0; //Nope, should return zero since time cannot be zero + } + + return (gsi_time)(ticks.tick / 1000); + +#elif defined(_PS3) + return (gsi_time)(sys_time_get_system_time()/1000); + +#elif defined(_REVOLUTION) + OSTick aTickNow= OSGetTick(); + gsi_time aMilliseconds = (gsi_time)OSTicksToMilliseconds(aTickNow); + return aMilliseconds; +#else + // unrecognized platform! contact devsupport + assert(0); +#endif + +} + +gsi_time current_time_hires() // returns current time in microseconds +{ +#ifdef _WIN32 +#if (!defined(_M_IX86) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64)) + static LARGE_INTEGER counterFrequency; + static BOOL haveCounterFrequency = FALSE; + static BOOL haveCounter = FALSE; + LARGE_INTEGER count; + + if(!haveCounterFrequency) + { + haveCounter = QueryPerformanceFrequency(&counterFrequency); + haveCounterFrequency = TRUE; + } + + if(haveCounter) + { + if(QueryPerformanceCounter(&count)) + { + return (gsi_time)(count.QuadPart * 1000000 / counterFrequency.QuadPart); + } + } +#endif + + return (current_time() / 1000); +#endif + +#ifdef _PS2 + unsigned int ticks; + static unsigned int msec = 0; + static unsigned int lastticks = 0; + sceCdCLOCK lasttimecalled; /* defined in libcdvd.h */ + + if(!msec) + { + sceCdReadClock(&lasttimecalled); /* libcdvd.a */ + msec = (unsigned int)(DEC(lasttimecalled.day) * 86400000) + + (unsigned int)(DEC(lasttimecalled.hour) * 3600000) + + (unsigned int)(DEC(lasttimecalled.minute) * 60000) + + (unsigned int)(DEC(lasttimecalled.second) * 1000); + msec *= 1000; + } + + ticks = (unsigned int)GetTicks(); + if(lastticks > ticks) + msec += ((sizeof(unsigned int) - lastticks) + ticks) / 300; + else + msec += (unsigned int)(ticks-lastticks) / 300; + lastticks = ticks; + + return msec; +#endif + +#ifdef _PSP + struct SceRtcTick ticks; + int result = 0; + + result = sceRtcGetCurrentTick(&ticks); + if (result < 0) + { + ScePspDateTime time; + result = sceRtcGetCurrentClock(&time, 0); + if (result < 0) + return 0; // um...error handling? //Nope, should return zero since time cannot be zero + result = sceRtcGetTick(&time, &ticks); + if (result < 0) + return 0; //Nope, should return zero since time cannot be zero + } + + return (gsi_time)(ticks.tick); +#endif + +#ifdef _UNIX + struct timeval time; + + gettimeofday(&time, NULL); + return (time.tv_sec * 1000000 + time.tv_usec); +#endif + +#ifdef _NITRO + assert(OS_IsTickAvailable() == TRUE); + return (gsi_time)OS_TicksToMicroSeconds(OS_GetTick()); +#endif + +#ifdef _PS3 + return (gsi_time)sys_time_get_system_time(); +#endif +} + + +void msleep(gsi_time msec) +{ +#if defined(_WIN32) + Sleep(msec); + +#elif defined(_PS2) + #ifdef SN_SYSTEMS + sn_delay((int)msec); + #endif + #ifdef EENET + if(msec >= 1000) + { + sleep(msec / 1000); + msec -= (msec / 1000); + } + if(msec) + usleep(msec * 1000); + #endif + #ifdef INSOCK + DelayThread(msec * 1000); + #endif + +#elif defined(_PSP) + sceKernelDelayThread(msec * 1000); + +#elif defined(_UNIX) + usleep(msec * 1000); + +#elif defined(_NITRO) + OS_Sleep(msec); + +#elif defined(_PS3) + sys_timer_usleep(msec* 1000); +#elif defined (_REVOLUTION) + OSSleepMilliseconds(msec); +#else + assert(0); // missing platform handler, contact devsupport +#endif +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// Cross-platform GSI wrapper time conversion functions +// +// NOTE: some portions of this copied from standard C library +#if defined(_NITRO) || defined(_REVOLUTION) + +// if an error occurs when calling mktime, return -1 +#define MKTIME_ERROR (time_t)(-1) + +// define common conversions for mktime +#define DAY_SEC (24L * 60L * 60L) /* secs in a day */ +#define YEAR_SEC (365L * DAY_SEC) /* secs in a year */ +#define FOUR_YEAR_SEC (1461L * DAY_SEC) /* secs in a 4 year interval */ +#define DEC_SEC 315532800L /* secs in 1970-1979 */ +#define BASE_DOW 4 /* 01-01-70 was a Thursday */ +#define BASE_YEAR 70L /* 1970 is the base year */ +#define LEAP_YEAR_ADJUST 17L /* Leap years 1900 - 1970 */ +#define MAX_YEAR 138L /* 2038 is the max year */ + +// ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed +#define ChkAdd(dest, src1, src2) ( ((src1 >= 0L) && (src2 >= 0L) \ + && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) ) + +// ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed +#define ChkMul(dest, src1, src2) ( src1 ? (dest/src1 != src2) : 0 ) + +int _lpdays[] = { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +int _days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; + +const char _dnames[] = { "SunMonTueWedThuFriSat" }; +/* Month names must be Three character abbreviations strung together */ +const char _mnames[] = { "JanFebMarAprMayJunJulAugSepOctNovDec" }; + +static struct tm tb = { 0 }; /* time block used in SecondsToDate */ + +static char buf[26]; /* buffer used to store string in SecondsToString */ + + +static char * store_dt(char *, int); +static char * store_dt(char *p, int val) +{ + *p++ = (char)(_T('0') + val / 10); + *p++ = (char)(_T('0') + val % 10); + return(p); +} +#endif //_NITRO || _REVOLUTION + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// GSI equivalent of Standard C-lib "gmtime function" +struct tm * gsiSecondsToDate(const time_t *timp) +{ +#if !defined(_NITRO) && !defined(_REVOLUTION) + + // for all platforms that support the standard C 'gmtime' use that + return gmtime(timp); + +#else + time_t caltim = *timp; /* calendar time to convert */ + int islpyr = 0; /* is-current-year-a-leap-year flag */ + int tmptim; + int *mdays; /* pointer to days or lpdays */ + struct tm *ptb = &tb; + + + if ( caltim < 0L ) + return(NULL); + + /* + * Determine years since 1970. First, identify the four-year interval + * since this makes handling leap-years easy (note that 2000 IS a + * leap year and 2100 is out-of-range). + */ + tmptim = (int)(caltim / FOUR_YEAR_SEC); + caltim -= ((long)tmptim * FOUR_YEAR_SEC); + + /* + * Determine which year of the interval + */ + tmptim = (tmptim * 4) + 70; /* 1970, 1974, 1978,...,etc. */ + + if ( caltim >= YEAR_SEC ) + { + tmptim++; /* 1971, 1975, 1979,...,etc. */ + caltim -= YEAR_SEC; + + if ( caltim >= YEAR_SEC ) + { + tmptim++; /* 1972, 1976, 1980,...,etc. */ + caltim -= YEAR_SEC; + + /* + * Note, it takes 366 days-worth of seconds to get past a leap + * year. + */ + if ( caltim >= (YEAR_SEC + DAY_SEC) ) + { + tmptim++; /* 1973, 1977, 1981,...,etc. */ + caltim -= (YEAR_SEC + DAY_SEC); + } + else + { + /* + * In a leap year after all, set the flag. + */ + islpyr++; + } + } + } + + /* + * tmptim now holds the value for tm_year. caltim now holds the + * number of elapsed seconds since the beginning of that year. + */ + ptb->tm_year = tmptim; + + /* + * Determine days since January 1 (0 - 365). This is the tm_yday value. + * Leave caltim with number of elapsed seconds in that day. + */ + ptb->tm_yday = (int)(caltim / DAY_SEC); + caltim -= (long)(ptb->tm_yday) * DAY_SEC; + + /* + * Determine months since January (0 - 11) and day of month (1 - 31) + */ + if ( islpyr ) + mdays = _lpdays; + else + mdays = _days; + + + for ( tmptim = 1 ; mdays[tmptim] < ptb->tm_yday ; tmptim++ ) ; + + ptb->tm_mon = --tmptim; + + ptb->tm_mday = ptb->tm_yday - mdays[tmptim]; + + /* + * Determine days since Sunday (0 - 6) + */ + ptb->tm_wday = ((int)(*timp / DAY_SEC) + BASE_DOW) % 7; + + /* + * Determine hours since midnight (0 - 23), minutes after the hour + * (0 - 59), and seconds after the minute (0 - 59). + */ + ptb->tm_hour = (int)(caltim / 3600); + caltim -= (long)ptb->tm_hour * 3600L; + + ptb->tm_min = (int)(caltim / 60); + ptb->tm_sec = (int)(caltim - (ptb->tm_min) * 60); + + ptb->tm_isdst = 0; + return( (struct tm *)ptb ); +#endif +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// GSI equivalent of Standard C-lib "mktime function" +time_t gsiDateToSeconds(struct tm *tb) +{ +#if !defined(_NITRO) && !defined(_REVOLUTION) + + // for all platforms that support the standard C 'mktime' use that + return mktime(tb); + +#else + time_t tmptm1, tmptm2, tmptm3; + struct tm *tbtemp; + /* + * First, make sure tm_year is reasonably close to being in range. + */ + if ( ((tmptm1 = tb->tm_year) < BASE_YEAR - 1) || (tmptm1 > MAX_YEAR + 1) ) + return MKTIME_ERROR; + + + /* + * Adjust month value so it is in the range 0 - 11. This is because + * we don't know how many days are in months 12, 13, 14, etc. + */ + + if ( (tb->tm_mon < 0) || (tb->tm_mon > 11) ) { + + /* + * no danger of overflow because the range check above. + */ + tmptm1 += (tb->tm_mon / 12); + + if ( (tb->tm_mon %= 12) < 0 ) { + tb->tm_mon += 12; + tmptm1--; + } + + /* + * Make sure year count is still in range. + */ + if ( (tmptm1 < BASE_YEAR - 1) || (tmptm1 > MAX_YEAR + 1) ) + return MKTIME_ERROR; + } + + /***** HERE: tmptm1 holds number of elapsed years *****/ + + /* + * Calculate days elapsed minus one, in the given year, to the given + * month. Check for leap year and adjust if necessary. + */ + tmptm2 = _days[tb->tm_mon]; + if ( !(tmptm1 & 3) && (tb->tm_mon > 1) ) + tmptm2++; + + /* + * Calculate elapsed days since base date (midnight, 1/1/70, UTC) + * + * + * 365 days for each elapsed year since 1970, plus one more day for + * each elapsed leap year. no danger of overflow because of the range + * check (above) on tmptm1. + */ + tmptm3 = (tmptm1 - BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2) + - LEAP_YEAR_ADJUST; + + /* + * elapsed days to current month (still no possible overflow) + */ + tmptm3 += tmptm2; + + /* + * elapsed days to current date. overflow is now possible. + */ + tmptm1 = tmptm3 + (tmptm2 = (long)(tb->tm_mday)); + if ( ChkAdd(tmptm1, tmptm3, tmptm2) ) + return MKTIME_ERROR; + + /***** HERE: tmptm1 holds number of elapsed days *****/ + + /* + * Calculate elapsed hours since base date + */ + tmptm2 = tmptm1 * 24L; + if ( ChkMul(tmptm2, tmptm1, 24L) ) + return MKTIME_ERROR; + + tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_hour); + if ( ChkAdd(tmptm1, tmptm2, tmptm3) ) + return MKTIME_ERROR; + + /***** HERE: tmptm1 holds number of elapsed hours *****/ + + /* + * Calculate elapsed minutes since base date + */ + + tmptm2 = tmptm1 * 60L; + if ( ChkMul(tmptm2, tmptm1, 60L) ) + return MKTIME_ERROR; + + tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_min); + if ( ChkAdd(tmptm1, tmptm2, tmptm3) ) + return MKTIME_ERROR; + + /***** HERE: tmptm1 holds number of elapsed minutes *****/ + + /* + * Calculate elapsed seconds since base date + */ + + tmptm2 = tmptm1 * 60L; + if ( ChkMul(tmptm2, tmptm1, 60L) ) + return MKTIME_ERROR; + + tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_sec); + if ( ChkAdd(tmptm1, tmptm2, tmptm3) ) + return MKTIME_ERROR; + + /***** HERE: tmptm1 holds number of elapsed seconds *****/ + + if ( (tbtemp = gsiSecondsToDate(&tmptm1)) == NULL ) + return MKTIME_ERROR; + + + /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/ + /***** for local time if requested *****/ + + *tb = *tbtemp; + return (time_t)tmptm1; +#endif +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// GSI equivalent of Standard C-lib "ctime function" +char * gsiSecondsToString(const time_t *timp) +{ +#if !defined(_NITRO) && !defined(_REVOLUTION) + + // for all platforms that support the standard C 'ctime' use that + return ctime(timp); + +#else + char *p = buf; + int day, mon; + int i; + struct tm *ptm; + + ptm = gsiSecondsToDate(timp); /* parse seconds into date structure */ + + p = buf; /* use static buffer */ + + /* copy day and month names into the buffer */ + + day = ptm->tm_wday * 3; /* index to correct day string */ + mon = ptm->tm_mon * 3; /* index to correct month string */ + + for (i=0; i < 3; i++,p++) { + *p = *(_dnames + day + i); + *(p+4) = *(_mnames + mon + i); + } + + *p = _T(' '); /* blank between day and month */ + + p += 4; + + *p++ = _T(' '); + p = store_dt(p, ptm->tm_mday); /* day of the month (1-31) */ + *p++ = _T(' '); + p = store_dt(p, ptm->tm_hour); /* hours (0-23) */ + *p++ = _T(':'); + p = store_dt(p, ptm->tm_min); /* minutes (0-59) */ + *p++ = _T(':'); + p = store_dt(p, ptm->tm_sec); /* seconds (0-59) */ + *p++ = _T(' '); + p = store_dt(p, 19 + (ptm->tm_year/100)); /* year (after 1900) */ + p = store_dt(p, ptm->tm_year%100); + *p++ = _T('\n'); + *p = _T('\0'); + + return ((char *) buf); +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Cross platform random number generator +#define RANa 16807 // multiplier +#define LONGRAND_MAX 2147483647L // 2**31 - 1 + +static long randomnum = 1; + +static long nextlongrand(long seed) +{ + unsigned + + long lo, hi; + lo = RANa *(unsigned long)(seed & 0xFFFF); + hi = RANa *((unsigned long)seed >> 16); + lo += (hi & 0x7FFF) << 16; + + if (lo > LONGRAND_MAX) + { + lo &= LONGRAND_MAX; + ++lo; + } + lo += hi >> 15; + + if (lo > LONGRAND_MAX) + { + lo &= LONGRAND_MAX; + ++lo; + } + + return(long)lo; +} + +// return next random long +static long longrand(void) +{ + randomnum = nextlongrand(randomnum); + return randomnum; +} + +// to seed it +void Util_RandSeed(unsigned long seed) +{ + // nonzero seed + randomnum = seed ? (long)(seed & LONGRAND_MAX) : 1; +} + +int Util_RandInt(int low, int high) +{ + unsigned int range = (unsigned int)high-low; + int num; + + if (range == 0) + return (low); // Prevent divide by zero + + num = (int)(longrand() % range); + + return(num + low); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/***************************** +UNICODE ENCODING +******************************/ + +static void QuartToTrip(char *quart, char *trip, int inlen) +{ + if (inlen >= 2) + trip[0] = (char)(quart[0] << 2 | quart[1] >> 4); + if (inlen >= 3) + trip[1] = (char)((quart[1] & 0x0F) << 4 | quart[2] >> 2); + if (inlen >= 4) + trip[2] = (char)((quart[2] & 0x3) << 6 | quart[3]); +} + +static void TripToQuart(const char *trip, char *quart, int inlen) +{ + unsigned char triptemp[3]; + int i; + for (i = 0; i < inlen ; i++) + { + triptemp[i] = (unsigned char)trip[i]; + } + while (i < 3) //fill the rest with 0 + { + triptemp[i] = 0; + i++; + } + quart[0] = (char)(triptemp[0] >> 2); + quart[1] = (char)(((triptemp[0] & 3) << 4) | (triptemp[1] >> 4)); + quart[2] = (char)((triptemp[1] & 0x0F) << 2 | (triptemp[2] >> 6)); + quart[3] = (char)(triptemp[2] & 0x3F); + +} + +const char defaultEncoding[] = {'+','/','='}; +const char alternateEncoding[] = {'[',']','_'}; +const char urlSafeEncodeing[] = {'-','_','='}; + +void B64Decode(const char *input, char *output, int inlen, int * outlen, int encodingType) +{ + const char *encoding = NULL; + const char *holdin = input; + int readpos = 0; + int writepos = 0; + char block[4]; + + //int outlen = -1; + //int inlen = (int)strlen(input); + + // 10-31-2004 : Added by Saad Nader + // now supports URL safe encoding + //////////////////////////////////////////////// + switch(encodingType) + { + case 1: + encoding = alternateEncoding; + break; + case 2: + encoding = urlSafeEncodeing; + break; + default: encoding = defaultEncoding; + } + + GS_ASSERT(inlen >= 0); + if (inlen <= 0) + { + if (outlen) + *outlen = 0; + output[0] = '\0'; + return; + } + + // Break at end of string or padding character + while (readpos < inlen && input[readpos] != encoding[2]) + { + // 'A'-'Z' maps to 0-25 + // 'a'-'z' maps to 26-51 + // '0'-'9' maps to 52-61 + // 62 maps to encoding[0] + // 63 maps to encoding[1] + if (input[readpos] >= '0' && input[readpos] <= '9') + block[readpos%4] = (char)(input[readpos] - 48 + 52); + else if (input[readpos] >= 'a' && input[readpos] <= 'z') + block[readpos%4] = (char)(input[readpos] - 71); + else if (input[readpos] >= 'A' && input[readpos] <= 'Z') + block[readpos%4] = (char)(input[readpos] - 65); + else if (input[readpos] == encoding[0]) + block[readpos%4] = 62; + else if (input[readpos] == encoding[1]) + block[readpos%4] = 63; + + // padding or '\0' characters also mark end of input + else if (input[readpos] == encoding[2]) + break; + else if (input[readpos] == '\0') + break; + else + { + // (assert(0)); //bad input data + if (outlen) + *outlen = 0; + output[0] = '\0'; + return; //invaid data + } + + // every 4 bytes, convert QuartToTrip into destination + if (readpos%4==3) // zero based, so (3%4) means four bytes, 0-1-2-3 + { + QuartToTrip(block, &output[writepos], 4); + writepos += 3; + } + readpos++; + } + + // Convert any leftover characters in block + if ((readpos != 0) && (readpos%4 != 0)) + { + // fill block with pad (required for QuartToTrip) + memset(&block[readpos%4], encoding[2], (unsigned int)4-(readpos%4)); + QuartToTrip(block, &output[writepos], readpos%4); + + // output bytes depend on the number of non-pad input bytes + if (readpos%4 == 3) + writepos += 2; + else + writepos += 1; + } + + if (outlen) + *outlen = writepos; + + GSI_UNUSED(holdin); +} + + + +void B64Encode(const char *input, char *output, int inlen, int encodingType) +{ + const char *encoding; + char *holdout = output; + char *lastchar; + int todo = inlen; + + // 10-31-2004 : Added by Saad Nader + // now supports URL safe encoding + //////////////////////////////////////////////// + switch(encodingType) + { + case 1: + encoding = alternateEncoding; + break; + case 2: + encoding = urlSafeEncodeing; + break; + default: encoding = defaultEncoding; + } + +//assume interval of 3 + while (todo > 0) + { + TripToQuart(input, output, min(todo, 3)); + output += 4; + input += 3; + todo -= 3; + } + lastchar = output; + if (inlen % 3 == 1) + lastchar -= 2; + else if (inlen % 3 == 2) + lastchar -= 1; + *output = 0; //null terminate! + while (output > holdout) + { + output--; + if (output >= lastchar) //pad the end + *output = encoding[2]; + else if (*output <= 25) + *output = (char)(*output + 65); + else if (*output <= 51) + *output = (char)(*output + 71); + else if (*output <= 61) + *output = (char)(*output + 48 - 52); + else if (*output == 62) + *output = encoding[0]; + else if (*output == 63) + *output = encoding[1]; + } +} + +int B64DecodeLen(const char *input, int encodingType) +{ + const char *encoding; + const char *holdin = input; + + switch(encodingType) + { + case 1: + encoding = alternateEncoding; + break; + case 2: + encoding = urlSafeEncodeing; + break; + default: encoding = defaultEncoding; + } + + while (*input) + { + if (*input == encoding[2]) + return (input - holdin) / 4 * 3 + (input - holdin - 1) % 4; + input++; + } + + return (input - holdin) / 4 * 3; +} + +void B64InitEncodeStream(B64StreamData *data, const char *input, int len, int encodingType) +{ + data->input = input; + data->len = len; + data->encodingType = encodingType; +} + +gsi_bool B64EncodeStream(B64StreamData *data, char output[4]) +{ + const char *encoding; + char *c; + int i; + + if(data->len <= 0) + return gsi_false; + + // 10-31-2004 : Added by Saad Nader + // now supports URL safe encoding + //////////////////////////////////////////////// + switch(data->encodingType) + { + case 1: + encoding = alternateEncoding; + break; + case 2: + encoding = urlSafeEncodeing; + break; + default: encoding = defaultEncoding; + } + + TripToQuart(data->input, output, min(data->len, 3)); + data->input += 3; + data->len -= 3; + + for(i = 0 ; i < 4 ; i++) + { + c = &output[i]; + if (*c <= 25) + *c = (char)(*c + 65); + else if (*c <= 51) + *c = (char)(*c + 71); + else if (*c <= 61) + *c = (char)(*c + 48 - 52); + else if (*c == 62) + *c = encoding[0]; + else if (*c == 63) + *c = encoding[1]; + } + + if(data->len < 0) + { + output[3] = encoding[2]; + if(data->len == -2) + output[2] = encoding[2]; + } + + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiPadRight(char *cArray, char padChar, int cLength); +char * gsiXxteaAlg(const char *sIn, int nIn, char key[XXTEA_KEY_SIZE], int bEnc, int *nOut); + +void gsiPadRight(char *cArray, char padChar, int cLength) +{ + int diff; + int length = (int)strlen(cArray); + + diff = cLength - length; + memset(&cArray[length], padChar, (size_t)diff); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// The heart of the XXTEA encryption/decryption algorithm. +// +// sIn: Input stream. +// nIn: Input length (bytes). +// key: Key (only first 128 bits are significant). +// bEnc: Encrypt (else decrypt)? +char * gsiXxteaAlg(const char *sIn, int nIn, char key[XXTEA_KEY_SIZE], int bEnc, int *nOut) +{ + int i, p, n1; + unsigned int *k, *v, z, y; + char *oStr = NULL, *pStr = NULL; + char *sIn2 = NULL; + ///////////////////////////////// + // ERROR CHECK! + if (!sIn || !key[0] || nIn == 0) + return NULL; + + // Convert stream length to a round number of 32-bit words + // Convert byte count to 32-bit word count + if (nIn % 4 == 0) // Fix for null terminated strings divisible by 4 + nIn = (nIn/4)+1; + else + nIn = (nIn + 3)/4; + + if ( nIn <= 1 ) // XXTEA requires at least 64 bits + nIn = 2; + + // Load and zero-pad first 16 characters (128 bits) of key + gsiPadRight( key , '\0', XXTEA_KEY_SIZE); + k = (unsigned int *)key; + + // Load and zero-pad entire input stream as 32-bit words + sIn2 = (char *)gsimalloc((size_t)(4 * nIn)); + strcpy(sIn2, sIn); + gsiPadRight( sIn2, '\0', 4*nIn); + v = (unsigned int *)sIn2; + + // Prepare to encrypt or decrypt + n1 = nIn - 1; + z = v[ n1 ]; + y = v[ 0 ]; + i = ( int )( 6 + 52/nIn ); + + if (bEnc == 1) // Encrypt + { + unsigned int sum = 0; + while ( i-- != 0 ) + { + int e; + sum += 0x9E3779B9; + e = ( int )( sum >> 2 ); + for ( p = -1; ++p < nIn; ) + { + y = v[( p < n1 ) ? p + 1 : 0 ]; + z = ( v[ p ] += + ( (( z >> 5 ) ^ ( y << 2 )) + + (( y >> 3 ) ^ ( z << 4 ))) + ^ ( ( sum ^ y ) + + ( k[( p ^ e ) & 3 ] ^ z ))); + } + } + } + else if (bEnc == 0) // Decrypt + { + unsigned int sum = ( unsigned int ) i * 0x9E3779B9; + while ( sum != 0 ) + { + int e = ( int )( sum >> 2 ); + for ( p = nIn; p-- != 0; ) + { + z = v[( p != 0 ) ? p - 1 : n1 ]; + y = ( v[ p ] -= + ( (( z >> 5 ) ^ ( y << 2 )) + + (( y >> 3 ) ^ ( z << 4 ))) + ^ ( ( sum ^ y ) + + ( k[( p ^ e ) & 3 ] ^ z ))); + } + sum -= 0x9E3779B9; + } + } + else return NULL; + // Convert result from 32-bit words to a byte stream + + + oStr = (char *)gsimalloc((size_t)(4 * nIn + 1)); + pStr = oStr; + *nOut = 4 *nIn; + for ( i = -1; ++i < nIn; ) + { + unsigned int q = v[ i ]; + + *pStr++ = (char)(q & 0xFF); + *pStr++ = (char)(( q >> 8 ) & 0xFF); + *pStr++ = (char)(( q >> 16 ) & 0xFF); + *pStr++ = (char)(( q >> 24 ) & 0xFF); + } + *pStr = '\0'; + gsifree(sIn2); + + return oStr; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// XXTEA Encrpyt +// params +// iStr : the input string to be encrypted +// iLength : the length of the input string +// key : the key used to encrypt +char * gsXxteaEncrypt(const char * iStr, int iLength, char key[XXTEA_KEY_SIZE], int *oLength) +{ + return gsiXxteaAlg( iStr, iLength, key, 1, oLength ); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// XXTEA Decrypt +// params +// iStr : the input string to be decrypted +// iLength : the length of the input string +// key : the key used to decrypt +char * gsXxteaDecrypt(const char * iStr, int iLength, char key[XXTEA_KEY_SIZE], int *oLength) +{ + return gsiXxteaAlg( iStr, iLength, key, 0, oLength); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_DEBUG) + +void gsiCheckStack(void) +{ +#if defined(_NITRO) +#if 1 + OS_CheckStack(OS_GetCurrentThread()); +#elif 1 + static gsi_bool checkFailed = gsi_false; + if(!checkFailed) + { + OSStackStatus status = OS_GetStackStatus(OS_GetCurrentThread()); + if(status != 0) + { + const char * reason; + if(status == OS_STACK_OVERFLOW) + reason = "OVERFLOW"; + else if(status == OS_STACK_ABOUT_TO_OVERFLOW) + reason = "ABOUT TO OVERFLOW"; + else if(status == OS_STACK_UNDERFLOW) + reason = "UNDERFLOW"; + else + reason = "UNKOWN REASON"; + + OS_TPrintf("STACK CHECK FAILED!: %s\n", reason); + + checkFailed = gsi_true; + } + } +#endif +#endif // nitro +} +#endif // _DEBUG + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef SN_SYSTEMS +int GOAGetLastError(SOCKET s) +{ + int val = 0; + int soval = sizeof(val); + if (0 != getsockopt(s,SOL_SOCKET,SO_ERROR,&val,&soval)) + return 0; // getsockopt failed + else + return val; +} +#endif + +#ifdef _NITRO +static const char * GOAGetUniqueID_Internal(void) +{ + static char keyval[17]; + u8 MAC[MAC_ALEN]; + + // check if we already have the Unique ID + if(keyval[0]) + return keyval; + + // get the MAC + IP_GetMacAddr(NULL, MAC); + + // format it + sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000", + MAC[0] & 0xFF, + MAC[1] & 0xFF, + MAC[2] & 0xFF, + MAC[3] & 0xFF, + MAC[4] & 0xFF, + MAC[5] & 0xFF); + + return keyval; +} +#endif + + +#ifdef _PS2 +#ifdef UNIQUEID + +#if defined(EENET) + +#include +// Removed due to updated sony libraries, Saad Nader +//#include +#include + +static const char * GetMAC(void) +{ + static struct sceEENetEtherAddr linkAddress; + struct sceEENetIfname * interfaces; + struct sceEENetIfname * interface; + int num; + int type; + int len; + int i; + const unsigned char * MAC = NULL; + + // get the local interfaces + sceEENetGetIfnames(NULL, &num); + interfaces = (struct sceEENetIfname *)gsimalloc(num * sizeof(struct sceEENetIfname)); + if(!interfaces) + return NULL; + sceEENetGetIfnames(interfaces, &num); + + // loop through the interfaces + for(i = 0 ; i < num ; i++) + { + // the next interface + interface = &interfaces[i]; + //printf("eenet%d: %s\n", i, interface->ifn_name); + + // get the type + len = sizeof(type); + if(sceEENetGetIfinfo(interface->ifn_name, sceEENET_IFINFO_IFTYPE, &type, &len) != 0) + continue; + //printf("eenet%d type: %d\n", i, type); + + // check for ethernet + if(type != sceEENET_IFTYPE_ETHER) + continue; + //printf("eenet%d: ethernet\n", i); + + // get the address + len = sizeof(linkAddress); + if(sceEENetGetIfinfo(interface->ifn_name, sceEENET_IFINFO_MACADDR, &linkAddress, &len) != 0) + continue; + MAC = linkAddress.ether_addr_octet; + //printf("eenet%d: MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", i, MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]); + + break; + } + + // free the interfaces + gsifree(interfaces); + + return MAC; +} + +#elif defined(SN_SYSTEMS) + + static const char * GetMAC(void) + { + static char MAC[6]; + int len = sizeof(MAC); + int rcode; + + // get the MAC + rcode = sndev_get_status(0, SN_DEV_STAT_MAC, MAC, &len); + if((rcode != 0) || (len != 6)) + return NULL; + + return MAC; + } + +#elif defined(INSOCK) + + static const char * GetMAC(void) + { + // Get the MAC address using the interface control + static char MAC[16]; + extern sceSifMClientData gGSIInsockClientData; + extern u_int gGSIInsockSocketBuffer[NETBUFSIZE] __attribute__((aligned(64))); + + int result = sceInetInterfaceControl(&gGSIInsockClientData, &gGSIInsockSocketBuffer, + 1, sceInetCC_GetHWaddr, MAC, sizeof(MAC)); + if (result == sceINETE_OK) + return MAC; + + // error + return NULL; + } + +#endif + +static const char * GOAGetUniqueID_Internal(void) +{ + static char keyval[17]; + const char * MAC; + + // check if we already have the Unique ID + if(keyval[0]) + return keyval; + + // get the MAC + MAC = GetMAC(); + if(!MAC) + { + // error getting the MAC + static char errorMAC[6] = { 1, 2, 3, 4, 5, 6 }; + MAC = errorMAC; + } + + // format it + sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000", + MAC[0] & 0xFF, + MAC[1] & 0xFF, + MAC[2] & 0xFF, + MAC[3] & 0xFF, + MAC[4] & 0xFF, + MAC[5] & 0xFF); + + return keyval; +} + +#endif // UNIQUEID +#endif // _PS2 + + +#if ((defined(_WIN32) && !defined(_XBOX)) || defined(_UNIX)) + +static void GenerateID(char *keyval) +{ + int i; + const char crypttab[63] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifdef _WIN32 + LARGE_INTEGER l1; + UINT seed; + if (QueryPerformanceCounter(&l1)) + seed = (l1.LowPart ^ l1.HighPart); + else + seed = 0; + Util_RandSeed(seed ^ GetTickCount() ^ (unsigned long)time(NULL) ^ clock()); +#else + Util_RandSeed(time(NULL) ^ clock()); +#endif + for (i = 0; i < 19; i++) + if (i == 4 || i == 9 || i == 14) + keyval[i] = '-'; + else + keyval[i] = crypttab[Util_RandInt(0, 62)]; + keyval[19] = 0; +} + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif + +#ifdef _WIN32 +#define REG_KEY "Software\\GameSpy\\GameSpy 3D\\Registration" +#endif + +const char * GOAGetUniqueID_Internal(void) +{ + static char keyval[PATH_MAX] = ""; + unsigned int ret; + +#ifdef _WIN32 + int docreate; + HKEY thekey; + DWORD thetype = REG_SZ; + DWORD len = MAX_PATH; + DWORD disp; + + if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_KEY, 0, KEY_ALL_ACCESS, &thekey) != ERROR_SUCCESS) + docreate = 1; + else + docreate = 0; + ret = RegQueryValueExA(thekey, (LPCSTR)"Crypt", 0, &thetype, (LPBYTE)keyval, &len); +#else + FILE *f; + f = fopen("id.bin","r"); + if (!f) + ret = 0; + else + { + ret = fread(keyval,1,19,f); + keyval[ret] = 0; + fclose(f); + } +#endif + + if (ret != 0 || strlen(keyval) != 19)//need to generate a new key + { + GenerateID(keyval); +#ifdef _WIN32 + if (docreate) + { + ret = RegCreateKeyExA(HKEY_CURRENT_USER, REG_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &thekey, &disp); + } + RegSetValueExA(thekey, (LPCSTR)"Crypt", 0, REG_SZ, (const LPBYTE)keyval, strlen(keyval)+1); +#else + f = fopen("id.bin","w"); + if (f) + { + fwrite(keyval,1,19,f); + fclose(f); + } else + keyval[0] = 0; //don't generate one each time!! +#endif + } + +#ifdef _WIN32 + RegCloseKey(thekey); +#endif + + // Strip out the -'s. + ///////////////////// + memmove(keyval + 4, keyval + 5, 4); + memmove(keyval + 8, keyval + 10, 4); + memmove(keyval + 12, keyval + 15, 4); + keyval[16] = '\0'; + + return keyval; +} + +#endif + +#ifdef _PSP +// Included here so that the implementation can appear in gsPlatformPSP.c +const char * GOAGetUniqueID_Internal(void); +#endif + + +#if (!defined(_PS2) && !defined(_PS3) && !defined(_XBOX) && !defined(_PSP)) || defined(UNIQUEID) +GetUniqueIDFunction GOAGetUniqueID = GOAGetUniqueID_Internal; +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} +#endif diff --git a/xrGameSpy/gamespy/common/gsPlatformUtil.h b/xrGameSpy/gamespy/common/gsPlatformUtil.h new file mode 100644 index 00000000000..1e56173487d --- /dev/null +++ b/xrGameSpy/gamespy/common/gsPlatformUtil.h @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSUTILITY_H__ +#define __GSUTILITY_H__ + + +#include "gsPlatform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Async DNS lookup + +// async way to resolve a hostname to an IP +typedef struct GSIResolveHostnameInfo * GSIResolveHostnameHandle; +#define GSI_STILL_RESOLVING_HOSTNAME 0 +#define GSI_ERROR_RESOLVING_HOSTNAME 0xFFFFFFFF + +// start resolving a hostname +// returns 0 on success, -1 on error +int gsiStartResolvingHostname(const char * hostname, GSIResolveHostnameHandle * handle); +// cancel a resolve in progress +void gsiCancelResolvingHostname(GSIResolveHostnameHandle handle); +// returns GSI_STILL_RESOLVING if still resolving the hostname +// returns GSI_ERROR_RESOLVING if it was unable to resolve the hostname +// on success, returns the IP of the host in network byte order +unsigned int gsiGetResolvedIP(GSIResolveHostnameHandle handle); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Get rid of compiler warnings when parameters are never used +// (Mainly used in sample apps and callback for platform switches) +#if (defined(__MWERKS__) && !defined(_NITRO)) || defined(WIN32) + #define GSI_UNUSED(x) x +#elif defined(_PS2) || defined(_NITRO) || defined(_PS3) || defined(_MACOSX) + #define GSI_UNUSED(x) {void* y=&x;y=NULL;} +#elif defined(_PSP) +#define GSI_UNUSED(x) (void)x; + +#else + #define GSI_UNUSED(x) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Cross platform random number generator +void Util_RandSeed(unsigned long seed); // to seed it +int Util_RandInt(int low, int high); // retrieve a random int + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Base 64 encoding (printable characters) +void B64Encode(const char *input, char *output, int inlen, int encodingType); +void B64Decode(const char *input, char *output, int inlen, int * outlen, int encodingType); + +// returns the length of the binary data represented by the base64 input string +int B64DecodeLen(const char *input, int encodingType); + +typedef struct +{ + const char *input; + int len; + int encodingType; +} B64StreamData; + +void B64InitEncodeStream(B64StreamData *data, const char *input, int len, int encodingType); + +// returns gsi_false if the stream has ended +gsi_bool B64EncodeStream(B64StreamData *data, char output[4]); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define XXTEA_KEY_SIZE 17 +gsi_i8 * gsXxteaEncrypt(const gsi_i8 * iStr, gsi_i32 iLength, gsi_i8 key[XXTEA_KEY_SIZE], gsi_i32 *oLength); +gsi_i8 * gsXxteaDecrypt(const gsi_i8 * iStr, gsi_i32 iLength, gsi_i8 key[XXTEA_KEY_SIZE], gsi_i32 *oLength); + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#if defined(_DEBUG) + void gsiCheckStack(void); +#else + #define gsiCheckStack() +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// time functions + +gsi_time current_time(); // milliseconds +gsi_time current_time_hires(); // microseconds +void msleep(gsi_time msec); // milliseconds + +// GSI equivalent of common C-lib time functions +struct tm * gsiSecondsToDate(const time_t *timp); //gmtime +time_t gsiDateToSeconds(struct tm *tb); //mktime +char * gsiSecondsToString(const time_t *timp); //ctime + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Misc utilities + + +#if defined(_NITRO) + time_t time(time_t *timer); + + #define gmtime(t) gsiSecondsToDate(t) + #define ctime(t) gsiSecondsToString(t) + #define mktime(t) gsiDateToSeconds(t) +#elif defined(_REVOLUTION) + time_t gsiTimeInSec(time_t *timer); + struct tm *gsiGetGmTime(time_t *theTime); + char *gsiCTime(time_t *theTime); + #define time(t) gsiTimeInSec(t) + #define gmtime(t) gsiGetGmTime(t) + #define ctime(t) gsiCTime(t) +#else + #include +#endif + + + #ifndef SOMAXCONN + #define SOMAXCONN 5 +#endif + +typedef const char * (* GetUniqueIDFunction)(); + +extern GetUniqueIDFunction GOAGetUniqueID; + +// Prototypes so the compiler won't warn +#ifdef _PS2 +extern int wprintf(const wchar_t*,...); +#endif + + +// 64-bit Integer reads and writes +gsi_i64 gsiStringToInt64(const char *theNumberStr); +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber); +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} +#endif + +#endif //__GSUTILITY_H__ + diff --git a/xrGameSpy/gamespy/common/gsRC4.c b/xrGameSpy/gamespy/common/gsRC4.c new file mode 100644 index 00000000000..3d8dbb18014 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsRC4.c @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCommon.h" +#include "gsRC4.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void swap_byte (unsigned char *a, unsigned char *b) +{ + unsigned char swapByte; + + swapByte = *a; + *a = *b; + *b = swapByte; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void RC4Init(RC4Context *context, const unsigned char *key, int len) +{ + int i=0; + unsigned char stateIndex = 0; + unsigned char keyIndex = 0; + + // must supply a key + assert(key != NULL && len != 0); + if (key == NULL || len == 0) + return; + + context->x = 0; + context->y = 0; + + for (i=0; i<256; i++) + context->state[i] = (unsigned char)i; + + for (i=0; i<256; i++) + { + stateIndex = (unsigned char)(stateIndex + context->state[i] + key[keyIndex]); + swap_byte(&context->state[i], &context->state[stateIndex]); + keyIndex = (unsigned char)((keyIndex+1)%len); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void RC4Encrypt(RC4Context *context, const unsigned char *src, unsigned char *dest, int len) +{ + int i = 0; + for (i=0; ix = (unsigned char)(context->x + 1); // ok to wrap around from overflow + context->y = (unsigned char)(context->y + context->state[context->x]); // ditto + swap_byte(&context->state[context->x], &context->state[context->y]); + dest[i] = (unsigned char)(src[i] ^ context->state[(unsigned char)(context->state[context->x]+context->state[context->y])]); + } +} diff --git a/xrGameSpy/gamespy/common/gsRC4.h b/xrGameSpy/gamespy/common/gsRC4.h new file mode 100644 index 00000000000..e5c6bc53afb --- /dev/null +++ b/xrGameSpy/gamespy/common/gsRC4.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSRC4_H__ +#define __GSRC4_H__ + + +#include "gsCommon.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct RC4Context +{ + unsigned char x; + unsigned char y; + unsigned char state[256]; +} RC4Context; + +void RC4Init(RC4Context *context, const unsigned char *key, int len); +void RC4Encrypt(RC4Context *context, const unsigned char *src, unsigned char *dest, int len); + +// Note: RC4Encrypt with src==dest is OK + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} +#endif +#endif // __GSRC4_H__ diff --git a/xrGameSpy/gamespy/common/gsSHA1.c b/xrGameSpy/gamespy/common/gsSHA1.c new file mode 100644 index 00000000000..c4e61061f5f --- /dev/null +++ b/xrGameSpy/gamespy/common/gsSHA1.c @@ -0,0 +1,390 @@ +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +//#include "sha1.h" +#include "gsSHA1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i>>2] + >> 8 * ( 3 - ( i & 0x03 ) )); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const uint8_t *message_array, + unsigned length) +{ + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (uint8_t)(*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = (uint32_t)(context->Message_Block[t * 4] << 24); + W[t] |= (uint32_t)(context->Message_Block[t * 4 + 1] << 16); + W[t] |= (uint32_t)(context->Message_Block[t * 4 + 2] << 8); + W[t] |= (uint32_t)(context->Message_Block[t * 4 + 3]); + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[57] = (uint8_t)(context->Length_High >> 16); + context->Message_Block[58] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[59] = (uint8_t)(context->Length_High); + context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t)(context->Length_Low); + + SHA1ProcessMessageBlock(context); +} diff --git a/xrGameSpy/gamespy/common/gsSHA1.h b/xrGameSpy/gamespy/common/gsSHA1.h new file mode 100644 index 00000000000..03471bc6a8d --- /dev/null +++ b/xrGameSpy/gamespy/common/gsSHA1.h @@ -0,0 +1,93 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +//#include +#include "gsCommon.h" +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typdef the following: + * name meaning + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ +#ifndef _PS3 + // these common types are defined in sony libs + typedef gsi_u32 uint32_t; + typedef gsi_u8 uint8_t; +#endif + +typedef gsi_i16 int_least16_t; + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const uint8_t *, + unsigned int); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + + +#if defined(__cplusplus) +} +#endif // extern "C" + + +#endif diff --git a/xrGameSpy/gamespy/common/gsSSL.c b/xrGameSpy/gamespy/common/gsSSL.c new file mode 100644 index 00000000000..36098b2ca8e --- /dev/null +++ b/xrGameSpy/gamespy/common/gsSSL.c @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsSSL.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Don't define the export cipher suites if you can avoid it, they present a security risk +const struct gsSSLCipherSuiteDesc gsSSLCipherSuites[GS_SSL_NUM_CIPHER_SUITES] = +{ + // Since common version of IIS supports these, + // we are safe to require the best + + // Algorithm ID (fixed const), KeyLen, CipherLen, IV Len + { TLS_RSA_WITH_RC4_128_MD5, 16, 16, 00 }, + //{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, 16, 20, 00 }, + + // Use of single DES is questionable + // { TLS_RSA_WITH_DES_CBC_SHA, 00, 00, 00 }, + + // Support for export ciphers poses a security risk + // A hacker can edit the packet stream to use a weak export cipher, + // then crack the session and modify the message MACs + // { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, 00, 00, 00 }, + // { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, 00, 00, 00 }, + // { TLS_RSA_EXPORT_WITH_RC4_40_MD5, 00, 00, 00 }, + // { TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, 00, 00, 00 }, + + // Plain diffie-helmann not supported + // { TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, 00, 00, 00 }, + // { TLS_DHE_DSS_WITH_DES_CBC_SHA, 00, 00, 00 }, + // { TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, 00, 00, 00 } +}; + + +const unsigned char gsSslRsaOid[9] = +{ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; diff --git a/xrGameSpy/gamespy/common/gsSSL.h b/xrGameSpy/gamespy/common/gsSSL.h new file mode 100644 index 00000000000..8bd2e3a0998 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsSSL.h @@ -0,0 +1,186 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSSSL_H__ +#define __GSSSL_H__ + +#include "../darray.h" +#include "../md5.h" +#include "gsCrypt.h" +#include "gsSHA1.h" +#include "gsRC4.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + + // SSL common types and defines. Used by HTTP SSL encryption engine + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// SSL v3.0 +#define GS_SSL_VERSION_MAJOR (0x03) +#define GS_SSL_VERSION_MINOR (0x00) + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + // SSL content types +#define GS_SSL_CONTENT_CHANGECIPHERSPEC (0x14) // 20 +#define GS_SSL_CONTENT_ALERT (0x15) // 21 Not sure if this is the correct value +#define GS_SSL_CONTENT_HANDSHAKE (0x16) // 22 +#define GS_SSL_CONTENT_APPLICATIONDATA (0x17) // 23 + + // SSL handshake message types +//#define GS_SSL_HANDSHAKE_HELLOREQUEST (0) +#define GS_SSL_HANDSHAKE_CLIENTHELLO (1) +#define GS_SSL_HANDSHAKE_SERVERHELLO (2) +#define GS_SSL_HANDSHAKE_CERTIFICATE (11) +//#define GS_SSL_HANDSHAKE_SERVERKEYEXCHANGE (12) +//#define GS_SSL_HANDSHAKE_CERTIFICATEREQUEST (13) +#define GS_SSL_HANDSHAKE_SERVERHELLODONE (14) +//#define GS_SSL_HANDSHAKE_CERTIFICATEVERIFY (15) +#define GS_SSL_HANDSHAKE_CLIENTKEYEXCHANGE (16) +#define GS_SSL_HANDSHAKE_FINISHED (20) + +// the largest payload for a single SSL packet, RFC const +// ----> RFC includes MAC and any padding, actual user data must be less +#define GS_SSL_MAX_CONTENTLENGTH ((0x4000) - (0xFF)) + +#ifndef HAVE_CIPHER_SUITES + /* these are the ones used by IE */ + #define TLS_RSA_WITH_RC4_128_MD5 0x04 + #define TLS_RSA_WITH_RCA_128_SHA 0x05 + #define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x0a + #define TLS_RSA_WITH_DES_CBC_SHA 0x09 + #define TLS_RSA_EXPORT1024_WITH_RC4_56_SHA 0x64 + #define TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x62 + #define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x03 + #define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x06 + #define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x13 + #define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x12 + #define TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x63 +#endif + + // These depend on the SSL cipher suite ranges +#define GS_SSL_MAX_MAC_SECRET_SIZE (20) +#define GS_SSL_MAX_SYMMETRIC_KEY_SIZE (16) +#define GS_SSL_MAX_IV_SIZE (16) +#define GS_SSL_NUM_CIPHER_SUITES (1) // cipher suite list defined in gsSSL.c +#define GS_SSL_MASTERSECRET_LEN (48) +#define GS_SSL_PAD_ONE "666666666666666666666666666666666666666666666666" // 48 bytes +#define GS_SSL_PAD_TWO "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" // 48 bytes +#define GS_SSL_MD5_PAD_LEN (48) +#define GS_SSL_SHA1_PAD_LEN (40) // use only 40 of the 48 bytes +#define GS_SSL_CLIENT_FINISH_VALUE "CLNT" +#define GS_SSL_SERVER_FINISH_VALUE "SRVR" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// SSL instance/session info +typedef struct gsSSL +{ + int sessionLen; + unsigned char sessionData[255]; // up to 256 bytes + unsigned short cipherSuite; + + //DArray certificateArray; + gsCryptRSAKey serverpub; + unsigned char sendSeqNBO[8]; // incrementing sequence number (for messages sent) + unsigned char receiveSeqNBO[8]; // ditto (for messages received) + + // Key buffers + // Actual data may be smaller than array size + unsigned char clientWriteMACSecret[GS_CRYPT_SHA1_HASHSIZE]; + unsigned char clientReadMACSecret [GS_CRYPT_SHA1_HASHSIZE]; + unsigned char clientWriteKey [GS_SSL_MAX_SYMMETRIC_KEY_SIZE]; + unsigned char clientReadKey [GS_SSL_MAX_SYMMETRIC_KEY_SIZE]; + unsigned char clientWriteIV [GS_SSL_MAX_IV_SIZE]; + unsigned char clientReadIV [GS_SSL_MAX_IV_SIZE]; + + // Actual lengths of the above data blocks + int clientWriteMACLen; + int clientReadMACLen; + int clientWriteKeyLen; + int clientReadKeyLen; + int clientWriteIVLen; + int clientReadIVLen; + + RC4Context sendRC4; // initialized ONCE per key exchange + RC4Context recvRC4; // initialized ONCE per key exchange + + // these are unused once the handshake is complete + // todo: dynamically allocate or remove to free space + MD5_CTX finishHashMD5; + SHA1Context finishHashSHA1; + unsigned char serverRandom[32]; // server random for key generation, sent plain text + unsigned char clientRandom[32]; // client random for key generation, sent plain text + unsigned char premastersecret[GS_SSL_MASTERSECRET_LEN]; // client random for key generation, sent encrypted with serverpub + unsigned char mastersecret[GS_SSL_MASTERSECRET_LEN]; + +} gsSSL; + + +// SSL messages (like the ClientHello) are wrapped in a "record" struct +typedef struct gsSSLRecordHeaderMsg +{ + unsigned char contentType; // = GS_SSL_CONTENT_HANDSHAKE; + unsigned char versionMajor; // = GS_SSL_VERSION_MAJOR; + unsigned char versionMinor; // = GS_SSL_VERSION_MINOR; + unsigned char lengthNBO[2]; // length of msg, limited to 2^14 + + // WARNING: lengthNBO can NOT be an unsigned short + // This would create alignment issues from the previous 3 parameters + +} gsSSLRecordHeaderMsg; + +typedef struct gsSSLClientHelloMsg +{ + gsSSLRecordHeaderMsg header; // include the header for easier packing + unsigned char handshakeType; // 0x01 + unsigned char lengthNBO[3]; // 3 byte length, NBO integer! 61 = 0x00 00 3d + unsigned char versionMajor; // = GS_SSL_VERSION_MAJOR; + unsigned char versionMinor; // = GS_SSL_VERSION_MINOR; + unsigned char time[4]; // 4 byte random (spec says set to current unix-time) + unsigned char random[28]; // 28 byte random, total of 32 random bytes + unsigned char sessionIdLen; // how many of the bytes that follow are session info? (def:0) + + // ALIGNMENT: 44 bytes prior to this, alignment should be OK + unsigned short cipherSuitesLength; // 2* number of cipher suites + unsigned short cipherSuites[GS_SSL_NUM_CIPHER_SUITES]; + unsigned char compressionMethodLen; // no standard methods, set to 1 + unsigned char compressionMethodList; // set to 0 +} gsSSLClientHelloMsg; + +typedef struct gsSSLClientKeyExchangeMsg +{ + gsSSLRecordHeaderMsg header; // included here for easier packing + unsigned char handshakeType; // 0x10 + unsigned char lengthNBO[3]; + // The next lengthNBO bytes are the client contribution to the key +} gsSSLClientKeyExchangeMsg; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Information about each cipher suite +typedef struct gsSSLCipherSuiteDesc +{ + int mSuiteID; + int mKeyLen; + int mMACLen; + int mIVLen; +} gsSSLCipherSuiteDesc; + +extern const gsSSLCipherSuiteDesc gsSSLCipherSuites[GS_SSL_NUM_CIPHER_SUITES]; +extern const unsigned char gsSslRsaOid[9]; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // __GSSSL_H__ diff --git a/xrGameSpy/gamespy/common/gsSoap.c b/xrGameSpy/gamespy/common/gsSoap.c new file mode 100644 index 00000000000..d28f97b1557 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsSoap.c @@ -0,0 +1,280 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// gSOAP Glue +#include "gsCore.h" +#include "gsSoap.h" +#include "gsPlatformThread.h" +#include "gsXML.h" +#include "../ghttp/ghttpASCII.h" + + +// GAMESPY DEVELOPERS -> Use gsiExecuteSoap + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Soap task delegates +static void gsiSoapTaskExecute(void* theTask); +static void gsiSoapTaskCallback(void* theTask, GSTaskResult theResult); +static void gsiSoapTaskCancel(void* theTask); +static gsi_bool gsiSoapTaskCleanup(void* theTask); +static GSTaskResult gsiSoapTaskThink(void* theTask); + +// Http triggered callbacks (don't take action now, wait for task callbacks) +static GHTTPBool gsiSoapTaskHttpCompletedCallback(GHTTPRequest request, GHTTPResult result, + char * buffer, GHTTPByteCount bufferLen, + void * param); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Execute a soap function (this should be the only call made from other SDKs) +GSSoapTask* gsiExecuteSoap(const char* theURL, const char* theService, + GSXmlStreamWriter theRequestSoap, GSSoapCallbackFunc theCallbackFunc, + void* theUserData) +{ + GSSoapTask* aSoapTask = NULL; + GSTask* aCoreTask = NULL; + + aSoapTask = (GSSoapTask*)gsimalloc(sizeof(GSSoapTask)); + if (aSoapTask == NULL) + return NULL; // out of memory + + aSoapTask->mCallbackFunc = theCallbackFunc; + aSoapTask->mCustomFunc = NULL; + aSoapTask->mURL = theURL; + aSoapTask->mService = theService; + aSoapTask->mRequestSoap = theRequestSoap; + aSoapTask->mPostData = NULL; + aSoapTask->mResponseSoap = NULL; + aSoapTask->mResponseBuffer = NULL; + aSoapTask->mUserData = theUserData; + aSoapTask->mRequestResult= (GHTTPResult)0; + aSoapTask->mCompleted = gsi_false; + + aCoreTask = gsiCoreCreateTask(); + if (aCoreTask == NULL) + { + gsifree(aSoapTask); + return NULL; // out of memory + } + + aCoreTask->mCallbackFunc = gsiSoapTaskCallback; + aCoreTask->mExecuteFunc = gsiSoapTaskExecute; + aCoreTask->mThinkFunc = gsiSoapTaskThink; + aCoreTask->mCleanupFunc = gsiSoapTaskCleanup; + aCoreTask->mCancelFunc = gsiSoapTaskCancel; + aCoreTask->mTaskData = (void*)aSoapTask; + + aSoapTask->mCoreTask = aCoreTask; + + gsiCoreExecuteTask(aCoreTask, 0); + + return aSoapTask; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Execute a soap function with a GSSoapCustomFunc that can access the soap +// structure prior to execution. This allows the client to set DIME +// attachments. (The GSSoapCustomFunc parameter could be added to +// gsiExecuteSoap itself as long as existing client code is updated) +GSSoapTask* gsiExecuteSoapCustom(const char* theURL, const char* theService, + GSXmlStreamWriter theRequestSoap, GSSoapCallbackFunc theCallbackFunc, + GSSoapCustomFunc theCustomFunc, void* theUserData) +{ + GSSoapTask* aSoapTask = NULL; + GSTask* aCoreTask = NULL; + + aSoapTask = (GSSoapTask*)gsimalloc(sizeof(GSSoapTask)); + aSoapTask->mCallbackFunc = theCallbackFunc; + aSoapTask->mCustomFunc = theCustomFunc; + aSoapTask->mURL = theURL; + aSoapTask->mService = theService; + aSoapTask->mRequestSoap = theRequestSoap; + aSoapTask->mPostData = NULL; + aSoapTask->mResponseSoap = NULL; + aSoapTask->mResponseBuffer = NULL; + aSoapTask->mUserData = theUserData; + aSoapTask->mRequestResult= (GHTTPResult)0; + aSoapTask->mCompleted = gsi_false; + + aCoreTask = gsiCoreCreateTask(); + aCoreTask->mCallbackFunc = gsiSoapTaskCallback; + aCoreTask->mExecuteFunc = gsiSoapTaskExecute; + aCoreTask->mThinkFunc = gsiSoapTaskThink; + aCoreTask->mCleanupFunc = gsiSoapTaskCleanup; + aCoreTask->mCancelFunc = gsiSoapTaskCancel; + aCoreTask->mTaskData = (void*)aSoapTask; + + aSoapTask->mCoreTask = aCoreTask; + + gsiCoreExecuteTask(aCoreTask, 0); + + return aSoapTask; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Cancels a soap task. +// - Because of network race conditions, the task may complete before it +// can be cancelled. If this happens, the task callback will be triggered +// with status GHTTPRequestCancelled and the result data will be discarded. +void gsiCancelSoap(GSSoapTask * theTask) +{ + GS_ASSERT(theTask != NULL); + + // Still in progress? cancel it! + if (gsi_is_false(theTask->mCompleted)) + gsiCoreCancelTask(theTask->mCoreTask); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + ////////// HTTP CALLBACKS ////////// + +static GHTTPBool gsiSoapTaskHttpCompletedCallback(GHTTPRequest request, GHTTPResult result, + char * buffer, GHTTPByteCount bufferLen, + void * param) +{ + gsi_bool parseResult = gsi_false; + + GSSoapTask* aSoapTask = (GSSoapTask*)param; + aSoapTask->mRequestResult = result; + aSoapTask->mCompleted = gsi_true; + aSoapTask->mResponseBuffer = buffer; + + if (result == GHTTPSuccess) + { + aSoapTask->mResponseSoap = gsXmlCreateStreamReader(); + if (aSoapTask->mResponseSoap == NULL) + { + // OOM! + aSoapTask->mRequestResult = GHTTPOutOfMemory; + } + else + { + parseResult = gsXmlParseBuffer(aSoapTask->mResponseSoap, buffer, (int)bufferLen); + if (gsi_is_false(parseResult)) + { + // Todo: handle multiple error conditions + aSoapTask->mRequestResult = GHTTPBadResponse; + } + } + } + + GSI_UNUSED(request); + + return GHTTPFalse; // don't let http free the buffer +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + ////////// SOAP EXECUTE TASK ////////// + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Checks to see if the soap task has completed +// - return GSTaskResult_InProgress for "keep checking" +// - return anything else for "finished - trigger callback and delete" +static GSTaskResult gsiSoapTaskThink(void* theTask) +{ + // is the request still processing? + GSSoapTask* aSoapTask = (GSSoapTask*)theTask; + if (gsi_is_true(aSoapTask->mCompleted)) + return GSTaskResult_Finished; + else + { + ghttpRequestThink(aSoapTask->mRequestId); + return GSTaskResult_InProgress; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Spawns the soap thread and begins execution +static void gsiSoapTaskExecute(void* theTask) +{ + GSSoapTask* aSoapTask = (GSSoapTask*)theTask; + //int threadID = 0; + + // make sure we aren't reusing a task without first resetting it + GS_ASSERT(gsi_is_false(aSoapTask->mCompleted)); + + aSoapTask->mPostData = ghttpNewPost(); + if (aSoapTask->mPostData == NULL) + { + // OOM: abort task + aSoapTask->mCompleted = gsi_true; + aSoapTask->mRequestResult = GHTTPOutOfMemory; + return; + } + + ghttpPostSetAutoFree(aSoapTask->mPostData, GHTTPFalse); + ghttpPostAddXml(aSoapTask->mPostData, aSoapTask->mRequestSoap); + + // Allow client to further configure soap object if desired + if (aSoapTask->mCustomFunc != NULL) + (aSoapTask->mCustomFunc)(aSoapTask->mPostData, aSoapTask->mUserData); + + + aSoapTask->mRequestId = ghttpGetExA(aSoapTask->mURL, aSoapTask->mService, + NULL, 0, aSoapTask->mPostData, GHTTPFalse, GHTTPFalse, NULL, + gsiSoapTaskHttpCompletedCallback, (void*)aSoapTask); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Called when the soap task needs to be cancelled +static void gsiSoapTaskCancel(void* theTask) +{ + GSSoapTask * soapTask = (GSSoapTask*)theTask; + if (gsi_is_false(soapTask->mCompleted)) + { + if (soapTask->mRequestId >= 0) + ghttpCancelRequest(soapTask->mRequestId); + soapTask->mRequestResult = GHTTPRequestCancelled; + soapTask->mCompleted = gsi_true; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Called when the soap task completes or is cancelled/timed out +static void gsiSoapTaskCallback(void* theTask, GSTaskResult theResult) +{ + // Call the developer callback + GSSoapTask* aSoapTask = (GSSoapTask*)theTask; + + (aSoapTask->mCallbackFunc)(aSoapTask->mRequestResult, aSoapTask->mRequestSoap, + aSoapTask->mResponseSoap, aSoapTask->mUserData); + + GSI_UNUSED(theResult); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// After the soap call has completed, launch a separate cleanup event (see comments) +static gsi_bool gsiSoapTaskCleanup(void *theTask) +{ + GSSoapTask* aSoapTask = (GSSoapTask*)theTask; + + if (aSoapTask->mResponseSoap != NULL) + gsXmlFreeReader(aSoapTask->mResponseSoap); + if (aSoapTask->mResponseBuffer != NULL) + gsifree(aSoapTask->mResponseBuffer); + if (aSoapTask->mPostData != NULL) + ghttpFreePost(aSoapTask->mPostData); // this also frees the request soap xml + gsifree(aSoapTask); + + return gsi_true; +} diff --git a/xrGameSpy/gamespy/common/gsSoap.h b/xrGameSpy/gamespy/common/gsSoap.h new file mode 100644 index 00000000000..b7e9bde4a29 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsSoap.h @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SOAP_H__ +#define __SOAP_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCommon.h" +#include "gsCore.h" + +#include "../ghttp/ghttp.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef void(*GSSoapCallbackFunc)(GHTTPResult theHTTPResult, GSXmlStreamWriter theRequest, GSXmlStreamReader theResponse, void *theUserData); +typedef void(*GSSoapCustomFunc)(GHTTPPost theSoap, void* theUserData); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct +{ + GSSoapCallbackFunc mCallbackFunc; + GSSoapCustomFunc mCustomFunc; + const char *mURL; + const char *mService; + + GSXmlStreamWriter mRequestSoap; + GSXmlStreamReader mResponseSoap; + + char * mResponseBuffer; // so we can free it later + GHTTPPost mPostData; // so we can free it later + + void * mUserData; + GSTask * mCoreTask; + + GHTTPRequest mRequestId; + GHTTPResult mRequestResult; + gsi_bool mCompleted; +} GSSoapTask; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Execute a soap call (Uses GameSpy core object) +GSSoapTask* gsiExecuteSoap(const char *theURL, const char *theService, + GSXmlStreamWriter theSoapData, GSSoapCallbackFunc theCallbackFunc, + void *theUserData); + +// Alternate version with GSSoapCustomFunc parameter allows client access +// to soap object to set DIME attachments +GSSoapTask* gsiExecuteSoapCustom(const char* theURL, const char* theService, + GSXmlStreamWriter theSoapData, GSSoapCallbackFunc theCallbackFunc, + GSSoapCustomFunc theCustomFunc, void* theUserData); + + +void gsiCancelSoap(GSSoapTask * theTask); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // __SOAP_H__ diff --git a/xrGameSpy/gamespy/common/gsStringUtil.c b/xrGameSpy/gamespy/common/gsStringUtil.c new file mode 100644 index 00000000000..166cb6f1c19 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsStringUtil.c @@ -0,0 +1,683 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Conversion Utility for ASCII, UTF8 and USC2 (Unicode) character sets +// +// See RFC2279 for reference +// +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsCommon.h" +#include "gsStringUtil.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Reads UCS2 character from UTF8String +// +// [in] theUTF8String : UTF8String, doesn't need to be null terminated +// [out] theUCS2Char : The 2 byte UCS2 equivalent +// [in] theMaxLength : Maximum number of *bytes* to read (not UTF8 characters) +// +// return value : The number of bytes read from theUTF8String +// 0 = error when parsing +// +// Remarks: +// If theUTF8String is invalid, theUnicodeChar will be set to '?' +// Function is designed for convenient parsing of UTF8 data streams +// +// Security Concern: +// Because data is routed through an ASCII stream prior to this function being +// called, embedded NULLs are stripped and hence, this function does not check for them +// For example, the UTF-8 byte :1000 0000, would convert to a UCS2 NULL character +// If this appeared in the middle of a stream, it could cause undesired operation +int _ReadUCS2CharFromUTF8String(const UTF8String theUTF8String, UCS2Char* theUnicodeChar, int theMaxLength) +{ +#ifndef _PS2 + assert(theUnicodeChar != NULL); +#endif + + if (theMaxLength == 0) + { + // assert? + *theUnicodeChar = (UCS2Char)REPLACE_INVALID_CHAR; + return 0; // not enough data + } + + // Check for normal ascii range (includes NULL terminator) + if (UTF8_IS_SINGLE_BYTE(theUTF8String[0])) + { + // ASCII, just copy the value + *theUnicodeChar = (UCS2Char)theUTF8String[0]; + return 1; + } + + // Check for 2 byte UTF8 + else if (UTF8_IS_TWO_BYTE(theUTF8String[0])) + { + if (theMaxLength < 2) + { + *theUnicodeChar = (UCS2Char)REPLACE_INVALID_CHAR; + return 0; // not enough data + } + + // Make sure the second byte is valid + if (UTF8_IS_FOLLOW_BYTE(theUTF8String[1])) + { + // Construct 11 bit unicode character + // 5 value bits from first UTF8Byte (:000ABCDE) + // plus 6 value bits from the second UTF8Byte (:00FGHIJK) + // Store as (:0000 0ABC DEFG HIJK) + *theUnicodeChar = (unsigned short)(((theUTF8String[0] & UTF8_TWO_BYTE_MASK) << 6) + + ((theUTF8String[1] & UTF8_FOLLOW_BYTE_MASK))); + return 2; + } + } + + // Check for 3 byte UTF8 + else if (UTF8_IS_THREE_BYTE(theUTF8String[0])) + { + if (theMaxLength < 3) + { + *theUnicodeChar = (UCS2Char)REPLACE_INVALID_CHAR; + return 0; // not enough data + } + + // Make sure the second and third bytes are valid + if (UTF8_IS_FOLLOW_BYTE(theUTF8String[1]) && + UTF8_IS_FOLLOW_BYTE(theUTF8String[2])) + { + // Construct 16 bit unicode character + // 4 value bits from first UTF8Byte (:0000ABCD) + // plus 6 value bits from the second UTF8Byte (:00EFGHIJ) + // plus 6 value bits from the third UTF8Byte (:00KLMNOP) + // Store as (:ABCD EFGH IJKL MNOP) + *theUnicodeChar = (unsigned short)(((theUTF8String[0] & UTF8_THREE_BYTE_MASK) << 12) + + ((theUTF8String[1] & UTF8_FOLLOW_BYTE_MASK) << 6) + + ((theUTF8String[2] & UTF8_FOLLOW_BYTE_MASK))); + return 3; + } + } + + // Invalid character, replace with '?' and return false + *theUnicodeChar = (UCS2Char)REPLACE_INVALID_CHAR; + + // The second byte on could have been the start of a new valid UTF8 character + // so we can only safely discard one invalid character + return 1; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Converts UCS2 (Unicode) character into UTF8String +// +// [in] theUCS2Char : The 2 byte character to convert +// [out] theUTF8String : The 1-3 byte UTF8 equivalent +// +// return value : The length of theUTF8String in bytes +// +// Remarks: +// theUTF8String may be up to 3 bytes, caller is responsible for allocating memory +// theUTF8String is NOT NULL terminated, +int _UCS2CharToUTF8String(UCS2Char theUCS2Char, UTF8String theUTF8String) +{ +#ifndef _PS2 + assert(theUTF8String != NULL); +#endif + + // Screen out simple ascii (includes NULL terminator) + if (theUCS2Char <= 0x7F) + { + // 0-7 bit unicode, copy stright over + theUTF8String[0] = (char)(UTF8ByteType)theUCS2Char; + return 1; + } + else if (theUCS2Char <= 0x07FF) + { + // 8-11 bits unicode, store as two byte UTF8 + // :00000ABC DEFGHIJK + // :110ABCDE 10FGHIJK + theUTF8String[0] = (char)(UTF8ByteType)(UTF8_TWO_BYTE_TAG | (theUCS2Char >> 6)); // Store the upper 5/11 bits as 0x110xxxxx + theUTF8String[1] = (char)(UTF8ByteType)(UTF8_FOLLOW_BYTE_TAG | (theUCS2Char & UTF8_FOLLOW_BYTE_MASK)); // Store the lower 6 bits as 0x10xxxxxx + return 2; + } + else + { + // 12-16 bits unicode, store as three byte UTF8 + // :ABCDEFGH IJKLMNOP + // :1110ABCD 10EFGHIJ 10KLMNOP + theUTF8String[0] = (char)(UTF8ByteType)(UTF8_THREE_BYTE_TAG | (theUCS2Char >> 12)); // Store the upper 4/16 bits as 0x1110xxxx + theUTF8String[1] = (char)(UTF8ByteType)(UTF8_FOLLOW_BYTE_TAG | ((theUCS2Char >> 6) & UTF8_FOLLOW_BYTE_MASK)); // Store the 5th-10th bits as 0x10xxxxxx + theUTF8String[2] = (char)(UTF8ByteType)(UTF8_FOLLOW_BYTE_TAG | ((theUCS2Char) & UTF8_FOLLOW_BYTE_MASK)); // Store the last 6 bits as 0x10xxxxxx + return 3; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert an ASCII string to UTF8 +// +// Since an ASCII string IS a valid UTF8 string, just copy and return +// +// [in] theAsciiString, NULL terminated c-string +// [out] theUTF8String, NULL terminated UTF8String +// +// returns the length of theUTF8String +int AsciiToUTF8String(const char* theAsciiString, UTF8String theUTF8String) +{ + // Allow for NULL here since SDKs allow for NULL string arrays + if (theAsciiString == NULL) + { + *theUTF8String = 0x00; + return 1; + } + else + { + // Copy the string, keeping track of length + unsigned int aLength = 0; + while (*theAsciiString != '\0') + { + *(theUTF8String++) = *(theAsciiString++); + aLength++; + } + + // Append the null + *theUTF8String = '\0'; + aLength++; + + return (int)aLength; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UTF8String to it's ASCII equivalent +// +// [in] theUTF8String, NULL terminated UTF8String +// [out] theAsciiString, NULL terminated c-string +// +// returns the length of theAsciiString +// +// Remarks: +// Unvalid ASCII characters are replaced with '?' +// Memory allocated for theAsciiString may need to be as large as the UTF8String +// UTF8String will be NULL terminated +int UTF8ToAsciiString(const UTF8String theUTF8String, char* theAsciiString) +{ + // Strip non-ascii characters and replace with REPLACE_INVALID_CHAR + const unsigned char* anInStream = (const unsigned char*)theUTF8String; + unsigned int aNumBytesWritten = 0; + + // Allow for NULL here since SDKs allow for NULL string arrays + if (theUTF8String == NULL) + { + *theAsciiString = 0x00; + return 1; + } + + // Keep extracting characters until we get a '\0' + while (*anInStream != '\0') + { + if (UTF8_IS_SINGLE_BYTE(*anInStream)) + theAsciiString[aNumBytesWritten++] = (char)*anInStream; + else + theAsciiString[aNumBytesWritten++] = REPLACE_INVALID_CHAR; + + // move to next character + anInStream++; + } + + // Append the '\0' + theAsciiString[aNumBytesWritten++] = '\0'; + return (int)aNumBytesWritten; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UCS2 (Unicode) string to it's UTF8 equivalent +// +// [in] theUCS2String, double NULL terminated UTF8String +// [out] theUTF8String, NULL terminated c-string +// +// returns the length of theUTF8String +// +// Remarks: +// Memory allocated for theUTF8String may need to be up to 1.5* the size of theUCS2String +// This means that for each UCS2 character, 3 UTF8 characters may be generated +int UCS2ToUTF8String(const UCS2String theUCS2String, UTF8String theUTF8String) +{ + unsigned int aTotalBytesWritten = 0; + unsigned int aUTF8CharLength = 0; + const UCS2Char* anInStream = theUCS2String; + unsigned char* anOutStream = (unsigned char*)theUTF8String; + + // Allow for NULL here since SDKs allow for NULL string parameters + if (theUCS2String == NULL) + { + *anOutStream = 0x00; + return 1; + } + + // Loop until we reach a NULL terminator + while(*anInStream != 0) + { + aUTF8CharLength = (unsigned int)_UCS2CharToUTF8String(*anInStream, (UTF8String)anOutStream); + + // Move out stream to next character position + anOutStream += aUTF8CharLength; + + // Move to next UCS2 character + anInStream++; + + // Record number of bytes written + aTotalBytesWritten += aUTF8CharLength; + } + + // Copy over the null terminator + *anOutStream = '\0'; + aTotalBytesWritten++; + + return (int)aTotalBytesWritten; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UTF8 string to it's UCS2 (Unicode) equivalent +// +// [in] theUTF8String, NULL terminated UTF8String +// [out] theUCS2String, NULL terminated c-string +// +// returns the length of theUCS2String +// +// Remarks: +// Unvalid UTF8 characters are replaced with '?' +// Memory allocated for theAsciiString may need to be as large as the UTF8String +// UTF8String will be NULL terminated +int UTF8ToUCS2String(const UTF8String theUTF8String, UCS2String theUCS2String) +{ + return UTF8ToUCS2StringLen(theUTF8String, theUCS2String, (gsi_i32)strlen(theUTF8String)); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Calculate the size needed to convert a UTF8String to a UCS2String +// +// [in] theUTF8String, NULL terminated UTF8String +// +// returns the length (in UCS2 characters) of theUCS2String that would be created +// +// Remarks: +// Unvalid UTF8 characters are treated as 1 byte +int _UTF8ToUCS2ConversionLengthOnly(const UTF8String theUTF8String) +{ + int length = 0; + const UTF8String theReadPos = theUTF8String; + + assert(theUTF8String != NULL); + if (theUTF8String == NULL) + return 0; + + while (*theReadPos != '\0') + { + // Check for valid two byte string + if (UTF8_IS_TWO_BYTE(theReadPos[0]) && UTF8_IS_FOLLOW_BYTE(theReadPos[1])) + theReadPos += 2; + + // Check for valid three byte string + else if (UTF8_IS_THREE_BYTE(theReadPos[0]) && + UTF8_IS_FOLLOW_BYTE(theReadPos[1]) && + UTF8_IS_FOLLOW_BYTE(theReadPos[2])) + { + theReadPos += 3; + } + // Anything else means one UTF8 character read from the buffer + else + theReadPos++; + + // Increment the length of the UCS2 string + length++; + } + + // don't count the null as a character, this conforms + // with ANSI strlen functions + return length; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Calculate the size needed to convert a UCS2String to a UTF8String +// +// [in] theUCS2String, NULL terminated UCS2String +// +// returns the length of theUTF8String that would be created +// +// Remarks: +// Unvalid UTF8 characters are treated as 1 byte +int _UCS2ToUTF8ConversionLengthOnly(const UCS2String theUCS2String) +{ + int length = 0; + const UCS2String theReadPos = theUCS2String; + assert(theUCS2String != NULL); + while (*theReadPos != 0x0000) + { + // Values <= 0x7F are single byte ascii + if (*theReadPos <= 0x7F) + length++; + // Values > 0x7F and <= 0x07FF are two bytes in UTF8 + else if (*theReadPos <= 0x07FF) + length += 2; + // Anything else is 3 bytes of UTF8 + else + length += 3; + + // Set read pos to right spot (1 more UCS2 Character = 2 bytes) + theReadPos++; + } + + // don't count the null as a character, this conforms + // with ANSI strlen functions + return length; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UTF8String to a UCS2String, allocate space for the UCS2String +// +// [in] theUTF8String, NULL terminated UTF8String +// +// returns the newly allocated UCS2String +// +// Remarks: +// The callee is responsible for freeing the allocated memory block +UCS2String UTF8ToUCS2StringAlloc(const UTF8String theUTF8String) +{ + // Allow for NULL here since SDKs allow for NULL string parameters + if (theUTF8String == NULL) + return NULL; + else + { + // Find the length of the UCS2 string and allocate a block + int newLength = _UTF8ToUCS2ConversionLengthOnly(theUTF8String); + UCS2String aUCS2String = (UCS2String)gsimalloc(sizeof(UCS2Char)*(newLength + 1)); + + // Do the conversion + UTF8ToUCS2String(theUTF8String, aUCS2String); + + // Return the allocated string + return aUCS2String; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UCS2String to a UTF8String, allocate space for the UTF8String +// +// [in] UCS2String, NULL terminated UCS2String +// +// returns the newly allocated UTF8String +// +// Remarks: +// The callee is responsible for freeing the allocated memory block +UTF8String UCS2ToUTF8StringAlloc(const UCS2String theUCS2String) +{ + // Allow for NULL here since SDKs allow for NULL string parameters + if (theUCS2String == NULL) + return NULL; + else + { + // Find the length of the UCS2 string and allocate a block + int newLength = _UCS2ToUTF8ConversionLengthOnly(theUCS2String); + UTF8String aUTF8String = (UTF8String)gsimalloc(sizeof(char)*(newLength + 1)); + + // Do the conversion + UCS2ToUTF8String(theUCS2String, aUTF8String); + + // Return the allocated string + return aUTF8String; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UTF8StringArray to a UCS2StringArray, allocate space for the UCS2Strings +// +// [in] UTF8StringArray, array of NULL terminated UTF8Strings +// [in] theNumStrings, how many strings are in the array +// +// returns the newly allocated UCS2StringArray +// +// Remarks: +// The callee is responsible for freeing the allocated memory block(s) +UCS2String* UTF8ToUCS2StringArrayAlloc(const UTF8String* theUTF8StringArray, int theNumStrings) +{ + // Allow for NULL here since SDKs allow for NULL string arrays + if(theUTF8StringArray == NULL || theNumStrings == 0) + return NULL; + else + { + UCS2String* aUCS2StringArray = (UCS2String*)gsimalloc(sizeof(UCS2String)*theNumStrings); + int stringNum = 0; + while(stringNum < theNumStrings) + { + aUCS2StringArray[stringNum] = UTF8ToUCS2StringAlloc(theUTF8StringArray[stringNum]); + stringNum++; + } + + return aUCS2StringArray; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UCS2StringArray to a UTF8StringArray, allocate space for the UTF8Strings +// +// [in] UCS2StringArray, array of NULL terminated UCS2Strings +// [in] theNumStrings, how many strings are in the array +// +// returns the newly allocated UTF8StringArray +// +// Remarks: +// The callee is responsible for freeing the allocated memory block +UTF8String* UCS2ToUTF8StringArrayAlloc(const UCS2String* theUCS2StringArray, int theNumStrings) +{ + // Allow for NULL here since SDKs allow for NULL string arrays + if (theUCS2StringArray == NULL || theNumStrings == 0) + return NULL; + else + { + UTF8String* aUTF8StringArray = (UTF8String*)gsimalloc(sizeof(UTF8String)*theNumStrings); + int stringNum = 0; + while(stringNum < theNumStrings) + { + aUTF8StringArray[stringNum] = UCS2ToUTF8StringAlloc(theUCS2StringArray[stringNum]); + stringNum++; + } + + return aUTF8StringArray; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UCS2String to an AsciiString +// +// [in] UCS2StringArray, NULL terminated UCS2String +// [in/out] theAsciiString, ascii representation +// +// returns the length of the Ascii string +// +// Remarks: +// callee is responsible for allocating memory for theAsciiString +// Invalid ASCII characters are truncated +// The ASCII buffer must be at least 1/2 the size of the UCS2String +int UCS2ToAsciiString(const UCS2String theUCS2String, char* theAsciiString) +{ + int length = 0; + const UCS2String aReadPos = theUCS2String; + char* aWritePos = theAsciiString; + + assert(theAsciiString != NULL); + + // Allow for NULL here since SDKs allow for NULL string arrays + if (theUCS2String == NULL) + { + *theAsciiString = '\0'; + return 1; + } + + // Convert each character until a '\0' is reached + while(*aReadPos != '\0') + { + (*aWritePos++) = (char)(0x00FF & (*aReadPos++)); + length++; + } + + // append the NULL + *aWritePos = '\0'; + length++; + + return length; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert an ASCII string to a UCS2String +// +// [in] theAsciiString, NULL terminated ASCII string +// [in/out] theUCS2String, UCS2String to be filled with the converted ASCII +// +// returns the length of the unicode string +// +// Remarks: +// The callee is responsible for allocating memory for theUCS2String +// the size returned should always be 2x the size passed in +int AsciiToUCS2String(const char* theAsciiString, UCS2String theUCS2String) +{ + int length = 0; + const char* aReadPos = theAsciiString; + UCS2String aWritePos = theUCS2String; + + assert(theUCS2String != NULL); + + // Allow for NULL here since SDKs allow for NULL string arrays + if (theAsciiString == NULL) + { + *theUCS2String = 0x0000; + return 1; + } + + // Convert each character until a '\0' is reached + while(*aReadPos != '\0') + { + (*aWritePos++) = (unsigned short)(0x00FF & (*aReadPos++)); // copy and strip extra byte + length++; + } + + // append a NULL terminator to the UCS2String + *aWritePos = '\0'; + length++; + + return length; +} + +/* +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UCS2String to a UTF8String with a maximum length +// +// [in] theUCS2String, NULL terminated UCS2String +// [in/out] theUTF8String, The UTF8 equivilent of theUCS2String +// [in] theMaxLength, maximum number of UTF8 characters to write +// +// returns the length of the UTF8String +// +// Remarks: +// The length of theUTF8String will not exceed theMaxLength supplied. +int UCS2ToUTF8StringLength(const UCS2String theUCS2String, UTF8String theUTF8String, int theMaxLength) +{ + return 0; +} +*/ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Convert a UTF8String to a UCS2String with a maximum length +// +// [in] theUTF8String, NULL terminated UTF8String +// [in/out] theUCS2String, The UCS2 equivilent of theUTF8String +// [in] theMaxLength, maximum number of UTF8 characters to write +// +// returns the length of the UCS2String +// +// Remarks: +// The length of theUCS2String will not exceed theMaxLength supplied. +int UTF8ToUCS2StringLen(const UTF8String theUTF8String, UCS2String theUCS2String, int theMaxLength) +{ + int aNumCharsWritten = 0; + int aNumBytesRead = 0; + int aTotalBytesRead = 0; + const unsigned char* anInStream = (const unsigned char*)theUTF8String; + UCS2Char* anOutStream= theUCS2String; + + // Allow for NULL here since SDKs allow for NULL string arrays + if (theUTF8String == NULL) + { + *anOutStream = 0x0000; + return 1; + } + + // Loop until we find the NULL terminator + while (*anInStream != '\0' && theMaxLength > aTotalBytesRead) + { + // Convert one character + aNumBytesRead = _ReadUCS2CharFromUTF8String((UTF8String)anInStream, anOutStream, theMaxLength-aTotalBytesRead); + if (aNumBytesRead == 0) + { + // Error, read past end of buffer + theUCS2String[0] = 0x0000; + return 0; + } + aTotalBytesRead += aNumBytesRead; + + // Move InStream position to new data + anInStream += aNumBytesRead; + + // Keep track of characters written + aNumCharsWritten++; + + // Move OutStream to next write position + anOutStream++; + } + + // NULL terminate the UCS2String + *anOutStream = 0x0000; + aNumCharsWritten++; + + return aNumCharsWritten; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} //extern "C" +#endif + + + diff --git a/xrGameSpy/gamespy/common/gsStringUtil.h b/xrGameSpy/gamespy/common/gsStringUtil.h new file mode 100644 index 00000000000..eb74f521834 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsStringUtil.h @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __STRINGUTIL_H__ +#define __STRINGUTIL_H__ + + +// String utilities used by the SDKs + +#ifdef __cplusplus +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef _PS2 +#define ALIGNED __attribute__ ((aligned(16))) +#else +#define ALIGNED +#endif + +#define UCS2Char unsigned short +#define UCS2String unsigned short* // null terminated +#define UTF8ByteType unsigned char // For type casting +#define UTF8String char* // may not be NULL terminated when treated as a single character + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define UTF8_FOLLOW_BYTE_TAG 0x80 //:1000 0000 // Identifies 2nd or 3rd byte of UTF8String +#define UTF8_TWO_BYTE_TAG 0xC0 //:1100 0000 // Identifies start of Two-byte UTF8String +#define UTF8_THREE_BYTE_TAG 0xE0 //:1110 0000 // Identifies start of Three-byte UTF8String +#define UTF8_FOUR_BYTE_TAG 0xF0 //:1111 0000 // Unsupported tag, need USC4 to store this + +#define UTF8_FOLLOW_BYTE_MASK 0x3F //:0011 1111 // The value bits in a follow byte +#define UTF8_TWO_BYTE_MASK 0x1F //:0001 1111 // The value bits in a two byte tag +#define UTF8_THREE_BYTE_MASK 0x0F //:0000 1111 // The value bits in a three byte tag + +#define UTF8_IS_THREE_BYTE(a) (((UTF8ByteType)a & UTF8_FOUR_BYTE_TAG)==UTF8_THREE_BYTE_TAG) +#define UTF8_IS_TWO_BYTE(a) (((UTF8ByteType)a & UTF8_THREE_BYTE_TAG)==UTF8_TWO_BYTE_TAG) +#define UTF8_IS_FOLLOW_BYTE(a) (((UTF8ByteType)a & UTF8_TWO_BYTE_TAG)==UTF8_FOLLOW_BYTE_TAG) +#define UTF8_IS_SINGLE_BYTE(a) ((UTF8ByteType)a <= 0x7F) // 0-127 + +#define REPLACE_INVALID_CHAR '?' // Replace invalid UTF8 chars with this + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Prototypes +// '_' denotes internal use functions +int _ReadUCS2CharFromUTF8String (const UTF8String theUTF8String, UCS2Char* theUnicodeChar, int theMaxLength); +int _UCS2CharToUTF8String (UCS2Char theUCS2Char, UTF8String theUTF8String); +int _UCS2ToUTF8ConversionLengthOnly (const UCS2String theUCS2String); +int _UTF8ToUCS2ConversionLengthOnly (const UTF8String theUTF8String); + +// Convert string types +int AsciiToUTF8String(const char* theAsciiString, UTF8String theUTF8String ); +int UTF8ToAsciiString(const UTF8String theUTF8String, char* theAsciiString); +int UCS2ToUTF8String (const UCS2String theUCS2String, UTF8String theUTF8String ); +int UTF8ToUCS2String (const UTF8String theUTF8String, UCS2String theUCS2String ); +int UCS2ToAsciiString(const UCS2String theUCS2String, char* theAsciiString); +int AsciiToUCS2String(const char* theAsciiString, UCS2String theUCS2String ); + +// Convert with maximum buffer length +// similar to strncpy +//int UCS2ToUTF8StringLength(const UCS2String theUCS2String, UTF8String theUTF8String, int theMaxLength); +int UTF8ToUCS2StringLen(const UTF8String theUTF8String, UCS2String theUCS2String, int theMaxLength); + +// Convert a string, allocate space for the new string +UTF8String UCS2ToUTF8StringAlloc(const UCS2String theUCS2String); +UCS2String UTF8ToUCS2StringAlloc(const UTF8String theUTF8String); + +// Convert an array of strings, allocate space for the new strings +UTF8String* UCS2ToUTF8StringArrayAlloc(const UCS2String* theUCS2StringArray, int theNumStrings); +UCS2String* UTF8ToUCS2StringArrayAlloc(const UTF8String* theUTF8StringArray, int theNumStrings); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __STRINGUTIL_H__ + diff --git a/xrGameSpy/gamespy/common/gsUdpEngine.c b/xrGameSpy/gamespy/common/gsUdpEngine.c new file mode 100644 index 00000000000..30c7771b21b --- /dev/null +++ b/xrGameSpy/gamespy/common/gsUdpEngine.c @@ -0,0 +1,1171 @@ +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Communication Engine +#include "gsUdpEngine.h" + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Internal Structures + +// Internal representation of a connection +// Also includes a ip and port for mapping to a connection +typedef struct +{ + unsigned int mAddr; + unsigned short mPort; + GT2Connection mConnection; +} GSUdpRemotePeer; + +// Message handler used filter traffic to a specific SDK or part of application +typedef struct +{ + unsigned char mInitialMsg[GS_UDP_MSG_HEADER_LEN]; + unsigned char mHeader[GS_UDP_MSG_HEADER_LEN]; + DArray mPendingConnections; + gsUdpConnClosedCallback mClosed; + gsUdpConnReceivedDataCallback mReceived; + gsUdpConnConnectedCallback mConnected; + gsUdpConnPingCallback mPingReply; + gsUdpErrorCallback mNetworkError; + void *mUserData; +} GSUdpMsgHandler; + +// The internal representation of UDP Communication Engine +typedef struct +{ + GT2Socket mSocket; + DArray mRemotePeers; + DArray mMsgHandlers; + gsi_bool mInitialized; + // Application callbacks for connection that gets + // un-handled messages + gsUdpConnConnectedCallback mAppConnected; + gsUdpConnClosedCallback mAppClosed; + gsUdpConnPingCallback mAppPingReply; + gsUdpConnReceivedDataCallback mAppRecvData; + gsUdpAppConnectAttemptCallback mAppConnAttempt; + // Error callback ? + gsUdpErrorCallback mAppNetworkError; + // Unknown Message + gsUdpUnknownMsgCallback mAppUnknownMessage; + void *mAppUserData; + + // This was any easier way to keep track of pending connections + // It does not rely on an address since it only keeps track of pending + // connections an app makes. + int mAppPendingConnections; + unsigned int mLocalAddr; + unsigned short mLocalPort; +}GSUdpEngineObject; + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Acts as the function to return the singleton +// This function is not exposed. It will only be +// used internally to do any modifications to the +// GSUdpEngineObject +GSUdpEngineObject * gsUdpEngineGetEngine() +{ + static GSUdpEngineObject aUdpObject; + return &aUdpObject; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Message Handler DArray functions +void gsUdpMsgHandlerFree(void *theMsgHandler) +{ + GSUdpMsgHandler *aHandler= (GSUdpMsgHandler *)theMsgHandler; + ArrayFree(aHandler->mPendingConnections); +} + +// Used to find a message handler based on the initial message. +int gsUdpMsgHandlerCompare(const void *theFirstHandler, const void *theSecondHandler) +{ + GSUdpMsgHandler *msgHandler1 = (GSUdpMsgHandler *)theFirstHandler, + *msgHandler2 = (GSUdpMsgHandler *)theSecondHandler; + int initCmp; + initCmp = memcmp(msgHandler1->mInitialMsg, msgHandler2->mInitialMsg, GS_UDP_MSG_HEADER_LEN); + return initCmp; + +} + +// Used to find a message handler based on the header. +int gsUdpMsgHandlerCompare2(const void *theFirstHandler, const void *theSecondHandler) +{ + GSUdpMsgHandler *msgHandler1 = (GSUdpMsgHandler *)theFirstHandler, + *msgHandler2 = (GSUdpMsgHandler *)theSecondHandler; + int headerCmp; + headerCmp = memcmp(msgHandler1->mHeader, msgHandler2->mHeader, GS_UDP_MSG_HEADER_LEN); + return headerCmp; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Remote Peer DArray compare functions + +// Finds a remote peer based on IP and Port +int gsUdpRemotePeerCompare(const void *theFirstPeer, const void *theSecondPeer) +{ + GSUdpRemotePeer *aPeer1 = (GSUdpRemotePeer *)theFirstPeer, + *aPeer2 = (GSUdpRemotePeer *)theSecondPeer; + if (aPeer1->mAddr != aPeer2->mAddr) + return 1; + if (aPeer1->mPort != aPeer2->mPort) + return 1; + + return 0; +} + +// Finds a remote peer based on a GT2Connection +int gsUdpRemotePeerCompare2(const void *theFirstPeer, const void *theSecondPeer) +{ + GSUdpRemotePeer *aPeer1 = (GSUdpRemotePeer *)theFirstPeer, + *aPeer2 = (GSUdpRemotePeer *)theSecondPeer; + if (aPeer1->mConnection != aPeer2->mConnection) + return 1; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Lets the Message Handler and App know about network errors +void gsUdpSocketError(GT2Socket theSocket) +{ + int i, len; + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Socket error, passing to app and message handlers\n"); + if (aUdp->mAppNetworkError) + aUdp->mAppNetworkError(GS_UDP_NETWORK_ERROR, aUdp->mAppUserData); + len = ArrayLength(aUdp->mMsgHandlers); + for (i = 0; i < len; i++) + { + GSUdpMsgHandler *aMsgHandler = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, i); + if (aMsgHandler->mNetworkError) + aMsgHandler->mNetworkError(GS_UDP_NETWORK_ERROR, aMsgHandler->mUserData); + } + GSI_UNUSED(theSocket); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Lets the App and Message Handlers know a peer left +void gsUdpClosedRoutingCB(GT2Connection theConnection, GT2CloseReason reason) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GSUdpRemotePeer aRemotePeer; + int index, len; + GSUdpCloseReason aReason; + char anAddr[GS_IP_ADDR_AND_PORT]; + + if (reason == GT2CommunicationError || reason == GT2SocketError) + aReason = GS_UDP_CLOSED_BY_COMM_ERROR; + else if (reason == GT2NotEnoughMemory) + aReason = GS_UDP_CLOSED_BY_LOW_MEM; + else + aReason = (GSUdpCloseReason)reason; + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connection closed to %s\n", gt2AddressToString(gt2GetRemoteIP(theConnection), + gt2GetRemotePort(theConnection), anAddr)); + len = ArrayLength(aUdp->mMsgHandlers); + for (index = 0; index < len; index++) + { + GSUdpMsgHandler *aHandler = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, index); + if (aHandler->mClosed) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connection closed: passed to message handler\n"); + aHandler->mClosed(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), aReason, aHandler->mUserData); + } + } + + if (aUdp->mAppClosed) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connection closed: passed to app\n"); + aUdp->mAppClosed(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), aReason, aUdp->mAppUserData); + } + + aRemotePeer.mConnection = theConnection; + index = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare2, 0, 0); + if (index != NOT_FOUND) + { + ArrayDeleteAt(aUdp->mRemotePeers, index); + } + GSI_UNUSED(anAddr); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// When a peer has accepted a GT2Connection the UDP layer needs to let +// higher level app or message handler know that it accepted the request to +// to message a peer. +void gsUdpConnectedRoutingCB(GT2Connection theConnection, GT2Result theResult, GT2Byte *theMessage, + int theMessageLen) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + int aIndex, len; + GSUdpErrorCode aCode; + char anAddr[GS_IP_ADDR_AND_PORT]; + + switch(theResult) + { + case GT2NegotiationError: + aCode = GS_UDP_REMOTE_ERROR; + break; + case GT2Rejected: + aCode = GS_UDP_REJECTED; + break; + case GT2TimedOut: + aCode = GS_UDP_TIMED_OUT; + break; + case GT2Success: + aCode = GS_UDP_NO_ERROR; + break; + default: + aCode = GS_UDP_UNKNOWN_ERROR; + break; + } + if (theResult == GT2Rejected) + { + int aRemotePeerIdx; + GSUdpRemotePeer aRemotePeer; + aRemotePeer.mAddr = gt2GetRemoteIP(theConnection); + aRemotePeer.mPort = gt2GetRemotePort(theConnection); + aRemotePeerIdx = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (aRemotePeerIdx != NOT_FOUND) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connect rejected by %s\n", gt2AddressToString(gt2GetRemoteIP(theConnection), + gt2GetRemotePort(theConnection), anAddr)); + + ArrayDeleteAt(aUdp->mRemotePeers, aRemotePeerIdx); + } + } + + len = ArrayLength(aUdp->mMsgHandlers); + for (aIndex = 0; aIndex < len; aIndex++) + { + int aRemotePeerIdx; + GSUdpRemotePeer aRemotePeer; + GSUdpMsgHandler *aTempHandler = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, aIndex); + + aRemotePeer.mAddr = gt2GetRemoteIP(theConnection); + aRemotePeer.mPort = gt2GetRemotePort(theConnection); + aRemotePeerIdx = ArraySearch(aTempHandler->mPendingConnections, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (aRemotePeerIdx != NOT_FOUND) + { + if (aTempHandler->mConnected) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Passing connect result to message handler\n"); + aTempHandler->mConnected(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), + aCode, theResult == GT2Rejected ? gsi_true : gsi_false, aTempHandler->mUserData); + } + ArrayDeleteAt(aTempHandler->mPendingConnections, aRemotePeerIdx); + return; + } + } + + if (aUdp->mAppPendingConnections > 0) + { + if (aUdp->mAppConnected) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Passing connect result to app\n"); + aUdp->mAppConnected(gt2GetRemoteIP(theConnection),gt2GetRemotePort(theConnection), + aCode, theResult == GT2Rejected ? gsi_true : gsi_false, aUdp->mAppUserData); + } + aUdp->mAppPendingConnections--; + } + GSI_UNUSED(theMessage); + GSI_UNUSED(theMessageLen); + GSI_UNUSED(anAddr); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Pings are passed on to higher level app or message handlers +void gsUdpPingRoutingCB(GT2Connection theConnection, int theLatency) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + int index, len; + char anAddr[GS_IP_ADDR_AND_PORT]; + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Received ping from %s\n", gt2AddressToString(gt2GetRemoteIP(theConnection), + gt2GetRemotePort(theConnection), anAddr)); + len = ArrayLength(aUdp->mMsgHandlers); + for (index = 0; index < len; index++) + { + GSUdpMsgHandler *aHandler = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, index); + if (aHandler->mPingReply) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Passed to message handler\n"); + aHandler->mPingReply(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), (unsigned int)theLatency, aHandler->mUserData); + return; + } + } + + if (aUdp->mAppPingReply) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Passed to app\n"); + aUdp->mAppPingReply(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), (unsigned int)theLatency, aUdp->mAppUserData); + } + GSI_UNUSED(anAddr); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Any data received prompts the UDP layer to first find a higher level +// message handler to handle the data. If there was no message handler +// found, the data is passed to the higher level app. +void gsUdpReceivedRoutingCB(GT2Connection theConnection, GT2Byte *theMessage, int theMessageLen, + GT2Bool reliable) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GSUdpMsgHandler aHandler; + int index; + char anAddr[GS_IP_ADDR_AND_PORT]; + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Received data from %s\n", gt2AddressToString(gt2GetRemoteIP(theConnection), + gt2GetRemotePort(theConnection), anAddr)); + //If there is a handler, pass it to the handler + //The header should not be stripped off + if (theMessageLen >= GS_UDP_MSG_HEADER_LEN) + { + memcpy(aHandler.mHeader, theMessage, GS_UDP_MSG_HEADER_LEN); + + index = ArraySearch(aUdp->mMsgHandlers, &aHandler, gsUdpMsgHandlerCompare2, 0, 0); + if (index != NOT_FOUND) + { + GSUdpMsgHandler *aHandlerFound = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, index); + if (aHandlerFound->mReceived) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Passed to message handler\n"); + aHandlerFound->mReceived(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), + theMessage + GS_UDP_MSG_HEADER_LEN, (unsigned int)(theMessageLen - GS_UDP_MSG_HEADER_LEN), reliable, aHandlerFound->mUserData); + return; + } + } + } + + if (aUdp->mAppRecvData) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Passed to app\n"); + aUdp->mAppRecvData(gt2GetRemoteIP(theConnection), gt2GetRemotePort(theConnection), theMessage, (unsigned int)theMessageLen, reliable, + aUdp->mAppUserData); + } + GSI_UNUSED(anAddr); +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Messages that are not recognized are passed only to the higher level app +// since message handlers always request to talk to peers +GT2Bool gsUdpUnrecognizedMsgCB(GT2Socket theSocket, unsigned int theIp, unsigned short thePort, GT2Byte * theMessage, + int theMsgLen) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + char anAddr[GS_IP_ADDR_AND_PORT]; + if (aUdp->mAppUnknownMessage) + { + gsi_bool aRet; + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Unknown message from %s, passing to app\n", gt2AddressToString(theIp, thePort, anAddr)); + aRet = aUdp->mAppUnknownMessage(theIp, thePort, (unsigned char *)theMessage, (unsigned int)theMsgLen, aUdp->mAppUserData); + return aRet ? GT2True : GT2False; + } + + GSI_UNUSED(theSocket); + GSI_UNUSED(anAddr); + return GT2False; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Requests for communication from a peer is handled by first checking if the +// initial message has a message handler registered for it. Otherwise +// the message is passed onto the app. +void gsUdpConnAttemptCB(GT2Socket socket, GT2Connection connection, unsigned int ip, + unsigned short port, int latency, GT2Byte * message, int len) +{ + // Get the message handler for the connection + int index; + GSUdpMsgHandler aHandler; + GSUdpRemotePeer aRemotePeer; + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + char anAddr[GS_IP_ADDR_AND_PORT]; + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connection attempt from %s\n", gt2AddressToString(ip, port, anAddr)); + //If there is a handler, automatically accept a connection if the initial message is + //the same as the handler's registered initial message + if (len >= GS_UDP_MSG_HEADER_LEN) + { + memcpy(aHandler.mInitialMsg, message, GS_UDP_MSG_HEADER_LEN); + + aRemotePeer.mAddr = ip; + aRemotePeer.mPort = port; + aRemotePeer.mConnection = connection; + + ArrayAppend(aUdp->mRemotePeers, &aRemotePeer); + index = ArraySearch(aUdp->mMsgHandlers, &aHandler, gsUdpMsgHandlerCompare, 0, 0); + if (index != NOT_FOUND) + { + GT2ConnectionCallbacks aCallbacks; + + aCallbacks.closed = gsUdpClosedRoutingCB; + aCallbacks.connected = gsUdpConnectedRoutingCB; + aCallbacks.ping = gsUdpPingRoutingCB; + aCallbacks.received = gsUdpReceivedRoutingCB; + + + // Automatically accept connections for Message Handlers + gt2Accept(aRemotePeer.mConnection, &aCallbacks); + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connection attempt auto-accepted for message handler\n"); + return; + } + } + // all other messages go to the app + if (aUdp->mAppConnAttempt) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "[Udp Engine] Connection attempt from %s, asking app to accept/reject\n", gt2AddressToString(ip, port, anAddr)); + aUdp->mAppConnAttempt(ip, port, latency, (unsigned char *)message, (unsigned int)len, aUdp->mAppUserData); + } + else + { + // Reject any un-handled connections or unknown connections + gt2Reject(connection, NULL, 0); + ArrayRemoveAt(aUdp->mRemotePeers, ArrayLength(aUdp->mRemotePeers) -1); + } + GSI_UNUSED(socket); + GSI_UNUSED(anAddr); +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Public functions + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Used to check if the UDP layer needs to be initialized +gsi_bool gsUdpEngineIsInitialized() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + return aUdp->mInitialized; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Initializes the UDP layer +// A specific port can be used if needed. +// An app must register their callbacks here. +// An App must also call this before starting SDKs since they might start +// the UDP layer without the app having a chance to register its callbacks. +// Any message handler can get the port the UDP layer is using if it did not +// initialize the UDP Layer. +// Use of the UDP Layer requires it to be initialized as is the case with most +// functions below. +GSUdpErrorCode gsUdpEngineInitialize(unsigned short thePort, int theIncomingBufSize, + int theOutgoingBufSize, gsUdpErrorCallback theAppNetworkError, + gsUdpConnConnectedCallback theAppConnected, + gsUdpConnClosedCallback theAppClosed, + gsUdpConnPingCallback theAppPing, + gsUdpConnReceivedDataCallback theAppReceive, + gsUdpUnknownMsgCallback theAppUnownMsg, + gsUdpAppConnectAttemptCallback theAppConnectAttempt, + void *theAppUserData) +{ + int incomingBufferSize, + outgoingBufferSize; + char anAddr[GS_IP_ADDR_AND_PORT]; + GT2Result aGt2Result; + // Grab the single instance of the UDP Communication Engine + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + // Setup our gt2 buffer sizes for reliable messages + + incomingBufferSize = theIncomingBufSize != 0 ? theIncomingBufSize : GS_UDP_DEFAULT_IN_BUFFSIZE; + outgoingBufferSize = theOutgoingBufSize != 0 ? theOutgoingBufSize : GS_UDP_DEFAULT_OUT_BUFFSIZE; + + // Setup our internal socket that will be shared among more than one application + aUdp->mAppNetworkError = theAppNetworkError; + aUdp->mAppUnknownMessage = theAppUnownMsg; + aUdp->mAppConnected = theAppConnected; + aUdp->mAppClosed = theAppClosed; + aUdp->mAppPingReply = theAppPing; + aUdp->mAppRecvData = theAppReceive; + aUdp->mAppConnAttempt = theAppConnectAttempt; + + // Any port can be used + gt2AddressToString(0, thePort, anAddr); + aGt2Result = gt2CreateSocket(&aUdp->mSocket, anAddr, outgoingBufferSize, incomingBufferSize, + gsUdpSocketError); + if (aGt2Result != GT2Success) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_WarmError, + "[Udp Engine] error creating gt2 socket, error code: %d\n", aGt2Result); + return GS_UDP_NETWORK_ERROR; + } + // We'll need to keep track of connections with an array of GPconnection to address mapping + aUdp->mRemotePeers = ArrayNew(sizeof(GSUdpRemotePeer), 1, NULL); + if (aUdp->mRemotePeers == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "[Udp Engine] No more memory!!!\n"); + return GS_UDP_NO_MEMORY; + } + + aUdp->mMsgHandlers = ArrayNew(sizeof(GSUdpMsgHandler), 1, gsUdpMsgHandlerFree); + if (aUdp->mMsgHandlers == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "[Udp Engine] No more memory!!!\n"); + return GS_UDP_NO_MEMORY; + } + + // Used by the manager to receive messages from backend services or other clients + // that may not be using gt2 + gt2SetUnrecognizedMessageCallback(aUdp->mSocket, gsUdpUnrecognizedMsgCB); + + // Automatically start listening for all SDKS and the game if game uses UDP Engine + gt2Listen(aUdp->mSocket, gsUdpConnAttemptCB); + aUdp->mLocalAddr = gt2GetLocalIP(aUdp->mSocket); + aUdp->mLocalPort = gt2GetLocalPort(aUdp->mSocket); + aUdp->mAppPendingConnections = 0; + aUdp->mInitialized = gsi_true; + if (theAppUserData) + { + aUdp->mAppUserData = theAppUserData; + } + else + aUdp->mAppUserData = NULL; + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Used obtain the peer's state +// theIp and thePort cannot be 0 (Zero) +GSUdpErrorCode gsUdpEngineGetPeerState(unsigned int theIp, unsigned short thePort, GSUdpPeerState *thePeerState) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GSUdpRemotePeer aPeer, *aPeerFound; + int index; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theIp); + GS_ASSERT(thePort); + GS_ASSERT(thePeerState != NULL); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_State, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + *thePeerState = GS_UDP_PEER_CLOSED; + return GS_UDP_NOT_INITIALIZED; + } + + aPeer.mAddr = theIp; + aPeer.mPort = thePort; + index = ArraySearch(aUdp->mRemotePeers, &aPeer, gsUdpRemotePeerCompare, 0, 0); + if (index == NOT_FOUND) + { + *thePeerState = GS_UDP_PEER_CLOSED; + return GS_UDP_NO_ERROR; + } + + aPeerFound = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, index); + + *thePeerState = (GSUdpPeerState)gt2GetConnectionState(aPeerFound->mConnection); + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// theIp and thePort cannot be 0 (Zero) +// Starts a request to open a communication channel with another peer based on +// IP and port. +GSUdpErrorCode gsUdpEngineStartTalkingToPeer(unsigned int theIp, unsigned short thePort, + char theInitMsg[GS_UDP_MSG_HEADER_LEN], int timeOut) +{ + char anAddr[GS_IP_ADDR_AND_PORT]; + GSUdpRemotePeer aRemotePeer; + GSUdpMsgHandler aHandler; + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GT2ConnectionCallbacks aCallbacks; + int index; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theIp); + GS_ASSERT(thePort); + + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + + if (theIp == 0 || thePort == 0) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Invalid parameter(s), check ip, port"); + return GS_UDP_PARAMETER_ERROR; + } + + aRemotePeer.mAddr = theIp; // In Network Byte Order for GT2 + aRemotePeer.mPort = thePort; // In Host Byte Order for GT2 + + index = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (index != NOT_FOUND) + { + GSUdpRemotePeer *aPeerFound = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, index); + GT2ConnectionState aState = gt2GetConnectionState(aPeerFound->mConnection); + if (aState == GT2Connected) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine is already talking to remote address\n"); + return GS_UDP_ADDRESS_ALREADY_IN_USE; + } + else if (aState == GT2Connecting) + { + memcpy(aHandler.mInitialMsg, theInitMsg, GS_UDP_MSG_HEADER_LEN); + + index = ArraySearch(aUdp->mMsgHandlers, &aHandler, gsUdpMsgHandlerCompare, 0, 0); + if (index != NOT_FOUND) + { + GSUdpMsgHandler *aHandlerFound = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, index); + ArrayAppend(aHandlerFound->mPendingConnections, aPeerFound); + } + } + } + else + { + gt2AddressToString(theIp, thePort, anAddr); + aCallbacks.closed = gsUdpClosedRoutingCB; + aCallbacks.connected = gsUdpConnectedRoutingCB; + aCallbacks.ping = gsUdpPingRoutingCB; + aCallbacks.received = gsUdpReceivedRoutingCB; + + // start the connect without blocking since we want the engine to be as asynchronous as possible + gt2Connect(aUdp->mSocket, &aRemotePeer.mConnection, anAddr, (unsigned char *)theInitMsg, GS_UDP_MSG_HEADER_LEN, timeOut, &aCallbacks, GT2False); + + ArrayAppend(aUdp->mRemotePeers, &aRemotePeer); + + memcpy(aHandler.mInitialMsg, theInitMsg, GS_UDP_MSG_HEADER_LEN); + + index = ArraySearch(aUdp->mMsgHandlers, &aHandler, gsUdpMsgHandlerCompare, 0, 0); + if (index != NOT_FOUND) + { + GSUdpRemotePeer *aRemotePeerPtr = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, ArrayLength(aUdp->mRemotePeers) - 1); + GSUdpMsgHandler *aHandlerFound = (GSUdpMsgHandler *)ArrayNth(aUdp->mMsgHandlers, index); + ArrayAppend(aHandlerFound->mPendingConnections, &aRemotePeerPtr); + } + else + { + aUdp->mAppPendingConnections++; + } + } + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// theIp and thePort cannot be 0 (Zero) +// Accepts a Peer's request for communication +// Should only be used by App +GSUdpErrorCode gsUdpEngineAcceptPeer(unsigned int theIp, unsigned short thePort) +{ + GSUdpRemotePeer aRemotePeer; + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + int index; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theIp); + GS_ASSERT(thePort); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + + if (theIp == 0 || thePort == 0) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Invalid parameter(s), check ip, port\n"); + return GS_UDP_PARAMETER_ERROR; + } + + aRemotePeer.mAddr = theIp; + aRemotePeer.mPort = thePort; + index = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (index != NOT_FOUND) + { + GT2ConnectionCallbacks aCallbacks; + + GSUdpRemotePeer *aPeerFound = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, index); + + aCallbacks.closed = gsUdpClosedRoutingCB; + aCallbacks.connected = gsUdpConnectedRoutingCB; + aCallbacks.ping = gsUdpPingRoutingCB; + aCallbacks.received = gsUdpReceivedRoutingCB; + + gt2Accept(aPeerFound->mConnection, &aCallbacks); + } + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// theIp and thePort cannot be 0 (Zero) +// Rejects a Peer's request for communication +// Should only be used by App +GSUdpErrorCode gsUdpEngineRejectPeer(unsigned int theIp, unsigned short thePort) +{ + GSUdpRemotePeer aRemotePeer; + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + int index; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theIp); + GS_ASSERT(thePort); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + + if (theIp == 0 || thePort == 0) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Invalid parameter(s), check ip, port\n"); + return GS_UDP_PARAMETER_ERROR; + } + + // Find the connection to reject in our array of peers + aRemotePeer.mAddr = theIp; + aRemotePeer.mPort = thePort; + index = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (index != NOT_FOUND) + { + GSUdpRemotePeer *aPeerFound = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, index); + gt2Reject(aPeerFound->mConnection, NULL, 0); + ArrayDeleteAt(aUdp->mRemotePeers, index); + } + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Sends a message to a peer using IP and Port +// An empty header constitutes the app sending this message. +// theIp and thePort cannot be 0 (Zero) +// +// WARNING: Messages should not be greater than the outgoing buffer size minus the header +// and the 7 byte header for reliable messages (used for internal gt2 operations). Most +// UDP fragmentation occurs if messages are bigger than 1500 bytes. Also, some routers are +// known to drop those packets that are larger than 1500 bytes. The recommended outgoing +// buffer size is the default (1460). So take that, and subtract 16 for message handler header +// and reliable message header (if sending data reliably). +// freeSpace = 1460 - 16 - 7 +GSUdpErrorCode gsUdpEngineSendMessage(unsigned int theIp, unsigned short thePort, + char theHeader[GS_UDP_MSG_HEADER_LEN], unsigned char *theMsg, + unsigned int theMsgLen, gsi_bool theReliable) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + int aTotalMessageLen, index; + GSUdpRemotePeer aRemotePeer, *aRemotePeerFound; + GT2Byte *fullMessage; + GT2Result aResult; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theIp); + GS_ASSERT(thePort); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + + // Messages being sent with an empty header are treated as app messages + if (!theHeader[0]) + aTotalMessageLen = (int)theMsgLen; + else + aTotalMessageLen = (int)(GS_UDP_MSG_HEADER_LEN + theMsgLen); + + aRemotePeer.mAddr = theIp; + aRemotePeer.mPort = thePort; + + index = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (index == NOT_FOUND) + { + char anAddr[GS_IP_ADDR_AND_PORT]; + gt2AddressToString(theIp, thePort, anAddr); + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_WarmError, + "[Udp Engine] address not found for sending message\n", anAddr); + return GS_UDP_ADDRESS_ERROR; + } + else + { + aRemotePeerFound = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, index); + } + + if (aTotalMessageLen > gt2GetOutgoingBufferSize(aRemotePeerFound->mConnection) && theReliable) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_WarmError, + "[Udp Engine] Message Size too large, dropping message\n"); + return GS_UDP_MSG_TOO_BIG; + } + + fullMessage = (GT2Byte *)gsimalloc((unsigned long)aTotalMessageLen); + memcpy(fullMessage, theHeader, GS_UDP_MSG_HEADER_LEN); + memcpy(fullMessage + GS_UDP_MSG_HEADER_LEN, theMsg, theMsgLen); + // Send the message + // reliable messages will be kept in the outgoing buffers till they are sent + aResult = gt2Send(aRemotePeerFound->mConnection, fullMessage, aTotalMessageLen, theReliable); + gsifree(fullMessage); + + if (aResult != GT2Success) + return GS_UDP_SEND_FAILED; + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// One the UDP Layer is initialized, this function +// should be called every 10-100 ms +// Message handlers already call this which means +// that the app may not have to call this function +GSUdpErrorCode gsUdpEngineThink() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + gt2Think(aUdp->mSocket); + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Shutdown should only happen if following is met: +// Apps can call this function after they have shutdown message handlers (SDKs), +// and verified there are no message handlers remaining. Calling the function +// gsUdpEngineNoMoreMsgHandlers will do this. +// Message handlers cannot call this function without checking if there no more +// message handlers remaining and if there is no app (gsUdpEngineNoApp). +GSUdpErrorCode gsUdpEngineShutdown() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + gt2CloseSocket(aUdp->mSocket); + ArrayFree(aUdp->mMsgHandlers); + ArrayFree(aUdp->mRemotePeers); + aUdp->mInitialized = gsi_false; + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Obtains the lower level socket that can be used to perform other operations +// or pass to other SDKs. +SOCKET gsUdpEngineGetSocket() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_HotError, + "[Udp Engine] Engine not initialized\n"); + return INVALID_SOCKET; + } + + return gt2GetSocketSOCKET(aUdp->mSocket); +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Gets the local IP the UDP layer is bound to. +unsigned int gsUdpEngineGetLocalAddr() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_HotError, + "[Udp Engine] Engine not initialized\n"); + return (unsigned int)-1; + } + return aUdp->mLocalAddr; + +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Gets the local port the UDP layer is bound to. +unsigned short gsUdpEngineGetLocalPort() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_HotError, + "[Udp Engine] Engine not initialized\n"); + return 0; + } + return aUdp->mLocalPort; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Message handlers are added using this function +// The initial message and header of a message handler cannot be empty +// However, they can be the same. +// User data can be useful for keeping track of Message Handler +GSUdpErrorCode gsUdpEngineAddMsgHandler(char theInitMsg[GS_UDP_MSG_HEADER_LEN], char theHeader[GS_UDP_MSG_HEADER_LEN], + gsUdpErrorCallback theMsgHandlerError, + gsUdpConnConnectedCallback theMsgHandlerConnected, + gsUdpConnClosedCallback theMsgHandlerClosed, + gsUdpConnPingCallback theMsgHandlerPing, + gsUdpConnReceivedDataCallback theMsgHandlerRecv, + void *theUserData) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GSUdpMsgHandler aMsgHandler; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theInitMsg || theInitMsg[0]); + GS_ASSERT(theHeader || theHeader[0]); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + + // setup a message handler that the UDP engine will use to pass connection attempts to + + //check for valid input + if (!theInitMsg[0]) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Invalid init message\n"); + return GS_UDP_PARAMETER_ERROR; + } + + if (!theHeader[0]) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Invalid header\n"); + return GS_UDP_PARAMETER_ERROR; + } + + // This check is not necessary. Some SDKs may not use all callbacks + /*if (!theMsgHandlerError || !theMsgHandlerConnected || !theMsgHandlerClosed + || !theMsgHandlerPing || !theMsgHandlerRecv) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Invalid callback(s)"); + return GS_UDP_PARAMETER_ERROR; + } + */ + aMsgHandler.mClosed = theMsgHandlerClosed; + aMsgHandler.mConnected = theMsgHandlerConnected; + aMsgHandler.mPingReply = theMsgHandlerPing; + aMsgHandler.mReceived = theMsgHandlerRecv; + + aMsgHandler.mNetworkError = theMsgHandlerError; + + memcpy(aMsgHandler.mInitialMsg, theInitMsg, GS_UDP_MSG_HEADER_LEN); + memcpy(aMsgHandler.mHeader, theHeader, GS_UDP_MSG_HEADER_LEN); + + aMsgHandler.mPendingConnections = ArrayNew(sizeof(GSUdpRemotePeer *), 1, NULL); + if (aMsgHandler.mPendingConnections == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "[Udp Engine] No more memory!!!\n"); + return GS_UDP_NO_MEMORY; + } + aMsgHandler.mUserData = theUserData; + ArrayAppend(aUdp->mMsgHandlers, &aMsgHandler); + + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// When a message handler is done or shutting down, the message handler should remove +// itself from the UDP Layer +// The header cannot be empty +GSUdpErrorCode gsUdpEngineRemoveMsgHandler(char theHeader[GS_UDP_MSG_HEADER_LEN]) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GSUdpMsgHandler aHandler; + int index; + + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theHeader); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return GS_UDP_NETWORK_ERROR; + } + + if (!theHeader || !theHeader[0]) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] invalid or empty header\n"); + return GS_UDP_PARAMETER_ERROR; + } + + memcpy(aHandler.mHeader, theHeader, GS_UDP_MSG_HEADER_LEN); + + index = ArraySearch(aUdp->mMsgHandlers, &aHandler, gsUdpMsgHandlerCompare2, 0, 0); + if (index != NOT_FOUND) + { + ArrayDeleteAt(aUdp->mMsgHandlers, index); + } + return GS_UDP_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// Checks to see if there any remaining message handlers. +// returns gsi_false if there are none. +gsi_bool gsUdpEngineNoMoreMsgHandlers() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return gsi_true; + } + + return ArrayLength(aUdp->mMsgHandlers) == 0 ? gsi_true : gsi_false; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// returns gsi_false if there is no app using the UDP Layer +gsi_bool gsUdpEngineNoApp() +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + + GS_ASSERT(aUdp->mInitialized); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return gsi_true; + } + + if (aUdp->mAppClosed || aUdp->mAppConnAttempt || aUdp->mAppConnected || aUdp->mAppNetworkError + || aUdp->mAppPingReply || aUdp->mAppRecvData || aUdp->mAppUnknownMessage) + { + return gsi_false; + } + + return gsi_true; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Layer must be initialized +// theIp and thePort cannot be 0 (Zero) +// Based on an IP and port, the function will return the amount of free space +// of a peer's buffer. +int gsUdpEngineGetPeerOutBufferFreeSpace(unsigned int theIp, unsigned short thePort) +{ + GSUdpEngineObject *aUdp = gsUdpEngineGetEngine(); + GSUdpRemotePeer aRemotePeer, *aRemotePeerFound; + int index; + GS_ASSERT(aUdp->mInitialized); + GS_ASSERT(theIp); + GS_ASSERT(thePort); + if (!aUdp->mInitialized) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Debug, + "[Udp Engine] Engine not initialized\n"); + return 0; + } + + aRemotePeer.mAddr = theIp; + aRemotePeer.mPort = thePort; + index = ArraySearch(aUdp->mRemotePeers, &aRemotePeer, gsUdpRemotePeerCompare, 0, 0); + if (index != NOT_FOUND) + { + aRemotePeerFound = (GSUdpRemotePeer *)ArrayNth(aUdp->mRemotePeers, index); + return gt2GetOutgoingBufferFreeSpace(aRemotePeerFound->mConnection); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Creates a string address given an IP and port +// IP and port can be 0. +void gsUdpEngineAddrToString(unsigned int theIp, unsigned short thePort, char addrstring[GS_IP_ADDR_AND_PORT]) +{ + gt2AddressToString(theIp, thePort, addrstring); +} diff --git a/xrGameSpy/gamespy/common/gsUdpEngine.h b/xrGameSpy/gamespy/common/gsUdpEngine.h new file mode 100644 index 00000000000..07c2b09e795 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsUdpEngine.h @@ -0,0 +1,180 @@ +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +#ifndef __GS_UDP_ENGINE_H__ +#define __GS_UDP_ENGINE_H__ + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// UDP Communication Engine +// +#include "gsCommon.h" +#include "../gt2/gt2.h" +#include "../darray.h" + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Constants + +// The UDP Engine should try the MSS (Maximum Segment Size = IP Packet size - IP Header) +// as a default size to keep the packets from being fragmented. Currently 1460 is the +// MSS for windows. Consoles may have a different size. +#define GS_UDP_DEFAULT_OUT_BUFFSIZE 1460 +#define GS_UDP_DEFAULT_IN_BUFFSIZE 1500 + +// a default size for address strings +#define GS_IP_ADDR_AND_PORT 22 + +// A fixed header len. unless we require a bigger size, it will stay this size. +// These need to be used for calculating the free space available on +// the outgoing buffers for an IP and Port which represent the peer. +#define GS_UDP_MSG_HEADER_LEN 16 +#define GS_UDP_RELIABLE_MSG_HEADER 7 + +// The following error codes will be given back to the higher level app +// or message handler. +typedef enum _GSUdpErrorCode +{ + GS_UDP_NO_ERROR, + GS_UDP_NO_MEMORY, + GS_UDP_REJECTED, + GS_UDP_NETWORK_ERROR, + GS_UDP_ADDRESS_ERROR, + GS_UDP_ADDRESS_ALREADY_IN_USE, + GS_UDP_TIMED_OUT, + GS_UDP_REMOTE_ERROR, + GS_UDP_SEND_FAILED, + GS_UDP_INVALID_MESSAGE, + GS_UDP_PARAMETER_ERROR, + GS_UDP_NOT_INITIALIZED, + GS_UDP_MSG_TOO_BIG, + GS_UDP_UNKNOWN_ERROR, + // Add new errors before here + GS_UDP_NUM_ERROR_CODES +} GSUdpErrorCode; + +// Used so that an app or message handler does +// not need to request to start talking to a peer twice +// Also lets higher level app or message handlers know about +// if a communication channel to a peer has been broken. +typedef enum _GSUdpPeerState +{ + GS_UDP_PEER_CONNECTING, + GS_UDP_PEER_CONNECTED, + GS_UDP_PEER_CLOSING, + GS_UDP_PEER_CLOSED, + // Add new connection state before here + GS_UDP_PEER_STATE_NUM +} GSUdpPeerState; + +// When a communication channel to a peer is closed +// the closed callback will let us know why it was closed +typedef enum _GSUdpCloseReason +{ + GS_UDP_CLOSED_LOCALLY, + GS_UDP_CLOSED_REMOTELY, + // errors: + GS_UDP_CLOSED_BY_COMM_ERROR, // An invalid message was received (it was either unexpected or wrongly formatted). + GS_UDP_CLOSED_BY_LOW_MEM, + // Add new reasons before here + GS_UDP_CLOSED_NUM +} GSUdpCloseReason; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Callbacks + +// Errors to give higher layers feedback +typedef void (*gsUdpErrorCallback)(GSUdpErrorCode theCode, void *theUserData); + + +// app Request attempt callback used to tell registered listeners about connection attempts +typedef void (*gsUdpAppConnectAttemptCallback)(unsigned int theIp, unsigned short thePort, + int theLatency, unsigned char *theInitMsg, + unsigned int theInitMsgLen, void *theUserData); + + +// peer communication channel callback types +typedef void (*gsUdpConnClosedCallback)(unsigned int ip, unsigned short port, GSUdpCloseReason reason, + void *theUserData); +typedef void (*gsUdpConnReceivedDataCallback)(unsigned int ip, unsigned short port, + unsigned char *message, unsigned int messageLength, + gsi_bool reliable, void *theUserData); +typedef void (*gsUdpConnConnectedCallback)(unsigned int ip, unsigned short port, + GSUdpErrorCode error, gsi_bool rejected, + void *theUserData); +typedef void (*gsUdpConnPingCallback)(unsigned int ip, unsigned short port, unsigned int latency, + void *theUserData); + + +// Messages that cannot be interpreted are passed on to the higher level app +typedef gsi_bool (*gsUdpUnknownMsgCallback)(unsigned int ip, unsigned short port, + unsigned char *message, unsigned int messageLength, + void *theUserData); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Public Functionality +// Initialization and test functions +gsi_bool gsUdpEngineIsInitialized(); +GSUdpErrorCode gsUdpEngineInitialize(unsigned short thePort, int theIncomingBufSize, + int theOutgoingBufSize, gsUdpErrorCallback theAppNetworkError, + gsUdpConnConnectedCallback theAppConnected, + gsUdpConnClosedCallback theAppClosed, + gsUdpConnPingCallback theAppPing, + gsUdpConnReceivedDataCallback theAppReceive, + gsUdpUnknownMsgCallback theAppUnownMsg, + gsUdpAppConnectAttemptCallback theAppConnectAttempt, + void *theAppUserData); +// update and shutdown +GSUdpErrorCode gsUdpEngineThink(); +GSUdpErrorCode gsUdpEngineShutdown(); + +// Connectivity functions +GSUdpErrorCode gsUdpEngineGetPeerState(unsigned int theIp, unsigned short thePort, + GSUdpPeerState *thePeerState); +GSUdpErrorCode gsUdpEngineStartTalkingToPeer(unsigned int theIp, unsigned short thePort, + char theInitMsg[GS_UDP_MSG_HEADER_LEN], int timeOut); +GSUdpErrorCode gsUdpEngineAcceptPeer(unsigned int theIp, unsigned short thePort); +GSUdpErrorCode gsUdpEngineRejectPeer(unsigned int theIp, unsigned short thePort); + +// Sending functionality +// WARNING: Messages should not be greater than the outgoing buffer size minus the header +// and the 7 byte header for reliable messages (used for internal gt2 operations). Most +// UDP fragmentation occurs if messages are bigger than 1500 bytes. Also, some routers are +// known to drop those packets that are larger than 1500 bytes because of set MTU sizes. +// The recommended outgoing buffer size is the default (1460). So take that, and subtract +// 16 for message handler header and reliable message header (if sending data reliably). +// freeSpace = 1460 - 16 - 7 +GSUdpErrorCode gsUdpEngineSendMessage(unsigned int theIp, unsigned short thePort, + char theHeader[GS_UDP_MSG_HEADER_LEN], unsigned char *theMsg, + unsigned int theMsgLen, gsi_bool theReliable); + +// This function should be called for those parts of the code that want specific handling of messages +// Any call to send should include the header registered here. +GSUdpErrorCode gsUdpEngineAddMsgHandler(char theInitMsg[GS_UDP_MSG_HEADER_LEN], + char theHeader[GS_UDP_MSG_HEADER_LEN], + gsUdpErrorCallback theMsgHandlerError, + gsUdpConnConnectedCallback theMsgHandlerConnected, + gsUdpConnClosedCallback theMsgHandlerClosed, + gsUdpConnPingCallback theMsgHandlerPing, + gsUdpConnReceivedDataCallback theMsgHandlerRecv, + void *theUserData); +GSUdpErrorCode gsUdpEngineRemoveMsgHandler(char theHeader[GS_UDP_MSG_HEADER_LEN]); +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Public Utility functionality +SOCKET gsUdpEngineGetSocket(); +void gsUdpEngineAddrToString(unsigned int theIp, unsigned short thePort, + char addrstring[GS_IP_ADDR_AND_PORT]); +unsigned int gsUdpEngineGetLocalAddr(); +unsigned short gsUdpEngineGetLocalPort(); + +// lets the app or message handler know if it is able to shutdown the udp layer +gsi_bool gsUdpEngineNoMoreMsgHandlers(); +gsi_bool gsUdpEngineNoApp(); + +// check the remaining free space on the outgoing buffer for the peer based +// IP and port +int gsUdpEngineGetPeerOutBufferFreeSpace(unsigned int theIp, unsigned short thePort); + +#endif diff --git a/xrGameSpy/gamespy/common/gsXML.c b/xrGameSpy/gamespy/common/gsXML.c new file mode 100644 index 00000000000..13a26f6cb2d --- /dev/null +++ b/xrGameSpy/gamespy/common/gsXML.c @@ -0,0 +1,2043 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "gsPlatform.h" +#include "gsMemory.h" +#include "gsXML.h" +#include "gsStringUtil.h" +#include "../darray.h" + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 155, 156, 161, 162 +#pragma warning(disable: 4244) //lines: 128, 720, 752 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define GS_XML_INITIAL_ELEMENT_ARRAY_COUNT 32 +#define GS_XML_INITIAL_ATTRIBUTE_ARRAY_COUNT 16 + +#define GS_XML_WHITESPACE "\x20\x09\x0D\x0A" + +#define GS_XML_CHECK(a) { if (gsi_is_false(a)) return gsi_false; } + +#define GS_XML_BASE64_ENCODING_TYPE 0 + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define GS_XML_SOAP_BUFFER_INITIAL_SIZE (1 * 1024) +#define GS_XML_SOAP_BUFFER_INCREMENT_SIZE (1 * 1024) +#define GS_XML_SOAP_INITIAL_NAMESPACE_COUNT 6 + +#define GS_XML_SOAP_HEADER "" +#define GS_XML_SOAP_FOOTER "" +#define GS_XML_SOAP_NAMESPACE_PREFIX "xmlns:" + +#define GS_XML_SOAP_DEFAULT_NAMESPACE_COUNT 4 +const char * GS_XML_SOAP_DEFAULT_NAMESPACES[GS_XML_SOAP_DEFAULT_NAMESPACE_COUNT] = +{ + "SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"", + "SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"", + "xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", + "xsd=\"http://www.w3.org/2001/XMLSchema\"" +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Warning: Do not store pointers to other GSXml* objects within a GSXml object +// Pointers to elements may be invalidate if the DArray's grow +// Instead, store the array index and require that indexes never change +typedef struct GSIXmlString +{ + const gsi_u8 * mData; + int mLen; +} GSIXmlString; + +typedef struct GSIXmlAttribute +{ + GSIXmlString mName; + GSIXmlString mValue; + + int mIndex; + int mParentIndex; +} GSIXmlAttribute; + +typedef struct GSIXmlElement +{ + GSIXmlString mName; + GSIXmlString mValue; // most do not have a value + + int mIndex; + int mParentIndex; +} GSIXmlElement; + +typedef struct GSIXmlStreamReader +{ + DArray mElementArray; + DArray mAttributeArray; + + int mElemReadIndex; // current index + int mValueReadIndex; // current child parsing index +} GSIXmlStreamReader; + +typedef struct GSIXmlStreamWriter +{ + char * mBuffer; + int mLen; + int mCapacity; + gsi_bool mClosed; // footer has been written, append not allowed +} GSIXmlStreamWriter; + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilSkipWhiteSpace(GSIXmlStreamReader * stream, const char * buffer, int len, int * pos); +static gsi_bool gsiXmlUtilParseName (GSIXmlStreamReader * stream, const char * buffer, int len, int * pos, GSIXmlString * strOut); +static gsi_bool gsiXmlUtilParseString (GSIXmlStreamReader * stream, char * buffer, int len, int * pos, GSIXmlString * strOut); +static gsi_bool gsiXmlUtilParseValue (GSIXmlStreamReader * stream, char * buffer, int len, int * pos, GSIXmlString * strOut); +static gsi_bool gsiXmlUtilParseElement (GSIXmlStreamReader * stream, char * buffer, int len, int * pos, int parentIndex); +static gsi_bool gsiXmlUtilTagMatches(const char * matchtag, GSIXmlString * xmlstr); + +// Note: Writes decoded form back into buffer +static gsi_bool gsiXmlUtilDecodeString(char * buffer, int * len); + +static void gsiXmlUtilElementFree(void * elem); +static void gsiXmlUtilAttributeFree(void * elem); + +static gsi_bool gsiXmlUtilWriteChar(GSIXmlStreamWriter * stream, char ch); +static gsi_bool gsiXmlUtilWriteString(GSIXmlStreamWriter * stream, const char * str); +static gsi_bool gsiXmlUtilWriteXmlSafeString(GSIXmlStreamWriter * stream, const char * str); +static gsi_bool gsiXmlUtilGrowBuffer(GSIXmlStreamWriter * stream); +#ifdef GSI_UNICODE +static gsi_bool gsiXmlUtilWriteAsciiString(GSIXmlStreamWriter * stream, const gsi_char * str); +#endif +static gsi_bool gsiXmlUtilWriteUnicodeString(GSIXmlStreamWriter * stream, const unsigned short * str); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static int gsUnicodeStringLen(const unsigned short * str) +{ + const unsigned short * end = str; + while(*end++) + {} + return (end - str - 1); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +GSXmlStreamWriter gsXmlCreateStreamWriter(const char ** namespaces, int count) +{ + GSIXmlStreamWriter * newStream = NULL; + int initialCapacity = GS_XML_SOAP_BUFFER_INCREMENT_SIZE; + int namespaceLen = 0; + int i=0; + + GS_ASSERT((namespaces == NULL && count == 0) || (namespaces != NULL && count != 0)); + + newStream = (GSIXmlStreamWriter*)gsimalloc(sizeof(GSIXmlStreamWriter)); + if (newStream == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "Out of memory in gsXmlCreateStreamWriter, needed %d bytes", sizeof(GSIXmlStreamWriter)); + return NULL; // OOM + } + + // do this to prevent an immediately reallocation due to long namespace string + for (i=0; i < GS_XML_SOAP_DEFAULT_NAMESPACE_COUNT; i++) + { + GS_ASSERT(GS_XML_SOAP_DEFAULT_NAMESPACES[i] != NULL); + namespaceLen += strlen(GS_XML_SOAP_NAMESPACE_PREFIX)+1; // +1 for space + namespaceLen += strlen(GS_XML_SOAP_DEFAULT_NAMESPACES[i]); + } + for (i=0; i < count; i++) + { + GS_ASSERT(namespaces[i] != NULL); + namespaceLen += strlen(GS_XML_SOAP_NAMESPACE_PREFIX)+1; // +1 for space + namespaceLen += strlen(namespaces[i]); + } + while (initialCapacity < namespaceLen) + initialCapacity += GS_XML_SOAP_BUFFER_INCREMENT_SIZE; + + // allocate write buffer + newStream->mBuffer = (char*)gsimalloc((size_t)initialCapacity); + if (newStream->mBuffer == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "Out of memory in gsXmlCreateStreamWriter, needed %d bytes", initialCapacity); + return NULL; // OOM + } + newStream->mCapacity = initialCapacity; + newStream->mLen = 0; + newStream->mBuffer[0] = '\0'; + newStream->mClosed = gsi_false; + + // write the XML header + if (gsi_is_false(gsiXmlUtilWriteString(newStream, GS_XML_SOAP_HEADER))) + { + gsifree(newStream->mBuffer); + gsifree(newStream); + return NULL; // OOM + } + for (i=0; i < GS_XML_SOAP_DEFAULT_NAMESPACE_COUNT; i++) + { + if (gsi_is_false(gsiXmlUtilWriteChar(newStream, ' ')) || + gsi_is_false(gsiXmlUtilWriteString(newStream, GS_XML_SOAP_NAMESPACE_PREFIX)) || + gsi_is_false(gsiXmlUtilWriteString(newStream, GS_XML_SOAP_DEFAULT_NAMESPACES[i]))) + { + gsifree(newStream->mBuffer); + gsifree(newStream); + return NULL; // OOM + } + } + for (i=0; i < count; i++) + { + if (gsi_is_false(gsiXmlUtilWriteChar(newStream, ' ')) || + gsi_is_false(gsiXmlUtilWriteString(newStream, GS_XML_SOAP_NAMESPACE_PREFIX)) || + gsi_is_false(gsiXmlUtilWriteString(newStream, namespaces[i])) ) + { + gsifree(newStream->mBuffer); + gsifree(newStream); + return NULL; // OOM + } + } + if (gsi_is_false(gsiXmlUtilWriteChar(newStream, '>')) || + gsi_is_false(gsiXmlUtilWriteString(newStream, GS_XML_SOAP_BODY_TAG)) ) + { + gsifree(newStream->mBuffer); + gsifree(newStream); + return NULL; // OOM + } + + return (GSXmlStreamWriter)newStream; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +GSXmlStreamReader gsXmlCreateStreamReader() +{ + GSIXmlStreamReader * newStream = NULL; + + newStream = (GSIXmlStreamReader*)gsimalloc(sizeof(GSIXmlStreamReader)); + if (newStream == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "Out of memory in gsXmlCreateStream, needed %d bytes", sizeof(GSIXmlStreamReader)); + return NULL; // OOM + } + + newStream->mElementArray = ArrayNew(sizeof(GSIXmlElement), GS_XML_INITIAL_ELEMENT_ARRAY_COUNT, gsiXmlUtilElementFree); + if (newStream->mElementArray == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "Out of memory in gsXmlCreateStream with mElementArray=ArrayNew()"); + gsifree(newStream); + return NULL; // OOM + } + + newStream->mAttributeArray = ArrayNew(sizeof(GSIXmlAttribute), GS_XML_INITIAL_ATTRIBUTE_ARRAY_COUNT, gsiXmlUtilAttributeFree); + if (newStream->mAttributeArray == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Memory, GSIDebugLevel_HotError, + "Out of memory in gsXmlCreateStream with mElementArray=ArrayNew()"); + ArrayFree(newStream->mElementArray); + gsifree(newStream); + return NULL; // OOM + } + + gsXmlMoveToStart(newStream); + return (GSXmlStreamReader)newStream; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlParseBuffer(GSXmlStreamReader stream, char * data, int len) +{ + GSIXmlStreamReader * reader; + int readPos = 0; + + GS_ASSERT(data != NULL); + GS_ASSERT(len > 0); + + reader = (GSIXmlStreamReader*)stream; + + gsXmlResetReader(stream); + + // Parse the root elements (automatically includes sub-elements) + while(readPos < len) + { + if (gsi_is_false(gsiXmlUtilParseElement(reader, data, len, &readPos, -1))) + return gsi_false; + } + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsXmlFreeWriter(GSXmlStreamWriter stream) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + gsifree(writer->mBuffer); + gsifree(writer); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsXmlFreeReader(GSXmlStreamReader stream) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + ArrayFree(reader->mAttributeArray); + ArrayFree(reader->mElementArray); + gsifree(reader); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsXmlResetReader(GSXmlStreamReader stream) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + ArrayClear(reader->mAttributeArray); + ArrayClear(reader->mElementArray); + gsXmlMoveToStart(stream); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlCloseWriter(GSXmlStreamWriter stream) +{ + GSIXmlStreamWriter* writer = (GSIXmlStreamWriter*)stream; + GS_ASSERT(stream != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + if (gsi_is_false(gsiXmlUtilWriteString(writer, GS_XML_SOAP_FOOTER))) + return gsi_false; + + writer->mClosed = gsi_true; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void gsiXmlUtilElementFree(void * elem) +{ + GSI_UNUSED(elem); + //GSXmlElement * dataPtr = (GSXmlElement*)elem; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void gsiXmlUtilAttributeFree(void * elem) +{ + GSI_UNUSED(elem); + //GSXmlAttribute * dataPtr = (GSXmlAttribute*)elem; + //gsifree(dataPtr); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +const char * gsXmlWriterGetData (GSXmlStreamWriter stream) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + GS_ASSERT(stream != NULL) + return writer->mBuffer; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int gsXmlWriterGetDataLength(GSXmlStreamWriter stream) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + GS_ASSERT(stream != NULL); + return writer->mLen; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilSkipWhiteSpace(GSIXmlStreamReader * stream, const char * buffer, int len, int * pos) +{ + GS_ASSERT(buffer != NULL); + GS_ASSERT(len > 0); + //GS_ASSERT(*pos < len); + + // check if the next character is in the whitespace set + while(*pos < len) + { + if (NULL == strchr(GS_XML_WHITESPACE, buffer[*pos])) + return gsi_true; + (*pos)++; // move to next character + } + + GSI_UNUSED(stream); + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilParseElement(GSIXmlStreamReader * stream, char * buffer, + int len, int * pos, int parentIndex) +{ + GSIXmlElement newElem; + int startPos = 0; + gsi_bool storeElement = gsi_true; + + GS_ASSERT(stream != NULL); + GS_ASSERT(buffer != NULL); + GS_ASSERT(len > 0); + GS_ASSERT(*pos < len); + + gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos); + if (*pos >= len) + return gsi_true; // legal EOF + + memset(&newElem, 0, sizeof(newElem)); + + // elements must begin with '<' + if (buffer[*pos] != '<') + return gsi_false; + (*pos)++; + if (*pos >= len) + return gsi_false; + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + // '<' can be followed with '!', '?', '%', '/' special characters + if (buffer[*pos] == '!' || buffer[*pos] == '?' || + buffer[*pos] == '%' || buffer[*pos] == '/') + { + storeElement = gsi_false; + (*pos)++; + startPos = (*pos)-2; + } + else + startPos = (*pos)-1; // store the position of '<' + + // should be a name (type) next + GS_XML_CHECK(gsiXmlUtilParseName(stream, buffer, len, pos, &newElem.mName)); + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + if (storeElement) + { + GS_ASSERT(newElem.mName.mData != NULL); + newElem.mIndex = ArrayLength(stream->mElementArray); + newElem.mParentIndex = parentIndex; + ArrayAppend(stream->mElementArray, &newElem); + } + + // read attributes (if any) + while (*pos < len && isalnum(buffer[*pos])) + { + // attribute format is name="", e.g. nickname="player1" + GSIXmlAttribute newAttr; + memset(&newAttr, 0, sizeof(newAttr)); + GS_XML_CHECK(gsiXmlUtilParseName(stream, buffer, len, pos, &newAttr.mName)); + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + if (buffer[*pos] != '=') + return gsi_false; + (*pos)++; // skip the '=' + GS_XML_CHECK(gsiXmlUtilParseString(stream, buffer, len, pos, &newAttr.mValue)); + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + // Store it in the array + if (storeElement) + { + GS_ASSERT(newElem.mName.mData != NULL); + GS_ASSERT(newElem.mIndex != -1); + GS_ASSERT(newAttr.mName.mData != NULL); + GS_ASSERT(newAttr.mValue.mData != NULL); + + newAttr.mIndex = ArrayLength(stream->mAttributeArray); + newAttr.mParentIndex = newElem.mIndex; + ArrayAppend(stream->mAttributeArray, &newAttr); + } + } + + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + // Check for immediate termination (no value or children) + // non-element tags end with the same character they start with + // element tags ending with '/>' also have no children + if ( (!isalnum(buffer[startPos+1]) && buffer[*pos] == buffer[startPos+1]) + || buffer[*pos] == '/') + { + (*pos)++; + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + if (buffer[*pos] != '>') + return gsi_false; // only legal character here is closing brace + (*pos)++; + return gsi_true; // legal termination + } + + // make sure we've found the end of the start tag + if (buffer[*pos] != '>') + return gsi_false; + (*pos)++; + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + // check for element value + if (buffer[*pos] != '<') + { + GS_XML_CHECK(gsiXmlUtilParseValue(stream, buffer, len, pos, &newElem.mValue)); + // update the array with the value information + if (storeElement) + ArrayReplaceAt(stream->mElementArray, &newElem, newElem.mIndex); + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + } + + // read child elements and close tag + while (*pos < len) + { + int childStartPos = *pos; + if (buffer[*pos] != '<') + return gsi_false; + (*pos)++; + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + if (buffer[*pos] == '/') + { + // this MUST be a close of the current element + // close tags are in the form: + (*pos)++; + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + if ((*pos)+newElem.mName.mLen >= len) + return gsi_false; // EOF before tag close + if (0 != strncmp((const char*)newElem.mName.mData, &buffer[*pos], (size_t)newElem.mName.mLen)) + return gsi_false; // close tag mismatch + (*pos) += newElem.mName.mLen; + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + if (buffer[*pos] != '>') + return gsi_false; + (*pos)++; + return gsi_true; + } + else + { + if (newElem.mValue.mData != NULL) + return gsi_false; // elements with value cannot have children + + // move read position to start of child element, then parse + *pos = childStartPos; + GS_XML_CHECK(gsiXmlUtilParseElement(stream, buffer, len, pos, newElem.mIndex)); + gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos); + } + } + return gsi_false; // EOF before tag close +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Parse element name +// Must begin with a letter and contains only alphanumeric | '_' | '-' characters +// Element names may consist of two "names", : +static gsi_bool gsiXmlUtilParseName(GSIXmlStreamReader * stream, const char * buffer, + int len, int * pos, GSIXmlString * strOut) +{ + gsi_bool haveNamespace = gsi_false; + GS_ASSERT(buffer != NULL); + GS_ASSERT(len > 0); + + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + // EOF? + if (*pos >= len) + return gsi_false; + + // first character must be alphanumeric but not a digit + if (!isalnum(buffer[*pos]) || isdigit(buffer[*pos])) + return gsi_false; + + strOut->mData = (gsi_u8*)&buffer[*pos]; + strOut->mLen = 1; + (*pos)++; + + while(*pos < len && NULL==strchr(GS_XML_WHITESPACE, buffer[*pos])) + { + // only alpha numeric and '_' characters are allowed, plus one namespace separator ':' + if (buffer[*pos] == ':') + { + if (gsi_is_true(haveNamespace)) + return gsi_false; // already have a namespace! + haveNamespace = gsi_true; + } + else if ((buffer[*pos] != '_') && (buffer[*pos] != '-') && (!isalnum(buffer[*pos]))) + return gsi_true; // treat all others as a new token example '=' + + strOut->mLen++; + (*pos)++; + } + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilParseString(GSIXmlStreamReader * stream, char * buffer, + int len, int * pos, GSIXmlString * strOut) +{ + char startCh = '\0'; + char * strStart = NULL; + //gsi_bool hasMarkup = gsi_false; + + + GS_ASSERT(stream != NULL); + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + // strings may start with either ' or " + startCh = buffer[*pos]; + if (startCh != '\"' && startCh != '\'') + return gsi_false; + + (*pos)++; + strStart = &buffer[*pos]; // remember this for easier processing below + strOut->mLen = 0; + + if (*pos >= len) + return gsi_false; // EOF when looking for string terminator + if (buffer[*pos] == startCh) + { + // empty string ? + strOut->mData = (const gsi_u8*)strStart; + (*pos)++; // skip the terminating character + return gsi_true; + } + + while(buffer[*pos] != startCh) + { + if (*pos >= len) + return gsi_false; // EOF when looking for string terminator + + //if (buffer[*pos] == '&') + //hasMarkup = gsi_true; + + (*pos)++; + strOut->mLen++; + } + (*pos)++; // skip the terminating character + + // decode the string if necessary + if (gsi_is_false(gsiXmlUtilDecodeString(strStart, &strOut->mLen))) + return gsi_false; + + // set the data into strOut + strOut->mData = (const gsi_u8*)strStart; + return gsi_true; + +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Remove '&' markup from the buffer, converts in place +static gsi_bool gsiXmlUtilDecodeString(char * buffer, int * len) +{ + int readPos = 0; + + while(readPos < *len) + { + int charsToRemove = 0; + + // we only want '&' + if (buffer[readPos] != '&') + { + readPos++; + continue; + } + + // check single character switches + if (strncmp(&buffer[readPos], "&", 5)==0) + { + buffer[readPos++] = '&'; + charsToRemove = 5-1; + } + else if (strncmp(&buffer[readPos], """, 6)==0) + { + buffer[readPos++] = '\"'; + charsToRemove = 6-1; + } + else if (strncmp(&buffer[readPos], "'", 6)==0) + { + buffer[readPos++] = '\''; + charsToRemove = 6-1; + } + else if (strncmp(&buffer[readPos], "<", 4)==0) + { + buffer[readPos++] = '<'; + charsToRemove = 4-1; + } + else if (strncmp(&buffer[readPos], ">", 4)==0) + { + buffer[readPos++] = '>'; + charsToRemove = 4-1; + } + else if (strncmp(&buffer[readPos], "&#x", 3)==0) + { + // hex digit + unsigned int digitValue = 0; + //unsigned int digitLength = 0; // 0x00000065 = 1 byte + char ch = ' '; + gsi_bool haveWritten = gsi_false; + int i=0; + unsigned int mask = 0xFF000000; + + char * digitEnd = strchr(&buffer[readPos+3], ';'); + if (digitEnd == NULL) + return gsi_false; // missing ';' + if (digitEnd - &buffer[readPos+3] > 8) + return gsi_false; // too many digits before end + + // scan digits into memory, do this as a block so that ť = 01 65 + sscanf(&buffer[readPos+3], "%08x", &digitValue); + + // write the digit back as a character array + for (i=0; i < 4; i++) + { + ch = (char)((digitValue & mask) >> ((3-i)*8)); // make 0x00006500 into 0x65 + if (haveWritten || ch != 0x00) + { + buffer[readPos++] = ch; + haveWritten = gsi_true; + } + mask = mask >> 8; + } + + // remove everything between the current read position and the semicolon + charsToRemove = digitEnd - &buffer[readPos] + 1; // remove the semicolon + } + else if (strncmp(&buffer[readPos], "&#", 2)==0) + { + // dec digit - like a hex digit, only use atoi instead of sscanf + unsigned int digitValue = 0; + //unsigned int digitLength = 0; // 0x00000065 = 1 byte + char ch = ' '; + gsi_bool haveWritten = gsi_false; + int i=0; + unsigned int mask = 0xFF000000; + + char * digitEnd = strchr(&buffer[readPos+2], ';'); + if (digitEnd == NULL) + return gsi_false; // missing ';' + + // scan digits into memory, do this as a block so that ť = 0165h = 01 65 + digitValue = (unsigned int)atoi(&buffer[readPos+2]); + + // write the digit back as a character array + for (i=0; i < 4; i++) + { + ch = (char)((digitValue & mask) >> ((3-i)*8)); // make 0x00006500 into 0x65 + if (haveWritten || ch != 0x00) + { + buffer[readPos++] = ch; + haveWritten = gsi_true; + } + mask = mask >> 8; + } + + // remove everything between the current read position and the semicolon + charsToRemove = digitEnd - &buffer[readPos] + 1; // remove the semicolon + + } + else + return gsi_false; // unhandle '&' type + + // remove characters by compressing buffer and adding whitespace at the end + // "&&" becomes "&& " after one iteration + memmove(&buffer[readPos], &buffer[readPos+charsToRemove], (size_t)(*len-(readPos+charsToRemove))); + memset(&buffer[*len-charsToRemove], ' ', (size_t)charsToRemove); + (*len) -= charsToRemove; + } + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Parse an entity value. +// Todo: resolving escaped strings? +static gsi_bool gsiXmlUtilParseValue(GSIXmlStreamReader * stream, char * buffer, + int len, int * pos, GSIXmlString * strOut) +{ + char * strStart = NULL; + + GS_ASSERT(stream != NULL); + GS_XML_CHECK(gsiXmlUtilSkipWhiteSpace(stream, buffer, len, pos)); + + if (buffer[*pos] != '<') + { + strStart = &buffer[*pos]; // store this so we can find it later + strOut->mData = (const gsi_u8*)strStart; + } + + while(*pos < len) + { + if (buffer[*pos] == '<') + { + // decode the string if necessary + if (gsi_is_false(gsiXmlUtilDecodeString(strStart, &strOut->mLen))) + return gsi_false; + return gsi_true; // extracted and decoded + } + (*pos)++; + strOut->mLen++; + } + return gsi_false; // EOF before tag end +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteOpenTag(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + if ( gsi_is_false(gsiXmlUtilWriteChar(writer, '<')) || + gsi_is_false(gsiXmlUtilWriteString(writer, namespaceName)) || + gsi_is_false(gsiXmlUtilWriteChar(writer, ':')) || + gsi_is_false(gsiXmlUtilWriteString(writer, tag)) || + gsi_is_false(gsiXmlUtilWriteChar(writer, '>')) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteCloseTag(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + if ( gsi_is_false(gsiXmlUtilWriteChar(writer, '<')) || + gsi_is_false(gsiXmlUtilWriteChar(writer, '/')) || + gsi_is_false(gsiXmlUtilWriteString(writer, namespaceName)) || + gsi_is_false(gsiXmlUtilWriteChar(writer, ':')) || + gsi_is_false(gsiXmlUtilWriteString(writer, tag)) || + gsi_is_false(gsiXmlUtilWriteChar(writer, '>')) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteStringElement(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag, const char * value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + int i=0; + int len = 0; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(value != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + // Check legal ASCII characters + // 0x9, 0xA, 0xD + // [0x20-0xFF] + len = (int)strlen(value); + for (i=0; i < len; i++) + { + // only check values less than 0x20 + if ((unsigned char)value[i] < 0x20) + { + if ((unsigned char)value[i] != 0x09 + && ((unsigned char)value[i] != 0x0A) + && ((unsigned char)value[i] != 0x0D) + ) + { + // contains illegal (and unencodable) characters. + return gsi_false; + } + } + } + + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteXmlSafeString(writer, value)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Converts unicode to ascii strings for writing to XML writer +gsi_bool gsXmlWriteAsciiStringElement(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag, const gsi_char * value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + int i=0; + int len = 0; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(value != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + // Check legal ASCII characters + // 0x9, 0xA, 0xD + // [0x20-0xFF] + len = (int)_tcslen(value); + for (i=0; i < len; i++) + { + // only check values less than 0x20 + if ((unsigned char)value[i] < 0x20) + { + if ((unsigned char)value[i] != 0x09 + && ((unsigned char)value[i] != 0x0A) + && ((unsigned char)value[i] != 0x0D) + ) + { + // contains illegal (and unencodable) characters. + return gsi_false; + } + } + } + +#ifdef GSI_UNICODE + //if unicode, write as Ascii string, otherwise it is already in Ascii format + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteAsciiString(writer, value)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } +#else + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteXmlSafeString(writer, value)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } +#endif + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteUnicodeStringElement(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag, const unsigned short * value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + int i = 0; + int len = 0; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(value != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + // Check legal UNICODE characters + // 0x9, 0xA, 0xD + // [0x20-0xD7FF] + // [xE000-xFFFD] + // [x10000-x10FFFF] (UTF-16, not supported) + len = gsUnicodeStringLen(value); + for (i=0; i < len; i++) + { + // check values less than 0x20 + if (value[i] < 0x0020) + { + if ((value[i] != 0x0009) && (value[i] != 0x0A) && (value[i] != 0x0D)) + return gsi_false; // contains illegal (and unencodable) characters. + } + else if (value[i] > 0xD7FF && value[i] < 0xE000) + return gsi_false; // contains illegal (and unencodable) characters. + else if (value[i] > 0xFFFD) + return gsi_false; // contains illegal (and unencodable) characters. + } + + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteUnicodeString(writer, value)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteIntElement(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag, gsi_u32 value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + char buf[32]; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + sprintf(buf, "%d", value); + + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteString(writer, buf)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteInt64Element(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag, gsi_i64 value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + char buf[33]; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + gsiInt64ToString(buf, value); + + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteString(writer, buf)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteFloatElement(GSXmlStreamWriter stream, const char * namespaceName, + const char * tag, float value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + char buf[32]; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + sprintf(buf, "%f", value); + + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteString(writer, buf)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// first character of HEX binary is HIGH byte +gsi_bool gsXmlWriteHexBinaryElement(GSXmlStreamWriter stream, const char * namespaceName, const char * tag, const gsi_u8 * data, int len) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + int pos = 0; + int temp = 0; + + char hex[3]; + hex[2] = '\0'; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(data != NULL); + GS_ASSERT(len > 0); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + if (gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag))) + return gsi_false; + + while (pos < len) + { + temp = data[pos]; // sprintf requires an int parameter for %02x operation + sprintf(hex, "%02x", temp); + pos++; + if (gsi_is_false(gsiXmlUtilWriteChar(writer, hex[0]))) + return gsi_false; + if (gsi_is_false(gsiXmlUtilWriteChar(writer, hex[1]))) + return gsi_false; + } + + if (gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag))) + return gsi_false; + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteBase64BinaryElement(GSXmlStreamWriter stream, const char * namespaceName, const char * tag, const gsi_u8 * data, int len) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + B64StreamData streamData; + char b64[5]; + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(data != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + if (gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag))) + return gsi_false; + + B64InitEncodeStream(&streamData, (const char*)data, len, GS_XML_BASE64_ENCODING_TYPE); + while(B64EncodeStream(&streamData, b64)) + { + b64[4] = '\0'; + if (gsi_is_false(gsiXmlUtilWriteString(writer, b64))) + return gsi_false; + } + + if (gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag))) + return gsi_false; + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlWriteDateTimeElement(GSXmlStreamWriter stream, const char * namespaceName, const char * tag, time_t value) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + char timeString[21]; + struct tm *timePtr; + + // convert the time to a string + timePtr = gsiSecondsToDate(&value); + + sprintf(timeString, "%d-%02d-%02dT%02d:%02d:%02dZ", + timePtr->tm_year + 1900, timePtr->tm_mon + 1, timePtr->tm_mday, + timePtr->tm_hour, timePtr->tm_min, timePtr->tm_sec); + + GS_ASSERT(stream != NULL); + GS_ASSERT(namespaceName != NULL); + GS_ASSERT(tag != NULL); + GS_ASSERT(gsi_is_false(writer->mClosed)); + + if ( gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag)) || + gsi_is_false(gsiXmlUtilWriteString(writer, timeString)) || + gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag)) + ) + { + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Must reverse byte order and strip leading zeroes +gsi_bool gsXmlWriteLargeIntElement(GSXmlStreamWriter stream, const char * namespaceName, const char * tag, const struct gsLargeInt_s * lint) +{ + GSIXmlStreamWriter * writer = (GSIXmlStreamWriter*)stream; + int readPos = (int)(lint->mLength - 1); + const l_word *readBuf = (const l_word*)lint->mData; + unsigned int temp; + int i; + char hex[3]; + gsi_bool first = gsi_true; + + if (gsi_is_false(gsXmlWriteOpenTag(stream, namespaceName, tag))) + return gsi_false; + + // skip leading zeroes + while(readPos >= 0 && readBuf[readPos] == 0) + readPos--; + + // dump words + for (; readPos >= 0; readPos--) + { + if(gsi_is_true(first)) + { + for(i = 0 ; i < GS_LARGEINT_DIGIT_SIZE_BYTES ; i++) + { + temp = ((lint->mData[readPos] >> (8 * (GS_LARGEINT_DIGIT_SIZE_BYTES - i - 1))) & 0xFF); + if(temp != 0) + break; + } + first = gsi_false; + } + else + { + i = 0; + } + + // loop through each byte from most to least significant + for (; i < GS_LARGEINT_DIGIT_SIZE_BYTES; i++) + { + temp = ((lint->mData[readPos] >> (8 * (GS_LARGEINT_DIGIT_SIZE_BYTES - i - 1))) & 0xFF); + sprintf(hex, "%02x", temp); + if (gsi_is_false(gsiXmlUtilWriteChar(writer, hex[0]))) + return gsi_false; + if (gsi_is_false(gsiXmlUtilWriteChar(writer, hex[1]))) + return gsi_false; + } + } + + if (gsi_is_false(gsXmlWriteCloseTag(stream, namespaceName, tag))) + return gsi_false; + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilWriteChar(GSIXmlStreamWriter * stream, char ch) +{ + GS_ASSERT(gsi_is_false(stream->mClosed)); + + if (stream->mLen >= stream->mCapacity) + { + if (gsi_is_false(gsiXmlUtilGrowBuffer(stream))) + return gsi_false; // OOM + } + stream->mBuffer[stream->mLen] = ch; + stream->mLen++; + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilWriteString(GSIXmlStreamWriter * stream, const char * str) +{ + int strLen = 0; + + GS_ASSERT(str != NULL); + GS_ASSERT(gsi_is_false(stream->mClosed)); + + // get URL encoded length + strLen = (int)strlen(str); + if (strLen == 0) + return gsi_true; + + // grow the buffer if necessary + while ((stream->mCapacity - stream->mLen) <= strLen) + { + if (gsi_is_false(gsiXmlUtilGrowBuffer(stream))) + return gsi_false; // OOM + } + + strcpy(&stream->mBuffer[stream->mLen], str); + stream->mLen += strLen; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef GSI_UNICODE +static gsi_bool gsiXmlUtilWriteAsciiString(GSIXmlStreamWriter * stream, const gsi_char * str) +{ + int strLen = 0; + + GS_ASSERT(str != NULL); + GS_ASSERT(gsi_is_false(stream->mClosed)); + + // get URL encoded length + strLen = (int)_tcslen(str); + if (strLen == 0) + return gsi_true; + + // grow the buffer if necessary + while ((stream->mCapacity - stream->mLen) <= strLen) + { + if (gsi_is_false(gsiXmlUtilGrowBuffer(stream))) + return gsi_false; // OOM + } + + UCS2ToAsciiString(str, &stream->mBuffer[stream->mLen]); + stream->mLen += strLen; + return gsi_true; +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilWriteUnicodeString(GSIXmlStreamWriter * stream, const unsigned short * str) +{ + int strLen = 0; + int pos = 0; + int utf8Len = 0; + char utf8String[4] = { '\0' }; + //gsi_bool result = gsi_false; + + GS_ASSERT(str != NULL); + GS_ASSERT(gsi_is_false(stream->mClosed)); + + strLen = gsUnicodeStringLen(str); + utf8String[3] = '\0'; + + for (pos = 0; pos < strLen; pos++) + { + utf8Len = _UCS2CharToUTF8String(str[pos], utf8String); + utf8String[utf8Len] = '\0'; // null terminate it + if (gsi_is_false(gsiXmlUtilWriteXmlSafeString(stream, utf8String))) + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilWriteXmlSafeString(GSIXmlStreamWriter * stream, const char * str) +{ + int strLen = 0; + int pos = 0; + gsi_bool result = gsi_false; + + GS_ASSERT(str != NULL); + GS_ASSERT(gsi_is_false(stream->mClosed)); + + strLen = (int)strlen(str); + + for (pos = 0; pos < strLen; pos++) + { + if (str[pos] == '&') + result = gsiXmlUtilWriteString(stream, "&"); + else if (str[pos] == '\'') + result = gsiXmlUtilWriteString(stream, "'"); + else if (str[pos] == '"') + result = gsiXmlUtilWriteString(stream, """); + else if (str[pos] == '<') + result = gsiXmlUtilWriteString(stream, "<"); + else if (str[pos] == '>') + result = gsiXmlUtilWriteString(stream, ">"); + else if (str[pos] == ' ') + result = gsiXmlUtilWriteString(stream, " "); + else if (str[pos] < 0x20 || ((unsigned char)str[pos]) > 0x7F) + { + // write as hex + char numeric[7]; + sprintf(numeric, "&#x%02x;", (unsigned char)str[pos]); + numeric[6] = '\0'; + result = gsiXmlUtilWriteString(stream, numeric); + } + else + result = gsiXmlUtilWriteChar(stream, str[pos]); + + if (gsi_is_false(result)) + return gsi_false; + } + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool gsiXmlUtilGrowBuffer(GSIXmlStreamWriter * stream) +{ + int newCapacity = stream->mCapacity + GS_XML_SOAP_BUFFER_INCREMENT_SIZE; + void* newBuf = NULL; + + newBuf = gsirealloc(stream->mBuffer, (size_t)newCapacity); + if (newBuf == NULL) + return gsi_false; + if (newBuf != stream->mBuffer) + stream->mBuffer = (char*)newBuf; + stream->mCapacity = newCapacity; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlMoveToStart(GSXmlStreamReader stream) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + reader->mElemReadIndex = -1; // start BEFORE first element + reader->mValueReadIndex = -1; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Move to next occurance of "matchtag" at any level +gsi_bool gsXmlMoveToNext(GSXmlStreamReader stream, const char * matchtag) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + int i=0; + + for (i=(reader->mElemReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + GSIXmlElement * elem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &elem->mName))) + { + reader->mElemReadIndex = i; + reader->mValueReadIndex = -1; + return gsi_true; + } + } + // no matching element found + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Move up one level in tree +gsi_bool gsXmlMoveToParent(GSXmlStreamReader stream) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + + // check for invalid position + if (reader->mElemReadIndex >= ArrayLength(reader->mElementArray) || + reader->mElemReadIndex == -1) + { + return gsi_false; // current position invalid + } + else + { + GSIXmlElement * elem = (GSIXmlElement*)ArrayNth(reader->mElementArray, reader->mElemReadIndex); + if (elem->mParentIndex == -1) + return gsi_false; // current elem is at highest level + if (elem->mParentIndex >= ArrayLength(reader->mElementArray)) + return gsi_false; // parent is invalid! + reader->mElemReadIndex = elem->mParentIndex; + reader->mValueReadIndex = -1; + return gsi_true; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Move to next unit who shares common parent +gsi_bool gsXmlMoveToSibling (GSXmlStreamReader stream, const char * matchtag) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + int i=0; + + int curElemParent = -1; + GSIXmlElement * searchElem = NULL; + + // If the current element is valid use its parent id + if (reader->mElemReadIndex < ArrayLength(reader->mElementArray)) + { + GSIXmlElement * curElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, reader->mElemReadIndex); + curElemParent = curElem->mParentIndex; + } + else + // otherwise search root elements only + curElemParent = -1; + + for (i=(reader->mElemReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + // if sibling... + if (searchElem->mParentIndex == curElemParent) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchElem->mName))) + { + reader->mElemReadIndex = i; + reader->mValueReadIndex = -1; + return gsi_true; + } + } + // bail if we reach a higher brance + if (searchElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + + // no matching element found + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlMoveToChild(GSXmlStreamReader stream, const char * matchtag) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchElem = NULL; + int i=0; + + for (i=(reader->mElemReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchElem->mName))) + { + reader->mElemReadIndex = i; + reader->mValueReadIndex = -1; + return gsi_true; + } + } + // check if we've reached a higher branch + // -- we know this when we've reached an element whose + // parent is above our level in the tree + if (searchElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsString(GSXmlStreamReader stream, const char * matchtag, + const char ** valueOut, int * lenOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + reader->mValueReadIndex = i; + *valueOut = (const char*)searchValueElem->mValue.mData; + *lenOut = searchValueElem->mValue.mLen; + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/* +gsi_bool gsXmlReadChildAsUnicodeString(GSXmlStreamReader stream, const char * matchtag, + gsi_char ** valueOut, int * lenOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + reader->mValueReadIndex = i; + if (searchValueElem->mValue.mData == NULL) + { + *valueOut = NULL; + *lenOut = 0; + return gsi_true; + } + *lenOut = UTF8ToUCS2StringLen((const char *)searchValueElem->mValue.mData, (unsigned short *) *valueOut, searchValueElem->mValue.mLen); + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +}*/ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Same as read child as string, but copies into valueOut and null terminates +gsi_bool gsXmlReadChildAsStringNT(GSXmlStreamReader stream, const char * matchtag, char valueOut[], int maxLen) +{ + const char * strValue = NULL; + int strLen = 0; + + if (gsi_is_false(gsXmlReadChildAsString(stream, matchtag, &strValue, &strLen))) + { + valueOut[0] = '\0'; + return gsi_false; + } + else + { + strncpy(valueOut, strValue, (size_t)min(maxLen, strLen)); + valueOut[min(maxLen-1, strLen)] = '\0'; + return gsi_true; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Same as readChildAsStringNT, but converts Ascii/UTF-8 to USC2 +gsi_bool gsXmlReadChildAsUnicodeStringNT(GSXmlStreamReader stream, const char * matchtag, gsi_char valueOut[], int maxLen) +{ + const char * utf8Value = NULL; + int unicodeLen = 0; + int utf8Len = 0; + + if (gsi_is_false(gsXmlReadChildAsString(stream, matchtag, &utf8Value, &utf8Len))) + { + valueOut[0] = '\0'; + return gsi_false; + } + else + { + // Convert into destination buffer + unicodeLen = UTF8ToUCS2StringLen(utf8Value, (unsigned short *)valueOut, utf8Len); + valueOut[min(maxLen-1, unicodeLen)] = '\0'; + return gsi_true; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsHexBinary(GSXmlStreamReader stream, const char * matchtag, + gsi_u8 valueOut[], int maxLen, int * lenOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + // switch endianess, e.g. first character in hexstring is HI byte + gsi_u32 temp = 0; + int writepos = 0; + int readpos = 0; + int bytesleft = min(maxLen*2, searchValueElem->mValue.mLen); + + // special case: zero length value + if (searchValueElem->mValue.mLen == 0 || searchValueElem->mValue.mData == NULL) + { + valueOut[0] = 0; + *lenOut = 0; + return gsi_true; + } + + // Checking length only? + if (valueOut == NULL) + { + *lenOut = searchValueElem->mValue.mLen / 2; + + // note: read position left at this elemtent so next read can record the data + return gsi_true; + } + + // 2 characters of hexbyte = 1 value byte + while(bytesleft > 1) + { + sscanf((char*)(&searchValueElem->mValue.mData[readpos]), "%02x", &temp); // sscanf requires a 4 byte dest + valueOut[writepos] = (gsi_u8)temp; // then we convert to byte, to ensure correct byte order + readpos += 2; + writepos += 1; + bytesleft -= 2; + } + if (bytesleft == 1) + { + sscanf((char*)(&searchValueElem->mValue.mData[readpos]), "%01x", &temp); // sscanf requires a 4 byte dest + valueOut[writepos] = (gsi_u8)temp; // then we convert to byte, to ensure correct byte order + readpos += 1; + writepos += 1; + bytesleft -= 1; + } + if (lenOut != NULL) + *lenOut = writepos; + + reader->mValueReadIndex = i; // mark that this element was read + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsBase64Binary(GSXmlStreamReader stream, const char * matchtag, gsi_u8 valueOut[], int * lenOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + if(valueOut) + { + reader->mValueReadIndex = i; + if(searchValueElem->mValue.mData) + B64Decode((char*)searchValueElem->mValue.mData, (char*)valueOut, searchValueElem->mValue.mLen, lenOut, GS_XML_BASE64_ENCODING_TYPE); + else + *lenOut = 0; + } + else + { + if(searchValueElem->mValue.mData) + *lenOut = B64DecodeLen((const char*)searchValueElem->mValue.mData, GS_XML_BASE64_ENCODING_TYPE); + else + *lenOut = 0; + } + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsInt (GSXmlStreamReader stream, const char * matchtag, + int * valueOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + reader->mValueReadIndex = i; + if (searchValueElem->mValue.mData == NULL) + return gsi_false; // invalid type! + *valueOut = atoi((const char*)searchValueElem->mValue.mData); + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsInt64(GSXmlStreamReader stream, const char * matchtag, + gsi_i64 * valueOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + reader->mValueReadIndex = i; + if (searchValueElem->mValue.mData == NULL) + return gsi_false; // invalid type! + *valueOut = gsiStringToInt64((const char*)searchValueElem->mValue.mData); + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsDateTimeElement (GSXmlStreamReader stream, const char * matchtag, + time_t * valueOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + struct tm timePtr; + + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + reader->mValueReadIndex = i; + if (searchValueElem->mValue.mData == NULL) + return gsi_false; // invalid type! + + // convert the time to from a string to a time struct + sscanf((const char*)searchValueElem->mValue.mData, "%i-%02d-%02dT%02d:%02d:%02d", + &timePtr.tm_year, &timePtr.tm_mon, &timePtr.tm_mday, + &timePtr.tm_hour, &timePtr.tm_min, &timePtr.tm_sec); + + timePtr.tm_year -= 1900; + timePtr.tm_mon -= 1; + timePtr.tm_isdst = -1; + *valueOut = gsiDateToSeconds(&timePtr); + + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool gsXmlReadChildAsFloat (GSXmlStreamReader stream, const char * matchtag, + float * valueOut) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchValueElem = NULL; + int i=0; + + // Do we have a valid value position already? + if (reader->mValueReadIndex == -1) + reader->mValueReadIndex = reader->mElemReadIndex; // start at current element + + for (i=(reader->mValueReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchValueElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchValueElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if (gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchValueElem->mName))) + { + reader->mValueReadIndex = i; + if (searchValueElem->mValue.mData == NULL) + return gsi_false; // invalid type! + *valueOut = (float)atof((const char*)searchValueElem->mValue.mData); + return gsi_true; + } + } + // bail if we've reached a higher branch + if (searchValueElem->mParentIndex < reader->mElemReadIndex) + return gsi_false; + } + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Compare only the text following the namespace character +static gsi_bool gsiXmlUtilTagMatches(const char * matchtag, GSIXmlString * xmlstr) +{ + const char * matchNoNamespace = NULL; + GSIXmlString xmlNoNamespace; + int xmlNamespacePos=0; + + GS_ASSERT(xmlstr != NULL); + + if (matchtag == NULL) + return gsi_true; + if (matchtag[strlen(matchtag)-1] == ':') + return gsi_false; // illegal to end with ':' + + // find post-namespace positions + matchNoNamespace = strchr(matchtag, ':'); + if (matchNoNamespace == NULL) + matchNoNamespace = matchtag; + + while(xmlNamespacePos < xmlstr->mLen && xmlstr->mData[xmlNamespacePos] != ':') + xmlNamespacePos++; + if (xmlNamespacePos == xmlstr->mLen) + xmlNamespacePos=0; + else + xmlNamespacePos++; // add one more to skip over the ':' + xmlNoNamespace.mData = xmlstr->mData + xmlNamespacePos; + xmlNoNamespace.mLen = xmlstr->mLen - xmlNamespacePos; + + // compare strings + if (0 == strncmp(matchNoNamespace, (const char*)xmlNoNamespace.mData, (size_t)xmlNoNamespace.mLen)) + return gsi_true; + else + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Reads childs as bin-endian hexbinary, then converts to little-endian large int +gsi_bool gsXmlReadChildAsLargeInt(GSXmlStreamReader stream, const char * matchtag, struct gsLargeInt_s * valueOut) +{ + int len = 0; + + // set to zero + memset(valueOut, 0, sizeof(struct gsLargeInt_s)); + + // parse the hexbinary + if (gsi_is_false(gsXmlReadChildAsHexBinary(stream, matchtag, (gsi_u8*)valueOut->mData, GS_LARGEINT_BINARY_SIZE/8*2, &len))) + return gsi_false; + + // save off length + valueOut->mLength = (l_word)(len/GS_LARGEINT_DIGIT_SIZE_BYTES); + if (len%GS_LARGEINT_DIGIT_SIZE_BYTES != 0) + valueOut->mLength++; + + // reverse byte order + if (gsi_is_false(gsLargeIntReverseBytes(valueOut))) + return gsi_false; + else + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Resets the child read position to the first child of the current element +// +gsi_bool gsXmlResetChildReadPosition(GSXmlStreamReader stream) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + reader->mValueReadIndex = -1; // no current child position means start at first + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Count the number of children with the tag +// If the tag is NULL, count all the children +// Only counts direct children, not grandchildren or lower +int gsXmlCountChildren(GSXmlStreamReader stream, const char * matchtag) +{ + GSIXmlStreamReader * reader = (GSIXmlStreamReader*)stream; + GSIXmlElement * searchElem = NULL; + int i=0; + int count=0; + + for (i=(reader->mElemReadIndex+1); i < ArrayLength(reader->mElementArray); i++) + { + searchElem = (GSIXmlElement*)ArrayNth(reader->mElementArray, i); + if (searchElem->mParentIndex == reader->mElemReadIndex) + { + // check match + if ((matchtag == NULL) || gsi_is_true(gsiXmlUtilTagMatches(matchtag, &searchElem->mName))) + { + count++; + } + } + // check if we've reached a higher branch + // -- we know this when we've reached an element whose + // parent is above our level in the tree + else if (searchElem->mParentIndex < reader->mElemReadIndex) + break; + } + return count; +} + + + diff --git a/xrGameSpy/gamespy/common/gsXML.h b/xrGameSpy/gamespy/common/gsXML.h new file mode 100644 index 00000000000..6f9a0c72271 --- /dev/null +++ b/xrGameSpy/gamespy/common/gsXML.h @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GSXML_H__ +#define __GSXML_H__ + + +#include "gsPlatform.h" +#include "gsLargeInt.h" // so that it can write large ints + + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// GameSpy XML parser for soap messages +// Create the stream object and attach to an XML text buffer. +// The stream will not modify the buffer. +// The buffer should not be released until after the stream is destroyed +// +// +// Limitations: +// Processing instructions other than ' + +#define _REENTRANT + +#define PTHREAD_NO_ERROR 0 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// These functions are unsupported in the current version of the SDK + +gsi_u32 gsiInterlockedIncrement(gsi_u32 * value) +{ + GS_ASSERT_STR(gsi_false, "gsiInterlockIncrement is unsupported for LINUX in the current version of the SDK\n"); + return 1; +} + +gsi_u32 gsiInterlockedDecrement(gsi_u32 * value) +{ + GS_ASSERT_STR(gsi_false, "gsiInterlockIncrement is unsupported for LINUX in the current version of the SDK\n"); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID * id) +{ + pthread_attr_init(&id->attr); + pthread_attr_setstacksize(&id->attr, theStackSize); + + if (pthread_create(&id->thread, &id->attr, (void *)func, arg) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create thread\r\n"); + return -1; + } + + return 0; +} + +void gsiCancelThread(GSIThreadID id) +{ + //should i destroy the attributes here? + pthread_attr_destroy(&id.attr); + + if (pthread_cancel(id.thread) != PTHREAD_NO_ERROR) { + //there was an error - how should we handle these? or should we? + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to cancel thread\r\n"); + } + //free up memory and set to NULL + + gsifree(&id.thread); +} + +// This must be called from INSIDE the thread you wish to exit +void gsiExitThread(GSIThreadID id) +{ + // detach the thread so that it knows to free resources upon exit + pthread_detach(id.thread); + + // exit thread to free up resources + pthread_exit(NULL); +} + +void gsiCleanupThread(GSIThreadID id) +{ + // destroy any leftover attributes associated with the thread + pthread_attr_destroy(&id.attr); +} + +gsi_u32 gsiHasThreadShutdown(GSIThreadID id) +{ + // pthreads lacks detection mechanism for this + GSI_UNUSED(id); + return 1; +} + +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_init(theCrit, NULL) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to initialize critical section\r\n"); + } +} + +void gsiEnterCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_lock(theCrit) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to lock mutex for entering critical section\r\n"); + } +} + +void gsiLeaveCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_unlock(theCrit) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to unlock mutex for leaving critical section\r\n"); + } +} + +void gsiDeleteCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_destroy(theCrit) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to destroy mutex\r\n"); + } + theCrit = NULL; +} + +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + int result; + GSISemaphoreID semaphore; + + //we can use the default attributes for the mutex by passing NULL + result = pthread_mutex_init(&semaphore.mLock, NULL); + + if (result != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create semaphore\r\n"); + } + + semaphore.mValue = theInitialCount; + semaphore.mMax = theMaxCount; + + GSI_UNUSED(theName); + return semaphore; +} + +// Waits for -- and signals -- the semaphore +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + gsi_time startTime = current_time(); + gsi_bool infinite = (theTimeoutMs == GSI_INFINITE)?gsi_true:gsi_false; + + do + { + //try to lock, if it doesn't then its busy + if(pthread_mutex_trylock(&theSemaphore.mLock) == PTHREAD_NO_ERROR) + { + if(theSemaphore.mValue > 0) + { + theSemaphore.mValue--; + pthread_mutex_unlock(&theSemaphore.mLock); + return 1; + } + + pthread_mutex_unlock(&theSemaphore.mLock); + } + + if(theTimeoutMs != 0) + msleep(2); + + } while(gsi_is_true(infinite) || ((current_time() - startTime) < theTimeoutMs)); + + return 0; +} + +// Allow other objects to access the semaphore +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + if(pthread_mutex_trylock(&theSemaphore.mLock) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to lock semaphore\r\n"); + + GSI_UNUSED(theReleaseCount); + } + else + { + theSemaphore.mValue += theReleaseCount; + if(theSemaphore.mValue > theSemaphore.mMax) + theSemaphore.mValue = theSemaphore.mMax; + + pthread_mutex_unlock(&theSemaphore.mLock); + } +} + +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + if (pthread_mutex_destroy(&theSemaphore.mLock) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to destroy semaphore\r\n"); + GSI_UNUSED(theSemaphore); + } + + //need to free up memory + gsifree(&theSemaphore.mValue); + gsifree(&theSemaphore.mMax); + gsifree(&theSemaphore); +} + + diff --git a/xrGameSpy/gamespy/common/linux/gsUtilLinux.c b/xrGameSpy/gamespy/common/linux/gsUtilLinux.c new file mode 100644 index 00000000000..537b7426eb4 --- /dev/null +++ b/xrGameSpy/gamespy/common/linux/gsUtilLinux.c @@ -0,0 +1,17 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return atoll(theNumberStr); +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%lld", theNumber); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/macosx/MacOSXCommon.c b/xrGameSpy/gamespy/common/macosx/MacOSXCommon.c new file mode 100644 index 00000000000..d4abb55ef2a --- /dev/null +++ b/xrGameSpy/gamespy/common/macosx/MacOSXCommon.c @@ -0,0 +1,47 @@ +#include "../gsCommon.h" +#include "../gsMemory.h" +#include "../gsDebug.h" + +// sample common entry point +extern int test_main(int argc, char ** argp); + +// Debug output +#ifdef GSI_COMMON_DEBUG +static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + +{ + GSI_UNUSED(theLevel); + { + static char string[256]; + vsprintf(string, theTokenStr, theParamList); + printf(string); + } + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); +} +#endif + +// Common entry point +int main(int argc, char** argp) +{ + int ret = 0; + // set up memanager + //void *heap = (void*)gsiMemManagedInit(); + +#ifdef GSI_COMMON_DEBUG + // Set up debugging + gsSetDebugCallback(DebugCallback); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); +#endif + + ret = test_main(argc, argp); + + //gsiMemManagedClose(heap); + + return ret; +} diff --git a/xrGameSpy/gamespy/common/macosx/Makefile b/xrGameSpy/gamespy/common/macosx/Makefile new file mode 100644 index 00000000000..d39190849b9 --- /dev/null +++ b/xrGameSpy/gamespy/common/macosx/Makefile @@ -0,0 +1,53 @@ +GOA = $(shell pwd)/../.. + +all: + cd '$(GOA)/Chat/chatc/chatmacosx/' ; make clean + cd '$(GOA)/Chat/chatc/chatmacosx/' ; make + cd '$(GOA)/Chat/chatc/chatmacosx/' ; make clean + cd '$(GOA)/Chat/chatc/chatmacosx/' ; make unicode + cd '$(GOA)/gcdkey/gcdkeymacosx/gcdkeyclientmacosx' ; make clean + cd '$(GOA)/gcdkey/gcdkeymacosx/gcdkeyclientmacosx' ; make + cd '$(GOA)/gcdkey/gcdkeymacosx/gcdkeyservermacosx' ; make clean + cd '$(GOA)/gcdkey/gcdkeymacosx/gcdkeyservermacosx' ; make + cd '$(GOA)/ghttp/ghttpc/ghttpmacosx/' ; make clean + cd '$(GOA)/ghttp/ghttpc/ghttpmacosx/' ; make + cd '$(GOA)/ghttp/ghttpc/ghttpmacosx/' ; make clean + cd '$(GOA)/ghttp/ghttpc/ghttpmacosx/' ; make unicode + cd '$(GOA)/GP/gptestc/gpmacosx' ; make clean + cd '$(GOA)/GP/gptestc/gpmacosx' ; make + cd '$(GOA)/GP/gptestc/gpmacosx' ; make clean + cd '$(GOA)/GP/gptestc/gpmacosx' ; make unicode + cd '$(GOA)/gstats/statstest/gstatsmacosx' ; make clean + cd '$(GOA)/gstats/statstest/gstatsmacosx' ; make + cd '$(GOA)/gstats/statstest/gstatsmacosx' ; make clean + cd '$(GOA)/gstats/statstest/gstatsmacosx' ; make unicode + cd '$(GOA)/gstats/persisttest/persistmacosx' ; make clean + cd '$(GOA)/gstats/persisttest/persistmacosx' ; make + cd '$(GOA)/gstats/persisttest/persistmacosx' ; make clean + cd '$(GOA)/gstats/persisttest/persistmacosx' ; make unicode + cd '$(GOA)/gt2/gt2testc/gt2macosx' ; make clean + cd '$(GOA)/gt2/gt2testc/gt2macosx' ; make + cd '$(GOA)/gt2/gt2testc/gt2macosx' ; make clean + cd '$(GOA)/gt2/gt2testc/gt2macosx' ; make unicode + cd '$(GOA)/natneg/simpletest/natnegmacosx' ; make clean + cd '$(GOA)/natneg/simpletest/natnegmacosx' ; make + cd '$(GOA)/Peer/peerc/peermacosx' ; make clean + cd '$(GOA)/Peer/peerc/peermacosx' ; make + cd '$(GOA)/Peer/peerc/peermacosx' ; make clean + cd '$(GOA)/Peer/peerc/peermacosx' ; make unicode + cd '$(GOA)/pt/pttestc/ptmacosx' ; make clean + cd '$(GOA)/pt/pttestc/ptmacosx' ; make + cd '$(GOA)/pt/pttestc/ptmacosx' ; make clean + cd '$(GOA)/pt/pttestc/ptmacosx' ; make unicode + cd '$(GOA)/qr2/qr2csample/qr2macosx' ; make clean + cd '$(GOA)/qr2/qr2csample/qr2macosx' ; make + cd '$(GOA)/qr2/qr2csample/qr2macosx' ; make clean + cd '$(GOA)/qr2/qr2csample/qr2macosx' ; make unicode + cd '$(GOA)/serverbrowsing/sbctest/sbmacosx' ; make clean + cd '$(GOA)/serverbrowsing/sbctest/sbmacosx' ; make + cd '$(GOA)/serverbrowsing/sbctest/sbmacosx' ; make clean + cd '$(GOA)/serverbrowsing/sbctest/sbmacosx' ; make unicode + cd '$(GOA)/Voice2/Voice2Test/gvmacosx' ; make clean + cd '$(GOA)/Voice2/Voice2Test/gvmacosx' ; make + cd '$(GOA)/Voice2/voice2bench/voice2benchmacosx' ; make clean + cd '$(GOA)/Voice2/voice2bench/voice2benchmacosx' ; make diff --git a/xrGameSpy/gamespy/common/macosx/Makefile.common b/xrGameSpy/gamespy/common/macosx/Makefile.common new file mode 100644 index 00000000000..3595117c2e8 --- /dev/null +++ b/xrGameSpy/gamespy/common/macosx/Makefile.common @@ -0,0 +1,33 @@ +# OSX Common Makefile +# Copyright 2006 GameSpy Industries + +CC=cc +BASE_CFLAGS=$(DEFINES) $(INCLUDES) -I../ -I../.. + +unicode: UNICODE_CFLAGS = -DGSI_UNICODE -fshort-wchar + +CFLAGS=$(BASE_CFLAGS) $(UNICODE_CFLAGS) -D_MACOSX -DGSI_COMMON_DEBUG -D_NO_NOPORT_H_ -g -O0 -Wall -Werror + +#optimization flags +#CFLAGS=$(BASE_CFLAGS) $(UNICODE_CFLAGS) -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -lpthreads + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) $(LIBS) + +############################################################################# +# MISC +############################################################################# + +unicode: $(PROJECT) + +clean: + rm -f $(PROG_OBJS) + +depend: + $(CC) -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/common/macosx/changelog.txt b/xrGameSpy/gamespy/common/macosx/changelog.txt new file mode 100644 index 00000000000..132e9c76fee --- /dev/null +++ b/xrGameSpy/gamespy/common/macosx/changelog.txt @@ -0,0 +1,15 @@ +Changelog for: MacOSX Common Code +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +06-03-2005 1.00.03 SN RELEASE Releasing to developer site. +04-28-2005 1.00.03 SN RELEASE Releasing to developer site. +04-04-2005 1.00.03 SN RELEASE Releasing to developer site. +09-30-2004 1.00.03 DES FEATURE Makefile.common can now include defines set in SDK Makefiles. + DES FEATURE Added optional optimization flags to Makefile.common. +09-16-2004 1.00.02 SN RELEASE Releasing to developer site. +08-27-2004 1.00.02 DES FEATURE Makefile also builds unicode versions (where applicable) + DES FEATURE Added a Makefile.common that us used by all other OSX makefiles +08-25-2004 1.00.01 DES FEATURE Added a makefile to build all the test apps on MacOS X. +08-24-2004 1.00.00 DES OTHER Changelog started diff --git a/xrGameSpy/gamespy/common/macosx/gsThreadMacOSX.c b/xrGameSpy/gamespy/common/macosx/gsThreadMacOSX.c new file mode 100644 index 00000000000..e0522a5b60f --- /dev/null +++ b/xrGameSpy/gamespy/common/macosx/gsThreadMacOSX.c @@ -0,0 +1,213 @@ +// +// Mac OSX Threading Support (pthreads) +// *same as Linux* +// +// NOTE: when implementing this make sure the "-lpthread" compiler option is used +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsPlatformUtil.h" +#include "../gsPlatformThread.h" +#include "../gsAssert.h" +#include "../gsDebug.h" +#include + +#define _REENTRANT + +#define PTHREAD_NO_ERROR 0 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// These functions are unsupported in the current version of the SDK + +gsi_u32 gsiInterlockedIncrement(gsi_u32 * value) +{ + GS_ASSERT_STR(gsi_false, "gsiInterlockIncrement is unsupported for Mac OSX in the current version of the SDK\n"); + return 1; +} + +gsi_u32 gsiInterlockedDecrement(gsi_u32 * value) +{ + GS_ASSERT_STR(gsi_false, "gsiInterlockIncrement is unsupported for Mac OSX in the current version of the SDK\n"); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID * id) +{ + pthread_attr_init(&id->attr); + pthread_attr_setstacksize(&id->attr, theStackSize); + + if (pthread_create(&id->thread, &id->attr, (void *)func, arg) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create thread\r\n"); + return -1; + } + + return 0; +} + +void gsiCancelThread(GSIThreadID id) +{ + //should i destroy the attributes here? + pthread_attr_destroy(&id.attr); + + if (pthread_cancel(id.thread) != PTHREAD_NO_ERROR) { + //there was an error - how should we handle these? or should we? + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to cancel thread\r\n"); + } + //free up memory and set to NULL + + gsifree(&id.thread); +} + +// This must be called from INSIDE the thread you wish to exit +void gsiExitThread(GSIThreadID id) +{ + // detach the thread so that it knows to free resources upon exit + pthread_detach(id.thread); + + // exit thread to free up resources + pthread_exit(NULL); +} + +void gsiCleanupThread(GSIThreadID id) +{ + // destroy any leftover attributes associated with the thread + pthread_attr_destroy(&id.attr); +} + +gsi_u32 gsiHasThreadShutdown(GSIThreadID id) +{ + // pthreads lacks detection mechanism for this + GSI_UNUSED(id); + return 1; +} + +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_init(theCrit, NULL) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to initialize critical section\r\n"); + } +} + +void gsiEnterCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_lock(theCrit) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to lock mutex for entering critical section\r\n"); + } +} + +void gsiLeaveCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_unlock(theCrit) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to unlock mutex for leaving critical section\r\n"); + } +} + +void gsiDeleteCriticalSection(GSICriticalSection *theCrit) +{ + if (pthread_mutex_destroy(theCrit) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to destroy mutex\r\n"); + } + theCrit = NULL; +} + +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + int result; + GSISemaphoreID semaphore; + + //we can use the default attributes for the mutex by passing NULL + result = pthread_mutex_init(&semaphore.mLock, NULL); + + if (result != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create semaphore\r\n"); + } + + semaphore.mValue = theInitialCount; + semaphore.mMax = theMaxCount; + + GSI_UNUSED(theName); + return semaphore; +} + +// Waits for -- and signals -- the semaphore +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + gsi_time startTime = current_time(); + gsi_bool infinite = (theTimeoutMs == GSI_INFINITE)?gsi_true:gsi_false; + + do + { + //try to lock, if it doesn't then its busy + if(pthread_mutex_trylock(&theSemaphore.mLock) == PTHREAD_NO_ERROR) + { + if(theSemaphore.mValue > 0) + { + theSemaphore.mValue--; + pthread_mutex_unlock(&theSemaphore.mLock); + return 1; + } + + pthread_mutex_unlock(&theSemaphore.mLock); + } + + if(theTimeoutMs != 0) + msleep(2); + + } while(gsi_is_true(infinite) || ((current_time() - startTime) < theTimeoutMs)); + + return 0; +} + +// Allow other objects to access the semaphore +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + if(pthread_mutex_trylock(&theSemaphore.mLock) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to lock semaphore\r\n"); + + GSI_UNUSED(theReleaseCount); + } + else + { + theSemaphore.mValue += theReleaseCount; + if(theSemaphore.mValue > theSemaphore.mMax) + theSemaphore.mValue = theSemaphore.mMax; + + pthread_mutex_unlock(&theSemaphore.mLock); + } +} + +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + if (pthread_mutex_destroy(&theSemaphore.mLock) != PTHREAD_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to destroy semaphore\r\n"); + GSI_UNUSED(theSemaphore); + } + + //need to free up memory + gsifree(&theSemaphore.mValue); + gsifree(&theSemaphore.mMax); + gsifree(&theSemaphore); +} + + diff --git a/xrGameSpy/gamespy/common/macosx/gsUtilMacOSX.c b/xrGameSpy/gamespy/common/macosx/gsUtilMacOSX.c new file mode 100644 index 00000000000..a5e038ccd90 --- /dev/null +++ b/xrGameSpy/gamespy/common/macosx/gsUtilMacOSX.c @@ -0,0 +1,17 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return atoll(theNumberStr); +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%lld", theNumber); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/backup.c b/xrGameSpy/gamespy/common/nitro/backup.c new file mode 100644 index 00000000000..6b5200dc524 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/backup.c @@ -0,0 +1,185 @@ +#include "..\nonport.h" +#include "backup.h" +#include "screen.h" + +//#define SUPPORT_FLASH +//#define SUPPORT_FRAM + +static const CARDBackupType BackupTypes[] = +{ + CARD_BACKUP_TYPE_EEPROM_4KBITS, + CARD_BACKUP_TYPE_EEPROM_64KBITS, + CARD_BACKUP_TYPE_EEPROM_512KBITS, +#if defined(SUPPORT_FLASH) + CARD_BACKUP_TYPE_FLASH_2MBITS, +#endif +#if defined(SUPPORT_FRAM) + CARD_BACKUP_TYPE_FRAM_256KBITS, +#endif +}; +static const char * BackupTypeDescriptions[] = +{ + "EEPROM 4 kb", + "EEPROM 64 kb", + "EEPROM 512 kb", +#if defined(SUPPORT_FLASH) + "FLASH 2 mb", +#endif +#if defined(SUPPORT_FRAM) + "FRAM 256 kb" +#endif +}; +static const int NumBackupTypes = (sizeof(BackupTypes) / sizeof(BackupTypes[0])); +static const CARDBackupType NullBackupType = CARD_BACKUP_TYPE_NOT_USE; + +static CARDBackupType InstalledBackupType; +static int InstalledBackupTypeIndex; + +static u16 LockID; + +static BOOL TestForBackupType(int index) +{ + const CARDBackupType type = BackupTypes[index]; + u32 totalSize; + BOOL result; + u8 buffer; + + Printf("Testing for %s\n", BackupTypeDescriptions[index]); + + CARD_LockBackup(LockID); + { + CARD_IdentifyBackup(type); + + totalSize = CARD_GetBackupTotalSize(); + + // set the buffer + buffer = (u8)(rand() & 0xFF); + + // write the buffer to the card + if(CARD_IsBackupEeprom()) + result = CARD_WriteAndVerifyEeprom(totalSize - 1, &buffer, 1); + else if(CARD_IsBackupFlash()) + result = CARD_WriteAndVerifyFlash(totalSize - 1, &buffer, 1); + else if(CARD_IsBackupFram()) + result = CARD_WriteAndVerifyFram(totalSize - 1, &buffer, 1); + } + CARD_UnlockBackup(LockID); + + return result; +} + +static void DetermineBackupType(void) +{ + int i; + + // determine what, if any, backup type is installed + for(i = 0 ; i < NumBackupTypes ; i++) + { + if(TestForBackupType(i) == TRUE) + { + InstalledBackupType = BackupTypes[i]; + InstalledBackupTypeIndex = i; + return; + } + } + + InstalledBackupType = NullBackupType; + InstalledBackupTypeIndex = -1; +} + +void BackupInit(void) +{ + // get an id for locking the card + s32 lockID = OS_GetLockID(); + if(lockID == OS_LOCK_ID_ERROR) + OS_Panic("OS_GetLockID() failed\n"); + LockID = (u16)lockID; + + // figure out the backup type + DetermineBackupType(); + + // make sure we have the right type identified + if(BackupExists()) + { + CARD_LockBackup(LockID); + { + CARD_IdentifyBackup(InstalledBackupType); + } + CARD_UnlockBackup(LockID); + } + + // show what we detected + if(BackupExists()) + Printf("Backup type: %s\n", BackupTypeDescriptions[InstalledBackupTypeIndex]); + else + Printf("No backup card detected\n"); +} + +BOOL BackupExists(void) +{ + return (InstalledBackupType != NullBackupType)?TRUE:FALSE; +} + +static const int StartPos = 32; + +BOOL WriteToBackup(const void * src, int len) +{ + BOOL result; + + if(!BackupExists()) + return FALSE; + + CARD_LockBackup(LockID); + + if(CARD_IsBackupEeprom()) + result = CARD_WriteAndVerifyEeprom(StartPos, src, (u32)len); + else if(CARD_IsBackupFlash()) + result = CARD_WriteAndVerifyFlash(StartPos, src, (u32)len); + else if(CARD_IsBackupFram()) + result = CARD_WriteAndVerifyFram(StartPos, src, (u32)len); + else + result = FALSE; + + CARD_UnlockBackup(LockID); + + if(result == FALSE) + { + u32 code = CARD_GetResultCode(); + Printf("CARD-WRITE-FAILURE: %d\n", code); + while(1) + ; + } + + return result; +} + +BOOL ReadFromBackup(void * dst, int len) +{ + BOOL result; + + if(!BackupExists()) + return FALSE; + + CARD_LockBackup(LockID); + + if(CARD_IsBackupEeprom()) + result = CARD_ReadEeprom(StartPos, dst, (u32)len); + else if(CARD_IsBackupFlash()) + result = CARD_ReadFlash(StartPos, dst, (u32)len); + else if(CARD_IsBackupFram()) + result = CARD_ReadFram(StartPos, dst, (u32)len); + else + result = FALSE; + + CARD_UnlockBackup(LockID); + + if(result == FALSE) + { + u32 code = CARD_GetResultCode(); + Printf("CARD-READ-FAILURE: %d\n", code); + while(1) + ; + } + + return result; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/backup.h b/xrGameSpy/gamespy/common/nitro/backup.h new file mode 100644 index 00000000000..b5a7854d924 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/backup.h @@ -0,0 +1,11 @@ +#ifndef _BACKUP_H_ +#define _BACKUP_H_ + +void BackupInit(void); + +BOOL BackupExists(void); + +BOOL WriteToBackup(const void * src, int len); +BOOL ReadFromBackup(void * dst, int len); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/changelog.txt b/xrGameSpy/gamespy/common/nitro/changelog.txt new file mode 100644 index 00000000000..fabc5db84ce --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/changelog.txt @@ -0,0 +1,28 @@ +Changelog for: Nitro (Nintendo DS) Common Code +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +05-17-2006 1.00.05 DES UPDATE Updated to use gsTestMain + DES FEATURE Added gmtime and ctime + DES FEATURE Added gsiInterlockedIncrement/Decrement +11-17-2005 1.00.04 DES FIX Updated sample project and common workspace. + DES CLEANUP Now using SOC_ instead of SO_. +09-21-2005 1.00.03 DES FEATURE Added support for more backup types + DES FIX Updated thread support + DES FIX nitrosample now uses the gmtest gamename +06-03-2005 1.00.02 SN RELEASE Releasing to developer site. +04-28-2005 1.00.02 SN RELEASE Releasing to developer site. +04-27-2005 1.00.02 DES RELEASE Limited release to Nintendo DS developers. +04-27-2005 1.00.02 DES CLEANUP The backup code now only checks for flash backup + if SUPPORT_FLASH is defined. + DES FEATURE Cosmetic changes to nitrosample and launcher code. + DES FIX Changed SDK_IRQ_STACKSIZE in nitro.lcf files to 4096. + DES FEATURE printf()'s can now be directed to the screen and/or the debugger. + DES FEATURE Updates to work with the latest NitroInet. + DES FEATURE Added nitrocommon.cww, workspace for CW with all test apps. +04-11-2005 1.00.01 DES CLEANUP Removed 232-bit WEP key, which is no longer supported by Nitro. + DES FEATURE Show a default network config if no backup memory is detected. + DES FIX Fixed bug with showing the failure reason in nitrosample. + DES FIX Fixed bug in handling Peer errors in nitrosample. +04-04-2005 1.00.00 DES OTHER Changelog started diff --git a/xrGameSpy/gamespy/common/nitro/font.c b/xrGameSpy/gamespy/common/nitro/font.c new file mode 100644 index 00000000000..58613576d64 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/font.c @@ -0,0 +1,587 @@ +/*---------------------------------------------------------------------------* + Project: NitroSDK - RTC - demos + File: font.c + + Copyright 2003,2004 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: font.c,v $ + Revision 1.2 2004/11/02 07:19:52 terui + Fixed spelling mistakes in comments. + + Revision 1.1 2004/05/12 02:38:49 terui + initial upload + + $NoKeywords: $ + *---------------------------------------------------------------------------*/ + +#include "font.h" + + +/*---------------------------------------------------------------------------* + Character data + *---------------------------------------------------------------------------*/ +const u32 d_CharData[ 8 * 256 ] = +{ + 0x00000000,0x00000000,0x00000000,0x00000000, // 0000h + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x01010010,0x01010010,0x00000110, // 0001h + 0x00011010,0x01100010,0x00000010,0x00000010, + 0x00000000,0x01011010,0x01010010,0x00010010, // 0002h + 0x00100010,0x00100010,0x00100001,0x00100001, + 0x00000000,0x01010001,0x01010001,0x01111111, // 0003h + 0x00000001,0x00000001,0x00000001,0x01111110, + 0x00000000,0x01010000,0x01111111,0x00100000, // 0004h + 0x00100000,0x00010000,0x00001000,0x00000110, + 0x00000000,0x01010000,0x01010100,0x00001010, // 0005h + 0x00010001,0x00100001,0x01000000,0x00000000, + 0x00000000,0x01011000,0x01011000,0x01111111, // 0006h + 0x00001000,0x00101010,0x01001010,0x01001001, + 0x00000000,0x01010010,0x01101111,0x01010010, // 0007h + 0x00010010,0x00010010,0x00010010,0x00001001, + 0x00000000,0x01010010,0x01011111,0x00000100, // 0008h + 0x00011111,0x00001000,0x00000001,0x00011110, + 0x00000000,0x01010000,0x01011000,0x00000110, // 0009h + 0x00000001,0x00000110,0x00011000,0x00100000, + 0x00000000,0x01010000,0x01111101,0x00010001, // 000ah + 0x00010001,0x00010001,0x00010001,0x00001010, + 0x00000000,0x01010000,0x01011110,0x00100000, // 000bh + 0x00000000,0x00000001,0x00000001,0x00111110, + 0x00000000,0x01010100,0x01011111,0x00001000, // 000ch + 0x00010000,0x00000001,0x00000001,0x00011110, + 0x00000000,0x01010001,0x01010001,0x00000001, // 000dh + 0x01000001,0x01000001,0x00100010,0x00011100, + 0x00000000,0x01010000,0x01111111,0x00011000, // 000eh + 0x00010100,0x00010100,0x00011000,0x00001100, + 0x00000000,0x01010010,0x01111111,0x00010010, // 000fh + 0x00010010,0x00000010,0x00000010,0x00111100, + 0x00000000,0x00001110,0x01010100,0x01010010, // 0010h + 0x00111111,0x00000100,0x00000100,0x00011000, + 0x00000000,0x01010100,0x01011111,0x00000100, // 0011h + 0x01110100,0x00000010,0x00001010,0x01110010, + 0x00000000,0x01010100,0x01011111,0x00000010, // 0012h + 0x00011110,0x00100001,0x00100000,0x00011110, + 0x00000000,0x01010000,0x01011100,0x00100011, // 0013h + 0x01000000,0x01000000,0x00100000,0x00011100, + 0x00000000,0x01010000,0x01111111,0x00010000, // 0014h + 0x00001000,0x00001000,0x00001000,0x00110000, + 0x00000000,0x01010010,0x01010010,0x00001100, // 0015h + 0x00000010,0x00000001,0x00000001,0x00111110, + 0x00000000,0x01010001,0x01111101,0x00010001, // 0016h + 0x00010001,0x00111001,0x01010101,0x00011001, + 0x00000000,0x01010100,0x01010011,0x01110010, // 0017h + 0x00010001,0x00010001,0x00001010,0x00000100, + 0x00000000,0x01011110,0x01011000,0x00000100, // 0018h + 0x00101001,0x01010001,0x01010001,0x00001100, + 0x00000000,0x01010000,0x01011100,0x00010010, // 0019h + 0x00010010,0x00100001,0x01000000,0x00000000, + 0x00000000,0x01011101,0x01010001,0x00111101, // 001ah + 0x00010001,0x00011001,0x00110101,0x00001001, + 0x00000000,0x01110001,0x01011101,0x00110001, // 001bh + 0x00010001,0x00111001,0x01010101,0x00011001, + 0x00000000,0x01110100,0x01010011,0x00110010, // 001ch + 0x00010001,0x00010001,0x00001010,0x00000100, + 0x00000000,0x01101110,0x01011000,0x00100100, // 001dh + 0x00101001,0x01010001,0x01010001,0x00001100, + 0x00000000,0x01110000,0x01011100,0x00110010, // 001eh + 0x00010010,0x00100001,0x01000000,0x00000000, + 0x00000000,0x01111101,0x01010001,0x00111101, // 001fh + 0x00010001,0x00011001,0x00110101,0x00001001, + 0x00000000,0x00000000,0x00000000,0x00000000, // 0020h + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00001000,0x00001000,0x00001000, // 0021h + 0x00001000,0x00001000,0x00000000,0x00001000, + 0x00000000,0x01101100,0x01001000,0x00100100, // 0022h + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00100100,0x01111111,0x00100100, // 0023h + 0x00100100,0x01111111,0x00010010,0x00010010, + 0x00000000,0x00001000,0x01111110,0x00001001, // 0024h + 0x00111110,0x01001000,0x00111111,0x00001000, + 0x00000000,0x01000010,0x00100101,0x00010010, // 0025h + 0x00001000,0x00100100,0x01010010,0x00100001, + 0x00000000,0x00001110,0x00010001,0x00001001, // 0026h + 0x01000110,0x00101001,0x00110001,0x01001110, + 0x00000000,0x00011000,0x00010000,0x00001000, // 0027h + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x01110000,0x00001000,0x00000100, // 0028h + 0x00000100,0x00000100,0x00001000,0x01110000, + 0x00000000,0x00000111,0x00001000,0x00010000, // 0029h + 0x00010000,0x00010000,0x00001000,0x00000111, + 0x00000000,0x00001000,0x01001001,0x00101010, // 002ah + 0x00011100,0x00101010,0x01001001,0x00001000, + 0x00000000,0x00001000,0x00001000,0x00001000, // 002bh + 0x01111111,0x00001000,0x00001000,0x00001000, + 0x00000000,0x00000000,0x00000000,0x00000000, // 002ch + 0x00000000,0x00001100,0x00001000,0x00000100, + 0x00000000,0x00000000,0x00000000,0x00000000, // 002dh + 0x01111111,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, // 002eh + 0x00000000,0x00000000,0x00000000,0x00001100, + 0x00000000,0x01000000,0x00100000,0x00010000, // 002fh + 0x00001000,0x00000100,0x00000010,0x00000001, + 0x00000000,0x00111110,0x01000001,0x01000001, // 0030h + 0x01000001,0x01000001,0x01000001,0x00111110, + 0x00000000,0x00011100,0x00010000,0x00010000, // 0031h + 0x00010000,0x00010000,0x00010000,0x00010000, + 0x00000000,0x00111110,0x01000001,0x01000000, // 0032h + 0x00111110,0x00000001,0x00000001,0x01111111, + 0x00000000,0x00111110,0x01000001,0x01000000, // 0033h + 0x00111110,0x01000000,0x01000001,0x00111110, + 0x00000000,0x00100000,0x00110000,0x00101000, // 0034h + 0x00100100,0x00100010,0x01111111,0x00100000, + 0x00000000,0x01111111,0x00000001,0x00111111, // 0035h + 0x01000000,0x01000000,0x01000001,0x00111110, + 0x00000000,0x00111110,0x00000001,0x00111111, // 0036h + 0x01000001,0x01000001,0x01000001,0x00111110, + 0x00000000,0x01111111,0x00100000,0x00100000, // 0037h + 0x00010000,0x00010000,0x00001000,0x00001000, + 0x00000000,0x00111110,0x01000001,0x01000001, // 0038h + 0x00111110,0x01000001,0x01000001,0x00111110, + 0x00000000,0x00111110,0x01000001,0x01000001, // 0039h + 0x01000001,0x01111110,0x01000000,0x00111110, + 0x00000000,0x00000000,0x00001100,0x00000000, // 003ah + 0x00000000,0x00000000,0x00001100,0x00000000, + 0x00000000,0x00000000,0x00001100,0x00000000, // 003bh + 0x00000000,0x00001100,0x00001000,0x00000100, + 0x00000000,0x01100000,0x00011000,0x00000110, // 003ch + 0x00000001,0x00000110,0x00011000,0x01100000, + 0x00000000,0x00000000,0x01111111,0x00000000, // 003dh + 0x00000000,0x00000000,0x01111111,0x00000000, + 0x00000000,0x00000011,0x00001100,0x00110000, // 003eh + 0x01000000,0x00110000,0x00001100,0x00000011, + 0x00000000,0x00111110,0x01000001,0x01000001, // 003fh + 0x00110000,0x00001000,0x00000000,0x00001000, + 0x00000000,0x00011100,0x00100010,0x01001001, // 0040h + 0x01010101,0x01010101,0x01010101,0x00111010, + 0x00000000,0x00001000,0x00010100,0x00010100, // 0041h + 0x00100010,0x00111110,0x01000001,0x01000001, + 0x00000000,0x00111111,0x01000001,0x01000001, // 0042h + 0x00111111,0x01000001,0x01000001,0x00111111, + 0x00000000,0x00111100,0x01000010,0x00000001, // 0043h + 0x00000001,0x00000001,0x01000010,0x00111100, + 0x00000000,0x00011111,0x00100001,0x01000001, // 0044h + 0x01000001,0x01000001,0x00100001,0x00011111, + 0x00000000,0x01111111,0x00000001,0x00000001, // 0045h + 0x01111111,0x00000001,0x00000001,0x01111111, + 0x00000000,0x01111111,0x00000001,0x00000001, // 0046h + 0x00111111,0x00000001,0x00000001,0x00000001, + 0x00000000,0x00111100,0x01000010,0x00000001, // 0047h + 0x01111001,0x01000001,0x01000010,0x00111100, + 0x00000000,0x01000001,0x01000001,0x01000001, // 0048h + 0x01111111,0x01000001,0x01000001,0x01000001, + 0x00000000,0x00111110,0x00001000,0x00001000, // 0049h + 0x00001000,0x00001000,0x00001000,0x00111110, + 0x00000000,0x01000000,0x01000000,0x01000000, // 004ah + 0x01000001,0x01000001,0x00100010,0x00011100, + 0x00000000,0x01100001,0x00011001,0x00000101, // 004bh + 0x00000011,0x00000101,0x00011001,0x01100001, + 0x00000000,0x00000001,0x00000001,0x00000001, // 004ch + 0x00000001,0x00000001,0x00000001,0x01111111, + 0x00000000,0x01000001,0x01100011,0x01010101, // 004dh + 0x01001001,0x01000001,0x01000001,0x01000001, + 0x00000000,0x01000001,0x01000011,0x01000101, // 004eh + 0x01001001,0x01010001,0x01100001,0x01000001, + 0x00000000,0x00011100,0x00100010,0x01000001, // 004fh + 0x01000001,0x01000001,0x00100010,0x00011100, + 0x00000000,0x00111111,0x01000001,0x01000001, // 0050h + 0x00111111,0x00000001,0x00000001,0x00000001, + 0x00000000,0x00011100,0x00100010,0x01000001, // 0051h + 0x01000001,0x01011001,0x00100010,0x01011100, + 0x00000000,0x00111111,0x01000001,0x01000001, // 0052h + 0x00111111,0x01000001,0x01000001,0x01000001, + 0x00000000,0x00111110,0x01000001,0x00000001, // 0053h + 0x00111110,0x01000000,0x01000001,0x00111110, + 0x00000000,0x01111111,0x00001000,0x00001000, // 0054h + 0x00001000,0x00001000,0x00001000,0x00001000, + 0x00000000,0x01000001,0x01000001,0x01000001, // 0055h + 0x01000001,0x01000001,0x00100010,0x00011100, + 0x00000000,0x01000001,0x01000001,0x00100010, // 0056h + 0x00100010,0x00010100,0x00010100,0x00001000, + 0x00000000,0x01000001,0x01000001,0x01000001, // 0057h + 0x01001001,0x01010101,0x01100011,0x01000001, + 0x00000000,0x01000001,0x00100010,0x00010100, // 0058h + 0x00001000,0x00010100,0x00100010,0x01000001, + 0x00000000,0x01000001,0x00100010,0x00010100, // 0059h + 0x00001000,0x00001000,0x00001000,0x00001000, + 0x00000000,0x01111111,0x00100000,0x00010000, // 005ah + 0x00001000,0x00000100,0x00000010,0x01111111, + 0x00000000,0x01111100,0x00000100,0x00000100, // 005bh + 0x00000100,0x00000100,0x00000100,0x01111100, + 0x00000000,0x00100010,0x00010100,0x00111110, // 005ch + 0x00001000,0x00111110,0x00001000,0x00001000, + 0x00000000,0x00011111,0x00010000,0x00010000, // 005dh + 0x00010000,0x00010000,0x00010000,0x00011111, + 0x00000000,0x00001000,0x00010100,0x00100010, // 005eh + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, // 005fh + 0x00000000,0x00000000,0x00000000,0x01111111, + 0x00000000,0x00010000,0x00001000,0x00011000, // 0060h + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00011110,0x00100001, // 0061h + 0x00111110,0x00100001,0x00100001,0x01011110, + 0x00000000,0x00000001,0x00000001,0x00111111, // 0062h + 0x01000001,0x01000001,0x01000001,0x00111111, + 0x00000000,0x00000000,0x00111100,0x01000010, // 0063h + 0x00000001,0x00000001,0x01000010,0x00111100, + 0x00000000,0x01000000,0x01000000,0x01111110, // 0064h + 0x01000001,0x01000001,0x01000001,0x01111110, + 0x00000000,0x00000000,0x00111110,0x01000001, // 0065h + 0x01111111,0x00000001,0x01000001,0x00111110, + 0x00000000,0x00110000,0x00001000,0x00001000, // 0066h + 0x01111111,0x00001000,0x00001000,0x00001000, + 0x00000000,0x00000000,0x01111110,0x01000001, // 0067h + 0x01000001,0x01111110,0x01000000,0x00111110, + 0x00000000,0x00000001,0x00000001,0x00000001, // 0068h + 0x00111111,0x01000001,0x01000001,0x01000001, + 0x00000000,0x00001000,0x00000000,0x00001000, // 0069h + 0x00001000,0x00001000,0x00001000,0x00001000, + 0x00000000,0x00100000,0x00000000,0x00100000, // 006ah + 0x00100000,0x00100001,0x00100001,0x00011110, + 0x00000000,0x00000001,0x00000001,0x01100001, // 006bh + 0x00011001,0x00000111,0x00011001,0x01100001, + 0x00000000,0x00001000,0x00001000,0x00001000, // 006ch + 0x00001000,0x00001000,0x00001000,0x00001000, + 0x00000000,0x00000000,0x00110111,0x01001001, // 006dh + 0x01001001,0x01001001,0x01001001,0x01001001, + 0x00000000,0x00000000,0x00111111,0x01000001, // 006eh + 0x01000001,0x01000001,0x01000001,0x01000001, + 0x00000000,0x00000000,0x00011100,0x00100010, // 006fh + 0x01000001,0x01000001,0x00100010,0x00011100, + 0x00000000,0x00000000,0x00111101,0x01000011, // 0070h + 0x01000001,0x01000011,0x00111101,0x00000001, + 0x00000000,0x00000000,0x01011110,0x01100001, // 0071h + 0x01000001,0x01100001,0x01011110,0x01000000, + 0x00000000,0x00000000,0x00110001,0x00001101, // 0072h + 0x00000011,0x00000001,0x00000001,0x00000001, + 0x00000000,0x00000000,0x00111110,0x01000001, // 0073h + 0x00001110,0x00110000,0x01000001,0x00111110, + 0x00000000,0x00000100,0x00000100,0x01111111, // 0074h + 0x00000100,0x00000100,0x00000100,0x01111000, + 0x00000000,0x00000000,0x01000001,0x01000001, // 0075h + 0x01000001,0x01000001,0x01000001,0x01111110, + 0x00000000,0x00000000,0x01000001,0x01000001, // 0076h + 0x00100010,0x00100010,0x00010100,0x00001000, + 0x00000000,0x00000000,0x01000001,0x01000001, // 0077h + 0x01001001,0x00101010,0x00101010,0x00010100, + 0x00000000,0x00000000,0x00100001,0x00010010, // 0078h + 0x00001100,0x00001100,0x00010010,0x00100001, + 0x00000000,0x00000000,0x01000001,0x01000001, // 0079h + 0x00100010,0x00011100,0x00001000,0x00000110, + 0x00000000,0x00000000,0x00111111,0x00010000, // 007ah + 0x00001000,0x00000100,0x00000010,0x00111111, + 0x00000000,0x00001000,0x00011110,0x01100100, // 007bh + 0x00011000,0x00100100,0x00000100,0x01111000, + 0x00000000,0x00000000,0x00011110,0x00000100, // 007ch + 0x00011110,0x00110101,0x00101101,0x00010010, + 0x00000000,0x00000000,0x00000000,0x00010001, // 007dh + 0x00100001,0x00100001,0x00000001,0x00000010, + 0x00000000,0x00000000,0x00011100,0x00000000, // 007eh + 0x00011110,0x00100000,0x00100000,0x00011100, + 0x00000000,0x00000000,0x00011100,0x00000000, // 007fh + 0x00111110,0x00010000,0x00001100,0x00110010, + 0x00000000,0x00000000,0x00000100,0x00101111, // 0080h + 0x01000100,0x00011110,0x00100101,0x00010110, + 0x00000000,0x00000000,0x00001010,0x00011110, // 0081h + 0x00101011,0x00100010,0x00010100,0x00000100, + 0x00000000,0x00000000,0x00001000,0x00011101, // 0082h + 0x00101011,0x00101001,0x00011001,0x00000100, + 0x00000000,0x00000000,0x00001000,0x00111000, // 0083h + 0x00001000,0x00011110,0x00101001,0x00000110, + 0x00000000,0x00000000,0x00000000,0x00011100, // 0084h + 0x00100011,0x00100000,0x00100000,0x00011100, + 0x00000000,0x00000110,0x01001001,0x00110000, // 0085h + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000100,0x00111111,0x00000100, // 0086h + 0x00111110,0x01010101,0x01001101,0x00100110, + 0x00000000,0x00000000,0x00100001,0x01000001, // 0087h + 0x01000001,0x01000001,0x00000001,0x00000010, + 0x00000000,0x00111100,0x00000000,0x00111110, // 0088h + 0x01000000,0x01000000,0x00100000,0x00011100, + 0x00000000,0x00011100,0x00000000,0x00111110, // 0089h + 0x00010000,0x00001000,0x00010100,0x01100010, + 0x00000000,0x00100100,0x01011111,0x00000100, // 008ah + 0x00111110,0x01000101,0x01000101,0x00100010, + 0x00000000,0x00100010,0x01001111,0x01010010, // 008bh + 0x01010010,0x00010010,0x00010010,0x00001001, + 0x00000000,0x00000100,0x00111110,0x00001000, // 008ch + 0x00111110,0x00010000,0x00000010,0x00111100, + 0x00000000,0x00100000,0x00011000,0x00000110, // 008dh + 0x00000001,0x00000110,0x00011000,0x00100000, + 0x00000000,0x00100000,0x01111101,0x00100001, // 008eh + 0x00100001,0x00100001,0x00100001,0x00010010, + 0x00000000,0x00011110,0x00100000,0x00000000, // 008fh + 0x00000000,0x00000001,0x00000001,0x00111110, + 0x00000000,0x00001000,0x01111111,0x00010000, // 0090h + 0x00100000,0x00000010,0x00000010,0x00111100, + 0x00000000,0x00000001,0x00000001,0x00000001, // 0091h + 0x01000001,0x01000001,0x00100010,0x00011100, + 0x00000000,0x00010000,0x01111111,0x00011000, // 0092h + 0x00010100,0x00010100,0x00011000,0x00001100, + 0x00000000,0x00100010,0x01111111,0x00100010, // 0093h + 0x00100010,0x00000010,0x00000010,0x01111100, + 0x00000000,0x00111100,0x00010000,0x00001100, // 0094h + 0x01111111,0x00001000,0x00001000,0x00110000, + 0x00000000,0x00000100,0x00011111,0x00000100, // 0095h + 0x01110100,0x00000010,0x00001010,0x01110010, + 0x00000000,0x00001000,0x01111111,0x00000100, // 0096h + 0x00111100,0x01000010,0x01000000,0x00111100, + 0x00000000,0x00000000,0x00011100,0x00100011, // 0097h + 0x01000000,0x01000000,0x00100000,0x00011100, + 0x00000000,0x01111111,0x00010000,0x00001000, // 0098h + 0x00001000,0x00001000,0x00001000,0x00110000, + 0x00000000,0x00000010,0x00110010,0x00001100, // 0099h + 0x00000010,0x00000001,0x00000001,0x00111110, + 0x00000000,0x00100100,0x01001111,0x01000010, // 009ah + 0x00010001,0x00111100,0x00010010,0x00001100, + 0x00000000,0x00000010,0x01111010,0x01000010, // 009bh + 0x00000010,0x00000010,0x00001010,0x01110010, + 0x00000000,0x00100010,0x00111110,0x01010010, // 009ch + 0x01001011,0x01101101,0x01010101,0x00110010, + 0x00000000,0x00110010,0x01001011,0x01000110, // 009dh + 0x01000110,0x01110010,0x01001011,0x00110010, + 0x00000000,0x00011100,0x00101010,0x01001001, // 009eh + 0x01001001,0x01000101,0x01000101,0x00110010, + 0x00000000,0x00100001,0x01111101,0x00100001, // 009fh + 0x00100001,0x00111001,0x01100101,0x00011001, + 0x00000000,0x00000100,0x00100011,0x01100010, // 00a0h + 0x00100001,0x00100001,0x00010010,0x00001100, + 0x00000000,0x00000000,0x00000000,0x00000000, // 00a1h + 0x00000000,0x00000100,0x00001010,0x00000100, + 0x00000000,0x01110000,0x00010000,0x00010000, // 00a2h + 0x00010000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, // 00a3h + 0x00001000,0x00001000,0x00001000,0x00001110, + 0x00000000,0x00000000,0x00000000,0x00000000, // 00a4h + 0x00000000,0x00000010,0x00000100,0x00000100, + 0x00000000,0x00000000,0x00000000,0x00011000, // 00a5h + 0x00011000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x01111111,0x01000000,0x01111111, // 00a6h + 0x01000000,0x01000000,0x00100000,0x00011100, + 0x00000000,0x00000000,0x00111111,0x00100000, // 00a7h + 0x00010100,0x00001100,0x00000100,0x00000010, + 0x00000000,0x00000000,0x00100000,0x00100000, // 00a8h + 0x00010000,0x00001111,0x00001000,0x00001000, + 0x00000000,0x00000000,0x00000100,0x00111111, // 00a9h + 0x00100001,0x00100000,0x00010000,0x00001100, + 0x00000000,0x00000000,0x00000000,0x00111110, // 00aah + 0x00001000,0x00001000,0x00001000,0x01111111, + 0x00000000,0x00000000,0x00010000,0x00111111, // 00abh + 0x00011000,0x00010100,0x00010010,0x00011001, + 0x00000000,0x00000000,0x00000010,0x00111111, // 00ach + 0x00100010,0x00010010,0x00000100,0x00000100, + 0x00000000,0x00000000,0x00000000,0x00111110, // 00adh + 0x00100000,0x00100000,0x00100000,0x01111111, + 0x00000000,0x00000000,0x00111110,0x00100000, // 00aeh + 0x00111110,0x00100000,0x00100000,0x00111110, + 0x00000000,0x00000000,0x00100101,0x00101010, // 00afh + 0x00101010,0x00100000,0x00010000,0x00001110, + 0x00000000,0x00000000,0x00000000,0x00000000, // 00b0h + 0x01111111,0x00000000,0x00000000,0x00000000, + 0x00000000,0x01111111,0x01000000,0x00101000, // 00b1h + 0x00011000,0x00001000,0x00001000,0x00000100, + 0x00000000,0x01000000,0x00100000,0x00011000, // 00b2h + 0x00010111,0x00010000,0x00010000,0x00010000, + 0x00000000,0x00001000,0x01111111,0x01000001, // 00b3h + 0x01000001,0x01000000,0x00100000,0x00011000, + 0x00000000,0x00000000,0x00111110,0x00001000, // 00b4h + 0x00001000,0x00001000,0x00001000,0x01111111, + 0x00000000,0x00100000,0x01111111,0x00110000, // 00b5h + 0x00101000,0x00100100,0x00100010,0x00110001, + 0x00000000,0x00000100,0x01111111,0x01000100, // 00b6h + 0x01000100,0x01000100,0x01000010,0x00100001, + 0x00000000,0x00000100,0x00111111,0x00001000, // 00b7h + 0x01111111,0x00010000,0x00010000,0x00010000, + 0x00000000,0x01111100,0x01000100,0x01000100, // 00b8h + 0x01000010,0x01000000,0x00100000,0x00011000, + 0x00000000,0x00000010,0x01111110,0x00100010, // 00b9h + 0x00100001,0x00100000,0x00010000,0x00001100, + 0x00000000,0x01111110,0x01000000,0x01000000, // 00bah + 0x01000000,0x01000000,0x01000000,0x01111110, + 0x00000000,0x00100010,0x01111111,0x00100010, // 00bbh + 0x00100010,0x00100000,0x00010000,0x00001100, + 0x00000000,0x00000011,0x00000100,0x01000011, // 00bch + 0x01000100,0x00100000,0x00011000,0x00000111, + 0x00000000,0x01111111,0x01000000,0x00100000, // 00bdh + 0x00010000,0x00011000,0x00100100,0x01000011, + 0x00000000,0x00000010,0x01111111,0x01000010, // 00beh + 0x00100010,0x00000010,0x00000010,0x01111100, + 0x00000000,0x01000001,0x01000010,0x01000000, // 00bfh + 0x00100000,0x00100000,0x00011000,0x00000110, + 0x00000000,0x01111110,0x01000010,0x01001110, // 00c0h + 0x01110001,0x01000000,0x00100000,0x00011000, + 0x00000000,0x01100000,0x00011110,0x00010000, // 00c1h + 0x01111111,0x00010000,0x00010000,0x00001100, + 0x00000000,0x01000101,0x01001010,0x01001010, // 00c2h + 0x01000000,0x00100000,0x00010000,0x00001110, + 0x00000000,0x00111110,0x00000000,0x01111111, // 00c3h + 0x00010000,0x00010000,0x00001000,0x00000110, + 0x00000000,0x00000010,0x00000010,0x00000110, // 00c4h + 0x00011010,0x01100010,0x00000010,0x00000010, + 0x00000000,0x00010000,0x00010000,0x01111111, // 00c5h + 0x00010000,0x00010000,0x00001000,0x00000110, + 0x00000000,0x00000000,0x00111110,0x00000000, // 00c6h + 0x00000000,0x00000000,0x00000000,0x01111111, + 0x00000000,0x01111110,0x01000000,0x01000100, // 00c7h + 0x00101000,0x00010000,0x00101000,0x01000110, + 0x00000000,0x00001000,0x01111111,0x00100000, // 00c8h + 0x00010000,0x00011100,0x01101011,0x00001000, + 0x00000000,0x01000000,0x01000000,0x01000000, // 00c9h + 0x00100000,0x00100000,0x00011000,0x00000111, + 0x00000000,0x00010010,0x00100010,0x00100010, // 00cah + 0x01000010,0x01000010,0x01000001,0x01000001, + 0x00000000,0x00000001,0x00000001,0x01111111, // 00cbh + 0x00000001,0x00000001,0x00000001,0x01111110, + 0x00000000,0x01111111,0x01000000,0x01000000, // 00cch + 0x01000000,0x00100000,0x00010000,0x00001110, + 0x00000000,0x00000000,0x00000100,0x00001010, // 00cdh + 0x00010001,0x00100001,0x01000000,0x00000000, + 0x00000000,0x00001000,0x00001000,0x01111111, // 00ceh + 0x00001000,0x00101010,0x01001010,0x01001001, + 0x00000000,0x01111111,0x01000000,0x01000000, // 00cfh + 0x00100010,0x00010100,0x00001000,0x00010000, + 0x00000000,0x00001110,0x01110000,0x00001110, // 00d0h + 0x01110000,0x00000110,0x00011000,0x01100000, + 0x00000000,0x00001000,0x00001000,0x00000100, // 00d1h + 0x00000100,0x00100010,0x01000010,0x01111111, + 0x00000000,0x01000000,0x01000000,0x00100100, // 00d2h + 0x00101000,0x00010000,0x00101100,0x01000011, + 0x00000000,0x01111111,0x00000100,0x01111111, // 00d3h + 0x00000100,0x00000100,0x00000100,0x01111000, + 0x00000000,0x00000010,0x01111111,0x01000010, // 00d4h + 0x00100010,0x00010100,0x00000100,0x00000100, + 0x00000000,0x00000000,0x00111110,0x00100000, // 00d5h + 0x00100000,0x00100000,0x00100000,0x01111111, + 0x00000000,0x01111110,0x01000000,0x01000000, // 00d6h + 0x01111110,0x01000000,0x01000000,0x01111110, + 0x00000000,0x00111110,0x00000000,0x01111111, // 00d7h + 0x01000000,0x01000000,0x00100000,0x00011100, + 0x00000000,0x01000010,0x01000010,0x01000010, // 00d8h + 0x01000010,0x01000000,0x00100000,0x00011000, + 0x00000000,0x00001010,0x00001010,0x00001010, // 00d9h + 0x01001010,0x01001010,0x00101010,0x00011001, + 0x00000000,0x00000010,0x00000010,0x01000010, // 00dah + 0x01000010,0x00100010,0x00010010,0x00001110, + 0x00000000,0x01111111,0x01000001,0x01000001, // 00dbh + 0x01000001,0x01000001,0x01000001,0x01111111, + 0x00000000,0x01111111,0x01000001,0x01000001, // 00dch + 0x01000000,0x01000000,0x00100000,0x00011100, + 0x00000000,0x01000011,0x01000100,0x01000000, // 00ddh + 0x01000000,0x00100000,0x00010000,0x00001111, + 0x00000000,0x00000000,0x00000000,0x00000000, // 00deh + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, // 00dfh + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00011110,0x00001000,0x00000100, // 00e0h + 0x00101001,0x01010001,0x01010001,0x00001100, + 0x00000000,0x00000000,0x00001100,0x00010010, // 00e1h + 0x00010010,0x00100001,0x01000000,0x00000000, + 0x00000000,0x01111101,0x00100001,0x01111101, // 00e2h + 0x00100001,0x00111001,0x01100101,0x00011001, + 0x00000000,0x00111100,0x00010000,0x00111100, // 00e3h + 0x00010000,0x00011100,0x00110010,0x00001100, + 0x00000000,0x00001110,0x00101000,0x00101000, // 00e4h + 0x00111110,0x01100101,0x00100101,0x00010010, + 0x00000000,0x00000100,0x00101111,0x01000100, // 00e5h + 0x00000110,0x01000101,0x01000101,0x00111110, + 0x00000000,0x00100010,0x00100010,0x00111110, // 00e6h + 0x01010010,0x01010101,0x01001101,0x00100110, + 0x00000000,0x00000100,0x00011111,0x00000010, // 00e7h + 0x00011111,0x01000010,0x01000010,0x00111100, + 0x00000000,0x00010010,0x00111110,0x01010011, // 00e8h + 0x01000010,0x00100100,0x00000100,0x00000100, + 0x00000000,0x00001000,0x00111101,0x01001011, // 00e9h + 0x01001001,0x01001001,0x00111000,0x00000100, + 0x00000000,0x00001000,0x00111000,0x00001000, // 00eah + 0x00001000,0x00011110,0x00101001,0x00000110, + 0x00000000,0x00011000,0x00100000,0x00000100, // 00ebh + 0x00111010,0x01000110,0x01000000,0x00111000, + 0x00000000,0x01000010,0x01000010,0x01000010, // 00ech + 0x01000110,0x01000000,0x00100000,0x00011000, + 0x00000000,0x00111110,0x00010000,0x00111100, // 00edh + 0x01000011,0x01001100,0x01010010,0x00111100, + 0x00000000,0x00100010,0x00110011,0x00101010, // 00eeh + 0x00100110,0x00100010,0x00100011,0x01000010, + 0x00000000,0x00111110,0x00010000,0x00111100, // 00efh + 0x01000011,0x01000000,0x01000010,0x00111100, + 0x00000000,0x00000010,0x00111011,0x01000110, // 00f0h + 0x01000010,0x01000011,0x01000010,0x00110010, + 0x00000000,0x00000100,0x00000100,0x00000010, // 00f1h + 0x01000110,0x01000101,0x01000101,0x00111001, + 0x00000000,0x01010100,0x01111111,0x00100100, // 00f2h + 0x00100100,0x00100100,0x00100010,0x00010001, + 0x00000000,0x01010100,0x01011111,0x00000100, // 00f3h + 0x00111111,0x00001000,0x00001000,0x00001000, + 0x00000000,0x01011110,0x01100010,0x00100010, // 00f4h + 0x00100001,0x00100000,0x00010000,0x00001100, + 0x00000000,0x01010010,0x01111110,0x00100010, // 00f5h + 0x00100001,0x00100000,0x00010000,0x00001100, + 0x00000000,0x01010000,0x01111111,0x00100000, // 00f6h + 0x00100000,0x00100000,0x00100000,0x00111111, + 0x00000000,0x01010010,0x01010010,0x00111111, // 00f7h + 0x00010010,0x00010000,0x00010000,0x00001100, + 0x00000000,0x01010011,0x01010100,0x00100011, // 00f8h + 0x00100100,0x00010000,0x00001000,0x00000111, + 0x00000000,0x01010000,0x01011111,0x00010000, // 00f9h + 0x00001000,0x00001100,0x00010010,0x00100001, + 0x00000000,0x01010010,0x01111111,0x00100010, // 00fah + 0x00010010,0x00000010,0x00000010,0x00111100, + 0x00000000,0x01010001,0x01010010,0x00100000, // 00fbh + 0x00100000,0x00010000,0x00001000,0x00000110, + 0x00000000,0x01011110,0x01010010,0x00100110, // 00fch + 0x00111001,0x00100000,0x00010000,0x00001100, + 0x00000000,0x01010000,0x01011110,0x00010000, // 00fdh + 0x01111111,0x00010000,0x00010000,0x00001100, + 0x00000000,0x00100101,0x01001010,0x00101010, // 00feh + 0x00100000,0x00010000,0x00001000,0x00000111, + 0x00000000,0x01011110,0x01010000,0x00111111, // 00ffh + 0x00001000,0x00001000,0x00001000,0x00000110 +}; + + +/*---------------------------------------------------------------------------* + Palette data + *---------------------------------------------------------------------------*/ +const u32 d_PaletteData[ 8 * 16 ] = +{ + 0x00000000, 0x00000000, 0x00000000, 0x00000000, // black + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x001f0000, 0x00000000, 0x00000000, 0x00000000, // red + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x03e00000, 0x00000000, 0x00000000, 0x00000000, // green + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7c000000, 0x00000000, 0x00000000, 0x00000000, // blue + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x03ff0000, 0x00000000, 0x00000000, 0x00000000, // yellow + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7c1f0000, 0x00000000, 0x00000000, 0x00000000, // purple + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7fe00000, 0x00000000, 0x00000000, 0x00000000, // light blue + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00180000, 0x00000000, 0x00000000, 0x00000000, // dark red + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x03000000, 0x00000000, 0x00000000, 0x00000000, // dark green + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x60000000, 0x00000000, 0x00000000, 0x00000000, // dark blue + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x03180000, 0x00000000, 0x00000000, 0x00000000, // dark yellow + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x60180000, 0x00000000, 0x00000000, 0x00000000, // dark purple + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x63000000, 0x00000000, 0x00000000, 0x00000000, // dark light blue + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x56b50000, 0x00000000, 0x00000000, 0x00000000, // gray + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2d6b0000, 0x00000000, 0x00000000, 0x00000000, // dark gray + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x7fff0000, 0x00000000, 0x00000000, 0x00000000, // white + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +/*---------------------------------------------------------------------------* + End of file + *---------------------------------------------------------------------------*/ diff --git a/xrGameSpy/gamespy/common/nitro/font.h b/xrGameSpy/gamespy/common/nitro/font.h new file mode 100644 index 00000000000..f13b225dcfc --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/font.h @@ -0,0 +1,44 @@ +/*---------------------------------------------------------------------------* + Project: NitroSDK - RTC - demos + File: font.h + + Copyright 2003,2004 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: font.h,v $ + Revision 1.1 2004/05/12 02:39:13 terui + initial upload + + $NoKeywords: $ + *---------------------------------------------------------------------------*/ + +#ifndef FONT_H_ +#define FONT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/*===========================================================================*/ + +#include + +extern const u32 d_CharData[ 8 * 256 ]; +extern const u32 d_PaletteData[ 8 * 16 ]; + +/*===========================================================================*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FONT_H_ */ + +/*---------------------------------------------------------------------------* + End of file + *---------------------------------------------------------------------------*/ diff --git a/xrGameSpy/gamespy/common/nitro/gsSocketNitro.c b/xrGameSpy/gamespy/common/nitro/gsSocketNitro.c new file mode 100644 index 00000000000..bd97b2ea859 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/gsSocketNitro.c @@ -0,0 +1,194 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_NITRO) + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// static variables +static int GSINitroErrno; + +// prototypes of static functions +static int CheckRcode(int rcode, int errCode); + +#define NITRO_SOCKET_ERROR -1 + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static int CheckRcode(int rcode, int errCode) +{ + if(rcode >= 0) + return rcode; + GSINitroErrno = rcode; + return errCode; +} + +int socket(int pf, int type, int protocol) +{ + int rcode = SOC_Socket(pf, type, protocol); + return CheckRcode(rcode, INVALID_SOCKET); +} +int closesocket(SOCKET sock) +{ + int rcode = SOC_Close(sock); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +int shutdown(SOCKET sock, int how) +{ + int rcode = SOC_Shutdown(sock, how); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +int bind(SOCKET sock, const SOCKADDR* addr, int len) +{ + SOCKADDR localAddr; + int rcode; + + // with nitro, don't bind to 0, just start using the port + if(((const SOCKADDR_IN*)addr)->port == 0) + return 0; + + memcpy(&localAddr, addr, sizeof(SOCKADDR)); + localAddr.len = (u8)len; + + rcode = SOC_Bind(sock, &localAddr); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} + +int connect(SOCKET sock, const SOCKADDR* addr, int len) +{ + SOCKADDR remoteAddr; + int rcode; + + memcpy(&remoteAddr, addr, sizeof(SOCKADDR)); + remoteAddr.len = (u8)len; + + rcode = SOC_Connect(sock, &remoteAddr); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +int listen(SOCKET sock, int backlog) +{ + int rcode = SOC_Listen(sock, backlog); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +SOCKET accept(SOCKET sock, SOCKADDR* addr, int* len) +{ + int rcode; + addr->len = (u8)*len; + rcode = SOC_Accept(sock, addr); + *len = addr->len; + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} + +int recv(SOCKET sock, char* buf, int len, int flags) +{ + int rcode = SOC_Recv(sock, buf, len, flags); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +int recvfrom(SOCKET sock, char* buf, int len, int flags, SOCKADDR* addr, int* fromlen) +{ + int rcode; + addr->len = (u8)*fromlen; + rcode = SOC_RecvFrom(sock, buf, len, flags, addr); + *fromlen = addr->len; + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +SOCKET send(SOCKET sock, const char* buf, int len, int flags) +{ + int rcode = SOC_Send(sock, buf, len, flags); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +SOCKET sendto(SOCKET sock, const char* buf, int len, int flags, const SOCKADDR* addr, int tolen) +{ + SOCKADDR remoteAddr; + int rcode; + + memcpy(&remoteAddr, addr, sizeof(SOCKADDR)); + remoteAddr.len = (u8)tolen; + + rcode = SOC_SendTo(sock, buf, len, flags, &remoteAddr); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} + +int getsockopt(SOCKET sock, int level, int optname, char* optval, int* optlen) +{ + int rcode = SOC_GetSockOpt(sock, level, optname, optval, optlen); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} +SOCKET setsockopt(SOCKET sock, int level, int optname, const char* optval, int optlen) +{ + int rcode = SOC_SetSockOpt(sock, level, optname, optval, optlen); + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} + +int getsockname(SOCKET sock, SOCKADDR* addr, int* len) +{ + int rcode; + addr->len = (u8)*len; + rcode = SOC_GetSockName(sock, addr); + *len = addr->len; + return CheckRcode(rcode, NITRO_SOCKET_ERROR); +} + +unsigned long inet_addr(const char* name) +{ + int rcode; + SOInAddr addr; + rcode = SOC_InetAtoN(name, &addr); + if(rcode == FALSE) + return INADDR_NONE; + return addr.addr; +} + +int GOAGetLastError(SOCKET sock) +{ + GSI_UNUSED(sock); + return GSINitroErrno; +} + + + +int GSISocketSelect(SOCKET theSocket, int* theReadFlag, int* theWriteFlag, int* theExceptFlag) +{ + SOPollFD pollFD; + int rcode; + + pollFD.fd = theSocket; + pollFD.events = 0; + if(theReadFlag != NULL) + pollFD.events |= SOC_POLLRDNORM; + if(theWriteFlag != NULL) + pollFD.events |= SOC_POLLWRNORM; + pollFD.revents = 0; + + rcode = SOC_Poll(&pollFD, 1, 0); + if(rcode < 0) + return NITRO_SOCKET_ERROR; + + if(theReadFlag != NULL) + { + if((rcode > 0) && (pollFD.revents & (SOC_POLLRDNORM|SOC_POLLHUP))) + *theReadFlag = 1; + else + *theReadFlag = 0; + } + if(theWriteFlag != NULL) + { + if((rcode > 0) && (pollFD.revents & SOC_POLLWRNORM)) + *theWriteFlag = 1; + else + *theWriteFlag = 0; + } + if(theExceptFlag != NULL) + { + if((rcode > 0) && (pollFD.revents & SOC_POLLERR)) + *theExceptFlag = 1; + else + *theExceptFlag = 0; + } + return rcode; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _NITRO \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/gsThreadNitro.c b/xrGameSpy/gamespy/common/nitro/gsThreadNitro.c new file mode 100644 index 00000000000..515009d4ebc --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/gsThreadNitro.c @@ -0,0 +1,155 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsPlatformThread.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 gsiInterlockedIncrement(gsi_u32 * value) +{ + OSIntrMode state = OS_DisableInterrupts_IrqAndFiq(); + gsi_u32 ret = ++(*value); + OS_RestoreInterrupts_IrqAndFiq(state); + + // return "ret" rather than "value" here b/c + // value may be modified by another thread + // before we can return it + return ret; +} + +gsi_u32 gsiInterlockedDecrement(gsi_u32 * value) +{ + OSIntrMode state = OS_DisableInterrupts_IrqAndFiq(); + gsi_u32 ret = --(*value); + OS_RestoreInterrupts_IrqAndFiq(state); + + // return "ret" rather than "value" here b/c + // value may be modified by another thread + // before we can return it + return ret; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int gsiStartThread(GSThreadFunc aThreadFunc, gsi_u32 theStackSize, void *arg, GSIThreadID* theThreadIdOut) +{ + if(theStackSize & 0x3) + { + theStackSize += 0x4; + theStackSize &= ~0x3; + } + + theThreadIdOut->mStack = gsimemalign(4, theStackSize); + + OS_CreateThread(&theThreadIdOut->mThread, aThreadFunc, arg, theThreadIdOut->mStack, theStackSize, 15); + OS_WakeupThreadDirect(&theThreadIdOut->mThread); + + return 0; +} + +void gsiCancelThread(GSIThreadID theThreadID) +{ + OS_DestroyThread(&theThreadID.mThread); + if(theThreadID.mStack) + { + gsifree(theThreadID.mStack); + theThreadID.mStack = NULL; + } +} + +void gsiCleanupThread(GSIThreadID theThreadID) +{ + OS_DestroyThread(&theThreadID.mThread); + if(theThreadID.mStack) + { + gsifree(theThreadID.mStack); + theThreadID.mStack = NULL; + } +} + +gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID) +{ + BOOL shutdown = OS_IsThreadTerminated(&theThreadID.mThread); + + if(shutdown == TRUE) + return 1; + return 0; +} + +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) +{ + OS_InitMutex(theCrit); +} + +void gsiEnterCriticalSection(GSICriticalSection *theCrit) +{ + OS_LockMutex(theCrit); +} + +void gsiLeaveCriticalSection(GSICriticalSection *theCrit) +{ + OS_UnlockMutex(theCrit); +} + +void gsiDeleteCriticalSection(GSICriticalSection *theCrit) +{ + GSI_UNUSED(theCrit); +} + +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + GSISemaphoreID semaphore; + + OS_InitMutex(&semaphore.mLock); + + semaphore.mValue = theInitialCount; + semaphore.mMax = theMaxCount; + + GSI_UNUSED(theName); + + return semaphore; +} + +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + gsi_time startTime = current_time(); + gsi_bool infinite = (theTimeoutMs == GSI_INFINITE)?gsi_true:gsi_false; + + do + { + if(OS_TryLockMutex(&theSemaphore.mLock) == TRUE) + { + if(theSemaphore.mValue > 0) + { + theSemaphore.mValue--; + OS_UnlockMutex(&theSemaphore.mLock); + return 1; + } + + OS_UnlockMutex(&theSemaphore.mLock); + } + + if(theTimeoutMs != 0) + msleep(2); + + } while(gsi_is_true(infinite) || ((current_time() - startTime) < theTimeoutMs)); + + return 0; +} + +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + OS_LockMutex(&theSemaphore.mLock); + + theSemaphore.mValue += theReleaseCount; + if(theSemaphore.mValue > theSemaphore.mMax) + theSemaphore.mValue = theSemaphore.mMax; + + OS_UnlockMutex(&theSemaphore.mLock); +} + +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + GSI_UNUSED(theSemaphore); +} diff --git a/xrGameSpy/gamespy/common/nitro/gsTimerNitro.c b/xrGameSpy/gamespy/common/nitro/gsTimerNitro.c new file mode 100644 index 00000000000..3efd1f6add7 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/gsTimerNitro.c @@ -0,0 +1,19 @@ +// NITRO +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + +// note that this doesn't return the standard time() value +// because the DS doesn't know what timezone it's in +time_t time(time_t *timer) +{ + time_t t; + + assert(OS_IsTickAvailable() == TRUE); + t = (time_t)OS_TicksToSeconds(OS_GetTick()); + + if(timer) + *timer = t; + + return t; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/gsUtilNitro.c b/xrGameSpy/gamespy/common/nitro/gsUtilNitro.c new file mode 100644 index 00000000000..c85744e7cda --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/gsUtilNitro.c @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return atoll(theNumberStr); +} + + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%lld", theNumber); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/key.c b/xrGameSpy/gamespy/common/nitro/key.c new file mode 100644 index 00000000000..dcecb91ae05 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/key.c @@ -0,0 +1,76 @@ +#include "..\nonport.h" +#include "key.h" + +#define KEY_REPEAT_START 25 // Number of frames before start of key repeat +#define KEY_REPEAT_SPAN 10 // Number of frames of key repeat interval + +static KeyInformation KeyInfo; + +/*---------------------------------------------------------------------------* + Name: KeyRead + + Description: Edit key input information + Detect pressing trigger, releasing trigger, and pressing hold repeat + *---------------------------------------------------------------------------*/ +const KeyInformation * KeyRead(void) +{ + static u16 repeat_count[12]; + int i; + u16 r; + + r = PAD_Read(); + KeyInfo.trg = 0x0000; + KeyInfo.up = 0x0000; + KeyInfo.rep = 0x0000; + + for( i = 0 ; i < 12 ; i ++ ) + { + if( r & ( 0x0001 << i ) ) + { + if( !( KeyInfo.cnt & ( 0x0001 << i ) ) ) + { + KeyInfo.trg |= ( 0x0001 << i ); // Pressing trigger input + repeat_count[ i ] = 1; + } + else + { + if( repeat_count[ i ] > KEY_REPEAT_START ) + { + KeyInfo.rep |= ( 0x0001 << i ); // Pressing hold repeat + repeat_count[ i ] = KEY_REPEAT_START - KEY_REPEAT_SPAN; + } + else + { + repeat_count[ i ] ++; + } + } + } + else + { + if( KeyInfo.cnt & ( 0x0001 << i ) ) + { + KeyInfo.up |= ( 0x0001 << i ); // Releasing trigger input + } + } + } + KeyInfo.cnt = r; // Unprocessed key input + + return &KeyInfo; +} + +void WaitForA(void) +{ + while(1) + { + SVC_WaitVBlankIntr(); + KeyRead(); + if(KEY_A_PRESSED(&KeyInfo)) + break; + } +} + +void KeyInit(void) +{ + // empty call of key input information acquisition (pushing the A button in IPL) + KeyRead(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/key.h b/xrGameSpy/gamespy/common/nitro/key.h new file mode 100644 index 00000000000..3c04105ef47 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/key.h @@ -0,0 +1,28 @@ +#ifndef _KEY_H_ +#define _KEY_H_ + +// Key input information +typedef struct KeyInformation +{ + u16 cnt; // Unprocessed input value + u16 trg; // Pressing trigger input + u16 up; // Releasing trigger input + u16 rep; // Pressing hold repeat input +} KeyInformation; + +void KeyInit(void); + +const KeyInformation * KeyRead(void); + +#define KEY_A_PRESSED(info) (((info)->trg | (info)->rep) & PAD_BUTTON_A) +#define KEY_B_PRESSED(info) (((info)->trg | (info)->rep) & PAD_BUTTON_B) +#define KEY_X_PRESSED(info) (((info)->trg | (info)->rep) & PAD_BUTTON_X) +#define KEY_Y_PRESSED(info) (((info)->trg | (info)->rep) & PAD_BUTTON_Y) +#define KEY_UP_PRESSED(info) (((info)->trg | (info)->rep) & PAD_KEY_UP) +#define KEY_DOWN_PRESSED(info) (((info)->trg | (info)->rep) & PAD_KEY_DOWN) +#define KEY_LEFT_PRESSED(info) (((info)->trg | (info)->rep) & PAD_KEY_LEFT) +#define KEY_RIGHT_PRESSED(info) (((info)->trg | (info)->rep) & PAD_KEY_RIGHT) + +void WaitForA(void); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/main.c b/xrGameSpy/gamespy/common/nitro/main.c new file mode 100644 index 00000000000..4905c5f168a --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/main.c @@ -0,0 +1,122 @@ +#include "..\nonport.h" +#include "screen.h" +#include "key.h" +#include "wireless.h" +#include "touch.h" +#include "backup.h" + +static void Startup(void) +{ +/* System */ + // init the OS system - internally initializes: + // arena - OS_InitArenaEx() + // communication system between preprocessors - PXI_Init() + // lock system - OS_InitLock() + // IRQ interrupt tables - OS_InitIrqTable() + // exception display system - OS_InitException() + // both WRAMs to the ARM7 - MI_SetWramBank() + // V count alarm system - OS_InitVAlarm() + // thread system - OS_InitThread() + // reset system - OS_InitReset() + // Game Pak library - CTRDG_Init() + // Card library - CARD_Init() + // power control system - PM_Init() + OS_Init(); + +/* Time */ + // init the system tick count + OS_InitTick(); + + // init the alarm + // this is needed for OS_Sleep() + OS_InitAlarm(); + +/* RTC */ + RTC_Init(); + +/* FIFO */ + PXI_InitFifo(); + +/* Screen */ + ScreenInit(); + Printf("Screen initialized\n"); + + SetTopScreenLineCentered(SCREEN_HEIGHT / 2, SCWhite, "Starting GameSpy Sample"); + +/* Keys */ + KeyInit(); + Printf("Input initialized\n"); + +/* Touch */ + TouchInit(); + Printf("Touch initialized\n"); + +/* Interrupts */ + OS_EnableIrq(); + OS_EnableInterrupts(); + Printf("Interrupts initialized\n"); + +/* Heap */ + { + u32 nHeapAdrs = 0; + u32 nHeapSize = 1 * 1024 * 1024; + OSHeapHandle hHeap; + + OS_SetMainArenaLo(OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1)); + nHeapAdrs = (u32)OS_AllocFromMainArenaLo(nHeapSize, 32); + hHeap = OS_CreateHeap(OS_ARENA_MAIN, (void*)(nHeapAdrs), (void*)(nHeapAdrs + nHeapSize)); + OS_SetCurrentHeap(OS_ARENA_MAIN, hHeap); + } + Printf("Heap initialized\n"); + +/* Backup */ + BackupInit(); + +/* Wireless */ + WirelessInit(); +} + +static void Shutdown(void) +{ + // close down wireless + Printf("Wireless cleanup\n"); + WirelessCleanup(); + +// ClearScreens(); +// SetTopScreenLineCentered(SCREEN_HEIGHT / 2, SCWhite, "GameSpy Sample Shutdown"); +// SVC_WaitVBlankIntr(); + + // terminate the os system + Printf("Terminating OS\n"); + OS_Terminate(); +} + +extern int test_main(int argc, char ** argv); + +static void Run(void) +{ + SetPrintMode(PRINT_TO_SCREEN|PRINT_TO_DEBUGGER); + + Printf("\n"); + Printf("GameSpy Test App Starting\n"); + Printf("-------------------------\n"); + + test_main(0, NULL); + + Printf("------------------------\n"); + Printf("GameSpy Test App Exiting\n"); + + SetPrintMode(PRINT_TO_DEBUGGER); +} + +void NitroMain(void) +{ + // startup everything we need + Startup(); + + // do stuff + Run(); + + // shutdown the system + Shutdown(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/menu.c b/xrGameSpy/gamespy/common/nitro/menu.c new file mode 100644 index 00000000000..6b3ddb81446 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/menu.c @@ -0,0 +1,410 @@ +#include "../nonport.h" +#include "menu.h" +#include "screen.h" +#include "key.h" +#include "touch.h" + +static MenuScreen Screen; + +static MenuScreenConfiguration * NextMenuScreenConfiguration; + +static MenuScreenConfiguration MenuExitScreenConfiguration; + +static void NewMenuScreen(MenuScreenConfiguration * configuration) +{ + int count; + + memset(&Screen, 0, sizeof(MenuScreen)); + Screen.configuration = configuration; + Screen.listSelection = -1; + count = 0; + while(configuration->choices[count].text && (count < MAX_CHOICES)) + count++; + Screen.numChoices = count; +} + +static void ShowMenuScreen(void) +{ + MenuScreenConfiguration * configuration = Screen.configuration; + MenuScreenChoice * choices = configuration->choices; + int options = configuration->options; + + const ScreenColor normalColor = SCGray; + const ScreenColor highlightColor = SCWhite; + const ScreenColor disabledColor = SCDarkGray; + const int topTextLine = 10; + const int animationLine = (topTextLine + 2); + const int extraTextLine = (animationLine + 2); + const int keyboardTextLine = 1; + const int startKeyboardRowsLine = 3; + const int numKeyboardRows = 3; + const int numListRows = 5; + const int startListLine = 1; + const int startChoicesLine = (SCREEN_HEIGHT - (Screen.numChoices * 2)); + const char keyboardRows[numKeyboardRows][32] = + { + "1 2 3 4 5 6 7 8 9 0 - + = _ . < ", + " A B C D E F G H I J K L M N O ", + " P Q R S T U V W X Y Z space " + }; + const char listBorder[32] = "--------------------"; + const int spacePos = (strchr(keyboardRows[2], 's') - keyboardRows[2]); + const char animationChars[] = "-*"; + const gsi_time animationTickTime = 500; + + BOOL done = FALSE; + int choiceIndex; + BOOL keyboard; + BOOL touching; + BOOL list; + BOOL animated; + int x, y; + int touchingLine; + int touchingPos; + int choiceLine; + int keyboardLine; + BOOL wasTouching = FALSE; + int wasTouchingChoice = -1; + ScreenColor color; + int i; + int range; + char touchingChar; + char wasTouchingChar = 0; + int keyboardPos; + int numListItems; + int listScroll = 0; + BOOL wasTouchingUp = FALSE; + BOOL wasTouchingDown = FALSE; + int listItem; + const char * choiceSelection; + int animationCount = 0; + gsi_time lastAnimationTime = current_time(); + gsi_time now; + char animationText[] = "-"; + + // is it animated? + animated = (options & SCREEN_OPTION_ANIMATED)?TRUE:FALSE; + + // is there a keyboard? + keyboard = (options & SCREEN_OPTION_KEYBOARD)?TRUE:FALSE; + + // is there a list? + list = (options & SCREEN_OPTION_LIST)?TRUE:FALSE; + + // we can't have a list and a keyboard + if(keyboard && list) + OS_Panic("Can't have a keyboard and a list on a menu screen\n"); + + // call the init func + if(configuration->initFunc) + { + configuration->initFunc(); + if(NextMenuScreenConfiguration) + return; + } + + // if there is a keyboard, get the initial position + if(keyboard) + keyboardPos = (int)strlen(Screen.keyboardText); + + // loop until we're done + while(!done) + { + // wait for a screen update to complete + SVC_WaitVBlankIntr(); + + // call the think func + if(configuration->thinkFunc) + { + configuration->thinkFunc(); + if(NextMenuScreenConfiguration) + return; + } + + // count the number of list items + if(list) + { + for(numListItems = 0 ; numListItems < MAX_LIST_STRINGS ; numListItems++) + { + if(Screen.list[numListItems][0] == '\0') + break; + } + } + + // check for a touch + touching = GetTouch(&x, &y); + if(touching) + { + // figure out which line we're touching + touchingLine = (y / (TOUCH_Y_RANGE / SCREEN_HEIGHT)); + + // figure out which position we're touching + touchingPos = (x / (TOUCH_X_RANGE / SCREEN_WIDTH)); + } + else if (wasTouching) + { + // check for touching a choice + if(wasTouchingChoice != -1) + { + choiceSelection = choices[wasTouchingChoice].text; + wasTouchingChoice = -1; + + // call the chose func + if(configuration->choseFunc) + { + configuration->choseFunc(choiceSelection); + if(NextMenuScreenConfiguration) + return; + } + } + // check for touching up on the list + else if(wasTouchingUp) + { + if(listScroll > 0) + listScroll--; + } + // check for touching down on the list + else if(wasTouchingDown) + { + if(listScroll < (numListItems - numListRows)) + listScroll++; + } + // check for touching a keyboard char + else if(wasTouchingChar != 0) + { + // check for backspace + if(wasTouchingChar == '<') + { + if(keyboardPos > 0) + { + keyboardPos--; + Screen.keyboardText[keyboardPos] = '\0'; + } + } + else + { + if(keyboardPos < MAX_KEYBOARD_TEXT_LEN) + { + Screen.keyboardText[keyboardPos] = wasTouchingChar; + keyboardPos++; + Screen.keyboardText[keyboardPos] = '\0'; + } + } + } + } + wasTouching = touching; + + // clear both screens + ClearScreens(); + + // show the title on the top screen + SetTopScreenLineCentered(topTextLine, SCYellow, configuration->topScreenText); + + // show animation + if(animated) + { + now = current_time(); + if((now - lastAnimationTime) >= animationTickTime) + { + animationCount++; + animationCount %= strlen(animationChars); + lastAnimationTime += animationTickTime; + } + + animationText[0] = animationChars[animationCount]; + + SetTopScreenLineCentered(animationLine, SCYellow, animationText); + } + + // show extra text + for(i = 0 ; i < MAX_EXTRA_TEXT_STRINGS ; i++) + { + if(options & SCREEN_OPTION_EXTRAS_CENTERED) + SetTopScreenLineCentered(extraTextLine + i, SCWhite, Screen.extraText[i]); + else + SetTopScreenLine(extraTextLine + i, SCWhite, Screen.extraText[i]); + } + + // show the list + if(list) + { + // clear touching vars + wasTouchingUp = FALSE; + wasTouchingDown = FALSE; + + // show "up" if needed + if(listScroll > 0) + { + if(touching && (touchingLine == startListLine)) + { + wasTouchingUp = TRUE; + color = highlightColor; + } + else + { + color = normalColor; + } + SetBottomScreenLineCentered(startListLine, color, "up"); + } + + // show the top line + SetBottomScreenLineCentered(startListLine + 1, normalColor, listBorder); + + // show the list items + for(i = 0 ; i < numListRows ; i++) + { + listItem = (listScroll + i); + + if(listItem >= numListItems) + break; + + // is this item being touched? + if(touching && (touchingLine == (startListLine + 2 + i))) + Screen.listSelection = listItem; + + // set the color + if(Screen.listSelection == listItem) + color = highlightColor; + else + color = normalColor; + + // show the item + SetBottomScreenLineCentered(startListLine + 2 + i, color, Screen.list[listScroll + i]); + } + + // show the bottom line + SetBottomScreenLineCentered(startListLine + numListRows + 2, normalColor, listBorder); + + // show "down" if needed + if(listScroll < (numListItems - numListRows)) + { + if(touching && (touchingLine == (startListLine + numListRows + 3))) + { + wasTouchingDown = TRUE; + color = highlightColor; + } + else + { + color = normalColor; + } + SetBottomScreenLineCentered(startListLine + numListRows + 3, color, "down"); + } + } + + // show a keyboard + if(keyboard) + { + // show the text + SetBottomScreenLine(keyboardTextLine, SCGreen, Screen.keyboardText); + + // clear touching var + wasTouchingChar = 0; + + // loop through the keyboard rows + for(i = 0 ; i < numKeyboardRows ; i++) + { + // get the line to show this row on + keyboardLine = (startKeyboardRowsLine + i); + + // check if we're touching this row + if(touching && (touchingLine == keyboardLine)) + { + // get the char we're touching + touchingChar = keyboardRows[i][touchingPos]; + + // handle touching 'space' specially + if(islower(touchingChar)) + { + wasTouchingChar = ' '; + + touchingPos = spacePos; + range = 5; + } + else + { + if(touchingChar != ' ') + wasTouchingChar = touchingChar; + + range = 1; + } + + // show the keyboard row with the selection highlighted + SetBottomScreenLineHighlight( + keyboardLine, normalColor, keyboardRows[i], + touchingPos, range, highlightColor); + } + else + { + // show the keyboard row + SetBottomScreenLine(keyboardLine, normalColor, keyboardRows[i]); + } + } + } + + // show the choices + wasTouchingChoice = -1; + for(choiceIndex = 0 ; choiceIndex < Screen.numChoices ; choiceIndex++) + { + // this is the line to show this choice on + choiceLine = (startChoicesLine + (choiceIndex * 2)); + + // check if we're touching this choice + if((choices[choiceIndex].options & CHOICE_OPTION_DISABLED) || + ((choices[choiceIndex].options & CHOICE_OPTION_NEEDS_LIST_SELECTION) && (Screen.listSelection == -1))) + { + color = disabledColor; + } + else if(touching && (touchingLine == choiceLine)) + { + color = highlightColor; + wasTouchingChoice = choiceIndex; + } + else + { + color = normalColor; + } + + // show the line + SetBottomScreenLineCentered(choiceLine, color, choices[choiceIndex].text); + } + } +} + +void StartMenuScreen(MenuScreenConfiguration * configuration) +{ + assert(configuration != NULL); + + // set the initial next screen + SetNextMenuScreen(configuration); + + // loop while there is a next screen to show + while(NextMenuScreenConfiguration != &MenuExitScreenConfiguration) + { + // setup the new screen + NewMenuScreen(NextMenuScreenConfiguration); + + // clear the next screen setting + SetNextMenuScreen(NULL); + + // show the menu screen + ShowMenuScreen(); + + // clear the display + ClearScreens(); + } +} + +void SetNextMenuScreen(MenuScreenConfiguration * configuration) +{ + NextMenuScreenConfiguration = configuration; +} + +void ExitMenu(void) +{ + SetNextMenuScreen(&MenuExitScreenConfiguration); +} + +MenuScreen * GetMenuScreen(void) +{ + return &Screen; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/menu.h b/xrGameSpy/gamespy/common/nitro/menu.h new file mode 100644 index 00000000000..ec8df39d58a --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/menu.h @@ -0,0 +1,65 @@ +#ifndef _MENU_H_ +#define _MENU_H_ + +// various length defines +#define MAX_CHOICE_STRING_LEN 32 +#define MAX_TOP_SCREEN_TEXT 32 +#define MAX_CHOICES 10 +#define MAX_LIST_STRINGS 16 +#define MAX_LIST_STRING_LEN 32 +#define MAX_KEYBOARD_TEXT_LEN 32 +#define MAX_EXTRA_TEXT_STRINGS 10 +#define MAX_EXTRA_TEXT_STRING_LEN 32 + +// options for screens +#define SCREEN_OPTION_ANIMATED 0x1 +#define SCREEN_OPTION_KEYBOARD 0x2 +#define SCREEN_OPTION_LIST 0x4 +#define SCREEN_OPTION_EXTRAS_CENTERED 0x8 + +// options for screen choices +#define CHOICE_OPTION_NEEDS_LIST_SELECTION 0x1 +#define CHOICE_OPTION_DISABLED 0x2 + +// a single choice on a screen +typedef struct MenuScreenChoice +{ + const char * text; + int options; +} MenuScreenChoice; + +// an instance of a screen +typedef struct MenuScreen +{ + struct MenuScreenConfiguration * configuration; + char extraText[MAX_EXTRA_TEXT_STRINGS][MAX_EXTRA_TEXT_STRING_LEN + 1]; + char list[MAX_LIST_STRINGS][MAX_LIST_STRING_LEN + 1]; + int listSelection; // default -1, no selection + char keyboardText[MAX_KEYBOARD_TEXT_LEN + 1]; + int numChoices; +} MenuScreen; + +// the static configuration for a screen +typedef struct MenuScreenConfiguration +{ + const char * topScreenText; + MenuScreenChoice choices[MAX_CHOICES]; + void (* initFunc)(void); + void (* choseFunc)(const char * choice); + void (* thinkFunc)(void); + int options; +} MenuScreenConfiguration; + +// call this to start showing a menu, pass in the initial screen to show +void StartMenuScreen(MenuScreenConfiguration * configuration); + +// call this from any of the configuration callback funcs to set the next screen to show +void SetNextMenuScreen(MenuScreenConfiguration * configuration); + +// call this to exit the menu +void ExitMenu(void); + +// gets the current menu screen +MenuScreen * GetMenuScreen(void); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/nitrocommon.cww b/xrGameSpy/gamespy/common/nitro/nitrocommon.cww new file mode 100644 index 00000000000..c9a2625ec95 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/nitrocommon.cww @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + -1 + 0 + true + nitrosample\nitrosample.mcp + + 604 + 352 + + + 400 + 372 + + + 1 + 0 + 0 + 59420 + 0.162898 + 378 + + 29705908 + 42137564 + + + + + -1 + 0 + ..\..\serverbrowsing\sbctest\sbnitrocw\sbnitrocw.mcp + + 458 + 315 + + + 400 + 372 + + + 1 + 0 + 2 + 59420 + 0.193501 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\qr2\qr2csample\qr2nitrocw\qr2nitrocw.mcp + + 285 + 274 + + + 400 + 379 + + + 1 + 0 + 1 + 59420 + 0.141566 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\pt\pttestc\ptnitrocw\ptnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 1 + 4 + 59420 + 0.165193 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\Peer\peerc\peernitrocw\peernitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 1 + 3 + 59420 + 0.172138 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\natneg\simpletest\natnegnitrocw\natnegnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 0 + 4 + 59420 + 0.174097 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\gt2\gt2testc\gt2nitrocw\gt2nitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 0 + 5 + 59420 + 0.152819 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\gstats\statstest\gstatsnitrocw\gstatsnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 1 + 1 + 59420 + 0.140610 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\gstats\persisttest\persistnitrocw\persistnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 1 + 2 + 59420 + 0.191763 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\GP\gptestc\gpnitrocw\gpnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 0 + 3 + 59420 + 0.175118 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\ghttp\ghttpc\ghttpnitrocw\ghttpnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 1 + 0 + 59420 + 0.163171 + 378 + + 0 + 0 + + + + + -1 + 0 + ..\..\Chat\chatc\chatnitrocw\chatnitrocw.mcp + + 457 + 317 + + + 392 + 344 + + + 1 + 1 + 5 + 59420 + 0.167125 + 378 + + 29736291 + 974026480 + + + + + 1073741824 + 35 + + 540 + 75 + + + 387 + 279 + + + 0 + + + + + + + + + + + GlobalSession, cpuARMLittle, osCWDS + C:\gamespy\GOA\GP\gptestc\gpnitrocw\bin\ARM9-TS\Debug\main.nef + 1 + + + + -2147483648 + 34 + + 4 + 23 + + + 528 + 334 + + + 0 + + + + + + + + + + + + + -2147483648 + 37 + + 4 + 22 + + + 358 + 327 + + + 0 + + + + + + + + + + + + + -2147483648 + 24 + + 6 + 81 + + + 566 + 477 + + + 0 + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/common/nitro/nitrosample/Nitro.lcf b/xrGameSpy/gamespy/common/nitro/nitrosample/Nitro.lcf new file mode 100644 index 00000000000..aedd7f177ce --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/nitrosample/Nitro.lcf @@ -0,0 +1,509 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.37 07/20/2006 07:29:12 kitase_hirotake +# Added descriptions explaining the version section. +# +# Revision 1.36 2006/07/18 11:11:01 yasu +# There was an error in the method for obtaining the size +# of the OVERLAY region when checking for overflow of the TCM region using check.xTCM. +# Stopped adding the OVERLAY region because the correct calculation method is unknown at this time. +# +# Revision 1.35 2006/05/10 03:19:47 yasu +# Added support for the CodeWarrior 2.x overlay expansion +# +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 2006/03/30 23:59:22 yasu +# changed creation year +# +# Revision 1.32 2006/03/29 13:14:22 yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 2005/09/02 04:14:22 yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 2005/08/31 09:34:57 yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 2005/08/26 11:22:16 yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 2005/06/20 12:29:20 yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 2005/03/25 12:54:59 yasu +# Include .version section +# +# Revision 1.22 2004/10/03 02:00:56 yasu +# Output component file list for compstatic tool +# +# Revision 1.21 2004/09/27 05:28:21 yasu +# Support .sinit +# +# Revision 1.20 2004/09/09 11:49:20 yasu +# Support compstatic in default +# +# Revision 1.19 2004/09/06 06:40:00 yasu +# Add labels for digest +# +# Revision 1.18 2004/08/20 06:19:59 yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 2004/08/02 10:38:53 yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 2004/07/26 02:22:32 yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 2004/07/26 00:08:27 yasu +# Fix label of exception table +# +# Revision 1.14 2004/07/24 05:42:25 yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 2004/07/23 11:32:14 yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 2004/07/12 12:21:08 yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 2004/07/10 04:10:26 yasu +# Support command 'Library' +# +# Revision 1.10 2004/07/02 08:13:02 yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + # + # Added .version section. + # The info in this section will be used for lotcheck. + # Make sure it remains at this locale. + # + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/common/nitro/nitrosample/ROM-TS.rsf b/xrGameSpy/gamespy/common/nitro/nitrosample/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/nitrosample/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/common/nitro/nitrosample/nitrosample.c b/xrGameSpy/gamespy/common/nitro/nitrosample/nitrosample.c new file mode 100644 index 00000000000..c129025f3d1 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/nitrosample/nitrosample.c @@ -0,0 +1,606 @@ +#include "../../nonport.h" +#include "../../peer/peer.h" +#include "../../peer/peerMain.h" +#include "menu.h" +#include "screen.h" + +/************************************************************************/ +/* Sample Menu */ +/************************************************************************/ + +static const char mscHostServer[] = "Host Server"; +static const char mscListServers[] = "List Servers"; +static const char mscExit[] = "Exit"; +static const char mscStartHosting[] = "Start Hosting"; +static const char mscCancel[] = "Cancel"; +static const char mscStopHosting[] = "Stop Hosting"; +static const char mscViewHostInfo[] = "View Host Info"; +static const char mscMainMenu[] = "Main Menu"; +static const char mscBack[] = "Back"; + +static void CheckingBackendAvailabilityInit(void); +static void CheckingBackendAvailabilityChose(const char * choice); +static void CheckingBackendAvailabilityThink(void); + +static MenuScreenConfiguration msCheckingBackendAvailability = +{ + "Checking Backend Availability", + { + { mscCancel } + }, + CheckingBackendAvailabilityInit, + CheckingBackendAvailabilityChose, + CheckingBackendAvailabilityThink, + SCREEN_OPTION_ANIMATED +}; + +static void BackendUnavailableChose(const char * choice); + +static MenuScreenConfiguration msBackendUnavailable = +{ + "Backend Unavailable", + { + { mscExit } + }, + NULL, + BackendUnavailableChose +}; + +static void FailedToIntializePeerSDKChose(const char * choice); + +static MenuScreenConfiguration msFailedToIntializePeerSDK = +{ + "Failed to Initialize Peer SDK", + { + { mscExit } + }, + NULL, + FailedToIntializePeerSDKChose +}; + +static void HostOrListChose(const char * choice); + +static MenuScreenConfiguration msHostOrList = +{ + "Host or List", + { + { mscHostServer }, + { mscListServers }, + { mscExit } + }, + NULL, + HostOrListChose +}; + +static void ChooseHostingNameInit(void); +static void ChooseHostingNameChose(const char * choice); + +static MenuScreenConfiguration msChooseHostingName = +{ + "Choose Hosting Name", + { + { mscStartHosting }, + { mscCancel} + }, + ChooseHostingNameInit, + ChooseHostingNameChose, + NULL, + SCREEN_OPTION_KEYBOARD +}; + +static void HostingServerInit(void); +static void HostingServerChose(const char * choice); +static void HostingServerThink(void); + +static MenuScreenConfiguration msHostingServer = +{ + "Hosting Server", + { + { mscStopHosting } + }, + HostingServerInit, + HostingServerChose, + HostingServerThink, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void ErrorStartingHostInit(void); +static void ErrorStartingHostChose(const char * choice); + +static MenuScreenConfiguration msErrorStartingHost = +{ + "Error Starting Host", + { + { mscMainMenu } + }, + ErrorStartingHostInit, + ErrorStartingHostChose +}; + +static void ListingHostsInit(void); +static void ListingHostsChose(const char * choice); +static void ListingHostsThink(void); + +static MenuScreenConfiguration msListingHosts = +{ + "Listing Hosts", + { + { mscViewHostInfo, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscMainMenu } + }, + ListingHostsInit, + ListingHostsChose, + ListingHostsThink, + SCREEN_OPTION_LIST | SCREEN_OPTION_ANIMATED +}; + +static void ErrorListingHostsInit(void); +static void ErrorListingHostsChose(const char * choice); + +static MenuScreenConfiguration msErrorListingHosts = +{ + "Error Listing Hosts", + { + { mscMainMenu } + }, + ErrorListingHostsInit, + ErrorListingHostsChose +}; + +static void ViewHostInfoInit(void); +static void ViewHostInfoChose(const char * choice); + +static MenuScreenConfiguration msViewHostInfo = +{ + "View Host Info", + { + { mscBack } + }, + ViewHostInfoInit, + ViewHostInfoChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +/************************************************************************/ +/* Sample Funcs */ +/************************************************************************/ + + +#define GAMENAME "gmtest" +#define SECRETKEY "HA6zkS" + +#define MAX_HOSTNAME_LEN MAX_KEYBOARD_TEXT_LEN + +static char Hostname[MAX_HOSTNAME_LEN + 1] = "Nitro Host"; +static char FailureReason[MAX_EXTRA_TEXT_STRINGS][MAX_EXTRA_TEXT_STRING_LEN + 1]; +static qr2_error_t QR2AddError; +static BOOL ListingError; +static PEER Peer; +static SBServer SelectedServer; +static int Mapname; +static int Gametype; + +static const char Mapnames[][64] = { "Rome", "London", "New York" }; +static const char Gametypes[][64] = { "Deathmatch", "Teamplay", "1 on 1" }; +static const int NumMapnames = (sizeof(Mapnames) / sizeof(Mapnames[0])); +static const int NumGametypes = (sizeof(Gametypes) / sizeof(Gametypes[0])); + +static gsi_u32 DebugLog2(gsi_u32 level) +{ + gsi_u32 total = 0; + while (level > 1) + { + level = level >> 1; + total++; + } + return total; +} + +static void DebugCallback(GSIDebugCategory category, GSIDebugType type, + GSIDebugLevel level, const char * format, va_list params) +{ + // Output line prefix + Printf("[%s][%s][%s] ", + gGSIDebugCatStrings[category], + gGSIDebugTypeStrings[type], + gGSIDebugLevelStrings[DebugLog2(level)]); + + // Output to file + VPrintf(format, + params); +} + +int main(int argc, char * argv) +{ + gsSetDebugCallback(DebugCallback); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + StartMenuScreen(&msCheckingBackendAvailability); + + return 0; +} + +static const char * QR2ErrorToString(qr2_error_t result) +{ + if(result == e_qrnoerror) + return "no error"; + if(result == e_qrwsockerror) + return "socket error"; + if(result == e_qrbinderror) + return "bind error"; + if(result == e_qrdnserror) + return "dns lookup error"; + if(result == e_qrconnerror) + return "nat error"; + if(result == e_qrnochallengeerror) + return "no challenge received"; + return "unknown error"; +} + +static void SetFailureReason(const char * reason) +{ + int i; + const char * line; + const char * nextLine; + size_t len; + + memset(FailureReason, 0, sizeof(FailureReason)); + + nextLine = reason; + + for(i = 0 ; i < MAX_EXTRA_TEXT_STRINGS ; i++) + { + line = nextLine; + if(line[0] == '\0') + return; + + nextLine = strchr(line, '\n'); + if(nextLine && ((nextLine - line) < MAX_EXTRA_TEXT_STRING_LEN)) + { + len = (size_t)(nextLine - line); + nextLine++; + } + else if(strlen(line) >= MAX_EXTRA_TEXT_STRING_LEN) + { + len = MAX_EXTRA_TEXT_STRING_LEN; + nextLine = (line + MAX_EXTRA_TEXT_STRING_LEN); + } + else + { + len = strlen(line); + nextLine = ""; + } + + memcpy(FailureReason[i], line, len); + FailureReason[i][len] = '\0'; + } +} + +static void KeyListCallback(PEER peer, qr2_key_type type, qr2_keybuffer_t buffer, void * param) +{ + switch(type) + { + case key_server: + qr2_keybuffer_add(buffer, HOSTNAME_KEY); + qr2_keybuffer_add(buffer, MAPNAME_KEY); + qr2_keybuffer_add(buffer, GAMETYPE_KEY); + break; + case key_player: + break; + case key_team: + break; + } + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void ServerKeyCallback(PEER peer, int key, qr2_buffer_t buffer, void * param) +{ + switch(key) + { + case HOSTNAME_KEY: + qr2_buffer_add(buffer, Hostname); + break; + case MAPNAME_KEY: + qr2_buffer_add(buffer, Mapnames[Mapname]); + break; + case GAMETYPE_KEY: + qr2_buffer_add(buffer, Gametypes[Gametype]); + break; + default: + qr2_buffer_add(buffer, _T("")); + } + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void AddErrorCallback(PEER peer, qr2_error_t error, gsi_char * errorString, void * param) +{ + QR2AddError = error; + + SetFailureReason(errorString); + + GSI_UNUSED(peer); + GSI_UNUSED(param); +} + +static void ListingGamesCallback(PEER peer, PEERBool success, const gsi_char * name, SBServer server, + PEERBool staging, int msg, int progress, void * param) +{ + int num; + int i; + MenuScreen * screen = GetMenuScreen(); + piConnection * connection = (piConnection *)peer; + + if(success == PEERFalse) + { + ListingError = PEERTrue; + return; + } + + num = SBServerListCount(&connection->gameList); + + for(i = 0 ; i < MAX_LIST_STRINGS ; i++) + { + if(i < num) + { + server = SBServerListNth(&connection->gameList, i); + strncpy(screen->list[i], SBServerGetStringValue(server, "hostname", "[no name]"), MAX_LIST_STRING_LEN + 1); + screen->list[i][MAX_LIST_STRING_LEN] = '\0'; + } + else + { + screen->list[i][0] = '\0'; + } + } + + GSI_UNUSED(name); + GSI_UNUSED(staging); + GSI_UNUSED(msg); + GSI_UNUSED(progress); + GSI_UNUSED(param); +} + +/************************************************************************/ +/* Sample Menu Funcs */ +/************************************************************************/ + +static void CheckingBackendAvailabilityInit(void) +{ + GSIStartAvailableCheck(GAMENAME); +} +static void CheckingBackendAvailabilityChose(const char * choice) +{ + if(choice == mscCancel) + ExitMenu(); +} +static void CheckingBackendAvailabilityThink(void) +{ + GSIACResult result = GSIAvailableCheckThink(); + PEERCallbacks callbacks; + + if(result == GSIACWaiting) + return; + + if(result != GSIACAvailable) + { + SetNextMenuScreen(&msBackendUnavailable); + return; + } + + memset(&callbacks, 0, sizeof(PEERCallbacks)); + callbacks.qrKeyList = KeyListCallback; + callbacks.qrServerKey = ServerKeyCallback; + callbacks.qrAddError = AddErrorCallback; + + Peer = peerInitialize(&callbacks); + if(!Peer) + { + SetNextMenuScreen(&msFailedToIntializePeerSDK); + return; + } + + if(!peerSetTitle(Peer, GAMENAME, SECRETKEY, GAMENAME, SECRETKEY, 0, 10, PEERTrue, NULL, NULL)) + { + peerShutdown(Peer); + SetNextMenuScreen(&msFailedToIntializePeerSDK); + return; + } + + SetNextMenuScreen(&msHostOrList); +} + +static void BackendUnavailableChose(const char * choice) +{ + if(choice == mscExit) + ExitMenu(); +} + +static void FailedToIntializePeerSDKChose(const char * choice) +{ + if(choice == mscExit) + ExitMenu(); +} + +static void HostOrListChose(const char * choice) +{ + if(choice == mscHostServer) + SetNextMenuScreen(&msChooseHostingName); + else if(choice == mscListServers) + SetNextMenuScreen(&msListingHosts); + else if(choice == mscExit) + { + peerShutdown(Peer); + ExitMenu(); + } +} + +static void ChooseHostingNameInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->keyboardText, Hostname, MAX_KEYBOARD_TEXT_LEN + 1); + screen->keyboardText[MAX_KEYBOARD_TEXT_LEN] = '\0'; +} +static void ChooseHostingNameChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(Hostname, screen->keyboardText, MAX_HOSTNAME_LEN + 1); + Hostname[MAX_HOSTNAME_LEN] = '\0'; + + if(choice == mscStartHosting) + SetNextMenuScreen(&msHostingServer); + else if(choice == mscCancel) + SetNextMenuScreen(&msHostOrList); +} + +static void HostingServerInit(void) +{ + PEERBool result; + MenuScreen * screen = GetMenuScreen(); + int line = 0; + + QR2AddError = e_qrnoerror; + + srand((unsigned int)time(NULL)); + Mapname = (rand() % NumMapnames); + Gametype = (rand() % NumGametypes); + + result = peerStartReporting(Peer); + + if(result == PEERFalse) + { + SetFailureReason("Failed to initialize hosting"); + SetNextMenuScreen(&msErrorStartingHost); + return; + } + + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN + 1, "Mapname: %s", Mapnames[Mapname]); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN + 1, "Gametype: %s", Gametypes[Gametype]); +} +static void HostingServerChose(const char * choice) +{ + if(choice == mscStopHosting) + { + peerStopGame(Peer); + SetNextMenuScreen(&msHostOrList); + } +} +static void HostingServerThink(void) +{ + peerThink(Peer); + + if(QR2AddError != e_qrnoerror) + { + char text[256]; + + peerStopGame(Peer); + snprintf(text, sizeof(text), "Failed to initialize hosting:\n%s", QR2ErrorToString(QR2AddError)); + SetFailureReason(text); + SetNextMenuScreen(&msErrorStartingHost); + } +} + +static void ErrorStartingHostInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + memcpy(screen->extraText, FailureReason, sizeof(FailureReason)); +} +static void ErrorStartingHostChose(const char * choice) +{ + if(choice == mscMainMenu) + SetNextMenuScreen(&msHostOrList); +} + +static void ListingHostsInit(void) +{ + const unsigned char keys[] = { HOSTNAME_KEY, MAPNAME_KEY, GAMETYPE_KEY }; + ListingError = FALSE; + + peerStartListingGames(Peer, keys, sizeof(keys), NULL, ListingGamesCallback, NULL); +} +static void ListingHostsChose(const char * choice) +{ + if(choice == mscViewHostInfo) + { + MenuScreen * screen = GetMenuScreen(); + piConnection * connection = (piConnection *)Peer; + + SelectedServer = SBServerListNth(&connection->gameList, screen->listSelection); + SetNextMenuScreen(&msViewHostInfo); + } + else if(choice == mscMainMenu) + { + peerStopListingGames(Peer); + SetNextMenuScreen(&msHostOrList); + } +} +static void ListingHostsThink(void) +{ + peerThink(Peer); + + if(ListingError == TRUE) + { + peerStopListingGames(Peer); + SetFailureReason("Failed to list hosts"); + SetNextMenuScreen(&msErrorListingHosts); + } +} + +static void ErrorListingHostsInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + memcpy(screen->extraText, FailureReason, sizeof(FailureReason)); +} +static void ErrorListingHostsChose(const char * choice) +{ + if(choice == mscMainMenu) + SetNextMenuScreen(&msHostOrList); +} + +static void ViewHostInfoInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + int line = 0; + + // hostname + strcpy(screen->extraText[line++], "[hostname]"); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " %s", SBServerGetStringValue(SelectedServer, "hostname", "N/A")); + + // public address + strcpy(screen->extraText[line++], "[public address]"); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " %s:%d", + SBServerGetPublicAddress(SelectedServer), SBServerGetPublicQueryPort(SelectedServer)); + + // private address + strcpy(screen->extraText[line++], "[private address]"); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " %s:%d", + SBServerGetPrivateAddress(SelectedServer), SBServerGetPrivateQueryPort(SelectedServer)); + + // mapname + strcpy(screen->extraText[line++], "[mapname]"); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " %s", SBServerGetStringValue(SelectedServer, "mapname", "N/A")); + + // gametype + strcpy(screen->extraText[line++], "[gametype]"); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " %s", SBServerGetStringValue(SelectedServer, "gametype", "N/A")); +} +static void ViewHostInfoChose(const char * choice) +{ + if(choice == mscBack) + SetNextMenuScreen(&msListingHosts); +} diff --git a/xrGameSpy/gamespy/common/nitro/nitrosample/nitrosample.mcp b/xrGameSpy/gamespy/common/nitro/nitrosample/nitrosample.mcp new file mode 100644 index 00000000000..fb93f166b46 Binary files /dev/null and b/xrGameSpy/gamespy/common/nitro/nitrosample/nitrosample.mcp differ diff --git a/xrGameSpy/gamespy/common/nitro/screen.c b/xrGameSpy/gamespy/common/nitro/screen.c new file mode 100644 index 00000000000..03404cc3ad7 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/screen.c @@ -0,0 +1,237 @@ +#include "..\nonport.h" +#include "screen.h" +#include "font.h" + +static u16 gTopScreen[SCREEN_HEIGHT * SCREEN_WIDTH]; +static u16 gBottomScreen[SCREEN_HEIGHT * SCREEN_WIDTH]; +static int gPos; +static int gPrintMode = PRINT_TO_DEBUGGER; + +static void VBlankIntr(void) +{ + // Reflect virtual screen to VRAM + DC_FlushRange( gTopScreen , sizeof( gTopScreen ) ); + DC_FlushRange( gBottomScreen , sizeof( gBottomScreen ) ); + GX_LoadBG0Scr( gTopScreen , 0 , sizeof( gTopScreen ) ); + GXS_LoadBG0Scr( gBottomScreen , 0 , sizeof( gBottomScreen ) ); + + // Set IRQ check flag + OS_SetIrqCheckFlag( OS_IE_V_BLANK ); +} + +void ClearTopScreen(void) +{ + MI_CpuClearFast( (void*)gTopScreen , sizeof( gTopScreen ) ); +// DC_FlushRange( gTopScreen , sizeof( gTopScreen ) ); +} + +void ClearBottomScreen(void) +{ + MI_CpuClearFast( (void*)gBottomScreen , sizeof( gBottomScreen ) ); +// DC_FlushRange( gBottomScreen , sizeof( gBottomScreen ) ); +} + +void ClearScreens(void) +{ + ClearTopScreen(); + ClearBottomScreen(); +} + +static void ScrollTopScreen(void) +{ + int i; + for(i = 0 ; i < (SCREEN_HEIGHT - 1) ; i++) + MI_CpuCopyFast((void*)&gTopScreen[SCREEN_WIDTH*(i+1)], (void*)&gTopScreen[SCREEN_WIDTH*i], SCREEN_WIDTH*sizeof(gTopScreen[0])); + MI_CpuClearFast((void*)&gTopScreen[(SCREEN_HEIGHT-1)*SCREEN_WIDTH], SCREEN_WIDTH*sizeof(gTopScreen[0])); +} + +void PrintChar(char c) +{ + u8 palette = 0xf; + + if(c == '\r') + return; + + if(gPos == SCREEN_WIDTH) + { + ScrollTopScreen(); + gPos = 0; + if(c == '\n') + return; + } + + if(c == '\n') + { + gPos = SCREEN_WIDTH; + } + else + { + gTopScreen[((SCREEN_HEIGHT - 1) * SCREEN_WIDTH) + gPos] = (u16)((palette << 12) | c); + gPos++; + } +} + +void Printf(const char* format, ...) +{ + va_list vlist; + + va_start(vlist, format); + VPrintf(format, vlist); + va_end(vlist); +} + +void VPrintf(const char* format, va_list args) +{ + if(gPrintMode & PRINT_TO_SCREEN) + { + static char text[2048]; + int i; + + vsnprintf(text, sizeof(text) - 1, format, args); + text[sizeof(text) - 1] = '\0'; + + for(i = 0 ; text[i] ; i++) + PrintChar(text[i]); + + SVC_WaitVBlankIntr(); + } + if(gPrintMode & PRINT_TO_DEBUGGER) + { + OS_VPrintf(format, args); + } +} + +void SetPrintMode(int mode) +{ + gPrintMode = mode; +} + +static void SetScreenLine(u16 * screen, int line, int offset, ScreenColor color, const char * text, int pos, int range, ScreenColor posColor) +{ + u8 palette = (u8)color; + u8 posPalette = (u8)posColor; + u16 val; + int i; + char c; + BOOL inRange; + + MI_CpuClearFast((void*)&screen[line*SCREEN_WIDTH], SCREEN_WIDTH*sizeof(gTopScreen[0])); + + for(i = 0 ; i < SCREEN_WIDTH ; i++) + { + c = text[i]; + + if(c == '\0') + break; + + inRange = ((i >= pos) && (i < (pos + range)))?TRUE:FALSE; + + val = (u16)(((inRange?posPalette:palette) << 12) | c); + screen[(line * SCREEN_WIDTH) + offset + i] = val; + } +} + +static void SetScreenLineCentered(u16 * screen, int line, ScreenColor color, const char * text) +{ + int len; + int offset; + + len = (int)strlen(text); + if(len < SCREEN_WIDTH) + offset = (((SCREEN_WIDTH - len) & ~1) / 2); + else + offset = 0; + + SetScreenLine(screen, line, offset, color, text, 0, 0, color); +} + +void SetTopScreenLine(int line, ScreenColor color, const char * text) +{ + SetScreenLine(gTopScreen, line, 0, color, text, 0, 0, color); +} + +void SetTopScreenLineCentered(int line, ScreenColor color, const char * text) +{ + SetScreenLineCentered(gTopScreen, line, color, text); +} + +void SetTopScreenLineHighlight(int line, ScreenColor color, const char * text, int pos, int range, ScreenColor posColor) +{ + SetScreenLine(gTopScreen, line, 0, color, text, pos, range, posColor); +} + +void SetBottomScreenLine(int line, ScreenColor color, const char * text) +{ + SetScreenLine(gBottomScreen, line, 0, color, text, 0, 0, color); +} + +void SetBottomScreenLineCentered(int line, ScreenColor color, const char * text) +{ + SetScreenLineCentered(gBottomScreen, line, color, text); +} + +void SetBottomScreenLineHighlight(int line, ScreenColor color, const char * text, int pos, int range, ScreenColor posColor) +{ + SetScreenLine(gBottomScreen, line, 0, color, text, pos, range, posColor); +} + +void ScreenInit(void) +{ + // init the graphics engine + GX_Init(); + + // turn off the display engine output + GX_DispOff(); + GXS_DispOff(); + + // setup the display memory + GX_SetBankForLCDC( GX_VRAM_LCDC_ALL ); + MI_CpuClearFast( (void*)HW_LCDC_VRAM , HW_LCDC_VRAM_SIZE ); + GX_DisableBankForLCDC(); + MI_CpuFillFast( (void*)HW_OAM,192 , HW_OAM_SIZE ); + MI_CpuClearFast( (void*)HW_PLTT , HW_PLTT_SIZE ); + MI_CpuFillFast( (void*)HW_DB_OAM , 192,HW_DB_OAM_SIZE ); + MI_CpuClearFast( (void*)HW_DB_PLTT , HW_DB_PLTT_SIZE ); + + // clear the screens + ClearScreens(); + + // 2D display setup for displaying character string + //g2 + GX_SetBankForBG( GX_VRAM_BG_128_A ); + G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256 , + GX_BG_COLORMODE_16 , + GX_BG_SCRBASE_0xf800 , // SCR base block 31 + GX_BG_CHARBASE_0x00000 , // CHR base block 0 + GX_BG_EXTPLTT_01 ); + G2_SetBG0Priority( 0 ); + G2_BG0Mosaic( FALSE ); + GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS , GX_BGMODE_0,GX_BG0_AS_2D ); + GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); + GX_LoadBG0Char( d_CharData , 0 , sizeof( d_CharData ) ); + GX_LoadBGPltt( d_PaletteData , 0 , sizeof( d_PaletteData ) ); + GX_LoadBG0Scr( gTopScreen , 0 , sizeof( gTopScreen ) ); + //g2s + GX_SetBankForSubBG( GX_VRAM_SUB_BG_128_C ); + G2S_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256 , + GX_BG_COLORMODE_16 , + GX_BG_SCRBASE_0xf800 , // SCR base block 31 + GX_BG_CHARBASE_0x00000 , // CHR base block 0 + GX_BG_EXTPLTT_01 ); + G2S_SetBG0Priority( 0 ); + G2S_BG0Mosaic( FALSE ); + GXS_SetGraphicsMode( GX_BGMODE_0 ); + GXS_SetVisiblePlane( GX_PLANEMASK_BG0 ); + GXS_LoadBG0Char( d_CharData , 0 , sizeof( d_CharData ) ); + GXS_LoadBGPltt( d_PaletteData , 0 , sizeof( d_PaletteData ) ); + GXS_LoadBG0Scr( gBottomScreen , 0 , sizeof( gBottomScreen ) ); + + // Interrupt setup + OS_SetIrqFunction( OS_IE_V_BLANK , VBlankIntr ); + OS_EnableIrqMask( OS_IE_V_BLANK ); + GX_VBlankIntr( TRUE ); + + // Start LCD display + GX_DispOn(); + GXS_DispOn(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/screen.h b/xrGameSpy/gamespy/common/nitro/screen.h new file mode 100644 index 00000000000..1099d93ca8b --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/screen.h @@ -0,0 +1,50 @@ +#ifndef _SCREEN_H_ +#define _SCREEN_H_ + +#define SCREEN_WIDTH 32 +#define SCREEN_HEIGHT 24 + +typedef enum +{ + SCBlack, + SCRed, + SCGreen, + SCBlue, + SCYellow, + SCPurple, + SCLightBlue, + SCDarkRed, + SCDarkGreen, + SCDarkBlue, + SCDarkYellow, + SCDarkPurple, + SCDarkLightBlue, + SCGray, + SCDarkGray, + SCWhite +} ScreenColor; + +// can be combined +#define PRINT_TO_SCREEN 1 // default +#define PRINT_TO_DEBUGGER 2 + +void ScreenInit(void); + +void ClearTopScreen(void); +void ClearBottomScreen(void); +void ClearScreens(void); + +void PrintChar(char c); +void Printf(const char* format, ...); +void VPrintf(const char* format, va_list args); +void SetPrintMode(int mode); + +void SetTopScreenLine(int line, ScreenColor color, const char * text); +void SetTopScreenLineCentered(int line, ScreenColor color, const char * text); +void SetTopScreenLineHighlight(int line, ScreenColor color, const char * text, int pos, int range, ScreenColor posColor); + +void SetBottomScreenLine(int line, ScreenColor color, const char * text); +void SetBottomScreenLineCentered(int line, ScreenColor color, const char * text); +void SetBottomScreenLineHighlight(int line, ScreenColor color, const char * text, int pos, int range, ScreenColor posColor); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/touch.c b/xrGameSpy/gamespy/common/nitro/touch.c new file mode 100644 index 00000000000..8c06b7cb730 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/touch.c @@ -0,0 +1,44 @@ +#include "../nonport.h" +#include "touch.h" + +void TouchInit(void) +{ + TPCalibrateParam calibrate; + + TP_Init(); + + if(!TP_GetUserInfo(&calibrate)) + OS_Panic("Failed to initialize touch panel"); + + TP_SetCalibrateParam(&calibrate); +} + +// 0 <= x <= 255 +// 0 <= y <= 191 +BOOL GetTouch(int * x, int * y) +{ + TPData data; + u32 result; + + result = TP_RequestCalibratedSampling(&data); + + if((result != 0) || (data.touch == TP_TOUCH_OFF)) + return FALSE; + + if(x) + *x = data.x; + if(y) + *y = data.y; + + return TRUE; +} + +void WaitForTouch(void) +{ + while(1) + { + SVC_WaitVBlankIntr(); + if(GetTouch(NULL, NULL)) + break; + } +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/touch.h b/xrGameSpy/gamespy/common/nitro/touch.h new file mode 100644 index 00000000000..fa1b41d5d34 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/touch.h @@ -0,0 +1,15 @@ +#ifndef _TOUCH_H_ +#define _TOUCH_H_ + +#define TOUCH_X_RANGE 256 +#define TOUCH_Y_RANGE 192 + +void TouchInit(void); + +// 0 <= x <= 255 +// 0 <= y <= 191 +BOOL GetTouch(int * x, int * y); + +void WaitForTouch(void); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/nitro/wireless.c b/xrGameSpy/gamespy/common/nitro/wireless.c new file mode 100644 index 00000000000..7eb0736333b --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/wireless.c @@ -0,0 +1,1541 @@ +#include "../nonport.h" +#include "wireless.h" +#include "screen.h" +#include "menu.h" +#include "backup.h" +#include "touch.h" + +#define USE_DHCP +#define SUPPORT_SAVED_CONFIGS + +#define AUTO_CONNECT +//static u8 MyBSSID[IW_BSSID_SIZE] = { 0x00, 0x0f, 0x66, 0x82, 0x38, 0x70 }; +static u8 MyBSSID[IW_BSSID_SIZE] = { 0x00, 0x09, 0x5b, 0x3f, 0x4b, 0xfb }; +static u8 MyWEP[IW_WEP_SIZE] = { WM_WEPMODE_NO }; + +/************************************************************************/ +/* Wireless Menu */ +/************************************************************************/ + +static const char mscUseSelectedConfiguration[] = "Use Selected Configuration"; +static const char mscCreateNewConfiguration[] = "Create New Configuration"; +static const char mscRenameSelectedConfiguration[] = "Rename Selected Configuration"; +static const char mscDeleteSelectedConfiguration[] = "Delete Selected Configuration"; +static const char mscExit[] = "Exit"; +static const char mscYes[] = "Yes"; +static const char mscNo[] = "No"; +static const char mscOK[] = "OK"; +static const char mscCancel[] = "Cancel"; +static const char mscRename[] = "Rename"; +static const char mscConnectToSelectedNetwork[] = "Connect to Selected Network"; +static const char mscViewNetworkInformation[] = "View Network Information"; +static const char mscBack[] = "Back"; +static const char mscEnter[] = "Enter"; +static const char mscUseKeyType[] = "Use Key Type"; +static const char mscRetry[] = "Retry"; +static const char mscContinue[] = "Continue"; +static const char mscSave[] = "Save"; +static const char mscDontSave[] = "Don't Save"; + +static void InitializingWirelessInit(void); +static void InitializingWirelessThink(void); +static void InitializingWirelessChose(const char * choice); + +static MenuScreenConfiguration msInitializingWireless = +{ + "Initializing Wireless", + { + { mscCancel } + }, + InitializingWirelessInit, + InitializingWirelessChose, + InitializingWirelessThink, + SCREEN_OPTION_ANIMATED +}; + +static void FailedToInitializeWirelessInit(void); +static void FailedToInitializeWirelessChose(const char * choice); + +static MenuScreenConfiguration msFailedToInitializeWireless = +{ + "Failed to Initialize Wireless", + { + { mscOK } + }, + FailedToInitializeWirelessInit, + FailedToInitializeWirelessChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void SelectNetworkConfigurationInit(void); +static void SelectNetworkConfigurationChose(const char * choice); + +static MenuScreenConfiguration msSelectNetworkConfiguration = +{ + "Select Network Configuration", + { + { mscUseSelectedConfiguration, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscCreateNewConfiguration }, + { mscRenameSelectedConfiguration, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscDeleteSelectedConfiguration, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscExit } + }, + SelectNetworkConfigurationInit, + SelectNetworkConfigurationChose, + NULL, + SCREEN_OPTION_LIST +}; + +static void RenameConfigurationInit(void); +static void RenameConfigurationChose(const char * choice); + +static MenuScreenConfiguration msRenameConfiguration = +{ + "Rename Configuration", + { + { mscRename }, + { mscCancel } + }, + RenameConfigurationInit, + RenameConfigurationChose, + NULL, + SCREEN_OPTION_KEYBOARD | SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void ConfirmDeleteInit(void); +static void ConfirmDeleteChose(const char * choice); + +static MenuScreenConfiguration msConfirmDelete = +{ + "Confirm Delete", + { + { mscYes }, + { mscNo } + }, + ConfirmDeleteInit, + ConfirmDeleteChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void ConfigurationDeletedChose(const char * choice); + +static MenuScreenConfiguration msConfigurationDeleted = +{ + "Configuration Deleted", + { + { mscOK } + }, + NULL, + ConfigurationDeletedChose +}; + +static void SearchingForNetworksInit(void); +static void SearchingForNetworksThink(void); +static void SearchingForNetworksChose(const char * choice); + +static MenuScreenConfiguration msSearchingForNetworks = +{ + "Searching for Networks", + { + { mscConnectToSelectedNetwork, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscViewNetworkInformation, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscCancel } + }, + SearchingForNetworksInit, + SearchingForNetworksChose, + SearchingForNetworksThink, + SCREEN_OPTION_ANIMATED | SCREEN_OPTION_LIST +}; + +static void SearchingForSavedNetworkInit(void); +static void SearchingForSavedNetworkThink(void); +static void SearchingForSavedNetworkChose(const char * choice); +static MenuScreenConfiguration msSearchingForSavedNetwork = +{ + "Searching for Saved Network", + { + { mscCancel } + }, + SearchingForSavedNetworkInit, + SearchingForSavedNetworkChose, + SearchingForSavedNetworkThink, + SCREEN_OPTION_ANIMATED +}; + +static void SearchFailedInit(void); +static void SearchFailedChose(const char * choice); + +static MenuScreenConfiguration msSearchFailed = +{ + "Search Failed", + { + { mscOK } + }, + SearchFailedInit, + SearchFailedChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void NetworkInformationInit(void); +static void NetworkInformationChose(const char * choice); + +static MenuScreenConfiguration msNetworkInformation = +{ + "Network Information", + { + { mscBack } + }, + NetworkInformationInit, + NetworkInformationChose, + NULL +}; + +static void SelectSecurityTypeInit(void); +static void SelectSecurityTypeChose(const char * choice); + +static MenuScreenConfiguration msSelectSecurityType = +{ + "Select Security Type", + { + { mscUseKeyType, CHOICE_OPTION_NEEDS_LIST_SELECTION }, + { mscBack } + }, + SelectSecurityTypeInit, + SelectSecurityTypeChose, + NULL, + SCREEN_OPTION_LIST +}; + +static void EnterSecurityKeyInit(void); +static void EnterSecurityKeyChose(const char * choice); + +static MenuScreenConfiguration msEnterSecurityKey = +{ + "Enter Security (WEP) Key", + { + { mscEnter }, + { mscBack } + }, + EnterSecurityKeyInit, + EnterSecurityKeyChose, + NULL, + SCREEN_OPTION_KEYBOARD +}; + +static void BadSecurityKeyEnteredInit(void); +static void BadSecurityKeyEnteredChose(const char * choice); + +static MenuScreenConfiguration msBadSecurityKeyEntered = +{ + "Bad Security Key Entered", + { + { mscBack } + }, + BadSecurityKeyEnteredInit, + BadSecurityKeyEnteredChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void ConnectingToNetworkInit(void); +static void ConnectingToNetworkChose(const char * choice); +static void ConnectingToNetworkThink(void); + +static MenuScreenConfiguration msConnectingToNetwork = +{ + "Connecting to Network", + { + { mscCancel } + }, + ConnectingToNetworkInit, + ConnectingToNetworkChose, + ConnectingToNetworkThink, + SCREEN_OPTION_ANIMATED +}; + +static void FailedToConnectToNetworkInit(void); +static void FailedToConnectToNetworkChose(const char * choice); + +static MenuScreenConfiguration msFailedToConnectToNetwork = +{ + "Failed to Connect to Network", + { + { mscBack } + }, + FailedToConnectToNetworkInit, + FailedToConnectToNetworkChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void ConnectingToInternetInit(void); +static void ConnectingToInternetChose(const char * choice); +static void ConnectingToInternetThink(void); + +static MenuScreenConfiguration msConnectingToInternet = +{ + "Connecting to Internet", + { + { mscCancel } + }, + ConnectingToInternetInit, + ConnectingToInternetChose, + ConnectingToInternetThink, + SCREEN_OPTION_ANIMATED +}; + +static void FailedToConnectToInternetInit(void); +static void FailedToConnectToInternetChose(const char * choice); + +static MenuScreenConfiguration msFailedToConnectToInternet = +{ + "Failed to Connect to Internet", + { + { mscBack } + }, + FailedToConnectToInternetInit, + FailedToConnectToInternetChose, + NULL, + SCREEN_OPTION_EXTRAS_CENTERED +}; + +static void ConnectedToInternetInit(void); +static void ConnectedToInternetChose(const char * choice); + +static MenuScreenConfiguration msConnectedToInternet = +{ + "Connected to Internet", + { + { mscContinue } + }, + ConnectedToInternetInit, + ConnectedToInternetChose +}; + +static void SaveNetworkConfigurationInit(void); +static void SaveNetworkConfigurationChose(const char * choice); + +static MenuScreenConfiguration msSaveNetworkConfiguration = +{ + "Save Network Configuration", + { + { mscSave}, + { mscDontSave } + }, + SaveNetworkConfigurationInit, + SaveNetworkConfigurationChose, + NULL, + SCREEN_OPTION_KEYBOARD +}; + +static void ConfigurationSavedChose(const char * choice); + +static MenuScreenConfiguration msConfigurationSaved = +{ + "Configuration Saved", + { + { mscContinue } + }, + NULL, + ConfigurationSavedChose +}; + +static MenuScreenConfiguration msCancelled = +{ + "Wireless Setup Cancelled" +}; + +static MenuScreenConfiguration msFailed = +{ + "Wireless Setup Failed" +}; + +/************************************************************************/ +/* Wireless Funcs */ +/************************************************************************/ + +#define APLIST_COUNT 8 + +#define MAX_SAVED_CONFIGS 3 +#define MAX_CONFIG_NAME_LEN 32 + +#define BSSDESC_MAX 16 + +static const char MagicString[] = "GOA-SAVED-CONFIGS"; +static const size_t MagicStringLen = sizeof(MagicString); + +typedef struct SavedConfig +{ + char name[MAX_CONFIG_NAME_LEN + 1]; + u8 bssid[IW_BSSID_SIZE]; + u8 wep[IW_WEP_SIZE]; +} SavedConfig; + +typedef struct SavedFile +{ + char magic[MagicStringLen]; + u8 numConfigs; + SavedConfig configs[MAX_SAVED_CONFIGS]; +} SavedFile; + +static SavedFile SavedSettings; + +static u8 IWBuffer[IW_WORK_SIZE] ATTRIBUTE_ALIGN(32); + +static u8 BSSID[IW_BSSID_SIZE]; + +static u8 WEPAny[IW_WEP_SIZE]; +static char WEPEntered[256]; +static u8 WEPKey[IW_WEP_SIZE]; + +static unsigned long BSSDescBuffer[IW_BSS_SIZE * BSSDESC_MAX / 4]; + +static IWConfig WirelessConfig = +{ + 3, + BSSDescBuffer, + IW_BSS_SIZE * BSSDESC_MAX, + 0 +}; + +static WMBssDesc APList[APLIST_COUNT]; +static int APIndex; +static int WEPType; + +static char FailureReason[MAX_EXTRA_TEXT_STRING_LEN + 1]; + +static int SelectedConfig; + +static BOOL NewConfig; + +static gsi_bool KeepPolling; + +static void * soAlloc(u32 name, s32 size) +{ + OSIntrMode nOSIntrMode; + void * alloc = NULL; + + GSI_UNUSED(name); + + nOSIntrMode = OS_DisableInterrupts(); + alloc = OS_Alloc((u32)size); + OS_RestoreInterrupts(nOSIntrMode); + + return alloc; +} + +static void soFree(u32 name, void * ptr, s32 size) +{ + OSIntrMode nOSIntrMode; + + GSI_UNUSED(name); + GSI_UNUSED(size); + + nOSIntrMode = OS_DisableInterrupts(); + OS_Free(ptr); + OS_RestoreInterrupts(nOSIntrMode); +} + +SOConfig SocketsConfig = +{ + SOC_VENDOR_NINTENDO, // vendor + SOC_VERSION, // version + + soAlloc, // alloc + soFree, // free + +#if defined(USE_DHCP) + SOC_FLAG_DHCP, // flag + SOC_HtoNl(SOC_INADDR_ANY), // addr + SOC_HtoNl(SOC_INADDR_ANY), // netmask + SOC_HtoNl(SOC_INADDR_ANY), // router + SOC_HtoNl(SOC_INADDR_ANY), // dns1 + SOC_HtoNl(SOC_INADDR_ANY), // dns2 +#else + 0, // flag + SOC_HtoNl(0xC0A8000C), // addr 192.168. 0. 12 + SOC_HtoNl(0xFFFFFF00), // netmask 255.255.255. 0 + SOC_HtoNl(0xC0A80001), // router 192.168. 0. 1 + SOC_HtoNl(0xC0A80001), // dns1 192.168. 0. 1 + SOC_HtoNl(SOC_INADDR_ANY), // dns2 +#endif + 4096, // timeWaitBuffer + 4096, // reassemblyBuffer + 0, // maximum transmission unit size + + // TCP + 0, // default TCP receive window size (default 2 x MSS) + 0, // default TCP total retransmit timeout value (default 100 sec) + + // PPP + NULL, + NULL, + + // PPPoE + NULL, + + // DHCP + "NintendoDS", // DHCP host name + 50, // TCP total retransmit times (default 4) + + // UDP + 0, // default UDP send buffer size (default 1472) + 0 // defualt UDP receive buffer size (default 4416) +}; + +static const char * IWResultToString(int result) +{ + if(result == IW_RESULT_SUCCESS) + return "success"; + if(result == IW_RESULT_FAILURE) + return "failure"; + if(result == IW_RESULT_PROGRESS) + return "progress"; + if(result == IW_RESULT_ACCEPT) + return "accept"; + if(result == IW_RESULT_REJECT) + return "reject"; + if(result == IW_RESULT_WMDISABLE) + return "wmdisable"; + if(result == IW_RESULT_MEMORYERROR) + return "memoryerror"; + if(result == IW_RESULT_FATALERROR) + return "fatalerror"; + return "unknown result"; +} + +static const char * IWNotifyToString(int notify) +{ + if(notify == IW_NOTIFY_COMMON) + return "common"; + if(notify == IW_NOTIFY_STARTUP) + return "startup"; + if(notify == IW_NOTIFY_CLEANUP) + return "cleanup"; + if(notify == IW_NOTIFY_SEARCH_START) + return "search_start"; + if(notify == IW_NOTIFY_SEARCH_END) + return "search_end"; + if(notify == IW_NOTIFY_CONNECT) + return "connect"; + if(notify == IW_NOTIFY_DISCONNECT) + return "disconnect"; + if(notify == IW_NOTIFY_FOUND) + return "found"; + if(notify == IW_NOTIFY_BEACON_LOST) + return "beacon_lost"; + if(notify == IW_NOTIFY_FATALERROR) + return "fatalerror"; + return "unknown notify"; +} + +static const char * IWPhaseToString(int phase) +{ + if(phase == IW_PHASE_NULL) + return "null"; + if(phase == IW_PHASE_WAIT) + return "wait"; + if(phase == IW_PHASE_WAIT_IDLE) + return "wait_idle"; + if(phase == IW_PHASE_IDLE) + return "idle"; + if(phase == IW_PHASE_IDLE_WAIT) + return "idle_wait"; + if(phase == IW_PHASE_IDLE_SCAN) + return "idle_scan"; + if(phase == IW_PHASE_SCAN) + return "scan"; + if(phase == IW_PHASE_SCAN_IDLE) + return "scan_idle"; + if(phase == IW_PHASE_IDLE_LINK) + return "idle_link"; + if(phase == IW_PHASE_LINK) + return "link"; + if(phase == IW_PHASE_LINK_IDLE) + return "link_idle"; + if(phase == IW_PHASE_FATALERROR) + return "fatalerror"; + return "unknown phase"; +} + +static void IW_Callback(IWNotice * arg) +{ + GSI_UNUSED(arg); + OS_TPrintf("Notify: %s | Result: %s\n", IWNotifyToString(arg->notify), IWResultToString(arg->result)); +} + +static gsi_bool IW_CheckResult(int result, const char * funcName) +{ + assert(funcName); + + OS_Printf("%s: %s\n", funcName, IWResultToString(result)); + switch(result) + { + case IW_RESULT_SUCCESS: + case IW_RESULT_PROGRESS: + case IW_RESULT_ACCEPT: + return gsi_true; + case IW_RESULT_FAILURE: + case IW_RESULT_REJECT: + OS_Printf(" IW_Phase = %s\n", IWPhaseToString(IW_GetPhase())); + case IW_RESULT_WMDISABLE: + case IW_RESULT_MEMORYERROR: + case IW_RESULT_FATALERROR: + default: + snprintf(FailureReason, sizeof(FailureReason), "%s result: %s", funcName, IWResultToString(result)); + return gsi_false; + } +} + +static gsi_bool IW_Poll(int polling, int success, const char * funcName, gsi_bool * keepPolling) +{ + int phase; + + assert(funcName); + + phase = IW_GetPhase(); + if(phase == polling) + { + if(keepPolling) + *keepPolling = gsi_true; + return gsi_true; + } + + if(keepPolling) + *keepPolling = gsi_false; + + if(phase == success) + return gsi_true; + + snprintf(FailureReason, sizeof(FailureReason), "%s phase: %s", funcName, IWPhaseToString(phase)); + return gsi_false; +} + +static void LoadSettings(void) +{ + if(BackupExists()) + { + // load the saved settings from the backup + ReadFromBackup(&SavedSettings, sizeof(SavedSettings)); + } + else + { + // use a default when there isn't a backup device + // this makes debugging with the dev kit easier + SavedConfig config; + strcpy(config.name, "Default WEP"); + memcpy(config.bssid, MyBSSID, sizeof(MyBSSID)); + memcpy(config.wep, MyWEP, sizeof(MyWEP)); + + memcpy(SavedSettings.magic, MagicString, MagicStringLen); + SavedSettings.numConfigs = 1; + memcpy(&SavedSettings.configs[0], &config, sizeof(SavedConfig)); + } + + if(memcmp(SavedSettings.magic, MagicString, MagicStringLen) != 0) + SavedSettings.numConfigs = 0; + + SavedSettings.numConfigs = (u8)min(SavedSettings.numConfigs, MAX_SAVED_CONFIGS); +} + +static void SaveSettings(void) +{ + if(BackupExists()) + { + memcpy(SavedSettings.magic, MagicString, MagicStringLen); + WriteToBackup(&SavedSettings, sizeof(SavedSettings)); + } +} + +void WirelessInit(void) +{ + // load wireless settings + LoadSettings(); + + // start the menu + StartMenuScreen(&msInitializingWireless); +} + +void WirelessCleanup(void) +{ + int result; + + SOC_Cleanup(); + + result = IW_Disconnect(); + IW_CheckResult(result, "IW_Disconnect"); + + do + { + if(!IW_Poll(IW_PHASE_LINK_IDLE, IW_PHASE_IDLE, "IW_Disconnect", &KeepPolling)) + OS_TPrintf("Failuring waiting for wait phase\n"); + } while(KeepPolling); + + result = IW_Cleanup(); + IW_CheckResult(result, "IW_Cleanup"); + + do + { + if(!IW_Poll(IW_PHASE_IDLE_WAIT, IW_PHASE_WAIT, "IW_Cleanup", &KeepPolling)) + OS_TPrintf("Failuring waiting for wait phase\n"); + } while(KeepPolling); + + result = IW_Exit(); + IW_CheckResult(result, "IW_Exit"); +} + +/************************************************************************/ +/* Wireless Menu Funcs */ +/************************************************************************/ + +static void InitializingWirelessInit(void) +{ + int result; + + // init the wireless library + result = IW_Init(IWBuffer, sizeof(IWBuffer)); + if(!IW_CheckResult(result, "IW_Init")) + { + SetNextMenuScreen(&msFailedToInitializeWireless); + return; + } + + // startup wireless + result = IW_Startup(&WirelessConfig, IW_Callback); + if(!IW_CheckResult(result, "IW_Startup")) + { + SetNextMenuScreen(&msFailedToInitializeWireless); + return; + } + + KeepPolling = gsi_true; +} + +static void InitializingWirelessChose(const char * choice) +{ + if(choice == mscCancel) + SetNextMenuScreen(&msCancelled); +} + +static void InitializingWirelessThink(void) +{ + // poll the phase + if(KeepPolling) + { + if(!IW_Poll(IW_PHASE_WAIT_IDLE, IW_PHASE_IDLE, "IW_Startup", &KeepPolling)) + { + SetNextMenuScreen(&msFailedToInitializeWireless); + return; + } + if(KeepPolling) + return; + } + +#if defined(AUTO_CONNECT) + { + memcpy(WEPKey, MyWEP, sizeof(WEPKey)); + memcpy(BSSID, MyBSSID, WM_SIZE_BSSID); + NewConfig = FALSE; + SetNextMenuScreen(&msSearchingForSavedNetwork); + return; + } +#endif + + // we're done with the startup +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msSearchingForNetworks); +} + +static void FailedToInitializeWirelessInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], FailureReason, MAX_EXTRA_TEXT_STRING_LEN + 1); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN] = '\0'; +} + +static void FailedToInitializeWirelessChose(const char * choice) +{ + if(choice == mscOK) + SetNextMenuScreen(&msFailed); +} + +static void SelectNetworkConfigurationInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + int i; + + for(i = 0 ; i < SavedSettings.numConfigs ; i++) + { + strncpy(screen->list[i], SavedSettings.configs[i].name, MAX_LIST_STRING_LEN); + screen->list[i][MAX_LIST_STRING_LEN - 1] = '\0'; + } +} + +static void SelectNetworkConfigurationChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + SelectedConfig = screen->listSelection; + + if(choice == mscUseSelectedConfiguration) + { + memcpy(WEPKey, SavedSettings.configs[SelectedConfig].wep, sizeof(WEPKey)); + memcpy(BSSID, SavedSettings.configs[SelectedConfig].bssid, WM_SIZE_BSSID); + NewConfig = FALSE; + //SetNextMenuScreen(&msConnectingToNetwork); + SetNextMenuScreen(&msSearchingForSavedNetwork); + } + else if(choice == mscCreateNewConfiguration) + { + SetNextMenuScreen(&msSearchingForNetworks); + } + else if(choice == mscRenameSelectedConfiguration) + { + SetNextMenuScreen(&msRenameConfiguration); + } + else if(choice == mscDeleteSelectedConfiguration) + { + SetNextMenuScreen(&msConfirmDelete); + } + else if(choice == mscExit) + { + SetNextMenuScreen(&msCancelled); + } +} + +static void RenameConfigurationInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], SavedSettings.configs[SelectedConfig].name, MAX_EXTRA_TEXT_STRING_LEN); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN - 1] = '\0'; + + strncpy(screen->keyboardText, SavedSettings.configs[SelectedConfig].name, MAX_KEYBOARD_TEXT_LEN); + screen->keyboardText[MAX_KEYBOARD_TEXT_LEN - 1] = '\0'; +} + +static void RenameConfigurationChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + if(choice == mscRename) + { + strncpy(SavedSettings.configs[SelectedConfig].name, screen->keyboardText, MAX_CONFIG_NAME_LEN); + SavedSettings.configs[SelectedConfig].name[MAX_CONFIG_NAME_LEN - 1] = '\0'; + + SaveSettings(); + + SetNextMenuScreen(&msSelectNetworkConfiguration); + } + else if(choice == mscCancel) + { + SetNextMenuScreen(&msSelectNetworkConfiguration); + } +} + +static void ConfirmDeleteInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], SavedSettings.configs[SelectedConfig].name, MAX_EXTRA_TEXT_STRING_LEN); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN - 1] = '\0'; +} + +static void ConfirmDeleteChose(const char * choice) +{ + int i; + + if(choice == mscYes) + { + SavedSettings.numConfigs--; + for(i = SelectedConfig ; i < SavedSettings.numConfigs ; i++) + memcpy(&SavedSettings.configs[i], &SavedSettings.configs[i + 1], sizeof(SavedConfig)); + + SaveSettings(); + + SetNextMenuScreen(&msConfigurationDeleted); + } + else if(choice == mscNo) + { + SetNextMenuScreen(&msSelectNetworkConfiguration); + } +} + +static void ConfigurationDeletedChose(const char * choice) +{ + if(choice == mscOK) + { + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else + SetNextMenuScreen(&msSearchingForNetworks); + } +} + +static void SearchingForNetworksInit(void) +{ + int result; + + // search for access points + result = IW_Search(IW_BSSID_ANY, IW_ESSID_ANY, IW_OPT_CHANNEL_ALL|IW_OPT_SCANTYPE_PASSIVE); + if(!IW_CheckResult(result, "IW_Search")) + { + SetNextMenuScreen(&msSearchFailed); + return; + } + + KeepPolling = gsi_true; +} + +static void SearchingForNetworksChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + APIndex = screen->listSelection; + + if(choice == mscViewNetworkInformation) + { + SetNextMenuScreen(&msNetworkInformation); + return; + } + + // we're connecting or cancelling, so stop searching + IW_Search(NULL, NULL, 0); + + if(choice == mscConnectToSelectedNetwork) + { + SetNextMenuScreen(&msSelectSecurityType); + } + else if(choice == mscCancel) + { +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msCancelled); + } +} + +static void SearchingForNetworksThink(void) +{ + MenuScreen * screen; + int i; + int count; + WMBssDesc * desc; + + if(KeepPolling) + { + // poll the search + if(!IW_Poll(IW_PHASE_IDLE_SCAN, IW_PHASE_SCAN, "IW_Search", &KeepPolling)) + { + IW_Search(NULL, NULL, 0); + SetNextMenuScreen(&msSearchFailed); + return; + } + if(KeepPolling) + return; + } + + // get the screen + screen = GetMenuScreen(); + + // lock the AP descriptions + IW_LockBssDesc(1); + + // get a count + count = IW_CountBssDesc(); + count = min(count, APLIST_COUNT); + + // copy the access points + for(i = 0 ; i < count ; i++) + { + desc = IW_PointBssDesc(i); + if(!desc) + { + count = i; + break; + } + + memcpy(&APList[i], desc, sizeof(WMBssDesc)); + } + + // unlock the APs + IW_LockBssDesc(0); + + // fill the screen list + for(i = 0 ; i < MAX_LIST_STRINGS ; i++) + { + if(i < count) + { + if(APList[i].ssidLength > 0) + snprintf(screen->list[i], MAX_LIST_STRING_LEN, "%s", APList[i].ssid); + else + strcpy(screen->list[i], "[no name]"); + } + else + { + screen->list[i][0] = '\0'; + } + } +} + +static void SearchingForSavedNetworkInit(void) +{ + int result; + + // search for access points + result = IW_Search(BSSID, IW_ESSID_ANY, IW_OPT_CHANNEL_ALL|IW_OPT_SCANTYPE_PASSIVE); + if(!IW_CheckResult(result, "IW_Search")) + { + SetNextMenuScreen(&msSearchFailed); + return; + } + + KeepPolling = gsi_true; +} + +static void SearchingForSavedNetworkChose(const char * choice) +{ + if(choice == mscCancel) + { + // stop searching + IW_Search(NULL, NULL, 0); + + SetNextMenuScreen(&msSelectNetworkConfiguration); + } +} + +static void SearchingForSavedNetworkThink(void) +{ + int count; + WMBssDesc * desc = NULL; + + if(KeepPolling) + { + // poll the search + if(!IW_Poll(IW_PHASE_IDLE_SCAN, IW_PHASE_SCAN, "IW_Search", &KeepPolling)) + { + IW_Search(NULL, NULL, 0); + SetNextMenuScreen(&msSearchFailed); + return; + } + if(KeepPolling) + return; + } + // lock the AP descriptions + IW_LockBssDesc(1); + + // get a count + count = IW_CountBssDesc(); + + // if we found it, copy it + if(count > 0) + { + desc = IW_PointBssDesc(0); + if(desc) + { + memcpy(&APList[0], desc, sizeof(WMBssDesc)); + APIndex = 0; + } + } + + // unlock the APs + IW_LockBssDesc(0); + + // check if we found it + if(desc) + { + // stop searching + IW_Search(NULL, NULL, 0); + + // connect + SetNextMenuScreen(&msConnectingToNetwork); + } +} + +static void SearchFailedInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], FailureReason, MAX_EXTRA_TEXT_STRING_LEN + 1); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN] = '\0'; +} + +static void SearchFailedChose(const char * choice) +{ + if(choice == mscOK) + { +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msFailed); + } +} + +static void NetworkInformationInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + // BSSID / MAC + snprintf(screen->extraText[0], MAX_EXTRA_TEXT_STRING_LEN, + " MAC: %02X:%02X:%02X:%02X:%02X:%02X", + APList[APIndex].bssid[0], + APList[APIndex].bssid[1], + APList[APIndex].bssid[2], + APList[APIndex].bssid[3], + APList[APIndex].bssid[4], + APList[APIndex].bssid[5]); + + // channel + snprintf(screen->extraText[1], MAX_EXTRA_TEXT_STRING_LEN, + " Channel: %d", + APList[APIndex].channel); +} + +static void NetworkInformationChose(const char * choice) +{ + if(choice == mscBack) + SetNextMenuScreen(&msSearchingForNetworks); +} + +static void SelectSecurityTypeInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strcpy(screen->list[0], "No WEP key"); + strcpy(screen->list[1], "40/64 bit key"); + strcpy(screen->list[2], "104 bit key"); + strcpy(screen->list[3], "128 bit key"); +} + +static void SelectSecurityTypeChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + WEPType = screen->listSelection; + + if(choice == mscUseKeyType) + { + if(WEPType == WM_WEPMODE_NO) + { + memset(WEPKey, 0, sizeof(WEPKey)); + memcpy(BSSID, APList[APIndex].bssid, WM_SIZE_BSSID); + NewConfig = TRUE; + SetNextMenuScreen(&msConnectingToNetwork); + } + else + { + SetNextMenuScreen(&msEnterSecurityKey); + } + } + else if(choice == mscBack) + { + SetNextMenuScreen(&msSearchingForNetworks); + } +} + +static int HexToInt(char hex) +{ + switch(hex) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'A': + return 10; + case 'B': + return 11; + case 'C': + return 12; + case 'D': + return 13; + case 'E': + return 14; + case 'F': + return 15; + } + + return -1; +} + +static void EnterSecurityKeyInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->keyboardText, WEPEntered, sizeof(screen->keyboardText)); + screen->keyboardText[sizeof(screen->keyboardText) - 1] = '\0'; +} + +static void EnterSecurityKeyChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + // save off the key as entered + strncpy(WEPEntered, screen->keyboardText, sizeof(WEPEntered)); + WEPEntered[sizeof(WEPEntered) - 1] = '\0'; + + if(choice == mscEnter) + { + int i; + int len; + int correctLen; + int index; + int val[2]; + char badChar; + // get the key len + len = (int)strlen(screen->keyboardText); + + // get the correct len for the type + if(WEPType == WM_WEPMODE_40BIT) + correctLen = (40 / 4); + else if(WEPType == WM_WEPMODE_104BIT) + correctLen = (104 / 4); + else if(WEPType == WM_WEPMODE_128BIT) + correctLen = (128 / 4); + else + correctLen = -1; + + // check the len + if(len != correctLen) + { + snprintf(FailureReason, sizeof(FailureReason), "Bad length (%d instead of %d)", len, correctLen); + SetNextMenuScreen(&msBadSecurityKeyEntered); + return; + } + + // convert the keyboard text to hex + memset(WEPKey, 0, sizeof(WEPKey)); + WEPKey[0] = (u8)WEPType; + index = 2; + for(i = 0 ; i < len ; i += 2) + { + // convert the next two chars to ints + val[0] = HexToInt(screen->keyboardText[i]); + val[1] = HexToInt(screen->keyboardText[i + 1]); + + // check the values + if((val[0] == -1) || (val[1] == -1)) + { + if(val[0] == -1) + badChar = screen->keyboardText[i]; + else + badChar = screen->keyboardText[i + 1]; + snprintf(FailureReason, sizeof(FailureReason), "Bad value ('%c' instead of hex)", badChar); + SetNextMenuScreen(&msBadSecurityKeyEntered); + return; + } + + // enter them in the WEP array + WEPKey[index++] = (u8)((val[0] << 4) | val[1]); + } + + memcpy(BSSID, APList[APIndex].bssid, WM_SIZE_BSSID); + NewConfig = TRUE; + SetNextMenuScreen(&msConnectingToNetwork); + } + else if (choice == mscBack) + { + SetNextMenuScreen(&msSelectSecurityType); + } +} + +static void BadSecurityKeyEnteredInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], FailureReason, MAX_EXTRA_TEXT_STRING_LEN + 1); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN] = '\0'; +} + +static void BadSecurityKeyEnteredChose(const char * choice) +{ + if(choice == mscBack) + SetNextMenuScreen(&msEnterSecurityKey); +} + +static void ConnectingToNetworkInit(void) +{ + int result; + + // make sure we're idle + OS_TPrintf("Waiting for idle...\n"); + while(IW_GetPhase() != IW_PHASE_IDLE) + ; + + // connect + result = IW_Connect(&APList[APIndex], WEPKey, IW_OPT_POWER_FULL); + if(!IW_CheckResult(result, "IW_Connect")) + { + SetNextMenuScreen(&msFailedToConnectToNetwork); + return; + } + + KeepPolling = gsi_true; +} + +static void ConnectingToNetworkChose(const char * choice) +{ + if(choice == mscCancel) + { + // disconnect + IW_Disconnect(); + +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msSearchingForNetworks); + } +} + +static void ConnectingToNetworkThink(void) +{ + if(KeepPolling) + { + // poll the connect + if(!IW_Poll(IW_PHASE_IDLE_LINK, IW_PHASE_LINK, "IW_Connect", &KeepPolling)) + { + IW_Disconnect(); + SetNextMenuScreen(&msFailedToConnectToNetwork); + return; + } + if(KeepPolling) + return; + } + + // we're connected to the network + SetNextMenuScreen(&msConnectingToInternet); +} + +static void FailedToConnectToNetworkInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], FailureReason, MAX_EXTRA_TEXT_STRING_LEN + 1); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN] = '\0'; +} + +static void FailedToConnectToNetworkChose(const char * choice) +{ + if(choice == mscBack) + { +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msSearchingForNetworks); + } +} + +static void ConnectingToInternetInit(void) +{ + int result; + BOOL linkStatus = FALSE; + + // init the sockets library + SOC_Init(); + + // get the IP link + do + { + IP_GetLinkState(NULL, &linkStatus); + } + while(!linkStatus); + + // startup the sockets library + result = SOC_Startup(&SocketsConfig); + if(result < 0) + { + snprintf(FailureReason, sizeof(FailureReason), "SOC_Startup failed: %d", result); + SetNextMenuScreen(&msFailedToConnectToInternet); + return; + } +} + +static void ConnectingToInternetChose(const char * choice) +{ + if(choice == mscCancel) + { + SOC_Cleanup(); + IW_Disconnect(); + +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msSearchingForNetworks); + } +} + +static void ConnectingToInternetThink(void) +{ + u32 localIP; + + // check if we have been allocated an IP + localIP = (u32)SOC_GetHostID(); + if(localIP != SOC_HtoNl(SOC_INADDR_ANY)) + { +#if !defined(AUTO_CONNECT) + SetNextMenuScreen(&msConnectedToInternet); +#else + u8 ip[IP_ALEN]; + SOInAddr dns1, dns2; + u8 mac[MAC_ALEN]; + + IP_GetAddr(NULL, ip); + OS_Printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + + IP_GetGateway (NULL, ip); + OS_Printf("Gateway: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + + SOC_GetResolver(&dns1, &dns2); + OS_Printf("DNS1: %s\n", inet_ntoa(dns1)); + OS_Printf("DNS2: %s\n", inet_ntoa(dns2)); + + IP_GetMacAddr(NULL, mac); + OS_Printf("MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + ExitMenu(); +#endif + } +} + +static void FailedToConnectToInternetInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->extraText[0], FailureReason, MAX_EXTRA_TEXT_STRING_LEN + 1); + screen->extraText[0][MAX_EXTRA_TEXT_STRING_LEN] = '\0'; +} + +static void FailedToConnectToInternetChose(const char * choice) +{ + if(choice == mscBack) + { +#if defined(SUPPORT_SAVED_CONFIGS) + if(SavedSettings.numConfigs > 0) + SetNextMenuScreen(&msSelectNetworkConfiguration); + else +#endif + SetNextMenuScreen(&msSearchingForNetworks); + } +} + +static void ConnectedToInternetInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + u8 ip[IP_ALEN]; + SOInAddr dns1, dns2; + u8 mac[MAC_ALEN]; + int line = 0; + + IP_GetAddr(NULL, ip); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " IP: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + IP_GetAlias(NULL, ip); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " Alias: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + IP_GetBroadcastAddr(NULL, ip); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " Broadcast: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + IP_GetNetmask (NULL, ip); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " Netmask: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + IP_GetGateway (NULL, ip); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " Gateway: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + SOC_GetResolver(&dns1, &dns2); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " DNS1: %s", inet_ntoa(dns1)); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " DNS2: %s", inet_ntoa(dns2)); + + IP_GetMacAddr(NULL, mac); + snprintf(screen->extraText[line++], MAX_EXTRA_TEXT_STRING_LEN, + " MAC: %02X-%02X-%02X-%02X-%02X-%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static void ConnectedToInternetChose(const char * choice) +{ + if(choice == mscContinue) + { +#if defined(SUPPORT_SAVED_CONFIGS) + if(BackupExists() && NewConfig && (SavedSettings.numConfigs < MAX_SAVED_CONFIGS)) + SetNextMenuScreen(&msSaveNetworkConfiguration); + else +#endif + ExitMenu(); + } +} + +static void SaveNetworkConfigurationInit(void) +{ + MenuScreen * screen = GetMenuScreen(); + + strncpy(screen->keyboardText, (const char *)APList[APIndex].ssid, MAX_KEYBOARD_TEXT_LEN); + screen->keyboardText[MAX_KEYBOARD_TEXT_LEN - 1] = '\0'; +} + +static void SaveNetworkConfigurationChose(const char * choice) +{ + MenuScreen * screen = GetMenuScreen(); + + if(choice == mscSave) + { + memcpy(SavedSettings.configs[SavedSettings.numConfigs].bssid, BSSID, IW_BSSID_SIZE); + memcpy(SavedSettings.configs[SavedSettings.numConfigs].wep, WEPKey, IW_WEP_SIZE); + strncpy(SavedSettings.configs[SavedSettings.numConfigs].name, screen->keyboardText, MAX_CONFIG_NAME_LEN); + SavedSettings.configs[SavedSettings.numConfigs].name[MAX_CONFIG_NAME_LEN - 1] = '\0'; + SavedSettings.numConfigs++; + SaveSettings(); + + SetNextMenuScreen(&msConfigurationSaved); + } + else if(choice == mscDontSave) + { + ExitMenu(); + } +} + +static void ConfigurationSavedChose(const char * choice) +{ + if(choice == mscContinue) + ExitMenu(); +} diff --git a/xrGameSpy/gamespy/common/nitro/wireless.h b/xrGameSpy/gamespy/common/nitro/wireless.h new file mode 100644 index 00000000000..18734eaafb2 --- /dev/null +++ b/xrGameSpy/gamespy/common/nitro/wireless.h @@ -0,0 +1,7 @@ +#ifndef _WIRELESS_H_ +#define _WIRELESS_H_ + +void WirelessInit(void); +void WirelessCleanup(void); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/Makefile b/xrGameSpy/gamespy/common/ps2/Makefile new file mode 100644 index 00000000000..9d7390f348c --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/Makefile @@ -0,0 +1,56 @@ +SHELL = /bin/sh +GOA = /usr/local/goa + +all: + cd $(GOA)/Chat/chatc/chatps2/ ; make clean + cd $(GOA)/Chat/chatc/chatps2/ ; make eenet + cd $(GOA)/Chat/chatc/chatps2/ ; make clean + cd $(GOA)/Chat/chatc/chatps2/ ; make snsystems + cd $(GOA)/ghttp/ghttpc/ghttpps2/ ; make clean + cd $(GOA)/ghttp/ghttpc/ghttpps2/ ; make eenet + cd $(GOA)/ghttp/ghttpc/ghttpps2/ ; make clean + cd $(GOA)/ghttp/ghttpc/ghttpps2/ ; make snsystems + cd $(GOA)/GP/gptestc/gpps2 ; make clean + cd $(GOA)/GP/gptestc/gpps2 ; make eenet + cd $(GOA)/GP/gptestc/gpps2 ; make clean + cd $(GOA)/GP/gptestc/gpps2 ; make snsystems + cd $(GOA)/gstats/statstest/gstatsps2 ; make clean + cd $(GOA)/gstats/statstest/gstatsps2 ; make eenet + cd $(GOA)/gstats/statstest/gstatsps2 ; make clean + cd $(GOA)/gstats/statstest/gstatsps2 ; make snsystems + cd $(GOA)/gstats/persisttest/persistps2 ; make clean + cd $(GOA)/gstats/persisttest/persistps2 ; make eenet + cd $(GOA)/gstats/persisttest/persistps2 ; make clean + cd $(GOA)/gstats/persisttest/persistps2 ; make snsystems + cd $(GOA)/gt2/gt2testc/gt2ps2 ; make clean + cd $(GOA)/gt2/gt2testc/gt2ps2 ; make eenet + cd $(GOA)/gt2/gt2testc/gt2ps2 ; make clean + cd $(GOA)/gt2/gt2testc/gt2ps2 ; make snsystems + cd $(GOA)/natneg/simpletest/natnegps2 ; make clean + cd $(GOA)/natneg/simpletest/natnegps2 ; make eenet + cd $(GOA)/natneg/simpletest/natnegps2 ; make clean + cd $(GOA)/natneg/simpletest/natnegps2 ; make snsystems + cd $(GOA)/Peer/peerc/peerps2 ; make clean + cd $(GOA)/Peer/peerc/peerps2 ; make eenet + cd $(GOA)/Peer/peerc/peerps2 ; make clean + cd $(GOA)/Peer/peerc/peerps2 ; make snsystems + cd $(GOA)/pt/pttestc/ptps2 ; make clean + cd $(GOA)/pt/pttestc/ptps2 ; make eenet + cd $(GOA)/pt/pttestc/ptps2 ; make clean + cd $(GOA)/pt/pttestc/ptps2 ; make snsystems + cd $(GOA)/qr2/qr2csample/qr2ps2 ; make clean + cd $(GOA)/qr2/qr2csample/qr2ps2 ; make eenet + cd $(GOA)/qr2/qr2csample/qr2ps2 ; make clean + cd $(GOA)/qr2/qr2csample/qr2ps2 ; make snsystems + cd $(GOA)/serverbrowsing/sbctest/sbps2 ; make clean + cd $(GOA)/serverbrowsing/sbctest/sbps2 ; make eenet + cd $(GOA)/serverbrowsing/sbctest/sbps2 ; make clean + cd $(GOA)/serverbrowsing/sbctest/sbps2 ; make snsystems + cd $(GOA)/Voice/voicetest/voicetestps2 ; make clean + cd $(GOA)/Voice/voicetest/voicetestps2 ; make eenet + cd $(GOA)/Voice/voicetest/voicetestps2 ; make clean + cd $(GOA)/Voice/voicetest/voicetestps2 ; make snsystems + cd $(GOA)/Voice/voicebench/voicebenchps2 ; make clean + cd $(GOA)/Voice/voicebench/voicebenchps2 ; make eenet + cd $(GOA)/Voice/voicebench/voicebenchps2 ; make clean + cd $(GOA)/Voice/voicebench/voicebenchps2 ; make snsystems diff --git a/xrGameSpy/gamespy/common/ps2/Makefile.common b/xrGameSpy/gamespy/common/ps2/Makefile.common new file mode 100644 index 00000000000..56e56e86dcc --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/Makefile.common @@ -0,0 +1,81 @@ +#GameSpy.net PS2 Makefile +#Included from sample-specific Makefiles + +SHELL = /bin/sh +SCE = /usr/local/sce +LIBDIR = $(SCE)/ee/lib +SYSINC = -I$(SCE)/ee/include -I$(SCE)/common/include +INCDIR = $(STACKINC) $(SYSINC) + +#the samples need this for EENet +ENTCNFDIR = $(SCE)/iop/sample/libeenet/ent_cnf +ENTCNF = $(ENTCNFDIR)/ent_cnf.irx + +LCFILE = $(LIBDIR)/app.cmd +LIBS = $(STACKLIB) \ + $(LIBDIR)/libdev.a \ + $(LIBDIR)/libgraph.a \ + $(LIBDIR)/libdma.a \ + $(LIBDIR)/libpkt.a \ + $(LIBDIR)/libcdvd.a \ + $(SDK_LIBS) + +snsystems: STACKLIB = $(LIBDIR)/sneetcp.a + +snsystems: STACKDEF = SN_SYSTEMS + +snsytems: STACKINC = + +eenet: STACKLIB = $(LIBDIR)/libeenet.a\ + $(LIBDIR)/eenetctl.a\ + $(LIBDIR)/ent_smap.a\ + $(LIBDIR)/ent_eth.a\ + $(LIBDIR)/ent_ppp.a\ + $(LIBDIR)/libscf.a + +eenet: STACKDEF = EENET + +eenet: STACKINC = -I$(SCE)/ee/include/libeenet/ + +PREFIX = ee +AS = $(PREFIX)-gcc +CC = $(PREFIX)-gcc +LD = $(PREFIX)-gcc +RUN = dsedb -r run +RM = /bin/rm -f + +CFLAGS = -g -O0 -Wall -Werror -Wa,-al -fno-common $(SDK_CFLAGS) +ASFLAGS = -c -xassembler-with-cpp -Wa,-al +LDFLAGS = -Wl,-Map,$(TARGET).map -mno-crt0 -L$(LIBDIR) -lm + +.SUFFIXES: .c .s + +all: FORCE + @echo type either make eenet or make snsystems + +$(TARGET).elf: $(OBJS) $(LIBS) + $(LD) -o $@ -T $(LCFILE) $(OBJS) $(STACKLIB) $(LIBS) $(LDFLAGS) + +crt0.o: $(LIBDIR)/crt0.s + $(AS) $(ASFLAGS) -o $@ $< > $*.lst + +.s.o: + $(AS) $(ASFLAGS) $(INCDIR) -o $@ $< > $*.lst + +.c.o: + $(CC) $(CFLAGS) -D$(STACKDEF) $(INCDIR) -c $< -o $*.o > $*.lst + +run: $(TARGET).elf + $(RUN) $(TARGET).elf + +snsystems: $(TARGET).elf + +$(ENTCNF): + cd $(ENTCNFDIR) ; make + +eenet: $(ENTCNF) $(TARGET).elf + +clean: + $(RM) $(OBJS) *.o *.map *.lst core *.dis *.elf + +FORCE: diff --git a/xrGameSpy/gamespy/common/ps2/changelog.txt b/xrGameSpy/gamespy/common/ps2/changelog.txt new file mode 100644 index 00000000000..c5199f9afa4 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/changelog.txt @@ -0,0 +1,47 @@ +Changelog for: PS2 Common Code +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +06-03-2005 1.05.19 SN RELEASE Releasing to developer site. +04-28-2005 1.05.19 SN RELEASE Releasing to developer site. +04-04-2005 1.05.19 SN RELEASE Releasing to developer site. +09-16-2004 1.05.19 SN RELEASE Releasing to developer site. +08-05-2004 1.05.19 SN RELEASE Releasing to developer site. +07-23-2004 1.05.19 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors.(ps2pad.c) +07-19-2004 1.05.18 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors.(ps2common.c) +07-14-2004 1.05.17 DES CLEANUP Updated and unified IRX module loading code. + FEATURE Added loading of IRX modules needed by GV SPU2 code. +06-22-2004 1.05.16 BED FEATURE Added PS2 Insock support +06-22-2004 1.05.15 DES FEATURE Add loading of Logitech video library for EyeToy support in GV. +06-08-2003 1.05.14 DES RELEASE Limited developer release (for GV) +04-22-2004 1.05.14 DES FEATURE Added ps2pad.c/h for getting input events from the controller. +10-21-2003 1.05.13 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) + BED FIX Removed misc compiler warnings on strict setting. +10-09-2003 1.05.13 BED FIX DHCP override settings defined but not used. Now passed into init call. +07-24-2003 1.05.12 DES RELEASE Releasing to developer site. +07-24-2003 1.05.12 DES FEATURE Added a Makefile for building all projects with gcc. + FEATURE Added a ProDG workspace that includes all the sample app projects. + FEATURE Added a CodeWarrior workspace that includes all the sample app projects. +07-23-2003 1.05.11 DES FIX Removed unneeded headers from ps2common.c which were causing warnings. + CLEANUP Removed EENet 2.6.0 compatibility. + CLEANUP Changed most printf()s in ps2common.c to scePrintf(). +07-21-2003 1.05.10 DES FIX Updated the gcc Makefile.common to automatically build the + ent_cnf.irx when making for EENet. +07-17-2003 1.05.09 DES FEATURE Put PS2 test app common Makefile code into Makefile.common. + It is then included from all the SDK-specific Makefiles. +07-16-2003 1.05.08 DES FIX EENet will no longer lockup if it can't load an irx module. + CLEANUP Removed Cisco NFT support. +02-25-2003 1.05.07 DES CLEANUP Changed sceEENetInit() for 2.6.1 EENet compatibility. + EENET_260 can be defined for 2.6.0 compatibility. +01-02-2003 1.05.06 DES FIX Added needed defines for modem support. + CLEANUP Removed references to ent_cnf.h and ent_cnf.irx. +12-18-2002 1.05.05 DES CLEANUP Updated SN Systems stack support. +12-13-2002 1.05.04 DES FEATURE Added PS2 eenet stack support. +12-05-2002 1.05.03 DES CLEANUP General cleanup + FEATURE Initial PS2 eenet stack support +11-20-2002 1.05.02 DES FEATURE Updated to use new Unique ID code. +11-14-2002 1.05.01 DES OTHER Updated the IOPIMAGE define to IOPRP255.IMG from IOPRP250.IMG +09-25-2002 1.05.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/common/ps2/cw/LinkSegment_PS2.lcf b/xrGameSpy/gamespy/common/ps2/cw/LinkSegment_PS2.lcf new file mode 100644 index 00000000000..bed58f27eef --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/LinkSegment_PS2.lcf @@ -0,0 +1,161 @@ +# =========================================================================== +# LinkSegment_PS2.lcf �1999-2000 Metrowerks Inc. All rights reserved. +# =========================================================================== +# +# linker command file for PS2 +# +# 06/09/2000 kashima, put dummy nop after .text section +# 06/09/2000 kashima, change default entry address +# 02/10/2000 kashima, add ALIGNALL before each section +# 01/15/2000 kashima, support overlay by lcf generator +# 11/03/1999 kashima, for SDK 1.10 +# 10/22/1999 kashima, change file extention from txt to lcf +# 10/20/1999 kashima, put all sections into main +# 10/12/1999 kashima, separate each sections +# 09/14/1999 kashima, +# +# =========================================================================== + +MEMORY +{ + main (RWX) : ORIGIN = 0x100000, LENGTH = 0x0 + heap (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 +} + +#FORCE_ACTIVE +#{ +#} + +KEEP_SECTION +{ + .vutext, + .vudata, + .vubss +} + +#REF_INCLUDE +#{ + +SECTIONS +{ + # define for crt0 + _heap_size = -1; + _stack = -1; + _stack_size = 0x00100000; + # define for lcf + _align_segment = 0x80; + + .main : + { + # text sections + . = ALIGN(0x80); + crt0.s (.text) + . = ALIGN(0x10); + ALIGNALL(0x8); + GROUP(ROOT) (.text) + WRITEW 0x0; # text section patch for EE pipeline + WRITEW 0x0; # text section patch for EE pipeline + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.vutext) + + # .reginfo + crt0.s (.reginfo) + + # data sections + __data_start = .; + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.data) + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.vudata) + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.rodata) + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.rdata) + + # static initializers + . = ALIGN(0x10); + ALIGNALL(0x4); + GROUP(ROOT) (.init) + . = ALIGN(0x10); + ALIGNALL(0x4); + __static_init = .; + GROUP(ROOT) (.ctor) + __static_init_end = .; + + # .vtables + . = ALIGN(0x10); + ALIGNALL(0x4); + * (.vtables) + + # exception table + . = ALIGN(0x10); + __exception_table_start__ = .; + __exception_table_end__ = .; + + # addresses for each overlay module + . = ALIGN(0x10); + _overlay_group_addresses = .; + WRITEW ADDR(.main); # + + __data_end = .; + __data_size = __data_end - __data_start; + + # the address of gp register + _gp = ALIGN(128) + 0x7FF0; + + # literal + . = ALIGN(0x80); + ALIGNALL(0x8); + LITERAL + + # small data sections + . = ALIGN(0x80); + ALIGNALL(0x4); + * (.sdata) + . = ALIGN(0x80); + _fbss = .; + ALIGNALL(0x4); + * (.sbss) + ALIGNALL(0x4); + * (.scommon) + ALIGNALL(0x4); + * (SCOMMON) + + # bss sections + __bss_start = .; + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.bss) + ALIGNALL(0x8); + GROUP(ROOT) (.common) + ALIGNALL(0x8); + GROUP(ROOT) (COMMON) + . = ALIGN(0x80); + ALIGNALL(0x8); + GROUP(ROOT) (.vubss) + ALIGNALL(0x8); + __bss_end = .; + __bss_size = __bss_end - __bss_start; + + . = ALIGN(_align_segment); + + } > main + + .heap : + { + # to get the address for heap + end = .; + _end = .; + } > heap + + +} + +# =========================================================================== +# end of lcf (auto-generated by pre-linker for PS2) +# =========================================================================== diff --git a/xrGameSpy/gamespy/common/ps2/cw/PREFIX_PS2_DEBUG_TC296.h b/xrGameSpy/gamespy/common/ps2/cw/PREFIX_PS2_DEBUG_TC296.h new file mode 100644 index 00000000000..e28c214452d --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/PREFIX_PS2_DEBUG_TC296.h @@ -0,0 +1,12 @@ +// =========================================================================== +// PREFIX_PS2_DEBUG_TC296.h (c) 2001 Metrowerks Inc. All rights reserved. +// =========================================================================== +// +// 08/02/2001 rcampana Created for support of GCC toolchain 2.96 + +#include + +#pragma divbyzerocheck on /* break if divided by zero */ + +#define DEBUG /* just for debugging */ + diff --git a/xrGameSpy/gamespy/common/ps2/cw/PREFIX_PS2_RELEASE_TC296.h b/xrGameSpy/gamespy/common/ps2/cw/PREFIX_PS2_RELEASE_TC296.h new file mode 100644 index 00000000000..b2643417970 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/PREFIX_PS2_RELEASE_TC296.h @@ -0,0 +1,11 @@ +// =========================================================================== +// PREFIX_PS2_TC296.h �2000-2001 Metrowerks Inc. All rights reserved. +// =========================================================================== +// +// 08/02/2001 rcampana Created for support of GCC toolchain 2.96 + +#include + +#define NDEBUG /* just for debugging */ + +#pragma cats off \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cw.cww b/xrGameSpy/gamespy/common/ps2/cw/cw.cww new file mode 100644 index 00000000000..f3df402ff69 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cw.cww @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + -1 + 0 + true + ..\..\Chat\chatc\chatps2cw\chatps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\ghttp\ghttpc\ghttpps2cw\ghttpps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\GP\gptestc\gpps2cw\gpps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\gstats\statstest\gstatsps2cw\gstatsps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\gstats\persisttest\persistps2cw\persistps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\gt2\gt2testc\gt2ps2cw\gt2ps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\NATNEG\simpletest\natnegps2cw\natnegps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\peer\peerc\peerps2cw\peerps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\pt\pttestc\ptps2cw\ptps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\QR2\qr2csample\qr2ps2cw\qr2ps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\SERVERBROWSING\SBCTEST\sbps2cw\sbps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\Voice\voicetest\voicetestps2cw\voicetestps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + + -1 + 0 + ..\..\Voice\voicebench\voicebenchps2cw\voicebenchps2cw.mcp + + 30 + 30 + + + 400 + 200 + + + 1 + 0 + 0 + 59420 + 1.000000 + 425 + + -2 + -2 + + + + diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_debug.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_debug.h new file mode 100644 index 00000000000..131b541e1af --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_debug.h @@ -0,0 +1,6 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" + +#define EENET +#define _DEBUG +//#define GSI_UNICODE +//#pragma ushort_wchar_t on \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_debug_uniqueid.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_debug_uniqueid.h new file mode 100644 index 00000000000..264b4f63c87 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_debug_uniqueid.h @@ -0,0 +1,5 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" + +#define EENET +#define _DEBUG +#define UNIQUEID \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_release.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_release.h new file mode 100644 index 00000000000..c7649701138 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_release.h @@ -0,0 +1,5 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" + +#define EENET +//#define GSI_UNICODE +//#pragma ushort_wchar_t on \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_release_uniqueid.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_release_uniqueid.h new file mode 100644 index 00000000000..996d90e598b --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_eenet_release_uniqueid.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" + +#define EENET +#define UNIQUEID \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_debug.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_debug.h new file mode 100644 index 00000000000..3fbc9793e7c --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_debug.h @@ -0,0 +1,6 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" + +#define INSOCK +#define _DEBUG +//#define GSI_UNICODE +//#pragma ushort_wchar_t on \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_debug_uniqueid.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_debug_uniqueid.h new file mode 100644 index 00000000000..f18119251aa --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_debug_uniqueid.h @@ -0,0 +1,5 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" + +#define INSOCK +#define _DEBUG +#define UNIQUEID \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_release.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_release.h new file mode 100644 index 00000000000..46220a81eb7 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_release.h @@ -0,0 +1,5 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" + +#define INSOCK +//#define GSI_UNICODE +//#pragma ushort_wchar_t on \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_release_uniqueid.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_release_uniqueid.h new file mode 100644 index 00000000000..1db3bb293e7 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_insock_release_uniqueid.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" + +#define INSOCK +#define UNIQUEID \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_debug.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_debug.h new file mode 100644 index 00000000000..81b86d14864 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_debug.h @@ -0,0 +1,6 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" + +#define SN_SYSTEMS +#define _DEBUG +//#define GSI_UNICODE +//#pragma ushort_wchar_t on \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_debug_uniqueid.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_debug_uniqueid.h new file mode 100644 index 00000000000..83f1f9d065a --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_debug_uniqueid.h @@ -0,0 +1,5 @@ +#include "PREFIX_PS2_DEBUG_TC296.h" + +#define SN_SYSTEMS +#define _DEBUG +#define UNIQUEID \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_release.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_release.h new file mode 100644 index 00000000000..6f4e4955347 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_release.h @@ -0,0 +1,5 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" + +#define SN_SYSTEMS +//#define GSI_UNICODE +//#pragma ushort_wchar_t on \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_release_uniqueid.h b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_release_uniqueid.h new file mode 100644 index 00000000000..42c0791fe5d --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/cw/cwprefix_snsystems_release_uniqueid.h @@ -0,0 +1,4 @@ +#include "PREFIX_PS2_RELEASE_TC296.h" + +#define SN_SYSTEMS +#define UNIQUEID \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/LinkSegment_PS2IOP.lcf b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/LinkSegment_PS2IOP.lcf new file mode 100644 index 00000000000..bc865d96363 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/LinkSegment_PS2IOP.lcf @@ -0,0 +1,78 @@ +#=========================================================================== +# LinkSegment_PS2IOP.lcf �1999-2003 Metrowerks Inc. All rights reserved. +#=========================================================================== +# +# Linker command file for PS2 IOP +# +#=========================================================================== + +MEMORY +{ + .text (RWX) : ORIGIN = 0x00000000, LENGTH = 0x00 + .data (RW) : ORIGIN = AFTER(.text), LENGTH = 0x00 + .bss (RW) : ORIGIN = AFTER(.data), LENGTH = 0X00 +} + +FORCE_ACTIVE{Module} + +SECTIONS +{ + .text : + { + . = ALIGN(0x10); + _ftext = .; + + # begin text section + * (.text) + * (.common) + * (.scommon) + # end of text section + + # align so that size of segment is 16 byte aligned + . = ALIGN(0x10); + _etext = .; + etext = .; + } > .text + + .data : + { + . = ALIGN(0x10); + _fdata = .; + + # start data section + * (.rodata) + * (.data) + _gp = ALIGN(0x10) + 0x7FF0; + * (.sdata) + # literal + LITERAL + + # end data section + + + # align so that size of segment is 16 byte aligned + . = ALIGN(0x10); + _edata = .; + edata = .; + + } > .data + + .bss : + { + . = ALIGN(0x10); + _fbss = .; + + # start bss section + * (.bss) + * (.sbss) + # end bss section + + # align so that size of segment is 16 byte aligned + . = ALIGN(0x10); + end = .; + _end = .; + + } > .bss +} + +#=========================================================================== diff --git a/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/PREFIX_PS2IOP_DEBUG.h b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/PREFIX_PS2IOP_DEBUG.h new file mode 100644 index 00000000000..b810f12baf1 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/PREFIX_PS2IOP_DEBUG.h @@ -0,0 +1,13 @@ +// =========================================================================== +// PREFIX_PS2_DEBUG.h �2000 Metrowerks Inc. All rights reserved. +// =========================================================================== +// +// 07/18/2000 james combs, for SDK1.6 + + +#include + +#pragma divbyzerocheck on /* break if divided by zero */ + +#define DEBUG /* just for debugging */ + diff --git a/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/PREFIX_PS2IOP_RELEASE.h b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/PREFIX_PS2IOP_RELEASE.h new file mode 100644 index 00000000000..3e650b58c5d --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/PREFIX_PS2IOP_RELEASE.h @@ -0,0 +1,9 @@ +// =========================================================================== +// PREFIX_PS2_RELEASE.h �2000 Metrowerks Inc. All rights reserved. +// =========================================================================== +// +// 07/18/2000 james combs, for SDK1.6 + +#include + +#define NDEBUG \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/ent_cnf.mcp b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/ent_cnf.mcp new file mode 100644 index 00000000000..b70c80076f0 Binary files /dev/null and b/xrGameSpy/gamespy/common/ps2/ent_cnf/cw/ent_cnf.mcp differ diff --git a/xrGameSpy/gamespy/common/ps2/ent_cnf/prodg/ent_cnf.dsp b/xrGameSpy/gamespy/common/ps2/ent_cnf/prodg/ent_cnf.dsp new file mode 100644 index 00000000000..a012bfd4bd9 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ent_cnf/prodg/ent_cnf.dsp @@ -0,0 +1,119 @@ +# Microsoft Developer Studio Project File - Name="ent_cnf" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ent_cnf - Win32 PS2 IOP Release +!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 "ent_cnf.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 "ent_cnf.mak" CFG="ent_cnf - Win32 PS2 IOP Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ent_cnf - Win32 PS2 IOP Debug" (based on "Win32 (x86) Application") +!MESSAGE "ent_cnf - Win32 PS2 IOP Release" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/ps2common/ent_cnf/prodg", UXEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ent_cnf - Win32 PS2 IOP Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ent_cnf___Win32_PS2_IOP_Debug" +# PROP BASE Intermediate_Dir "ent_cnf___Win32_PS2_IOP_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "ent_cnf___Win32_PS2_IOP_Debug" +# PROP Intermediate_Dir "ent_cnf___Win32_PS2_IOP_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\sample\libeenet\ent_cnf" /D "SN_TARGET_PS2_IOP" /Fo"PS2_IOP_Debug/" /FD -G0 /debug /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 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 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 eenetctl.ilb netcnf.ilb C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.o /nologo /pdb:none /debug /machine:IX86 /out:"c:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnf.irx" /D:SN_TARGET_PS2_IOP +# Begin Special Build Tool +SOURCE="$(InputPath)" +PreLink_Cmds=ioplibgen C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnf.tbl -e C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.s ps2cc -iop -o C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.o C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.s +# End Special Build Tool + +!ELSEIF "$(CFG)" == "ent_cnf - Win32 PS2 IOP Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ent_cnf___Win32_PS2_IOP_Release" +# PROP BASE Intermediate_Dir "ent_cnf___Win32_PS2_IOP_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "ent_cnf___Win32_PS2_IOP_Release" +# PROP Intermediate_Dir "ent_cnf___Win32_PS2_IOP_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\sample\libeenet\ent_cnf" /D "SN_TARGET_PS2_IOP" /Fo"PS2_IOP_Release/" /FD -G0 /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 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 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 eenetctl.ilb netcnf.ilb C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.o /nologo /pdb:none /machine:IX86 /out:"c:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnf.irx" /D:SN_TARGET_PS2_IOP +# Begin Special Build Tool +SOURCE="$(InputPath)" +PreLink_Cmds=ioplibgen C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnf.tbl -e C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.s ps2cc -iop -o C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.o C:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnfent.s +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "ent_cnf - Win32 PS2 IOP Debug" +# Name "ent_cnf - Win32 PS2 IOP Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=c:\usr\local\sce\iop\sample\libeenet\ent_cnf\ent_cnf.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=c:\usr\local\sce\iop\sample\libeenet\ent_cnf\ioptypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\prodg\PS2_in_VC.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/common/ps2/ent_cnf/prodg/ent_cnf.dsw b/xrGameSpy/gamespy/common/ps2/ent_cnf/prodg/ent_cnf.dsw new file mode 100644 index 00000000000..3a68ef0aa3e --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ent_cnf/prodg/ent_cnf.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ent_cnf"=.\ent_cnf.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ps2common/ent_cnf/prodg", UXEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ps2common/ent_cnf/prodg", UXEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/common/ps2/gsSocketPs2.c b/xrGameSpy/gamespy/common/ps2/gsSocketPs2.c new file mode 100644 index 00000000000..f99d509c556 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/gsSocketPs2.c @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gscommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// INSOCK +#if defined(INSOCK) +#define INSOCK_MAX_UDP_BUFSIZE 8000000 // default max +#define INSOCK_MAX_TCP_BUFSIZE 32000 + +extern sceSifMClientData gGSIInsockClientData; +extern u_int gGSIInsockSocketBuffer[NETBUFSIZE] __attribute__((aligned(64))); + +// NOT FULLY IMPLEMENTED +int SetReceiveBufferSize(SOCKET sock, int size) +{return -1; GSI_UNUSED(sock); GSI_UNUSED(size); } + +// NOT FULLY IMPLEMENTED +int SetSendBufferSize(SOCKET sock, int size) +{return -1; GSI_UNUSED(sock); GSI_UNUSED(size); } + +int GetReceiveBufferSize(SOCKET sock) +{return NETBUFSIZE; GSI_UNUSED(sock); } + +int GetSendBufferSize(SOCKET sock) +{return NETBUFSIZE; GSI_UNUSED(sock); } + +// Poll socket for Send, Recv and Except +int GSISocketSelect(SOCKET theSocket, int* theReadFlag, int* theWriteFlag, int* theExceptFlag) +{ + int result = 0; + sceInetPollFd_t aPollFdSet; + + // Init the flags to 0 + if ((theReadFlag != NULL)) + *theReadFlag = 0; + if ((theWriteFlag != NULL)) + *theWriteFlag = 0; + if ((theExceptFlag != NULL)) + *theExceptFlag = 0; + + // Setup the fd set + aPollFdSet.cid = theSocket; // the socket + aPollFdSet.events = 0; // events in + aPollFdSet.revents = 0; // events out + + if (theReadFlag != NULL) aPollFdSet.events |= sceINET_POLLIN; + if (theWriteFlag != NULL) aPollFdSet.events |= sceINET_POLLOUT; + if (theExceptFlag != NULL) aPollFdSet.events |= sceINET_POLLERR; + + // Poll the fds + // 1 fds, 0 ms timeout + result = sceInsockPoll(&aPollFdSet, 1, 0); + if (result > 0) + { + // If the Flag is valid, set the return value + if ((theReadFlag != NULL)) + *theReadFlag = (aPollFdSet.revents & sceINET_POLLIN) ? 1:0; + if ((theWriteFlag != NULL)) + *theWriteFlag = (aPollFdSet.revents & sceINET_POLLOUT) ? 1:0; + if ((theExceptFlag != NULL)) + *theExceptFlag = (aPollFdSet.revents & sceINET_POLLERR) ? 1:0; + } + return result; +} + +// shutdown needs to have a timeout that can be done +// right before shutting down +int gsiShutdown(SOCKET s, int how) +{ + // set the shutdown timeout to thirty milliseconds based on most games running + // thirty frames per second (33ms rounded down to 30) + sceInsockSetShutdownTimeout(s, 30); + return sceInsockShutdown(s, how); +} +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/gsThreadPs2.c b/xrGameSpy/gamespy/common/ps2/gsThreadPs2.c new file mode 100644 index 00000000000..89594dbbac8 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/gsThreadPs2.c @@ -0,0 +1,204 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gscommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 gsiInterlockedIncrement(gsi_u32 * value) +{ + int interrupt = DI(); + int ret = ++(*value); + if (interrupt) + EI(); + + // return "ret" rather than "value" here b/c + // value may be modified by another thread + // before we can return it + return ret; +} + +gsi_u32 gsiInterlockedDecrement(gsi_u32 * value) +{ + int interrupt = DI(); + int ret = --(*value); + if (interrupt) + EI(); + + // return "ret" rather than "value" here b/c + // value may be modified by another thread + // before we can return it + return ret; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) +{ + theCrit->mSemaphore = gsiCreateSemaphore(1, 1, NULL); + theCrit->mOwnerThread = 0; + theCrit->mEntryCount = 0; +} +void gsiEnterCriticalSection(GSICriticalSection *theCrit) +{ + // If we're not already in it, wait for it + if (GetThreadId() != theCrit->mOwnerThread) + { + gsiWaitForSemaphore(theCrit->mSemaphore, 0); + theCrit->mOwnerThread = GetThreadId(); + } + + // Increment entry count + theCrit->mEntryCount++; +} +void gsiLeaveCriticalSection(GSICriticalSection *theCrit) +{ + // We must be the owner? (assert?) + if (GetThreadId() != theCrit->mOwnerThread) + { + assert(GetThreadId() == theCrit->mOwnerThread); + return; + } + + // Release semaphore + theCrit->mEntryCount--; + if (theCrit->mEntryCount == 0) + { + theCrit->mOwnerThread = 0; + gsiReleaseSemaphore(theCrit->mSemaphore, 1); + } +} + +void gsiDeleteCriticalSection(GSICriticalSection *theCrit) +{ + gsiCloseSemaphore(theCrit->mSemaphore); +} + +gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID) +{ + struct ThreadParam aStatus; + ReferThreadStatus(theThreadID, &aStatus); + if (aStatus.status == THS_DORMANT) + return 1; // dead + else + return 0; // still kicking; +} + +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + struct SemaParam aParam; + int aSemaphore = 0; + + aParam.initCount = theInitialCount; + aParam.maxCount = theMaxCount; + + aSemaphore = CreateSema(&aParam); + if (aSemaphore < 0) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create semaphore\r\n"); + } + + GSI_UNUSED(theName); + + return aSemaphore; +} + +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + int result = WaitSema(theSemaphore); + return (gsi_u32)result; + + GSI_UNUSED(theTimeoutMs); +} + +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + while (theReleaseCount-- > 0) + SignalSema(theSemaphore); + //ReleaseSemaphore(theSemaphore, theReleaseCount, NULL); +} + +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + DeleteSema(theSemaphore); +} + +int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID *id) +{ + const unsigned int stackSize = theStackSize; + const int threadPriority = 3; + struct ThreadParam param; + void * stack; + int threadID; + + // allocate a stack + stack = gsimemalign(16, stackSize); + if(!stack) + return -1; + + // setup the thread parameters + param.entry = func; + param.stack = stack; + param.stackSize = (int)stackSize; + param.gpReg = &_gp; + param.initPriority = threadPriority; + + // create the thread + threadID = CreateThread(¶m); + if(threadID == -1) + { + gsifree(stack); + return -1; + } + + // start the thread + if(StartThread(threadID, arg) == -1) + { + DeleteThread(threadID); + gsifree(stack); + return -1; + } + + // store the id + *id = threadID; + + // Note: This was added to prevent PS2 lockups when starting multiple threads + // The PS2 would block for approx 5 seconds + msleep(1); + + return 0; +} + +void gsiCancelThread(GSIThreadID id) +{ + void* aStack = NULL; + + // get the stack ptr + struct ThreadParam aThreadParam; + ReferThreadStatus(id, &aThreadParam); + aStack = (void*)aThreadParam.stack; + + // terminate the thread + TerminateThread(id); + + // delete the thread + DeleteThread(id); + + //free the stack + gsifree(aStack); +} + +// This must be called from INSIDE the thread you wish to exit +void gsiExitThread(GSIThreadID id) +{ + // TODO: does PS2 need to explicitly EXIT a thread like win32/linux? + GSI_UNUSED(id); +} + +void gsiCleanupThread(GSIThreadID id) +{ + // same as cancel (terminates just to be sure) + gsiCancelThread(id); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/gsUtilPs2.c b/xrGameSpy/gamespy/common/ps2/gsUtilPs2.c new file mode 100644 index 00000000000..71b10415274 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/gsUtilPs2.c @@ -0,0 +1,15 @@ +#include "../gsCommon.h" + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return atol(theNumberStr); +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%ld", theNumber); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/ps2/prodg/PS2_in_VC.h b/xrGameSpy/gamespy/common/ps2/prodg/PS2_in_VC.h new file mode 100644 index 00000000000..c1aa1d86f66 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/prodg/PS2_in_VC.h @@ -0,0 +1,45 @@ +// +// The purpose of this file is to, as much as possible, facilitate the +// compilation of the PS2 GNU files by the VC6 compiler. Not all problems +// can be solved via this file. So far, a couple of hacks are required +// directly within the headers themselves. +// + +// +// This will nullify all of the GNU compiler's __attribute__ things. +// +#define __attribute__(a) + +// +// This will prevent an Endian not defined error. +// +#define __IEEE_LITTLE_ENDIAN + +// +// This will prevent a size_t redefinition error. +// +#define __size_t__ + +// +// This will prevent errors by headers which use u_long128. Obviously +// the type defined below is only 32 bits, but (1) this is what the real +// headers seem to do in the GNU compiler and more importantly (2) it works! +// +typedef unsigned int u_long128; + + +#define long _int64 + +#define INLINE __inline + +#define size_t int + +#define __asm__ asm + +#define __volatile__ + +#define asm(a) asm() + +#define inline + +#define volatile diff --git a/xrGameSpy/gamespy/common/ps2/prodg/prodg.dsw b/xrGameSpy/gamespy/common/ps2/prodg/prodg.dsw new file mode 100644 index 00000000000..5a3e33c310a --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/prodg/prodg.dsw @@ -0,0 +1,229 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "chatps2prodg"=..\..\Chat\chatc\chatps2prodg\chatps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat/chatc/chatps2prodg", DSEDAAAA + ..\..\chat\chatc\chatps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ghttpps2prodg"=..\..\ghttp\ghttpc\ghttpps2prodg\ghttpps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp/ghttpc/ghttpps2prodg", JSEDAAAA + ..\..\ghttp\ghttpc\ghttpps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gpps2prodg"=..\..\GP\gptestc\gpps2prodg\gpps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/GP/gptestc/gpps2prodg", PSEDAAAA + ..\..\gp\gptestc\gpps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gstatsps2prodg"=..\..\gstats\statstest\gstatsps2prodg\gstatsps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/statstest/gstatsps2prodg", VSEDAAAA + ..\..\gstats\statstest\gstatsps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2ps2prodg"=..\..\gt2\gt2testc\gt2ps2prodg\gt2ps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2testc/gt2ps2prodg", XREDAAAA + ..\..\gt2\gt2testc\gt2ps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gvps2prodg"=..\..\Voice2\Voice2Test\gvps2prodg\gvps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Voice2/Voice2Test/gvps2prodg", XPODAAAA + ..\..\voice2\voice2test\gvps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "natnegps2prodg"=..\..\NATNEG\simpletest\natnegps2prodg\natnegps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/natneg/simpletest/natnegps2prodg", HTEDAAAA + ..\..\natneg\simpletest\natnegps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "peerps2prodg"=..\..\peer\peerc\peerps2prodg\peerps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer/peerc/peerps2prodg", NTEDAAAA + ..\..\peer\peerc\peerps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "persistps2prodg"=..\..\gstats\persisttest\persistps2prodg\persistps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/persisttest/persistps2prodg", BTEDAAAA + ..\..\gstats\persisttest\persistps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ptps2prodg"=..\..\pt\pttestc\ptps2prodg\ptps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pt/pttestc/ptps2prodg", TTEDAAAA + ..\..\pt\pttestc\ptps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "qr2ps2prodg"=..\..\QR2\qr2csample\qr2ps2prodg\qr2ps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/qr2/qr2csample/qr2ps2prodg", ZTEDAAAA + ..\..\qr2\qr2csample\qr2ps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "sbps2prodg"=..\..\SERVERBROWSING\SBCTEST\sbps2prodg\sbps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing/sbctest/sbps2prodg", FUEDAAAA + ..\..\serverbrowsing\sbctest\sbps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "voice2benchps2prodg"=..\..\Voice2\voice2bench\voice2benchps2prodg\voice2benchps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/Voice2/voice2bench/voice2benchps2prodg + ..\..\voice2\voice2bench\voice2benchps2prodg + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ps2common/prodg", DVEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/common/ps2/prodg/ps2.lk b/xrGameSpy/gamespy/common/ps2/prodg/ps2.lk new file mode 100644 index 00000000000..826c59f71d3 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/prodg/ps2.lk @@ -0,0 +1,88 @@ +; SN Systems default linker script for PS2. +; Updated for libraries 1.6.0 by Gil + +; Default libraries. (Supply others on the command line.) + + inclib libc.a + inclib libkernl.a + inclib libgcc.a + inclib libm.a + + +; The heap size and stack details are defined here. + +_heap_size equ 0xffffffff +_stack equ 0xffffffff +_stack_size equ 0x00100000 + + +; Groups represent entries in the output ELF's program headers table. +; Each contains one or more sections. +; A group only appears in the PHDRS table if it is named and has +; nonzero size. + + +; This group is for the program's code and initialised data. + + org 0x00100000 + +text group + + sectalign 8 + section .text,text + section .vutext,text + + sectalign 16 + section .data,text + section.128 .vudata,text + section .rodata,text + section .rdata,text + section .gcc_except_table,text + +; Collect everything else which is part of the image here. +; (Subsequent section directives get a chance to collect contents first.) + + section *,text + +; Set the GP register's value. +; The total size of these sections (from .lit8 to .scommon) cannot +; exceed 64K. + +_gp equ __lit8_obj+0x7FF0 + + section .lit8,text + section .lit4,text + section .sdata,text + + +; This group is for uninitialised data + +bss group bss + + +; This is the start marker for the startup code's zeroing routine. + +_fbss equ _bss_obj + +; These sections are to be zeroised by crt0.o. + + section .sbss,bss + section .scommon,bss + section .bss,bss + section.128 .vubss,bss + + +; This is crt0.o's marker for the start of the heap. + +_end equ _bss_objend + + +; This group is for the scratchpad. + + org 0x70000000 + +spad group + + sectalign 4 + + section .spad,spad diff --git a/xrGameSpy/gamespy/common/ps2/ps2common.c b/xrGameSpy/gamespy/common/ps2/ps2common.c new file mode 100644 index 00000000000..248a7659fb2 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ps2common.c @@ -0,0 +1,876 @@ +#include "../gsCommon.h" + +// One of the following network devices must be defined +#if 0 +#define T10K_ETHERNET +#endif +#if 0 +#define USB_ETHERNET +#endif +#if 0 +#define USB_ETHERNET_WITH_PPPOE +#endif +#if 1 +#define HDD_ETHERNET +#endif +#if 0 +#define HDD_ETHERNET_WITH_PPPOE +#endif +#if 0 +#define MODEM +#endif + +// attempts to load a module +static int load_module(const char * filename, int args, const char * argp) +{ + int result; + + result = sceSifLoadModule(filename, args, argp); + if(result < 0) + { + const char * errorString; + if(result == -100) + errorString = "Called from exception handler / interrupt handler"; + else if(result == -200) + errorString = "Resident library required by loaded module does not exist"; + else if(result == -201) + errorString = "Object file format is invalid"; + else if(result == -203) + errorString = "Specified file was not found"; + else if(result == -204) + errorString = "Error occurred when reading file"; + else if(result == -400) + errorString = "Insufficient memory"; + else if(result == -0x10000) + errorString = "Binding to the IOP module failed."; + else if(result == -0x10001) + errorString = "RPC to the IOP failed."; + else if(result == -0x10004) + errorString = "The IOP module version does not match."; + else + errorString = "Unknown error"; + scePrintf("FAILED TO LOAD MODULE: %s\n", filename); + scePrintf("\t(%d:%s)\n", result, errorString); + while(1) + msleep(1); + } + + return result; +} + +#define SCEROOT "host0:/usr/local/sce/" +#define MODROOT SCEROOT "iop/modules/" +#define APPROOT SCEROOT "conf/neticon/english/" + +// SN Systems stack +#ifdef SN_SYSTEMS + +// these only need to be set if using DHCP +// up to four DNS servers can be specified, and the list must be terminated with an empty string +#define SNPS2_IP_ADDR "0.0.0.0" +#define SNPS2_SUB_MSK "0.0.0.0" +#define SNPS2_GATEWAY "0.0.0.0" +static const sn_char* dns_servers[] = { "" }; + +static void load_network_modules() +{ + // load the TCP/IP stack module +#ifndef _DEBUG + load_module(MODROOT "snstkrel.irx", 0, NULL); +#else + const char iop_params[] + = SNPS2_IP_ADDR "\x00" SNPS2_SUB_MSK "\x00" SNPS2_GATEWAY; + + load_module(MODROOT "snstkdbg.irx", sizeof(iop_params), (char*) iop_params); +#endif + + // load device specific module(s) +#if defined(T10K_ETHERNET) + load_module(MODROOT "sndrv000.irx", 0, NULL); + +#elif defined(USB_ETHERNET) + load_module(MODROOT "usbd.irx", 0, NULL); + #if defined(USB_LUCENT) + load_module(MODROOT "sndrv002.irx", 0, NULL); + #elif defined(USB_CONEXANT) + load_module(MODROOT "sndrv003.irx", 0, NULL); + #else + load_module(MODROOT "sndrv001.irx", 0, NULL); + #endif + +#elif defined(USB_ETHERNET_WITH_PPPOE) + load_module(MODROOT "usbd.irx", 0, NULL); + load_module(MODROOT "sndrv200.irx", 0, NULL); + load_module(MODROOT "sndrv201.irx", 0, NULL); + +#elif defined(HDD_ETHERNET) + load_module(MODROOT "dev9.irx", 0, NULL); + load_module(MODROOT "sndrv100.irx", 0, NULL); + load_module(MODROOT "smap.irx", 0, NULL); + +#elif defined(HDD_ETHERNET_WITH_PPPOE) + load_module(MODROOT "dev9.irx", 0, NULL); + load_module(MODROOT "sndrv200.irx", 0, NULL); + load_module(MODROOT "sndrv202.irx", 0, NULL); + load_module(MODROOT "smap.irx", 0, NULL); + +#elif defined(MODEM) + load_module(MODROOT "dev9.irx", 0, NULL); + load_module(MODROOT "sndrv101.irx", 0, NULL); + load_module(MODROOT "spduart.irx", 0, NULL); +#endif +} + +static sn_int32 do_initialisation(void) +{ + sn_int32 result; + sn_int32 device_attached; + sn_int16 idVendor; + sn_int16 idProduct; + sn_int32 stack_state; + sndev_set_ether_ip_type params; + struct hostent * host; + sn_bool got_ip; + struct in_addr addr; + + // load network modules + load_network_modules(); + + // init the socket API + scePrintf("Initializing the sockets API\n"); + result = sockAPIinit(1); + if(result != 0) + { + scePrintf("sockAPIinit() failed %d\n", result); + return result; + } + + // register this thread with the socket API + result = sockAPIregthr(); + if(result != 0) + { + scePrintf("sockAPIregthr() failed %d\n", result); + return result; + } + + // wait for the device adaptor to be attached + scePrintf("Waiting for network device to be initialized\n"); + device_attached = SN_DEV_TYPE_NONE; + while(device_attached == SN_DEV_TYPE_NONE) + { + // check if attached + result = sndev_get_attached(0, &device_attached, &idVendor, &idProduct); + if(result != 0) + { + scePrintf("sndev_get_attached() failed %d\n", result); + return result; + } + + // if nothing attached, give it a rest before trying again + if(device_attached == SN_DEV_TYPE_NONE) + sn_delay(10); + } + + scePrintf("Device ready (idVendor=0x%04X idProduct=0x%04X)\n", ((int)idVendor) & 0xFFFF, ((int)idProduct) & 0xFFFF); + + // set the DNS servers + result = sntc_set_dns_server_list((const sn_char**)dns_servers); + if(result != 0) + { + scePrintf("sntc_set_dns_server_list() failed %d\n", result); + return result; + } + + // set the IP, subnet mask, and gateway (all 0's for DHCP) + inet_aton(SNPS2_IP_ADDR, (struct in_addr*)¶ms.ip_addr); + inet_aton(SNPS2_SUB_MSK, (struct in_addr*)¶ms.sub_mask); + inet_aton(SNPS2_GATEWAY, (struct in_addr*)¶ms.gateway); + result = sndev_set_options(0, SN_DEV_SET_ETHER_IP, ¶ms, sizeof(params)); + if(result != 0) + { + scePrintf("sndev_set_options() failed %d\n", result); + return result; + } + + // start the stack + scePrintf("Starting the TCP/IP stack\n"); + result = sn_stack_state(SN_STACK_STATE_START, &stack_state); + if(result != 0) + { + scePrintf("sn_stack_sate() failed %d\n", result); + return result; + } + + // wait for the stack to come up + while(sn_socket_api_ready() == SN_FALSE) + sn_delay(100); + + // wait for a non-zero IP (for DHCP) + scePrintf("Waiting for DHCP-supplied IP\n"); + got_ip = SN_FALSE; + do + { + // get the local host info + host = gethostbyname(LOCAL_NAME); + if(host && host->h_addr_list[0]) + { + // copy the IP + memcpy(&addr, host->h_addr_list[0], sizeof(addr)); + if(addr.s_addr) + { + got_ip = SN_TRUE; + scePrintf("DHCP allocated IP addr %s\n", inet_ntoa(addr)); + } + } + + // don't hog the CPU + if(got_ip == SN_FALSE) + sn_delay(100); + } + while(got_ip == SN_FALSE); + + return 0; +} + +static void do_shutdown(void) +{ + int result; + int stack_state; + + // stopping the stack + result = sn_stack_state(SN_STACK_STATE_STOP, &stack_state); + if(result != 0) + { + scePrintf("sn_stack_sate() failed %d\n", result); + return; + } + + // deregister this thread with the socket API + sockAPIderegthr(); +} +#endif // SN_SYSTEMS + +#ifdef EENET + +#ifdef __MWERKS__ +#include "/ee/sample/libeenet/ent_cnf/ent_cnf.h" +#else +#include "/usr/local/sce/ee/sample/libeenet/ent_cnf/ent_cnf.h" +#endif + +#if defined(USB_ETHERNET) +#define USR_CONF_NAME "Combination4" +#elif defined(USB_ETHERNET_WITH_PPPOE) +#define USR_CONF_NAME "Combination5" +#elif defined(HDD_ETHERNET) +#define USR_CONF_NAME "Combination6" +#elif defined(HDD_ETHERNET_WITH_PPPOE) +#define USR_CONF_NAME "Combination7" +#elif defined(MODEM) +#define USR_CONF_NAME "" +#endif + +#define MOD_NETCNF MODROOT "netcnf.irx" +#define MOD_EENETCTL MODROOT "eenetctl.irx" +#define MOD_DEV9 MODROOT "dev9.irx" +#define MOD_USBD MODROOT "usbd.irx" +#define MOD_ENT_DEVM MODROOT "ent_devm.irx" +#define MOD_ENT_SMAP MODROOT "ent_smap.irx" +#define MOD_ENT_ETH MODROOT "ent_eth.irx" +#define MOD_ENT_PPP MODROOT "ent_ppp.irx" +#define MOD_ENT_CNF SCEROOT "iop/sample/libeenet/ent_cnf/ent_cnf.irx" +#define MOD_MODEMDRV "" + +#define INETCTL_ARG "-no_auto" "\0" "-no_decode" +#define NETCNF_ICON APPROOT "SYS_NET.ICO" +#define NETCNF_ICONSYS APPROOT "icon.sys" +#define NETCNF_ARG "icon=" NETCNF_ICON "\0" "iconsys=" NETCNF_ICONSYS +#define MODEMDRV_ARG "" + +#define NET_DB SCEROOT "conf/net/net.db" + +#define EENET_MEMSIZE (512 * 1024) +#define EENET_TPL 32 +#define EENET_APP_PRIO 48 + +static int eenetctl_mid; +static int ent_cnf_mid; +static int ent_devm_mid; +#if defined(HDD_ETHERNET) || defined(HDD_ETHERNET_WITH_PPPOE) +#define EENET_IFNAME "smap0" +static int ent_smap_mid; +#endif +#if defined(USB_ETHERNET) || defined(USB_ETHERNET_WITH_PPPOE) +#define EENET_IFNAME "eth0" +static int ent_eth_mid; +#endif +#if defined(MODEM) +#define EENET_IFNAME "ppp0" +static int ent_ppp_mid; +static int modem_mid; +#endif + +static void * eenet_pool; + +static int sema_id; +static int event_flag = 0; +#define Ev_Attach 0x01 +#define Ev_UpCompleted 0x02 +#define Ev_DownCompleted 0x04 +#define Ev_DetachCompleted 0x08 + +#define WaitEvent(event) \ + while(1){ \ + WaitSema(sema_id); \ + if(event_flag & (event)) \ + break; \ + } + +static void event_handler(const char *ifname, int af, int type) +{ + scePrintf("event_handler: event happened. af = %d, type = %d\n", af, type); + + switch(type) + { + case sceEENETCTL_IEV_Attach: + if(strcmp(ifname, EENET_IFNAME)) + break; + event_flag |= Ev_Attach; + SignalSema(sema_id); + break; + case sceEENETCTL_IEV_UpCompleted: + event_flag |= Ev_UpCompleted; + SignalSema(sema_id); + break; + case sceEENETCTL_IEV_DownCompleted: + event_flag |= Ev_DownCompleted; + SignalSema(sema_id); + break; + case sceEENETCTL_IEV_DetachCompleted: + if(strcmp(ifname, EENET_IFNAME)) + break; + event_flag |= Ev_DetachCompleted; + SignalSema(sema_id); + break; + } + + return; +} + +static int create_sema(int init_count, int max_count){ + struct SemaParam sema_param; + int sema_id; + + memset(&sema_param, 0, sizeof(struct SemaParam)); + sema_param.initCount = init_count; + sema_param.maxCount = max_count; + sema_id = CreateSema(&sema_param); + + return sema_id; +} + +// ent_cnf sifrpc num +#define ENT_CNF_SIFRPC_NUM 0x0a31108e + +// code +#define ENT_CNF_SIFRPC_LOAD_CONFIG 1 +#define ENT_CNF_SIFRPC_SET_CONFIG 2 +#define ENT_CNF_SIFRPC_SET_SIFCMD 3 + +// utility macro +#define ee_rpc_size(size) ((size + 15) & ~15) +#define iop_rpc_size(size) ((size + 3) & ~3) + +#define NETBUFSIZE 512 +#define RPCSIZE NETBUFSIZE * 4 + +static sceSifClientData cd; +static u_int rpc_buffer[NETBUFSIZE] __attribute__((aligned(64))); + +int ent_cnf_init(void) +{ + int i; + + /* bind rpc */ + while(1){ + if (sceSifBindRpc(&cd, ENT_CNF_SIFRPC_NUM, 0) < 0) { + scePrintf("ent_cnf: sceSifBindRpc failed.\n"); + while(1) {}; + } + if (cd.serve != 0) break; + i = 0x10000; + while(i --) {}; + } + + return 0; +} + +int ent_cnf_load_config(const char *fname, const char *usr_name) +{ + int ret, len; + + strcpy((char *)rpc_buffer, fname); + len = (int)strlen(fname) + 1; + strcpy((char *)rpc_buffer + len, usr_name); + len += (int)strlen(usr_name) + 1; + + ret = sceSifCallRpc(&cd, ENT_CNF_SIFRPC_LOAD_CONFIG, 0, + (void *)rpc_buffer, ee_rpc_size(len), + (void *)rpc_buffer, ee_rpc_size(sizeof(u_int)), 0, 0); + if(ret < 0){ + scePrintf("ent_cnf: RPC call in ent_cnf_load_config() failed.\n"); + return -1; + } + + return (int)rpc_buffer[0]; +} + +int ent_cnf_set_config(void) +{ + int ret; + + ret = sceSifCallRpc(&cd, ENT_CNF_SIFRPC_SET_CONFIG, 0, + NULL, 0, (void *)rpc_buffer, ee_rpc_size(sizeof(u_int)), 0, 0); + if(ret < 0){ + scePrintf("ent_cnf: RPC call in ent_cnf_set_config() failed.\n"); + return -1; + } + + return (int)rpc_buffer[0]; +} + +static void load_network_modules() +{ + ent_devm_mid = load_module(MOD_ENT_DEVM, 0, NULL); + load_module(MOD_NETCNF, sizeof(NETCNF_ARG), NETCNF_ARG); + eenetctl_mid = load_module(MOD_EENETCTL, 0, NULL); + ent_cnf_mid = load_module(MOD_ENT_CNF, 0, NULL); +#if defined( HDD_ETHERNET ) || defined( HDD_ETHERNET_WITH_PPPOE ) + load_module(MOD_DEV9, 0, NULL); + ent_smap_mid = load_module(MOD_ENT_SMAP, 0, NULL); + //PreparePowerOff(); +#endif +#if defined( USB_ETHERNET ) || defined( USB_ETHERNET_WITH_PPPOE ) + load_module(MOD_USBD, 0, NULL); + ent_eth_mid = load_module(MOD_ENT_ETH, 0, NULL); +#endif +#if defined( MODEM ) + ent_ppp_mid = load_module(MOD_ENT_PPP, 0, NULL); + modem_mid = load_module(MOD_MODEMDRV, sizeof(MODEMDRV_ARG), MODEMDRV_ARG); +#endif +} + +static int do_initialisation(void) +{ + int rcode; + + // create a semaphore + sema_id = create_sema(0, 1); + if(sema_id < 0) + { + scePrintf("create_sema() failed.\n"); + return -1; + } + + // load network modules + load_network_modules(); + + // allocate memory for EENet + //eenet_pool = gsimemalign(64, EENET_MEMSIZE); + eenet_pool = memalign(64, EENET_MEMSIZE); + if(eenet_pool == NULL) + return -1; + + // initialize eenet + rcode = sceEENetInit(eenet_pool, EENET_MEMSIZE, EENET_TPL, 8192, EENET_APP_PRIO); + + + if(rcode < 0) + { + scePrintf("sceEENetInit failed (%d)\n", rcode); + return -1; + } + +#ifdef _DEBUG + sceEENetSetLogLevel(EENET_LOG_DEBUG); +#endif + + // init eenetctl.a + rcode = sceEENetCtlInit(8192, 32, 8192, 32, 8192, 32, 1, 0); + if(rcode < 0) + { + scePrintf("sceEENetCtlInit failed (%d)\n", rcode); + return -1; + } + + // add event handler + rcode = sceEENetCtlRegisterEventHandler(event_handler); + if(rcode < 0) + { + scePrintf("sceEENetCtlRegisterEventHandler failed (%d)\n", rcode); + return -1; + } + + // init ent_cnf + rcode = ent_cnf_init(); + if(rcode < 0) + { + scePrintf("ent_cnf_init failed (%d)\n", rcode); + return -1; + } + + // register network interface driver +#if defined( HDD_ETHERNET ) || defined( HDD_ETHERNET_WITH_PPPOE ) + rcode = sceEENetDeviceSMAPReg(8192, 8192); + if(rcode < 0) + { + scePrintf("sceEENetDeviceSMAPReg failed (%d)\n", rcode); + return -1; + } +#endif +#if defined( USB_ETHERNET ) || defined( USB_ETHERNET_WITH_PPPOE ) + rcode = sceEENetDeviceETHReg(8192, 8192); + if(rcode < 0) + { + scePrintf("sceEENetDeviceETHReg failed (%d)\n", rcode); + return -1; + } +#endif +#if defined( MODEM ) + rcode = sceEENetDevicePPPReg(8192, 8192); + if(rcode < 0) + { + scePrintf("sceEENetDevicePPPReg failed (%d)\n", rcode); + return -1; + } +#endif + + // wait until target interface is attached + WaitEvent(Ev_Attach); + + // load network configuration + rcode = ent_cnf_load_config(NET_DB, USR_CONF_NAME); + if(rcode < 0) + { + scePrintf("ent_cnf_load_config failed (%d)\n", rcode); + return -1; + } + + // set network configuration + rcode = ent_cnf_set_config(); + if(rcode < 0) + { + scePrintf("ent_cnf_set_config failed (%d)\n", rcode); + return -1; + } + + // wait for interface initialization to complete + WaitEvent(Ev_UpCompleted); + + return 0; +} + +static void do_shutdown(void) +{ + int rcode; + + // bring down the interface + rcode = sceEENetCtlDownInterface(EENET_IFNAME); + if(rcode < 0) + { + scePrintf("sceEENetCtlDownInterface failed (%d)\n", rcode); + return; + } + + // wait for the termination to complete + WaitEvent(Ev_DownCompleted); + + // unload the driver module +#if defined( HDD_ETHERNET ) || defined( HDD_ETHERNET_WITH_PPPOE ) + rcode = sceEENetDeviceSMAPUnreg(); + if(rcode < 0) + { + scePrintf("sceEENetDeviceSMAPUnreg failed (%d)\n", rcode); + return; + } +#endif +#if defined( USB_ETHERNET ) || defined( USB_ETHERNET_WITH_PPPOE ) + rcode = sceEENetDeviceETHUnreg(); + if(rcode < 0) + { + scePrintf("sceEENetDeviceETHUnreg failed (%d)\n", rcode); + return; + } +#endif +#if defined( MODEM ) + rcode = sceEENetDevicePPPUnreg(); + if(rcode < 0) + { + scePrintf("sceEENetDevicePPPUnreg failed (%d)\n", rcode); + return; + } +#endif + + // wait for the detach to complete + WaitEvent(Ev_DetachCompleted); + + // cancel the event handler + rcode = sceEENetCtlUnregisterEventHandler(event_handler); + if(rcode < 0) + { + scePrintf("sceEENetCtlUnRegisterEventHandler failed (%d)\n", rcode); + return; + } + + // eenetctl.a termination processing + rcode = sceEENetCtlTerm(); + if(rcode < 0) + { + scePrintf("sceEENetCtlTerm failed (%d)\n", rcode); + return; + } + + // terminate eenet + rcode = sceEENetTerm(); + if(rcode < 0) + { + scePrintf("sceEENetTerm failed (%d)\n", rcode); + return; + } + + // stop and unload modules +#if defined( HDD_ETHERNET ) || defined( HDD_ETHERNET_WITH_PPPOE ) + sceSifStopModule(ent_smap_mid, 0, NULL, &rcode); + sceSifUnloadModule(ent_smap_mid); +#endif +#if defined( USB_ETHERNET ) || defined( USB_ETHERNET_WITH_PPPOE ) + sceSifStopModule(ent_eth_mid, 0, NULL, &rcode); + sceSifUnloadModule(ent_eth_mid); +#endif +#if defined( MODEM ) + sceSifStopModule(modem_mid, 0, NULL, &rcode); + sceSifUnloadModule(modem_mid); + + sceSifStopModule(ent_ppp_mid, 0, NULL, &rcode); + sceSifUnloadModule(ent_ppp_mid); +#endif + + sceSifStopModule(ent_cnf_mid, 0, NULL, &rcode); + sceSifUnloadModule(ent_cnf_mid); + + sceSifStopModule(eenetctl_mid, 0, NULL, &rcode); + sceSifUnloadModule(eenetctl_mid); + + sceSifStopModule(ent_devm_mid, 0, NULL, &rcode); + sceSifUnloadModule(ent_devm_mid); + + // free the EENet pool + if(eenet_pool != NULL) + free(eenet_pool); +} + +#endif + +#ifdef INSOCK + +// These are also used in nonport.c to obtain the MAC address +sceSifMClientData gGSIInsockClientData; +u_int gGSIInsockSocketBuffer[NETBUFSIZE] __attribute__((aligned(64))); + + +// IRX paths +#define IOP_MOD_INET MODROOT "inet.irx" +#define IOP_MOD_AN986 MODROOT "an986.irx" +#define IOP_MOD_USBD MODROOT "usbd.irx" +#define IOP_MOD_NETCNF MODROOT "netcnf.irx" +#define IOP_MOD_INETCTL MODROOT "inetctl.irx" +#define IOP_MOD_MSIFRPC MODROOT "msifrpc.irx" +#define IOP_MOD_DEV9 MODROOT "dev9.irx" +#define IOP_MOD_SMAP MODROOT "smap.irx" +#define IOP_MOD_PPP MODROOT "ppp.irx" +#define IOP_MOD_PPPOE MODROOT "pppoe.irx" +#define IOP_MOD_LIBNET MODROOT "libnet.irx" +#define IOP_MOD_NETCNFIF MODROOT "netcnfif.irx" +#define IOP_MOD_INETLOG SCEROOT "iop/util/inet/inetlog.irx" +#define IOP_MOD_MODEMDRV "" +#define NET_DB SCEROOT "conf/net/net.db" +#define INET_ARG "debug=18" +#define INETCTL_ARG "-no_auto" "\0" "-no_decode" +#define LIBNET_ARG "-verbose" +#define NETCNF_ICON APPROOT "SYS_NET.ICO" +#define NETCNF_ICONSYS APPROOT "icon.sys" +#define NETCNF_ARG "icon=" NETCNF_ICON "\0" "iconsys=" NETCNF_ICONSYS +#define MODEMDRV_ARG "" + +#if defined( USB_ETHERNET ) +#define USR_CONF_NAME "Combination4" +#elif defined( USB_ETHERNET_WITH_PPPOE ) +#define USR_CONF_NAME "Combination5" +#elif defined( HDD_ETHERNET ) +#define USR_CONF_NAME "Combination6" +#elif defined( HDD_ETHERNET_WITH_PPPOE ) +#define USR_CONF_NAME "Combination7" +#elif defined( MODEM ) +#define USR_CONF_NAME "" +#endif + +static int do_initialisation(void) +{ + int result; + int i; + int if_id[sceLIBNET_MAX_INTERFACE]; + sceInetAddress_t myaddr; + + sceSifInitRpc( 0 ); + + load_module( IOP_MOD_INET, 0, NULL ); + load_module( IOP_MOD_NETCNF, sizeof( NETCNF_ARG ), NETCNF_ARG ); + load_module( IOP_MOD_INETCTL, sizeof( INETCTL_ARG ), INETCTL_ARG ); + +#if defined( USB_ETHERNET ) || defined( USB_ETHERNET_WITH_PPPOE ) + load_module( IOP_MOD_USBD, 0, NULL ); + load_module( IOP_MOD_AN986, 0, NULL ); +#endif + +#if defined( HDD_ETHERNET ) || defined( HDD_ETHERNET_WITH_PPPOE ) + load_module( IOP_MOD_DEV9, 0, NULL ); + load_module( IOP_MOD_SMAP, 0, NULL ); +#endif + +#if defined( USB_ETHERNET_WITH_PPPOE ) || defined( HDD_ETHERNET_WITH_PPPOE ) + load_module( IOP_MOD_PPP, 0, NULL ); + load_module( IOP_MOD_PPPOE, 0, NULL ); +#endif + +#if defined( MODEM ) + load_module( IOP_MOD_PPP, 0, NULL ); + load_module( IOP_MOD_USBD, 0, NULL ); + load_module( IOP_MOD_MODEMDRV, sizeof( MODEMDRV_ARG ), MODEMDRV_ARG ); +#endif + + load_module( IOP_MOD_MSIFRPC, 0, NULL ); + load_module( IOP_MOD_LIBNET, sizeof( LIBNET_ARG ), LIBNET_ARG ); + load_module( IOP_MOD_NETCNFIF, 0, NULL ); + +#if defined( HDD_ETHERNET ) || defined( HDD_ETHERNET_WITH_PPPOE ) +// PreparePowerOff(); +#endif + + // Initialize Libnet + sceSifMInitRpc(0); + + result = sceInsockSetSifMBindRpcValue(NETBUFSIZE, sceLIBNET_STACKSIZE, sceLIBNET_PRIORITY); + if (result < 0) + return result; + + result = sceLibnetInitialize(&gGSIInsockClientData, NETBUFSIZE, sceLIBNET_STACKSIZE, sceLIBNET_PRIORITY); + if (result < 0) + return result; + + result = sceLibnetRegisterHandler(&gGSIInsockClientData, gGSIInsockSocketBuffer); + if (result < 0) + return result; + + result = load_set_conf_extra(&gGSIInsockClientData, gGSIInsockSocketBuffer, NET_DB, USR_CONF_NAME, sceLIBNETF_AUTO_UPIF); + if (result < 0) + return result; + + result = sceLibnetWaitGetAddress( &gGSIInsockClientData, gGSIInsockSocketBuffer, if_id, sceLIBNET_MAX_INTERFACE, &myaddr, sceLIBNETF_AUTO_UPIF ); + if (result < 0) + return result; + + for ( i = 0; i < sceLIBNET_MAX_INTERFACE; i++ ) { + if ( if_id[ i ] == 0 ) { + break; + } + scePrintf( "interface: %d\n", if_id[ i ] ); + } + + return 0; +} + +static void do_shutdown(void) +{ + // Release the network interface + down_interface(&gGSIInsockClientData, gGSIInsockSocketBuffer, 0); + + // Shutdown libnet + libnet_term(&gGSIInsockClientData); + + sceSifMExitRpc(); +} + +#endif // INSOCK + +#ifdef GSI_VOICE +void load_voice_modules(void); // prototype so codewarrior will be happy +void load_voice_modules(void) +{ + // this is the maximum size of a raw frame, in bytes + char lgaudArgs[] = "maxstream=512\n"; + + // load the usb module + load_module("host0:/usr/local/sce/iop/modules/usbd.irx", 0, NULL); + + // load the lgAud module + // see the lgAud documentation for info on optional loading parameters + load_module("host0:/usr/local/sce/iop/modules/lgaud.irx", sizeof(lgaudArgs), lgaudArgs); + + // load the lgVid module + // see the lgVid documentation for info on optional loading parameters + load_module("host0:/usr/local/sce/iop/modules/lgvid.irx", 0, NULL); + + // load the SPU2 modules + load_module("host0:/usr/local/sce/iop/modules/libsd.irx", 0, NULL); + load_module("host0:/usr/local/sce/iop/modules/sdrdrv.irx", 0, NULL); +} +#endif + +// New hooks required by crt0.s +#if !defined(__MWERKS__) +int _init(){ return 0; } +int _fini(){ return 0; } + + #if (__GNUC__ >= 3) + int __main(int argc, char ** argp){ GSI_UNUSED(argp); GSI_UNUSED(argc); return 0; } + #endif +#endif + +extern int test_main(int argc, char ** argp); +int main(int argc, char ** argp) +{ + int result = 0; + + GSI_UNUSED(argc); + GSI_UNUSED(argp); + + printf("\nGameSpy Test App Initializing\n" + "----------------------------------\n"); + + // init RPC + sceSifInitRpc(0); + + // initialize the stack + result = (int)do_initialisation(); + if(result) + { + printf("Initialization failed\n"); + return result; + } + +#ifdef GSI_VOICE + load_voice_modules(); +#endif + + // start the actual program + printf("\nGameSpy Test App Starting\n" + "----------------------------------\n"); + test_main(argc, argp); + + // do any needed cleanup + do_shutdown(); + printf("\nGameSpy Test App Exiting\n" + "----------------------------------\n"); + + return 0; +} diff --git a/xrGameSpy/gamespy/common/ps2/ps2pad.c b/xrGameSpy/gamespy/common/ps2/ps2pad.c new file mode 100644 index 00000000000..0b8ebe24354 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ps2pad.c @@ -0,0 +1,214 @@ +#include "ps2pad.h" +#include +#include +#include + +#define BUTTON_LEFT(d) ((d[2] & (1 << (3+4)))==0) +#define BUTTON_DOWN(d) ((d[2] & (1 << (2+4)))==0) +#define BUTTON_RIGHT(d) ((d[2] & (1 << (1+4)))==0) +#define BUTTON_UP(d) ((d[2] & (1 << (0+4)))==0) + +#define BUTTON_START(d) ((d[2] & (1 << 3))==0) +#define BUTTON_RSTICK(d) ((d[2] & (1 << 2))==0) +#define BUTTON_LSTICK(d) ((d[2] & (1 << 1))==0) +#define BUTTON_SELECT(d) ((d[2] & (1 << 0))==0) + +#define BUTTON_SQUARE(d) ((d[3] & (1 << (3+4)))==0) +#define BUTTON_X(d) ((d[3] & (1 << (2+4)))==0) +#define BUTTON_CIRCLE(d) ((d[3] & (1 << (1+4)))==0) +#define BUTTON_TRI(d) ((d[3] & (1 << (0+4)))==0) + +#define BUTTON_R1(d) ((d[3] & (1 << 3))==0) +#define BUTTON_L1(d) ((d[3] & (1 << 2))==0) +#define BUTTON_R2(d) ((d[3] & (1 << 1))==0) +#define BUTTON_L2(d) ((d[3] & (1 << 0))==0) + +static int term_id = 0; + +static u_long128 mPadDMABuf[scePadDmaBufferMax] __attribute__((aligned (64))); +static int mPadState; +static int mPadPhase; + +static unsigned char mActDirect[6]; +static unsigned char mActAlign[6]; + +static unsigned short PadReadData(int events[NumPadEvents]) +{ + static unsigned char rdata_prev[32]; + unsigned char rdata[32]; + unsigned short tpad = 0; + unsigned short paddata = 0; + static unsigned short rpad = 0; + + if (scePadRead(0,0,rdata) == 0) + return 0; + + if (rdata[0] == 0) + { + paddata = (unsigned short)(0xffff ^ ((rdata[2]<<8)|rdata[3])); + + tpad = (unsigned short)(paddata & ~rpad); + rpad = paddata; + + term_id = (rdata[1]>>4); + + events[PadLeft] = (BUTTON_LEFT(rdata) && !BUTTON_LEFT(rdata_prev)); + events[PadDown] = (BUTTON_DOWN(rdata) && !BUTTON_DOWN(rdata_prev)); + events[PadRight] = (BUTTON_RIGHT(rdata) && !BUTTON_RIGHT(rdata_prev)); + events[PadUp] = (BUTTON_UP(rdata) && !BUTTON_UP(rdata_prev)); + events[PadStart] = (BUTTON_START(rdata) && !BUTTON_START(rdata_prev)); + events[PadRightStick] = (BUTTON_RSTICK(rdata) && !BUTTON_RSTICK(rdata_prev)); + events[PadLeftStick] = (BUTTON_LSTICK(rdata) && !BUTTON_LSTICK(rdata_prev)); + events[PadSelect] = (BUTTON_SELECT(rdata) && !BUTTON_SELECT(rdata_prev)); + events[PadSquare] = (BUTTON_SQUARE(rdata) && !BUTTON_SQUARE(rdata_prev)); + events[PadX] = (BUTTON_X(rdata) && !BUTTON_X(rdata_prev)); + events[PadCircle] = (BUTTON_CIRCLE(rdata) && !BUTTON_CIRCLE(rdata_prev)); + events[PadTriangle] = (BUTTON_TRI(rdata) && !BUTTON_TRI(rdata_prev)); + events[PadR1] = (BUTTON_R1(rdata) && !BUTTON_R1(rdata_prev)); + events[PadL1] = (BUTTON_L1(rdata) && !BUTTON_L1(rdata_prev)); + events[PadR2] = (BUTTON_R2(rdata) && !BUTTON_R2(rdata_prev)); + events[PadL2] = (BUTTON_L2(rdata) && !BUTTON_L2(rdata_prev)); + } + + // store current data + memcpy(rdata_prev, rdata, 32); + + return (tpad); +} + +#define ROOT_DIR "host0:/usr/local/sce/iop/modules/" +int PadInit(void) +{ + int i; + + mPadPhase = 0; + mPadState = 0; + + for (i=0; i <6; i++) + { + mActDirect[i] = 0; + mActAlign[i] = 0; + } + + // Load serial io module + if (0 >= sceSifLoadModule(ROOT_DIR "sio2man.irx", 0, NULL)) + return 0; + + // Load control pad module + if (0 >= sceSifLoadModule(ROOT_DIR "padman.irx", 0, NULL)) + return 0; + + // Misc init + sceDmaReset(1); // reset DMA + sceGsResetPath(); // reset GS + sceGsSyncPath(0, 0); // wait for completion + + // Open the pad port + scePadInit(0); + if (0 == scePadPortOpen(0, 0, mPadDMABuf)) + return 0; // couldn't initialize pad + + return 1; +} + +void PadReadInput(int events[NumPadEvents]) +{ + static int id = 0; + int exid; + int i; + + for(i = 0 ; i < NumPadEvents ; i++) + events[i] = 0; + + // check buttons or some junk + mPadState = scePadGetState(0, 0); + //if (mPadState >= 0 && state <= 7) + // scePadStateIntToStr(state, buf); // get error string + if (mPadState == scePadStateDiscon) + mPadPhase = 0; // lost pad + + switch(mPadPhase) + { + case 0: + { + // Wait until stable or need to find ctp1 + if (mPadState != scePadStateStable && mPadState != scePadStateFindCTP1) + break; + + // Get controller ID + id = scePadInfoMode(0, 0, InfoModeCurID, 0); + if (id == 0) + break; + + // Is there an extended ID? + exid = scePadInfoMode(0,0, InfoModeCurExID, 0); + if (exid > 0) + id = exid; + + if (id == 40) + // Special processing for "standard" controller + mPadPhase = 40; + else if (id == 7) + // Special processing for "analog" controller + mPadPhase = 70; + else + // Skip to end of setup + mPadPhase = 99; + break; + } + + // 1st step special processing for "standard" controller + case 40: + if (scePadInfoMode(0, 0, InfoModeCurExID, 0)==0) + { + // Skip to end if this was set from an extended ID + mPadPhase = 99; + break; + } + + // Set main mode + if (scePadSetMainMode(0, 0, 1, 0)==1) + mPadPhase++; + break; + + // 2nd step special processing for "standard" controller + case 41: + if (scePadGetReqState(0,0) == scePadReqStateFaild) + mPadPhase--; // failed, go back a phase + if (scePadGetReqState(0,0) == scePadReqStateComplete) + mPadPhase = 0; // completed, go back to beginning to try again + break; + + // 1st step special processing for "analog" controller + case 70: + if (scePadInfoAct(0, 0, -1, 0)==0) + mPadPhase = 99; // done + mActAlign[0] = 0; + mActAlign[1] = 1; + for (i=2; i<6; i++) + mActAlign[i] = 0xff; + if (scePadSetActAlign(0, 0, mActAlign)) + mPadPhase++; + break; + + // 2nd step special processing for "analog" controller + case 71: + if (scePadGetReqState(0,0) == scePadReqStateFaild) + mPadPhase--; + if (scePadGetReqState(0,0) == scePadReqStateComplete) + mPadPhase = 99; // finished, jump to end + + case 99: + default: + if (mPadState == scePadStateStable || mPadState == scePadStateFindCTP1) + { + // read button states + //unsigned short pad = ReadPadData(); + PadReadData(events); + + if (term_id != id) + mPadPhase = 0; + } + break; + }; +} diff --git a/xrGameSpy/gamespy/common/ps2/ps2pad.h b/xrGameSpy/gamespy/common/ps2/ps2pad.h new file mode 100644 index 00000000000..4346039d716 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps2/ps2pad.h @@ -0,0 +1,30 @@ +#ifndef __PS2PAD_H__ +#define __PS2PAD_H__ + +#include "../../../nonport.h" + +typedef enum +{ + PadLeft, + PadDown, + PadRight, + PadUp, + PadStart, + PadRightStick, + PadLeftStick, + PadSelect, + PadSquare, + PadX, + PadCircle, + PadTriangle, + PadR1, + PadL1, + PadR2, + PadL2, + NumPadEvents +} PadEvents; + +int PadInit(void); +void PadReadInput(int events[NumPadEvents]); + +#endif diff --git a/xrGameSpy/gamespy/common/ps3/Makefile.common b/xrGameSpy/gamespy/common/ps3/Makefile.common new file mode 100644 index 00000000000..fb3edd3643b --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/Makefile.common @@ -0,0 +1,31 @@ +#GameSpy.net PS3 Makefile +#Included from sample-specific Makefiles + +CELL_TARGET_PATH = $(CELL_SDK)/target-ceb +CELL_HOST_BIN_PATH = $(HOST_PATH)/bin + +LIBDIR = $(CELL_TARGET_PATH)/ppu/lib + +CFLAGS = -g -O0 -Wall -Werror -Wa,-al -fno-common -I$(GAMESPY_DIR) -DGSI_COMMON_DEBUG -D_PS3 $(SDK_CFLAGS) +ASFLAGS = -c -xassembler-with-cpp -Wa,-al +LDFLAGS = -lm +INCDIR = -I$(CELL_SDK)/target-ceb/ppu/include/network + +LIBS = $(SDK_LIBS) \ + $(LIBDIR)/libnet.a \ + $(LIBDIR)/libio.a + +AS = ppu-lv2-as +CC = ppu-lv2-gcc +LD = ppu-lv2-g++ + +.SUFFIXES: .c + +$(TARGET).elf: $(OBJS) + $(LD) -o $@ $(OBJS) $(LIBS) $(LDFLAGS) + +.c.o: + $(CC) $(CFLAGS) $(INCDIR) -c $< -o $*.o > /dev/null + +clean: + $(RM) $(OBJS) *.o $(TARGET).elf diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/CellConfiguration.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/CellConfiguration.h new file mode 100644 index 00000000000..411c9da04d0 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/CellConfiguration.h @@ -0,0 +1,18 @@ +/* [SCE CONFIDENTIAL DOCUMENT] + * PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com) + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * All Rights Reserved. + */ + +#ifndef __CELL_CONFIGURATION_H +#define __CELL_CONFIGURATION_H + +#undef SCE_CONTROL_CONSOLE + +#ifdef WIN32 +#define EXPORT_SYM __declspec( dllexport ) +#else +#define EXPORT_SYM +#endif + +#endif diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/CellVectorMath.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/CellVectorMath.h new file mode 100644 index 00000000000..01e2645f7c4 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/CellVectorMath.h @@ -0,0 +1,25 @@ +#ifndef __CELL_VECTORMATH_H__ +#define __CELL_VECTORMATH_H__ + +#ifndef __CELLOS_LV2__ +class vec_float4 +{ + float x, y, z, w; +} +#ifdef __GNUC__ +__attribute__ ((aligned (16))); +#else +__declspec(align(16)); +#endif // __GNUC__ +#endif // __CELLOS_LV2__ + +#ifdef __CELLOS_LV2__ +#include "vectormath_soa.h" +#else +#include "vectormath_scalar/vectormath_aos.h" +#endif // __CELLOS_LV2__ + +using namespace Vectormath; +using namespace Vectormath::Aos; + +#endif /* __CELL_VECTORMATH_H__ */ diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/PS3Types.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/PS3Types.h new file mode 100644 index 00000000000..d11567cfb38 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/PS3Types.h @@ -0,0 +1,7 @@ +#ifndef PS3_TYPES_H +#define PS3_TYPES_H + +//#include "CellVectorMath.h" + + +#endif //PS3_TYPES_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SPUAssert.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SPUAssert.h new file mode 100644 index 00000000000..fb58827e5c5 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SPUAssert.h @@ -0,0 +1,44 @@ +#ifndef __SPU_ASSERT_H__ +#define __SPU_ASSERT_H__ + +// Author: Sauce +// 1/18/2006 +// Better assert on SPU side, but it assumes spu_printf works. + +#ifdef _DEBUG + +#ifdef __CELLOS_LV2__ +#include +#define SPU_ASSERT(cond) do { if (__builtin_expect(!(cond), 0)) { spu_printf("SPU: Assertion failed! Expression: " #cond "\n in %s at " __FILE__ ":%i\n", __FUNCTION__, __LINE__); spu_hcmpeq((cond), 0); } } while (0) +#else // __CELLOS_LV2__ +#define SPU_ASSERT(cond) assert(cond) +#endif //__CELLOS_LV2__ + +#else // _DEBUG + +#ifdef __CELLOS_LV2__ +#include +#define SPU_ASSERT(cond) do { if (__builtin_expect(!(cond), 0)) { spu_printf("SPU: Assertion failed! Expression: " #cond "\n in %s at " __FILE__ ":%i\n", __FUNCTION__, __LINE__); spu_hcmpeq((cond), 0); } } while (0) +// Sauce +// Later on we'll want no asserts in release builds +//#define SPU_ASSERT(cond) do {} while (0) +#else // __CELLOS_LV2__ +#define SPU_ASSERT(cond) assert(cond) +#endif // __CELLOS_LV2__ + +#endif // _DEBUG + +// Usage: +// SPU_COMPILE_TIME_ASSERT(sizeof(MyStructure) <= 128); +// Gives the following error message if it fails: +// error: size of array `spu_compile_time_assert_failed' is negative +#define SPU_COMPILE_TIME_ASSERT(cond) extern char spu_compile_time_assert_failed[cond ? 1 : -1] + +// Usage: +// SPU_NAMED_COMPILE_TIME_ASSERT(MyStructure_is_more_than_128_bytes, sizeof(MyStructure) <= 128); +// Gives the following error message if it fails: +// error: size of array `MyStructure_is_more_than_128_bytes' is negative +#define SPU_NAMED_COMPILE_TIME_ASSERT(name, cond) extern char name[cond ? 1 : -1] + + +#endif diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpeexSpursTask_vs2005.vcproj b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpeexSpursTask_vs2005.vcproj new file mode 100644 index 00000000000..8f50e416fb5 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpeexSpursTask_vs2005.vcproj @@ -0,0 +1,644 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpeexSpursTask_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpeexSpursTask_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpeexSpursTask_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpuSpeexTaskMain.cpp b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpuSpeexTaskMain.cpp new file mode 100644 index 00000000000..b301ef29925 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTask/SpuSpeexTaskMain.cpp @@ -0,0 +1,515 @@ +// Copyright 2007 GameSpy Industries, Inc +// +// Speex SPURS Task +// Encode supported +// Decode supported +// + +#define __STDC_CONSTANT_MACROS + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "SPUAssert.h" + +#include "spursSupportInterface.h" +#include "SpursSpeexTaskManager.h" +#include "SpuFakeDma.h" +#include "SpursSpeexCInterface.h" + +#include + +#include +#include "LibSN_SPU.h" + +#define GVRate_8KHz 8000 +#define GVRate_16KHz 16000 + +// use this for data read in from each task request +SpursSpeexTaskDesc gviSpursSpeexTaskDesc; + +// internal data used by speex functions +SpeexBits gviSpursSpeexBits; + +char gviSpursSpeexStateBuffer[SPEEX_ENCODER_STATE_BUFFER_SIZE] POST_ALIGN(128); +char gviSpursSpeexBitsBuffer[MAX_BYTES_PER_FRAME] POST_ALIGN(16); + +void spuDebugPrintf(const char *fmt, ...) +{ + #ifdef SPU_VERBOSE_DEBUGGING + char debugOut[256]; + va_list args; + va_start(args, fmt); + vsprintf(debugOut, fmt, args); + va_end(args); + spu_printf(debugOut); + #endif +} + +void gviSpursSpeexEncoderInitialize(SpursSpeexTaskOutput *spuOutput) +{ + void *gviSpeexEncoderState; + int sampleRate = gviSpursSpeexTaskDesc.mSamplesPerSecond; + int quality = gviSpursSpeexTaskDesc.mQuality; + int rate; + int bitsPerFrame; + + //spuDebugPrintf("[Speex][SPU] sample rate: %d, quality: %d\n", sampleRate, quality); + + // create a new encoder state + if (sampleRate == GVRate_8KHz) + gviSpeexEncoderState = speex_encoder_init(&speex_nb_mode, gviSpursSpeexStateBuffer); + else if (sampleRate == GVRate_16KHz) + gviSpeexEncoderState = speex_encoder_init(&speex_wb_mode, gviSpursSpeexStateBuffer); + else + { + //spuDebugPrintf("[Speex][SPU] Initializing Speex failed\n"); + spuOutput->mSpeexReturnCode = -2; + return; + } + + if(!gviSpeexEncoderState) + { + //spuDebugPrintf("[Speex][SPU] Initializing Speex failed\n"); + spuOutput->mSpeexReturnCode = -3; + return; + } + + //spuDebugPrintf("[Speex][SPU] Done getting speex mode\n"); + //spuDebugPrintf("[Speex][SPU] encoder state addr: 0x%8x\n", gviSpeexEncoderState); + + // set the sampling rate + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_SET_SAMPLING_RATE, &sampleRate); + + // Get the samples per frame setting. + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_GET_FRAME_SIZE, &spuOutput->mSpeexSamplesPerFrame); + + // set the quality + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_SET_QUALITY, &quality); + + // (re)initialize the bits struct + speex_bits_init_buffer(&gviSpursSpeexBits,gviSpursSpeexBitsBuffer,sizeof(gviSpursSpeexBitsBuffer)); + + //spuDebugPrintf("[Speex][SPU] speex bits addr: 0x%8x\n", gviSpeexBits); + + // get the bit rate + speex_encoder_ctl(gviSpeexEncoderState, SPEEX_GET_BITRATE, &rate); + + //spuDebugPrintf("[Speex][SPU] Done with customizing options for speex\n"); + + // convert to bits per frame + bitsPerFrame = (rate / (sampleRate / spuOutput->mSpeexSamplesPerFrame)); + + // convert to bytes per frame and store, round up to allocate more space than needed. + spuOutput->mSpeexEncodedFrameSize = (bitsPerFrame / 8); + if (bitsPerFrame % 8) + spuOutput->mSpeexEncodedFrameSize++; + + // we're now initialized + spuOutput->mSpeexInitialized = 1; + + //spuDebugPrintf("[Speex][SPU] Done with initing speex\n"); + + spuOutput->mSpeexReturnCode = 0; +} + +void gviSpursSpeexDecoderInitialize(SpursSpeexTaskOutput *spuTaskOut) +{ + void * decoder = gviSpursSpeexStateBuffer; + int perceptualEnhancement = 1; + + // create a new decoder state + if (gviSpursSpeexTaskDesc.mSamplesPerSecond == GVRate_8KHz) + speex_decoder_init(&speex_nb_mode, decoder); + else if (gviSpursSpeexTaskDesc.mSamplesPerSecond == GVRate_16KHz) + speex_decoder_init(&speex_wb_mode, decoder); + else + { + //spuDebugPrintf("[Speex][SPU] Error: invalid sample rate!\n"); + spuTaskOut->mSpeexReturnCode = -1; + } + + if(!decoder) + { + //spuDebugPrintf("[Speex][SPU] Error: initializing decoder failed!\n"); + spuTaskOut->mSpeexReturnCode = -2; + } + + // turn on the perceptual enhancement + speex_decoder_ctl(decoder, SPEEX_SET_ENH, &perceptualEnhancement); + + spuTaskOut->mSpeexReturnCode = 0; +} + +void gviSpursSpeexEncode(SpursSpeexTaskOutput *spuTaskOut) +{ + short *inBuffer; + float *speexBuffer; + char *outBuffer; + unsigned int i; + spuTaskOut->mSpeexEncodedFrameSize = 0; + spuTaskOut->mSpeexInitialized = 1; + spuTaskOut->mSpeexSamplesPerFrame = 0; + spuTaskOut->mSpeexReturnCode = 0; + spuTaskOut->mSpeexOutBufferSize = 0; + + speexBuffer = (float *)memalign(16, gviSpursSpeexTaskDesc.mInputBufferSize * sizeof(float)); + inBuffer = (short *)memalign(16, gviSpursSpeexTaskDesc.mInputBufferSize * sizeof(short)); + outBuffer = (char *)memalign(16, gviSpursSpeexTaskDesc.mOutputBufferSize); + + memset(speexBuffer, 0, gviSpursSpeexTaskDesc.mInputBufferSize * sizeof(float)); + memset(inBuffer, 0, gviSpursSpeexTaskDesc.mInputBufferSize * sizeof(short)); + memset(outBuffer, 0, gviSpursSpeexTaskDesc.mOutputBufferSize); + + cellDmaGet(inBuffer, (uint64_t)gviSpursSpeexTaskDesc.mInputBuffer, gviSpursSpeexTaskDesc.mInputBufferSize * sizeof(short), DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + // convert the input to floats for encoding + for(i = 0 ; i < gviSpursSpeexTaskDesc.mInputBufferSize ; i++) + speexBuffer[i] = inBuffer[i]; + + // (re)initialize the bits struct + speex_bits_init_buffer(&gviSpursSpeexBits,gviSpursSpeexBitsBuffer,sizeof(gviSpursSpeexBitsBuffer)); + + // flush the bits + speex_bits_reset(&gviSpursSpeexBits); + + // encode the frame + speex_encode(gviSpursSpeexStateBuffer, speexBuffer, &gviSpursSpeexBits); + // write the bits to the output + spuTaskOut->mSpeexOutBufferSize = speex_bits_write(&gviSpursSpeexBits, (char *)outBuffer, gviSpursSpeexTaskDesc.mEncodedFrameSize); + //spuDebugPrintf("[Speex][SPU] transferring data back, output size should be: %d\n", gviSpursSpeexTaskDesc.mOutputBufferSize>16?gviSpursSpeexTaskDesc.mOutputBufferSize:16); + cellDmaPut(outBuffer, (uint64_t)gviSpursSpeexTaskDesc.mOutputBuffer, gviSpursSpeexTaskDesc.mOutputBufferSize, DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + //spuDebugPrintf("[Speex][SPU] done transferring data back\n"); + free(speexBuffer); + free(inBuffer); + free(outBuffer); + spuTaskOut->mSpeexReturnCode = 0; +} + +void gviSpursSpeexDecodeAdd(SpursSpeexTaskOutput *spuTaskOut) +{ + char *inBuffer; + float *speexBuffer; + short *outBuffer; + int rcode; + unsigned int i; + + //spuDebugPrintf("[Speex][SPU] allocating buffers for decoding\n"); + speexBuffer = (float *)memalign(16, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(float)); + outBuffer = (short *)memalign(16, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(short)); + inBuffer = (char *)memalign(16, gviSpursSpeexTaskDesc.mInputBufferSize); + + memset(speexBuffer, 0, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(float)); + memset(outBuffer, 0, gviSpursSpeexTaskDesc.mOutputBufferSize); + memset(inBuffer, 0, gviSpursSpeexTaskDesc.mInputBufferSize * sizeof(short)); + + + //spuDebugPrintf("[Speex][SPU] done allocating, getting input data, inbuffer size: %d\n", gSpuSampleTaskDesc.mInputBufferSize); + cellDmaGet(inBuffer, (uint64_t)gviSpursSpeexTaskDesc.mInputBuffer, gviSpursSpeexTaskDesc.mInputBufferSize, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + // spuDebugPrintf("[Speex][SPU] done getting input data, preparing for speex to decode\n"); + // read the data into the bits + // (re)initialize the bits struct + speex_bits_init_buffer(&gviSpursSpeexBits,gviSpursSpeexBitsBuffer,sizeof(gviSpursSpeexBitsBuffer)); + + speex_bits_read_from(&gviSpursSpeexBits, (char *)inBuffer, gviSpursSpeexTaskDesc.mEncodedFrameSize); + + // decode it + rcode = speex_decode((void *)gviSpursSpeexStateBuffer, &gviSpursSpeexBits, speexBuffer); + assert(rcode == 0); + //spuDebugPrintf("[Speex][SPU] done with speex decode\n"); + // convert the output from floats + for(i = 0 ; i < gviSpursSpeexTaskDesc.mOutputBufferSize ; i++) + outBuffer[i] = (short)speexBuffer[i]; + + //spuDebugPrintf("[Speex][SPU] transferring data back\n"); + cellDmaPut(outBuffer, (uint64_t)gviSpursSpeexTaskDesc.mOutputBuffer, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(short), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + //spuDebugPrintf("[Speex][SPU] done transferring data back\n"); + free(speexBuffer); + free(inBuffer); + free(outBuffer); + spuTaskOut->mSpeexReturnCode = 0; +} + +void gviSpursSpeexDecodeSet(SpursSpeexTaskOutput *spuTaskOut) +{ + char *inBuffer; + float *speexBuffer; + short *outBuffer; + int rcode; + unsigned int i; + + speexBuffer = (float *)memalign(16, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(float)); + outBuffer = (short *)memalign(16, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(short)); + inBuffer = (char *)memalign(16, gviSpursSpeexTaskDesc.mInputBufferSize); + + memset(speexBuffer, 0, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(float)); + memset(inBuffer, 0, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(short)); + memset(outBuffer, 0, gviSpursSpeexTaskDesc.mInputBufferSize); + + cellDmaGet(inBuffer, (uint64_t)gviSpursSpeexTaskDesc.mInputBuffer, gviSpursSpeexTaskDesc.mInputBufferSize, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + // read the data into the bits + speex_bits_read_from(&gviSpursSpeexBits, (char *)inBuffer, gviSpursSpeexTaskDesc.mEncodedFrameSize); + + // decode it + rcode = speex_decode((void *)gviSpursSpeexStateBuffer, &gviSpursSpeexBits, speexBuffer); + assert(rcode == 0); + + // convert the output from floats + for(i = 0 ; i < gviSpursSpeexTaskDesc.mOutputBufferSize ; i++) + // Expanded to remove warnings in VS2K5 + outBuffer[i] = (short)speexBuffer[i]; + + cellDmaPut(outBuffer, (uint64_t)gviSpursSpeexTaskDesc.mOutputBuffer, gviSpursSpeexTaskDesc.mOutputBufferSize * sizeof(short), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + free(speexBuffer); + free(inBuffer); + free(outBuffer); + spuTaskOut->mSpeexReturnCode = 0; +} + +void procesEncodeInit(unsigned int uiPtr) +{ + SpursSpeexTaskOutput spuOutput; + + //spuDebugPrintf("[Speex][SPU] CMD_SAMPLE_TASK_ENCODE_INIT_COMMAND\n"); + cellDmaGet(&gviSpursSpeexTaskDesc, uiPtr, sizeof(SpursSpeexTaskDesc), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + if (gviSpursSpeexTaskDesc.mDebugPause) + { + snPause(); + } + + gviSpursSpeexEncoderInitialize(&spuOutput); + if (spuOutput.mSpeexReturnCode < 0) + { + spuDebugPrintf("[Speex][SPU] failed to initialize encoder, ret = %d\n", spuOutput.mSpeexReturnCode); + } + + //spuDebugPrintf("[Speex][SPU] done with initializing things for speex, now returning data via DMA put\n"); + + //printGlobalTaskDescData(); + + cellDmaPut(&spuOutput, (uint64_t)gviSpursSpeexTaskDesc.mSpeexTaskOutput, sizeof(SpursSpeexTaskOutput), DMA_TAG(1), + 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] task dma done\n"); + + cellDmaLargePut(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, SPEEX_ENCODER_STATE_BUFFER_SIZE, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] buffer dma done\n"); +} + +void processDecodeInit(unsigned int uiPtr) +{ + SpursSpeexTaskOutput spuOutput; + cellDmaGet(&gviSpursSpeexTaskDesc, uiPtr, sizeof(SpursSpeexTaskDesc), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] CMD_SAMPLE_TASK_DECODE_INIT_COMMAND\n"); + + if (gviSpursSpeexTaskDesc.mDebugPause) + { + snPause(); + } + + gviSpursSpeexDecoderInitialize(&spuOutput); + + if (spuOutput.mSpeexReturnCode < 0) + { + spuDebugPrintf("[Speex][SPU] failed to initialize decoder, ret = %d\n", spuOutput.mSpeexReturnCode); + } + + cellDmaPut(&spuOutput, (uint64_t)gviSpursSpeexTaskDesc.mSpeexTaskOutput, sizeof(SpursSpeexTaskOutput), DMA_TAG(1), + 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + cellDmaLargePut(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, + gviSpursSpeexTaskDesc.mSpeexStateBufferSize, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] buffer dma done\n"); +} + +void processEncode(unsigned int uiPtr) +{ + SpursSpeexTaskOutput spuOutput; + cellDmaGet(&gviSpursSpeexTaskDesc, uiPtr, sizeof(SpursSpeexTaskDesc), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + spuDebugPrintf("[Speex][SPU] CMD_SAMPLE_TASK_ENCODE_COMMAND\n"); + + if (gviSpursSpeexTaskDesc.mDebugPause) + { + snPause(); + } + cellDmaLargeGet(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, SPEEX_ENCODER_STATE_BUFFER_SIZE, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + gviSpursSpeexEncode(&spuOutput); + + if (spuOutput.mSpeexReturnCode < 0) + { + spuDebugPrintf("SPU: failed to encode, ret = %d\n", spuOutput.mSpeexReturnCode); + } + + cellDmaPut(&spuOutput, (uint64_t)gviSpursSpeexTaskDesc.mSpeexTaskOutput, sizeof(SpursSpeexTaskOutput), DMA_TAG(1), + 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + cellDmaLargePut(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, SPEEX_ENCODER_STATE_BUFFER_SIZE, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + spuDebugPrintf("[Speex][SPU] buffer dma done\n"); +} + + +void processDecodeAdd(unsigned int uiPtr) +{ + SpursSpeexTaskOutput spuOutput; + cellDmaGet(&gviSpursSpeexTaskDesc, uiPtr, sizeof(SpursSpeexTaskDesc), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] CMD_SAMPLE_TASK_DECODEADD_COMMAND\n"); + + if (gviSpursSpeexTaskDesc.mDebugPause) + { + snPause(); + } + + cellDmaLargeGet(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, gviSpursSpeexTaskDesc.mSpeexStateBufferSize, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + gviSpursSpeexDecodeAdd(&spuOutput); + + if (spuOutput.mSpeexReturnCode < 0) + { + spuDebugPrintf("SPU: failed to decode, ret = %d\n", spuOutput.mSpeexReturnCode); + } + + cellDmaPut(&spuOutput, (uint64_t)gviSpursSpeexTaskDesc.mSpeexTaskOutput, sizeof(SpursSpeexTaskOutput), DMA_TAG(1), + 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + cellDmaLargePut(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, SPEEX_DECODER_STATE_BUFFER_SIZE, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] done sending back state buffer\n"); +} + +void processDecodeSet(unsigned int uiPtr) +{ + SpursSpeexTaskOutput spuOutput; + cellDmaGet(&gviSpursSpeexTaskDesc, uiPtr, sizeof(SpursSpeexTaskDesc), DMA_TAG(1), 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] CMD_SAMPLE_TASK_DECODESET_COMMAND\n"); + + if (gviSpursSpeexTaskDesc.mDebugPause) + { + snPause(); + } + cellDmaLargeGet(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, SPEEX_DECODER_STATE_BUFFER_SIZE, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + gviSpursSpeexDecodeSet(&spuOutput); + + if (spuOutput.mSpeexReturnCode < 0) + { + spuDebugPrintf("SPU: failed to encode, ret = %d\n", spuOutput.mSpeexReturnCode); + } + + cellDmaPut(&spuOutput, (uint64_t)gviSpursSpeexTaskDesc.mSpeexTaskOutput, sizeof(SpursSpeexTaskOutput), DMA_TAG(1), + 0, 0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + cellDmaLargePut(gviSpursSpeexStateBuffer, (uint64_t)gviSpursSpeexTaskDesc.mSpeexStateBuffer, SPEEX_DECODER_STATE_BUFFER_SIZE, DMA_TAG(1), 0,0); + cellDmaWaitTagStatusAll(DMA_MASK(1)); + + //spuDebugPrintf("[Speex][SPU] buffer dma done\n"); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void cellSpursMain(qword argTask, uint64_t argTaskset) +{ + // grab the arguments to extract the command + CellSPURSArgument args={uiQWord : (vec_uint4) argTask}; + + unsigned int uiCommand, uiArg1=0, uiArg2=0; + //int spuId = cellSpursGetCurrentSpuId(); + //int taskId = cellSpursGetTaskId(); + + //spuDebugPrintf("[Speex][SPU] taskid: %d, spuId: %d\n", taskId, spuId); + + // grab the command and arguments to be processed below + uiCommand=args.uiCommand; + uiArg1=args.uiArgument0; + uiArg2=args.uiArgument1; + + uint64_t uiPtr = uiArg1; + + switch(uiCommand) + { + + case SPEEX_TASK_ENCODE_INIT_COMMAND: + { + // cleaner this way + procesEncodeInit(uiPtr); + + sendResponseToPPUAndExit(args.ppuResponseQueue, (uint32_t)uiArg2, 0); + break; + } + + case SPEEX_TASK_ENCODE_COMMAND: + { + processEncode(uiPtr); + sendResponseToPPUAndExit(args.ppuResponseQueue, (uint32_t)uiArg2, 0); + break; + } + + case SPEEX_TASK_DECODE_INIT_COMMAND: + { + processDecodeInit(uiPtr); + sendResponseToPPUAndExit(args.ppuResponseQueue, (uint32_t)uiArg2, 0); + break; + } + case SPEEX_TASK_DECODEADD_COMMAND: + { + processDecodeAdd(uiPtr); + sendResponseToPPUAndExit(args.ppuResponseQueue, (uint32_t)uiArg2, 0); + break; + } + + case SPEEX_TASK_DECODESET_COMMAND: + { + processDecodeSet(uiPtr); + sendResponseToPPUAndExit(args.ppuResponseQueue, (uint32_t)uiArg2, 0); + break; + } + + default: + { + //spuDebugPrintf("SPURS Sample:unknown case in switch uiCommand: %x uiArg1 %x uiArg2 %x\n",uiCommand,uiArg1,uiArg2); + } + + } +} + + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTaskManager_vs2005.vcproj b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTaskManager_vs2005.vcproj new file mode 100644 index 00000000000..c2503267680 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTaskManager_vs2005.vcproj @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTaskManager_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTaskManager_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpeexSpursTaskManager_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpuDoubleBuffer.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpuDoubleBuffer.h new file mode 100644 index 00000000000..2a333e237a0 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpuDoubleBuffer.h @@ -0,0 +1,106 @@ +#ifndef DOUBLE_BUFFER_H +#define DOUBLE_BUFFER_H + +#include "SpuFakeDma.h" + + +///DoubleBuffer +template +class DoubleBuffer +{ +#ifdef __CELLOS_LV2__ + T m_buffer0[size] __attribute__ ((aligned (128))); + T m_buffer1[size] __attribute__ ((aligned (128))); +#else + T m_buffer0[size]; + T m_buffer1[size]; +#endif + + T *m_frontBuffer; + T *m_backBuffer; + + unsigned int m_dmaTag; + bool m_dmaPending; +public: + bool isPending() const { return m_dmaPending;} + DoubleBuffer(); + + void init (); + + // dma get and put commands + void backBufferDmaGet(uint64_t ea, unsigned int numBytes, unsigned int tag); + void backBufferDmaPut(uint64_t ea, unsigned int numBytes, unsigned int tag); + + // gets pointer to a buffer + T *getFront(); + T *getBack(); + + // if back buffer dma was started, wait for it to complete + // then move back to front and vice versa + T *swapBuffers(); +}; + +template +DoubleBuffer::DoubleBuffer() +{ + init (); +} + +template +void DoubleBuffer::init() +{ + this->m_dmaPending = false; + this->m_frontBuffer = &this->m_buffer0[0]; + this->m_backBuffer = &this->m_buffer1[0]; +} + +template +void +DoubleBuffer::backBufferDmaGet(uint64_t ea, unsigned int numBytes, unsigned int tag) +{ + m_dmaPending = true; + m_dmaTag = tag; + cellDmaLargeGet(m_backBuffer, ea, numBytes, tag, 0, 0); +} + +template +void +DoubleBuffer::backBufferDmaPut(uint64_t ea, unsigned int numBytes, unsigned int tag) +{ + m_dmaPending = true; + m_dmaTag = tag; + cellDmaLargePut(m_backBuffer, ea, numBytes, tag, 0, 0); +} + +template +T * +DoubleBuffer::getFront() +{ + return m_frontBuffer; +} + +template +T * +DoubleBuffer::getBack() +{ + return m_backBuffer; +} + +template +T * +DoubleBuffer::swapBuffers() +{ + if (m_dmaPending) + { + cellDmaWaitTagStatusAll(1< +#include + +#define DMA_TAG(xfer) (xfer + 1) +#define DMA_MASK(xfer) (1 << DMA_TAG(xfer)) + +#elif defined (WIN32) + +#define DMA_TAG(a) (a) +#define DMA_MASK(a) (a) + + +/// cellDmaLargeGet Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy) +int cellDmaLargeGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); +int cellDmaGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); +/// cellDmaLargePut Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy) +int cellDmaLargePut(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); +/// cellDmaWaitTagStatusAll Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy) +void cellDmaWaitTagStatusAll(int ignore); +#endif //WIN32 + +///stallingUnalignedDmaSmallGet internally uses DMA_TAG(1) +int stallingUnalignedDmaSmallGet(void *ls, uint64_t ea, uint32_t size); + +#endif //FAKE_DMA_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpuSpeexTaskOutput.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpuSpeexTaskOutput.h new file mode 100644 index 00000000000..9c0d0a99288 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpuSpeexTaskOutput.h @@ -0,0 +1,33 @@ + + +#ifndef __SPEEX_TASK_OUTPUT_H +#define __SPEEX_TASK_OUTPUT_H + +#define POST_ALIGN(x) __attribute__((aligned (x))) + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPEEX_ENCODER_WB_BUFFERSIZE 32256 +#define SPEEX_ENCODER_NB_BUFFERSIZE 32288 +#define SPEEX_ENCODER_STATE_BUFFER_SIZE (SPEEX_ENCODER_NB_BUFFERSIZE + SPEEX_ENCODER_WB_BUFFERSIZE+128) +#define SPEEX_DECODER_NB_BUFFERSIZE 16832 +#define SPEEX_DEOCDER_WB_BUFFERSIZE 24192 +#define SPEEX_DECODER_STATE_BUFFER_SIZE (SPEEX_DECODER_NB_BUFFERSIZE+SPEEX_DEOCDER_WB_BUFFERSIZE+128) +//#define SPEEX_STATE_ + ///pure output, any input is in SpuSampleTaskDesc +struct SpursSpeexTaskOutput +{ + int mSpeexInitialized; + int mSpeexSamplesPerFrame; + int mSpeexEncodedFrameSize; + int mSpeexOutBufferSize; + int mSpeexReturnCode; +} POST_ALIGN(128); + +#ifdef __cplusplus +} +#endif + +#endif //__SPEEX_TASK_OUTPUT_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexCInterface.cpp b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexCInterface.cpp new file mode 100644 index 00000000000..47d64db880e --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexCInterface.cpp @@ -0,0 +1,102 @@ +#include "spursConfiguration.h" +#include "SpursSpeexCInterface.h" +#include +#include "SpursSpeexTaskManager.h" +#include "spursSupportInterface.h" +#include + +SpursSpeexTaskManager* gSpursSpeexTaskManager = 0; +SpursSupportInterface* gSpursSupport = 0; +const unsigned int MAX_SPURS_SPEEX_TASKS=1; + + +///initialize SPURS +int initializeSpursSampleTask() +{ + gSpursSupport = new SpursSupportInterface(); + + gSpursSpeexTaskManager = new SpursSpeexTaskManager(gSpursSupport,MAX_SPURS_SPEEX_TASKS); + return gSpursSpeexTaskManager->initialize(); +} + +///not finished, need to pass proper data +int issueSampleTaskEncodeInit(int quality, int samplesPerFrame, SpursSpeexTaskOutput *taskOutput, char *userAllocatedSpeexBuffer, int userAllocatedSpeexBufferSize) +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + + return gSpursSpeexTaskManager->issueEncodeInitTask(quality, samplesPerFrame, taskOutput,userAllocatedSpeexBuffer,userAllocatedSpeexBufferSize); + + //printf("issueSampleTaskEncodeInit called\n"); +} + +///submit some work to SPURS +int issueSampleTaskEncode(short* inBuffer, int inBufferSize, int encodedFrameSize, char *outBuffer, int outBufferSize, + struct SpursSpeexTaskOutput *taskOuput, char *userAllocatedSpeexBuffer, int userAllocatedSpeexBufferSize ) +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + + return gSpursSpeexTaskManager->issueEncodeTask(inBuffer, inBufferSize, encodedFrameSize, outBuffer, outBufferSize, taskOuput, + userAllocatedSpeexBuffer,userAllocatedSpeexBufferSize); + + //printf("issueSampleTaskEncode called\n"); +} + +int issueSampleTaskDecodeAdd(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput) +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + + return gSpursSpeexTaskManager->issueDecodeAddTask(decoderStateBuffer, decoderStateBufferSize, inBuffer, inBufferSize, encodedFrameSize, + outBuffer, outBufferSize, taskOutput); + + //printf("issueSampleTaskDecode called\n"); +} + +int issueSampleTaskDecodeSet(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput) +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + + return gSpursSpeexTaskManager->issueDecodeSetTask(decoderStateBuffer, decoderStateBufferSize, inBuffer, inBufferSize, encodedFrameSize, + outBuffer, outBufferSize, taskOutput); + + //printf("issueSampleTaskDecode called\n"); +} + +int issueSampleTaskDecodeInit(char *decoderStateBuffer, int decoderStateBufferSize, int sampleRate, struct SpursSpeexTaskOutput *taskOutput) +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + + return gSpursSpeexTaskManager->issueDecodeInitTask(decoderStateBuffer, decoderStateBufferSize, sampleRate, taskOutput); + + //printf("issueSampleTaskDecode called\n"); +} + + +///wait for the work to be finished +/* +int flushSampleTask() +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + + //printf("flushSampleTask called\n"); +} +*/ + +///shutdown SPURS +int shutdownSpursTask() +{ + btAssert(gSpursSpeexTaskManager!=0); + btAssert(gSpursSupport!=0); + delete gSpursSpeexTaskManager; + delete gSpursSupport; + if (spursConfiguration_terminate() != 0) + return -1; + return 0; +} diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexCInterface.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexCInterface.h new file mode 100644 index 00000000000..3785165c1ee --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexCInterface.h @@ -0,0 +1,54 @@ +#ifndef SPU_TASK_C_INTERFACE_H +#define SPU_TASK_C_INTERFACE_H + +//#include +#include "SpuSpeexTaskOutput.h" + +#define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +typedef float plReal; +typedef plReal plVector3[3]; +typedef plReal plQuaternion[4]; + +#ifdef __cplusplus +extern "C" { +#endif + +#define GVI_REMAINING_BYTES 3 + + +///initialize SPURS +int initializeSpursSampleTask(); + +///submit some work to SPURS +int issueSampleTaskEncode(short* inBuffer, int inBufferSize, int encodedFrameSize, char *outBuffer, int outBufferSize, + struct SpursSpeexTaskOutput *taskOuput, char *userAllocatedSpeexBuffer, + int userAllocatedSpeexBufferSize); + +///not finished, need to pass proper data +int issueSampleTaskEncodeInit(int quality, int samplesPerFrame, struct SpursSpeexTaskOutput *taskOutput, + char *userAllocatedSpeexBuffer, int userAllocatedSpeexBufferSize); +///not finished, need to pass proper data +int issueSampleTaskDecodeAdd(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput); +int issueSampleTaskDecodeSet(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput); +///not finished, need to pass proper data +int issueSampleTaskDecodeInit(char *decoderStateBuffer, int decoderStateBufferSize, int sampleRate, struct SpursSpeexTaskOutput *taskOutput); + + + + +///wait for the work to be finished +//int flushSampleTask(); + +///shutdown SPURS +int shutdownSpursTask(); + +///used to pass into SPURS + +#ifdef __cplusplus +} +#endif + +#endif //SPU_TASK_C_INTERFACE_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexTaskManager.cpp b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexTaskManager.cpp new file mode 100644 index 00000000000..1923db73f7f --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexTaskManager.cpp @@ -0,0 +1,273 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +//#define __CELLOS_LV2__ 1 + +#define USE_SAMPLE_PROCESS 1 +#ifdef USE_SAMPLE_PROCESS + + +#include "spursThreadSupportInterface.h" + +//#include "SPUAssert.h" +#include + + +#include "SpursSpeexTaskManager.h" + + +#include + + +void SampleThreadFunc(void* userPtr,void* lsMemory) +{ + //do nothing + printf("hello world\n"); +} + +void* SamplelsMemoryFunc() +{ + //don't create local store memory, just return 0 + return 0; +} + + + +extern "C" +{ + extern char SPU_SAMPLE_ELF_SYMBOL[]; +}; + + + + + +SpursSpeexTaskManager::SpursSpeexTaskManager(spursThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks) +:m_threadInterface(threadInterface), +m_maxNumOutstandingTasks(maxNumOutstandingTasks) +{ + + m_taskBusy.resize(m_maxNumOutstandingTasks); + mSpursSpeexTaskDesc.resize(m_maxNumOutstandingTasks); + + for (int i = 0; (unsigned int)i < m_maxNumOutstandingTasks; i++) + { + m_taskBusy[i] = false; + } + m_numBusyTasks = 0; + m_currentTask = 0; + + m_initialized = false; +} + +SpursSpeexTaskManager::~SpursSpeexTaskManager() +{ + m_threadInterface->stopSPU(); +} + + + +int SpursSpeexTaskManager::initialize() +{ +#ifdef DEBUG_SPU_TASK_SCHEDULING + printf("SpuSampleTaskProcess::initialize()\n"); +#endif //DEBUG_SPU_TASK_SCHEDULING + + for (int i = 0; (unsigned int)i < m_maxNumOutstandingTasks; i++) + { + m_taskBusy[i] = false; + } + m_numBusyTasks = 0; + m_currentTask = 0; + m_initialized = true; + + if (m_threadInterface->startSPU() != 0) + { + return -1; + } + return 0; +} + + + +int SpursSpeexTaskManager::issueEncodeInitTask( int theQuality,int theGviSpeexSamplesPerSecond, SpursSpeexTaskOutput *taskOutput, char *userAllocatedSpeexBuffer,int userAllocatedSpeexBufferSize ) +{ + m_taskBusy[m_currentTask] = true; + m_numBusyTasks++; + + SpursSpeexTaskDesc& taskDesc = mSpursSpeexTaskDesc[m_currentTask]; + taskDesc.mSpeexStateBuffer = userAllocatedSpeexBuffer; + taskDesc.mSpeexStateBufferSize = userAllocatedSpeexBufferSize; + + taskDesc.mQuality = theQuality; + taskDesc.mSamplesPerSecond = theGviSpeexSamplesPerSecond; + taskDesc.mSpeexTaskOutput = taskOutput; + if (issueTask(taskDesc,SPEEX_TASK_ENCODE_INIT_COMMAND) != 0) + return -1; + return 0; +} + +int SpursSpeexTaskManager::issueEncodeTask(int16_t * inBuffer, int inBufferSize, int encodedFrameSize, char *outBuffer, + int outBufferSize, SpursSpeexTaskOutput *taskOuput,char *userAllocatedSpeexBuffer, + int userAllocatedSpeexBufferSize ) +{ + m_taskBusy[m_currentTask] = true; + m_numBusyTasks++; + + SpursSpeexTaskDesc& taskDesc = mSpursSpeexTaskDesc[m_currentTask]; + taskDesc.mSpeexStateBuffer = userAllocatedSpeexBuffer; + taskDesc.mSpeexStateBufferSize = userAllocatedSpeexBufferSize; + taskDesc.mEncodedFrameSize = encodedFrameSize; + taskDesc.mInputBuffer = inBuffer; + taskDesc.mInputBufferSize = inBufferSize; + taskDesc.mOutputBuffer = outBuffer; + taskDesc.mOutputBufferSize = outBufferSize; + taskDesc.mSpeexTaskOutput = taskOuput; + if (issueTask(taskDesc,SPEEX_TASK_ENCODE_COMMAND) != 0) + return -1; + return 0; +} + +int SpursSpeexTaskManager::issueDecodeAddTask(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput) +{ + m_taskBusy[m_currentTask] = true; + m_numBusyTasks++; + + SpursSpeexTaskDesc& taskDesc = mSpursSpeexTaskDesc[m_currentTask]; + taskDesc.mSpeexStateBuffer = decoderStateBuffer; + taskDesc.mSpeexStateBufferSize = decoderStateBufferSize; + taskDesc.mEncodedFrameSize = encodedFrameSize; + taskDesc.mInputBuffer = inBuffer; + taskDesc.mInputBufferSize = inBufferSize; + taskDesc.mOutputBuffer = outBuffer; + taskDesc.mOutputBufferSize = outBufferSize; + taskDesc.mSpeexTaskOutput = taskOutput; + if (issueTask(taskDesc,SPEEX_TASK_DECODEADD_COMMAND) != 0) + return -1; + return 0; +} + +int SpursSpeexTaskManager::issueDecodeSetTask(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput ) +{ + m_taskBusy[m_currentTask] = true; + m_numBusyTasks++; + + SpursSpeexTaskDesc& taskDesc = mSpursSpeexTaskDesc[m_currentTask]; + taskDesc.mSpeexStateBuffer = decoderStateBuffer; + taskDesc.mSpeexStateBufferSize = decoderStateBufferSize; + taskDesc.mEncodedFrameSize = encodedFrameSize; + taskDesc.mInputBuffer = inBuffer; + taskDesc.mInputBufferSize = inBufferSize; + taskDesc.mOutputBuffer = outBuffer; + taskDesc.mOutputBufferSize = outBufferSize; + taskDesc.mSpeexTaskOutput = taskOutput; + if (issueTask(taskDesc,SPEEX_TASK_DECODESET_COMMAND) != 0) + return -1; + return 0; +} + +int SpursSpeexTaskManager::issueDecodeInitTask( char *decoderStateBuffer, int decoderStateBufferSize, int sampleRate, struct SpursSpeexTaskOutput *taskOutput ) +{ + m_taskBusy[m_currentTask] = true; + m_numBusyTasks++; + + SpursSpeexTaskDesc& taskDesc = mSpursSpeexTaskDesc[m_currentTask]; + taskDesc.mSpeexStateBuffer = decoderStateBuffer; + taskDesc.mSpeexStateBufferSize = decoderStateBufferSize; + taskDesc.mSamplesPerSecond = sampleRate; + taskDesc.mSpeexTaskOutput = taskOutput; + if (issueTask(taskDesc,SPEEX_TASK_DECODE_INIT_COMMAND) != 0) + return -1; + return 0; +} + + +int SpursSpeexTaskManager::issueTask( SpursSpeexTaskDesc& taskDesc,uint32_t uiCommand ) +{ +#ifdef DEBUG_SPU_TASK_SCHEDULING + printf("SpuSampleTaskProcess::issueTask (m_currentTask= %d\)n", m_currentTask); +#endif //DEBUG_SPU_TASK_SCHEDULING + + //some bookkeeping to recognize finished tasks + taskDesc.mTaskId = m_currentTask; + + if (m_threadInterface->sendRequest(uiCommand, (uint32_t) &taskDesc, m_currentTask) != 0) + { + m_taskBusy[m_currentTask] = false; + m_numBusyTasks--; + return -1; + } + + // if all tasks busy, wait for spu event to clear the task. + if (m_numBusyTasks >= m_maxNumOutstandingTasks) + { + unsigned int taskId; + unsigned int outputSize; + + if (m_threadInterface->waitForResponse(&taskId, &outputSize) != 0) + { + return -2; + } + + //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize); + //postProcess(taskId, outputSize); + m_taskBusy[taskId] = false; + m_numBusyTasks--; + } + + // find new task buffer + for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++) + { + if (!m_taskBusy[i]) + { + m_currentTask = i; + break; + } + } + return 0; +} + +///Optional PPU-size post processing for each task +// void SpuSampleTaskProcess::postProcess(int taskId, int outputSize) +// { +// +// } + + +int SpursSpeexTaskManager::flush() +{ +#ifdef DEBUG_SPU_TASK_SCHEDULING + printf("\nSpuCollisionTaskProcess::flush()\n"); +#endif //DEBUG_SPU_TASK_SCHEDULING + + // all tasks are issued, wait for all tasks to be complete + while(m_numBusyTasks > 0) + { + // Consolidating SPU code + unsigned int taskId; + unsigned int outputSize; + + if (m_threadInterface->waitForResponse(&taskId, &outputSize) != 0) + return -1; + //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize); + //postProcess(taskId, outputSize); + m_taskBusy[taskId] = false; + m_numBusyTasks--; + } + return 0; +} +#endif //USE_SAMPLE_PROCESS diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexTaskManager.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexTaskManager.h new file mode 100644 index 00000000000..887a5167166 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/SpursSpeexTaskManager.h @@ -0,0 +1,122 @@ +// Gamespy Technology +// NOTE: this code has been provided by Sony for usage in Speex SPURS Manager + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPU_SAMPLE_TASK_PROCESS_H +#define SPU_SAMPLE_TASK_PROCESS_H + +#include + + +#include "spursPlatformDefinitions.h" + +#include + +#include "spursAlignedObjectArray.h" + +#include "SpuSpeexTaskOutput.h" + +///SpuSampleTaskDesc +struct SpursSpeexTaskDesc +{ + SpursSpeexTaskDesc() + :mDebugPause(false) + { + + } + int mQuality; + int mSamplesPerSecond; + int mEncodedFrameSize; + void *mInputBuffer; // make it + unsigned int mInputBufferSize; + + SpursSpeexTaskOutput *mSpeexTaskOutput; + void *mOutputBuffer; + unsigned int mOutputBufferSize; + + char *mSpeexStateBuffer; + unsigned int mSpeexStateBufferSize; + bool mDebugPause; + + uint16_t mTaskId; + //uint16_t _padding_[3]; //padding to make this multiple of 16 bytes +} POST_ALIGN(128); + +//just add your commands here, try to keep them globally unique for debugging purposes +#define SPEEX_TASK_ENCODE_COMMAND 10 +#define SPEEX_TASK_ENCODE_INIT_COMMAND 11 +#define SPEEX_TASK_DECODEADD_COMMAND 12 +#define SPEEX_TASK_DECODESET_COMMAND 13 +#define SPEEX_TASK_DECODE_INIT_COMMAND 14 + + + +/// SpuSampleTaskProcess handles SPU processing of collision pairs. +/// When PPU issues a task, it will look for completed task buffers +/// PPU will do postprocessing, dependent on workunit output (not likely) +class SpursSpeexTaskManager +{ + // track task buffers that are being used, and total busy tasks + spursAlignedObjectArray m_taskBusy; + spursAlignedObjectArraymSpursSpeexTaskDesc; + + unsigned int m_numBusyTasks; + + // the current task and the current entry to insert a new work unit + unsigned int m_currentTask; + + bool m_initialized; + + //void postProcess(int taskId, int outputSize); + + class spursThreadSupportInterface* m_threadInterface; + + unsigned int m_maxNumOutstandingTasks; + + + int issueTask(SpursSpeexTaskDesc& taskDesc,uint32_t uiCommand); + + +public: + SpursSpeexTaskManager(spursThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks); + + ~SpursSpeexTaskManager(); + + ///call initialize in the beginning of the frame, before addCollisionPairToTask + int initialize(); + + int issueEncodeTask(int16_t * inBuffer, int inBufferSize, int encodedFrameSize, char *outBuffer, int outBufferSize, + SpursSpeexTaskOutput *taskOuput,char *m_userAllocatedSpeexBuffer,int userAllocatedSpeexBufferSize); + + int issueEncodeInitTask(int theQuality,int theGviSpeexSamplesPerSecond, SpursSpeexTaskOutput *taskOutput, char *m_userAllocatedSpeexBuffer, + int userAllocatedSpeexBufferSize); + + int issueDecodeAddTask(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput); + + int issueDecodeSetTask(char *decoderStateBuffer, int decoderStateBufferSize, char *inBuffer, int inBufferSize, int encodedFrameSize, + short* outBuffer, int outBufferSize, struct SpursSpeexTaskOutput *taskOutput); + + int issueDecodeInitTask(char *decoderStateBuffer, int decoderStateBufferSize, int sampleRate, struct SpursSpeexTaskOutput *taskOutput); + + ///call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished + int flush(); +}; + + +#endif // SPU_SAMPLE_TASK_PROCESS_H + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedAllocator.cpp b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedAllocator.cpp new file mode 100644 index 00000000000..20221a87fe8 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedAllocator.cpp @@ -0,0 +1,38 @@ +// Gamespy Technology +// NOTE: this code has been provided by Sony for usage in Speex SPURS Manager + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "spursAlignedAllocator.h" + +#include + +int numAllocs = 0; +int numFree = 0; + +void* spursAlignedAlloc (int size, int alignment) +{ + numAllocs++; + return memalign(alignment, size); +} + +void spursAlignedFree (void* ptr) +{ + numFree++; + free(ptr); +} + + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedAllocator.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedAllocator.h new file mode 100644 index 00000000000..97f1c7fa91b --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedAllocator.h @@ -0,0 +1,81 @@ +// Gamespy Technology +// NOTE: this code has been provided by Sony for usage in Speex SPURS Manager + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_ALIGNED_ALLOCATOR +#define BT_ALIGNED_ALLOCATOR + +///we probably replace this with our own aligned memory allocator +///so we replace _aligned_malloc and _aligned_free with our own +///that is better portable and more predictable + +void* spursAlignedAlloc (int size, int alignment); + +void spursAlignedFree (void* ptr); + + +typedef int size_type; + + +template < typename T , unsigned Alignment > +class spursAlignedAllocator { + + typedef spursAlignedAllocator< T , Alignment > self_type; + +public: + + //just going down a list: + spursAlignedAllocator() {} + /* + btAlignedAllocator( const self_type & ) {} + */ + + template < typename Other > + spursAlignedAllocator( const spursAlignedAllocator< Other , Alignment > & ) {} + + typedef const T* const_pointer; + typedef const T& const_reference; + typedef T* pointer; + typedef T& reference; + typedef T value_type; + + pointer address ( reference ref ) const { return &ref; } + const_pointer address ( const_reference ref ) const { return &ref; } + pointer allocate ( size_type n , const_pointer * hint = 0 ) { + (void)hint; + return reinterpret_cast< pointer >(spursAlignedAlloc( sizeof(value_type) * n , Alignment )); + } + void construct ( pointer ptr , const value_type & value ) { new (ptr) value_type( value ); } + void deallocate( pointer ptr ) { + spursAlignedFree( reinterpret_cast< void * >( ptr ) ); + } + void destroy ( pointer ptr ) { ptr->~value_type(); } + + + template < typename O > struct rebind { + typedef spursAlignedAllocator< O , Alignment > other; + }; + template < typename O > + self_type & operator=( const spursAlignedAllocator< O , Alignment > & ) { return *this; } + + friend bool operator==( const self_type & , const self_type & ) { return true; } +}; + + + +#endif //BT_ALIGNED_ALLOCATOR + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedObjectArray.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedObjectArray.h new file mode 100644 index 00000000000..af13d3b5ae4 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursAlignedObjectArray.h @@ -0,0 +1,370 @@ +// Gamespy Technology +// NOTE: this code has been provided by Sony for usage in Speex SPURS Manager + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef BT_OBJECT_ARRAY__ +#define BT_OBJECT_ARRAY__ + +#include "spursScalar.h" // has definitions like SIMD_FORCE_INLINE +#include "spursAlignedAllocator.h" + +///If the platform doesn't support placement new, you can disable BT_USE_PLACEMENT_NEW +///then the btAlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors +///You can enable BT_USE_MEMCPY, then swapping elements in the array will use memcpy instead of operator= +///see discussion here: http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1231 and +///http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1240 + +#define BT_USE_PLACEMENT_NEW 1 +//#define BT_USE_MEMCPY 1 //disable, because it is cumbersome to find out for each platform where memcpy is defined. It can be in or or otherwise... + +#ifdef BT_USE_MEMCPY +#include +#include +#endif //BT_USE_MEMCPY + +#ifdef BT_USE_PLACEMENT_NEW +#include //for placement new +#endif //BT_USE_PLACEMENT_NEW + + +///btAlignedObjectArray uses a subset of the stl::vector interface for its methods +///It is developed to replace stl::vector to avoid STL alignment issues to add SIMD/SSE data +template +//template +class spursAlignedObjectArray +{ + spursAlignedAllocator m_allocator; + + int m_size; + int m_capacity; + T* m_data; + + protected: + SIMD_FORCE_INLINE int allocSize(int size) + { + return (size ? size*2 : 1); + } + SIMD_FORCE_INLINE void copy(int start,int end, T* dest) + { + int i; + for (i=start;i size()) + { + reserve(newsize); + } +#ifdef BT_USE_PLACEMENT_NEW + for (int i=curSize;i + void downHeap(T *pArr, int k, int n,L CompareFunc) + { + /* PRE: a[k+1..N] is a heap */ + /* POST: a[k..N] is a heap */ + + T temp = pArr[k - 1]; + /* k has child(s) */ + while (k <= n/2) + { + int child = 2*k; + + if ((child < n) && CompareFunc(pArr[child - 1] , pArr[child])) + { + child++; + } + /* pick larger child */ + if (CompareFunc(temp , pArr[child - 1])) + { + /* move child up */ + pArr[k - 1] = pArr[child - 1]; + k = child; + } + else + { + break; + } + } + pArr[k - 1] = temp; + } /*downHeap*/ + + void swap(int index0,int index1) + { +#ifdef BT_USE_MEMCPY + char temp[sizeof(T)]; + memcpy(temp,&m_data[index0],sizeof(T)); + memcpy(&m_data[index0],&m_data[index1],sizeof(T)); + memcpy(&m_data[index1],temp,sizeof(T)); +#else + T temp = m_data[index0]; + m_data[index0] = m_data[index1]; + m_data[index1] = temp; +#endif //BT_USE_PLACEMENT_NEW + + } + + template + void heapSort(L CompareFunc) + { + /* sort a[0..N-1], N.B. 0 to N-1 */ + int k; + int n = m_size; + for (k = n/2; k > 0; k--) + { + downHeap(m_data, k, n, CompareFunc); + } + + /* a[1..N] is now a heap */ + while ( n>=1 ) + { + swap(0,n-1); /* largest of a[0..n-1] */ + + + n = n - 1; + /* restore a[1..i-1] heap */ + downHeap(m_data, 1, n, CompareFunc); + } + } + + ///non-recursive binary search, assumes sorted array + int findBinarySearch(const T& key) const + { + int first = 0; + int last = size(); + + //assume sorted array + while (first <= last) { + int mid = (first + last) / 2; // compute mid point. + if (key > m_data[mid]) + first = mid + 1; // repeat search in top half. + else if (key < m_data[mid]) + last = mid - 1; // repeat search in bottom half. + else + return mid; // found it. return position ///// + } + return size(); // failed to find key + } + + + int findLinearSearch(const T& key) const + { + int index=size(); + int i; + + for (i=0;i + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELL_SPURS_DEFAULT_SPU_COUNT 1 + +// "-Wl,--whole-archive -lprof_stub -Wl,--no-whole-archive" + +enum CellSpursReturn { + CELL_SPURS_OK=0, + CELL_SPURS_EBUSY, + CELL_SPURS_EINVAL, + CELL_SPURS_EMISC +}; + +/** + * \brief This class controls the SPU usage of SPURS + * + * There are three ways to initialize SPU usage. + * + * The first way is to initialize SPURS yourself, and to pass in a pointer to + * SPURS as well as priorities for the use of the SPUs, using initWithSpurs. + * This is good if you intend to use SPURS elsewhere in your code, the management + * can be shared across all processes. + * + * The second way is to control the number of SPUs used by SPURS with + * initWithSpuCount. Software will create its own instance of SPURS when it needs + * it using that maximum number of SPUs. + * + * If you do neither of the two, Software will create its own instance of SPURS when + * it needs it using CELL_SPURS_DEFAULT_SPU_COUNT SPUs. + * + * terminate() can be used to either detatch from an existing SPURS or to + * terminate the Software-created SPURS. Note that this will only work if all collision + * scenes have been destroyed, otherwise SPURS would still be needed. + * + * Creating a new scene will cause SPURS to re-initialize. + * + * isSpursInitialized can be used to query whether software is currently using SPURS. + * + **/ + +/** + * \brief Initializes SPUs given a pre-configured SPURS. + * \param[in] pSpurs A pointer to SPURS + * \param[in] iSPUCount The number of SPUs + * \param[in] auiPriorities The priorities for the code to use + * \return Return is: + * CELL_SPURS_OK on success + * CELL_SPURS_EBUSY if SPU usage has already been initialized + * CELL_SPURS_EINVAL if the priorities or SPURS pointer is invalid. + */ +int spursConfiguration_initWithSpurs(CellSpurs *pSpurs, int iSPUCount, uint8_t auiPriorities[8]); + +/** + * \brief Sets the number of SPUs to be used by a software-initialized SPURS. + * \param[in] iSPUCount A valid value is in the range 1-6 + * \return Return is: + * CELL_SPURS_OK on success + * CELL_SPURS_EBUSY if SPU usage has already been initialized + * CELL_SPURS_EINVAL if iSPUCount is out of range or if SPURS couldn't be + * initialized to that many SPUs. + */ +int spursConfiguration_initWithSpuCount(int iSPUCount); + +/** + * \brief Terminates (or disconnects from) SPURS. + * \return Return is: + * CELL_SPURS_OK if SPURS terminates ok, or if it was previously terminated/ + * never initialized. + * CELL_SPURS_EBUSY if there are existing Scenes which would need SPURS. + */ +int spursConfiguration_terminate(); + +/** + * \brief Queries whether SPU usage has been initialized. + * \return True if initialized. + */ +bool spursConfiguration_isSpursInitialized(); + +#ifdef __cplusplus +} +#endif + +#endif //__CELL_SPU_CONFIG diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursPlatformDefinitions.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursPlatformDefinitions.h new file mode 100644 index 00000000000..2d00593a308 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursPlatformDefinitions.h @@ -0,0 +1,13 @@ +#ifndef TYPE_DEFINITIONS_H +#define TYPE_DEFINITIONS_H + +////////////////////////////////////////////////////////////////////////// +// Don't need printf in this sample +///Playstation 3 Cell SDK +//#include + +#include +#include +#include //for memcpy + +#endif //TYPE_DEFINITIONS_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursScalar.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursScalar.h new file mode 100644 index 00000000000..e766ca342d3 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursScalar.h @@ -0,0 +1,172 @@ +// Gamespy Technology +// NOTE: this code has been provided by Sony for usage in Speex SPURS Manager + +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef SIMD___SCALAR_H +#define SIMD___SCALAR_H + +#include + +#include +#include +#include + +#define SIMD_FORCE_INLINE inline +#define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) +#ifndef assert +#include +#endif +#define btAssert assert +//btFullAssert is optional, slows down a lot +#define btFullAssert(x) + +////////////////////////////////////////////////////////////////////////// +// removed since only ps3 used +/* +/// older compilers (gcc 3.x) and Sun needs double version of sqrt etc. +/// exclude Apple Intel (i's assumed to be a Macbook or new Intel Dual Core Processor) +#if defined (__sun) || defined (__sun__) || defined (__sparc) || (defined (__APPLE__) && ! defined (__i386__)) +//use slow double float precision operation on those platforms +#ifndef BT_USE_DOUBLE_PRECISION +#define BT_FORCE_DOUBLE_FUNCTIONS +#endif +#endif +*/ + +////////////////////////////////////////////////////////////////////////// +// removed since only ps3 used +/* +#if defined(BT_USE_DOUBLE_PRECISION) +typedef double btScalar; +#else +typedef float btScalar; +#endif +*/ + +////////////////////////////////////////////////////////////////////////// +// removed since not needed +/* +#if defined(BT_USE_DOUBLE_PRECISION) || defined(BT_FORCE_DOUBLE_FUNCTIONS) + +SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) { return sqrt(x); } +SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabs(x); } +SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cos(x); } +SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sin(x); } +SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tan(x); } +SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { return acos(x); } +SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { return asin(x); } +SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atan(x); } +SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2(x, y); } +SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return exp(x); } +SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return log(x); } +SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return pow(x,y); } + +#else + +SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) { return sqrtf(x); } +SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabsf(x); } +SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cosf(x); } +SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sinf(x); } +SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tanf(x); } +SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { return acosf(x); } +SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { return asinf(x); } +SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atanf(x); } +SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2f(x, y); } +SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return expf(x); } +SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return logf(x); } +SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return powf(x,y); } + +#endif +*/ + + +////////////////////////////////////////////////////////////////////////// +// removed since not necessary +/* +#define SIMD_2_PI btScalar(6.283185307179586232) +#define SIMD_PI (SIMD_2_PI * btScalar(0.5)) +#define SIMD_HALF_PI (SIMD_2_PI * btScalar(0.25)) +#define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0)) +#define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI) + +#ifdef BT_USE_DOUBLE_PRECISION +#define SIMD_EPSILON DBL_EPSILON +#define SIMD_INFINITY DBL_MAX +#else +#define SIMD_EPSILON FLT_EPSILON +#define SIMD_INFINITY FLT_MAX +#endif + +SIMD_FORCE_INLINE btScalar btAtan2Fast(btScalar y, btScalar x) +{ + btScalar coeff_1 = SIMD_PI / 4.0f; + btScalar coeff_2 = 3.0f * coeff_1; + btScalar abs_y = btFabs(y); + btScalar angle; + if (x >= 0.0f) { + btScalar r = (x - abs_y) / (x + abs_y); + angle = coeff_1 - coeff_1 * r; + } else { + btScalar r = (x + abs_y) / (abs_y - x); + angle = coeff_2 - coeff_1 * r; + } + return (y < 0.0f) ? -angle : angle; +} + +SIMD_FORCE_INLINE bool btFuzzyZero(btScalar x) { return btFabs(x) < SIMD_EPSILON; } + +SIMD_FORCE_INLINE bool btEqual(btScalar a, btScalar eps) { + return (((a) <= eps) && !((a) < -eps)); +} +SIMD_FORCE_INLINE bool btGreaterEqual (btScalar a, btScalar eps) { + return (!((a) <= eps)); +} +*/ + +/*SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cosf(x); } +SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sinf(x); } +SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tanf(x); } +SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { return acosf(x); } +SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { return asinf(x); } +SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atanf(x); } +SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2f(x, y); } +*/ + + +////////////////////////////////////////////////////////////////////////// +// removed since not necessary +/* +SIMD_FORCE_INLINE int btIsNegative(btScalar x) { + return x < btScalar(0.0) ? 1 : 0; +} + +SIMD_FORCE_INLINE btScalar btRadians(btScalar x) { return x * SIMD_RADS_PER_DEG; } +SIMD_FORCE_INLINE btScalar btDegrees(btScalar x) { return x * SIMD_DEGS_PER_RAD; } + +#define BT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +#ifndef btFsel +SIMD_FORCE_INLINE btScalar btFsel(btScalar a, btScalar b, btScalar c) +{ + return a >= 0 ? b : c; +} +#endif +#define btFsels(a,b,c) (btScalar)btFsel(a,b,c) +*/ + +#endif //SIMD___SCALAR_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursSupportInterface.cpp b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursSupportInterface.cpp new file mode 100644 index 00000000000..4b7a42759ff --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursSupportInterface.cpp @@ -0,0 +1,553 @@ +#include "spursConfiguration.h" +#include "spursSupportInterface.h" +#include +#include +#include +#include +#include +#include +#include + +#define SCE_EXTERNAL_RELEASE + +// for CELL_FS_MAX_FS_PATH_LENGTH +#include + +static uint32_t _g_uiNextEventQueueKey=0x92400ABDUL; +uint32_t _SpursSupportGetUniqueEventQueueKey() { + return _g_uiNextEventQueueKey++; +} + +sys_event_queue_t _g_SpuPrintfEventQueue; +sys_ppu_thread_t _g_SpursPrintfThread; + +void _SpursPrintfThreadMain(uint64_t arg); + +#define SPURS_PPU_THREAD_PRIO 1001 +#define SPU_PRINTF_EVENT_QUEUE_SIZE 8 +#define SPU_PRINTF_EVENT_QUEUE_PORT 0x1 +#define SPU_PRINTF_THREAD_PRIO 1001 +#define SPU_PRINTF_THREAD_STACK_SIZE (64 * 1024) + +/* +typedef struct BulletSpursElf { + const char *pcElfName; + void *pvElfImage; +} BulletSpursElf; +*/ + +#ifdef _DEBUG +extern char _binary_spu_SpeexSpursTaskDebug_elf_start[]; +void *g_SpursTaskElfStart = _binary_spu_SpeexSpursTaskDebug_elf_start; +#else +extern char _binary_spu_SpeexSpursTaskRelease_elf_start[]; +void *g_SpursTaskElfStart = _binary_spu_SpeexSpursTaskRelease_elf_start; +#endif //#ifdef _DEBUG + + +/* +BulletSpursElf _g_aSPURSElfs[]={ +#ifdef _DEBUG + {"test.elf", _binary_spu_PS3_SPURS_SpeexDebug_elf_start} +#else + {"test.elf", _binary_spu_PS3_SPURS_SpeexRelease_elf_start} +#endif +}; +*/ + +/* +#ifndef SCE_EXTERNAL_RELEASE +// Here's the search path for the SPURS programs: +char *_g_apcSPURSELFSearchPaths[]={ + "/app_home/", + "/app_home/../../lib/", // works with samples + "/app_home/../../../lib/", // works with tutorials + "/app_home/../../../../lib/", + "/app_home/../../../../../lib/", +}; +unsigned int _g_uiSPURSELFSearchPathCount=sizeof(_g_apcSPURSELFSearchPaths)/sizeof(char *); +#endif // SCE_EXTERNAL_RELEASE +*/ + +// E The priority for the SPU thread group used by SPURS +#define SPURS_SPU_THREAD_PRIORITY 200 + +static CellSpurs *g_spursInstance=0; +static CellSpursTaskset g_spursTaskSet __attribute__ ((aligned(128))); + +static int g_iDefaultSPUCount=CELL_SPURS_DEFAULT_SPU_COUNT; +static bool g_bSpursInitialized=false; +static bool g_bUserSpursGiven=false; +static uint32_t g_uiSpursReferenceCounter=0; + +/** + * E This is the main function of the spu_printf service thread. + * It listens for messages and calls the printf handler when it gets them, + * then notifies the SPU of completion by using a mailbox. + */ +//UPDATE: this function is not currently being used in the speex task or spurs manager +void _SpursPrintfThreadMain(uint64_t arg) +{ + sys_event_t event; + int iReturn; + + // E For unused parameter warnings + (void) arg; + + while (1) { + iReturn=sys_event_queue_receive(_g_SpuPrintfEventQueue, &event, + SYS_NO_TIMEOUT); + + if (iReturn!=CELL_OK) { + fprintf(stderr, "Event queue receive wasn't successful: %i\n", + iReturn); + exit(-1); + } + + iReturn=spu_thread_printf(event.data1, event.data3); + sys_spu_thread_write_spu_mb(event.data1, iReturn); + } +} + +/* +void *loadBulletImage(const char *pcFilename) { + void *pvElf; + FILE *pfInputFile=fopen(pcFilename, "rb"); + uint64_t uiFileSize; + + if (!pfInputFile) { + return 0; + } + + fseek(pfInputFile, 0, SEEK_END); + uiFileSize=ftell(pfInputFile); + fseek(pfInputFile, 0, SEEK_SET); + pvElf=memalign(128, uiFileSize); + + if (!pvElf) { + printf("Cannot allocate memory for file %s\n", pcFilename); + fclose(pfInputFile); + return 0; + } + + fread(pvElf, 1, uiFileSize, pfInputFile); + fclose(pfInputFile); + + return pvElf; +} + +void unloadBulletSpursElfs() { +#ifdef SCE_EXTERNAL_RELEASE + return; +#endif + + for (int iELF=0; iELF6) + { + return CELL_SPURS_EINVAL; + } + + return initializeSpursTaskSet(pSpurs, iSPUCount, auiPriorities); +} + +/** + * Sets the number of SPUs to be used by a Bullet-initialized SPURS. + * Valid iSPUCount is in the range 1-6. + * Return is: + * CELL_SPURS_OK on success + * CELL_SPURS_EBUSY if SPU usage has already been initialized + * CELL_SPURS_EINVAL if iSPUCount is out of range or if SPURS couldn't be + * initialized to that many SPUs. + */ +int spursConfiguration_initWithSpuCount(int iSPUCount) +{ + if (g_bSpursInitialized) + { + return CELL_SPURS_EBUSY; + } + + if (iSPUCount<1 || iSPUCount>6) + { + return CELL_SPURS_EINVAL; + } + + return initializeSpursTaskSet(0, iSPUCount, 0); +} + +/** + * Terminates (or disconnects from) SPURS. + * Return is: + * CELL_SPURS_OK if SPURS terminates ok, or if it was previously terminated/ + * never initialized. + * CELL_SPURS_EBUSY if there are existing Scenes which would need SPURS. + */ +int spursConfiguration_terminate() +{ + if (!g_bSpursInitialized) + { + return CELL_SPURS_OK; + } + + if (g_uiSpursReferenceCounter) + { + return CELL_SPURS_EBUSY; + } + int iReturn; + bool bUserSpurs=g_bUserSpursGiven; + + g_bSpursInitialized=false; + g_bUserSpursGiven=false; + + iReturn=cellSpursShutdownTaskset(&g_spursTaskSet); + if (iReturn!=CELL_OK) + { + return -1; + //fprintf(stderr, "Bullet: Error shutting down SPURS task set: %i\n", iReturn); + } + + iReturn=cellSpursJoinTaskset(&g_spursTaskSet); + if (iReturn!=CELL_OK) + { + return -2; + //fprintf(stderr, "Bullet: Error joining SPURS task set: %i\n", iReturn); + } + + if (!bUserSpurs) + { + int iReturn=cellSpursFinalize(g_spursInstance); + + if (iReturn!=CELL_OK) + { + return -3; + //fprintf(stderr, "Bullet: Error shutting down SPURS: %d\n", iReturn); + } + + free(g_spursInstance); + } + + g_spursInstance=0; + + // Not loading SPURS task from file anymore + //unloadBulletSpursElfs(); +// printf code is commented out for the time being +//#warning TODO: Clean up SPU printf thread. + + return CELL_SPURS_OK; +} + +/** + * Queries whether SPU usage has been initialized. + * Return is: + * true if initialized. + */ +bool spursConfiguration_isSpursInitialized() +{ + return g_bSpursInitialized; +} + + +SpursSupportInterface::SpursSupportInterface() +{ + //assert(elfId < SPU_ELF_LAST); + //m_elfId=elfId; + m_bQueueInitialized=false; + + cellAtomicIncr32(&g_uiSpursReferenceCounter); +} + +SpursSupportInterface::~SpursSupportInterface() +{ + stopSPU(); + + cellAtomicDecr32(&g_uiSpursReferenceCounter); +} + +int SpursSupportInterface::startSPU() +{ + int iReturn; + + if (!m_bQueueInitialized) + { + if (checkSpursTaskSet() != CELL_SPURS_OK) + { + return -1; + } + + iReturn=cellSpursQueueInitialize(&g_spursTaskSet, + &m_responseQueue, m_aResponseBuffer, sizeof(CellSPURSArgument), + CELL_SPURS_RESPONSE_QUEUE_SIZE, CELL_SPURS_QUEUE_SPU2PPU); + if (iReturn!=CELL_OK) + { + return -2; + } + + iReturn=cellSpursQueueAttachLv2EventQueue(&m_responseQueue); + if (iReturn!=CELL_OK) + { + return -3; + } + + m_bQueueInitialized=true; + } + return 0; +} + +int SpursSupportInterface::stopSPU() +{ + if (m_bQueueInitialized) + { + int iReturn=cellSpursQueueDetachLv2EventQueue(&m_responseQueue); + if (iReturn != CELL_OK) + return -1; + m_bQueueInitialized=false; + } + return 0; +} + +int SpursSupportInterface::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1) +{ + int iReturn; + CellSpursTaskId taskId; + CellSPURSArgument arguments; + + arguments.ppuResponseQueue=&m_responseQueue; + arguments.uiCommand=uiCommand; + arguments.uiArgument0=uiArgument0; + arguments.uiArgument1=uiArgument1; + + if (checkSpursTaskSet() != CELL_SPURS_OK) + { + return -1; + } + + iReturn=cellSpursCreateTask(&g_spursTaskSet, &taskId, g_SpursTaskElfStart, NULL, 0, 0, &arguments.spursArgument); + if (iReturn!=CELL_OK) + { + return -2; + } + + return 0; +} + + +/** + * Wait for the SPU to send an event back to our event queue. + */ +int SpursSupportInterface::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) +{ + CellSPURSArgument response __attribute__((aligned(16))); + int iReturn; + + iReturn=cellSpursQueuePop(&m_responseQueue, (void *) &response); + + if (iReturn!=CELL_OK) + { + return -1; + } + + if (puiArgument0) + *puiArgument0=response.uiArgument0; + + if (puiArgument1) + *puiArgument1=response.uiArgument1; + return 0; +} + diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursSupportInterface.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursSupportInterface.h new file mode 100644 index 00000000000..a71f146133f --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursSupportInterface.h @@ -0,0 +1,133 @@ +/* [SCE CONFIDENTIAL DOCUMENT] + * PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com) + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * All Rights Reserved. + */ + + +#ifndef __SPURS_SUPPORT_INTERFACE_H +#define __SPURS_SUPPORT_INTERFACE_H + +#include +#include "spursUtilityMacros.h" +#include "spursThreadSupportInterface.h" + +#ifdef __SPU__ +#include + +#include + +#if CELL_SDK_VERSION < 0x081000 +#define CELL_SPURS_TASK_ERROR_AGAIN CELL_SPURS_EAGAIN +#define CELL_SPURS_TASK_ERROR_BUSY CELL_SPURS_EBUSY +#endif // CELL_SDK_VERSION < 0x081000 + +#else // __SPU__ +#include + +#endif // __SPU__ + +#define CELL_SPURS_RESPONSE_QUEUE_SIZE 128 + +/** + * Note: + * The order of elements in this enum are important, that's why each one is explicitly + * given a value. They will correspond to the .elf names/addresses that will be + * loaded into SPURS. + * Mixing up these values will cause the wrong code to execute, for instance, the + * solver may be asked to do a collision detection job. + */ +////////////////////////////////////////////////////////////////////////// +// only one type of SPURS Task ELF +// typedef enum { +// // SPU_ELF_MID_PHASE=0, +// // SPU_ELF_SOLVER, +// SPU_ELF_SPEEX, +// SPU_ELF_LAST, +// } CellSpursElfId_t; + +typedef union CellSPURSArgument +{ + struct + { + CELL_PPU_POINTER(CellSpursQueue) ppuResponseQueue; + uint32_t uiCommand; + uint32_t uiArgument0; + uint32_t uiArgument1; + }; + +#if __PPU__ + CellSpursTaskArgument spursArgument; +#elif __SPU__ + vec_uint4 uiQWord; +#endif +} CellSPURSArgument __attribute__((aligned(16))); + +#if __SPU__ +#include "SPUAssert.h" +#include + +static inline void sendResponseToPPU(uint32_t ppuQueueEA, uint32_t uiArgument0, + uint32_t uiArgument1, int iTag=1) { + CellSPURSArgument response + __attribute__ ((aligned(16))); + + response.uiArgument0=uiArgument0; + response.uiArgument1=uiArgument1; + + int iReturn; + do { + iReturn=cellSpursQueueTryPushBegin(ppuQueueEA, &response, iTag); + } while (iReturn == CELL_SPURS_TASK_ERROR_AGAIN || + iReturn == CELL_SPURS_TASK_ERROR_BUSY); + + SPU_ASSERT((iReturn == CELL_OK) && "Error writing to SPURS queue."); + + cellSpursQueuePushEnd(ppuQueueEA, iTag); + +} + +static inline void sendResponseToPPUAndExit(uint32_t ppuQueueEA, uint32_t uiArgument0, + uint32_t uiArgument1, int iTag=1) { + CellSPURSArgument response + __attribute__ ((aligned(16))); + + response.uiArgument0=uiArgument0; + response.uiArgument1=uiArgument1; + + int iReturn; + do { + iReturn=cellSpursQueueTryPushBegin(ppuQueueEA, &response, iTag); + } while (iReturn == CELL_SPURS_TASK_ERROR_AGAIN || + iReturn == CELL_SPURS_TASK_ERROR_BUSY); + + SPU_ASSERT((iReturn == CELL_OK) && "Error writing to SPURS queue."); + + cellSpursQueuePushEnd(ppuQueueEA, iTag); + + cellSpursExit(); +} +#elif __PPU__ // not __SPU__ + +class SpursSupportInterface : public spursThreadSupportInterface +{ +public: + SpursSupportInterface(); + ~SpursSupportInterface(); + int sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1=0); + int waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); + int startSPU(); + int stopSPU(); + +protected: + //CellSpursElfId_t m_elfId; + void *m_spursTaskAddress; + CellSpursQueue m_responseQueue __attribute__((aligned(128))); + CellSPURSArgument m_aResponseBuffer[CELL_SPURS_RESPONSE_QUEUE_SIZE] __attribute__((aligned(16))); + + bool m_bQueueInitialized; +}; +#endif // __SPU__ / __PPU__ + + +#endif // CELL_SPURS_SUPPORT_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursThreadSupportInterface.cpp b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursThreadSupportInterface.cpp new file mode 100644 index 00000000000..411b57d93f8 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursThreadSupportInterface.cpp @@ -0,0 +1,21 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "spursThreadSupportInterface.h" + +spursThreadSupportInterface::~spursThreadSupportInterface() +{ + +} diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursUtilityMacros.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursUtilityMacros.h new file mode 100644 index 00000000000..3e348517b01 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursUtilityMacros.h @@ -0,0 +1,21 @@ +#ifndef __CELL_UTILITY_MACROS_H +#define __CELL_UTILITY_MACROS_H + +// This type pretends to be a pointer to a type on the PPU, and +// just an unsigned int on the SPU. +#ifndef CELL_PPU_POINTER +#define CELL_PPU_PTR_TYPE uint32_t + +#ifdef __SPU__ +#define CELL_PPU_POINTER(x) CELL_PPU_PTR_TYPE +#else // __SPU__ +#define CELL_PPU_POINTER(x) x * + +// Hope we never switch away from 32 bits... +// But this is here just in case... +//NX_COMPILE_TIME_ASSERT(sizeof(void *)==sizeof(CELL_PPU_PTR_TYPE)); +#endif // __SPU__ +#endif // CELL_PPU_POINTER + +#endif +// end __CELL_UTILITY_MACROS_H diff --git a/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursthreadsupportinterface.h b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursthreadsupportinterface.h new file mode 100644 index 00000000000..a9a1627e564 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/SpeexSpursTaskManager/spursthreadsupportinterface.h @@ -0,0 +1,43 @@ +// Gamespy Technology +// NOTE: this code has been provided by Sony for usage in Speex SPURS Manager + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef THREAD_SUPPORT_INTERFACE_H +#define THREAD_SUPPORT_INTERFACE_H + +#include "spursPlatformDefinitions.h" + +class spursThreadSupportInterface +{ +public: + + virtual ~spursThreadSupportInterface(); + +///send messages to SPUs + virtual int sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1) =0; + +///check for messages from SPUs + virtual int waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) =0; + +///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) + virtual int startSPU() =0; + +///tell the task scheduler we are done with the SPU tasks + virtual int stopSPU()=0; +}; + +#endif //THREAD_SUPPORT_INTERFACE_H diff --git a/xrGameSpy/gamespy/common/ps3/gsSocketPS3.c b/xrGameSpy/gamespy/common/ps3/gsSocketPS3.c new file mode 100644 index 00000000000..45345c0e129 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/gsSocketPS3.c @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" +#include "../gsPlatformSocket.h" +#include + + + +// ToDo: Move this to PS3 implemenation +HOSTENT * getlocalhost(void) +{ // Global storage + + #define MAX_IPS 10 + static HOSTENT localhost; + static char * aliases = NULL; + static char * ipPtrs[MAX_IPS + 1]; + static unsigned int ips [MAX_IPS]; + int r; + union CellNetCtlInfo gCellNetInfo; + // Todo: support mutliple ip's. + + // initialize the host + localhost.h_name = "localhost"; + localhost.h_aliases = &aliases; + localhost.h_addrtype = AF_INET; + localhost.h_length = sizeof(unsigned int); + localhost.h_addr_list = ipPtrs; + ipPtrs[0] = (char *)&ips[0]; + ipPtrs[1] = NULL; + + // to do, cache this, and do this once at init. + r = cellNetCtlGetInfo( CELL_NET_CTL_INFO_IP_ADDRESS,&gCellNetInfo ); + if (r == CELL_OK) + { + ips[0] = inet_addr(gCellNetInfo.ip_address); + + + return &localhost; + } + else + return NULL; + +} diff --git a/xrGameSpy/gamespy/common/ps3/gsUtilPS3.c b/xrGameSpy/gamespy/common/ps3/gsUtilPS3.c new file mode 100644 index 00000000000..3f556313baf --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/gsUtilPS3.c @@ -0,0 +1,76 @@ +#if defined(_PS3) + +#include +#include +#include +#include + +#include "../gsCommon.h" + +// This needs to be set during interface start +extern int gNetInterfaceID; + +#if defined(_PS3) && defined(UNIQUEID) + static const char * GetMAC(void) + { + // Get the MAC address using the interface control + static union CellNetCtlInfo gCellNetInfo; + int r; + // Get MAC + // to do, cache this, and do this once at init. + r = cellNetCtlGetInfo( CELL_NET_CTL_INFO_ETHER_ADDR,&gCellNetInfo ); + if (r == CELL_OK) + { + + return (const char *)&gCellNetInfo.ether_addr; + }// else error + return NULL; + } + + static const char * GOAGetUniqueID_Internal(void) + { + static char keyval[17]; + const char * MAC; + + // check if we already have the Unique ID + if(keyval[0]) + return keyval; + + // get the MAC + MAC = GetMAC(); + if(!MAC) + { + // error getting the MAC + static char errorMAC[6] = { 1, 2, 3, 4, 5, 6 }; + MAC = errorMAC; + } + + // format it + sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000", + MAC[0] & 0xFF, + MAC[1] & 0xFF, + MAC[2] & 0xFF, + MAC[3] & 0xFF, + MAC[4] & 0xFF, + MAC[5] & 0xFF); + + return keyval; + } +#endif + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return atoll(theNumberStr); +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%lld", theNumber); +} +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _PS3 only diff --git a/xrGameSpy/gamespy/common/ps3/ps3common.c b/xrGameSpy/gamespy/common/ps3/ps3common.c new file mode 100644 index 00000000000..04057e07505 --- /dev/null +++ b/xrGameSpy/gamespy/common/ps3/ps3common.c @@ -0,0 +1,248 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Common code for GameSpy samples +// Note: This code is not intended to be used in a retail program +// +// Portions taken from PS3 sample applications. Please refer to Sony +// documentation and samples for application startup procedures. +#include +#include +#include +#include + +#include "../gsPlatform.h" +#include "../gsPlatformUtil.h" +#include "../gsMemory.h" +// entry point for GameSpy samples +extern int test_main(int argc, char ** argp); + +#define PRIO (1001) +#define HOST_NAME "localhost" + + +// * added due to PS3 SDK 092.00x and above - all stub libraries require you to load the module +// * for it to be properly linked +gsi_bool _LoadModules() +{ + cellSysmoduleInitialize(); + + if (cellSysmoduleLoadModule(CELL_SYSMODULE_NET) != CELL_OK) + { + printf("cellSysmoduleLoadModule(CELL_SYSMODULE_NET) failed\n"); + return gsi_false; + } + if (cellSysmoduleLoadModule(CELL_SYSMODULE_IO) != CELL_OK) + { + printf("cellSysmoduleLoadModule(CELL_SYSMODULE_IO) failed\n"); + return gsi_false; + } + if (cellSysmoduleLoadModule(CELL_SYSMODULE_USBD) != CELL_OK) + { + printf("cellSysmoduleLoadModule(CELL_SYSMODULE_USBD) failed\n"); + return gsi_false; + } + if (cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_NP) != CELL_OK) + { + printf("cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_NP) failed\n"); + return gsi_false; + } + if (cellSysmoduleLoadModule(CELL_SYSMODULE_RTC) != CELL_OK) + { + printf("cellSysmoduleLoadModule(CELL_SYSMODULE_RTC) failed\n"); + return gsi_false; + } + + return gsi_true; +} + +// unloads modules to free up memory +void _UnloadModules() +{ + cellSysmoduleUnloadModule(CELL_SYSMODULE_NET); + cellSysmoduleUnloadModule(CELL_SYSMODULE_IO); + cellSysmoduleUnloadModule(CELL_SYSMODULE_USBD); + cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_NP); + cellSysmoduleUnloadModule(CELL_SYSMODULE_RTC); + + cellSysmoduleFinalize(); +} + + +gsi_bool _NetworkInit() +{ + int r = sys_net_initialize_network(); + + if (r!=CELL_OK) + { + printf("ccNetworkInitializeNetwork: sys_net_initialize_network() failed: %i\n",r); + return gsi_false; + } + + + return (r==0); +} + + + +gsi_bool _NetworkStart() +{ + int iReturn, iNetworkState; + + /*iReturn = cellSysutilInit(); + if (iReturn < 0) + { + printf("cellSysutilInit() failed(%x)\n", iReturn); + return gsi_false; + }*/ + + iReturn = cellNetCtlInit(); + if (iReturn!=CELL_OK) + { + printf("ccNetworkInitializeNetwork: cellNetCtlInit() failed: %i\n", + iReturn); + return gsi_false; + } + + + while (1) + { + iReturn=cellNetCtlGetState(&iNetworkState); + + + if (iReturn!=CELL_OK) + { + printf("ccNetworkInitializeNetwork: cellNetCtlGetState() failed: %i\n", + iReturn); + return gsi_false; + } + + if (iNetworkState!=CELL_NET_CTL_STATE_IPObtained) + { + sys_timer_usleep(100 * 1000); + } + else + { + break; + } + }; + + return gsi_true; +} + +void _NetworkStop() +{ + cellNetCtlTerm(); + //cellSysutilShutdown(); +} + +void _NetworkClose() +{ + sys_net_finalize_network(); +} + +void * gsiMemManagedInit() +{ + // Init the GSI memory manager (optional - for limiting GSI mem usage) +#if defined GSI_MEM_MANAGED +#define aMemoryPoolSize (1024*1024*8) + char *aMemoryPool = calloc(aMemoryPoolSize,32); + if(aMemoryPool == NULL) + { + printf("Failed to create memory pool - aborting\r\n"); + return NULL; + } + else + { + gsMemMgrContext c = gsMemMgrCreate(gsMemMgrContext_Default, "Default",aMemoryPool, aMemoryPoolSize); + GSI_UNUSED(c); + } + return aMemoryPool; +#else + return NULL; +#endif + +} + +void gsiMemManagedClose(void * aMemoryPool) +{ +#if defined(GSI_MEM_MANAGED) + // Optional - Dump memory leaks + + gsi_u32 MemAvail = gsMemMgrMemAvailGet (gsMemMgrContext_Default); + gsi_u32 MemUsed = gsMemMgrMemUsedGet (gsMemMgrContext_Default); + gsi_u32 HwMark = gsMemMgrMemHighwaterMarkGet (gsMemMgrContext_Default); + + printf("MemAvail %u: MemUsed%u MemHWMark %u\n", MemAvail,MemUsed,HwMark); + gsMemMgrDumpStats(); + gsMemMgrDumpAllocations(); + gsMemMgrValidateMemoryPool(); + gsMemMgrDestroy(gsMemMgrContext_Default); + free(aMemoryPool); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char ** argp) +{ + //sys_pid_t pid = 0; + //int result = 0; + //int count = 0; + //int id_list[10]; + //int i=0; + void *heap; + printf("\nGameSpy Test App Initializing\n" + "----------------------------------\n"); +/* + // spawn IO module + if (sys_process_spawn(&pid, "brio.elf", NULL, 0, PRIO, 0) != SUCCEEDED) { + printf("sys_process_spawn(brio.elf) failed\n"); + return (0); + } +*/ + + // load required modules + if(!_LoadModules()) + { + printf("_LoadModules() failed\n"); + return (0); + } + + // initialize network using hardcoded settings above + if(!_NetworkInit()) + { + printf("_NetworkInit() failed\n"); + return (0); + } + + if(!_NetworkStart()) + { + printf("_NetworkStart() failed\n"); + return (0); + } + + heap = gsiMemManagedInit(); + // start the actual program + printf("\nGameSpy Test App Starting\n" + "----------------------------------\n"); + test_main(argc, argp); + + // do any needed cleanup + printf("\nGameSpy Test App Exiting\n" + "----------------------------------\n"); + gsiMemManagedClose(heap); + // close network + _NetworkStop(); + _NetworkClose(); + + // unload modules + _UnloadModules(); + + // don't exit into never never land and lose our tty output. + while(1) + { + msleep(100); + } + return 0; +} + diff --git a/xrGameSpy/gamespy/common/psp/Makefile.common b/xrGameSpy/gamespy/common/psp/Makefile.common new file mode 100644 index 00000000000..cf95bd08e9c --- /dev/null +++ b/xrGameSpy/gamespy/common/psp/Makefile.common @@ -0,0 +1,48 @@ +#GameSpy.net PSP Makefile +#Included from sample-specific Makefiles + +DEVKIT_TOP = /usr/local/psp/devkit +INCDIR = $(DEVKIT_TOP)/include +PLATFORMDEF = _PSP +AS = psp-gcc +CC = psp-gcc +LD = psp-ld + +DBGFLAG = -g +OPTFLAG = -O2 +CFLAGS = -W -Wall $(DBGFLAG) $(OPTFLAG) -D$(PLATFORMDEF) -I$(INCDIR) $(SDK_CFLAGS) +ASFLAGS = $(DBGFLAG) +LDFLAGS = $(DBGFLAG) +LDLIBS = -lgum -lgu -lm +LIB = \ + $(DEVKIT_TOP)/lib/wlan_stub.a \ + $(DEVKIT_TOP)/lib/rtc_stub.a \ + $(DEVKIT_TOP)/lib/pspnet_stub_weak.a \ + $(DEVKIT_TOP)/lib/pspnet_inet_stub_weak.a \ + $(DEVKIT_TOP)/lib/pspnet_resolver_stub_weak.a \ + $(DEVKIT_TOP)/lib/pspnet_apctl_stub_weak.a \ + $(DEVKIT_TOP)/lib/pspnet_ap_dialog_dummy_stub_weak.a + +.SUFFIXES: .c .s + +all: $(TARGET).prx $(TARGET).elf + +clean: + rm -f $(TARGET).prx $(TARGET).elf $(OBJS) *.o *~ *.bak + +$(TARGET).prx: $(OBJS) + $(LINK.c) $^ $(LDLIBS) $(LIB) -startfiles -o $@ + +$(TARGET).elf: $(OBJS) + $(LINK.c) $^ $(LDLIBS) $(LIB) -zgenelf -o $@ + +.s.o: + $(AS) $(ASFLAGS) -I$(INCDIR) -o $@ $< > $*.lst + +.c.o: + $(CC) $(CFLAGS) -D$(PLATFORMDEF) -I$(INCDIR) -c $< -o $*.o > $*.lst + +#----------- rules -------------- +-include PathDefs +PathDefs: + psp-path-setup > PathDefs || (rm -f PathDefs ; exit 1) diff --git a/xrGameSpy/gamespy/common/psp/gsSocketPSP.c b/xrGameSpy/gamespy/common/psp/gsSocketPSP.c new file mode 100644 index 00000000000..afa60e0c1f7 --- /dev/null +++ b/xrGameSpy/gamespy/common/psp/gsSocketPSP.c @@ -0,0 +1,350 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../gsCommon.h" +#include "../gsPlatformSocket.h" + + +#if(0) // enable after remove from platform socket +int SetSockBlocking(SOCKET sock, int isblocking) +{ + int rcode; + unsigned long argp; + + if(isblocking) + argp = 0; + else + argp = 1; + + rcode = setsockopt(sock, SCE_NET_INET_SOL_SOCKET, SCE_NET_INET_SO_NBIO, &argp, sizeof(argp)); + + if(rcode == 0) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "SetSockBlocking: Set socket %d to %s\r\n", (unsigned int)sock, isblocking ? "blocking":"non-blocking"); + return 1; + } + + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Comment, + "SetSockBlocking failed: tried to set socket %d to %s\r\n", (unsigned int)sock, isblocking ? "blocking":"non-blocking"); + return 0; +} +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define MAX_IPS 5 +struct hostent* gsSocketGetHostByName(const char* name) +{ + // parameter check + GS_ASSERT(name); + { + int result = 0; + int resolverID = 0; + // mj taking this off the stack 04/05/06 + #define GetHostByNameBufferSize 1024 + char *buf = gsimalloc(GetHostByNameBufferSize);//[GetHostByNameBufferSize]; // PSP documentation recommends 1024 + struct in_addr ip; + + static struct hostent ahostent; + static char * aliases = NULL; + static char * ipPtrs[MAX_IPS + 1]; + static unsigned int ips[MAX_IPS]; + + GS_ASSERT(buf); + + ahostent.h_name = ""; + ahostent.h_aliases = &aliases; + ahostent.h_addrtype = AF_INET; + ahostent.h_addr_list = ipPtrs; + + result = sceNetResolverCreate(&resolverID, buf, GetHostByNameBufferSize); + if (result < 0) + { + gsifree(buf); + return NULL; + } + // this will block until completed + result = sceNetResolverStartNtoA(resolverID, name, &ip, GSI_RESOLVER_TIMEOUT, GSI_RESOLVER_RETRY); + sceNetResolverDelete(resolverID); // delete right away, result is stored in ip + if (result < 0) + { + gsifree(buf); + return NULL; + } + ahostent.h_length = sizeof(struct in_addr); + memcpy(&ips[0], &ip, sizeof(struct in_addr)); + ahostent.h_addr_list[0] = (char*)&ips[0]; + ahostent.h_addr_list[1] = NULL; + + { + const char * out = sceNetInetInetNtop(SCE_NET_INET_AF_INET, &ip, buf, sizeof(buf)); + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Network, GSIDebugLevel_Notice, + "gsSocketGetHostByName: %s = %s\r\n", name, out?out:"void"); + } + gsifree(buf); + return &ahostent; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +const char* gsSocketInetNtoa(struct in_addr in) +{ + static char buf[sizeof("XXX.XXX.XXX.XXX")]; + sceNetInetInetNtop(SCE_NET_INET_AF_INET, &in, buf, sizeof(buf)); + return buf; +} + +HOSTENT * getlocalhost(void) +{ + #define MAX_IPS 5 + static HOSTENT localhost; + static char * aliases = NULL; + static char * ipPtrs[MAX_IPS + 1]; + static unsigned int ips[MAX_IPS]; + int result = 0; + gsi_u32 addr; + + static union SceNetApctlInfo info; + + localhost.h_name = "localhost"; + localhost.h_aliases = &aliases; + localhost.h_addrtype = AF_INET; + localhost.h_length = 0; + localhost.h_addr_list = (char **)ipPtrs; + ipPtrs[0] = (char *)&ips[0]; + ipPtrs[1] = NULL; + ips[0] = 0; + + result = sceNetApctlGetInfo(SCE_NET_APCTL_INFO_IP_ADDRESS, &info); + if (result < 0) + { + printf("getlocalhost sceNetApctlGetInfo returned %d\r\n", result); + return NULL; + } + + // fill in the hostent structure + addr = inet_addr(info.ip_address); // NBO + memcpy(&ips[0], &addr, sizeof(addr)); // still NBO + localhost.h_length = (gsi_u16)sizeof(addr); + + return &localhost; +} + + +// ******* PSP AdHoc Socket Code ******************** +// See SampleAPP SDK PSP gsNetwork.c code for sample, and network start-up code +#define RXBUFLEN 1024 + +#ifdef GSI_ADHOC +void NetAdhocMacGet (char *mac) +{ + int ret = sceWlanGetEtherAddr((struct SceNetEtherAddr *)mac); +} + + +int _NetworkAdHocSocketCreate(gsi_u16 port) +{ + int ret, id; + struct SceWlanEtherAddr tmp_local; + static struct SceNetEtherAddr addr; + // Get local MAC address + ret = sceWlanGetEtherAddr(&tmp_local); + if (ret < 0) + { + // Error handling + return -1;// INVALID_SOCKET + } + memcpy(&addr, &tmp_local.addr,sizeof(struct SceNetEtherAddr)); + #ifdef _PSPNET_LOG + printf("Create Adhoc Socket: MAC:%x,%x,%x,%x,%x,%x\n",(gsi_u32)tmp_local.addr[0],(gsi_u32)tmp_local.addr[1],(gsi_u32)tmp_local.addr[2],(gsi_u32)tmp_local.addr[3],(gsi_u32)tmp_local.addr[4],(gsi_u32)tmp_local.addr[5]); + #endif + + // Set socket buffer to 8192 bytes + id = sceNetAdhocPdpCreate(&addr, port, RXBUFLEN, 0); + if (id < 0) + { + // SCE_ERROR_NET_ADHOC_INVALID_ADDR + // ToDo: Error handling + return -1;// INVALID_SOCKET + } + return id; +} + +void _NetworkAdHocSocketDestroy(int socket) +{ + int ret; + ret = sceNetAdhocPdpDelete(socket,0); + if (ret < 0) + { + // ToDo: Error handling + } +} + +int _NetworkAdHocSocketBroadcast( int socketid, + const void *data, + int len, + int flags, + gsi_u16 dest_port + ) +{ + const static gsi_u8 broadcast_addr[SCE_NET_ETHER_ADDR_LEN] = {0xff}; + int ret = sceNetAdhocPdpSend( + socketid, // id Socket ID + broadcast_addr, // daddr Destination MAC address + dest_port, // dport Destination port number + data, // data Pointer to send data + len, // len Length of send data + 10, // timeout Timeout (�sec) + flags // flag Send options + ); + + // todo: translate return value to GSI specific + return ret; +} + + +int _NetworkAdHocSocketSendTo( int socketid, + const void *data, + int len, + int flags, + const char *dest_addr, + gsi_u16 dest_port + ) +{ +#if(0) // test + const static gsi_u8 broadcast_addr[SCE_NET_ETHER_ADDR_LEN] = {0xff}; + int ret = sceNetAdhocPdpSend( + socketid, // id Socket ID + broadcast_addr, // daddr Destination MAC address + dest_port, // dport Destination port number + data, // data Pointer to send data + len, // len Length of send data + 10, // timeout Timeout (�sec) + flags // flag Send options + ); +#else + + int ret = sceNetAdhocPdpSend( + socketid, // id Socket ID + dest_addr, // daddr Destination MAC address + dest_port, // dport Destination port number + data, // data Pointer to send data + len, // len Length of send data + 10, // timeout Timeout (�sec) + flags // flag Send options + ); +#endif + #ifdef _PSPNET_LOG + printf("AdHoc SendTo: MAC:%x,%x,%x,%x,%x,%x port=%d Len=%d\n",(gsi_u32)dest_addr[0],(gsi_u32)dest_addr[1],(gsi_u32)dest_addr[2],(gsi_u32)dest_addr[3],(gsi_u32)dest_addr[4],(gsi_u32)dest_addr[5],dest_port,len); + #endif + // todo: translate return value to GSI specific + return ret; +} + +// return 0 if no data, -1 if error, >0 if data to read +int _NetworkAdHocCanReceiveOnSocket(int socket_id) +{ + int ret; + struct SceNetAdhocPdpStat stat; + int stat_buflen; + + /* + // get SceNetAdhocPdpStat + next Pointer to next entry in list (NULL indicates end) + id Socket ID + laddr Local address + lport Local port number + rcv_sb_cc Size of data in receive buffer + */ + + stat_buflen = sizeof(struct SceNetAdhocPdpStat); + ret = sceNetAdhocGetPdpStat(&stat_buflen, (void *)&stat); + if (ret < 0) + { + // Error Condition + + if(ret == SCE_ERROR_NET_ADHOC_INVALID_ARG) + { + printf("sceNetAdhocGetPdpStat() failed. SCE_ERROR_NET_ADHOC_INVALID_ARG ret = 0x%x\n", ret); + } + else + if(ret == SCE_ERROR_NET_ADHOC_NOT_INITIALIZED) + { + printf("sceNetAdhocGetPdpStat() failed. SCE_ERROR_NET_ADHOC_NOT_INITIALIZED ret = 0x%x\n", ret); + } + else + { + printf("sceNetAdhocGetPdpStat() failed. ret = 0x%x\n", ret); + } + return -1; + } + + if (stat_buflen == 0 || stat.id != socket_id) + { + printf("sceNetAdhocGetPdpStat() invalid data.\n"); + return 0; + } + + return stat.rcv_sb_cc; // valid date to read +} + +// return length if successful +// <=0 on error +int _NetworkAdHocSocketRecv(int socket_id, + char *buf, + int bufferlen, + int flags, + char *saddr, //struct SceNetEtherAddr = char[6]; + u_int16 *sport + ) +{ + int ret = sceNetAdhocPdpRecv( + socket_id, // id Socket ID + saddr, // saddr Sender�s MAC address + sport, // sport Sender port number + buf, // buf Pointer to receive buffer + &bufferlen, // len Receive buffer size (IN), receive data length (OUT) + 0, // timeout Timeout (�sec) + SCE_NET_ADHOC_F_NONBLOCK// flag Receive options + ); + + // translate return values to gsi standard + if (ret < 0) + { + return ret; + } + if (ret == (int)SCE_ERROR_NET_ADHOC_WOULD_BLOCK) + { + // no data, just return + return SCE_OK; + } + #ifdef _PSPNET_LOG + if(ret >= 0) + printf("AdHoc Recv From: MAC:%x,%x,%x,%x,%x,%x: port=%d len:%d\n",saddr[0],saddr[1],saddr[2],saddr[3],saddr[4],saddr[5],*sport,bufferlen); + #endif + + + return bufferlen; +} +#endif + diff --git a/xrGameSpy/gamespy/common/psp/gsUtilPSP.c b/xrGameSpy/gamespy/common/psp/gsUtilPSP.c new file mode 100644 index 00000000000..4363a51a537 --- /dev/null +++ b/xrGameSpy/gamespy/common/psp/gsUtilPSP.c @@ -0,0 +1,275 @@ +#if defined(_PSP) +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if !defined(GSI_NO_THREADS) + +static void gsiResolveHostnameThread(void * arg) +{ + int result = 0; + int resolverID = 0; + char buf[1024]; // PSP documentation recommends 1024 + in_addr addr; + GSIResolveHostnameHandle * info = (GSIResolveHostnameHandle)arg; + + result = sceNetResolverCreate(&resolverID, buf, sizeof(buf)); + if (result < 0) + { + // failed to create resolver, did you call sceNetResolverInit() ? + info->ip = GSI_ERROR_RESOLVING_HOSTNAME; + return -1; + } + else + { + // this will block until completed + result = sceNetResolverStartNtoA(resolverID, info->hostname, &addr, &info->ip, GSI_RESOLVER_TIMEOUT, GSI_RESOLVER_RETRY); + if (result < 0) + info->ip = GSI_ERROR_RESOLVING_HOSTNAME; + sceNetResolverDelete(resolverID); + } +} + +int gsiStartResolvingHostname(const char * hostname, GSIResolveHostnameHandle * handle) +{ + GSIResolveHostnameInfo * info; + + // allocate a handle + info = (GSIResolveHostnameInfo *)gsimalloc(sizeof(GSIResolveHostnameInfo)); + if(!info) + return -1; + + // make a copy of the hostname so the thread has access to it + info->hostname = goastrdup(hostname); + if(!info->hostname) + { + gsifree(info); + return -1; + } + + // not resolved yet + info->finishedResolving = 0; + + // start the thread + if(gsiStartThread(gsiResolveHostnameThread, (0x1000), info, &info->threadID) == -1) + { + gsifree(info->hostname); + gsifree(info); + return -1; + } + + // set the handle to the info + *handle = info; + + return 0; +} + +void gsiCancelResolvingHostname(GSIResolveHostnameHandle handle) +{ + if (0 == handle->finishedResolving) + { + sceNetResolverStop(handle->resolverID); // safe to call from separate thread + gsiCancelThread(handle->threadID); + } +} + +unsigned int gsiGetResolvedIP(GSIResolveHostnameHandle handle) +{ + return handle->ip; +} + +#endif // (GSI_NO_THREADS) + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(UNIQUEID) + +static const char * GetMAC(void) +{ + static struct SceNetEtherAddr mac; + int result = 0; + + result = sceNetGetLocalEtherAddr(&mac); + if (result == 0) + return (char *)&mac.data; + else + return NULL; +} + +const char * GOAGetUniqueID_Internal(void) +{ + static char keyval[17]; + const char * MAC; + + // check if we already have the Unique ID + if(keyval[0]) + return keyval; + + // get the MAC + MAC = GetMAC(); + if(!MAC) + { + // error getting the MAC + static char errorMAC[6] = { 1, 2, 3, 4, 5, 6 }; + MAC = errorMAC; + } + + // format it + sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000", + MAC[0] & 0xFF, + MAC[1] & 0xFF, + MAC[2] & 0xFF, + MAC[3] & 0xFF, + MAC[4] & 0xFF, + MAC[5] & 0xFF); + + return keyval; +} + +#endif + +//NEED These again since MAX INTEGRAL BITS is not defined +#define GSI_MIN_I64 LONG_LONG_MIN +#define GSI_MAX_I64 LONG_LONG_MAX +#define GSI_MAX_U64 ULONG_LONG_MAX +/* flag values */ +#define FL_UNSIGNED 1 /* strtouq called */ +#define FL_NEG 2 /* negative sign found */ +#define FL_OVERFLOW 4 /* overflow occured */ +#define FL_READDIGIT 8 /* we've read at least one correct digit */ + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + const char *p; + char c; + gsi_i64 number; + unsigned digval; + gsi_u64 maxval; + int flags = 0; + // Added for compatibility reasons + int ibase = 10; + + p = theNumberStr; // p is our scanning pointer + number = 0; // start with zero + + // read char + c = *p++; + + // skip whitespace + while ( isspace(c) ) + c = *p++; + + + if (c == '-') { + flags |= FL_NEG; // remember minus sign + c = *p++; + } + // skip sign + else if (c == '+') + c = *p++; + + if (ibase == 0) + { + // determine base free-lance, based on first two chars of + // string + if (c != '0') + ibase = 10; + else if (*p == 'x' || *p == 'X') + ibase = 16; + else + ibase = 8; + } + + if (ibase == 16) + { + // we might have 0x in front of number; remove if there + if (c == '0' && (*p == 'x' || *p == 'X')) { + ++p; + c = *p++; /* advance past prefix */ + } + } + + // if our number exceeds this, we will overflow on multiply + maxval = GSI_MAX_U64 / ibase; + + + // exit in middle of loop + for (;;) + { + // convert c to value + if ( isdigit(c) ) + digval = c - '0'; + else if ( isalpha(c) ) + digval = toupper(c) - 'A' + 10; + else + break; + + // exit loop if bad digit found + if (digval >= (unsigned)ibase) + break; + + /* record the fact we have read one digit */ + flags |= FL_READDIGIT; + + // we now need to compute number = number * base + digval, + // but we need to know if overflow occurred. This requires + // a tricky pre-check. + + if (number < maxval || (number == maxval && + (gsi_u64)digval <= GSI_MAX_U64 % ibase)) + { + // we won't overflow, go ahead and multiply + number = number * ibase + digval; + } + else + { + // we have overflowed, set the flag + flags |= FL_OVERFLOW; + break; + } + + c = *p++; /* read next digit */ + } + + --p; /* point to place that stopped scan */ + + if (!(flags & FL_READDIGIT)) { + /* no number there; return 0 and point to beginning of + string */ + number = 0L; /* return 0 */ + } + else if ( (flags & FL_OVERFLOW) || + ( !(flags & FL_UNSIGNED) && + ( ( (flags & FL_NEG) && (number > GSI_MIN_I64) ) || + ( !(flags & FL_NEG) && (number > GSI_MAX_I64) ) ) ) ) + { + /* overflow or signed overflow occurred */ + errno = ERANGE; + if ( flags & FL_NEG ) + number = GSI_MIN_I64; + else + number = GSI_MAX_I64; + } + + if (flags & FL_NEG) + /* negate result if there was a neg sign */ + number = -number; + + return number; /* done. */ +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%lld", theNumber); +} +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _PSP only diff --git a/xrGameSpy/gamespy/common/psp/pspcommon.c b/xrGameSpy/gamespy/common/psp/pspcommon.c new file mode 100644 index 00000000000..3015b591966 --- /dev/null +++ b/xrGameSpy/gamespy/common/psp/pspcommon.c @@ -0,0 +1,416 @@ +#if defined(_PSP) +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + +#include +#include +#include + +/******** THIS FILE IS FOR USE BY THE GAMESPY SAMPLE APPLICATIONS ********/ + +// Portions taken from Sony PSP http_get sample have been modified to suite the +// sample/demonstration of the Gamespy SDKs +// This code is not intended to be used in a shipping title +// (e.g. You should have your own network setup code which supports other configurations) + + +// Code modified from http_get used to export information about this module +SCE_MODULE_INFO(PspCommon, 0, 1, 1); + +// Paths setup for specific modules and libraries used by the Tool +#define DEVKIT_PATH "host0:/usr/local/devkit/" +#define MODULE_PATH DEVKIT_PATH "module/" +#define PSPNET_AP_DIALOG_DUMMY_PRX MODULE_PATH "pspnet_ap_dialog_dummy.prx" + +// Memory pool size for network stack and other stacks +#define PSPNET_POOLSIZE (256 * 1024) +#define CALLOUT_TPL 32 +#define NETINTR_TPL 32 +#define SCE_APCTL_HANDLER_STACKSIZE (1024 * 1) +#define SCE_APCTL_STACKSIZE (SCE_NET_APCTL_LEAST_STACK_SIZE + SCE_APCTL_HANDLER_STACKSIZE) +#define SCE_APCTL_PRIO 40 + +#define AP_DIALOG_DUMMY_WAIT_TIME (1000 * 1000) + +#define PSPNET_APCTLHDLR 0x80 +#define PSPNET_APDUMDLG_STARTED 0x40 +#define PSPNET_CONNECTED 0x20 +// If necessary, use this to select a specific router by SSID. +#ifndef AUTO_SELECT_ROUTER +#define YOUR_WIRELESS_ROUTER_NAME "PubServ DLink" +#endif + +// function prototypes +int gsiPspLoadRequiredModules(void); +int gsiPspUnloadRequiredModules(void); + +// static vars used for disconnect warnings and setting up network connection +static int gDisconnected = 0; +static struct SceNetApDialogDummyParam gApDialogDummyParam; + +// Globals +// the sce kernel detects this global variable and sets the heapsize from it +// see devkit\src\crt0\kernel_bridge.c(232-253) +int sce_newlib_heap_kb_size = 1000; +SceUID gPspnetApDialogDummyModid = 0; +int gPspnetApctlHandlerId = -1; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Used to start needed kernel model +static SceUID gsiPspLoadModule(const char *path) +{ + SceUID modid = 0; + int ret = 0, mresult; + + ret = sceKernelLoadModule(path, 0, NULL); + if(ret < 0) + { + printf("sceKernelLoadModule() failed. ret = 0x%x\n", ret); + return ret; + } + modid = ret; + + ret = sceKernelStartModule(modid, 0, 0, &mresult, NULL); + if(ret < 0) + { + printf("sceKernelStartModule() failed. ret = 0x%x\n", ret); + ret = sceKernelUnloadModule(modid); + if (ret < 0) + printf("sceKernelUnloadModule() failed. ret = 0x%x\n", ret); + return ret; + } + ret = modid; + + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Used to stop kernel model +static int gsiPspUnloadModule(SceUID modid) +{ + int ret = 0; + + ret = sceKernelStopModule(modid, 0, NULL, NULL, NULL); + if (ret < 0) + { + printf("sceKernelStopModule() failed. ret = 0x%x\n", ret); + return ret; + } + + ret = sceKernelUnloadModule(modid); + if (ret < 0) + { + printf("sceKernelUnloadModule() failed. ret = 0x%x\n", ret); + return ret; + } + + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// used to start up network library modules +int gsiPspLoadRequiredModules() +{ + int ret = 0; + + ret = sceUtilityLoadModule(SCE_UTILITY_MODULE_NET_COMMON); + if(ret < 0) + { + printf("sceUtilityLoadModule(SCE_UTILITY_MODULE_NET_COMMON) failed. ret = 0x%x\n", ret); + gsiPspUnloadRequiredModules(); + return ret; + } + + ret = sceUtilityLoadModule(SCE_UTILITY_MODULE_NET_INET); + if(ret < 0) + { + printf("sceUtilityLoadModule(SCE_UTILITY_MODULE_NET_INET) failed. ret = 0x%x\n", ret); + gsiPspUnloadRequiredModules(); + return ret; + } + + ret = gsiPspLoadModule(PSPNET_AP_DIALOG_DUMMY_PRX); + if(ret < 0) + { + printf("load_module %s failed. ret = 0x%x\n",PSPNET_AP_DIALOG_DUMMY_PRX, ret); + gsiPspUnloadRequiredModules(); + return ret; + } + gPspnetApDialogDummyModid = ret; + + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Used to shutdown network library modules +int gsiPspUnloadRequiredModules() +{ + int ret = 0; + + + ret = gsiPspUnloadModule(gPspnetApDialogDummyModid); + if (ret < 0) + { + printf("unload_module() failed. ret = 0x%x\n", ret); + return ret; + } + + ret = sceUtilityUnloadModule(SCE_UTILITY_MODULE_NET_INET); + if (ret < 0) + { + printf("sceUtilityUnloadModule(SCE_UTILITY_MODULE_NET_INET) failed. ret = 0x%x\n", ret); + } + + ret = sceUtilityUnloadModule(SCE_UTILITY_MODULE_NET_COMMON); + if (ret < 0) + { + printf("sceUtilityUnloadModule(SCE_UTILITY_MODULE_NET_COMMON) failed. ret = 0x%x\n", ret); + } + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// AP network connection handler used to detect if psp was disconnected +void gsiPspApctlHandler(int prev_state, int new_state, int event, int error_code, void *arg) +{ + (void)arg; + + if(new_state == SCE_NET_APCTL_STATE_Disconnected) + { + if(event == SCE_NET_APCTL_EVENT_DISCONNECT_REQ) + gDisconnected = 1; + if(prev_state == SCE_NET_APCTL_STATE_IPObtained && + event == SCE_NET_APCTL_EVENT_ERROR) + printf("Apctl error happened, error = 0x%x\n", error_code); + } +} + +int gsiPspnetDisconnect() +{ + int ret; + + gDisconnected = 0; + + ret = sceNetApctlDisconnect(); + if(ret < 0) + { + printf("sceNetApctlDisconnect() failed. ret = 0x%x\n", ret); + return ret; + } + + while(gDisconnected == 0) + sceKernelDelayThread(AP_DIALOG_DUMMY_WAIT_TIME); + + sceNetApDialogDummyTerm(); + if (gPspnetApctlHandlerId >= 0) + { + sceNetApctlDelHandler(gPspnetApctlHandlerId); + } + + return ret; +} + +void gsiPspnetStop() +{ + // turn off all services if they are available + sceNetApctlTerm(); + + sceNetResolverTerm(); + + sceNetInetTerm(); + + sceNetTerm(); +} + +// Error Handler used to stop network libraries in case of failure +void gsiPspnetErrorHandler(int shutDownServices) +{ + + if (shutDownServices & PSPNET_CONNECTED) + gsiPspnetDisconnect(); + + if (shutDownServices & PSPNET_APDUMDLG_STARTED) + sceNetApDialogDummyTerm(); + + if (shutDownServices & PSPNET_APCTLHDLR) + if(gPspnetApctlHandlerId >= 0) + sceNetApctlDelHandler(gPspnetApctlHandlerId); + + gsiPspnetStop(); +} + +// +int gsiPspStartNetworkModules() +{ + struct SceNetApDialogDummyStateInfo ap_dialog_dummy_state; + union SceNetApctlInfo apctl_info; + int ret; + // error bit starts at 1 and is shifted left with one added + int serviceToShutDown = 0; + + ret = sceNetInit(PSPNET_POOLSIZE, CALLOUT_TPL, 0, + NETINTR_TPL, 0); + if(ret < 0) + { + printf("sceNetInit() failed. ret = 0x%x\n", ret); + return ret; + } + + + ret = sceNetInetInit(); + if(ret < 0) + { + printf("sceNetInetInit() failed. ret = 0x%x\n", ret); + gsiPspnetStop(); + return ret; + } + + + ret = sceNetResolverInit(); + if(ret < 0) + { + printf("sceNetResolverInit() failed. ret = 0x%x\n", ret); + gsiPspnetStop(); + return ret; + } + + + ret = sceNetApctlInit(SCE_APCTL_STACKSIZE, SCE_APCTL_PRIO); + if(ret < 0) + { + printf("sceNetApctlInit() failed. ret = 0x%x\n", ret); + gsiPspnetStop(); + return ret; + } + + + ret = sceNetApctlAddHandler(gsiPspApctlHandler, NULL); + if(ret < 0) + { + printf("sceNetApctlAddHandler() failed. ret = 0x%x\n", ret); + gsiPspnetStop(); + return ret; + } + gPspnetApctlHandlerId = ret; + + serviceToShutDown = serviceToShutDown | PSPNET_APCTLHDLR; + ret = sceNetApDialogDummyInit(); + if(ret < 0) + { + printf("sceNetApDialogDummyInit() failed. ret = 0x%x\n", ret); + gsiPspnetErrorHandler(serviceToShutDown); // called with 31 + return ret; + } + + serviceToShutDown = serviceToShutDown | PSPNET_APDUMDLG_STARTED; + /* check Wireless LAN switch */ + ret = sceWlanGetSwitchState(); + if(ret == SCE_WLAN_SWITCH_STATE_OFF){ + printf("Wireless LAN switch has been turned off.\n"); + gsiPspnetErrorHandler(serviceToShutDown); // called with 63 + return ret; + } + + + memset(&gApDialogDummyParam, 0, sizeof(gApDialogDummyParam)); +#ifndef AUTO_SELECT_ROUTER + strcpy(gApDialogDummyParam.ssid, YOUR_WIRELESS_ROUTER_NAME); +#endif + ret = sceNetApDialogDummyConnect(&gApDialogDummyParam); + if(ret < 0) + { + printf("sceNetApDialogDummyConnect() failed. ret = 0x%x\n", ret); + gsiPspnetErrorHandler(serviceToShutDown); // called with 63 + return ret; + } + + while(1){ + ret = sceNetApDialogDummyGetState(&ap_dialog_dummy_state); + if(ret == 0){ + if(ap_dialog_dummy_state.state == SceNetApDialogDummyState_Connected || + ap_dialog_dummy_state.state == SceNetApDialogDummyState_Disconnected) + break; + } + sceKernelDelayThread(AP_DIALOG_DUMMY_WAIT_TIME); + } + + if(ap_dialog_dummy_state.state == SceNetApDialogDummyState_Disconnected) + { + printf("failed to Join or Get IP addr. error = 0x%x\n", ap_dialog_dummy_state.error_code); + gsiPspnetErrorHandler(serviceToShutDown); // called with 63 + return ap_dialog_dummy_state.error_code; + } + + serviceToShutDown = serviceToShutDown | PSPNET_CONNECTED; + ret = sceNetApctlGetInfo(SCE_NET_APCTL_INFO_IP_ADDRESS, &apctl_info); + if(ret < 0) + { + printf("sceNetApctlGetInfo() failed. ret = 0x%x\n", ret); + gsiPspnetErrorHandler(serviceToShutDown); // called with 127 + return ret; + } + printf("obtained IP addr: %s\n", apctl_info.ip_address); + return ret; +} + +// sample entry point +extern int test_main(int argc, char ** argp); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Common PSP entry point +int main(int argc, char** argp) +{ + int ret = 0; + + + // Load the modules required to do basic TCP/IP networking + ret = gsiPspLoadRequiredModules(); + if(ret < 0) + { + printf("gsiPspLoadRequiredModules failed. See previous return value. return = 0x%x\n", + ret); + return SCE_KERNEL_EXIT_SUCCESS; + } + + + // Start up PSPNET libraries + ret = gsiPspStartNetworkModules(); + if (ret < 0) + { + printf("gsiPspStartNetworkModules failed See previous return value. return = 0x%x\n", ret); + return ret; + } + + + /////////////////////////////////// + // Call the application entry point + ret = test_main(argc, argp); + + ret = gsiPspnetDisconnect(); + if (ret < 0) + { + printf("gsiPspnetDisconnect failed See previous return value. return = 0x%x\n", ret); + return ret; + } + + // Shut down the PSPNET network library + gsiPspnetStop(); + + ret = gsiPspUnloadRequiredModules(); + if(ret < 0) + return SCE_KERNEL_EXIT_SUCCESS; + + return SCE_KERNEL_EXIT_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _PSP only diff --git a/xrGameSpy/gamespy/common/revolution/gsSocketRevolution.c b/xrGameSpy/gamespy/common/revolution/gsSocketRevolution.c new file mode 100644 index 00000000000..0b587ea2695 --- /dev/null +++ b/xrGameSpy/gamespy/common/revolution/gsSocketRevolution.c @@ -0,0 +1,197 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_REVOLUTION) + +// include the revolution socket header +#include "../gsPlatform.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// static variables +static int GSIRevolutionErrno; + +// prototypes of static functions +static int CheckRcode(int rcode, int errCode); + +#define REVOlUTION_SOCKET_ERROR -1 + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// parses rcode into a generic -1 error if an error has occured +static int CheckRcode(int rcode, int errCode) +{ + if(rcode >= 0) + return rcode; + GSIRevolutionErrno = rcode; + return errCode; +} + +int socket(int pf, int type, int protocol) +{ + int rcode = SOSocket(pf, type, 0); + GSI_UNUSED(protocol); + return CheckRcode(rcode, INVALID_SOCKET); +} +int closesocket(SOCKET sock) +{ + int rcode = SOClose(sock); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +int shutdown(SOCKET sock, int how) +{ + int rcode = SOShutdown(sock, how); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +int bind(SOCKET sock, const SOCKADDR* addr, int len) +{ + SOCKADDR localAddr; + int rcode; + + // with Revolution, don't bind to 0, just start using the port + if(((const SOCKADDR_IN*)addr)->port == 0) + return 0; + + memcpy(&localAddr, addr, sizeof(SOCKADDR)); + localAddr.len = (u8)len; + + rcode = SOBind(sock, &localAddr); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} + +int connect(SOCKET sock, const SOCKADDR* addr, int len) +{ + SOCKADDR remoteAddr; + int rcode; + + memcpy(&remoteAddr, addr, sizeof(SOCKADDR)); + remoteAddr.len = (u8)len; + + rcode = SOConnect(sock, &remoteAddr); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +int listen(SOCKET sock, int backlog) +{ + int rcode = SOListen(sock, backlog); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +SOCKET accept(SOCKET sock, SOCKADDR* addr, int* len) +{ + int rcode; + addr->len = (u8)*len; + rcode = SOAccept(sock, addr); + *len = addr->len; + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} + +int recv(SOCKET sock, char* buf, int len, int flags) +{ + int rcode = SORecv(sock, buf, len, flags); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +int recvfrom(SOCKET sock, char* buf, int len, int flags, SOCKADDR* addr, int* fromlen) +{ + int rcode; + addr->len = (u8)*fromlen; + rcode = SORecvFrom(sock, buf, len, flags, addr); + *fromlen = addr->len; + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +SOCKET send(SOCKET sock, const char* buf, int len, int flags) +{ + int rcode = SOSend(sock, buf, len, flags); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +SOCKET sendto(SOCKET sock, const char* buf, int len, int flags, const SOCKADDR* addr, int tolen) +{ + SOCKADDR remoteAddr; + int rcode; + + memcpy(&remoteAddr, addr, sizeof(SOCKADDR)); + remoteAddr.len = (u8)tolen; + + rcode = SOSendTo(sock, buf, len, flags, &remoteAddr); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} + +int getsockopt(SOCKET sock, int level, int optname, char* optval, int* optlen) +{ + int rcode = SOGetSockOpt(sock, level, optname, optval, optlen); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} +SOCKET setsockopt(SOCKET sock, int level, int optname, const char* optval, int optlen) +{ + int rcode = SOSetSockOpt(sock, level, optname, optval, optlen); + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} + +int getsockname(SOCKET sock, SOCKADDR* addr, int* len) +{ + int rcode; + addr->len = (u8)*len; + rcode = SOGetSockName(sock, addr); + *len = addr->len; + return CheckRcode(rcode, REVOlUTION_SOCKET_ERROR); +} + +unsigned long inet_addr(const char* name) +{ + int rcode; + SOInAddr addr; + rcode = SOInetAtoN(name, &addr); + if(rcode == FALSE) + return INADDR_NONE; + return addr.addr; +} + +int GOAGetLastError(SOCKET sock) +{ + GSI_UNUSED(sock); + return GSIRevolutionErrno; +} + +int GSISocketSelect(SOCKET theSocket, int* theReadFlag, int* theWriteFlag, int* theExceptFlag) +{ + SOPollFD pollFD; + int rcode; + + pollFD.fd = theSocket; + pollFD.events = 0; + if(theReadFlag != NULL) + pollFD.events |= SO_POLLRDNORM; + if(theWriteFlag != NULL) + pollFD.events |= SO_POLLWRNORM; + pollFD.revents = 0; + + rcode = SOPoll(&pollFD, 1, 0); + if(rcode < 0) + return REVOlUTION_SOCKET_ERROR; + + if(theReadFlag != NULL) + { + if((rcode > 0) && (pollFD.revents & (SO_POLLRDNORM|SO_POLLHUP))) + *theReadFlag = 1; + else + *theReadFlag = 0; + } + if(theWriteFlag != NULL) + { + if((rcode > 0) && (pollFD.revents & SO_POLLWRNORM)) + *theWriteFlag = 1; + else + *theWriteFlag = 0; + } + if(theExceptFlag != NULL) + { + if((rcode > 0) && (pollFD.revents & SO_POLLERR)) + *theExceptFlag = 1; + else + *theExceptFlag = 0; + } + return rcode; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // _REVOLUTION \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/revolution/gsThreadRevoulution.c b/xrGameSpy/gamespy/common/revolution/gsThreadRevoulution.c new file mode 100644 index 00000000000..9a9808d959d --- /dev/null +++ b/xrGameSpy/gamespy/common/revolution/gsThreadRevoulution.c @@ -0,0 +1,183 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" + + +// Begin of Threading for Revolution +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 gsiInterlockedIncrement(gsi_u32 * value) +{ + BOOL enabled = OSDisableInterrupts(); + + gsi_u32 ret = ++(*value); + OSRestoreInterrupts(enabled); + + // return "ret" rather than "value" here b/c + // value may be modified by another thread + // before we can return it + return ret; +} + +gsi_u32 gsiInterlockedDecrement(gsi_u32 * value) +{ + BOOL state = OSDisableInterrupts(); + gsi_u32 ret = --(*value); + OSRestoreInterrupts(state); + + // return "ret" rather than "value" here b/c + // value may be modified by another thread + // before we can return it + return ret; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +int gsiStartThread(GSThreadFunc aThreadFunc, gsi_u32 theStackSize, void *arg, GSIThreadID* theThreadIdOut) +{ + char *aStackBase; + if(theStackSize % 32 != 0) + { + OSRoundUp32B(theStackSize); + } + + theThreadIdOut->mStack = gsimalloc(theStackSize); + aStackBase = (char *)theThreadIdOut->mStack; + aStackBase += theStackSize; + + OSCreateThread(&theThreadIdOut->mThread, aThreadFunc, arg, (void *)aStackBase, + theStackSize, 16, OS_THREAD_ATTR_DETACH); + + OSResumeThread(&theThreadIdOut->mThread); + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiCancelThread(GSIThreadID theThreadID) +{ + OSCancelThread(&theThreadID.mThread); + if(theThreadID.mStack) + { + gsifree(theThreadID.mStack); + theThreadID.mStack = NULL; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiCleanupThread(GSIThreadID theThreadID) +{ + + if (!OSIsThreadTerminated(&theThreadID.mThread)) + OSCancelThread(&theThreadID.mThread); + if(theThreadID.mStack) + { + gsifree(theThreadID.mStack); + theThreadID.mStack = NULL; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID) +{ + BOOL shutdown = OSIsThreadTerminated(&theThreadID.mThread); + + if(shutdown == TRUE) + return 1; + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) +{ + OSInitMutex(theCrit); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiEnterCriticalSection(GSICriticalSection *theCrit) +{ + OSLockMutex(theCrit); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiLeaveCriticalSection(GSICriticalSection *theCrit) +{ + OSUnlockMutex(theCrit); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiDeleteCriticalSection(GSICriticalSection *theCrit) +{ + GSI_UNUSED(theCrit); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + GSISemaphoreID semaphore; + + OSInitSemaphore(&semaphore, theInitialCount); + + GSI_UNUSED(theName); + GSI_UNUSED(theMaxCount); + + return semaphore; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + gsi_u32 retval = (unsigned int)OSWaitSemaphore(&theSemaphore); + GSI_UNUSED(theTimeoutMs); + return retval; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + OSSignalSemaphore(&theSemaphore); + GSI_UNUSED(theReleaseCount); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + GSI_UNUSED(theSemaphore); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void gsiExitThread(GSIThreadID theThreadID) +{ + GSI_UNUSED(theThreadID); +} + + + +// End of Threading for Revolution +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/revolution/gsUtilRevolution.c b/xrGameSpy/gamespy/common/revolution/gsUtilRevolution.c new file mode 100644 index 00000000000..d0a34000dd5 --- /dev/null +++ b/xrGameSpy/gamespy/common/revolution/gsUtilRevolution.c @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" +#include "../gsPlatformUtil.h" + +void gsiRevolutionSleep(u32 msec); +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static OSAlarm gAlarm; +static OSThreadQueue gQueue; +static BOOL gQueueInitialized; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static const char * GOAGetUniqueID_Internal(void) +{ + static char keyval[17]; + u8 aMac[ETH_ALEN]; + int aMacLen; + + // check if we already have the Unique ID + if(keyval[0]) + return keyval; + + aMacLen = ETH_ALEN; + SOGetInterfaceOpt (NULL, SO_SOL_CONFIG, SO_CONFIG_MAC_ADDRESS, + aMac, &aMacLen); + + // format it + sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000", + aMac[0] & 0xFF, + aMac[1] & 0xFF, + aMac[2] & 0xFF, + aMac[3] & 0xFF, + aMac[4] & 0xFF, + aMac[5] & 0xFF); + + return keyval; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Time Functions +static char GSIMonthNames[12][3] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +static char GSIWeekDayNames[7][3] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + +time_t gsiTimeInSec(time_t *timer) +{ + time_t t = 0; + t = (gsi_i32)OSTicksToSeconds(OSGetTime()); + + if (timer) + *timer = t; + + return t; +} + + +struct tm *gsiGetGmTime(time_t *theTime) +{ + static struct tm aTimeStruct; + static struct tm *aRetVal = &aTimeStruct; + OSCalendarTime aCalTimeStruct; + + OSTicksToCalendarTime(*theTime, &aCalTimeStruct); + + aRetVal->tm_sec = aCalTimeStruct.sec; + aRetVal->tm_min = aCalTimeStruct.min; + aRetVal->tm_hour = aCalTimeStruct.hour; + aRetVal->tm_mday = aCalTimeStruct.mday; + aRetVal->tm_mon = aCalTimeStruct.mon; + aRetVal->tm_year = aCalTimeStruct.year - 1900; + aRetVal->tm_wday = aCalTimeStruct.wday; + aRetVal->tm_yday = 0; + aRetVal->tm_isdst = 0; + return aRetVal; +} + +char *gsiCTime(time_t *theTime) +{ + static char str[26]; + struct tm *ptm = gsiGetGmTime(theTime); + + // e.g.: "Wed Jan 02 02:03:55 1980\n\0" + sprintf(str, "%s %s %02d %02d:%02d:%02d %d\n", + GSIWeekDayNames[ptm->tm_wday], + GSIMonthNames[ptm->tm_mon], ptm->tm_mday, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec, + ptm->tm_year + 1900); + + return str; +} + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return atoll(theNumberStr); +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + + sprintf(theNumberStr, "%lld", theNumber); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/revolution/revolutionCommon.c b/xrGameSpy/gamespy/common/revolution/revolutionCommon.c new file mode 100644 index 00000000000..221f849b2ce --- /dev/null +++ b/xrGameSpy/gamespy/common/revolution/revolutionCommon.c @@ -0,0 +1,240 @@ +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// (C) Gamespy Industries +// +// Commonly shared network startup code +// WARNING: Please do not use this code as a basis for +// Game Network startup code. This is only for testing +// purposes. +// +// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +#include "../gsCommon.h" +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +static NCDIfConfig gIfConfig; +static NCDIpConfig gIpConfig; +static OSMutex gOsMemMutex; +static MEMHeapHandle heapHandleSocket = NULL; + +#define SOCKET_HEAPSIZE_DEFAULT (1024*128) + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +static void SetDefaultIfConfig( NCDIfConfig* theIfConfig ) +{ + (void)memset( theIfConfig, 0, sizeof( NCDIfConfig ) ); + + theIfConfig->selectedMedia = NCD_IF_SELECT_WIRED; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +static void SetDefaultIpConfig( NCDIpConfig* theIpConfig ) +{ + + (void)memset( theIpConfig, 0, sizeof( NCDIpConfig ) ); + + theIpConfig->useDhcp = TRUE; + + theIpConfig->adjust.maxTransferUnit = 1300; // Value can be 1460 depending on network library + theIpConfig->adjust.tcpRetransTimeout = 100; + theIpConfig->adjust.dhcpRetransCount = 4; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Memory functions used by the network library + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +static void* _Alloc(unsigned long theName, long theSize) +{ + void* a_memory_p = NULL; + + (void)theName; + + if (0 < theSize) + { + //OSLockMutex(&gOsMemMutex); + //a_memory_p = OSAlloc((u32)theSize); + //OSUnlockMutex(&gOsMemMutex); + + // 02OCT07 BED: MEM2 was initialized with MEM_HEAP_OPT_THREAD_SAFE + // so we don't need to manually lock it + a_memory_p = MEMAllocFromExpHeapEx( heapHandleSocket, (u32) theSize, 32 ); + } + + return a_memory_p; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +static void _Free(unsigned long theName, void* theMemoryPointer, long theSize) +{ + GSI_UNUSED(theName); + + if (theMemoryPointer && 0 < theSize) + { + //OSLockMutex(&gOsMemMutex); + //OSFree(theMemoryPointer); + //OSUnlockMutex(&gOsMemMutex); + + // 02OCT07 BED: MEM2 was initialized with MEM_HEAP_OPT_THREAD_SAFE + // so we don't need to manually lock it + MEMFreeToExpHeap( heapHandleSocket, theMemoryPointer); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// StartNetwork +// +BOOL StartNetwork() +{ + s32 rc; + + OSInitMutex(&gOsMemMutex); + + // Start up the network interface USB device + SetDefaultIfConfig( &gIfConfig ); + OSReport( "NCDSetIfConfig() ..." ); + rc = NCDSetIfConfig( &gIfConfig ); + if( rc != NCD_RESULT_SUCCESS ) + { + OSReport( "failed (%d)\n", rc ); + return FALSE; + } + OSReport( "success\n" ); + + + SetDefaultIpConfig( &gIpConfig ); + OSReport( "NCDSetIpConfig() ..." ); + rc = NCDSetIpConfig( &gIpConfig ); + if( rc != NCD_RESULT_SUCCESS ) + { + OSReport( "failed (%d)\n", rc ); + return FALSE; + } + OSReport( "success\n" ); + + + // Waiting for the network interface to come with the + // configuration previously set. + OSReport( "NCDIsInterfaceDecided() " ); + while( NCDIsInterfaceDecided() == FALSE ) + { + NCDSleep( OSMillisecondsToTicks( 10 ) ); + } + OSReport( "success\n" ); + + + // Finished bringing up network interface + // Now initializing the socket library + OSReport( "SOInit() ..." ); + { + SOLibraryConfig soLibConfig; + + (void)memset(&soLibConfig, 0, sizeof(soLibConfig)); + soLibConfig.alloc = _Alloc; + soLibConfig.free = _Free; + + rc = SOInit(&soLibConfig); + if( rc != SO_SUCCESS ) + { + switch(rc) + { + case SO_EALREADY: + OSReport("failed (SO_EALREADY)\n"); + break; + case SO_EINVAL: + OSReport("failed (SO_EINVAL)\n"); + break; + case SO_ENOMEM: + OSReport("failed (SO_ENOMEM)\n"); + break; + default: + OSReport("failed (%d)\n", rc); + }; + return FALSE; + } + } + OSReport( "success\n" ); + + + //Now Starting the sockets library + OSReport( "SOStartup() " ); + rc = SOStartup(); + if( rc != SO_SUCCESS ) + { + OSReport( "failed (%d)\n", rc ); + return FALSE; + } + OSReport( "success\n" ); + + // Getting the IP address of the local machine via DHCP + while( SOGetHostID() == 0 ) + { + NCDSleep( OSMillisecondsToTicks( 10 ) ); + } + { + SOInAddr addr; + addr.addr = (u32)SOGetHostID(); + OSReport( "IP address = %s\n", SOInetNtoA( addr ) ); + } + return TRUE; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// StopNetwork +// +void StopNetwork() +{ + (void)SOCleanup(); +} + +extern int test_main(int argc, char **argv); +void main(int argc, char **argv) +{ +// init 128k memory for sockets + void* arenaLo; + void* arenaHi; + + DEMOInit(NULL); // Init the OS, game pad, graphics and video. + + // Initialize heap for socket allocations + // Nintendo samples say this must be in MEM2 + arenaLo = OSGetMEM2ArenaLo(); + arenaHi = OSGetMEM2ArenaHi(); + + if ((u32) arenaHi - (u32) arenaLo < SOCKET_HEAPSIZE_DEFAULT) + OSHalt("Insufficient memory in MEM2 for socket lib. Check SOCKET_HEAPSIZE_DEFAULT"); + heapHandleSocket = MEMCreateExpHeapEx( arenaLo, SOCKET_HEAPSIZE_DEFAULT, MEM_HEAP_OPT_THREAD_SAFE ); + if (heapHandleSocket == MEM_HEAP_INVALID_HANDLE) + OSHalt("MEMCreateExpHeapEx failed.\n"); + OSSetArenaLo((u8*)arenaLo + SOCKET_HEAPSIZE_DEFAULT); + + // Start the network + if (!StartNetwork()) + OSHalt("Network was not started\n"); + OSReport("=======================================================================\n"); + OSReport("Gamespy:// Starting App\n"); + test_main(argc, argv); + OSReport("=======================================================================\n"); + OSReport("Gamespy:// Ending App\n"); + StopNetwork(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/win32/Win32Common.c b/xrGameSpy/gamespy/common/win32/Win32Common.c new file mode 100644 index 00000000000..49c13137cc2 --- /dev/null +++ b/xrGameSpy/gamespy/common/win32/Win32Common.c @@ -0,0 +1,98 @@ +#include "../gsCommon.h" +#include "../gsMemory.h" +#include "../gsDebug.h" +#include +// Debug output +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + + { + GSI_UNUSED(theLevel); + { + static char string[256]; + vsprintf(string, theTokenStr, theParamList); + OutputDebugString(string); + } + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); + } +#endif + +#if (_MSC_VER <= 1300) + //extern added for vc6 compatability. + extern void * __cdecl _aligned_malloc(size_t size, size_t boundary); + extern void __cdecl _aligned_free(void * memblock); +#endif +void * gsiMemManagedInit() +{ +// Init the GSI memory manager (optional - for limiting GSI mem usage) +#if defined GSI_MEM_MANAGED + #define aMemoryPoolSize (1024*1024*4) + char *aMemoryPool = (char *)_aligned_malloc(aMemoryPoolSize,64); + if(aMemoryPool == NULL) + { + printf("Failed to create memory pool - aborting\r\n"); + return NULL; + } + { + gsMemMgrCreate(gsMemMgrContext_Default, "Default",aMemoryPool, aMemoryPoolSize); + } + return aMemoryPool; +#else + return NULL; +#endif + +} + +void gsiMemManagedClose(void * theMemoryPool) +{ + #if defined(GSI_MEM_MANAGED) + // Optional - Dump memory leaks + + gsi_u32 MemAvail = gsMemMgrMemAvailGet (gsMemMgrContext_Default); + gsi_u32 MemUsed = gsMemMgrMemUsedGet (gsMemMgrContext_Default); + gsi_u32 HwMark = gsMemMgrMemHighwaterMarkGet (gsMemMgrContext_Default); + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_Comment, + "MemAvail %u: MemUsed%u MemHWMark %u\n", MemAvail,MemUsed,HwMark); + gsMemMgrDumpStats(); + gsMemMgrDumpAllocations(); + gsMemMgrValidateMemoryPool(); + gsMemMgrDestroy(gsMemMgrContext_Default); + #endif + _aligned_free(theMemoryPool); +} + + +// sample common entry point +extern int test_main(int argc, char ** argp); + + +// Common entry point +int __cdecl main(int argc, char** argp) +{ + int ret = 0; + // set up memanager + void *heap = gsiMemManagedInit(); + + #ifdef GSI_COMMON_DEBUG + // Set up debugging + gsSetDebugCallback(DebugCallback); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); + #endif + + ret = test_main(argc, argp); + + gsiMemManagedClose(heap); + + return ret; +} + + + + diff --git a/xrGameSpy/gamespy/common/win32/changelog.txt b/xrGameSpy/gamespy/common/win32/changelog.txt new file mode 100644 index 00000000000..825c2d1f308 --- /dev/null +++ b/xrGameSpy/gamespy/common/win32/changelog.txt @@ -0,0 +1,14 @@ +Changelog for: Win32 Common Code +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +09-15-2006 1.00.02 DES FIX Always call CreateSemaphoreA +09-21-2005 1.00.01 DES FEATURE Updated workspace +06-03-2005 1.00.00 SN RELEASE Releasing to developer site. +04-28-2005 1.00.00 SN RELEASE Releasing to developer site. +04-04-2005 1.00.00 SN RELEASE Releasing to developer site. +09-16-2004 1.00.00 SN RELEASE Releasing to developer site. +08-26-2004 1.00.00 DES OTHER Changelog started + FEATURE Added a workspace for building all the C test apps. + diff --git a/xrGameSpy/gamespy/common/win32/gsSocketWin32.c b/xrGameSpy/gamespy/common/win32/gsSocketWin32.c new file mode 100644 index 00000000000..9622b31f7cd --- /dev/null +++ b/xrGameSpy/gamespy/common/win32/gsSocketWin32.c @@ -0,0 +1,3 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + diff --git a/xrGameSpy/gamespy/common/win32/gsThreadWin32.c b/xrGameSpy/gamespy/common/win32/gsThreadWin32.c new file mode 100644 index 00000000000..8bcb1d786b6 --- /dev/null +++ b/xrGameSpy/gamespy/common/win32/gsThreadWin32.c @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsPlatformUtil.h" +#include "../gsPlatformThread.h" +#include "../gsAssert.h" +#include "../gsDebug.h" + + + +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) { InitializeCriticalSection(theCrit); } +void gsiEnterCriticalSection (GSICriticalSection *theCrit) { EnterCriticalSection(theCrit); } +void gsiLeaveCriticalSection (GSICriticalSection *theCrit) { LeaveCriticalSection(theCrit); } +void gsiDeleteCriticalSection (GSICriticalSection *theCrit) { DeleteCriticalSection(theCrit); } + +gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID) +{ + DWORD result = WaitForSingleObject(theThreadID, 0); + if (result == WAIT_ABANDONED || result == WAIT_OBJECT_0) + return 1; // thread is dead + else + return 0; // keep waiting +} + +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + GSISemaphoreID aSemaphore = CreateSemaphoreA(NULL, theInitialCount, theMaxCount, theName); + if (aSemaphore == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create semaphore\r\n"); + } + return aSemaphore; +} + +// Waits for -- and signals -- the semaphore +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + DWORD result = WaitForSingleObject((HANDLE)theSemaphore, (DWORD)theTimeoutMs); + return (gsi_u32)result; +} + +// Allow other objects to access the semaphore +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + ReleaseSemaphore(theSemaphore, theReleaseCount, NULL); +} + +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + CloseHandle(theSemaphore); +} + + +int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID * id) +{ + HANDLE handle; + DWORD threadID; + + // create the thread + handle = CreateThread(NULL, theStackSize, func, arg, 0, &threadID); + if(handle == NULL) + return -1; + + // store the id + *id = handle; + + return 0; +} + +void gsiCancelThread(GSIThreadID id) +{ + //TODO: is TerminateThread causing lost resources? + //should this be terminated with "failure" exit status? + TerminateThread(id, 0); +} + +void gsiExitThread(GSIThreadID id) +{ + GSI_UNUSED(id); +} + +void gsiCleanupThread(GSIThreadID id) +{ + CloseHandle(id); +} + + diff --git a/xrGameSpy/gamespy/common/win32/gsUtilWin32.c b/xrGameSpy/gamespy/common/win32/gsUtilWin32.c new file mode 100644 index 00000000000..84dd81662fd --- /dev/null +++ b/xrGameSpy/gamespy/common/win32/gsUtilWin32.c @@ -0,0 +1,19 @@ +#include "../gsCommon.h" + +gsi_i64 gsiStringToInt64(const char *theNumberStr) +{ + return _atoi64(theNumberStr); +} + +void gsiInt64ToString(char theNumberStr[33], gsi_i64 theNumber) +{ + // you want to fit the number! + // give me a valid string! + GS_ASSERT(theNumberStr != NULL); + +#if _MSC_VER > 1300 + sprintf(theNumberStr, "%lld", theNumber); +#else + sprintf(theNumberStr, "%I64d", theNumber); +#endif +} diff --git a/xrGameSpy/gamespy/common/win32/win32common.dsw b/xrGameSpy/gamespy/common/win32/win32common.dsw new file mode 100644 index 00000000000..b46b3327341 --- /dev/null +++ b/xrGameSpy/gamespy/common/win32/win32common.dsw @@ -0,0 +1,245 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Voice2Test"=..\..\Voice2\Voice2Test\Voice2Test.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Voice2/Voice2Test", MPNDAAAA + ..\..\voice2\voice2test + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "chatc"=..\..\Chat\chatc\chatc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Chat/chatc", RRUAAAAA + ..\..\chat\chatc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gcdkeyclient"=..\..\gcdkey\gcdkeyclient.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gcdkey", JIGAAAAA + ..\..\gcdkey + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gcdkeyserver"=..\..\gcdkey\gcdkeyserver.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gcdkey", JIGAAAAA + ..\..\gcdkey + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ghttpc"=..\..\ghttp\ghttpc\ghttpc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp/ghttpc", BUZAAAAA + ..\..\ghttp\ghttpc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gptestc"=..\..\GP\gptestc\gptestc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/GP/gptestc", ZHJAAAAA + ..\..\gp\gptestc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gstats"=..\..\gstats\gstats.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats", BSGAAAAA + ..\..\gstats + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2testc"=..\..\gt2\gt2testc\gt2testc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2testc", LPOCAAAA + ..\..\gt2\gt2testc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "peerc"=..\..\Peer\peerc\peerc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/Peer/peerc", GSUAAAAA + ..\..\peer\peerc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "persisttest"=..\..\gstats\persisttest\persisttest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/persisttest", BBVAAAAA + ..\..\gstats\persisttest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "pttestc"=..\..\pt\pttestc\pttestc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pt/pttestc", KCGBAAAA + ..\..\pt\pttestc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "qr2csample"=..\..\qr2\qr2csample\qr2csample.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/qr2/qr2csample + ..\..\qr2\qr2csample + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "sbctest"=..\..\serverbrowsing\sbctest\sbctest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/serverbrowsing/sbctest + ..\..\serverbrowsing\sbctest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "simpletest"=..\..\natneg\simpletest\simpletest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/natneg/simpletest", HFUCAAAA + ..\..\natneg\simpletest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/common/win32 + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/common/x360/X360Common.c b/xrGameSpy/gamespy/common/x360/X360Common.c new file mode 100644 index 00000000000..73586221b60 --- /dev/null +++ b/xrGameSpy/gamespy/common/x360/X360Common.c @@ -0,0 +1,93 @@ +#include "../gsCommon.h" +#include "../gsMemory.h" +#include "../gsDebug.h" +#include +// Debug output +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + + { + GSI_UNUSED(theLevel); + { + static char string[256]; + vsprintf(string, theTokenStr, theParamList); + OutputDebugString(string); + } + } +#endif + +#if (_MSC_VER <= 1300) + //extern added for vc6 compatability. + extern void * __cdecl _aligned_malloc(size_t size, int boundary); + extern void * __cdecl _aligned_free(void * memblock); +#endif +void * gsiMemManagedInit() +{ +// Init the GSI memory manager (optional - for limiting GSI mem usage) +#if defined GSI_MEM_MANAGED + #define aMemoryPoolSize (1024*1024*4) + char *aMemoryPool = _aligned_malloc(aMemoryPoolSize,64); + if(aMemoryPool == NULL) + { + printf("Failed to create memory pool - aborting\r\n"); + return NULL; + } + { + gsMemMgrCreate(gsMemMgrContext_Default, "Default",aMemoryPool, aMemoryPoolSize); + } + return aMemoryPool; +#else + return NULL; +#endif + +} + +void gsiMemManagedClose(void * theMemoryPool) +{ + #if defined(GSI_MEM_MANAGED) + // Optional - Dump memory leaks + + gsi_u32 MemAvail = gsMemMgrMemAvailGet (gsMemMgrContext_Default); + gsi_u32 MemUsed = gsMemMgrMemUsedGet (gsMemMgrContext_Default); + gsi_u32 HwMark = gsMemMgrMemHighwaterMarkGet (gsMemMgrContext_Default); + + gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_Comment, + "MemAvail %u: MemUsed%u MemHWMark %u\n", MemAvail,MemUsed,HwMark); + gsMemMgrDumpStats(); + gsMemMgrDumpAllocations(); + gsMemMgrValidateMemoryPool(); + + #endif + _aligned_free(theMemoryPool); +} + + +// sample common entry point +extern int test_main(int argc, char ** argp); + + +// Common entry point +int __cdecl main(int argc, char** argp) +{ + int ret = 0; + // set up memanager + void *heap = gsiMemManagedInit(); + + #ifdef GSI_COMMON_DEBUG + // Set up debugging + gsSetDebugCallback(DebugCallback); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); + #endif + + ret = test_main(argc, argp); + + gsiMemManagedClose(heap); + + return ret; +} + + + + diff --git a/xrGameSpy/gamespy/common/x360/gsSocketX360.c b/xrGameSpy/gamespy/common/x360/gsSocketX360.c new file mode 100644 index 00000000000..d3ee7036cc1 --- /dev/null +++ b/xrGameSpy/gamespy/common/x360/gsSocketX360.c @@ -0,0 +1,52 @@ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_X360) +char * inet_ntoa(IN_ADDR in_addr) +{ + static char buffer[16]; + sprintf(buffer, "%d.%d.%d.%d", in_addr.S_un.S_un_b.s_b1, in_addr.S_un.S_un_b.s_b2, + in_addr.S_un.S_un_b.s_b3, in_addr.S_un.S_un_b.s_b4); + return buffer; +} + +struct hostent * gethostbyname(const char* name) +{ + XNDNS *pxndns; + static HOSTENT host; + HOSTENT *rvalue; + + if(XNetDnsLookup(name, NULL, &pxndns) != 0) + return NULL; + + while (pxndns->iStatus == WSAEINPROGRESS) + { + msleep(5); + } + + if ((pxndns->iStatus == 0) && (pxndns->cina > 0)) + { + static char * ipPtrs[2]; + static IN_ADDR ip; + + host.h_name = (char*)name; + host.h_aliases = NULL; + host.h_addrtype = AF_INET; + host.h_length = (gsi_u16)sizeof(IN_ADDR); + host.h_addr_list = (gsi_i8 **)ipPtrs; + + ip = pxndns->aina[0]; + ipPtrs[0] = (char *)&ip; + ipPtrs[1] = NULL; + + rvalue = &host; + } + else + { + rvalue = NULL; + } + XNetDnsRelease(pxndns); + + return rvalue; +} +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/common/x360/gsThreadX360.c b/xrGameSpy/gamespy/common/x360/gsThreadX360.c new file mode 100644 index 00000000000..281067434ba --- /dev/null +++ b/xrGameSpy/gamespy/common/x360/gsThreadX360.c @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../gsPlatformUtil.h" +#include "../gsPlatformThread.h" +#include "../gsAssert.h" +#include "../gsDebug.h" + + + +void gsiInitializeCriticalSection(GSICriticalSection *theCrit) { InitializeCriticalSection(theCrit); } +void gsiEnterCriticalSection (GSICriticalSection *theCrit) { EnterCriticalSection(theCrit); } +void gsiLeaveCriticalSection (GSICriticalSection *theCrit) { LeaveCriticalSection(theCrit); } +void gsiDeleteCriticalSection (GSICriticalSection *theCrit) { DeleteCriticalSection(theCrit); } + +gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID) +{ + DWORD result = WaitForSingleObject(theThreadID, 0); + if (result == WAIT_ABANDONED || result == WAIT_OBJECT_0) + return 1; // thread is dead + else + return 0; // keep waiting +} + +GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName) +{ + GSISemaphoreID aSemaphore = CreateSemaphoreA(NULL, theInitialCount, theMaxCount, theName); + if (aSemaphore == NULL) + { + gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Failed to create semaphore\r\n"); + } + return aSemaphore; +} + +// Waits for -- and signals -- the semaphore +gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs) +{ + DWORD result = WaitForSingleObject((HANDLE)theSemaphore, (DWORD)theTimeoutMs); + return (gsi_u32)result; +} + +// Allow other objects to access the semaphore +void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount) +{ + ReleaseSemaphore(theSemaphore, theReleaseCount, NULL); +} + +void gsiCloseSemaphore(GSISemaphoreID theSemaphore) +{ + CloseHandle(theSemaphore); +} + + +int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID * id) +{ + HANDLE handle; + DWORD threadID; + + // create the thread + handle = CreateThread(NULL, theStackSize, func, arg, 0, &threadID); + if(handle == NULL) + return -1; + + // store the id + *id = handle; + + return 0; +} + +void gsiCancelThread(GSIThreadID id) +{ + //there is no way to terminate a thread + //we should move to always signalling threads to close + GSI_UNUSED(id); +} + +void gsiExitThread(GSIThreadID id) +{ + GSI_UNUSED(id); +} + +void gsiCleanupThread(GSIThreadID id) +{ + CloseHandle(id); +} + + diff --git a/xrGameSpy/gamespy/common/xbox/gsSocketXbox.c b/xrGameSpy/gamespy/common/xbox/gsSocketXbox.c new file mode 100644 index 00000000000..41ab79788dc --- /dev/null +++ b/xrGameSpy/gamespy/common/xbox/gsSocketXbox.c @@ -0,0 +1,12 @@ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_XBOX) +char * inet_ntoa(IN_ADDR in_addr) +{ + static char buffer[16]; + sprintf(buffer, "%d.%d.%d.%d", in_addr.S_un.S_un_b.s_b1, in_addr.S_un.S_un_b.s_b2, + in_addr.S_un.S_un_b.s_b3, in_addr.S_un.S_un_b.s_b4); + return buffer; +} +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/darray.c b/xrGameSpy/gamespy/darray.c new file mode 100644 index 00000000000..45669b0555d --- /dev/null +++ b/xrGameSpy/gamespy/darray.c @@ -0,0 +1,381 @@ +/* + * + * File: darray.c + * --------------- + * David Wright + * 10/8/98 + * + * See darray.h for function descriptions + */ +#include +#include +#include "darray.h" + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 202, 260 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + +#ifdef _MFC_MEM_DEBUG +#define _CRTDBG_MAP_ALLOC 1 +#include +#endif + + +#define DEF_GROWBY 8 + +#ifdef _NO_NOPORT_H_ + #define gsimalloc malloc + #define gsifree free + #define gsirealloc realloc + #include "common/gsAssert.h" +#else + #include "nonport.h" //for gsimalloc/realloc/free/GS_ASSERT +#endif + + +// STRUCTURES +struct DArrayImplementation +{ + int count, capacity; + int elemsize; + int growby; + ArrayElementFreeFn elemfreefn; + void *list; //array of elements +}; + +// PROTOTYPES +static void *mylsearch(const void *key, void *base, int count, int size, + ArrayCompareFn comparator); +static void *mybsearch(const void *elem, void *base, int num, int elemsize, + ArrayCompareFn comparator, int *found); +// FUNCTIONS + +/* FreeElement + * Frees the element at position N in the array + */ +static void FreeElement(DArray array, int n) +{ + if (array->elemfreefn != NULL) + array->elemfreefn(ArrayNth(array,n)); +} + +/* ArrayGrow + * Reallocates the array to a new size, incresed by growby + */ +static void ArrayGrow(DArray array) +{ + GS_ASSERT(array->elemsize) // sanity check -mj Oct 31st + array->capacity += array->growby; + array->list = gsirealloc(array->list, (size_t) array->capacity * array->elemsize); + GS_ASSERT(array->list); +} + +/* SetElement + * Sets the element at pos to the contents of elem + */ +static void SetElement(DArray array, const void *elem, int pos) +{ + GS_ASSERT(array) // safety check -mj Oct 31st + GS_ASSERT(elem) + GS_ASSERT(array->elemsize) + + memcpy(ArrayNth(array,pos), elem, (size_t)array->elemsize); +} + +DArray ArrayNew(int elemSize, int numElemsToAllocate, + ArrayElementFreeFn elemFreeFn) +{ + DArray array; + + array = (DArray) gsimalloc(sizeof(struct DArrayImplementation)); + GS_ASSERT(array); + GS_ASSERT(elemSize); + if (numElemsToAllocate == 0) + numElemsToAllocate = DEF_GROWBY; + array->count = 0; + array->capacity = numElemsToAllocate;; + array->elemsize = elemSize; + array->growby = numElemsToAllocate; + array->elemfreefn = elemFreeFn; + if (array->capacity != 0) + { + array->list = gsimalloc((size_t)array->capacity * array->elemsize); + GS_ASSERT(array->list); + } else + array->list = NULL; + + return array; +} + +void ArrayFree(DArray array) +{ + int i; + + GS_ASSERT(array); + for (i = 0; i < array->count; i++) + { + FreeElement(array, i); + } + // mj to do: move these asserts into gsi_free. maybe, depends on whether user overloads them + GS_ASSERT(array->list) + GS_ASSERT(array) + gsifree(array->list); + gsifree(array); +} + +void *ArrayGetDataPtr(DArray array) +{ + GS_ASSERT(array); + return array->list; +} + +void ArraySetDataPtr(DArray array, void *ptr, int count, int capacity) +{ + int i; + + GS_ASSERT(array); + if (array->list != NULL) + { + for (i = 0; i < array->count; i++) + { + FreeElement(array, i); + } + gsifree(array->list); + } + array->list = ptr; + array->count = count; + array->capacity = capacity; + +} + + +int ArrayLength(const DArray array) +{ + GS_ASSERT(array) + return array->count; +} + +void *ArrayNth(DArray array, int n) +{ + // 2004.Nov.16.JED - modified GS_ASSERT to include "if" to add robustness + GS_ASSERT( (n >= 0) && (n < array->count)); + if( ! ((n >= 0) && (n < array->count)) ) + return NULL; + + return (char *)array->list + array->elemsize*n; +} + +/* ArrayAppend + * Just do an Insert at the end of the array + */ +void ArrayAppend(DArray array, const void *newElem) +{ + GS_ASSERT(array); + if(array) + ArrayInsertAt(array, newElem, array->count); +} + +void ArrayInsertAt(DArray array, const void *newElem, int n) +{ + GS_ASSERT (array) + GS_ASSERT ( (n >= 0) && (n <= array->count)); + + if (array->count == array->capacity) + ArrayGrow(array); + array->count++; + if (n < array->count - 1) //if we aren't appending + memmove(ArrayNth(array, n+1), ArrayNth(array,n), + (size_t)(array->count - 1 - n) * array->elemsize); + SetElement(array, newElem, n); +} + +void ArrayInsertSorted(DArray array, const void *newElem, ArrayCompareFn comparator) +{ + int n; + void *res; + int found; + + GS_ASSERT (array) + GS_ASSERT (comparator); + + res=mybsearch(newElem, array->list, array->count, array->elemsize, comparator, &found); + n = (((char *)res - (char *)array->list) / array->elemsize); + ArrayInsertAt(array, newElem, n); +} + + +void ArrayRemoveAt(DArray array, int n) +{ + GS_ASSERT (array) + GS_ASSERT( (n >= 0) && (n < array->count)); + + if (n < array->count - 1) //if not last element + memmove(ArrayNth(array,n),ArrayNth(array,n+1), + (size_t)(array->count - 1 - n) * array->elemsize); + array->count--; +} + +void ArrayDeleteAt(DArray array, int n) +{ + GS_ASSERT (array) + GS_ASSERT ( (n >= 0) && (n < array->count)); + + FreeElement(array,n); + ArrayRemoveAt(array, n); +} + + +void ArrayReplaceAt(DArray array, const void *newElem, int n) +{ + GS_ASSERT (array) + GS_ASSERT ( (n >= 0) && (n < array->count)); + + FreeElement(array, n); + SetElement(array, newElem,n); +} + + +void ArraySort(DArray array, ArrayCompareFn comparator) +{ + GS_ASSERT (array) + qsort(array->list, (size_t)array->count, (size_t)array->elemsize, comparator); +} + +//GS_ASSERT will be raised by ArrayNth if fromindex out of range +int ArraySearch(DArray array, const void *key, ArrayCompareFn comparator, + int fromIndex, int isSorted) +{ + void *res; + int found = 1; + if (!array || array->count == 0) + return NOT_FOUND; + + if (isSorted) + res=mybsearch(key, ArrayNth(array,fromIndex), + array->count - fromIndex, array->elemsize, comparator, &found); + else + res=mylsearch(key, ArrayNth(array, fromIndex), + array->count - fromIndex, array->elemsize, comparator); + if (res != NULL && found) + return (((char *)res - (char *)array->list) / array->elemsize); + else + return NOT_FOUND; +} + + +void ArrayMap(DArray array, ArrayMapFn fn, void *clientData) +{ + int i; + + GS_ASSERT (array) + GS_ASSERT(fn); + + for (i = 0; i < array->count; i++) + fn(ArrayNth(array,i), clientData); + +} + +void ArrayMapBackwards(DArray array, ArrayMapFn fn, void *clientData) +{ + int i; + + GS_ASSERT(fn); + + for (i = (array->count - 1) ; i >= 0 ; i--) + fn(ArrayNth(array,i), clientData); + +} + +void * ArrayMap2(DArray array, ArrayMapFn2 fn, void *clientData) +{ + int i; + void * pcurr; + + GS_ASSERT(fn); + GS_ASSERT(clientData); + + for (i = 0; i < array->count; i++) + { + pcurr = ArrayNth(array,i); + if(!fn(pcurr, clientData)) + return pcurr; + } + + return NULL; +} + +void * ArrayMapBackwards2(DArray array, ArrayMapFn2 fn, void *clientData) +{ + int i; + void * pcurr; + + GS_ASSERT(fn); + GS_ASSERT(clientData); + + for (i = (array->count - 1) ; i >= 0 ; i--) + { + pcurr = ArrayNth(array,i); + if(!fn(pcurr, clientData)) + return pcurr; + } + + return NULL; +} + +void ArrayClear(DArray array) +{ + int i; + + // This could be more optimal! + ////////////////////////////// + for(i = (ArrayLength(array) - 1) ; i >= 0 ; i--) + ArrayDeleteAt(array, i); +} + +/* mylsearch + * Implementation of a standard linear search on an array, since we + * couldn't use lfind + */ +static void *mylsearch(const void *key, void *base, int count, int size, + ArrayCompareFn comparator) +{ + int i; + GS_ASSERT(key); + GS_ASSERT(base); + for (i = 0; i < count; i++) + { + if (comparator(key, (char *)base + size*i) == 0) + return (char *)base + size*i; + } + return NULL; +} + +/* mybsearch + * Implementation of a bsearch, since its not available on all platforms + */ +static void *mybsearch(const void *elem, void *base, int num, int elemsize, ArrayCompareFn comparator, int *found) +{ + int L, H, I, C; + + GS_ASSERT(elem); + GS_ASSERT(base); + GS_ASSERT(found); + + L = 0; + H = num - 1; + *found = 0; + while (L <= H) + { + I = (L + H) >> 1; + C = comparator(((char *)base) + I * elemsize,elem); + if (C == 0) + *found = 1; + if (C < 0) + L = I + 1; + else + { + H = I - 1; + } + } + return ((char *)base) + L * elemsize; +} diff --git a/xrGameSpy/gamespy/darray.h b/xrGameSpy/gamespy/darray.h new file mode 100644 index 00000000000..ad84b13f3bd --- /dev/null +++ b/xrGameSpy/gamespy/darray.h @@ -0,0 +1,317 @@ +#ifndef _DARRAY_H +#define _DARRAY_H + +/* File: darray.h + * -------------- + * Defines the interface for the DynamicArray ADT. + * The DArray allows the client to store any number of elements of any desired + * base type and is appropriate for a wide variety of storage problems. It + * supports efficient element access, and appending/inserting/deleting elements + * as well as optional sorting and searching. In all cases, the DArray imposes + * no upper bound on the number of elements and deals with all its own memory + * management. The client specifies the size (in bytes) of the elements that + * will be stored in the array when it is created. Thereafter the client and + * the DArray can refer to elements via (void*) ptrs. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Type: DArray + * ---------------- + * Defines the DArray type itself. The client can declare variables of type + * DArray, but these variables must be initialized with the result of ArrayNew. + * The DArray is implemented with pointers, so all client copies in variables + * or parameters will be "shallow" -- they will all actually point to the + * same DArray structure. Only calls to ArrayNew create new arrays. + * The struct declaration below is "incomplete"- the implementation + * details are literally not visible in the client .h file. + */ +typedef struct DArrayImplementation *DArray; + + +/* ArrayCompareFn + * -------------- + * ArrayCompareFn is a pointer to a client-supplied function which the + * DArray uses to sort or search the elements. The comparator takes two + * (const void*) pointers (these will point to elements) and returns an int. + * The comparator should indicate the ordering of the two elements + * using the same convention as the strcmp library function: + * If elem1 is "less than" elem2, return a negative number. + * If elem1 is "greater than" elem2, return a positive number. + * If the two elements are "equal", return 0. + */ +#if defined(WIN32) + typedef int (__cdecl *ArrayCompareFn)(const void *elem1, const void *elem2); +#else + typedef int (*ArrayCompareFn)(const void *elem1, const void *elem2); +#endif + + +/* ArrayMapFn + * ---------- + * ArrayMapFn defines the space of functions that can be used to map over + * the elements in a DArray. A map function is called with a pointer to + * the element and a client data pointer passed in from the original + * caller. + */ +typedef void (*ArrayMapFn)(void *elem, void *clientData); + +/* ArrayMapFn2 + * ----------_ + * Same as ArrayMapFn, but can return 0 to stop the mapping. + * Used by ArrayMap2 + */ +typedef int (*ArrayMapFn2)(void *elem, void *clientData); + + /* ArrayElementFreeFn + * ------------------ + * ArrayElementFreeFn defines the space of functions that can be used as the + * clean-up function for an element as it is deleted from the array + * or when the entire array of elements is freed. The cleanup function is + * called with a pointer to an element about to be deleted. + */ +typedef void (*ArrayElementFreeFn)(void *elem); + + +/* ArrayNew + * -------- + * Creates a new DArray and returns it. There are zero elements in the array. + * to start. The elemSize parameter specifies the number of bytes that a single + * element of this array should take up. For example, if you want to store + * elements of type Binky, you would pass sizeof(Binky) as this parameter. + * An assert is raised if the size is not greater than zero. + * + * The numElemsToAllocate parameter specifies the initial allocated length + * of the array, as well as the dynamic reallocation increment for when the + * array grows. Rather than growing the array one element at a time as + * elements are added (which is rather inefficient), you will grow the array + * in chunks of numElemsToAllocate size. The "allocated length" is the number + * of elements that have been allocated, the "logical length" is the number of + * those slots actually being currently used. + * + * A new array is initially allocated to the size of numElemsToAllocate, the + * logical length is zero. As elements are added, those allocated slots fill + * up and when the initial allocation is all used, grow the array by another + * numElemsToAllocate elements. You will continue growing the array in chunks + * like this as needed. Thus the allocated length will always be a multiple + * of numElemsToAllocate. Don't worry about using realloc to shrink the array + * allocation if many elements are deleted from the array. It turns out that + * many implementations of realloc don't even pay attention to such a request + * so there is little point in asking. Just leave the array over-allocated. + * + * The numElemsToAllocate is the client's opportunity to tune the resizing + * behavior for their particular needs. If constructing large arrays, + * specifying a large allocation chunk size will result in fewer resizing + * operations. If using small arrays, a small allocation chunk size will + * result in less space going unused. If the client passes 0 for + * numElemsToAllocate, the implementation will use the default value of 8. + * + * The elemFreeFn is the function that will be called on an element that + * is about to be deleted (using ArrayDeleteAt) or on each element in the + * array when the entire array is being freed (using ArrayFree). This function + * is your chance to do any deallocation/cleanup required for the element + * (such as freeing any pointers contained in the element). The client can pass + * NULL for the cleanupFn if the elements don't require any handling on free. + */ +DArray ArrayNew(int elemSize, int numElemsToAllocate, + ArrayElementFreeFn elemFreeFn); + + + + /* ArrayFree + * ---------- + * Frees up all the memory for the array and elements. It DOES NOT + * automatically free memory owned by pointers embedded in the elements. + * This would require knowledge of the structure of the elements which the + * DArray does not have. However, it will iterate over the elements calling + * the elementFreeFn earlier supplied to ArrayNew and therefore, the client, + * who knows what the elements are, can do the appropriate deallocation of any + * embedded pointers through that function. After calling this, the value of + * what array is pointing to is undefined. + */ +void ArrayFree(DArray array); + + +/* ArrayLength + * ----------- + * Returns the logical length of the array, i.e. the number of elements + * currently in the array. Must run in constant time. + */ +int ArrayLength(const DArray array); + + +/* ArrayNth + * -------- + * Returns a pointer to the element numbered n in the specified array. + * Numbering begins with 0. An assert is raised if n is less than 0 or greater + * than the logical length minus 1. Note this function returns a pointer into + * the DArray's element storage, so the pointer should be used with care. + * This function must operate in constant time. + * + * We could have written the DArray without this sort of access, but it + * is useful and efficient to offer it, although the client needs to be + * careful when using it. In particular, a pointer returned by ArrayNth + * becomes invalid after any calls which involve insertion, deletion or + * sorting the array, as all of these may rearrange the element storage. + */ +void *ArrayNth(DArray array, int n); + + +/* ArrayAppend + * ----------- + * Adds a new element to the end of the specified array. The element is + * passed by address, the element contents are copied from the memory pointed + * to by newElem. Note that right after this call, the new element will be + * the last in the array; i.e. its element number will be the logical length + * minus 1. This function must run in constant time (neglecting + * the memory reallocation time which may be required occasionally). + */ +void ArrayAppend(DArray array, const void *newElem); + +/* ArrayInsertAt + * ------------- + * Inserts a new element into the array, placing it at the position n. + * An assert is raised if n is less than 0 or greater than the logical length. + * The array elements after position n will be shifted over to make room. The + * element is passed by address, the new element's contents are copied from + * the memory pointed to by newElem. This function runs in linear time. + */ +void ArrayInsertAt(DArray array, const void *newElem, int n); + +/* ArrayInsertSorted + * ------------- + * Inserts a new element into the array, placing it at the position indicated by + * a binary search of the array using comparator. + * The array MUST be sorted prior to calling InsertSorted. + * Note that if you only ever call InsertSorted, the array will always be sorted. + */ +void ArrayInsertSorted(DArray array, const void *newElem, ArrayCompareFn comparator); + + /* ArrayDeleteAt + * ------------- + * Deletes the element numbered n from the array. Before being removed, + * the elemFreeFn that was supplied to ArrayNew will be called on the element. + * An assert is raised if n is less than 0 or greater than the logical length + * minus one. All the elements after position n will be shifted over to fill + * the gap. This function runs in linear time. It does not shrink the + * allocated size of the array when an element is deleted, the array just + * stays over-allocated. + */ +void ArrayDeleteAt(DArray array, int n); + + /* ArrayDeleteAt + * ------------- + * Removes the element numbered n from the array. The element will not be freed + * before being removed. All the elements after position n will be shifted over to fill + * the gap. This function runs in linear time. It does not shrink the + * allocated size of the array when an element is deleted, the array just + * stays over-allocated. + */ +void ArrayRemoveAt(DArray array, int n); + +/* ArrayReplaceAt + * ------------- + * Overwrites the element numbered n from the array with a new value. Before + * being overwritten, the elemFreeFn that was supplied to ArrayNew is called + * on the old element. Then that position in the array will get a new value by + * copying the new element's contents from the memory pointed to by newElem. + * An assert is raised if n is less than 0 or greater than the logical length + * minus one. None of the other elements are affected or rearranged by this + * operation and the size of the array remains constant. This function must + * operate in constant time. + */ +void ArrayReplaceAt(DArray array, const void *newElem, int n); + + +/* ArraySort + * --------- + * Sorts the specified array into ascending order according to the supplied + * comparator. The numbering of the elements will change to reflect the + * new ordering. An assert is raised if the comparator is NULL. + */ +void ArraySort(DArray array, ArrayCompareFn comparator); + + +#define NOT_FOUND -1 // returned when a search fails to find the key + +/* ArraySearch + * ----------- + * Searches the specified array for an element whose contents match + * the element passed as the key. Uses the comparator argument to test + * for equality. The "fromIndex" parameter controls where the search + * starts looking from. If the client desires to search the entire array, + * they should pass 0 as the fromIndex. The function will search from + * there to the end of the array. The "isSorted" parameter allows the client + * to specify that the array is already in sorted order, and thus it uses a + * faster binary search. If isSorted is false, a simple linear search is + * used. If a match is found, the position of the matching element is returned + * else the function returns NOT_FOUND. Calling this function does not + * re-arrange or change contents of DArray or modify the key in any way. + * An assert is raised if fromIndex is less than 0 or greater than + * the logical length (although searching from logical length will never + * find anything, allowing this case means you can search an entirely empty + * array from 0 without getting an assert). An assert is raised if the + * comparator is NULL. + */ +int ArraySearch(DArray array, const void *key, ArrayCompareFn comparator, + int fromIndex, int isSorted); + + +/* ArrayMap + * ----------- + * Iterates through each element in the array in order (from element 0 to + * element n-1) and calls the function fn for that element. The function is + * called with the address of the array element and the clientData pointer. + * The clientData value allows the client to pass extra state information to + * the client-supplied function, if necessary. If no client data is required, + * this argument should be NULL. An assert is raised if map function is NULL. + */ +void ArrayMap(DArray array, ArrayMapFn fn, void *clientData); + +/* ArrayMapBackwards + * ----------- + * Same as ArrayMap, but goes through the array from end to front. This + * makes it safe to free elements during the mapping. + */ +void ArrayMapBackwards(DArray array, ArrayMapFn fn, void *clientData); + +/* ArrayMap2 + * ----------- + * Same as ArrayMap, but allows the mapping to be stopped by returning 0 + * from the mapping function. If the mapping was stopped, the element + * it was stopped at will be returned. If it wasn't stopped, then NULL + * will be returned. + */ +void * ArrayMap2(DArray array, ArrayMapFn2 fn, void *clientData); + +/* ArrayMapBackwards2 + * ------------ + * Goes through the array backwards, and allows you to stop the mapping. + */ +void * ArrayMapBackwards2(DArray array, ArrayMapFn2 fn, void *clientData); + +/* ArrayClear + * ----------- + * Deletes all elements in the array, but without freeing the array. + */ +void ArrayClear(DArray array); + +/* ArrayGetDataPtr + * ----------- + * Obtain the pointer to the actual data storage + */ +void *ArrayGetDataPtr(DArray array); + +/* ArraySetDataPtr + * ----------- + * Set the pointer to the actual data storage, which must be allocated with malloc + */ +void ArraySetDataPtr(DArray array, void *ptr, int count, int capacity); + +#ifdef __cplusplus +} +#endif + +#endif //_DARRAY_ diff --git a/xrGameSpy/gamespy/gcdkey/CdkeyGen/CdkeyGen.dsp b/xrGameSpy/gamespy/gcdkey/CdkeyGen/CdkeyGen.dsp new file mode 100644 index 00000000000..b554f08218d --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/CdkeyGen/CdkeyGen.dsp @@ -0,0 +1,96 @@ +# Microsoft Developer Studio Project File - Name="CdkeyGen" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=CdkeyGen - 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 "CdkeyGen.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 "CdkeyGen.mak" CFG="CdkeyGen - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CdkeyGen - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "CdkeyGen - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/gcdkey/CdkeyGen" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "CdkeyGen - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 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:console /machine:I386 +# ADD LINK32 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:console /machine:I386 + +!ELSEIF "$(CFG)" == "CdkeyGen - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "CdkeyGen - Win32 Release" +# Name "CdkeyGen - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gcdkeygen.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gcdkey/CdkeyGen/CdkeyGen_vs2005.vcproj b/xrGameSpy/gamespy/gcdkey/CdkeyGen/CdkeyGen_vs2005.vcproj new file mode 100644 index 00000000000..3e1fcbb529d --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/CdkeyGen/CdkeyGen_vs2005.vcproj @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gcdkey/CdkeyGen/gcdkeygen.c b/xrGameSpy/gamespy/gcdkey/CdkeyGen/gcdkeygen.c new file mode 100644 index 00000000000..22f72afe506 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/CdkeyGen/gcdkeygen.c @@ -0,0 +1,227 @@ +/****** +gcdkeygen.c +GameSpy CDKey SDK CD Key Generation / Validation Example + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + This source is simply an example of how you might generate + CD Keys and how you would validate them on the client side. + + You can use this algorithm, or a derivation thereof, or your own, + but always make sure that: + 1. Your valid keys are a SMALL subset of the possible keys + 2. The distribution of valid keys within the full set is even, but + not regular. + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + +#include +#include +#include +#include +#include + +static void Util_RandSeed(unsigned long seed); +static int Util_RandInt(int low, int high); + + +#define MINKEYSEED 0x0000100000 +#define MAXKEYSEED 0xFFFFFFFFFF +/* +The CD Key is in the form: +RSSS-SSSS-SSSR-CCCC +Where +R = random chars +S = bytes of the seed (two S's per byte) +C = bytes of the check (two C's per byte) + +The seed of the keys is a 40 bit number. If you generate 1 million +keys, then the chances of guessing a valid key (even knowing the algorithm) +is about 1 in 1.09 million. +You can easily take this number into the trillions by using the full 64 bits +(of course it makes your CD Key longer, unless you use base 26 numbers) + +In addition to the seed, we use a 16 bit check value. The chances of guessing +a mathematically correct key, without knowing the algorithm, is 1 in 65 thousand. +You could make that 1 in 4 billion by using a 32 bit check value. However, even +if a key is mathematically correct, it is not necessarily valid. + +It is important that the key generation algorithm actually pick out random +valid keys out of the entire range of keys. If it picks according to a non-random +algorithm (for example, every 1000000'th seed) then you can figure out all +the valid CD Keys from 1 valid one. + +The generate keys function is designed to generate all the keys you will +ever need in 1 shot, if you use it twice you may end up with key collisions +(although the probability is VERY low). You can change this by using different +min/max key seeds each time you run it. +*/ +void DoGenerateKeys() +{ + char resp[128] = ""; + char key[128]; + char hexstr[20]; + int keyct; + unsigned int interval; + __int64 offset; + __int64 base = MINKEYSEED; + __int64 seed; + short check; + FILE *f; + + Util_RandSeed(time(NULL) ^ GetTickCount()); + printf("How many keys would you like? "); + gets(resp); + + keyct = atoi(resp); + + offset = (MAXKEYSEED - MINKEYSEED) / keyct; + if (offset > 0xFFFFFFFF) //too big for a uint.. too few keys really + interval = 0xFFFFFFFF; + else + interval = (unsigned int)offset; + + + f = fopen("keys.txt","w"); + if (!f) + return; + while (keyct != 0) + { + seed = base + Util_RandInt(0,interval); //pick a number between this base and the next + base += offset; //move up the base + //note: a 1 way xform on seed at this point would increase security + //print a 40 bit hex number to the string + sprintf(hexstr,"%.10I64x",seed); + + check = ((short)(seed % 65535)) ^ 0x9249; //these are "secret" check calculation values + + sprintf(&key[11],"%.8x",check); //add the check as the last 4 chars (but it prints 8 chars) + key[0] = '0' + (char)(Util_RandInt(0,9)); //first character is random + strncpy(&key[1],hexstr,3); //add first 3 chars of seed + key[4] = '-'; + strncpy(&key[5],&hexstr[3],4); //next 4 chars of seed + key[9] = '-'; + strncpy(&key[10],&hexstr[7],3); //last 3 chars of seed + key[13] = '0' + (char)(Util_RandInt(0,9)); //this character is random + key[14] = '-'; + + fprintf(f,"%s\n",key); //print it to the key file + keyct--; + } + fclose(f); + printf("Keys output to keys.txt\n"); +} + +int ValidateKey(char *key) +{ + __int64 seed; + char hexstr[20] = "0x"; + int check; + short realcheck; + + //extract the seed value + strncpy(hexstr + 2,key + 1,3); + strncpy(hexstr + 5, key + 5, 4); + strncpy(hexstr + 9, key + 10, 3); + hexstr[12] = 0; + sscanf(hexstr,"%I64x",&seed); + + //extract the check value + strncpy(hexstr + 2, key + 15, 4); + hexstr[6] = 0; + sscanf(hexstr, "%x",&check); + + //calc the real check value + realcheck = ((short)(seed % 65535)) ^ 0x9249; + return ((short)check == realcheck); +} + +void DoValidateKeys() +{ + char resp[128] = ""; + + do + { + printf("Enter a CD Key to validate, or [ENTER] to quit: "); + gets(resp); + if (!resp[0]) + return; + if (ValidateKey(resp)) + printf("Key Validated\n"); + else + printf("Invalid Key\n"); + + } while (1); + + +} + +int main(int argc, char **argv) +{ + char resp[10]; + //display a menu + printf("What would you like to do?\n\t1. Generate CD Keys\n\t2. Validate a CD Key\n:"); + gets(resp); + if (resp[0] == '1') + DoGenerateKeys(); + else + DoValidateKeys(); +} + +/*********** +Random Number Generation Code +***********/ +#define RANa 16807 /* multiplier */ +#define LONGRAND_MAX 2147483647L /* 2**31 - 1 */ + +static long randomnum = 1; + +/************** +** FUNCTIONS ** +**************/ +static long nextlongrand(long seed) +{ + unsigned long lo, hi; + + lo = RANa * (long)(seed & 0xFFFF); + hi = RANa * (long)((unsigned long)seed >> 16); + lo += (hi & 0x7FFF) << 16; + if (lo > LONGRAND_MAX) + { + lo &= LONGRAND_MAX; + ++lo; + } + lo += hi >> 15; + if (lo > LONGRAND_MAX) + { + lo &= LONGRAND_MAX; + ++lo; + } + return (long)lo; +} + +static long longrand(void) /* return next random long */ +{ + randomnum = nextlongrand(randomnum); + return randomnum; +} + +static void Util_RandSeed(unsigned long seed) /* to seed it */ +{ + randomnum = seed ? (seed & LONGRAND_MAX) : 1; /* nonzero seed */ +} + +static int Util_RandInt(int low, int high) +{ + int range = high-low; + int num = longrand() % range; + + return(num + low); +} diff --git a/xrGameSpy/gamespy/gcdkey/ClientTest/ClientTest.dsp b/xrGameSpy/gamespy/gcdkey/ClientTest/ClientTest.dsp new file mode 100644 index 00000000000..1d59a930f98 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ClientTest/ClientTest.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="ClientTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ClientTest - 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 "ClientTest.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 "ClientTest.mak" CFG="ClientTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ClientTest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ClientTest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/gcdkey/ClientTest" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ClientTest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I "../" /I "../../" /I "../../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 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:console /machine:I386 +# ADD LINK32 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:console /machine:I386 + +!ELSEIF "$(CFG)" == "ClientTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ClientTest___Win32_Debug" +# PROP BASE Intermediate_Dir "ClientTest___Win32_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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "../" /I "../../" /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# 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 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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ClientTest - Win32 Release" +# Name "ClientTest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gcdkeyclienttest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "CdkeySDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\gcdkeyc.c +# End Source File +# Begin Source File + +SOURCE=..\gcdkeyc.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gcdkey/ClientTest/ClientTest_vs2005.vcproj b/xrGameSpy/gamespy/gcdkey/ClientTest/ClientTest_vs2005.vcproj new file mode 100644 index 00000000000..fcf8ffa1d71 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ClientTest/ClientTest_vs2005.vcproj @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gcdkey/ClientTest/gcdkeyclienttest.c b/xrGameSpy/gamespy/gcdkey/ClientTest/gcdkeyclienttest.c new file mode 100644 index 00000000000..fc8be5c9407 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ClientTest/gcdkeyclienttest.c @@ -0,0 +1,135 @@ +/****** +gcdkeyclienttest.c +GameSpy CDKey SDK Client Sample + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + +#include "../common/gsCommon.h" +#include "gcdkeyc.h" + +#define DEFAULT_SERVER "127.0.0.1" // Run gcdkeyserver app on local host +#define DEFAULT_PORT 2000 +#define DEFAULT_KEY "8014-c119-a892-74d2" + +#define BUFSIZE 256 + +#define readstring(buffer) { fgets(buffer, sizeof(buffer), stdin); buffer[strlen(buffer) - 1] ='\0'; } + +int test_main(int argc, char **argv) +{ + char data[256]; + int len; + char cdkey[64]; + char server[64]; + char port[64]; + char response[RESPONSE_SIZE]; + SOCKET s; + struct sockaddr_in saddr; + + while(1) + { + //get the server IP and a CD Key + printf("Server to connect to [%s]: ",DEFAULT_SERVER); + readstring(server); + if (server[0]==0 || server[0]=='\n') + strcpy(server,DEFAULT_SERVER); + printf("Port to connect to [%d]: ",DEFAULT_PORT); + readstring(port); + if (port[0]=='\0' || port[0]=='\n') + sprintf(port,"%d", DEFAULT_PORT); + printf("Enter your CD Key [%s]: ", DEFAULT_KEY); + readstring(cdkey); + if (cdkey[0]==0 || cdkey[0]=='\n') + strcpy(cdkey,DEFAULT_KEY); + + /* normally we would verify the CD Key (mathematically) at this point, + if (!ValidateKey(cdkey)) + return; + */ + + /* create a TCP socket to connect to the server, obviously you would + connect with whatever protocol your game uses (TCP/UDP/DPlay/etc) */ + SocketStartUp(); + s = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = inet_addr(server); + saddr.sin_port = htons((unsigned short)atoi(port)); + if (gsiSocketIsError(connect(s,(struct sockaddr *)&saddr,sizeof(saddr)))) + { + printf("Error connecting to server\n"); + getchar(); + continue; + } + + /* Once we are connected, there is a "handshake" where the server sends + a "challenge" in the form "c:challenge", and we send a response in the + for "r:response". How you do this is again, completely up to you */ + len = recv(s,data,BUFSIZE-1,0); + if (len <= 0) + { + printf("Error connecting to server\n"); + getchar(); + continue; + } + data[len] = 0; + + // compute the response based on the challenge (which starts at data[2]) + gcd_compute_response(cdkey, data+2, response, CDResponseMethod_NEWAUTH); + + // send the response back to the server + printf("Got: %s\nSending: %s\n",data, response); + sprintf(data,"r:%s",response); + send(s,data,strlen(data),0); + + // enter our main loop and wait for data + while (1) + { + len = recv(s,data,BUFSIZE-1,0); + if (len <= 0) + { + printf("Server Disconnected\n"); + getchar(); + //goto start; + break; + } + data[len] = 0; + + // Keep a watch for reauthentication requests + // In this case, the sample server sends "r:" + // and the client sample responds with "p:" + // Your game should use it's own message types and headers. + if (data[0] == 'r' && data[1] == ':') + { + char hint[9]; + memcpy(hint, data+2, 8); // 8 characters are a hint + hint[8] = '\0'; + + printf("Got reauth: %s, %s\n",hint, data+10); + + gcd_compute_response(cdkey, data+10, response, CDResponseMethod_REAUTH); + sprintf(data, "p:%s%s", hint, response); + send(s,data,strlen(data),0); + printf("Sending: %s\n", response); + } + else + printf("Got: %s\n", data); + } + } +// goto start; + + SocketShutDown(); + return 0; + + GSI_UNUSED(argv); + GSI_UNUSED(argc); +} diff --git a/xrGameSpy/gamespy/gcdkey/ServerTest/ServerTest.dsp b/xrGameSpy/gamespy/gcdkey/ServerTest/ServerTest.dsp new file mode 100644 index 00000000000..197e4932f9e --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ServerTest/ServerTest.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="ServerTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ServerTest - 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 "ServerTest.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 "ServerTest.mak" CFG="ServerTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ServerTest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ServerTest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/gcdkey/ServerTest" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ServerTest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I "../" /I "../../" /I "../../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 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:console /machine:I386 +# ADD LINK32 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:console /machine:I386 + +!ELSEIF "$(CFG)" == "ServerTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ServerTest___Win32_Debug" +# PROP BASE Intermediate_Dir "ServerTest___Win32_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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "../" /I "../../" /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# 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 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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ServerTest - Win32 Release" +# Name "ServerTest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gcdkeyservertest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "CdkeySDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\gcdkeys.c +# End Source File +# Begin Source File + +SOURCE=..\gcdkeys.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gcdkey/ServerTest/ServerTest_vs2005.vcproj b/xrGameSpy/gamespy/gcdkey/ServerTest/ServerTest_vs2005.vcproj new file mode 100644 index 00000000000..716666097c0 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ServerTest/ServerTest_vs2005.vcproj @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gcdkey/ServerTest/gcdkeyservertest.c b/xrGameSpy/gamespy/gcdkey/ServerTest/gcdkeyservertest.c new file mode 100644 index 00000000000..718967b4b60 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ServerTest/gcdkeyservertest.c @@ -0,0 +1,251 @@ +/****** +gcdkeyservertest.c +GameSpy CDKey SDK Server Sample + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + + +#include "gcdkeys.h" +#include "../common/gsCommon.h" +#include "../common/gsAvailable.h" +#ifdef _WIN32 + #include +#endif + + +#define MAXCLIENTS 64 +#define MY_GAMEID 0 // This is assigned by GameSpy +#define MY_GAMENAME "gmtest" +#define PORT 2000 + +// a structure for storing client information.. you will probably have most/all +// of these things in your client structure / object +typedef struct +{ + SOCKET sock; + char challenge[32]; + struct sockaddr_in saddr; + int auth; +} client_t; + +//generate a rand nchar challenge +static char *randomchallenge(int nchars) +{ + static char s[33]; + if (nchars > 32) nchars = 32; + s[nchars] = 0; + while (nchars--) + { + s[nchars] = 'a' + (char)(rand() % 26); + } + return s; +} + +/* Callback function to indicate whether a client has been authorized or not. +If the client has been, then we send them a "welcome" string, representative of +allowing them to "enter" the game. If they have not been authenticated, we dump +them after sending an error message */ +static void ClientAuthorize(int gameid, int localid, int authenticated, char *errmsg, void *instance) +{ + client_t *clients = (client_t *)instance; + char outbuf[512]; + + if (!authenticated) //doh.. bad! + { + printf("Client %d was NOT authenticated (%s)\n",localid, errmsg); + sprintf(outbuf,"E:%s\n",errmsg); + send(clients[localid].sock, outbuf, strlen(outbuf),0); + shutdown(clients[localid].sock, 2); + closesocket(clients[localid].sock); + clients[localid].sock = INVALID_SOCKET; + } else + { + printf("Client %d was authenticated (%s)\n",localid, errmsg); + sprintf(outbuf,"M:Welcome to the game, have fun! (%s)\n",errmsg); + send(clients[localid].sock, outbuf, strlen(outbuf),0); + } + + GSI_UNUSED(gameid); +} + +/* Callback function to reauthorize players. */ +static void ClientRefreshAuthorize(int gameid, int localid, int hint, char *challenge, void *instance) +{ + client_t *clients = (client_t *)instance; + char outbuf[512]; + + // Some one else is trying to login using this key, so we're asking the client to re-validate + // The hint is sent along as a pass through value. The client will include it with the response. + // It is passed as the first 8 characters along with the challenge to the client. + sprintf(outbuf, "r:%08d%s", hint, challenge); + send(clients[localid].sock, outbuf, strlen(outbuf),0); + + GSI_UNUSED(gameid); +} + + +/* Primary "game" logic. Basically: +1. Set up a "server" listen socket +2. Initialize the client structures +3. Enter a main loop + a. Let the gcd code think / do callbacks + b. Check for a new connection on the server socket and create a new client + c. Check for data on the client sockets + d. Check for disconnects on the client sockets +4. Disconnect remaining players and exit +*/ +int test_main(int argc, char **argv) +{ + + client_t clients[MAXCLIENTS]; + SOCKET ssock; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + fd_set set; + struct timeval timeout = {0,0}; + int error; + int i,len; + int quit = 0; + char buf[512]; + unsigned short port; + GSIACResult result; + + // check that the game's backend is available + GSIStartAvailableCheck(MY_GAMENAME); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + printf("The backend is not available\n"); + return 1; + } + + /* Initialize the gcd system with the + gameid you have been assigned */ + if(gcd_init(MY_GAMEID) != 0) + { + printf("Error initializing\n"); + return 1; + } + + SocketStartUp(); + ssock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + + i = 0; // initialize here just to prevent compiler error + for(port = PORT ; port < (PORT + 100) ; port++) + { + saddr.sin_port = htons(port); + i = bind(ssock, (struct sockaddr *)&saddr, sizeof(saddr)); + if(gsiSocketIsNotError(i)) + break; + } + if (gsiSocketIsError(i)) + { + printf("Unable to bind to any of the ports %d through %d (%d)\n",PORT, port - 1, GOAGetLastError(ssock)); + return 1; + } + listen(ssock, SOMAXCONN); + + for (i = 0 ; i < MAXCLIENTS ; i++) + clients[i].sock = INVALID_SOCKET; + + printf("Running on port %d... press any key to quit\n", port); + while (!quit) + { //main loop + msleep(10); + gcd_think(); + + + #ifdef _WIN32 + quit = _kbhit(); + #else + //on other systems, you gotta kill it hard + #endif + + FD_ZERO ( &set ); + FD_SET ( ssock, &set ); + for (i = 0 ; i < MAXCLIENTS ; i++) + if (clients[i].sock != INVALID_SOCKET) + FD_SET(clients[i].sock , &set); + error = select(FD_SETSIZE, &set, NULL, NULL, &timeout); + if (/*gsiSocketIsError(ret) ||*/ 0 == error) + continue; + + //new connection + if (FD_ISSET(ssock, &set)) + { + for (i = 0 ; i < MAXCLIENTS ; i++) + if (clients[i].sock == INVALID_SOCKET) + { + clients[i].sock = accept(ssock, (struct sockaddr *)&(clients[i].saddr), &saddrlen); + listen(ssock,SOMAXCONN); + strcpy(clients[i].challenge,randomchallenge(8)); + len = sprintf(buf,"c:%s",clients[i].challenge); + send(clients[i].sock ,buf, len,0); //send a challenge + clients[i].auth = 0; + printf("Client %d connected\n",i); + break; + } + } + + //client data + for (i = 0 ; i < MAXCLIENTS ; i++) + if (clients[i].sock != INVALID_SOCKET && FD_ISSET(clients[i].sock, &set)) + { + len = recv(clients[i].sock,buf, 512, 0); + if (len <= 0) //the client disconnected + { + printf("Client %d disconnected\n",i); + closesocket(clients[i].sock); + clients[i].sock = INVALID_SOCKET; + if (clients[i].auth) //if they were authorized + gcd_disconnect_user(MY_GAMEID, i); + continue; + } + buf[len] = 0; + if (buf[0] == 'r' && buf[1] == ':' && clients[i].auth == 0) //challenge response + { + printf("Client %d said %s\n",i,buf); + clients[i].auth = 1; + gcd_authenticate_user(MY_GAMEID, i,clients[i].saddr.sin_addr.s_addr, + clients[i].challenge, buf+2, ClientAuthorize, ClientRefreshAuthorize, clients); + } + else if (buf[0] == 'p' && buf[1] == ':' && clients[i].auth == 1) // ison proof response + { + //gcd_send_reauth_response needs to know the sesskey (so keymaster can find the task) + // and fromaddr (so gcdkey knows which keymaster to respond to) + if (len > 11) + { + char hintstr[9]; + int hint = 0; + + memcpy(hintstr, buf+2, 8); // first 8 characters are the hint + hintstr[8] = '\0'; + hint = atoi(hintstr); + + printf("Client %d prooved %d, %s\n",i,hint,buf+10); + gcd_process_reauth(MY_GAMEID, i, hint, buf+10); + } + } + } + } + gcd_disconnect_all(MY_GAMEID); + gcd_shutdown(); + SocketShutDown(); + printf("All done!\n"); + return 0; + + GSI_UNUSED(argv); + GSI_UNUSED(argc); +} diff --git a/xrGameSpy/gamespy/gcdkey/ServerTestQR2/ServerTestQR2.dsp b/xrGameSpy/gamespy/gcdkey/ServerTestQR2/ServerTestQR2.dsp new file mode 100644 index 00000000000..feff5023485 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ServerTestQR2/ServerTestQR2.dsp @@ -0,0 +1,260 @@ +# Microsoft Developer Studio Project File - Name="ServerTestQR2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ServerTestQR2 - 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 "ServerTestQR2.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 "ServerTestQR2.mak" CFG="ServerTestQR2 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ServerTestQR2 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ServerTestQR2 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/gcdkey/ServerTestQR2" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ServerTestQR2 - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I "../" /I "../../" /I "../../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "QR2CDKEY_INTEGRATION" /FD /c +# SUBTRACT CPP /YX +# 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 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:console /machine:I386 +# ADD LINK32 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:console /machine:I386 + +!ELSEIF "$(CFG)" == "ServerTestQR2 - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "../" /I "../../" /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "QR2CDKEY_INTEGRATION" /D "GSI_COMMON_DEBUG" /FD /GZ /c +# SUBTRACT CPP /YX +# 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 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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ServerTestQR2 - Win32 Release" +# Name "ServerTestQR2 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gcdkeyservertest_qr2.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "CdkeySDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\gcdkeyc.c +# End Source File +# Begin Source File + +SOURCE=..\gcdkeyc.h +# End Source File +# Begin Source File + +SOURCE=..\gcdkeys.c +# End Source File +# Begin Source File + +SOURCE=..\gcdkeys.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\qr2\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gcdkey/ServerTestQR2/ServerTestQR2_vs2005.vcproj b/xrGameSpy/gamespy/gcdkey/ServerTestQR2/ServerTestQR2_vs2005.vcproj new file mode 100644 index 00000000000..eaf6f40c69e --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ServerTestQR2/ServerTestQR2_vs2005.vcproj @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gcdkey/ServerTestQR2/gcdkeyservertest_qr2.c b/xrGameSpy/gamespy/gcdkey/ServerTestQR2/gcdkeyservertest_qr2.c new file mode 100644 index 00000000000..39b8e33b034 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/ServerTestQR2/gcdkeyservertest_qr2.c @@ -0,0 +1,392 @@ +/****** +gcdkeyservertest_qr2.c +GameSpy CDKey SDK Server Sample - with Query & Reporting 2 SDK Integration + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + This sample is similar to the gcdkeyservertest sample, except that it also + demonstrates support for Query & Reporting 2 SDK integration, as detailed in the documentation. + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ +#include "gcdkeys.h" +#include "gcdkeyc.h" +#include "../common/gsAvailable.h" +#ifdef _WIN32 +#include +#endif + + +#define GAME_NAME "gmtest" +#define GAMEID 0 + +#define DEFAULT_KEY "2dd4-893a-ce85-6411" //used to have Host register himself +#define HOST_ID 100 //set to 100 so that client id's don't overlap +#define DEFAULT_PORT 5000 + +void serverkey_callback(int keyid, qr2_buffer_t outbuf, void *userdata) +{ + switch (keyid) + { + case HOSTNAME_KEY: + qr2_buffer_add(outbuf, "Gamespy CDKEY TestServer"); + break; + case GAMEVER_KEY: + qr2_buffer_add_int(outbuf, 10); + break; + default: + qr2_buffer_add(outbuf, ""); + } + + GSI_UNUSED(userdata); +} + +void playerkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + switch (keyid) + { + default: + qr2_buffer_add(outbuf, ""); + break; + } + + GSI_UNUSED(userdata); + GSI_UNUSED(index); +} + +void teamkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + switch (keyid) + { + default: + qr2_buffer_add(outbuf, ""); + break; + } + + GSI_UNUSED(userdata); + GSI_UNUSED(index); +} + +void keylist_callback(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata) +{ + switch (keytype) + { + case key_server: + qr2_keybuffer_add(keybuffer, HOSTNAME_KEY); + qr2_keybuffer_add(keybuffer, GAMEVER_KEY); + break; + case key_player: + break; + case key_team: + break; + } + + GSI_UNUSED(userdata); +} + +int count_callback(qr2_key_type keytype, void *userdata) +{ + if (keytype == key_player) + return 0; + else if (keytype == key_team) + return 0; + else + return 0; + + GSI_UNUSED(userdata); +} + +void adderror_callback(qr2_error_t error, char *errmsg, void *userdata) +{ + printf("Error adding server: %d, %s\n", error, errmsg); + + GSI_UNUSED(userdata); +} + +#define MAXCLIENTS 64 + +// a structure for storing client information.. you will probably have most/all +// of these things in your client structure / object +typedef struct +{ + SOCKET sock; + char challenge[32]; + struct sockaddr_in saddr; + int auth; +} client_t; + +//generate a rand nchar challenge +static char *randomchallenge(int nchars) +{ + static char s[33]; + if (nchars > 32) nchars = 32; + s[nchars] = 0; + while (nchars--) + { + s[nchars] = 'a' + (char)(rand() % 26); + } + return s; +} + +/* Callback function to indicate whether a client has been authorized or not. +If the client has been, then we send them a "welcome" string, representative of +allowing them to "enter" the game. If they have not been authenticated, we dump +them after sending an error message */ +static void ClientAuthorize(int gameid, int localid, int authenticated, char *errmsg, void *instance) +{ + client_t *clients = (client_t *)instance; + char outbuf[512]; + + if (!authenticated) //doh.. bad! + { + sprintf(outbuf,"E:%s\n",errmsg); + send(clients[localid].sock, outbuf, strlen(outbuf),0); + shutdown(clients[localid].sock, 2); + closesocket(clients[localid].sock); + clients[localid].sock = INVALID_SOCKET; + } else + { + sprintf(outbuf,"M:Welcome to the game, have fun! (%s)\n",errmsg); + send(clients[localid].sock, outbuf, strlen(outbuf),0); + } + + GSI_UNUSED(gameid); +} + +/* Callback function to reauthorize players. */ +static void ClientRefreshAuthorize(int gameid, int localid, int hint, char *challenge, void *instance) +{ + client_t *clients = (client_t *)instance; + char outbuf[512]; + + // Some one else is trying to login using this key, so we're asking the client to re-validate + // The hint is sent along as a pass through value. The client will include it with the response. + sprintf(outbuf, "r:%08d%s", hint, challenge); + send(clients[localid].sock, outbuf, strlen(outbuf),0); + + GSI_UNUSED(gameid); +} + +// host SELF authorization +static void HostAuthorize(int gameid, int localid, int authenticated, char *errmsg, void *instance) +{ + if (!authenticated) //doh.. bad! + printf("HOST was NOT authenticated (%s)\n",errmsg); + else + printf("HOST was authenticated (%s)\n",errmsg); + + GSI_UNUSED(instance); + GSI_UNUSED(localid); + GSI_UNUSED(gameid); +} + +// host SELF reauthorization +static void HostRefreshAuthorize(int gameid, int localid, int hint, char *challenge, void *instance) +{ + char response[73]; + printf("REAUTHENTICATING host\n"); + gcd_compute_response(DEFAULT_KEY, challenge, response, CDResponseMethod_REAUTH); + gcd_process_reauth(GAMEID, HOST_ID, hint, response); + + GSI_UNUSED(instance); + GSI_UNUSED(localid); + GSI_UNUSED(gameid); +} + +void PublicAddressCallback(unsigned int ip, unsigned short port, void * userdata) +{ + //self validation using the public IP + char response[73]; + char challenge[32]; + + strcpy(challenge, randomchallenge(8)); + printf("authenticating host\n"); + gcd_compute_response(DEFAULT_KEY, challenge, response, CDResponseMethod_NEWAUTH); + gcd_authenticate_user(GAMEID, HOST_ID , ip, challenge, response, HostAuthorize, HostRefreshAuthorize, NULL); + + GSI_UNUSED(userdata); + GSI_UNUSED(port); +} + + +/* Primary "game" logic. Basically: +1. Set up a "server" listen socket +2. Initialize the client structures +3. Enter a main loop +a. Let the gcd code think / do callbacks +b. Check for a new connection on the server socket and create a new client +c. Check for data on the client sockets +d. Check for disconnects on the client sockets +4. Disconnect remaining players and exit +*/ +int test_main(int argc, char **argv) +{ + + client_t clients[MAXCLIENTS]; + SOCKET ssock; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + fd_set set; + struct timeval timeout = {0,0}; + int error; + int i,len; + int quit = 0; + char buf[512]; + char secret_key[9]; + GSIACResult result; + + // check that the game's backend is available + GSIStartAvailableCheck(GAME_NAME); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + printf("The backend is not available\n"); + return 1; + } + + /** + First we set up the Query & Reporting SDK - this is mostly taken from the "qrcsample" sample + **/ + //set the secret key, in a semi-obfuscated manner + secret_key[0] = 'H'; + secret_key[1] = 'A'; + secret_key[2] = '6'; + secret_key[3] = 'z'; + secret_key[4] = 'k'; + secret_key[5] = 'S'; + secret_key[6] = '\0'; + + //call qr2_init with the query port number and gamename, default IP address, and no user data + if(qr2_init(NULL,NULL, 26900,GAME_NAME, secret_key, 1, 1, serverkey_callback, playerkey_callback, + teamkey_callback, keylist_callback, count_callback, adderror_callback, NULL) != 0) + { + printf("Error starting query sockets\n"); + return -1; + } + + //register for public address to do Host self validation in the callback + qr2_register_publicaddress_callback(NULL, PublicAddressCallback); + + + /* Once the QR SDK is initialized, you can initialize the CDKey SDK with the special QR + integration function. Pass in the GAMEID you were assigned. */ + gcd_init_qr2(NULL, GAMEID); + + SocketStartUp(); + ssock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_port = htons(DEFAULT_PORT); //listen on port 5000 by default + saddr.sin_family = AF_INET; + + i = bind(ssock, (struct sockaddr *)&saddr, sizeof(saddr)); + if (gsiSocketIsError(i)) + { + printf("Unable to bind to port %d (%d)\n",DEFAULT_PORT,GOAGetLastError(ssock)); + return 1; + } + listen(ssock, SOMAXCONN); + + for (i = 0 ; i < MAXCLIENTS ; i++) + clients[i].sock = INVALID_SOCKET; + + printf("Running server on port %d... press any key to quit\n", DEFAULT_PORT); + while (!quit) + { //main loop + msleep(10); + /* We process both QR Queries and any CDKey related activity. The QR SDK + automatically passes any network traffic for the CDKey SDK to the SDK directly */ + qr2_think(NULL); + gcd_think(); + + + #ifdef _WIN32 + quit = _kbhit(); + #endif + + FD_ZERO ( &set ); + FD_SET ( ssock, &set ); + for (i = 0 ; i < MAXCLIENTS ; i++) + if (clients[i].sock != INVALID_SOCKET) + FD_SET(clients[i].sock , &set); + error = select(FD_SETSIZE, &set, NULL, NULL, &timeout); + if (/*gsiSocketIsError(ret) ||*/ 0 == error) + continue; + + //new connection + if (FD_ISSET(ssock, &set)) + { + for (i = 0 ; i < MAXCLIENTS ; i++) + if (clients[i].sock == INVALID_SOCKET) + { + clients[i].sock = accept(ssock, (struct sockaddr *)&(clients[i].saddr), &saddrlen); + listen(ssock,SOMAXCONN); + strcpy(clients[i].challenge,randomchallenge(8)); + len = sprintf(buf,"c:%s",clients[i].challenge); + send(clients[i].sock ,buf, len,0); //send a challenge + clients[i].auth = 0; + printf("Client %d connected\n",i); + break; + } + } + + //client data + for (i = 0 ; i < MAXCLIENTS ; i++) + if (clients[i].sock != INVALID_SOCKET && FD_ISSET(clients[i].sock, &set)) + { + len = recv(clients[i].sock,buf, 512, 0); + if (len <= 0) //the client disconnected + { + printf("Client %d disconnected\n",i); + closesocket(clients[i].sock); + clients[i].sock = INVALID_SOCKET; + if (clients[i].auth) //if they were authorized + gcd_disconnect_user(GAMEID, i); + continue; + } + buf[len] = 0; + if (buf[0] == 'r' && buf[1] == ':' && clients[i].auth == 0) //challenge response + { + printf("Client %d said %s\n",i,buf); + clients[i].auth = 1; + gcd_authenticate_user(GAMEID, i,clients[i].saddr.sin_addr.s_addr, + clients[i].challenge, buf+2, ClientAuthorize, ClientRefreshAuthorize, clients); + } else if (buf[0] == 'p' && buf[1] == ':' && clients[i].auth == 1) // ison proof response + { + //gcd_send_reauth_response needs to know the sesskey (so keymaster can find the task) + // and fromaddr (so gcdkey knows which keymaster to respond to) + if (len > 11) + { + char hintstr[9]; + int hint = 0; + + memcpy(hintstr, buf+2, 8); // first 8 characters are the hint + hintstr[8] = '\0'; + hint = atoi(hintstr); + + printf("Client %d prooved %d, %s\n",i,hint,buf+10); + gcd_process_reauth(GAMEID, i, hint, buf+10); + } + } + + + } + + } + gcd_disconnect_all(GAMEID); + gcd_shutdown(); + qr2_shutdown(NULL); + + SocketShutDown(); + printf("All done!\n"); + return 0; + + GSI_UNUSED(argv); + GSI_UNUSED(argc); +} diff --git a/xrGameSpy/gamespy/gcdkey/changelog.txt b/xrGameSpy/gamespy/gcdkey/changelog.txt new file mode 100644 index 00000000000..7ccc5b5aaa9 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/changelog.txt @@ -0,0 +1,78 @@ +Changelog for: GameSpy CDKey SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.08.00 RMV RELEASE Released to Developer Site +12-06-2007 1.07.01 SAH OTHER Added NatNeg to ServerTestQR2 projects to remove compiler errors +08-06-2007 1.07.00 RMV RELEASE Released to Developer Site +07-16-2007 1.06.02 RMV FIX Added win32common.c to ClientTest/ServerTest Project to fix compilation error + 1.06.02 RMV OTHER Changed cd key used by ServerTestQR2 to be different than that used by ClientTest +07-11-2007 1.06.02 RMV FIX Fixed typecasting, possibly uninitialized variable and unreferenced variable warnings in test projects +12-18-2006 1.06.01 SAH FIX Fixed a bug in the ServerTest app causing an incorrect hint value to be passed to the client +12-15-2006 1.06.00 MJW RELEASE Released to Developer Site +12-12-2006 1.05.12 SAH FIX Changed all references in ServerTestQR2 of PRODUCTID to GAMEID +10-05-2006 1.05.11 SAH FIX Updated MacOSX Makefile +08-24-2006 1.05.10 SAH FIX Fixed VC7 project file +08-02-2006 1.05.09 SAH RELEASE Releasing to developer site +07-31-2006 1.05.09 SAH FIX Fixed Linux makefile +07-24-2006 1.05.08 SAH OTHER Added Host self-validation check to the gcd/qr2server sample app +05-31-2006 1.05.07 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-25-2006 1.05.06 SAH FIX Changed keyserver_qr2 to have natNegotiate set to 1 +04-25-2006 1.05.05 SAH RELEASE Releasing to developer site +04-24-2006 1.05.05 SAH FIX Commented out unused gsiIsSocketError check in **server.c tests +01-27-2006 1.05.04 SN RELEASE Releasing to developer site +12-16-2005 1.05.04 SN OTHER Moved projects to subdirectories + Reorganized each project to have latest common code +11-14-2005 1.05.03 DES FIX Updates for OSX. +08-17-2005 1.05.02 SN FIX Fixed method parameter causing C++ compiler errors for computing responses +08-02-2005 1.05.01 BED FIX Renamed "skey" parameter of RefreshAuthCallbackFn to "hint" for consistency +07-28-2005 1.05.00 SN RELEASE Releasing to developer site. +06-05-2005 1.05.00 SN FIX Fixed the newline bug in the client sample causing all CD Keys to be invalid +06-03-2005 1.05.00 SN RELEASE Releasing to developer site. +05-26-2005 1.05.00 BED RELEASE Releasing to developer site. +05-17-2005 1.05.00 BED FEATURE Added challenge proof to "ison" messages. +05-05-2005 1.04.19 BED OTHER Updated projects to use new common folder +05-29-2005 1.04.18 SN OTHER Created Visual Studio .NET projects +04-28-2005 1.04.18 SN RELEASE Releasing to developer site. +04-04-2005 1.04.18 SN RELEASE Releasing to developer site. +11-25-2004 1.04.18 SN FIX Added const qualifiers to function parameters not modified +11-19-2004 1.04.17 SN RELEASE Releasing to developer site. +11-18-2004 1.04.17 BED FIX Fixed buffer overflow vulnerability in gcdkeys.c +09-16-2004 1.04.16 SN RELEASE Releasing to developer site. +08-27-2004 1.04.16 DES CLEANUP Removed MacOS style includes + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Fixed warnings under OSX + DES CLEANUP Removed legacy QRCDKEY_INTEGRATION code and sample + DES CLEANUP Updated OSX Makefiles +08-24-2004 1.04.15 DES CLEANUP Removed references to MacOS. +08-05-2004 1.04.14 SN RELEASE Releasing to developer site. +02-03-2003 1.04.14 BED RELEASE Releasing to developer site. +02-02-2004 1.04.13 DES FIX Fixed code that assumed there was a second backslash if a first was found. +11-10-2003 1.04.12 DES RELEASE Releasing to developer site. +11-07-2003 1.04.12 DES FIX Updated the linux Makefile. +11-04-2003 1.04.11 DES FEATURE Added availability check code. +10-21-2003 1.04.10 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +09-30-2003 1.04.10 BED FIX Parameters named "productid" are now called "gameid" to avoid confusion. +08-21-2003 1.04.09 DES RELEASE Releasing to developer site. +07-25-2003 1.04.09 DES FIX Removed usage of gets in the clienttext to get rid of Linux warnings. +07-24-2003 1.04.08 DES RELEASE Releasing to developer site. +07-23-2003 1.04.08 BED CLEANUP General cleanup to remove "no newline at end of file" warnings. +07-16-2003 1.04.07 DES FEATURE The server sample will try a range of ports until it gets a successful bind. + FEATURE The client can specify which port to connect to on the server. +05-20-2003 1.04.06 DES FIX Fixed gcd_shutdown to not close the socket if using CDKey integration. +04-22-2003 1.04.05 DES RELEASE Releasing to developer site. + FIX Updated to use the new name of the global QR2 structure. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +03-03-2003 1.04.04 DES CLEANUP General cleanup to remove warnings. +01-06-2003 1.04.03 DES FEATURE Added integration with QR2, including a new test project, gcdkeyserver_qr2. +12-19-2002 1.04.02 DES RELEASE Releasing to developer site. +12-19-2002 1.04.02 DES CLEANUP Removed assert.h include. +12-16-2002 1.04.01 DES FIX Set listen calls in samples to use SOMAXCONN for the backlog paramter. +10-24-2002 1.04.00 DES RELEASE Release on developer site with updated documentation +10-22-2002 1.04.00 DES RELEASE Release on developer site +10-21-2002 1.04.00 DDW FEATURE Added ability to support multiple products simultaneously + Games must now pass productID to the authenticate and disconnect functions + The productID is now passed in the authentication callback +09-25-2002 1.03.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/gcdkey/gcdkey.dsw b/xrGameSpy/gamespy/gcdkey/gcdkey.dsw new file mode 100644 index 00000000000..fb7d465c6e0 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkey.dsw @@ -0,0 +1,85 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CdkeyGen"=.\CdkeyGen\CdkeyGen.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/gcdkey/CdkeyGen + .\cdkeygen + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ClientTest"=.\ClientTest\ClientTest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/gcdkey/ClientTest + .\ClientTest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ServerTest"=.\ServerTest\ServerTest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/gcdkey/ServerTest + .\ServerTest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ServerTestQR2"=.\ServerTestQR2\ServerTestQR2.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/gcdkey/ServerTestQR2 + .\ServerTestQR2 + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gcdkey", JIGAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/gcdkey/gcdkey_vs2005.sln b/xrGameSpy/gamespy/gcdkey/gcdkey_vs2005.sln new file mode 100644 index 00000000000..a4d2cba39b4 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkey_vs2005.sln @@ -0,0 +1,37 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CdkeyGen_vs2005", "CdkeyGen\CdkeyGen_vs2005.vcproj", "{25364C96-DA21-4ED5-AABD-BD3EFAB6357B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ClientTest_vs2005", "ClientTest\ClientTest_vs2005.vcproj", "{E6CF8D9C-138F-4940-B1F2-BE5F369F4034}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServerTest_vs2005", "ServerTest\ServerTest_vs2005.vcproj", "{D247EC2E-5318-41A4-8EB4-AF9DBC33A017}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServerTestQR2_vs2005", "ServerTestQR2\ServerTestQR2_vs2005.vcproj", "{55A76B25-95BD-4F54-9122-8418D2D5F8BD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25364C96-DA21-4ED5-AABD-BD3EFAB6357B}.Debug|Win32.ActiveCfg = Debug|Win32 + {25364C96-DA21-4ED5-AABD-BD3EFAB6357B}.Debug|Win32.Build.0 = Debug|Win32 + {25364C96-DA21-4ED5-AABD-BD3EFAB6357B}.Release|Win32.ActiveCfg = Release|Win32 + {25364C96-DA21-4ED5-AABD-BD3EFAB6357B}.Release|Win32.Build.0 = Release|Win32 + {E6CF8D9C-138F-4940-B1F2-BE5F369F4034}.Debug|Win32.ActiveCfg = Debug|Win32 + {E6CF8D9C-138F-4940-B1F2-BE5F369F4034}.Debug|Win32.Build.0 = Debug|Win32 + {E6CF8D9C-138F-4940-B1F2-BE5F369F4034}.Release|Win32.ActiveCfg = Release|Win32 + {E6CF8D9C-138F-4940-B1F2-BE5F369F4034}.Release|Win32.Build.0 = Release|Win32 + {D247EC2E-5318-41A4-8EB4-AF9DBC33A017}.Debug|Win32.ActiveCfg = Debug|Win32 + {D247EC2E-5318-41A4-8EB4-AF9DBC33A017}.Debug|Win32.Build.0 = Debug|Win32 + {D247EC2E-5318-41A4-8EB4-AF9DBC33A017}.Release|Win32.ActiveCfg = Release|Win32 + {D247EC2E-5318-41A4-8EB4-AF9DBC33A017}.Release|Win32.Build.0 = Release|Win32 + {55A76B25-95BD-4F54-9122-8418D2D5F8BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {55A76B25-95BD-4F54-9122-8418D2D5F8BD}.Debug|Win32.Build.0 = Debug|Win32 + {55A76B25-95BD-4F54-9122-8418D2D5F8BD}.Release|Win32.ActiveCfg = Release|Win32 + {55A76B25-95BD-4F54-9122-8418D2D5F8BD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeyc.c b/xrGameSpy/gamespy/gcdkey/gcdkeyc.c new file mode 100644 index 00000000000..50e3d746fa4 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeyc.c @@ -0,0 +1,75 @@ +/****** +gcdkeyc.c +GameSpy CDKey SDK Client Code + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 64, 68 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +#include "../md5.h" +#include "gcdkeyc.h" +#include +#include +#include +#include + +#define RAWSIZE 512 + +#ifdef __cplusplus +extern "C" { +#endif + + // method = 0 for normal auth response from game server + // method = 1 for reauth response originating from keymaster +void gcd_compute_response(char *cdkey, char *challenge, char response[RESPONSE_SIZE], CDResponseMethod method) +{ + char rawout[RAWSIZE]; + unsigned int anyrandom; + char randstr[9]; + + + /* check to make sure we weren't passed a huge cd key/challenge */ + if (strlen(cdkey) * 2 + strlen(challenge) + 8 >= RAWSIZE) + { + strcpy(response,"CD Key or challenge too long"); + return; + } + + /* make sure we are randomized */ + srand((unsigned int)time(NULL) ^ 0x33333333); + /* Since RAND_MAX is 16 bit on many systems, make sure we get a 32 bit number */ + anyrandom = (rand() << 16 | rand()); + sprintf(randstr,"%.8x",anyrandom); + + /* auth response = MD5(cdkey + random mod 0xffff + challenge) */ + /* reauth response = MD5(challenge + random mode 0xffff + cdkey) */ + if (method == 0) + sprintf(rawout, "%s%d%s",cdkey, anyrandom % 0xFFFF , challenge ); + else + sprintf(rawout, "%s%d%s",challenge, anyrandom % 0xFFFF, cdkey); + + /* do the cd key md5 */ + MD5Digest((unsigned char *)cdkey, strlen(cdkey), response); + /* add the random value */ + strcpy(&response[32], randstr); + /* do the response md5 */ + MD5Digest((unsigned char *)rawout, strlen(rawout), &response[40]); +} + + +#ifdef __cplusplus +} +#endif + diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeyc.h b/xrGameSpy/gamespy/gcdkey/gcdkeyc.h new file mode 100644 index 00000000000..f3b1994d360 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeyc.h @@ -0,0 +1,40 @@ +/****** +gcdkeyc.h +GameSpy CDKey SDK Client Header + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + +#ifndef _GOACDKEYC_H_ +#define _GOACDKEYC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define RESPONSE_SIZE 73 + +typedef enum +{ + CDResponseMethod_NEWAUTH, // method = 0 for normal auth + CDResponseMethod_REAUTH // method = 1 for ison proof +} CDResponseMethod; + + +void gcd_compute_response(char *cdkey, char *challenge,/*out*/ char response[73], CDResponseMethod method); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeylinux/gcdkeyclientlinux/Makefile b/xrGameSpy/gamespy/gcdkey/gcdkeylinux/gcdkeyclientlinux/Makefile new file mode 100644 index 00000000000..ee2e616e45d --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeylinux/gcdkeyclientlinux/Makefile @@ -0,0 +1,46 @@ +# CDKey SDK Client Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=gcdkeyclient + +CC=gcc +BASE_CFLAGS=-D_LINUX -I../ -I../.. + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../gcdkeyc.o\ + ../../../md5c.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../ClientTest/gcdkeyclienttest.o\ + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeylinux/gcdkeyserverlinux/Makefile b/xrGameSpy/gamespy/gcdkey/gcdkeylinux/gcdkeyserverlinux/Makefile new file mode 100644 index 00000000000..2ace2747501 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeylinux/gcdkeyserverlinux/Makefile @@ -0,0 +1,47 @@ +# CDKey SDK Server +# Copyright 2004 GameSpy Industries + +PROJECT=gcdkeyserver + +CC=gcc +BASE_CFLAGS=-D_LINUX -I../ -I../.. + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -mtune=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../gcdkeys.o\ + ../../../md5c.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../ServerTest/gcdkeyservertest.o\ + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeymacosx/gcdkeyclientmacosx/Makefile b/xrGameSpy/gamespy/gcdkey/gcdkeymacosx/gcdkeyclientmacosx/Makefile new file mode 100644 index 00000000000..15aea14a3aa --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeymacosx/gcdkeyclientmacosx/Makefile @@ -0,0 +1,20 @@ +# CDKey SDK Client Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=gcdkeyclient + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../gcdkeyc.o\ + ../../ClientTest/gcdkeyclienttest.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeymacosx/gcdkeyservermacosx/Makefile b/xrGameSpy/gamespy/gcdkey/gcdkeymacosx/gcdkeyservermacosx/Makefile new file mode 100644 index 00000000000..dff0bcf814c --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeymacosx/gcdkeyservermacosx/Makefile @@ -0,0 +1,22 @@ +# CDKey SDK Server Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=gcdkeyserver + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../gcdkeyc.o\ + ../../gcdkeys.o\ + ../../ServerTest/gcdkeyservertest.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeys.c b/xrGameSpy/gamespy/gcdkey/gcdkeys.c new file mode 100644 index 00000000000..8db0d12f4a7 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeys.c @@ -0,0 +1,965 @@ +/****** +gcdkeys.c +GameSpy CDKey SDK Server Code + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + +/******** +INCLUDES +********/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 845, 846 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + +#include "gcdkeys.h" +#include "../common/gsCommon.h" +#include "../common/gsAvailable.h" +#include "../common/gsDebug.h" +#include + +#ifdef GUSE_ASSERTS + #define gassert(a) assert(a) +#else + #define gassert(a) +#endif + +#define BUFSIZE 512 + +#ifdef __cplusplus +extern "C" { +#endif + +/******** +DEFINES +********/ +#define VAL_PORT 29910 +/* #define VAL_ADDR "key.gamespy.com" */ +/*#define VAL_ADDR "204.182.161.103"*/ +#define VAL_TIMEOUT 2000 +#define VAL_RETRIES 2 +#define INBUF_LEN 1024 +#define MAX_PRODUCTS 4 +#define MAX_KEEP_ALIVE_INTERVAL 20000 + +#define MAXPENDING_REAUTH 5 // prevent memory growth from spammed reauths. +#define REAUTH_LIFESPAN 5000 // prevent memory growth from unanswered reauths. +#define PROOF_TXT 'p','r','o','o','f' +#define IGNORED_TXT 's','e','e','d' + +/******** +TYPEDEFS +********/ +typedef enum {cs_sentreq, cs_gotok, cs_gotnok, cs_done} gsclientstate_t; + +typedef struct gsnode_s +{ + void *object; + struct gsnode_s *next, *prev; +} gsnode_t; + +typedef struct gsclient_s +{ + int localid; + char hkey[33]; + int sesskey; + int ip; + unsigned long sttime; + int ntries; + gsclientstate_t state; + void *instance; + AuthCallBackFn authfn; + RefreshAuthCallBackFn refreshauthfn; + char *errmsg; + char *reqstr; + int reqlen; + gsnode_t reauthq; +} gsclient_t; + +typedef struct gsreauth_s +{ + int sesskey; + char challenge[33]; + struct sockaddr_in fromaddr; + gsi_time starttime; +} gsreauth_t; + +typedef struct gsproduct_s +{ + int pid; + gsnode_t clientq; +} gsproduct_t; + + +/******** +GLOBALS +********/ +char gcd_hostname[64] = ""; + +/******** +PROTOTYPES +********/ +static void send_auth_req(gsproduct_t *prod, gsclient_t *client, const char *challenge, const char *response); +static void resend_auth_req(gsclient_t *client); +static void send_keep_alive(); +static void send_disconnect_req(gsproduct_t *prod, gsclient_t *client); +static void cdkey_process_buf(char *buf, int len, struct sockaddr *fromaddr); +static void process_oks(char *buf, int isok); +static void process_ison(char *buf, struct sockaddr_in *fromaddr); +static void process_ucount(char *buf, struct sockaddr_in *fromaddr); +static void send_uon(int skey, const char* ignored, const char* proof, struct sockaddr_in *fromaddr); +static void free_client_node(gsnode_t *node); + +static int get_sockaddrin(char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent); +static void xcode_buf(char *buf, int len); +static char *value_for_key(const char *s, const char *key); + + +static void add_to_queue(gsnode_t *t, gsnode_t *que); +static gsnode_t *remove_from_queue(gsnode_t *t, gsnode_t *que); +static int gcd_init_common(int gameid); +static int init_incoming_socket(); +static gsproduct_t *find_product(int gameid); + +/******** +VARS +********/ +static SOCKET sock = INVALID_SOCKET; +static unsigned short localport = 0; +static char enc[9]; /* used for xor encoding */ +static struct sockaddr_in valaddr; + +static int numproducts = 0; +gsproduct_t products[MAX_PRODUCTS]; + +/****************************************************************************/ +/* PUBLIC FUNCTIONS */ +/****************************************************************************/ + + +int gcd_init(int gameid) +{ + int ret; + const char defaulthost[] = {'k','e','y','.','g','a','m','e','s','p','y','.','c','o','m','\0'}; //key.gamespy.com + + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return -1; + + if (sock == INVALID_SOCKET) //hasn't been initialized yet + { + /* set up the UDP socket */ + SocketStartUp(); + ret = init_incoming_socket(); + if (ret < 0) + return ret; + + if (gcd_hostname[0] == 0) + strcpy(gcd_hostname, defaulthost); + get_sockaddrin(gcd_hostname,VAL_PORT,&valaddr,NULL); + } + + + return gcd_init_common(gameid); + +} + + +#ifdef QR2CDKEY_INTEGRATION +extern struct qr2_implementation_s static_qr2_rec; +int gcd_init_qr2(qr2_t qrec, int gameid) +{ + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return -1; + + if (qrec == NULL) + qrec = &static_qr2_rec; + + localport = (unsigned short)-1; /* we don't process any incoming data ourselves - it gets passed from the QR SDK */ + + sock = qrec->hbsock; + qrec->cdkeyprocess = cdkey_process_buf; + /* grab the outgoing address from the QR SDK */ + memset(&valaddr,0,sizeof(struct sockaddr_in)); + valaddr.sin_family = AF_INET; + valaddr.sin_port = htons((unsigned short)VAL_PORT); + valaddr.sin_addr.s_addr = qrec->hbaddr.sin_addr.s_addr; + return gcd_init_common(gameid); + +} + +#endif + + +void gcd_shutdown(void) +{ + int i; + /* Make sure everyone is disconnected */ + for (i = 0 ; i < numproducts ; i++) + gcd_disconnect_all(products[i].pid); + if(localport != (unsigned short)-1) + { + closesocket(sock); + SocketShutDown(); + } + sock = INVALID_SOCKET; + numproducts = 0; +} + + +void gcd_authenticate_user(int gameid, int localid, unsigned int userip, const char *challenge, + const char *response, AuthCallBackFn authfn, RefreshAuthCallBackFn refreshfn, void *instance) +{ + gsnode_t *node; + gsclient_t *client; + char hkey[33]; + char *errmsg = NULL; + char badcdkey_t[] = {'B','a','d',' ','C','D',' ','K','e','y','\0'}; //Bad CD Key + char keyinuse_t[] = {'C','D',' ','K','e','y',' ','i','n',' ','u','s','e','\0'}; //CD Key in use + gsproduct_t *prod = find_product(gameid); + + gassert(prod); + if (prod == NULL) + return; + + /* get the hashed key */ + strncpy(hkey, response, 32); + hkey[32] = 0; + + /* if response is bogus, lets kill them */ + if (strlen(response) < 72) + errmsg = goastrdup(badcdkey_t); + + /* First, scan the current list for the same, or similar client */ + node = &prod->clientq; + while ((node = node->next) != NULL) + { + /* make sure the localid isn't being reused + Change this code if you want to allow multiple users with the same CD Key on the + same server */ + gsclient_t* client = (gsclient_t*)node->object; + gassert(client->localid != localid); + if (strcmp(hkey, client->hkey) == 0) + { /* they appear to be on already!! */ + errmsg = goastrdup(keyinuse_t); + break; + } + } + + /* Create a new client */ + client = (gsclient_t *)gsimalloc(sizeof(gsclient_t)); + gassert(client); + client->localid = localid; + client->ip = (int)userip; + client->instance = instance; + client->errmsg = NULL; + client->reqstr = NULL; + client->authfn = authfn; + client->refreshauthfn = refreshfn; + client->reauthq.next = NULL; + client->reauthq.object = NULL; + client->reauthq.prev = NULL; + strcpy(client->hkey, hkey); + node = (gsnode_t *)gsimalloc(sizeof(gsnode_t)); + gassert(node); + node->object = (void*)client; + add_to_queue(node, &prod->clientq); + + if (errmsg != NULL) + { /* there was already and error, mark them to die */ + client->state = cs_gotnok; + client->errmsg = errmsg; + } else /* They aren't on this server, lets check the validation server */ + send_auth_req(prod, client,challenge, response); +} + +void gcd_process_reauth(int gameid, int localid, int skey, const char *response) +{ + // find the pending reauth attempt + gsnode_t *clientnode; + gsnode_t *reauthnode; + gsproduct_t *prod = find_product(gameid); + + gassert(prod); + if (prod == NULL) + return; + + // find the client for this gameid + clientnode = &prod->clientq; + while ((clientnode = clientnode->next) != NULL) + { + gsclient_t *client = (gsclient_t*)clientnode->object; + if (client->localid == localid) + { + // find the reauth info for this client/skey + reauthnode = &client->reauthq; + while((reauthnode = reauthnode->next) != NULL) + { + gsreauth_t *reauth = (gsreauth_t*)reauthnode->object; + if (reauth->sesskey == skey) + { + // send the proof to the keymaster + send_uon(skey, "", response, &reauth->fromaddr); + remove_from_queue(reauthnode, &client->reauthq); + gsifree(reauthnode->object); + gsifree(reauthnode); + return; + } + } + } + } +} + +// utility to free memory associated with a client node +static void free_client_node(gsnode_t *node) +{ + if (node) + { + gsclient_t* client = (gsclient_t*)node->object; + if (client) + { + if (client->reqstr != NULL) + gsifree(client->reqstr); + if (client->errmsg != NULL) + gsifree(client->errmsg); + + // free auth nodes + while (client->reauthq.next != NULL) + { + gsnode_t* authNode = remove_from_queue(client->reauthq.next, &client->reauthq); + gsifree(authNode->object); + gsifree(authNode); + } + gsifree(client); + } + gsifree(node); + } + return; +} + +void gcd_disconnect_user(int gameid, int localid) +{ + gsnode_t *node; + gsproduct_t *prod = find_product(gameid); + + gassert(prod); + if (prod == NULL) + return; + + /* First, scan the list for the client*/ + node = &prod->clientq; + while ((node = node->next) != NULL) + { + gsclient_t* client = (gsclient_t*)node->object; + if (client->localid == localid) + { + send_disconnect_req(prod, client); + remove_from_queue(node, &prod->clientq); + free_client_node(node); + return; + } + } + /* No client found -- we should never get here! + But we may if you call disconnect_user during an negative authentication + (they are already removed) */ + +} + +void gcd_disconnect_all(int gameid) +{ + gsnode_t *node; + + gsproduct_t *prod = find_product(gameid); + + gassert(prod); + if (prod == NULL) + return; + + /* Clear the entire list */ + node = &prod->clientq; + while ((node = node->next) != NULL) + { + gsclient_t* client = (gsclient_t*)node->object; + send_disconnect_req(prod, client); + remove_from_queue(node, &prod->clientq); + free_client_node(node); + node = &prod->clientq; + } +} + +char *gcd_getkeyhash(int gameid, int localid) +{ + + gsproduct_t *prod = find_product(gameid); + gsnode_t *node; + + gassert(prod); + if (prod == NULL) + return ""; + + node = &prod->clientq; + + /* Scan the list for the client*/ + while ((node = node->next) != NULL) + { + gsclient_t* client = (gsclient_t*)node->object; + if (client->localid == localid) + return client->hkey; + } + return ""; +} + +void gcd_think(void) +{ + static char indata[INBUF_LEN]; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + fd_set set; + struct timeval timeout = {0,0}; + int error; + int i; + gsnode_t *node, *oldnode; + char validated_t[] = {'V','a','l','i','d','a','t','e','d','\0'}; //Validated + char timeout_t[] = {'V','a','l','i','d','a','t','i','o','n',' ','T','i','m','e','o','u','t','\0'}; //Validation Timeout + + gassert (sock != INVALID_SOCKET); + /* First, check for data on the socket and process commands */ + + if (localport != (unsigned short)-1) /* don't check if we are getting data from the QR SDK instead */ + { + FD_ZERO ( &set ); + FD_SET ( sock, &set ); + while (1) + { + error = select(FD_SETSIZE, &set, NULL, NULL, &timeout); + if (gsiSocketIsError(error) || 0 == error) + break; + /* else we have data */ + error = recvfrom(sock, indata, INBUF_LEN - 1, 0, (struct sockaddr *)&saddr, &saddrlen); + if (gsiSocketIsNotError(error)) + { + indata[error] = '\0'; + cdkey_process_buf(indata, error, (struct sockaddr *)&saddr); + } + } + } + + send_keep_alive(); + + for (i = 0 ; i < numproducts ; i++) + { + /* Next, update the status of any clients and make callbacks */ + node = &products[i].clientq; + while ((node = node->next) != NULL) + { + gsclient_t* client = (gsclient_t*)node->object; + switch (client->state) + { + case cs_sentreq: + if (current_time() < client->sttime + VAL_TIMEOUT) + break; /* keep waiting */ + if (client->ntries <= VAL_RETRIES) + { /* resend */ + resend_auth_req(client); + break; + } /* else, go ahead an auth them, the val server timed out */ + case cs_gotok: + /* if authorized or they timed out with no response, just auth them */ + client->authfn(products[i].pid, client->localid, 1, + client->state == cs_gotok ? validated_t : timeout_t, + client->instance); + client->state = cs_done; + gsifree(client->reqstr); + client->reqstr = NULL; + break; + case cs_gotnok: + /* remove them first, in case the user calls disconnect */ + oldnode = node; + node = node->prev; + remove_from_queue(oldnode, &products[i].clientq); + + client->authfn(products[i].pid, client->localid, 0, + client->errmsg == NULL ? "" : client->errmsg, + client->instance); + free_client_node(oldnode); + break; + case cs_done: + // check pending reauth timeouts + if (client->reauthq.next != NULL) + { + // always look at "next" because we may remove nodes + gsnode_t* authnode = &client->reauthq; + while(authnode->next != NULL) + { + gsreauth_t* authdata = (gsreauth_t*)authnode->next->object; + gsi_time now = current_time(); + if ((now - authdata->starttime) > REAUTH_LIFESPAN) + { + gsDebugFormat(GSIDebugCat_CDKey, GSIDebugType_Misc, GSIDebugLevel_Notice, + "Removing timed out reauth request [localid: %d, from: %s\r\n", + client->localid, inet_ntoa(authdata->fromaddr.sin_addr)); + + // timed out, delete it + remove_from_queue(authnode->next, &client->reauthq); + gsifree(authdata); + gsifree(authnode->next); + authnode->next = NULL; + } + else + authnode = authnode->next; + } + } + break; + default: + break; + } + } + } +} + + +/****************************************************************************/ +/* UTIL FUNCTIONS */ +/****************************************************************************/ +static void cdkey_process_buf(char *buf, int len, struct sockaddr *fromaddr) +{ + char tok[32]; + char *pos; + char uok_t[] = {'u','o','k','\0'}; //uok + char unok_t[] = {'u','n','o','k','\0'}; //unok + char ison_t[] = {'i','s','o','n','\0'}; //ison + char ucount_t[] = {'u','c','o','u','n','t','\0'}; //ucount + xcode_buf(buf, len); + + tok[0] = 0; + if (buf[0] == '\\') + { + pos = strchr(buf+1,'\\'); + if (pos && (pos - buf <= 32)) /* right size token */ + { + strncpy(tok, buf+1,pos-buf-1); + tok[pos-buf-1] = 0; + } + } + if (!tok[0]) + return; /* bad command */ + + if (!strcmp(tok, uok_t)) + { + process_oks(buf, 1); + } + else if (!strcmp(tok, unok_t)) + { + process_oks(buf, 0); + } + else if (!strcmp(tok, ison_t)) + { + process_ison(buf, (struct sockaddr_in *)fromaddr); + } + else if (!strcmp(tok, ucount_t)) + { + process_ucount(buf, (struct sockaddr_in *)fromaddr); + } + else + { + send_keep_alive(); + return; /* bad command */ + } + send_keep_alive(); +} + +static int init_incoming_socket() +{ + int ret; + struct sockaddr_in saddr; + int saddrlen; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock == INVALID_SOCKET) + return -1; + get_sockaddrin(NULL,0,&saddr,NULL); + ret = bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)); + if (gsiSocketIsError(ret)) + return -1; + + saddrlen = sizeof(saddr); + ret = getsockname(sock,(struct sockaddr *)&saddr, &saddrlen); + if (gsiSocketIsError(ret)) + return -1; + localport = saddr.sin_port; + + return 0; +} + +static int gcd_init_common(int gameid) +{ + gsproduct_t *prod; + gassert(numproducts < MAX_PRODUCTS); + if (numproducts >= MAX_PRODUCTS) + return -1; //too many products + prod = &products[numproducts++]; + prod->pid = gameid; + prod->clientq.next = NULL; + prod->clientq.prev = NULL; + prod->clientq.object = NULL; + srand((unsigned int)current_time()); + enc[0]='g';enc[1]='a';enc[2]='m';enc[3]='e'; + enc[4]='s';enc[5]='p';enc[6]='y';enc[7]=0; + return 0; +} +static gsclient_t *find_client(char *keyhash, int sesskey, int* productid) +{ + gsnode_t *node; + int i; + + for (i = 0 ; i < numproducts ; i++) + { + node = &products[i].clientq; + while ((node = node->next) != NULL) + { + gsclient_t* client = (gsclient_t*)node->object; + if (strcmp(keyhash, client->hkey) == 0 && (sesskey == -1 || client->sesskey == sesskey)) + { + if (productid != NULL) + *productid = products[i].pid; + return client; + } + } + } + return NULL; +} + +static void process_oks(char *buf, int isok) +{ + int sesskey; + char keyhash[33]; + gsclient_t *client; + const char skey_t[] = {'s','k','e','y','\0'}; //skey + const char cd_t[] = {'c','d','\0'}; //cd + const char errmsg_t[] = {'e','r','r','m','s','g','\0'}; //errmsg + +/* Samples +\uok\\cd\fe6667736f0c8ed7ff5cd9c0e74f\skey\2342 +\unok\\cd\fe6667736f0c8ed7ff5cd9c0e74f\skey\23423\errmsg\Already playing on xyz server */ + sesskey = atoi(value_for_key(buf,skey_t)); + strncpy(keyhash,value_for_key(buf,cd_t),32); + keyhash[32] = 0; + + client = find_client(keyhash, sesskey, NULL); + if (!client) + return; + if (client->sesskey != sesskey) /* bad session key */ + return; + if (client->state == cs_done) /* too late to do anything! */ + return; + if (isok) + client->state = cs_gotok; + else + { + client->state = cs_gotnok; + client->errmsg = goastrdup(value_for_key(buf,errmsg_t)); + } + +} +static void process_ucount(char *buf, struct sockaddr_in *fromaddr) +{ + char outbuf[64]; + char ucountformat[] = {'\\','u','c','o','u','n','t','\\','%','d','\0'}; //\\ucount\\%d + char pid_t[] = {'p','i','d','\0'}; //pid + gsnode_t *node; + int count = 0; + int len; + gsproduct_t *prod; + char *pos = value_for_key(buf, pid_t); + if (pos[0] == 0 && numproducts > 0) //not present.. use the first product + prod = &products[0]; + else + prod = find_product(atoi(pos)); + if (prod != NULL) + { + node = &prod->clientq; + while ((node = node->next) != NULL) + { + count++; + } + } + len = sprintf(outbuf, ucountformat, count); + xcode_buf(outbuf, len); + sendto(sock, outbuf, len, 0, (struct sockaddr *)fromaddr, sizeof(struct sockaddr_in)); +} + +static void send_uon(int skey, const char* ignored, const char* proof, struct sockaddr_in *fromaddr) +{ + char outbuf[256]; + int len; + const char uonformat[] = {'\\','u','o','n','\\','\\','s','k','e','y','\\','%','d','\\',IGNORED_TXT,'\\','%','s','\\',PROOF_TXT,'\\','%','s','\0'}; //\\uon\\\\skey\\%d\\seed\\%s\\proof\\%s +/* \ison\\cd\fe6667736f0c8ed7ff5cd9c0e74f\skey\32423 */ +/* \uon\\skey\32423\seed\\proof\ OR \un\skey\32423\proof\fe6667736f0c8ed7ff5cd9c0e74f OR \uoff\\skey\32423 */ + + // seed is ignored by server + len = snprintf(outbuf, 255, uonformat,skey, ignored, proof); + outbuf[255] = '\0'; // snprintf doesn't null terminate in some cases + xcode_buf(outbuf, len); + sendto(sock, outbuf, len, 0, (struct sockaddr *)fromaddr, sizeof(struct sockaddr_in)); + + gsDebugFormat(GSIDebugCat_CDKey, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sent uon response (ison) to %s. (proof: %s)\r\n", + inet_ntoa(fromaddr->sin_addr), proof); +} + +static void send_uoff(int skey, struct sockaddr_in *fromaddr) +{ + char outbuf[64]; + int len; + const char uoffformat[] = {'\\','u','o','f','f','\\','\\','s','k','e','y','\\','%','d','\0'}; //\\uoff\\\\skey\\%d + len = sprintf(outbuf, uoffformat,skey); + xcode_buf(outbuf, len); + sendto(sock, outbuf, len, 0, (struct sockaddr *)fromaddr, sizeof(struct sockaddr_in)); +} + +static int get_queue_size(gsnode_t* node) +{ + int count = 0; + if (!node) + return 0; + if (node->object) // starting from a valid node + count++; + while (node->next != NULL) + { + count++; + node = node->next; + } + return count; +} + +static void process_ison(char *buf, struct sockaddr_in *fromaddr) +{ + int sesskey; + int productid; + char* proofchallenge; + + gsclient_t *client; + + const char proofchallenge_t[] = {'p','c','h','\0'}; // proof challenge + const char skey_t[] = {'s','k','e','y','\0'}; //skey + const char cd_t[] = {'c','d','\0'}; //cd + + sesskey = atoi(value_for_key(buf,skey_t)); + proofchallenge = value_for_key(buf,proofchallenge_t); + if ( (client = find_client(value_for_key(buf,cd_t), -1, &productid)) != NULL + && (client->state == cs_done)) /* If they are connected, return on */ + { + // check the queue size to prevent memory growth (from malicious reauth requests) + int count = get_queue_size(&client->reauthq); + if (count < MAXPENDING_REAUTH) + { + // store the sesskey and fromaddr so we can respond with proof later + gsnode_t* node = (gsnode_t*)gsimalloc(sizeof(gsnode_t)); + gsreauth_t* reauthdata = (gsreauth_t*)gsimalloc(sizeof(gsreauth_t)); + gassert(node); + gassert(reauthdata); + + memcpy(reauthdata->challenge, proofchallenge, 32); + memcpy(&reauthdata->fromaddr, fromaddr, sizeof(struct sockaddr_in)); + reauthdata->sesskey = sesskey; + reauthdata->starttime = current_time(); + node->object = (void*)reauthdata; + add_to_queue(node, &client->reauthq); + + // send normal ison right away, later we'll followup with proof + // owatagusiam is ignored by server + send_uon(sesskey, "owatagusiam", "0", fromaddr); + + // notify developer that we need proof of "ison" + client->refreshauthfn(productid, client->localid, sesskey, proofchallenge, client->instance); + } + } + else + { + send_uoff(sesskey, fromaddr); + } +} + +static void send_disconnect_req(gsproduct_t *prod, gsclient_t *client) +{ + char buf[BUFSIZE]; + int len; + const char discformat[] = {'\\','d','i','s','c','\\','\\','p','i','d','\\','%','d','\\','c','d','\\','%','s','\\','i','p','\\','%','d','\0'}; //\\disc\\\\pid\\%d\\cd\\%s\\ip\\%d + +/* \disc\\pid\12\cd\fe6667736f0c8ed7ff5cd9c0e74f\ip\2342342 */ + len = sprintf(buf,discformat, + prod->pid, client->hkey,client->ip); + xcode_buf(buf, len); + sendto(sock, buf, len, 0, (struct sockaddr *)&valaddr, sizeof(valaddr)); +} + +static void send_auth_req(gsproduct_t *prod, gsclient_t *client, const char *challenge, const char *response) +{ + char buf[BUFSIZE]; + int len; + const char authformat[] = {'\\','a','u','t','h','\\','\\','p','i','d','\\','%','d','\\','c','h','\\','%','s','\\','r','e','s','p','\\','%','s','\\','i','p','\\','%','d','\\','s','k','e','y','\\','%','d','\\','r','e','q','p','r','o','o','f','\\','1','\\','\0'}; //\\auth\\\\pid\\%d\\ch\\%s\\resp\\%s\\ip\\%d\\skey\\%d\\reqproof\\1 + + client->state = cs_sentreq; + client->sesskey = (unsigned int)(rand() ^ current_time()) % 16384; + client->sttime = current_time(); + client->ntries = 1; +/* \auth\\pid\12\ch\efx3232\resp\fe6667736f0c8ed7ff5cd9c0e74f98fd69e4da39560b82f40a628522ed10f0165c1d44a0\ip\2342342\skey\132432 */ + len = snprintf(buf, BUFSIZE, authformat, + prod->pid, challenge, response, client->ip, client->sesskey); + buf[BUFSIZE-1] = '\0'; // sometimes snprintf doesn't null terminate + xcode_buf(buf, len); + sendto(sock, buf, len, 0, (struct sockaddr *)&valaddr, sizeof(valaddr)); + /* save a copy for resends */ + client->reqstr = (char *)gsimalloc(len); + memmove(client->reqstr, buf, len); + client->reqlen = len; +} + +static void resend_auth_req(gsclient_t *client) +{ + client->sttime = current_time(); + client->ntries++; + sendto(sock, client->reqstr, client->reqlen, 0, (struct sockaddr *)&valaddr, sizeof(valaddr)); +} + +static void send_keep_alive() +{ + static gsi_time lastKeepAliveSent = 0; + static const char *keepAlive = "\\ka\\\0"; + char buf[BUFSIZE]; + if (lastKeepAliveSent == 0) + lastKeepAliveSent = current_time(); + if (current_time() > lastKeepAliveSent + MAX_KEEP_ALIVE_INTERVAL) + { + strcpy(buf, keepAlive); + xcode_buf(buf, strlen(keepAlive)); + sendto(sock, buf, strlen(keepAlive), 0, (struct sockaddr *)&valaddr, sizeof(struct sockaddr_in)); + lastKeepAliveSent = current_time(); + } +} +/* value_for_key: this returns a value for a certain key in s, where s is a string +containing key\value pairs. If the key does not exist, it returns "" +Note: the value is stored in a common buffer. If you want to keep it, make a copy! */ +static char *value_for_key(const char *s, const char *key) +{ + static int valueindex; + char *pos,*pos2; + char slash_t[] = {'\\','\0'}; + char keyspec[256]; + static char value[2][256]; + + valueindex ^= 1; + strcpy(keyspec, slash_t); + strcat(keyspec,key); + strcat(keyspec,slash_t); + pos = strstr(s,keyspec); + if (!pos) + return ""; + pos += strlen(keyspec); + pos2 = value[valueindex]; + while (*pos && *pos != '\\' && (pos2 - value[valueindex] < 200)) + *pos2++ = *pos++; + *pos2 = '\0'; + return value[valueindex]; +} + +/* simple xor encoding */ +static void xcode_buf(char *buf, int len) +{ + int i; + char *pos = enc; + + for (i = 0 ; i < len ; i++) + { + buf[i] ^= *pos++; + if (*pos == 0) + pos = enc; + } +} + +/* Return a sockaddrin for the given host (numeric or DNS) and port) +Returns the hostent in savehent if it is not NULL */ +static int get_sockaddrin(char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent) +{ + struct hostent *hent = NULL; + char broadcast_t[] = {'2','5','5','.','2','5','5','.','2','5','5','.','2','5','5','\0'}; //255.255.255.255 + + memset(saddr,0,sizeof(struct sockaddr_in)); + saddr->sin_family = AF_INET; + saddr->sin_port = htons((unsigned short)port); + if (host == NULL) + saddr->sin_addr.s_addr = INADDR_ANY; + else + saddr->sin_addr.s_addr = inet_addr(host); + + if (saddr->sin_addr.s_addr == INADDR_NONE && strcmp(host,broadcast_t) != 0) + { + hent = gethostbyname(host); + if (!hent) + return 0; + saddr->sin_addr.s_addr = *(u_long *)hent->h_addr_list[0]; + } + if (savehent != NULL) + *savehent = hent; + return 1; +} + +static gsproduct_t *find_product(int gameid) +{ + int i; + for (i = 0 ; i < numproducts ; i++) + if (products[i].pid == gameid) + return &products[i]; + return NULL; +} + + +/*********** +Linked List Code +***********/ + + +/******* +add_to_queue +*******/ +static void add_to_queue(gsnode_t *t, gsnode_t *que) +{ + while(que->next) + que=que->next; + que->next = t; + t->prev = que; + t->next = NULL; +} + +/******* +remove_from_queue + +if NULL is given as first parameter, top list item is popped off + +item that is removed is returned, or NULL if not found +*******/ +static gsnode_t *remove_from_queue(gsnode_t *t, gsnode_t *que) +{ + + if(!t) t = que->next; + if(!t) return(NULL); + t->prev->next = t->next; + if(t->next) + t->next->prev = t->prev; + + return(t); +} + +#ifdef __cplusplus +} +#endif diff --git a/xrGameSpy/gamespy/gcdkey/gcdkeys.h b/xrGameSpy/gamespy/gcdkey/gcdkeys.h new file mode 100644 index 00000000000..32579a0da47 --- /dev/null +++ b/xrGameSpy/gamespy/gcdkey/gcdkeys.h @@ -0,0 +1,124 @@ +/****** +gcdkeys.h +GameSpy CDKey SDK Server Header + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy CDKey SDK documentation for more + information + +******/ + + +#ifndef _GOACDKEYS_H_ +#define _GOACDKEYS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define GUSE_ASSERTS + +/***** +QR2CDKEY_INTEGRATION: This define controls where the functions needed to integrate +the networking of the Query & Reporting 2 SDK and CDKey SDKs are available. +If you intend to use the integration option for these SDKs, you must uncomment the +define below, or provide it as an option to your compiler. +*******/ +#define QR2CDKEY_INTEGRATION + +typedef void (*AuthCallBackFn)(int gameid, int localid, int authenticated, char *errmsg, void *instance); +typedef void (*RefreshAuthCallBackFn)(int gameid, int localid, int hint, char *challenge, void *instance); + +/* The hostname of the validation server. +If the app resolves the hostname, an +IP can be stored here before calling +gcd_init */ +extern char gcd_hostname[64]; + +/******** +gcd_init +Initializes the Server API and creates the socket +Should only be called once (unless gcd_shutdown has been called) +*********/ +int gcd_init(int gameid); + +/******** +gcd_init_qr2 +Initializes the Server API and integrates the networking of the CDKey SDK +with the Query & Reporting 2 SDK. +You must initialize the Query & Reporting 2 SDK with qr2_init or qr2_init_socket +prior to calling this. If you are using multiple instances of the QR2 SDK, you +can pass the specific instance information in via the "qrec" argument. Otherwise +you can simply pass in NULL. +*********/ +#ifdef QR2CDKEY_INTEGRATION + +#include "../qr2/qr2.h" +int gcd_init_qr2(qr2_t qrec, int gameid); + +#endif + +/******** +gcd_shutdown +Frees the socket and client structures +Also calls gcd_disconnect_all to make sure all users are signaled as offline +*********/ +void gcd_shutdown(void); + +/******** +gcd_authenticate_user +Creates a new client and sends a request for authorization to the +validation server. +*********/ +void gcd_authenticate_user(int gameid, int localid, unsigned int userip, const char *challenge, + const char *response, AuthCallBackFn authfn, RefreshAuthCallBackFn refreshfn, void *instance); + +/******** +gcd_authenticate_user +Creates a new client and sends a request for authorization to the +validation server. +*********/ +void gcd_process_reauth(int gameid, int localid, int hint, const char *response); + + +/******** +gcd_disconnect_user +Notify the validation server that a user has disconnected +*********/ +void gcd_disconnect_user(int gameid, int localid); + + +/******** +gcd_disconnect_all +Calls gcd_disconnect_user for each user still online (shortcut) +*********/ +void gcd_disconnect_all(int gameid); + +/******** +gcd_think +Processes any pending data from the validation server +and calls the callback to indicate whether a client was +authorized or not +*********/ +void gcd_think(void); + +/******** +gcd_getkeyhash +Returns the key hash for the given user. This hash will always +be the same for that users, which makes it good for banning or +tracking of users (used with the Tracking/Stats SDK). Returns +an empty string if that user isn't connected. +*********/ +char *gcd_getkeyhash(int gameid, int localid); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/xrGameSpy/gamespy/ghttp/changelog.txt b/xrGameSpy/gamespy/ghttp/changelog.txt new file mode 100644 index 00000000000..b6ba926fb14 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/changelog.txt @@ -0,0 +1,156 @@ +Changelog for: GameSpy HTTP SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.11.00 RMV RELEASE Released to Developer Site +12-12-2007 1.10.05 RMV FIX Updated ghttpStreamEx call in ghttpc.c to use a URL requiring Nintendo certification, since it + uses REVOEXSSL +11-27-2007 1.10.04 SAH FIX Fixed bug where hostname lookup thread wasn't cancelled if request was + SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +11-12-2007 1.10.03 SAH FIX Incorporated Nintendo suggestions for Built-in RevoEX SSL Certification +10-08-2007 1.10.02 BED RELEASE Limited Release +10-03-2007 1.10.02 BED FIX Switched use of GS_ASSERT(0) with GS_FAIL() +10-01-2007 1.10.01 BED FEATURE Added RevoEX SSL support +08-06-2007 1.10.00 RMV RELEASE Released to Developer Site +07-18-2007 1.09.03 SAH FIX Rolled back version of ghttpProcess to use stack allocation - DS changes were causing socket errors. +07-16-2007 1.09.02 RMV FIX Fixed URL for getting header in ghttpc +07-11-2007 1.09.02 RMV FIX Fixed ghttpc/ghttpmfc Project files to get rid of Unicode warnings and fixed other compiler warnings +04-19-2007 1.09.01 SAH FIX Fixed ghiDoReceivingHeaders/File to support DS limited stack size - uses heap allocation now. +03-05-2007 1.09.00 SAH RELEASE Released to Developer Site +03-02-2007 1.08.06 SN FIX Fixed some compiler warnings for code warrior +02-22-2007 1.08.05 SN FIX Changed parts of code that used strdup to use goastrdup +01-22-2007 1.08.04 SAH FIX Fixed unicode-specific bug for PostAddFileFromMemory +01-16-2007 1.08.03 DES FEATURE Added X360 support +01-04-2007 1.08.02 BED FIX Fixed PS3 Byte order bug in encryption algorithm +12-19-2006 1.08.01 BED FEATURE Added support for Unicode file names when saving to disk. +12-15-2006 1.08.00 MJW RELEASE Released to Developer Site +11-28-2006 1.07.49 SAH FIX Fixed previous change, postWaitContinue set to true for soap messages only +11-13-2006 1.07.48 SAH FIX Rolled back the 1.07.37 change, set postWaitContinue to FALSE. +11-10-2006 1.07.47 JR RELEASE Limited release +10-23-2006 1.07.47 DES RELEASE Limited release +10-05-2006 1.07.47 SAH FIX Updated MacOSX Makefile +09-28-2006 1.07.46 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-24-2006 1.07.45 SAH FIX Fixed VC7 project file +08-04-2006 1.07.44 SN FIX Fixed asynchronous DNS lookup code: removed unnecessary memory allocation +08-02-2006 1.07.43 SAH RELEASE Releasing to developer site +07-31-2006 1.07.43 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 1.07.42 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-07-2006 1.07.41 SAH FIX Fixed HTTP DNS cleanup - needed to explicitly free handle pointer memory +07-06-2006 1.07.40 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +07-05-2006 1.07.39 SAH FIX Fixed postWaitContinue functionality to remain false when waiting + SAH FIX Fixed log call define +06-30-2006 1.07.38 SAH FIX Fixed Linux makefile +06-30-2006 1.07.37 SAH FIX Uncommented postWaitContinue if statement (caused extra newline sent in posts) + SAH FIX Fixed Nitro project file & linker command file to work with CW 2.0/NitroSDK 3.1 +06-20-2006 1.07.36 SAH FEATURE Added asynchronous DNS lookup for LINUX (pthreads) + SAH OTHER Added some more debugging statements for failed host lookups + SAH FIX Fixed Linux makefile - added "-lpthread" compiler option for asynch DNS +06-09-2006 1.07.35 SAH FEATURE Added asynchronous DNS lookup support for WIN32 (multi-threaded) +05-31-2006 1.07.34 SAH RELEASE Releasing to developer site +05-25-2006 1.07.33 SAH FIX Added GSI_UNUSED calls to get rid of PSP warnings + SAH FIX Changed PSP project warning levels + SAH FIX Fixed PS3 project to compile with 084_001 SDK +05-24-2006 1.07.32 SAH FIX Uncommented secure page test in gptestc.c +05-19-2006 1.07.31 SAH FIX Added gsTestMain.c to nitro CodeWarrior Project +05-18-2006 1.07.30 BED FIX Fixed bug with byte alignment for SSL on DS/PS3 + BED FIX Fixed bug where a line was mistakenly removed from previous version. +05-18-2006 1.07.29 DES RELEASE Limited developer release +05-18-2006 1.07.29 SAH FIX Added a check in ghiDoSend to ensure buffer != NULL and len != 0 +05-15-2006 1.07.28 SAH FIX Added "PS3 Release" configuration to project +05-08-2006 1.07.27 SAH FIX Fixed PS2 Project file (was missing gsXML) +05-02-2006 1.07.26 BED FIX Removed "expect continue" functionality that (may have) caused issues with some UK web proxies. +04-25-2006 1.07.25 SAH RELEASE Releasing to developer site +04-24-2006 1.07.25 SAH FIX added typecasts, fixed #includes to get rid of warnings in CW +04-20-2006 1.07.24 SAH FIX got rid of unused variables, switched GSI_USUNUSED above the returns +04-19-2006 1.07.23 SAH FIX Bill switched some byte ordering for PS3 compatibility +04-18-2006 1.07.22 SAH FIX Added || defined(_PS3) for PS3 support +04-13-2006 1.07.21 SAH FIX Replaced all (rcode == SOCKET_ERROR) w/ (gsiSocketIsError(rcode)) +02-21-2006 1.07.20 BED OTHER Adjusted debug output level for http continue. +01-26-2006 1.07.19 SN FIX Added psp to the test_main definition + SN OTHER Added and updated psp prodg project and solution +01-26-2006 1.07.18 BED FIX Added error checking between REQUEST and POST. + BED OTHER HTTPS requests now default to GameSpy SSL encryptor. + BED FIX Fixed an efficiency bug with plain text posts. +01-20-2006 1.07.17 BED FEATURE Added support for DIME attachments. +01-13-2006 1.07.16 BED FEATURE Added ghttpPostAddXml to support http soap requests. +12-16-2005 1.07.15 SN OTHER Cleaned up project files and added missing common code if any +11-17-2005 1.07.15 DES FIX Updated Nitro makefile. +11-14-2005 1.07.14 DES FIX Updated the makefiles and project files. + DES FIX Fixed a few minor HTTPS bugs. + DES FEATURE Updated MFC sample to work with HTTPS. +09-23-2005 1.07.13 DES FEATURE Updated DS support +07-28-2005 1.07.12 SN RELEASE Releasing to developer site. +07-28-2005 1.07.12 SN FEATURE Added HTTP SSL common code to projects +06-03-2005 1.07.11 SN RELEASE Releasing to developer site. +06-01-2004 1.07.11 SN FIX Fixed the function ghiParseStatus to find the status string after it checks for correct header information. +05-09-2005 1.07.10 BED FEATURE Added ghttpCloseRequest to handle graceful shutdowns +05-08-2005 1.07.09 DES FIX CompletedCallback now gets the file length for Save and Stream requests. +05-05-2005 1.07.08 BED FIX Updated project files to use new common folder +04-29-2005 1.07.07 SN OTHER Created Visual Studio .NET projects +04-28-2005 1.07.07 SN RELEASE Releasing to developer site. +04-27-2005 1.07.07 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 1.07.07 DES FEATURE Added debug logging. + DES CLEANUP Removed old commented-out code. + DES CLEANUP General cleanup of ghttpc. +04-12-2005 1.07.06 BED FIX Fixed bug where User-Agent header could appear twice. +04-04-2005 1.07.05 SN RELEASE Releasing to developer site. +03-29-2005 1.07.05 DES FIX Fixed warnings for internal functions +03-14-2005 1.07.04 DES FEATURE Nintendo DS support +01-12-2004 1.07.03 BED FIX Was missing a #ifdef around matrixssl.h +12-20-2004 1.07.02 BED FIX Fixed ghttpGetHeaders with SSL support. +12-06-2004 1.07.01 BED FEATURE Added initial support for SSL connections. +11-19-2004 1.07.00 DDW FEATURE Added internal support for persistent server connections +09-16-2004 1.06.25 SN RELEASE Releasing to developer site. +08-27-2004 1.06.25 DES CLEANUP Removed MacOS style includes + DES CLEANUP General Unicode cleanup + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Fixed warnings under OSX + DES CLEANUP Updated OSX Makefile +08-13-2004 1.06.24 SN FIX Changed asserts in ghiParseProxyServer to reflect the correct checks on parameters +08-04-2004 1.06.23 SN RELEASE Releasing to developer site. +07-19-2004 1.06.23 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +06-18-2004 1.06.22 BED RELEASE Releasing to developer site. +06-17-2004 1.06.22 BED FIX ghttpc sample no longer builds UNICODE mode by default + BED FEATURE Added PS2 Insock support +01-26-2004 1.06.21 BED FEATURE Added the ability to set a "proxy override" on each request. +11-10-2003 1.06.20 DES RELEASE Releasing to developer site. +11-07-2003 1.06.20 DES FIX Updated the linux makefile. +10-21-2003 1.06.19 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-20-2003 1.06.19 BED FEATURE Added ghttpSetMaxRecvTime() to prevent async downloads from blocking in special cases +01-05-2003 1.06.18 JED FEATURE Added download size checking and GHTTPFileToBig error code +09-30-2003 1.06.17 BED FEATURE Modified sample app to check (result < 0) instead of (result == -1) to handle additional error codes. +09-16-2003 1.06.16 JED FIX Added stringutil.c/h incudes to ghttp.dsp +09-08-2003 1.06.15 BED FEATURE Added wrapper for UNICODE support. (Two byte UNICODE converted to single byte ASCII) + BED FEATURE Added new return status "GHTTPFileIncomplete" to notify of a partial or interrupted download + BED FEATURE Added extra error return codes per JED request. To enable these define GHTTP_EXTENDEDERROR +07-24-2003 1.06.14 DES RELEASE Releasing to developer site. +07-18-2003 1.06.14 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 1.06.13 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 1.06.12 DES FIX Changed a __mips64 checks to a _PS2 check. + BED FEATURE Added ProDG sample project files. +07-15-2003 1.06.11 DES RELEASE Releasing to developer site. +07-10-2003 1.06.11 BED FIX Added newline to end of file to prevent compiler warning. +05-09-2003 1.06.10 DES CLEANUP Removed Dreamcast support. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +04-15-2003 1.06.09 JED CLEANUP More cleanup to remove a few DevStudio Level4 warnings +03-03-2003 1.06.08 DES CLEANUP General cleanup to remove warnings. +01-28-2003 1.06.07 DES FIX Fixed a bug which could cause a request to fail if a 1xx (Continue) + status response was received (common when posting). + CLEANUP Changed posting code to send no more than 32K in a single send() call. + Win98 was having trouble dealing with large blocks of data. +01-23-2003 1.06.06 DES FIX Replaced a malloc with gsimalloc. +01-15-2003 1.06.05 DES FIX Fixed a crashing bug involving parsing received data that started + with the last byte of a chunk header. +12-19-2002 1.06.04 DES RELEASE Releasing to developer site. +12-19-2002 1.06.04 DES CLEANUP Removed assert.h include. +12-16-2002 1.06.03 DES CLEANUP Removed call to GOAClearSocketError. +12-13-2002 1.06.02 DES FEATURE Added PS2 eenet stack support. + CLEANUP Cleaned up code to remove PS2 compiler warnings. +11-14-2002 1.06.01 DES FIX Send "Connection: close" in request header to be 1.1 compliant + FIX Fixed bug with reading end of chunked header + OTHER Removed "#if 1" block from around chunked transfer code + OTHER Each connection gets a unique ID (for debugging, not exposed in API) +09-25-2002 1.06.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/ghttp/ghttp.dsp b/xrGameSpy/gamespy/ghttp/ghttp.dsp new file mode 100644 index 00000000000..a1899677bb1 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttp.dsp @@ -0,0 +1,284 @@ +# Microsoft Developer Studio Project File - Name="ghttp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=ghttp - 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 "ghttp.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 "ghttp.mak" CFG="ghttp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ghttp - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "ghttp - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/ghttp", PHXAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ghttp - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "ghttp - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "ghttp - Win32 Release" +# Name "ghttp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=.\ghttpProcess.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ghttp.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpProcess.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/ghttp/ghttp.dsw b/xrGameSpy/gamespy/ghttp/ghttp.dsw new file mode 100644 index 00000000000..6aa040dfac0 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttp.dsw @@ -0,0 +1,69 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ghttp"=.\ghttp.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp", PHXAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ghttpc"=.\ghttpc\ghttpc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp/ghttpc", BUZAAAAA + .\ghttpc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ghttpmfc"=.\ghttpmfc\ghttpmfc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp/ghttpmfc", PUZAAAAA + .\ghttpmfc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp", PHXAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/ghttp/ghttp.h b/xrGameSpy/gamespy/ghttp/ghttp.h new file mode 100644 index 00000000000..8e72c503ac3 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttp.h @@ -0,0 +1,644 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTP_H_ +#define _GHTTP_H_ + +#include + +#include "../common/gsCommon.h" +#include "../common/gsXML.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GSI_UNICODE +#define ghttpGet ghttpGetA +#define ghttpGetEx ghttpGetExA +#define ghttpSave ghttpSaveA +#define ghttpSaveEx ghttpSaveExA +#define ghttpStream ghttpStreamA +#define ghttpStreamEx ghttpStreamExA +#define ghttpHead ghttpHeadA +#define ghttpHeadEx ghttpHeadExA +#define ghttpPost ghttpPostA +#define ghttpPostEx ghttpPostExA +#define ghttpPostAddString ghttpPostAddStringA +#define ghttpPostAddFileFromDisk ghttpPostAddFileFromDiskA +#define ghttpPostAddFileFromMemory ghttpPostAddFileFromMemoryA +#else +#define ghttpGet ghttpGetW +#define ghttpGetEx ghttpGetExW +#define ghttpSave ghttpSaveW +#define ghttpSaveEx ghttpSaveExW +#define ghttpStream ghttpStreamW +#define ghttpStreamEx ghttpStreamExW +#define ghttpHead ghttpHeadW +#define ghttpHeadEx ghttpHeadExW +#define ghttpPost ghttpPostW +#define ghttpPostEx ghttpPostExW +#define ghttpPostAddString ghttpPostAddStringW +#define ghttpPostAddFileFromDisk ghttpPostAddFileFromDiskW +#define ghttpPostAddFileFromMemory ghttpPostAddFileFromMemoryW +#endif + +// Boolean. +/////////// +typedef enum +{ + GHTTPFalse, + GHTTPTrue +} GHTTPBool; + +// ByteCount. +///////////// +#if (GSI_MAX_INTEGRAL_BITS >= 64) +typedef gsi_i64 GHTTPByteCount; +#else +typedef gsi_i32 GHTTPByteCount; +#endif + +// The current state of an http request. +//////////////////////////////////////// +typedef enum +{ + GHTTPSocketInit, // Socket creation and initialization. + GHTTPHostLookup, // Resolving hostname to IP (asynchronously if possible). + GHTTPLookupPending, // Asychronous DNS lookup pending. + GHTTPConnecting, // Waiting for socket connect to complete. + GHTTPSecuringSession, // Setup secure channel. + GHTTPSendingRequest, // Sending the request. + GHTTPPosting, // Positing data (skipped if not posting). + GHTTPWaiting, // Waiting for a response. + GHTTPReceivingStatus, // Receiving the response status. + GHTTPReceivingHeaders, // Receiving the headers. + GHTTPReceivingFile // Receiving the file. +} GHTTPState; + +// The result of an http request. +///////////////////////////////// +typedef enum +{ + GHTTPSuccess, // 0: Successfully retrieved file. + GHTTPOutOfMemory, // 1: A memory allocation failed. + GHTTPBufferOverflow, // 2: The user-supplied buffer was too small to hold the file. + GHTTPParseURLFailed, // 3: There was an error parsing the URL. + GHTTPHostLookupFailed, // 4: Failed looking up the hostname. + GHTTPSocketFailed, // 5: Failed to create/initialize/read/write a socket. + GHTTPConnectFailed, // 6: Failed connecting to the http server. + GHTTPBadResponse, // 7: Error understanding a response from the server. + GHTTPRequestRejected, // 8: The request has been rejected by the server. + GHTTPUnauthorized, // 9: Not authorized to get the file. + GHTTPForbidden, // 10: The server has refused to send the file. + GHTTPFileNotFound, // 11: Failed to find the file on the server. + GHTTPServerError, // 12: The server has encountered an internal error. + GHTTPFileWriteFailed, // 13: An error occured writing to the local file (for ghttpSaveFile[Ex]). + GHTTPFileReadFailed, // 14: There was an error reading from a local file (for posting files from disk). + GHTTPFileIncomplete, // 15: Download started but was interrupted. Only reported if file size is known. + GHTTPFileToBig, // 16: The file is to big to be downloaded (size exceeds range of interal data types) + GHTTPEncryptionError, // 17: Error with encryption engine. + GHTTPRequestCancelled // 18: User requested cancel and/or graceful close. +} GHTTPResult; + +// Encryption engines +typedef enum +{ + GHTTPEncryptionEngine_None, + GHTTPEncryptionEngine_GameSpy, // must add /common/gsSSL.h and /common/gsSSL.c to project + GHTTPEncryptionEngine_MatrixSsl, // must define MATRIXSSL and include matrixssl source files + GHTTPEncryptionEngine_RevoEx, // must define REVOEXSSL and include RevoEX SSL source files + + GHTTPEncryptionEngine_Default // Will use GameSpy unless another engine is defined + // using MATRIXSSL or REVOEXSSL +} GHTTPEncryptionEngine; + +// Represents an http file request. +/////////////////////////////////// +typedef int GHTTPRequest; + +// Invalid GHTTPRequest values represent an error +/////////////////////////////////// +#ifdef GHTTP_EXTENDEDERROR + typedef enum + { + GHTTPErrorStart = -8, + GHTTPFailedToOpenFile, + GHTTPInvalidPost, + GHTTPInsufficientMemory, + GHTTPInvalidFileName, + GHTTPInvalidBufferSize, + GHTTPInvalidURL, + GHTTPUnspecifiedError = -1 + } GHTTPRequestError; +#else + // Backwards compatibility, developers may have relied on -1 as the only error code + typedef enum + { + GHTTPErrorStart = -1, + GHTTPFailedToOpenFile = -1, + GHTTPInvalidPost = -1, + GHTTPInsufficientMemory = -1, + GHTTPInvalidFileName = -1, + GHTTPInvalidBufferSize = -1, + GHTTPInvalidURL = -1, + GHTTPUnspecifiedError = -1 + } GHTTPRequestError; +#endif + +#define IS_GHTTP_ERROR(x) (x<0) + +// Data that can be posted to the server. +// Don't try to access this object directly, +// use the ghttpPost*() functions. +//////////////////////////////////////////// +typedef struct GHIPost * GHTTPPost; + + +// Called with updates on the current state of the request. +// The buffer should not be accessed once this callback returns. +// If ghttpGetFile[Ex] was used, buffer contains all of the data that has been +// received so far, and bufferSize is the total number of bytes received. +// If ghttpSaveFile[Ex] was used, buffer only contains the most recent data +// that has been received. This same data is saved to the file. The buffer +// will not be valid after this callback returns. +// If ghttpStreamFileEx was used, buffer only contains the most recent data +// that has been received. This data will be lost once the callback +// returns, and should be copied if it needs to be saved. bufferSize +// is the number of bytes in the current block of data. +////////////////////////////////////////////////////////////////////////////// +typedef void (* ghttpProgressCallback) +( + GHTTPRequest request, // The request. + GHTTPState state, // The current state of the request. + const char * buffer, // The file's bytes so far, NULL if state[:port]". If port is omitted, 80 will be used. +// If server is NULL or "", no proxy server will be used. +// This should not be called while there are any current requests. +////////////////////////////////////////////////////////////////// +GHTTPBool ghttpSetProxy +( + const char * server +); + +// Sets a proxy server for a specific request. The address should be of the +// form "[:port]". If port is omitted, 80 will be used. +// If server is NULL or "", no proxy server will be used. +////////////////////////////////////////////////////////////////// +GHTTPBool ghttpSetRequestProxy +( + GHTTPRequest request, + const char * server +); + +// Used to start/stop throttling an existing connection. +// This may not be as efficient as starting a request +// with the desired setting. +//////////////////////////////////////////////////////// +void ghttpSetThrottle +( + GHTTPRequest request, + GHTTPBool throttle +); + +// Used to adjust the throttle settings. +//////////////////////////////////////// +void ghttpThrottleSettings +( + int bufferSize, // The number of bytes to get each receive. + gsi_time timeDelay // How often to receive data, in milliseconds. +); + +// Used to throttle based on time, not on bandwidth +// Prevents recv-loop blocking on ultrafast connections without directly limiting transfer rate +//////////////////////////////////////// +void ghttpSetMaxRecvTime +( + GHTTPRequest request, + gsi_time maxRecvTime +); + +// Creates a new post object, which is used to represent data to send to +// the web server as part of a request. +// After getting the post object, use the ghttpPostAdd*() functions +// to add data to the object, and ghttPostSetCallback() to add a +// callback to monitor the progress of the data upload. +// By default post objects automatically free themselves after posting. +// To use the same post with more than one request, set auto-free to false, +// then use ghttpFreePost to free it _after_ every request its being used +// in is _completed_. +// Returns NULL on error. +/////////////////////////////////////////////////////////////////////////// +GHTTPPost ghttpNewPost +( + void +); + +// Sets a post object's auto-free flag. +// By default post objects automatically free themselves after posting. +// To use the same post with more than one request, set auto-free to false, +// then use ghttpFreePost to free it _after_ every request its being used +// in is _completed_. +/////////////////////////////////////////////////////////////////////////// +void ghttpPostSetAutoFree +( + GHTTPPost post, + GHTTPBool autoFree +); + +// Frees a post object. +/////////////////////// +void ghttpFreePost +( + GHTTPPost post // The post object to free. +); + +// Adds a string to the post object. +//////////////////////////////////// +GHTTPBool ghttpPostAddString +( + GHTTPPost post, // The post object to add to. + const gsi_char * name, // The name to attach to this string. + const gsi_char * string // The actual string. +); + +// Adds a disk file to the post object. +// The reportFilename is what is reported to the server as the filename. +// If NULL or empty, the filename will be used (including any possible path). +// The contentType is the MIME type to report for this file. +// If NULL, "application/octet-stream" is used. +// The file isn't read from until the data is actually sent to the server. +// Returns false for any error. +///////////////////////////////////////////////////////////////////////////// +GHTTPBool ghttpPostAddFileFromDisk +( + GHTTPPost post, // The post object to add to. + const gsi_char * name, // The name to attach to this file. + const gsi_char * filename, // The name (and possibly path) to the file to upload. + const gsi_char * reportFilename,// The filename given to the web server. + const gsi_char * contentType // The MIME type for this file. +); + +// Adds a file, in memory, to the post object. +// The reportFilename is what is reported to the server as the filename. +// Cannot be NULL or empty. +// The contentType is the MIME type to report for this file. +// If NULL, "application/octet-stream" is used. +// The data is NOT copied off in this call. The data pointer is read from +// as the data is actually sent to the server. The pointer must remain +// valid during requests. +// Returns false for any error. +////////////////////////////////////////////////////////////////////////// +GHTTPBool ghttpPostAddFileFromMemory +( + GHTTPPost post, // The post object to add to. + const gsi_char * name, // The name to attach to this string. + const char * buffer, // The data to send. + int bufferLen, // The number of bytes of data to send. + const gsi_char * reportFilename, // The filename given to the web server. + const gsi_char * contentType // The MIME type for this file. +); + +// Adds an XML SOAP object to the post object. +// See ghttpNewSoap and other Soap related functions +// Content-Type = text/xml +// The most common use of this function is to add ghttpSoap data +GHTTPBool ghttpPostAddXml +( + GHTTPPost post, + GSXmlStreamWriter xmlSoap +); + +// Called during requests to let the app know how much of the post +// data has been uploaded. +////////////////////////////////////////////////////////////////// +typedef void (* ghttpPostCallback) +( + GHTTPRequest request, // The request. + int bytesPosted, // The number of bytes of data posted so far. + int totalBytes, // The total number of bytes being posted. + int objectsPosted, // The total number of data objects uploaded so far. + int totalObjects, // The total number of data objects to upload. + void * param // User-data. +); + +// Set the callback for a post object. +////////////////////////////////////// +void ghttpPostSetCallback +( + GHTTPPost post, // The post object to set the callback on. + ghttpPostCallback callback, // The callback to call when using this post object. + void * param // User-data passed to the callback. +); + +// Use ssl encryption engine +GHTTPBool ghttpSetRequestEncryptionEngine +( + GHTTPRequest request, + GHTTPEncryptionEngine engine +); + + +// These are defined for backwards compatibility with the "file" function names. +//////////////////////////////////////////////////////////////////////////////// +#define ghttpGetFile(a, b, c, d) ghttpGet(a, b, c, d) +#define ghttpGetFileEx(a, b, c, d, e, f, g, h, i, j) ghttpGetEx(a, b, c, d, e, f, g, h, i, j) +#define ghttpSaveFile(a, b, c, d, e) ghttpSave(a, b, c, d, e) +#define ghttpSaveFileEx(a, b, c, d, e, f, g, h, i) ghttpSaveEx(a, b, c, d, e, f, g, h, i) +#define ghttpStreamFile(a, b, c, d, e) ghttpStream(a, b, c, d, e) +#define ghttpStreamFileEx(a, b, c, d, e, f, g, h) ghttpStreamEx(a, b, c, d, e, f, g, h) +#define ghttpHeadFile(a, b, c, d) ghttpHead(a, b, c, d) +#define ghttpHeadFileEx(a, b, c, d, e, f, g) ghttpHeadEx(a, b, c, d, e, f, g) + +// This ASCII version needs to be define even in UNICODE mode +GHTTPRequest ghttpGetA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. +); +#define ghttpGetFileA(a, b, c, d) ghttpGetA(a, b, c, d) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpASCII.h b/xrGameSpy/gamespy/ghttp/ghttpASCII.h new file mode 100644 index 00000000000..6c427e06a4d --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpASCII.h @@ -0,0 +1,270 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +// ASCII PROTOTYPES FOR USE IN UNICODE MODE +// INCLUDED TO SILENCE CODEWARRIOR WARNINGS +#ifndef _GHTTPASCII_H_ +#define _GHTTPASCII_H_ + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Get a file from an http server. +// Returns GHTTPRequestError if an error occurs. +////////////////////////////////// +GHTTPRequest ghttpGetA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. +); + +// Get a file from an http server. +// Returns GHTTPRequestError if an error occurs. +// Allows an optional user-supplied buffer to be used, +// optional extra http headers, +// and an optional progress callback. +// The optional headers must be 0 or more HTTP headers, +// each terminated by a CR-LF pair (0xD, 0xA). +// If using a user-supplied buffer: +// set buffer to the buffer to use, +// set bufferSize to the size of the buffer in bytes. +// To have the library allocate a buffer: +// set buffer to NULL, set bufferSize to 0 +/////////////////////////////////////////////////////// +GHTTPRequest ghttpGetExA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const char * headers, // Optional headers to pass with the request. Can be NULL or "". + char * buffer, // Optional user-supplied buffer. Set to NULL to have one allocated. + int bufferSize, // The size of the user-supplied buffer in bytes. 0 if buffer is NULL. + GHTTPPost post, // Optional data to be posted. + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpProgressCallback progressCallback, // Called periodically with progress updates. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. +); + +// Gets a file and saves it to disk. +// Returns GHTTPRequestError if an error occurs. +//////////////////////////////////// +GHTTPRequest ghttpSaveA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const char * filename, // The path and name to store the file as locally. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. +); + +// Gets a file and saves it to disk. +// Returns GHTTPRequestError if an error occurs. +// Allows optional extra http headers and +// an optional progress callback. +///////////////////////////////////////// +GHTTPRequest ghttpSaveExA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const char * filename, // The path and name to store the file as locally. + const char * headers, // Optional headers to pass with the request. Can be NULL or "". + GHTTPPost post, // Optional data to be posted. + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpProgressCallback progressCallback, // Called periodically with progress updates. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. +); + +// Streams a file from an http server. +// Returns GHTTPRequestError if an error occurs. +////////////////////////////////////// +GHTTPRequest ghttpStreamA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + GHTTPBool blocking, // If true, this call doesn't return until the file has finished streaming. + ghttpProgressCallback progressCallback, // Called whenever new data is received. + ghttpCompletedCallback completedCallback, // Called when the file has finished streaming. + void * param // User-data to be passed to the callbacks. +); + +// Streams a file from an http server. +// Returns GHTTPRequestError if an error occurs. +// Allows optional extra http headers. +////////////////////////////////////// +GHTTPRequest ghttpStreamExA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const char * headers, // Optional headers to pass with the request. Can be NULL or "". + GHTTPPost post, // Optional data to be posted. + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until the file has finished streaming. + ghttpProgressCallback progressCallback, // Called whenever new data is received. + ghttpCompletedCallback completedCallback, // Called when the file has finished streaming. + void * param // User-data to be passed to the callbacks. +); + +// Does a file request without actually getting the file. +// Use this to check the headers returned by a server when a request is made. +// Returns GHTTPRequestError if an error occurs. +///////////////////////////////////////////////////////////////////////////// +GHTTPRequest ghttpHeadA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + GHTTPBool blocking, // If true, this call doesn't return until finished + ghttpCompletedCallback completedCallback, // Called when the request has finished. + void * param // User-data to be passed to the callbacks. +); + +// Does a file request without actually getting the file. +// Use this to check the headers returned by a server when a request is made. +// Returns GHTTPRequestError if an error occurs. +// Allows optional extra http headers. +///////////////////////////////////////////////////////////////////////////// +GHTTPRequest ghttpHeadExA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const char * headers, // Optional headers to pass with the request. Can be NULL or "". + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until finished + ghttpProgressCallback progressCallback, // Called whenever new data is received. + ghttpCompletedCallback completedCallback, // Called when the request has finished. + void * param // User-data to be passed to the callbacks. +); + +// Does an HTTP POST, which can be used to upload data to a web server. +// The post parameter must be a valid GHTTPPost, setup with the data to be uploaded. +// No data will be returned from this request. If data is needed, use one of the +// ghttp*FileEx() functions, and pass in a GHTTPPost object. +// Returns GHTTPRequestError if an error occurs. +/////////////////////////////////////////////////////////////////////////////////// +GHTTPRequest ghttpPostA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + GHTTPPost post, // The data to be posted. + GHTTPBool blocking, // If true, this call doesn't return until finished + ghttpCompletedCallback completedCallback, // Called when the file has finished streaming. + void * param // User-data to be passed to the callbacks. +); + +// Does an HTTP POST, which can be used to upload data to a web server. +// The post parameter must be a valid GHTTPPost, setup with the data to be uploaded. +// No data will be returned from this request. If data is needed, use one of the +// ghttp*FileEx() functions, and pass in a GHTTPPost object. +// Returns GHTTPRequestError if an error occurs. +// Allows optional extra http headers and +// an optional progress callback. +/////////////////////////////////////////////////////////////////////////////////// +GHTTPRequest ghttpPostExA +( + const char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const char * headers, // Optional headers to pass with the request. Can be NULL or "". + GHTTPPost post, // The data to be posted. + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until finished + ghttpProgressCallback progressCallback, // Called whenever new data is received. + ghttpCompletedCallback completedCallback, // Called when the file has finished streaming. + void * param // User-data to be passed to the callbacks. +); + + +// Gets the status code and status string for a request. +// A pointer to the status string is returned, or NULL on error. +// Only valid if the GHTTPState for this request +// is greater than GHTTPReceivingStatus. +//////////////////////////////////////////////////////////////// +const char * ghttpGetResponseStatus +( + GHTTPRequest request, // The request to get the response state of. + int * statusCode // If not NULL, the status code is stored here. +); + +// Gets headers returned by the http server. +// Only valid if the GHTTPState for this +// request is GHTTPReceivingFile. +//////////////////////////////////////////// +const char * ghttpGetHeaders +( + GHTTPRequest request +); + +// Gets the URL for a given request. +//////////////////////////////////// +const char * ghttpGetURL +( + GHTTPRequest request +); + +// Sets a proxy server address. The address should be of the +// form "[:port]". If port is omitted, 80 will be used. +// If server is NULL or "", no proxy server will be used. +// This should not be called while there are any current requests. +////////////////////////////////////////////////////////////////// +GHTTPBool ghttpSetProxyA +( + const char * server +); + +// Adds a string to the post object. +//////////////////////////////////// +GHTTPBool ghttpPostAddStringA +( + GHTTPPost post, // The post object to add to. + const char * name, // The name to attach to this string. + const char * string // The actual string. +); + +// Adds a disk file to the post object. +// The reportFilename is what is reported to the server as the filename. +// If NULL or empty, the filename will be used (including any possible path). +// The contentType is the MIME type to report for this file. +// If NULL, "application/octet-stream" is used. +// The file isn't read from until the data is actually sent to the server. +// Returns false for any error. +///////////////////////////////////////////////////////////////////////////// +GHTTPBool ghttpPostAddFileFromDiskA +( + GHTTPPost post, // The post object to add to. + const char * name, // The name to attach to this file. + const char * filename, // The name (and possibly path) to the file to upload. + const char * reportFilename,// The filename given to the web server. + const char * contentType // The MIME type for this file. +); + +// Adds a file, in memory, to the post object. +// The reportFilename is what is reported to the server as the filename. +// Cannot be NULL or empty. +// The contentType is the MIME type to report for this file. +// If NULL, "application/octet-stream" is used. +// The data is NOT copied off in this call. The data pointer is read from +// as the data is actually sent to the server. The pointer must remain +// valid during requests. +// Returns false for any error. +////////////////////////////////////////////////////////////////////////// +GHTTPBool ghttpPostAddFileFromMemoryA +( + GHTTPPost post, // The post object to add to. + const char * name, // The name to attach to this string. + const char * buffer, // The data to send. + int bufferLen, // The number of bytes of data to send. + const char * reportFilename, // The filename given to the web server. + const char * contentType // The MIME type for this file. +); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpBuffer.c b/xrGameSpy/gamespy/ghttp/ghttpBuffer.c new file mode 100644 index 00000000000..a70ad673387 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpBuffer.c @@ -0,0 +1,561 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "ghttpBuffer.h" +#include "ghttpConnection.h" +#include "ghttpMain.h" +#include "ghttpCommon.h" +#include "../common/gsCrypt.h" +#include "../common/gsSSL.h" + + +// Resize the buffer. +///////////////////// +GHTTPBool ghiResizeBuffer +( + GHIBuffer * buffer, + int sizeIncrement +) +{ + char * tempPtr; + int newSize; + + assert(buffer); + assert(sizeIncrement > 0); + assert(buffer->fixed == GHTTPFalse); // implied by sizeIncrement > 0 + + // Check args. + ////////////// + if(!buffer) + return GHTTPFalse; + if(sizeIncrement <= 0) + return GHTTPFalse; + + // Reallocate with the bigger size. + /////////////////////////////////// + newSize = (buffer->size + sizeIncrement); + tempPtr = (char *)gsirealloc(buffer->data, (unsigned int)newSize); + if(!tempPtr) + return GHTTPFalse; + + // Set the new info. + //////////////////// + buffer->data = tempPtr; + buffer->size = newSize; + + return GHTTPTrue; +} + +GHTTPBool ghiInitBuffer +( + struct GHIConnection * connection, + GHIBuffer * buffer, + int initialSize, + int sizeIncrement +) +{ + GHTTPBool bResult; + + assert(connection); + assert(buffer); + assert(initialSize > 0); + assert(sizeIncrement > 0); + + // Check args. + ////////////// + if(!connection) + return GHTTPFalse; + if(!buffer) + return GHTTPFalse; + if(initialSize <= 0) + return GHTTPFalse; + if(sizeIncrement <= 0) + return GHTTPFalse; + + // Init the struct. + /////////////////// + buffer->connection = connection; + buffer->data = NULL; + buffer->size = 0; + buffer->len = 0; + buffer->pos = 0; + buffer->sizeIncrement = sizeIncrement; + buffer->fixed = GHTTPFalse; + buffer->dontFree = GHTTPFalse; + buffer->readOnly = GHTTPFalse; + + // Do the initial resize. + ///////////////////////// + bResult = ghiResizeBuffer(buffer, initialSize); + if(!bResult) + return GHTTPFalse; + + // Start with an empty string. + ////////////////////////////// + *buffer->data = '\0'; + + return GHTTPTrue; +} + +GHTTPBool ghiInitFixedBuffer +( + struct GHIConnection * connection, + GHIBuffer * buffer, + char * userBuffer, + int size +) +{ + assert(connection); + assert(buffer); + assert(userBuffer); + assert(size > 0); + + // Check args. + ////////////// + if(!connection) + return GHTTPFalse; + if(!buffer) + return GHTTPFalse; + if(!userBuffer) + return GHTTPFalse; + if(size <= 0) + return GHTTPFalse; + + // Init the struct. + /////////////////// + buffer->connection = connection; + buffer->data = userBuffer; + buffer->size = size; + buffer->len = 0; + buffer->pos = 0; + buffer->sizeIncrement = 0; + buffer->fixed = GHTTPTrue; + buffer->dontFree = GHTTPTrue; + buffer->readOnly = GHTTPFalse; + + // Start with an empty string. + ////////////////////////////// + *buffer->data = '\0'; + + return GHTTPTrue; +} + +GHTTPBool ghiInitReadOnlyBuffer +( + struct GHIConnection * connection, // The connection. + GHIBuffer * buffer, // The buffer to init. + const char * userBuffer, // The user-buffer to use. + int size // The size of the buffer. +) +{ + assert(connection); + assert(buffer); + assert(userBuffer); + assert(size > 0); + + // Check args. + ////////////// + if(!connection) + return GHTTPFalse; + if(!buffer) + return GHTTPFalse; + if(!userBuffer) + return GHTTPFalse; + if(size <= 0) + return GHTTPFalse; + + // Init the struct. + /////////////////// + buffer->connection = connection; + buffer->data = (char*)userBuffer; // cast away const + buffer->size = size; + buffer->pos = 0; + buffer->sizeIncrement = 0; + buffer->fixed = GHTTPTrue; + buffer->dontFree = GHTTPTrue; + buffer->readOnly = GHTTPTrue; + + // Start with user supplied data + ////////////////////////////// + buffer->len = size; + + return GHTTPTrue; +} + +void ghiFreeBuffer +( + GHIBuffer * buffer +) +{ + assert(buffer); + + // Check args. + ////////////// + if(!buffer) + return; + if(!buffer->data) + return; + + // Cleanup the struct. + ////////////////////// + if(!buffer->dontFree) + gsifree(buffer->data); + memset(buffer, 0, sizeof(GHIBuffer)); +} + +GHTTPBool ghiAppendDataToBuffer +( + GHIBuffer * buffer, + const char * data, + int dataLen +) +{ + GHTTPBool bResult; + int newLen; + + assert(buffer); + assert(data); + assert(dataLen >= 0); + + // Check args. + ////////////// + if(!buffer) + return GHTTPFalse; + if(!data) + return GHTTPFalse; + if(dataLen < 0) + return GHTTPFalse; + if (buffer->readOnly) + return GHTTPFalse; + + // Get the string length if needed. + /////////////////////////////////// + if(dataLen == 0) + dataLen = (int)strlen(data); + + // Get the new length. + ////////////////////// + newLen = (buffer->len + dataLen); + + // Make sure the array is big enough. + ///////////////////////////////////// + while(newLen >= buffer->size) + { + // Check for a fixed buffer. + //////////////////////////// + if(buffer->fixed) + { + buffer->connection->completed = GHTTPTrue; + buffer->connection->result = GHTTPBufferOverflow; + return GHTTPFalse; + } + + bResult = ghiResizeBuffer(buffer, buffer->sizeIncrement); + if(!bResult) + { + buffer->connection->completed = GHTTPTrue; + buffer->connection->result = GHTTPOutOfMemory; + return GHTTPFalse; + } + } + + // Add the data. + //////////////// + memcpy(buffer->data + buffer->len, data, (unsigned int)dataLen); + buffer->len = newLen; + buffer->data[buffer->len] = '\0'; + return GHTTPTrue; +} + + +// Use sparingly. This function wraps the data in an SSL record. +GHTTPBool ghiEncryptDataToBuffer +( + GHIBuffer * buffer, + const char * data, + int dataLen +) +{ + GHIEncryptionResult result; + int bufSpace = 0; + int pos = 0; + + assert(buffer); + assert(data); + assert(dataLen >= 0); + + // Check args. + ////////////// + if(!buffer) + return GHTTPFalse; + if(!data) + return GHTTPFalse; + if(dataLen < 0) + return GHTTPFalse; + if (buffer->readOnly) + return GHTTPFalse; + + // Switch to plain text append when not using SSL + if (buffer->connection->encryptor.mEngine == GHTTPEncryptionEngine_None || + buffer->connection->encryptor.mSessionEstablished == GHTTPFalse) + { + return ghiAppendDataToBuffer(buffer, data, dataLen); + } + + // Get the string length if needed. + /////////////////////////////////// + if(dataLen == 0) + dataLen = (int)strlen(data); + if (dataLen == 0) + return GHTTPTrue; // no data and strlen == 0 + bufSpace = buffer->size - buffer->len; + + do + { + int fragmentLen = min(dataLen, GS_SSL_MAX_CONTENTLENGTH); + + // Call the encryptor function + // bufSize is reduced by the number of bytes written + result = buffer->connection->encryptor.mEncryptFunc(buffer->connection, &buffer->connection->encryptor, + &data[pos], dataLen, + &buffer->data[buffer->len], &bufSpace); + if (result == GHIEncryptionResult_BufferTooSmall) + { + if (ghiResizeBuffer(buffer, buffer->sizeIncrement) == GHTTPFalse) + return GHTTPFalse; + bufSpace = buffer->size - buffer->len; + } + else if (result == GHIEncryptionResult_Success) + { + // update data and buffer positions + pos += fragmentLen; + buffer->len = buffer->size - bufSpace; + } + else + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "ghiEncryptDataToBuffer encountered unhandled return code: %d\r\n", result); + return GHTTPFalse; + } + } while(pos < dataLen); + + return GHTTPTrue; +} + +GHTTPBool ghiAppendHeaderToBuffer +( + GHIBuffer * buffer, + const char * name, + const char * value +) +{ + if(!ghiAppendDataToBuffer(buffer, name, 0)) + return GHTTPFalse; + if(!ghiAppendDataToBuffer(buffer, ": ", 2)) + return GHTTPFalse; + if(!ghiAppendDataToBuffer(buffer, value, 0)) + return GHTTPFalse; + if(!ghiAppendDataToBuffer(buffer, CRLF, 2)) + return GHTTPFalse; + + return GHTTPTrue; +} + +GHTTPBool ghiAppendCharToBuffer +( + GHIBuffer * buffer, + int c +) +{ + GHTTPBool bResult; + assert(buffer); + + // Check args. + ////////////// + if(!buffer) + return GHTTPFalse; + if (buffer->readOnly) + return GHTTPFalse; + + // Make sure the array is big enough. + ///////////////////////////////////// + if((buffer->len + 1) >= buffer->size) + { + // Check for a fixed buffer. + //////////////////////////// + if(buffer->fixed) + { + buffer->connection->completed = GHTTPTrue; + buffer->connection->result = GHTTPBufferOverflow; + return GHTTPFalse; + } + + bResult = ghiResizeBuffer(buffer, buffer->sizeIncrement); + if(!bResult) + { + buffer->connection->completed = GHTTPTrue; + buffer->connection->result = GHTTPOutOfMemory; + return GHTTPFalse; + } + } + + // Add the char. + //////////////// + buffer->data[buffer->len] = (char)(c & 0xFF); + buffer->len++; + buffer->data[buffer->len] = '\0'; + + return GHTTPTrue; +} + +GHTTPBool ghiAppendIntToBuffer +( + GHIBuffer * buffer, + int i +) +{ + char intValue[16]; + + sprintf(intValue, "%d", i); + + return ghiAppendDataToBuffer(buffer, intValue, 0); +} + +void ghiResetBuffer +( + GHIBuffer * buffer +) +{ + assert(buffer); + + buffer->len = 0; + buffer->pos = 0; + + // Start with an empty string. + ////////////////////////////// + if (!buffer->readOnly) + *buffer->data = '\0'; +} + +GHTTPBool ghiSendBufferedData +( + struct GHIConnection * connection +) +{ + int rcode; + int writeFlag; + int exceptFlag; + char * data; + int len; + + // Loop while we can send. + ////////////////////////// + do + { + rcode = GSISocketSelect(connection->socket, NULL, &writeFlag, &exceptFlag); + if((gsiSocketIsError(rcode)) || ((rcode == 1) && exceptFlag)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPSocketFailed; + if(gsiSocketIsError(rcode)) + connection->socketError = GOAGetLastError(connection->socket); + else + connection->socketError = 0; + return GHTTPFalse; + } + if((rcode < 1) || !writeFlag) + { + // Can't send anything. + /////////////////////// + return GHTTPTrue; + } + + // Figure out what, and how much, to send. + ////////////////////////////////////////// + data = (connection->sendBuffer.data + connection->sendBuffer.pos); + len = (connection->sendBuffer.len - connection->sendBuffer.pos); + + // Do the send. + /////////////// + rcode = ghiDoSend(connection, data, len); + if(gsiSocketIsError(rcode)) + return GHTTPFalse; + + // Update the position. + /////////////////////// + connection->sendBuffer.pos += rcode; + } + while(connection->sendBuffer.pos < connection->sendBuffer.len); + + return GHTTPTrue; +} + + +// Read data from a buffer +GHTTPBool ghiReadDataFromBuffer +( + GHIBuffer * bufferIn, // the GHIBuffer to read from + char bufferOut[], // the raw buffer to write to + int * len // max number of bytes to append, becomes actual length written +) +{ + int bytesAvailable = 0; + int bytesToCopy = 0; + + + // Verify parameters + assert(bufferIn != NULL); + assert(len != NULL); + if (*len == 0) + return GHTTPFalse; + + // Make sure the bufferIn isn't emtpy + bytesAvailable = (int)bufferIn->len - bufferIn->pos; + if (bytesAvailable <= 0) + return GHTTPFalse; + + // Calculate the actual number of bytes to copy + bytesToCopy = min(*len-1, bytesAvailable); + + // Copy the bytes + memcpy(bufferOut, bufferIn->data + bufferIn->pos, (size_t)bytesToCopy); + bufferOut[bytesToCopy] = '\0'; + *len = bytesToCopy; + + // Adjust the bufferIn read position + bufferIn->pos += bytesToCopy; + return GHTTPTrue; +} + + +// Read data from a buffer with a garunteed length +GHTTPBool ghiReadDataFromBufferFixed +( + GHIBuffer * bufferIn, // the GHIBuffer to read from + char bufferOut[], // the raw buffer to write to + int bytesToCopy // number of bytes to read +) +{ + // Verify parameters + assert(bufferIn != NULL); + if (bytesToCopy == 0) + return GHTTPTrue; + + // Make sure the bufferIn isn't too small + if (bufferIn->len < bytesToCopy) + return GHTTPFalse; + + // Copy the bytes + memcpy(bufferOut, bufferIn->data + bufferIn->pos, (size_t)bytesToCopy); + + // Adjust the bufferIn read position + bufferIn->pos += bytesToCopy; + return GHTTPTrue; +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpBuffer.h b/xrGameSpy/gamespy/ghttp/ghttpBuffer.h new file mode 100644 index 00000000000..3aea4a3e45d --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpBuffer.h @@ -0,0 +1,170 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPBUFFER_H_ +#define _GHTTPBUFFER_H_ + +#include "ghttpMain.h" +#include "ghttpEncryption.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// A data buffer. +///////////////// +typedef struct GHIBuffer +{ + struct GHIConnection * connection; // The connection. + char * data; // The actual bytes of data. + int size; // The number of bytes allocated for data. + int len; // The number of actual data bytes filled in. + int pos; // A marker to keep track of position. + int sizeIncrement; // How much to increment the buffer by when needed. + GHTTPBool fixed; // If true, don't resize the buffer. + GHTTPBool dontFree; // Don't free the data when the buffer is cleaned up. + GHTTPBool readOnly; // Read Only, write operations will fail +} GHIBuffer; + +// Initializes a buffer and allocates the initial data bytes. +// The initialSize and sizeIncrement must both be >0. +///////////////////////////////////////////////////////////// +GHTTPBool ghiInitBuffer +( + struct GHIConnection * connection, // The connection. + GHIBuffer * buffer, // The buffer to init. + int initialSize, // The initial size of the buffer. + int sizeIncrement // The size increment for the buffer. +); + +// Initializes a fixed-size buffer. This will not get resized. +/////////////////////////////////////////////////////////////// +GHTTPBool ghiInitFixedBuffer +( + struct GHIConnection * connection, // The connection. + GHIBuffer * buffer, // The buffer to init. + char * userBuffer, // The user-buffer to use. + int size // The size of the buffer. +); + +// Initializes a read-only fixed-size buffer. This will not get resized. +/////////////////////////////////////////////////////////////// +GHTTPBool ghiInitReadOnlyBuffer +( + struct GHIConnection * connection, // The connection. + GHIBuffer * buffer, // The buffer to init. + const char * userBuffer, // The user-buffer to use. + int size // The size of the buffer. +); + +// Free's a buffer's allocated memory (does +// not free the actual GHIBuffer structure). +//////////////////////////////////////////// +void ghiFreeBuffer +( + GHIBuffer * buffer +); + +// Appends data to the buffer. +// If data is a NUL-terminated string, 0 can be +// used for dataLen to use the length of the string. +//////////////////////////////////////////////////// +GHTTPBool ghiAppendDataToBuffer +( + GHIBuffer * buffer, // The buffer to append to. + const char * data, // The data to append. + int dataLen // The number of bytes of data to append, 0 for NUL-terminated string. +); + +// Appends data to the buffer, wrapped in an SSL record +// If data is a NUL-terminated string, 0 can be +// used for dataLen to use the length of the string. +// Encryption has some size overhead, so call this sparingly. +//////////////////////////////////////////////////// +GHTTPBool ghiEncryptDataToBuffer +( + GHIBuffer * buffer, // The buffer to append to. + const char * data, // The data to append. + int dataLen // The number of bytes of data to append, 0 for NUL-terminated string. +); + +// Appends a header to the buffer. +// Both the name and value must be NUL-terminated. +// The header will be added to the buffer as: +// : \n +////////////////////////////////////////////////// +GHTTPBool ghiAppendHeaderToBuffer +( + GHIBuffer * buffer, // The buffer to append to. + const char * name, // The name of the header. + const char * value // The value of the header. +); + +// Appends a single character to the buffer. +//////////////////////////////////////////// +GHTTPBool ghiAppendCharToBuffer +( + GHIBuffer * buffer, // The buffer to append to. + int c // The char to append. +); + +// Read data from a buffer +GHTTPBool ghiReadDataFromBuffer +( + GHIBuffer * bufferIn, // the GHIBuffer to read from + char bufferOut[], // the raw buffer to write to + int * len // max number of bytes to append, becomes actual length written +); + +// Read a fixed number of bytes from a buffer +GHTTPBool ghiReadDataFromBufferFixed +( + GHIBuffer * bufferIn, + char bufferOut[], + int len +); + +// Converts the int to a string and appends it to the buffer. +///////////////////////////////////////////////////////////// +GHTTPBool ghiAppendIntToBuffer +( + GHIBuffer * buffer, // The buffer to append to. + int i // The int to append. +); + +// Resets a buffer. +// Does this by setting both len and pos to 0. +////////////////////////////////////////////// +void ghiResetBuffer +( + GHIBuffer * buffer // The buffer to reset. +); + +// Sends as much buffer data as it can. +// Returns false if there was an error. +/////////////////////////////////////// +GHTTPBool ghiSendBufferedData +( + struct GHIConnection * connection +); + +// Increases the size of a buffer. +// This happens automatically when using the ghiAppend* functions +GHTTPBool ghiResizeBuffer +( + GHIBuffer * buffer, + int sizeIncrement +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpCallbacks.c b/xrGameSpy/gamespy/ghttp/ghttpCallbacks.c new file mode 100644 index 00000000000..7fecb00096c --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpCallbacks.c @@ -0,0 +1,114 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "ghttpCallbacks.h" +#include "ghttpPost.h" + +void ghiCallCompletedCallback +( + GHIConnection * connection +) +{ + GHTTPBool freeBuffer; + char * buffer; + GHTTPByteCount bufferLen; + + assert(connection); + +#ifdef GSI_COMMON_DEBUG + if(connection->result != GHTTPSuccess) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Socket Error: %d\n", connection->socketError); + } +#endif + + // Check for no callback. + ///////////////////////// + if(!connection->completedCallback) + return; + + // Figure out the buffer/bufferLen parameters. + ////////////////////////////////////////////// + if(connection->type == GHIGET) + { + buffer = connection->getFileBuffer.data; + } + else + { + buffer = NULL; + } + bufferLen = connection->fileBytesReceived; + + // Call the callback. + ///////////////////// + freeBuffer = connection->completedCallback( + connection->request, + connection->result, + buffer, + bufferLen, + connection->callbackParam); + + // Check for gsifree. + ////////////////// + if(buffer && !freeBuffer) + connection->getFileBuffer.dontFree = GHTTPTrue; +} + +void ghiCallProgressCallback +( + GHIConnection * connection, + const char * buffer, + GHTTPByteCount bufferLen +) +{ + assert(connection); + + // Check for no callback. + ///////////////////////// + if(!connection->progressCallback) + return; + + // Call the callback. + ///////////////////// + connection->progressCallback( + connection->request, + connection->state, + buffer, + bufferLen, + connection->fileBytesReceived, + connection->totalSize, + connection->callbackParam + ); +} + +void ghiCallPostCallback +( + GHIConnection * connection +) +{ + assert(connection); + + // Check for no callback. + ///////////////////////// + if(!connection->postingState.callback) + return; + + // Call the callback. + ///////////////////// + connection->postingState.callback( + connection->request, + connection->postingState.bytesPosted, + connection->postingState.totalBytes, + connection->postingState.index, + ArrayLength(connection->postingState.states), + connection->callbackParam + ); +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpCallbacks.h b/xrGameSpy/gamespy/ghttp/ghttpCallbacks.h new file mode 100644 index 00000000000..d53835aafa7 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpCallbacks.h @@ -0,0 +1,48 @@ +/* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPCALLBACKS_H_ +#define _GHTTPCALLBACKS_H_ + +#include "ghttpMain.h" +#include "ghttpConnection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Call the completed callback for this connection. +/////////////////////////////////////////////////// +void ghiCallCompletedCallback +( + GHIConnection * connection +); + +// Call the progress callback for this connection. +////////////////////////////////////////////////// +void ghiCallProgressCallback +( + GHIConnection * connection, + const char * buffer, + GHTTPByteCount bufferLen +); + +// Call the post callback for this connection. +////////////////////////////////////////////// +void ghiCallPostCallback +( + GHIConnection * connection +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpCommon.c b/xrGameSpy/gamespy/ghttp/ghttpCommon.c new file mode 100644 index 00000000000..ee402b8531f --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpCommon.c @@ -0,0 +1,597 @@ +/* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "ghttpCommon.h" + +// Disable compiler warnings for issues that are unavoidable. +///////////////////////////////////////////////////////////// +#if defined(_MSC_VER) // DevStudio +// Level4, "conditional expression is constant". +// Occurs with use of the MS provided macro FD_SET +#pragma warning ( disable: 4127 ) +#endif // _MSC_VER + +#ifdef WIN32 +// A lock. +////////// +typedef void * GLock; + +// The lock used by ghttp. +////////////////////////// +static GLock ghiGlobalLock; +#endif + +// Proxy server. +//////////////// +char * ghiProxyAddress; +unsigned short ghiProxyPort; + +// Throttle settings. +///////////////////// +int ghiThrottleBufferSize = 125; +gsi_time ghiThrottleTimeDelay = 250; + +// Number of connections +///////////////////// +extern int ghiNumConnections; + + +#ifdef WIN32 +// Creates a lock. +////////////////// +static GLock GNewLock(void) +{ + CRITICAL_SECTION * criticalSection; + + criticalSection = (CRITICAL_SECTION *)gsimalloc(sizeof(CRITICAL_SECTION)); + if(!criticalSection) + return NULL; + + InitializeCriticalSection(criticalSection); + + return (GLock)criticalSection; +} + +// Frees a lock. +//////////////// +static void GFreeLock(GLock lock) +{ + CRITICAL_SECTION * criticalSection = (CRITICAL_SECTION *)lock; + + if(!lock) + return; + + DeleteCriticalSection(criticalSection); + + gsifree(criticalSection); +} + +// Locks a lock. +//////////////// +static void GLockLock(GLock lock) +{ + CRITICAL_SECTION * criticalSection = (CRITICAL_SECTION *)lock; + + if(!lock) + return; + + EnterCriticalSection(criticalSection); +} + +// Unlocks a lock. +////////////////// +static void GUnlockLock(GLock lock) +{ + CRITICAL_SECTION * criticalSection = (CRITICAL_SECTION *)lock; + + if(!lock) + return; + + LeaveCriticalSection(criticalSection); +} +#endif + +// Creates the ghttp lock. +////////////////////////// +void ghiCreateLock(void) +{ +#ifdef WIN32 + // We shouldn't already have a lock. + //////////////////////////////////// + assert(!ghiGlobalLock); + + // Create the lock. + /////////////////// + ghiGlobalLock = GNewLock(); +#endif +} + +// Frees the ghttp lock. +//////////////////////// +void ghiFreeLock(void) +{ +#ifdef WIN32 + if(!ghiGlobalLock) + return; + + GFreeLock(ghiGlobalLock); + ghiGlobalLock = NULL; +#endif +} + +// Locks the ghttp lock. +//////////////////////// +void ghiLock +( + void +) +{ +#ifdef WIN32 + if(!ghiGlobalLock) + return; + + GLockLock(ghiGlobalLock); +#endif +} + +// Unlocks the ghttp lock. +////////////////////////// +void ghiUnlock +( + void +) +{ +#ifdef WIN32 + if(!ghiGlobalLock) + return; + + GUnlockLock(ghiGlobalLock); +#endif +} + +// Logs traffic. +//////////////// +#ifdef HTTP_LOG +void ghiLogToFile(const char * buffer, int len, const char* fileName) +{ +#ifdef _NITRO + int i; + + if(!buffer || !len) + return; + + for(i = 0 ; i < len ; i++) + OS_PutChar(buffer[i]); +#else + FILE * file; + + if(!buffer || !len) + return; + + file = fopen(fileName, "ab"); + if(file) + { + fwrite(buffer, 1, len, file); + fclose(file); + } +#endif +} +#endif + +// Reads encrypted data from decodeBuffer +// Appends decrypted data to recvBuffer +// Returns GHTTPFalse if there was a fatal error +//////////////////////////////////////////////// +GHTTPBool ghiDecryptReceivedData(struct GHIConnection * connection) +{ + // Decrypt data from decodeBuffer to recvBuffer + GHIEncryptionResult aResult = GHIEncryptionResult_None; + + // data to be decrypted + char* aReadPos = NULL; + char* aWritePos = NULL; + int aReadLen = 0; + int aWriteLen = 0; + + do + { + // Call the decryption func + do + { + aReadPos = connection->decodeBuffer.data + connection->decodeBuffer.pos; + aReadLen = connection->decodeBuffer.len - connection->decodeBuffer.pos; + aWritePos = connection->recvBuffer.data + connection->recvBuffer.len; + aWriteLen = connection->recvBuffer.size - connection->recvBuffer.len; // the amount of room in recvbuffer + + aResult = (connection->encryptor.mDecryptFunc)(connection, &connection->encryptor, + aReadPos, &aReadLen, aWritePos, &aWriteLen); + if (aResult == GHIEncryptionResult_BufferTooSmall) + { + // Make some more room + if (GHTTPFalse == ghiResizeBuffer(&connection->recvBuffer, connection->recvBuffer.sizeIncrement)) + return GHTTPFalse; // error + } + else if(aResult == GHIEncryptionResult_Error) + { + return GHTTPFalse; + } + } while (aResult == GHIEncryptionResult_BufferTooSmall && aWriteLen == 0); + + // Adjust GHIBuffer sizes so they account for transfered data + if(aReadLen > connection->decodeBuffer.len) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_HotError, + "ghiDecryptReceivedData read past the end of connection->decodeBuffer! (%d\\%d bytes)\r\n", + aReadLen, connection->decodeBuffer.len); + return GHTTPFalse; + } + + connection->decodeBuffer.pos += aReadLen; + connection->recvBuffer.len += aWriteLen; + + } while(aWriteLen > 0); + + // Discard data from the decodedBuffer in chunks + if (connection->decodeBuffer.pos > 0xFF) + { + int bytesToKeep = connection->decodeBuffer.len - connection->decodeBuffer.pos; + if (bytesToKeep == 0) + ghiResetBuffer(&connection->decodeBuffer); + else + { + memmove(connection->decodeBuffer.data, + connection->decodeBuffer.data + connection->decodeBuffer.pos, + (size_t)bytesToKeep); + connection->decodeBuffer.pos = 0; + connection->decodeBuffer.len = bytesToKeep; + } + } + + return GHTTPTrue; +} + +// Receive some data. +///////////////////// +GHIRecvResult ghiDoReceive +( + GHIConnection * connection, + char buffer[], + int * bufferLen +) +{ + int rcode; + int socketError; + int len; + + // How much to try and receive. + /////////////////////////////// + len = (*bufferLen - 1); + + // Are we throttled? + //////////////////// + if(connection->throttle) + { + unsigned long now; + + // Don't receive too often. + /////////////////////////// + now = current_time(); + if(now < (connection->lastThrottleRecv + ghiThrottleTimeDelay)) + return GHINoData; + + // Update the receive time. + /////////////////////////// + connection->lastThrottleRecv = (unsigned int)now; + + // Don't receive too much. + ////////////////////////// + len = min(len, ghiThrottleBufferSize); + } + + // Receive some data. + ///////////////////// + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mSessionEstablished == GHTTPTrue && + connection->encryptor.mEncryptOnSend == GHTTPTrue ) + { + GHIEncryptionResult result; + int recvLength = len; + + result = ghiEncryptorSslDecryptRecv(connection, &connection->encryptor, buffer, &recvLength); + if (result == GHIEncryptionResult_Success) + rcode = recvLength; + else + rcode = -1; // signal termination of connection + } + else + { + rcode = recv(connection->socket, buffer, len, 0); + } + + + // There was an error. + ////////////////////// + if(gsiSocketIsError(rcode)) + { + // Get the error code. + ////////////////////// + socketError = GOAGetLastError(connection->socket); + + // Check for a closed connection. + ///////////////////////////////// + if(socketError == WSAENOTCONN) + { + connection->connectionClosed = GHTTPTrue; + return GHIConnClosed; + } + + // Check for nothing waiting. + ///////////////////////////// + if((socketError == WSAEWOULDBLOCK) || (socketError == WSAEINPROGRESS) || (socketError == WSAETIMEDOUT)) + return GHINoData; + + // There was a real error. + ////////////////////////// + connection->completed = GHTTPTrue; + connection->result = GHTTPSocketFailed; + connection->socketError = socketError; + connection->connectionClosed = GHTTPTrue; + + return GHIError; + } + + // The connection was closed. + ///////////////////////////// + if(rcode == 0) + { + connection->connectionClosed = GHTTPTrue; + return GHIConnClosed; + } + + // Cap the buffer. + ////////////////// + buffer[rcode] = '\0'; + *bufferLen = rcode; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_RawDump, "Received %d bytes\n", rcode); + + // Notify app. + ////////////// + return GHIRecvData; +} + +int ghiDoSend +( + struct GHIConnection * connection, + const char * buffer, + int len +) +{ + int rcode; + + if (buffer == NULL || len == 0) + return 0; + + // Do the send. + /////////////// + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mSessionEstablished == GHTTPTrue && + connection->encryptor.mEncryptOnSend == GHTTPTrue) + { + int bytesSent = 0; + GHIEncryptionResult result; + + // send through encryption engine + result = ghiEncryptorSslEncryptSend(connection, &connection->encryptor, buffer, len, &bytesSent); + + // Check for an error. + ////////////////////// + if(result != GHIEncryptionResult_Success) + rcode = -1; // signal termination of connection + else + rcode = bytesSent; + } + else + { + // send directly to socket + rcode = send(connection->socket, buffer, len, 0); + } + + // Check for an error. + ////////////////////// + if(gsiSocketIsError(rcode)) + { + int error; + + // Would block just means 0 bytes sent. + /////////////////////////////////////// + error = GOAGetLastError(connection->socket); + if((error == WSAEWOULDBLOCK) || (error == WSAEINPROGRESS) || (error == WSAETIMEDOUT)) + return 0; + + connection->completed = GHTTPTrue; + connection->result = GHTTPSocketFailed; + connection->socketError = error; + + return -1; + } + + //do not add CRLF as part of bytes posted - make sure waitPostContinue is false + if(connection->state == GHTTPPosting && connection->postingState.waitPostContinue == GHTTPFalse) + { + connection->postingState.bytesPosted += rcode; + ghiLogRequest(buffer, rcode); + } + + return rcode; +} + +GHITrySendResult ghiTrySendThenBuffer +( + GHIConnection * connection, + const char * buffer, + int len +) +{ + int rcode = 0; + + // **SSL pattern 1: buffer everything into an SSL record** + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mSessionEstablished == GHTTPTrue && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + if (!ghiEncryptDataToBuffer(&connection->sendBuffer, buffer + rcode, len - rcode)) + return GHITrySendError; + + // Try to send immediately + if (ghiSendBufferedData(connection) == GHTTPFalse) + return GHITrySendError; + if (connection->sendBuffer.pos >= connection->sendBuffer.len) + { + ghiResetBuffer(&connection->sendBuffer); + return GHITrySendSent; // everything sent + } + return GHITrySendBuffered; + } + + // **Plain text or SSL encrypt on send** + + // If we already have something buffered, don't send. + ///////////////////////////////////////////////////// + if(connection->sendBuffer.pos >= connection->sendBuffer.len) + { + // Try and send. + //////////////// + rcode = ghiDoSend(connection, buffer, len); + if(gsiSocketIsError(rcode)) + return GHITrySendError; + + // Was it all sent? + /////////////////// + if(rcode == len) + return GHITrySendSent; + } + + // Buffer whatever wasn't sent. + /////////////////////////////// + if(!ghiAppendDataToBuffer(&connection->sendBuffer, buffer + rcode, len - rcode)) + return GHITrySendError; + return GHITrySendBuffered; +} + +static GHTTPBool ghiParseProxyServer +( + const char * server, + char ** proxyAddress, // [out] the proxy address + unsigned short * proxyPort // [out] the proxy port +) +{ + char * strPort; + + // Make sure each pointer is valid as well as what it points to + assert(server && *server); + assert(proxyAddress && !*proxyAddress); + assert(proxyPort); + + // Copy off the server address. + /////////////////////////////// + *proxyAddress = goastrdup(server); + if(!*proxyAddress) + return GHTTPFalse; + + // Check for a port. + //////////////////// + if((strPort = strchr(*proxyAddress, ':')) != NULL) + { + *strPort++ = '\0'; + + // Try getting the port. + //////////////////////// + *proxyPort = (unsigned short)atoi(strPort); + if(!*proxyPort) + { + gsifree(*proxyAddress); + *proxyAddress = NULL; + return GHTTPFalse; + } + } + else + { + *proxyPort = GHI_DEFAULT_PORT; + } + return GHTTPTrue; +} + +GHTTPBool ghiSetProxy +( + const char * server +) +{ + // Free any existing proxy address. + /////////////////////////////////// + if(ghiProxyAddress) + { + gsifree(ghiProxyAddress); + ghiProxyAddress = NULL; + } + ghiProxyPort = 0; + + // If a server was supplied, try to parse it + if(server && *server) + return ghiParseProxyServer(server, &ghiProxyAddress, &ghiProxyPort); + + // No server supplied results in proxy being cleared + return GHTTPTrue; +} + +GHTTPBool ghiSetRequestProxy +( + GHTTPRequest request, + const char * server +) +{ + // Obtain the connection for this request + GHIConnection* connection = ghiRequestToConnection(request); + if (connection == NULL) + return GHTTPFalse; + + // Free any existing proxy address. + /////////////////////////////////// + if(connection->proxyOverrideServer) + { + gsifree(connection->proxyOverrideServer); + connection->proxyOverrideServer = NULL; + connection->proxyOverridePort = GHI_DEFAULT_PORT; + } + + // If a server was supplied, try to parse it + if(server && *server) + return ghiParseProxyServer(server, &connection->proxyOverrideServer, &connection->proxyOverridePort); + + // No server supplied results in proxy being cleared + return GHTTPTrue; +} + +void ghiThrottleSettings +( + int bufferSize, + gsi_time timeDelay +) +{ + ghiThrottleBufferSize = bufferSize; + ghiThrottleTimeDelay = timeDelay; +} + +// Re-enable previously disabled compiler warnings +/////////////////////////////////////////////////// +#if defined(_MSC_VER) +#pragma warning ( default: 4127 ) +#endif // _MSC_VER + diff --git a/xrGameSpy/gamespy/ghttp/ghttpCommon.h b/xrGameSpy/gamespy/ghttp/ghttpCommon.h new file mode 100644 index 00000000000..2034e80f6af --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpCommon.h @@ -0,0 +1,154 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPCOMMON_H_ +#define _GHTTPCOMMON_H_ + +#include "ghttp.h" +#include "ghttpConnection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// HTTP Line-terminator. +//////////////////////// +#define CRLF "\xD\xA" + +// HTTP URL Encoding +//////////////////////// +#define GHI_LEGAL_URLENCODED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_@-.*" +#define GHI_DIGITS "0123456789ABCDEF" + +// Default HTTP port. +///////////////////// +#define GHI_DEFAULT_PORT 80 +#define GHI_DEFAULT_SECURE_PORT 443 +#define GHI_DEFAULT_THROTTLE_BUFFER_SIZE 125 +#define GHI_DEFAULT_THROTTLE_TIME_DELAY 250 + +// Proxy server. +//////////////// +extern char * ghiProxyAddress; +extern unsigned short ghiProxyPort; + +// Throttle settings. +///////////////////// +extern int ghiThrottleBufferSize; +extern gsi_time ghiThrottleTimeDelay; + +// Our thread lock. +/////////////////// +void ghiCreateLock(void); +void ghiFreeLock(void); +void ghiLock(void); +void ghiUnlock(void); + +// Do logging. +////////////// +#ifdef HTTP_LOG +void ghiLogToFile +( + const char * buffer, + int len, + const char * fileName +); +#define ghiLogRequest(b,c) ghiLogToFile(b,c,"request.log"); +#define ghiLogResponse(b,c) ghiLogToFile(b,c,"response.log"); +#define ghiLogPost(b,c) ghiLogToFile(b,c,"post.log"); +#else +#define ghiLogRequest(b,c) +#define ghiLogResponse(b,c) +#define ghiLogPost(b,c) +#endif + + +// Possible results from ghiDoReceive. +////////////////////////////////////// +typedef enum +{ + GHIRecvData, // Data was received. + GHINoData, // No data was available. + GHIConnClosed, // The connection was closed. + GHIError // There was a socket error. +} GHIRecvResult; + +// Receive some data. +///////////////////// +GHIRecvResult ghiDoReceive +( + GHIConnection * connection, + char buffer[], + int * bufferLen +); + +// Do a send on the connection's socket. +// Returns number of bytes sent (0 or more). +// If error, returns (-1). +//////////////////////////////////////////// +int ghiDoSend +( + GHIConnection * connection, + const char * buffer, + int len +); + +// Results for ghtTrySendThenBuffer. +//////////////////////////////////// +typedef enum +{ + GHITrySendError, // There was an error sending. + GHITrySendSent, // Everything was sent. + GHITrySendBuffered // Some or all of the data was buffered. +} GHITrySendResult; + +// Sends whatever it can on the socket. +// Buffers whatever can't be sent in the sendBuffer. +//////////////////////////////////////////////////// +GHITrySendResult ghiTrySendThenBuffer +( + GHIConnection * connection, + const char * buffer, + int len +); + +// Set the proxy server +//////////////////////// +GHTTPBool ghiSetProxy +( + const char * server +); + +// Set the proxy server for a specific request +//////////////////////// +GHTTPBool ghiSetRequestProxy +( + GHTTPRequest request, + const char * server +); + +// Set the throttle settings. +///////////////////////////// +void ghiThrottleSettings +( + int bufferSize, + gsi_time timeDelay +); + +// Decrypt data from the decode buffer into the receive buffer. +/////////////////////////////////////////////////////////////// +GHTTPBool ghiDecryptReceivedData(struct GHIConnection * connection); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpConnection.c b/xrGameSpy/gamespy/ghttp/ghttpConnection.c new file mode 100644 index 00000000000..a0882b07f80 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpConnection.c @@ -0,0 +1,424 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "ghttpConnection.h" +#include "ghttpCommon.h" + +// Initial size and increment amount for the connections array. +/////////////////////////////////////////////////////////////// +#define CONNECTIONS_CHUNK_LEN 4 + +// An array of pointers to GHIConnection objects. +// A GHTTPRequest is an index into this array. +///////////////////////////////////////////////// +static GHIConnection ** ghiConnections; +static int ghiConnectionsLen; +static int ghiNumConnections; +static int ghiNextUniqueID; + +// Finds a gsifree slot in the ghiConnections array. +// If there are no gsifree slots, the array size will be increased. +//////////////////////////////////////////////////////////////// +static int ghiFindFreeSlot +( + void +) +{ + int i; + GHIConnection ** tempPtr; + int oldLen; + int newLen; + + // Look for an open slot. + ///////////////////////// + for(i = 0 ; i < ghiConnectionsLen ; i++) + { + if(!ghiConnections[i]->inUse) + return i; + } + + assert(ghiNumConnections == ghiConnectionsLen); + + // Nothing found, resize the array. + /////////////////////////////////// + oldLen = ghiConnectionsLen; + newLen = (ghiConnectionsLen + CONNECTIONS_CHUNK_LEN); + tempPtr = (GHIConnection **)gsirealloc(ghiConnections, sizeof(GHIConnection *) * newLen); + if(!tempPtr) + return -1; + ghiConnections = tempPtr; + + // Create the new connection objects. + ///////////////////////////////////// + for(i = oldLen ; i < newLen ; i++) + { + ghiConnections[i] = (GHIConnection *)gsimalloc(sizeof(GHIConnection)); + if(!ghiConnections[i]) + { + for(i-- ; i >= oldLen ; i--) + gsifree(ghiConnections[i]); + return -1; + } + ghiConnections[i]->inUse = GHTTPFalse; + } + + // Update the length. + ///////////////////// + ghiConnectionsLen = newLen; + + return oldLen; +} + +GHIConnection * ghiNewConnection +( + void +) +{ + int slot; + GHIConnection * connection; + GHTTPBool bResult; + + ghiLock(); + + // Find a gsifree slot. + //////////////////// + slot = ghiFindFreeSlot(); + if(slot == -1) + { + ghiUnlock(); + return NULL; + } + + // Get a pointer to the object. + /////////////////////////////// + connection = ghiConnections[slot]; + + // Init the object. + /////////////////// + memset(connection, 0, sizeof(GHIConnection)); + connection->inUse = GHTTPTrue; + connection->request = (GHTTPRequest)slot; + connection->uniqueID = ghiNextUniqueID++; + connection->type = GHIGET; + connection->state = GHTTPSocketInit; + connection->URL = NULL; + connection->serverAddress = NULL; + connection->serverIP = INADDR_ANY; + connection->serverPort = (unsigned short)0; + connection->requestPath = NULL; + connection->sendHeaders = NULL; + connection->saveFile = NULL; + connection->blocking = GHTTPFalse; + connection->persistConnection = GHTTPFalse; + connection->result = GHTTPSuccess; + connection->progressCallback = NULL; + connection->completedCallback = NULL; + connection->callbackParam = NULL; + connection->socket = INVALID_SOCKET; + connection->socketError = 0; + connection->userBufferSupplied = GHTTPFalse; + connection->statusMajorVersion = 0; + connection->statusMinorVersion = 0; + connection->statusCode = 0; + connection->statusStringIndex = 0; + connection->headerStringIndex = 0; + connection->completed = GHTTPFalse; + connection->fileBytesReceived = 0; + connection->totalSize = -1; + connection->redirectURL = NULL; + connection->redirectCount = 0; + connection->chunkedTransfer = GHTTPFalse; + connection->processing = GHTTPFalse; + connection->throttle = GHTTPFalse; + connection->lastThrottleRecv = 0; + connection->post = NULL; + connection->maxRecvTime = 500; // Prevent blocking in async mode with systems that never generate WSAEWOULDBLOCK + connection->proxyOverridePort = GHI_DEFAULT_PORT; + connection->proxyOverrideServer = NULL; + connection->encryptor.mInterface = NULL; + +//handle used for asynch DNS lookups +#if !defined(GSI_NO_THREADS) + connection->handle = NULL; +#endif + + bResult = ghiInitBuffer(connection, &connection->sendBuffer, SEND_BUFFER_INITIAL_SIZE, SEND_BUFFER_INCREMENT_SIZE); + if(bResult) + bResult = ghiInitBuffer(connection, &connection->encodeBuffer, ENCODE_BUFFER_INITIAL_SIZE, ENCODE_BUFFER_INCREMENT_SIZE); + if(bResult) + bResult = ghiInitBuffer(connection, &connection->recvBuffer, RECV_BUFFER_INITIAL_SIZE, RECV_BUFFER_INCREMENT_SIZE); + if (bResult) + bResult = ghiInitBuffer(connection, &connection->decodeBuffer, DECODE_BUFFER_INITIAL_SIZE, DECODE_BUFFER_INCREMENT_SIZE); + + if(!bResult) + { + ghiFreeConnection(connection); + ghiUnlock(); + return NULL; + } + + // One more connection. + /////////////////////// + ghiNumConnections++; + + ghiUnlock(); + + return connection; +} + +GHTTPBool ghiFreeConnection +( + GHIConnection * connection +) +{ + assert(connection); + assert(connection->request >= 0); + assert(connection->request < ghiConnectionsLen); + assert(connection->inUse); + + // Check args. + ////////////// + if(!connection) + return GHTTPFalse; + if(!connection->inUse) + return GHTTPFalse; + if(connection->request < 0) + return GHTTPFalse; + if(connection->request >= ghiConnectionsLen) + return GHTTPFalse; + + ghiLock(); + + // Free data. + ///////////// + gsifree(connection->URL); + gsifree(connection->serverAddress); + gsifree(connection->requestPath); + gsifree(connection->sendHeaders); + gsifree(connection->redirectURL); + gsifree(connection->proxyOverrideServer); +#ifndef NOFILE + if(connection->saveFile) + fclose(connection->saveFile); +#endif + if(connection->socket != INVALID_SOCKET) + { + shutdown(connection->socket, 2); + closesocket(connection->socket); + } + ghiFreeBuffer(&connection->sendBuffer); + ghiFreeBuffer(&connection->encodeBuffer); + ghiFreeBuffer(&connection->recvBuffer); + ghiFreeBuffer(&connection->decodeBuffer); + ghiFreeBuffer(&connection->getFileBuffer); + if(connection->postingState.states) + ghiPostCleanupState(connection); + +#if !defined(GSI_NO_THREADS) + // Cancel and free asychronous lookup if it has not already been done + ///////////////////////////////////////////////////////////////////// + if (connection->handle) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, + "Cancelling Thread and freeing memory\n"); + gsiCancelResolvingHostname(connection->handle); + } +#endif + + // Check for an auto-free post. + /////////////////////////////// + if(connection->post && ghiIsPostAutoFree(connection->post)) + { + ghiFreePost(connection->post); + connection->post = NULL; + } + + // Check for an encryptor + if (connection->encryptor.mInitialized != GHTTPFalse) + { + if (connection->encryptor.mCleanupFunc) + (connection->encryptor.mCleanupFunc)(connection, &connection->encryptor); + connection->encryptor.mInitialized = GHTTPFalse; + } + + // Free the slot. + ///////////////// + connection->inUse = GHTTPFalse; + + // One less connection. + /////////////////////// + ghiNumConnections--; + + ghiUnlock(); + + return GHTTPTrue; +} + +GHIConnection * ghiRequestToConnection +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + assert(request >= 0); + assert(request < ghiConnectionsLen); + + ghiLock(); + + // Check args. + ////////////// + if((request < 0) || (request >= ghiConnectionsLen)) + { + ghiUnlock(); + return NULL; + } + + connection = ghiConnections[request]; + + // Check for not in use. + //////////////////////// + if(!connection->inUse) + connection = NULL; + + ghiUnlock(); + + return connection; +} + +void ghiEnumConnections +( + GHTTPBool (* callback)(GHIConnection *) +) +{ + int i; + + // Check for no connections. + //////////////////////////// + if(ghiNumConnections <= 0) + return; + + ghiLock(); + for(i = 0 ; i < ghiConnectionsLen ; i++) + if(ghiConnections[i]->inUse) + callback(ghiConnections[i]); + ghiUnlock(); +} + +void ghiRedirectConnection +( + GHIConnection * connection +) +{ + assert(connection); + assert(connection->redirectURL); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Redirecting Connection\n"); + + // Reset state. + /////////////// + connection->state = GHTTPSocketInit; + +#if !defined(GSI_NO_THREADS) + // Cancel and free asychronous lookup if it has not already been done + ///////////////////////////////////////////////////////////////////// + if (connection->handle) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, + "Cancelling Thread and freeing memory\n"); + gsiCancelResolvingHostname(connection->handle); + } +#endif + + // New URL. + /////////// + gsifree(connection->URL); + connection->URL = connection->redirectURL; + connection->redirectURL = NULL; + + // Reset stuff parsed from the URL. + /////////////////////////////////// + gsifree(connection->serverAddress); + connection->serverAddress = NULL; + connection->serverIP = 0; + connection->serverPort = 0; + gsifree(connection->requestPath); + connection->requestPath = NULL; + + // Close the socket. + //////////////////// + shutdown(connection->socket, 2); + closesocket(connection->socket); + connection->socket = INVALID_SOCKET; + + // Reset buffers. + ///////////////// + ghiResetBuffer(&connection->sendBuffer); + ghiResetBuffer(&connection->encodeBuffer); + ghiResetBuffer(&connection->recvBuffer); + ghiResetBuffer(&connection->decodeBuffer); + + // Reset status. + //////////////// + connection->statusMajorVersion = 0; + connection->statusMinorVersion = 0; + connection->statusCode = 0; + connection->statusStringIndex = 0; + + connection->headerStringIndex = 0; + + // The connection isn't closed. + /////////////////////////////// + connection->connectionClosed = GHTTPFalse; + + // Check for an encryptor + if (connection->encryptor.mInitialized != GHTTPFalse) + { + // cleanup the encryptor + if (connection->encryptor.mCleanupFunc) + (connection->encryptor.mCleanupFunc)(connection, &connection->encryptor); + connection->encryptor.mInitialized = GHTTPFalse; + + // if the redirect isn't secure, clear it + if(strncmp("https://", connection->URL, 8) != 0) + { + connection->encryptor.mEngine = GHTTPEncryptionEngine_None; + connection->encryptor.mInterface = NULL; + } + } + + // One more redirect. + ///////////////////// + connection->redirectCount++; +} + +void ghiCleanupConnections +( + void +) +{ + int i; + + if(!ghiConnections) + return; + + // Cleanup all running connections. + /////////////////////////////////// + ghiEnumConnections(ghiFreeConnection); + + // Cleanup the connection states. + ///////////////////////////////// + for(i = 0 ; i < ghiConnectionsLen ; i++) + gsifree(ghiConnections[i]); + gsifree(ghiConnections); + ghiConnections = NULL; + ghiConnectionsLen = 0; + ghiNumConnections = 0; +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpConnection.h b/xrGameSpy/gamespy/ghttp/ghttpConnection.h new file mode 100644 index 00000000000..b80b3bbfc94 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpConnection.h @@ -0,0 +1,217 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPCONNECTION_H_ +#define _GHTTPCONNECTION_H_ + +#include "ghttpMain.h" +#include "ghttpEncryption.h" +#include "ghttpBuffer.h" +#include "ghttpPost.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Initial size and increment amount for the send buffer. +///////////////////////////////////////////////////////// +#define SEND_BUFFER_INITIAL_SIZE (2 * 1024) +#define SEND_BUFFER_INCREMENT_SIZE (4 * 1024) + +// Initial size and increment amount for the recv buffer. +///////////////////////////////////////////////////////////////// +#define RECV_BUFFER_INITIAL_SIZE (2 * 1024) +#define RECV_BUFFER_INCREMENT_SIZE (2 * 1024) + +// Initial size and increment amount for the get file buffer. +///////////////////////////////////////////////////////////// +#define GET_FILE_BUFFER_INITIAL_SIZE (2 * 1024) +#define GET_FILE_BUFFER_INCREMENT_SIZE (2 * 1024) + +// Initial size and increment amount for the ssl encoding buffer. +///////////////////////////////////////////////////////////////// +#define ENCODE_BUFFER_INITIAL_SIZE (2 * 1024) +#define ENCODE_BUFFER_INCREMENT_SIZE (1 * 1024) + +// Initial size and increment amount for the ssl decoding buffer. +///////////////////////////////////////////////////////////////// +#define DECODE_BUFFER_INITIAL_SIZE (2 * 1024) +#define DECODE_BUFFER_INCREMENT_SIZE (1 * 1024) + +// The size of the buffer for chunk headers (NOT including the NUL). +//////////////////////////////////////////////////////////////////// +#define CHUNK_HEADER_SIZE 10 + +// The type of request made. +//////////////////////////// +typedef enum +{ + GHIGET, // Buffer the file. + GHISAVE, // Save the file to disk. + GHISTREAM, // Stream the file. + GHIHEAD, // Get just the headers for a request. + GHIPOST // Only posting data (all types can post). +} GHIRequestType; + +// Chunk-reading states. +//////////////////////// +typedef enum +{ + CRHeader, // Reading a chunk header. + CRChunk, // Reading chunk (actual content). + CRCRLF, // Reading the CRLF at the end of a chunk. + CRFooter // Reading the footer at the end of the file (chunk with size of 0). +} CRState; + +// Protocol. +//////////// +typedef enum +{ + GHIHttp, + GHIHttps +} GHIProtocol; + +// This is the data for a single http connection. +///////////////////////////////////////////////// +typedef struct GHIConnection +{ + GHTTPBool inUse; // If true, this connection object is being used. + GHTTPRequest request; // This object's request index. + int uniqueID; // Every connection object has a unqiue ID. + + GHIRequestType type; // The type of request this connection is for. + + GHTTPState state; // The state of the request. + + char * URL; // The URL for the file. + char * serverAddress; // The address of the server as contained in the URL. + unsigned int serverIP; // The server's IP. + unsigned short serverPort; // The server's port. + char * requestPath; // The path as contained in the URL. + + GHIProtocol protocol; // Protocol used for this connection. + + char * sendHeaders; // Optional headers to pass with the request. + + FILE * saveFile; // If saving to disk, the file being saved to. + + GHTTPBool blocking; // Blocking flag. + + GHTTPBool persistConnection; // If TRUE, Connection: close will not be sent in the headers and the connection will be left open + + GHTTPResult result; // The result of the request. + ghttpProgressCallback progressCallback; // Called periodically with progress updates. + ghttpCompletedCallback completedCallback; // Called when the file has been received. + void * callbackParam; // User-data to be passed to the callbacks. + + SOCKET socket; // The socket for this connection. + int socketError; // If there was a socket error, the last error code is stored here. + + GHIBuffer sendBuffer; // The buffer for outgoing data. + GHIBuffer encodeBuffer; // The buffer for outgoing data. (will be encrypted; only used with https) + GHIBuffer recvBuffer; // The buffer for incoming data. (plain text) + GHIBuffer decodeBuffer; // The buffer for incoming data. (encrypted)(only used with https) + + GHIBuffer getFileBuffer; // ghttpGetFile[Ex] uses this buffer (which may be user-supplied). + GHTTPBool userBufferSupplied; // True if a user buffer was supplied. + + int statusMajorVersion; // The major-version number from the server's response. + int statusMinorVersion; // The minor-version number from the server's response. + int statusCode; // The status-code from the server's response. + int statusStringIndex; // Index in the recvBuffer where the status string starts. + + int headerStringIndex; // Index in the recvBuffer where the headers begin + + GHTTPBool completed; // This connection is completed - call the callback and kill it. + + GHTTPByteCount fileBytesReceived; // Number of file bytes received. + GHTTPByteCount totalSize; // Total size of the file, -1 if unknown. + + char * redirectURL; // If this is not NULL, we need to redirect the download to this URL. + int redirectCount; // Number of redirections done for this request. + + GHTTPBool chunkedTransfer; // The body of the response is chunky ("Transfer-Encoding: chunked"). + char chunkHeader[CHUNK_HEADER_SIZE + 1]; // Partial chunk headers are stored in here. + int chunkHeaderLen; // The number of bytes in chunkHeader. + int chunkBytesLeft; // Number of bytes left in the chunk (only valid for CRChunk). + CRState chunkReadingState; // Determines if a chunk header or chunk data is being read. + + GHTTPBool processing; // If true, being processed. Used to prevent recursive processing. + GHTTPBool connectionClosed; // If true, the connection has been closed (orderly or abortive) + + GHTTPBool throttle; // If true, throttle this connection. + gsi_time lastThrottleRecv; // The last time we received on a throttled connection. + + GHTTPPost post; // If not NULL, a reference to a post object to upload with the request. + GHIPostingState postingState; // If posting, the state of the upload. + + gsi_time maxRecvTime; // Max time spent receiving per call to "Think" - Prevents blocking on ultrafast connections + char * proxyOverrideServer; // Allows use of a different proxy than the global proxy + unsigned short proxyOverridePort; + + struct GHIEncryptor encryptor; + +#if !defined(GSI_NO_THREADS) + GSIResolveHostnameHandle handle; //handle used for asychronous DNS lookups +#endif + +} GHIConnection; + +// Create a new connection object. +// Returns NULL on failure. +////////////////////////////////// +GHIConnection * ghiNewConnection +( + void +); + +// Frees the connection object. +/////////////////////////////// +GHTTPBool ghiFreeConnection +( + GHIConnection * connection +); + +// Returns the connection object for a request index. +// Returns NULL if the index is bad. +///////////////////////////////////////////////////// +GHIConnection * ghiRequestToConnection +( + GHTTPRequest request +); + +// Calls the callback on each connection. +///////////////////////////////////////// +void ghiEnumConnections +( + GHTTPBool (* callback)(GHIConnection *) +); + +// Redirects the given connection. +// Resets the connection to get the +// file at connection->redirectURL. +/////////////////////////////////// +void ghiRedirectConnection +( + GHIConnection * connection +); + +// Kills all connections and frees up all memory. +///////////////////////////////////////////////// +void ghiCleanupConnections +( + void +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpEncryption.c b/xrGameSpy/gamespy/ghttp/ghttpEncryption.c new file mode 100644 index 00000000000..ccc579cd6e2 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpEncryption.c @@ -0,0 +1,1786 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "ghttpCommon.h" +#if defined(MATRIXSSL) +#include "../matrixssl/matrixssl.h" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +GHTTPBool ghttpSetRequestEncryptionEngine(GHTTPRequest request, GHTTPEncryptionEngine engine) +{ + GHIConnection * connection = ghiRequestToConnection(request); + if(!connection) + return GHTTPFalse; + + // Translate default into the actual engine name + // We don't want to set the engine value to "default" because + // we'd lose the ability to determine the engine name in other places + if (engine == GHTTPEncryptionEngine_Default) + { + #if defined(MATRIXSSL) + engine = GHTTPEncryptionEngine_MatrixSsl; + #elif defined(REVOEXSSL) + engine = GHTTPEncryptionEngine_RevoEx; + #else + engine = GHTTPEncryptionEngine_GameSpy; + #endif + } + + // If the same engine has previously been set then we're done + if (connection->encryptor.mEngine == engine) + return GHTTPTrue; + + // If a different engine has previously been set then we're screwed + if (connection->encryptor.mInterface != NULL && + connection->encryptor.mEngine != engine) + { + return GHTTPFalse; + } + + // If the URL is HTTPS but the engine is specific as NONE then we can't connect + if((engine == GHTTPEncryptionEngine_None) && (strncmp(connection->URL, "https://", 8) == 0)) + return GHTTPFalse; + + // Initialize the engine + connection->encryptor.mEngine = engine; + + if (engine == GHTTPEncryptionEngine_None) + { + connection->encryptor.mInterface = NULL; + return GHTTPTrue; // this is the default, just return + } + else + { + // 02OCT07 BED: Design was changed to only allow one engine at a time + // Assert that the specified engine is the one supported + if (engine != GHTTPEncryptionEngine_Default) + { + #if defined(MATRIXSSL) + GS_ASSERT(engine==GHTTPEncryptionEngine_MatrixSsl); + #elif defined(REVOEXSSL) + GS_ASSERT(engine==GHTTPEncryptionEngine_RevoEx); + #else + GS_ASSERT(engine==GHTTPEncryptionEngine_GameSpy); + #endif + } + + connection->encryptor.mInterface = NULL; + connection->encryptor.mInitFunc = ghiEncryptorSslInitFunc; + connection->encryptor.mStartFunc = ghiEncryptorSslStartFunc; + connection->encryptor.mCleanupFunc = ghiEncryptorSslCleanupFunc; + connection->encryptor.mEncryptFunc = ghiEncryptorSslEncryptFunc; + connection->encryptor.mDecryptFunc = ghiEncryptorSslDecryptFunc; + connection->encryptor.mInitialized = GHTTPFalse; + connection->encryptor.mSessionStarted = GHTTPFalse; + connection->encryptor.mSessionEstablished = GHTTPFalse; + connection->encryptor.mEncryptOnBuffer = GHTTPTrue; + connection->encryptor.mEncryptOnSend = GHTTPFalse; + connection->encryptor.mLibSendsHandshakeMessages = GHTTPFalse; + return GHTTPTrue; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// ********************* MATRIXSSL ENCRYPTION ENGINE ********************* // +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef MATRIXSSL + +// SSL requires a certificate validator +static int ghiSslCertValidator(struct sslCertInfo* theCertInfo, void* theUserData) +{ + // Taken from matrisSslExample + sslCertInfo_t *next; +/* + Make sure we are checking the last cert in the chain +*/ + next = theCertInfo; + while (next->next != NULL) { + next = next->next; + } + return next->verified; +} + +// Init the engine +GHIEncryptionResult ghiEncryptorSslInitFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + sslKeys_t *keys = NULL; + sslSessionId_t *id = NULL; + + int ecodeResult; + + if (matrixSslOpen() < 0) + return GHIEncryptionResult_Error; + + if (matrixSslReadKeys(&keys, NULL, NULL, NULL, NULL) < 0) + return GHIEncryptionResult_Error; + + if (matrixSslNewSession((ssl_t**)&theEncryptor->mInterface, keys, id, 0) < 0) + return GHIEncryptionResult_Error; + + matrixSslSetCertValidator((ssl_t*)theEncryptor->mInterface, ghiSslCertValidator, NULL); + + theEncryptor->mInitialized = GHTTPTrue; + return GHIEncryptionResult_Success; +} + +// Start the handshake process +GHIEncryptionResult ghiEncryptorSslInitFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + sslBuf_t helloWrapper; + + // Prepare the hello message + helloWrapper.buf = connection->sendBuffer.data; + helloWrapper.size = connection->sendBuffer.size; + helloWrapper.start = connection->sendBuffer.data + connection->sendBuffer.pos; + helloWrapper.end = helloWrapper.start; // start writing here + + ecodeResult = matrixSslEncodeClientHello((ssl_t*)theEncryptor->mInterface, &helloWrapper, 0); // 0 = cipher + if (ecodeResult != 0) + return GHIEncryptionResult_Error; // error! + + // Adjust the sendBuffer to account for the new data + connection->sendBuffer.len += (int)(helloWrapper.end - helloWrapper.start); + connection->sendBuffer.encrypted = GHTTPTrue; + theEncryptor->mSessionStarted = GHTTPTrue; +} + +// Destroy the engine +GHIEncryptionResult ghiEncryptorSslCleanupFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + matrixSslClose(); + return GHIEncryptionResult_Success; +} + +// Encrypt some data +// - theEncryptedLength is reduced by the length of data written to theEncryptedBuffer +GHIEncryptionResult ghiEncryptorSslEncryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + char * theEncryptedBuffer, + int * theEncryptedLength) +{ + int encodeResult = 0; + + // SSL buffer wrapper + // Append to theDecryptedBuffer + sslBuf_t encryptedBuf; + encryptedBuf.buf = theEncryptedBuffer; // buf starts here + encryptedBuf.start = theEncryptedBuffer; // readpos, set to start + encryptedBuf.end = theEncryptedBuffer; // writepos, set to start + encryptedBuf.size = *theEncryptedLength; // total size of buf + + // perform the encryption + encodeResult = matrixSslEncode(connection->encryptor.mInterface, + (unsigned char*)thePlainTextBuffer, *thePlainTextLength, &encryptedBuf); + + if (encodeResult == SSL_ERROR) + return GHIEncryptionResult_Error; + else if (encodeResult == SSL_FULL) + return GHIEncryptionResult_BufferTooSmall; + else + { + //*thePlainTextLength = *thePlainTextLength; // we always use the entire buffer + *theEncryptedLength -= (int)(encryptedBuf.end - encryptedBuf.start); + return GHIEncryptionResult_Success; + } +} + +// Decrypt some data +// - During the handshaking process, this may result in data being appended to the send buffer +// - Data may be left in the encrypted buffer +// - theEncryptedLength becomes the length of data read from theEncryptedBuffer +// - theDecryptedLength becomes the length of data written to theDecryptedBuffer +GHIEncryptionResult ghiEncryptorSslDecryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * theEncryptedBuffer, + int * theEncryptedLength, + char * theDecryptedBuffer, + int * theDecryptedLength) +{ + GHTTPBool decryptMore = GHTTPTrue; + int decodeResult = 0; + + // SSL buffer wrappers + sslBuf_t inBuf; + sslBuf_t decryptedBuf; + int encryptedStartSize = *theEncryptedLength; + + // Read from theEncryptedBuffer - Have to cast away the "const" + inBuf.buf = (unsigned char*)theEncryptedBuffer; + inBuf.start = (unsigned char*)theEncryptedBuffer; + inBuf.end = (unsigned char*)theEncryptedBuffer + *theEncryptedLength; + inBuf.size = *theEncryptedLength; + + // Append to theDecryptedBuffer + decryptedBuf.buf = theDecryptedBuffer; // buf starts here + decryptedBuf.start = theDecryptedBuffer; // readpos, set to start + decryptedBuf.end = theDecryptedBuffer; // writepos, set to start + decryptedBuf.size = *theDecryptedLength; // total size of buf + + // Perform the decode operation + // - may require multiple tries + while(decryptMore != GHTTPFalse && ((inBuf.end-inBuf.start) > 0)) + { + unsigned char error = 0; + unsigned char alertlevel = 0; + unsigned char alertdescription = 0; + + // perform the decode, this will decode a single SSL message at a time + decodeResult = matrixSslDecode(theEncryptor->mInterface, &inBuf, &decryptedBuf, + &error, &alertlevel, &alertdescription); + switch(decodeResult) + { + case SSL_SUCCESS: + // a message was handled internally by matrixssl + // No data is appeneded to the decrypted buffer + if (matrixSslHandshakeIsComplete(theEncryptor->mInterface)) + theEncryptor->mSessionEstablished = GHTTPTrue; + break; + + case SSL_PROCESS_DATA: + // We've received app data, continue on. + // App data was appended to the decrypted buffer + break; + + case SSL_SEND_RESPONSE: + { + // we must send an SSL response which has been written to decryptedBuf + // transfer this response to the connection's sendBuffer + int responseSize = decryptedBuf.end - decryptedBuf.start; + + // force disable-encryption + // this may seem like a hack, but it's the best way to avoid + // unnecessary data copies without modifying matrixSSL + theEncryptor->mSessionEstablished = GHTTPFalse; + ghiTrySendThenBuffer(connection, decryptedBuf.start, responseSize); + theEncryptor->mSessionEstablished = GHTTPTrue; + + // Remove the bytes from the decrypted buffer (we don't want to return them to the app) + decryptedBuf.end = decryptedBuf.start; // bug? + break; + } + + case SSL_ERROR: + // error decoding the data + decryptMore = GHTTPFalse; + break; + + case SSL_ALERT: + // server sent an alert + if (alertdescription == SSL_ALERT_CLOSE_NOTIFY) + decryptMore = GHTTPFalse; + break; + + case SSL_PARTIAL: + // need to read more data from the socket(inbuf incomplete) + decryptMore = GHTTPFalse; + break; + + case SSL_FULL: + { + // decodeBuffer is too small, need to increase size and try again + decryptMore = GHTTPFalse; + break; + } + }; + } + + // Store off the lengths + *theEncryptedLength = encryptedStartSize - (inBuf.end - inBuf.start); + *theDecryptedLength = decryptedBuf.end - decryptedBuf.start; + + // Return status to app + if (decodeResult == SSL_FULL) + return GHIEncryptionResult_BufferTooSmall; + else if (decodeResult == SSL_ERROR || decodeResult == SSL_ALERT) + return GHIEncryptionResult_Error; + + //if ((int)(decryptedBuf.end - decryptedBuf.start) > 0) + // printf ("Decrypted: %d bytes\r\n", *theDecryptedLength); + return GHIEncryptionResult_Success; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// ********************* REVOEX SSL ENCRYPTION ENGINE ******************** // +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#elif defined(REVOEXSSL) +#include + +typedef struct gsRevoExInterface +{ + SSLId mId; + SSLClientCertId mClientCertId; + SSLRootCAId mRootCAId; + GHTTPBool mConnected; // means "connected to socket", not "connected to remote machine" +} gsRevoExInterface; + +// Init the engine +GHIEncryptionResult ghiEncryptorSslInitFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + int i=0; + gsRevoExInterface* sslInterface = NULL; + + // There is only one place where this function should be called, + // and it should check if the engine has been initialized + GS_ASSERT(theEncryptor->mInitialized == GHTTPFalse); + GS_ASSERT(theEncryptor->mInterface == NULL); + + // allocate the interface (need one per connection) + theEncryptor->mInterface = gsimalloc(sizeof(gsRevoExInterface)); + if (theEncryptor->mInterface == NULL) + { + // memory allocation failed + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Memory, GSIDebugLevel_WarmError, + "Failed to allocate SSL interface (out of memory: %d bytes)\r\n", sizeof(gsRevoExInterface)); + return GHIEncryptionResult_Error; + } + memset(theEncryptor->mInterface, 0, sizeof(gsRevoExInterface)); + sslInterface = (gsRevoExInterface*)theEncryptor->mInterface; + + { + int verifyOption = 0; + int rcode = 0; + + verifyOption = SSL_VERIFY_COMMON_NAME + | SSL_VERIFY_ROOT_CA + | SSL_VERIFY_DATE + | SSL_VERIFY_CHAIN + | SSL_VERIFY_SUBJECT_ALT_NAME; + + // todo serverAddress, is this used for certificate name? + sslInterface->mId = SSLNew(verifyOption, connection->serverAddress); + + rcode = SSLSetBuiltinRootCA(sslInterface->mId, SSL_ROOTCA_NINTENDO_1); + if(rcode != SSL_ENONE){ + SSLShutdown(sslInterface->mId); + return GHIEncryptionResult_Error; + } + + rcode = SSLSetBuiltinClientCert(sslInterface->mId, SSL_CLIENTCERT_NINTENDO_0); + if(rcode != SSL_ENONE){ + SSLShutdown(sslInterface->mId); + return GHIEncryptionResult_Error; + } + } + + theEncryptor->mInitialized = GHTTPTrue; + theEncryptor->mSessionStarted = GHTTPFalse; + theEncryptor->mSessionEstablished = GHTTPFalse; + //theEncryptor->mUseSSLConnect = GHTTPTrue; + theEncryptor->mEncryptOnBuffer = GHTTPFalse; + theEncryptor->mEncryptOnSend = GHTTPTrue; + theEncryptor->mLibSendsHandshakeMessages = GHTTPTrue; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx engine) initialized\r\n"); + + return GHIEncryptionResult_Success; +} + + +// Destroy the engine +GHIEncryptionResult ghiEncryptorSslCleanupFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + if (theEncryptor != NULL) + { + gsRevoExInterface* sslInterface = (gsRevoExInterface*)theEncryptor->mInterface; + if (sslInterface != NULL) + { + SSLShutdown(sslInterface->mId); + gsifree(sslInterface); + theEncryptor->mInterface = NULL; + } + theEncryptor->mInitialized = GHTTPFalse; + theEncryptor->mSessionStarted = GHTTPFalse; + theEncryptor->mSessionEstablished = GHTTPFalse; + } + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) engine cleanup called\r\n"); + + GSI_UNUSED(connection); + + return GHIEncryptionResult_Success; +} + + +GHIEncryptionResult ghiEncryptorSslStartFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + gsRevoExInterface* sslInterface = (gsRevoExInterface*)theEncryptor->mInterface; + int result = 0; + + GS_ASSERT(theEncryptor->mSessionStarted == GHTTPFalse); + + // Call this only AFTER the socket has been connected to the remote server + if (!sslInterface->mConnected) + { + result = SSLConnect(sslInterface->mId, connection->socket); + if (result != SSL_ENONE) + { + switch(result) + { + case SSL_EFAILED: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLConnect failed (SSL_EFAILED)\r\n"); + break; + case SSL_ESSLID: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLConnect failed (SSL_ESSLID)\r\n"); + break; + default: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLConnect failed (Unhandled Error)\r\n"); + break; + } + return GHIEncryptionResult_Error; + } + sslInterface->mConnected = GHTTPTrue; + } + + GS_ASSERT(sslInterface->mConnected == GHTTPTrue); + + // begin securing the session + result = SSLDoHandshake(sslInterface->mId); + if (result != SSL_ENONE) + { + // Check for EWOULDBLOCK conditions + if (result == SSL_EWANT_READ || result == SSL_EWANT_WRITE) + return GHIEncryptionResult_Success; + + switch(result) + { + case SSL_EFAILED: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EFAILED)\r\n"); + break; + case SSL_ESSLID: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_ESSLID)\r\n"); + break; + case SSL_ESYSCALL: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_ESYSCALL)\r\n"); + break; + case SSL_EZERO_RETURN: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EZERO_RETURN)\r\n"); + break; + case SSL_EWANT_CONNECT: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EWANT_CONNECT)\r\n"); + break; + case SSL_EVERIFY_COMMON_NAME: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EVERIFY_COMMON_NAME)\r\n"); + break; + case SSL_EVERIFY_CHAIN: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EVERIFY_CHAIN)\r\n"); + break; + case SSL_EVERIFY_ROOT_CA: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EVERIFY_ROOT_CA)\r\n"); + break; + case SSL_EVERIFY_DATE: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (SSL_EVERIFY_DATE)\r\n"); + break; + default: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLDoHandshake failed (Unhandled Error)\r\n"); + break; + } + return GHIEncryptionResult_Error; + } + + // Success + theEncryptor->mSessionStarted = GHTTPTrue; + theEncryptor->mSessionEstablished = GHTTPTrue; + return GHIEncryptionResult_Success; +} + +// Encrypt and send some data +GHIEncryptionResult ghiEncryptorSslEncryptSend(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + int * theBytesSentOut) +{ + gsRevoExInterface* sslInterface = (gsRevoExInterface*)theEncryptor->mInterface; + int result = 0; + + result = SSLWrite(sslInterface->mId, thePlainTextBuffer, thePlainTextLength); + if (result == SSL_EZERO_RETURN) + { + // send 0 is not fatal + *theBytesSentOut = 0; + } + else if (result == SSL_EWANT_WRITE) + { + // signal socket error, GetLastError will return EWOULDBLOCK or EINPROGRESS + *theBytesSentOut = -1; + } + else if (result < 0) + { + switch(result) + { + case SSL_EFAILED: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLWrite failed (SSL_EFAILED)\r\n"); + break; + case SSL_ESSLID: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLWrite failed (SSL_ESSLID)\r\n"); + break; + case SSL_EWANT_READ: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLWrite failed (SSL_EWANT_READ)\r\n"); + break; + case SSL_ESYSCALL: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLWrite failed (SSL_ESYSCALL)\r\n"); + break; + case SSL_EWANT_CONNECT: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLWrite failed (SSL_EWANT_CONNECT)\r\n"); + break; + default: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLWrite failed (Unhandled Error)\r\n"); + break; + } + return GHIEncryptionResult_Error; + } + else + { + GS_ASSERT(result > 0); + *theBytesSentOut = result; + } + GSI_UNUSED(connection); + return GHIEncryptionResult_Success; +} + +// Receive and decrypt some data +GHIEncryptionResult ghiEncryptorSslDecryptRecv(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + char * theDecryptedBuffer, + int * theDecryptedLength) +{ + gsRevoExInterface* sslInterface = (gsRevoExInterface*)theEncryptor->mInterface; + int result = 0; + + result = SSLRead(sslInterface->mId, theDecryptedBuffer, *theDecryptedLength); + if (result == SSL_EZERO_RETURN) + { + // receive 0 is not fatal + *theDecryptedLength = 0; + } + else if (result == SSL_EWANT_READ) + { + // signal socket error, GetLastError will return EWOULDBLOCK or EINPROGRESS + *theDecryptedLength = -1; + } + else if (result < 0) + { + // Fatal errors + switch(result) + { + case SSL_EFAILED: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLRead failed (SSL_EFAILED)\r\n"); + break; + case SSL_ESSLID: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLRead failed (SSL_ESSLID)\r\n"); + break; + case SSL_EWANT_WRITE: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLRead failed (SSL_EWANT_WRITE)\r\n"); + break; + case SSL_ESYSCALL: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLRead failed (SSL_ESYSCALL)\r\n"); + break; + case SSL_EWANT_CONNECT: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLRead failed (SSL_EWANT_CONNECT)\r\n"); + break; + default: + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL (RevoEx) SSLRead failed (Unhandled Error)\r\n"); + break; + } + return GHIEncryptionResult_Error; + } + else + { + GS_ASSERT(result > 0); + *theDecryptedLength = result; + } + GSI_UNUSED(connection); + return GHIEncryptionResult_Success; +} + +GHIEncryptionResult ghiEncryptorSslEncryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + char * theEncryptedBuffer, + int * theEncryptedLength) +{ + GS_FAIL(); // Should never call this for RevoEx SSL! It uses encrypt on send + + GSI_UNUSED(connection); + GSI_UNUSED(theEncryptor); + GSI_UNUSED(thePlainTextBuffer); + GSI_UNUSED(thePlainTextLength); + GSI_UNUSED(theEncryptedBuffer); + GSI_UNUSED(theEncryptedLength); + + return GHIEncryptionResult_Error; +} + +GHIEncryptionResult ghiEncryptorSslDecryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * theEncryptedBuffer, + int * theEncryptedLength, + char * theDecryptedBuffer, + int * theDecryptedLength) +{ + GS_FAIL(); // Should never call this for RevoEx SSL! It uses decrypt on recv + + GSI_UNUSED(connection); + GSI_UNUSED(theEncryptor); + GSI_UNUSED(theEncryptedBuffer); + GSI_UNUSED(theEncryptedLength); + GSI_UNUSED(theDecryptedBuffer); + GSI_UNUSED(theDecryptedLength); + + return GHIEncryptionResult_Error; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// *********************** GS SSL ENCRYPTION ENGINE ********************** // +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#else + +#include "../common/gsSSL.h" +#include "../common/gsSHA1.h" +#include "../common/gsRC4.h" +#include "../md5.h" + + +// Processor for SSL state messages (transparent to application) +static GHIEncryptionResult ghiEncryptorProcessSSLHandshake(struct GHIConnection * connection, + struct GHIEncryptor * encryptor, + GHIBuffer * data); + +// SSL-ASN.1 lengths are variable length NBO integers +// we use this utility to make data packing easier +// example: 61 little-endian(intel) = 61 00 00 00 +// big-endian(network) = 00 00 00 61 +static void ghiEncryptorWriteNBOLength(unsigned char* buf, int value, int size) +{ + int NBO = (int)htonl(value); + unsigned char* NBOData = (unsigned char*)&NBO; + + assert(size <= sizeof(NBO)); + if (size > sizeof(NBO)) + return; // can't write more than 4 bytes! + + // this won't work if NBO ever changes from big-endian + memcpy(buf, NBOData+(sizeof(int)-size), (size_t)size); +} +static GHTTPBool ghiEncryptorReadNBOLength(GHIBuffer * data, int* value, int size) +{ + assert(size <= sizeof(*value)); + if (size > sizeof(*value)) + return GHTTPFalse; + if (GHTTPFalse == ghiReadDataFromBufferFixed(data, ((char*)value)+(sizeof(int)-size), size)) + return GHTTPFalse; + + *value = (int)htonl(*value); + return GHTTPTrue; +} + +static GHTTPBool ghiEncryptorParseASN1Sequence(GHIBuffer * data, int* lenOut) +{ + char tempChar = '\0'; + + if (GHTTPFalse == ghiReadDataFromBufferFixed(data, &tempChar, 1)) + return GHTTPFalse; + if (tempChar != 0x30) // sequence start byte + return GHTTPFalse; + + if (GHTTPFalse == ghiReadDataFromBufferFixed(data, &tempChar, 1)) + return GHTTPFalse; + if ((tempChar & 0x80) == 0x80) + { + int tempInt = 0; + + // length is stored in next (tempChar^0x80) bytes + tempChar ^= 0x80; + if (GHTTPFalse == ghiEncryptorReadNBOLength(data, &tempInt, tempChar)) + return GHTTPFalse; + if (tempInt > (data->len - data->pos)) + return GHTTPFalse; + + *lenOut = tempInt; + return GHTTPTrue; + } + else + { + if ((int)tempChar > (data->len - data->pos)) + return GHTTPFalse; + + *lenOut = tempChar; + return GHTTPTrue; + } +} + +static void ghiEncryptorGenerateEncryptionKeys(gsSSL* sslInterface) +{ + // Use the server random, client random and pre master secret + // to compute the encryption key. + + // SSLv3 style + // master_secret = { + // MD5(pre_master_secret + SHA1("A"+pre_master_secret+client_random+server_random)) + + // MD5(pre_master_secret + SHA1("BB"+pre_master_secret+client_random+server_random)) + + // MD5(pre_master_secret + SHA1("CCC"+pre_master_secret+client_random+server_random)) + // } + // key_block = { + // MD5(master_secret + SHA1("A"+master_secret+server_random+client_random)) + + // MD5(master_secret + SHA1("BB"+master_secret+server_random+client_random)) + + // MD5(master_secret + SHA1("CCC"+master_secret+server_random+client_random)) + + SHA1Context sha1; + MD5_CTX md5; + unsigned char temp[SHA1HashSize]; + + unsigned int randomSize = 32; + unsigned char keyblock[64]; // todo: support different key sizes + + // master_secret "A" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"A", 1); + SHA1Input(&sha1, (const unsigned char*)sslInterface->premastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->premastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final((unsigned char*)&sslInterface->mastersecret[0*GS_CRYPT_MD5_HASHSIZE], &md5); + + // master_secret "BB" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"BB", 2); + SHA1Input(&sha1, (const unsigned char*)sslInterface->premastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->premastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final((unsigned char*)&sslInterface->mastersecret[1*GS_CRYPT_MD5_HASHSIZE], &md5); + + // master_secret "CCC" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"CCC", 3); + SHA1Input(&sha1, (const unsigned char*)sslInterface->premastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->premastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final((unsigned char*)&sslInterface->mastersecret[2*GS_CRYPT_MD5_HASHSIZE], &md5); + + // key_block "A" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"A", 1); + SHA1Input(&sha1, (const unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final(&keyblock[0*GS_CRYPT_MD5_HASHSIZE], &md5); + + // key_block "BB" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"BB", 2); + SHA1Input(&sha1, (const unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final(&keyblock[1*GS_CRYPT_MD5_HASHSIZE], &md5); + + // key_block "CCC" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"CCC", 3); + SHA1Input(&sha1, (const unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final(&keyblock[2*GS_CRYPT_MD5_HASHSIZE], &md5); + + // key_block "DDDD" + SHA1Reset(&sha1); + SHA1Input(&sha1, (const unsigned char*)"DDDD", 4); + SHA1Input(&sha1, (const unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sha1, (const unsigned char*)sslInterface->serverRandom, randomSize); + SHA1Input(&sha1, (const unsigned char*)sslInterface->clientRandom, randomSize); + SHA1Result(&sha1, temp); + MD5Init(&md5); + MD5Update(&md5, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&md5, temp, GS_CRYPT_SHA1_HASHSIZE); + MD5Final(&keyblock[3*GS_CRYPT_MD5_HASHSIZE], &md5); + + // key_block "EEEEE" + // key_block "FFFFFF" + // ... continue if more key material is needed + + // todo: support different key sizes + // KEYBLOCK + // writemac[16], readmac[16], writekey[16], readkey[16], writeIV[0], readIV[0] + memcpy(sslInterface->clientWriteMACSecret, &keyblock[0], 16); + memcpy(sslInterface->clientReadMACSecret, &keyblock[16], 16); + memcpy(sslInterface->clientWriteKey, &keyblock[32], 16); + memcpy(sslInterface->clientReadKey, &keyblock[48], 16); + + sslInterface->clientWriteMACLen = 16; + sslInterface->clientReadMACLen = 16; + sslInterface->clientWriteKeyLen = 16; + sslInterface->clientReadKeyLen = 16; + + // Init the stream cipher + RC4Init(&sslInterface->sendRC4, (const unsigned char*)sslInterface->clientWriteKey, sslInterface->clientWriteKeyLen); + RC4Init(&sslInterface->recvRC4, (const unsigned char*)sslInterface->clientReadKey, sslInterface->clientReadKeyLen); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "Generated SSL session keys\r\n"); +} + + +// Init the engine +GHIEncryptionResult ghiEncryptorSslInitFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + gsSSL* sslInterface = NULL; + + // There is only one place where this function should be called, + // and it should check if the engine has been initialized + assert(theEncryptor->mInitialized == GHTTPFalse); + assert(theEncryptor->mInterface == NULL); + + // Make sure the send buffer is large enough for the SSL handshake (handshake is <1k) + if (connection->sendBuffer.size - connection->sendBuffer.len < sizeof(gsSSLClientHelloMsg)) + return GHIEncryptionResult_BufferTooSmall; + + // allocate the interface (need one per connection) + theEncryptor->mInterface = gsimalloc(sizeof(gsSSL)); + if (theEncryptor->mInterface == NULL) + { + // memory allocation failed + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Memory, GSIDebugLevel_WarmError, + "Failed to allocate SSL interface (out of memory: %d bytes)\r\n", sizeof(gsSSL)); + return GHIEncryptionResult_Error; + } + memset(theEncryptor->mInterface, 0, sizeof(gsSSL)); + sslInterface = (gsSSL*)theEncryptor->mInterface; + + theEncryptor->mInitialized = GHTTPTrue; + theEncryptor->mSessionStarted = GHTTPFalse; + theEncryptor->mSessionEstablished = GHTTPFalse; + theEncryptor->mEncryptOnBuffer = GHTTPTrue; + theEncryptor->mEncryptOnSend = GHTTPFalse; + theEncryptor->mLibSendsHandshakeMessages = GHTTPFalse; + MD5Init(&sslInterface->finishHashMD5); + SHA1Reset(&sslInterface->finishHashSHA1); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL engine initialized\r\n"); + + return GHIEncryptionResult_Success; +} + +// Destroy the engine +GHIEncryptionResult ghiEncryptorSslCleanupFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + if (theEncryptor != NULL) + { + gsSSL* sslInterface = (gsSSL*)theEncryptor->mInterface; + if (sslInterface != NULL) + { + gsifree(sslInterface); + theEncryptor->mInterface = NULL; + } + theEncryptor->mInitialized = GHTTPFalse; + theEncryptor->mSessionStarted = GHTTPFalse; + theEncryptor->mSessionEstablished = GHTTPFalse; + } + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL engine cleanup called\r\n"); + + GSI_UNUSED(connection); + + return GHIEncryptionResult_Success; +} + +// Init the engine +GHIEncryptionResult ghiEncryptorSslStartFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor) +{ + gsSSL* sslInterface = (gsSSL*)theEncryptor->mInterface; + gsSSLClientHelloMsg helloMsg; + int i=0; + + // prepare the client hello + // 1) + helloMsg.header.contentType = GS_SSL_CONTENT_HANDSHAKE; + helloMsg.header.versionMajor = GS_SSL_VERSION_MAJOR; + helloMsg.header.versionMinor = GS_SSL_VERSION_MINOR; + + // Set the length of the client hello message (2-byte NBO int, not including record header) + ghiEncryptorWriteNBOLength(helloMsg.header.lengthNBO, sizeof(gsSSLClientHelloMsg)-sizeof(gsSSLRecordHeaderMsg), 2); + + helloMsg.handshakeType = GS_SSL_HANDSHAKE_CLIENTHELLO; + helloMsg.versionMajor = GS_SSL_VERSION_MAJOR; + helloMsg.versionMinor = GS_SSL_VERSION_MINOR; + + // Set the length of the client hello data (3 byte NBO int) + // This is the total message length MINUS the SSL record header MINUS four additional header bytes + ghiEncryptorWriteNBOLength(helloMsg.lengthNBO, sizeof(gsSSLClientHelloMsg)-sizeof(gsSSLRecordHeaderMsg)-4, 3); + //ghttpEncryptorSetNBOBytesFromHBOInt(helloMsg.time, (gsi_u32)current_time(), 4); // 4 byte time value (for randomness) + ghiEncryptorWriteNBOLength(helloMsg.time, 0, 4); // test code: no randomness + + // fill in the [rest of the] random + // Security Note: If a hacker is able to discern the current_time() they may be able to + // recreate the random bytes and recover the session key. + Util_RandSeed(current_time()); + for (i=0; i<28; i++) + { + #if defined(GS_CRYPT_NO_RANDOM) + #pragma message ("!!!WARNING: SSL Random disable for debug purposes. SSL not secured!!!") + helloMsg.random[i] = 0; // test code: no randomness + #else + helloMsg.random[i] = (unsigned char)Util_RandInt(0, 0xff); + #endif + } + + // store a copy of the random (used later for key generation) + memcpy(&sslInterface->clientRandom[0], helloMsg.time, 4); + memcpy(&sslInterface->clientRandom[4], helloMsg.random, 28); + + // todo: session resumption + helloMsg.sessionIdLen = 0; + + // fill in cipher suite IDs + helloMsg.cipherSuitesLength = htons(sizeof(gsi_u16)*GS_SSL_NUM_CIPHER_SUITES); + for (i=0; i < GS_SSL_NUM_CIPHER_SUITES; i++) + helloMsg.cipherSuites[i] = htons((unsigned short)gsSSLCipherSuites[i].mSuiteID); + + // there are no standard SSL compression methods + helloMsg.compressionMethodLen = 1; + helloMsg.compressionMethodList = 0; + + // We need to compute a hash of all the handshake messages + // Add this message to the hash (both MD5 hash and SHA1 hash) + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)&helloMsg+sizeof(gsSSLRecordHeaderMsg), sizeof(gsSSLClientHelloMsg)-sizeof(gsSSLRecordHeaderMsg)); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)&helloMsg+sizeof(gsSSLRecordHeaderMsg), sizeof(gsSSLClientHelloMsg)-sizeof(gsSSLRecordHeaderMsg)); + + // Now send it (we already verified the length, so this should not fail) + if (GHTTPFalse == ghiAppendDataToBuffer(&connection->sendBuffer, (const char*)&helloMsg, sizeof(gsSSLClientHelloMsg))) + { + // assert or just return? + return GHIEncryptionResult_BufferTooSmall; + } + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "GameSpy SSL engine handshake started\r\n"); + + theEncryptor->mSessionStarted = GHTTPTrue; + return GHIEncryptionResult_Success; + +} + +// Encrypt some data +// - theEncryptedLength is reduced by the length of data written to theEncryptedBuffer +// So if the encrypted buffer is 255 bytes long and we write 50 additional bytes, we'll return 205. +GHIEncryptionResult ghiEncryptorSslEncryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + char * theEncryptedBuffer, + int * theEncryptedLength) +{ + if (theEncryptor != NULL) + { + gsSSL* sslInterface = (gsSSL*)theEncryptor->mInterface; + if (sslInterface == NULL || theEncryptor->mSessionEstablished == GHTTPFalse) + { + // not secured yet, send as plain text + if (thePlainTextLength > *theEncryptedLength) + return GHIEncryptionResult_BufferTooSmall; + memcpy(theEncryptedBuffer, thePlainTextBuffer, (size_t)thePlainTextLength); + *theEncryptedLength += thePlainTextLength; // number of bytes written + } + else + { + // Create an SSL encrypted record + // The order of operations below is very important. + // The MAC must be computed before ciphering the plain text because + // theEncryptedBuffer may be the same memory location as thePlainTextBuffer + + gsSSL* sslInterface = (gsSSL*)theEncryptor->mInterface; + gsSSLRecordHeaderMsg* header = NULL; + MD5_CTX md5; + int pos = 0; + unsigned short lengthNBO = htons((unsigned short)thePlainTextLength); + unsigned char MAC[GS_CRYPT_MD5_HASHSIZE]; + + // The SSL record adds a little overhead + if (*theEncryptedLength < (thePlainTextLength+(int)sizeof(gsSSLRecordHeaderMsg))) + return GHIEncryptionResult_BufferTooSmall; + + // write the SSL header + header = (gsSSLRecordHeaderMsg*)theEncryptedBuffer; + header->contentType = GS_SSL_CONTENT_APPLICATIONDATA; + header->versionMajor = GS_SSL_VERSION_MAJOR; + header->versionMinor = GS_SSL_VERSION_MINOR; + pos += sizeof(gsSSLRecordHeaderMsg); + + // calculate the MAC + MD5Init(&md5); + MD5Update(&md5, sslInterface->clientWriteMACSecret, (unsigned int)sslInterface->clientWriteMACLen); + MD5Update(&md5, (unsigned char*)GS_SSL_PAD_ONE, GS_SSL_MD5_PAD_LEN); + MD5Update(&md5, sslInterface->sendSeqNBO, sizeof(sslInterface->sendSeqNBO)); + MD5Update(&md5, (unsigned char*)"\x17", 1); // content type application data + MD5Update(&md5,(unsigned char*)&lengthNBO, sizeof(lengthNBO)); + MD5Update(&md5, (unsigned char*)thePlainTextBuffer, (unsigned int)thePlainTextLength); // **cast-away const** + MD5Final(MAC, &md5); // first half of MAC + + MD5Init(&md5); + MD5Update(&md5, sslInterface->clientWriteMACSecret, (unsigned int)sslInterface->clientWriteMACLen); + MD5Update(&md5, (unsigned char*)GS_SSL_PAD_TWO, GS_SSL_MD5_PAD_LEN); + MD5Update(&md5, MAC, GS_CRYPT_MD5_HASHSIZE); + MD5Final(MAC, &md5); // complete MAC + + // apply stream cipher to data + MAC + RC4Encrypt(&sslInterface->sendRC4, (const unsigned char*)thePlainTextBuffer, (unsigned char*)&theEncryptedBuffer[pos], thePlainTextLength); + pos += thePlainTextLength; + RC4Encrypt(&sslInterface->sendRC4, MAC, (unsigned char*)&theEncryptedBuffer[pos], GS_CRYPT_MD5_HASHSIZE); + pos += GS_CRYPT_MD5_HASHSIZE; + + // Now that we know the final length (data+mac+pad), write it into the header + ghiEncryptorWriteNBOLength(header->lengthNBO, (int)(pos - sizeof(gsSSLRecordHeaderMsg)), 2); + + // adjust encrypted length + *theEncryptedLength -= pos; + + // Update the sequence number for the next message (8-byte, NBO) + pos = 7; // **changing the semantic of variable "pos" + do + { + //int carry = 0; + if (sslInterface->sendSeqNBO[pos] == 0xFF) // wraparound means carry + { + //carry = 1; + sslInterface->sendSeqNBO[pos] = 0; + pos -= 1; + } + else + { + sslInterface->sendSeqNBO[pos] += 1; + pos = 0; // end addition + } + } while(pos >= 0); + } + } + + GSI_UNUSED(connection); + return GHIEncryptionResult_Success; +} + +// Decrypt some data +// - During the handshaking process, this may result in data being appended to the send buffer +// - Data may be left in the encrypted buffer +// - theEncryptedLength becomes the length of data read from theEncryptedBuffer +// - theDecryptedLength becomes the length of data written to theDecryptedBuffer +GHIEncryptionResult ghiEncryptorSslDecryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * theEncryptedBuffer, + int * theEncryptedLength, + char * theDecryptedBuffer, + int * theDecryptedLength) +{ + gsSSL* sslInterface = NULL; + int readPos = 0; + int writePos = 0; + + // Make sure we have a valid encryptor + assert(theEncryptor != NULL); + assert(theEncryptor->mInterface != NULL); + if (theEncryptor == NULL || theEncryptor->mInterface == NULL) + { + // no encryption set? copy as plain text + memcpy(theDecryptedBuffer, theEncryptedBuffer, (size_t)(*theEncryptedLength)); + *theDecryptedLength = *theEncryptedLength; + *theEncryptedLength = 0; // no bytes remaining + return GHIEncryptionResult_Success; + } + + sslInterface = (gsSSL*)theEncryptor->mInterface; + if (sslInterface == NULL) + return GHIEncryptionResult_Error; + + // Read each SSL message from the stream (leave partial messages) + while(readPos < *theEncryptedLength) + { + gsSSLRecordHeaderMsg* header = NULL; + unsigned short length = 0; + GHIEncryptionResult result; + + // make sure we have the complete record header + if ((*theEncryptedLength-readPos) < sizeof(gsSSLRecordHeaderMsg)) + break; + header = (gsSSLRecordHeaderMsg*)&theEncryptedBuffer[readPos]; + + // make sure we have the complete record data + // Warning: Convert the length in two steps to avoid issues with byte order + // BAD!! -> length = ntohs((header->lengthNBO[0] | (header->lengthNBO[1] << 8))); + //length = (unsigned short)(header->lengthNBO[0] | (header->lengthNBO[1] << 8)); + memcpy(&length, &header->lengthNBO[0], sizeof(length)); + length = ntohs(length); + if ( *theEncryptedLength < (readPos + length +(int)sizeof(gsSSLRecordHeaderMsg))) + break; // wait for more data + + // if we have to decrypt, make sure there is room in the decrypt buffer + if (connection->encryptor.mSessionEstablished) + { + if ((*theDecryptedLength-writePos) < length) + { + *theEncryptedLength = readPos; // bytes read *NOT* bytes remaining + *theDecryptedLength = writePos; // bytes written + + if (*theDecryptedLength>0) + return GHIEncryptionResult_Success; + else + return GHIEncryptionResult_BufferTooSmall; + } + } + + //readPos += sizeof(gsSSLRecordHeaderMsg); + + // process the record data + switch(header->contentType) + { + case GS_SSL_CONTENT_HANDSHAKE: + { + GHIBuffer data; + + // Apply stream cipher if the session has been established + readPos += sizeof(gsSSLRecordHeaderMsg); + if (connection->encryptor.mSessionEstablished) + RC4Encrypt(&sslInterface->recvRC4, (const unsigned char*)&theEncryptedBuffer[readPos], (unsigned char*)&theEncryptedBuffer[readPos], length); + + ghiInitReadOnlyBuffer(connection, &data, &theEncryptedBuffer[readPos], length); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "SSL handshake message received\r\n"); + + result = ghiEncryptorProcessSSLHandshake(connection, theEncryptor, &data); + if (result != GHIEncryptionResult_Success) + return result; // error! + + break; + } + case GS_SSL_CONTENT_APPLICATIONDATA: + { + // make sure there is enough room to receive this data + if ( (*theDecryptedLength-writePos) < length) + { + } + + // Apply stream cipher if the session has been established + readPos += sizeof(gsSSLRecordHeaderMsg); + if (connection->encryptor.mSessionEstablished) + RC4Encrypt(&sslInterface->recvRC4, (const unsigned char*)&theEncryptedBuffer[readPos], (unsigned char*)&theEncryptedBuffer[readPos], length); + + // verify MAC and pad + // verifyMAC(); + + // copy to decrypted buffer so HTTP layer can process + memcpy(theDecryptedBuffer+writePos, &theEncryptedBuffer[readPos], (size_t)(length - GS_CRYPT_MD5_HASHSIZE)); + writePos += length - GS_CRYPT_MD5_HASHSIZE; + break; + } + + case GS_SSL_CONTENT_CHANGECIPHERSPEC: + readPos += sizeof(gsSSLRecordHeaderMsg); + //if(readPos > *theEncryptedLength) + // _asm int 3; + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Misc, GSIDebugLevel_Debug, + "SSL change cipher spec message received\r\n"); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_Notice, + "SSL: Incoming traffic now encrypted\r\n"); + connection->encryptor.mSessionEstablished = GHTTPTrue; + break; + + case GS_SSL_CONTENT_ALERT: + readPos += sizeof(gsSSLRecordHeaderMsg); + //if(readPos > *theEncryptedLength) + // _asm int 3; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_WarmError, + "SSL received unhandled ALERT\r\n"); + // server alert + break; + + default: + readPos += sizeof(gsSSLRecordHeaderMsg); + return GHIEncryptionResult_Error; // unhandled content type + }; + + readPos += length; + }; + + // remove read bytes from the stream + *theEncryptedLength = readPos; // bytes read *NOT* bytes remaining + *theDecryptedLength = writePos; // bytes written + + if (*theEncryptedLength < 0) + return GHIEncryptionResult_Error; + else + return GHIEncryptionResult_Success; +} + +static GHTTPBool ghiCertificateChainIsValid(gsSSL* sslInterface) +{ + GSI_UNUSED(sslInterface); + + return GHTTPTrue; +} + +#define CHECK(a) { if (GHTTPFalse == a) return GHIEncryptionResult_Error; } + + +// Programmer note: +// The structure of these SSL handshake messages may seem a bit cryptic, +// due to their variable length data items. Refer to the ASN1/DER encoding guide +// for tag specifics. +GHIEncryptionResult ghiEncryptorProcessSSLHandshake(struct GHIConnection * connection, + struct GHIEncryptor * encryptor, + GHIBuffer * data) +{ + // There may be multiple messages within the handshake message + // length must be completely used, otherwise it's a protocol error + gsSSL* sslInterface = (gsSSL*)encryptor->mInterface; + + while(data->pos < data->len) + { + // Parse each SSL handshake message (there may be multiple) + int messageStart = data->pos; + char messageType = 0; + CHECK(ghiReadDataFromBufferFixed(data, &messageType, 1)); + + if (messageType == GS_SSL_HANDSHAKE_SERVERHELLO) + { + int totalMsgLen = 0; // length of header + data + int msgDataLen = 0; // length of data + int tempInt = 0; + char tempChar = '\0'; + + // make sure we don't have a session already (e.g. dupe hello message) + if (sslInterface->sessionLen != 0) + return GHIEncryptionResult_Error; // abort connection + + CHECK(ghiEncryptorReadNBOLength(data, &msgDataLen, 3)); + + // check reported size against the actual bytes remaining + if (msgDataLen > (data->len - data->pos)) + return GHIEncryptionResult_Error; // abort connection + + // skip SSL version + // (length check not required because we did that above) + data->pos += 2; + + // store server random (used for key generation) + CHECK(ghiReadDataFromBufferFixed(data, (char*)&sslInterface->serverRandom[0], 32)); + + // store session information (length followed by data) + CHECK(ghiReadDataFromBufferFixed(data, &tempChar, 1)); + CHECK(ghiReadDataFromBufferFixed(data, (char*)sslInterface->sessionData, tempChar)); + sslInterface->sessionLen = (int)tempChar; + + // store cipher suite + CHECK(ghiEncryptorReadNBOLength(data, &tempInt, 2)); + sslInterface->cipherSuite = (unsigned short)tempInt; + + // skip compression algorithms (should always be 0x00 since we don't support any!) + CHECK(ghiReadDataFromBufferFixed(data, &tempChar, 1)); + if (tempChar != 0x00) + return GHIEncryptionResult_Error; + + // add it to the running handshake hash + totalMsgLen = data->pos - messageStart; + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)&data->data[messageStart], (unsigned int)totalMsgLen); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)&data->data[messageStart], (unsigned int)totalMsgLen); + } + else if (messageType == GS_SSL_HANDSHAKE_CERTIFICATE) + { + int msgLength = 0; // combined length of the message (size in SSL message header) + int certListLen = 0; // combined length of all certificates + int totalMsgLen = 0; // our calculated msg length (for handshake hashing) + + int certCount = 0; + int certListEndPos = 0; + + CHECK(ghiEncryptorReadNBOLength(data, &msgLength, 3)); + CHECK(ghiEncryptorReadNBOLength(data, &certListLen, 3)); + if (msgLength != certListLen + 3) + return GHIEncryptionResult_Error; + + // make sure we don't have the certificates already (e.g. dupe message) + //if (sslInterface->certificateArray != NULL) + // return GHIEncryptionResult_Error; // abort connection + + // make sure we have enough data to cover the certificate list + certListEndPos = data->pos + certListLen; + if (certListLen > (data->len - data->pos)) + return GHIEncryptionResult_Error; + + // read the certificates + while(data->pos < certListEndPos) + { + int certLength = 0; + int certStartPos = 0; + + int temp = 0; + int version = 0; + + // Must start with a 3 byte length + CHECK(ghiEncryptorReadNBOLength(data, &certLength, 3)); + + // Make sure we have enough data to cover this certificate + if (certLength > (data->len - data->pos)) + return GHIEncryptionResult_Error; // certificate too big + + // 0xFFFF is max message size in SSL v3.0, we don't currently support + // split messages + if (certLength > 0xFFFF) + return GHIEncryptionResult_Error; + + certStartPos = data->pos; // remember this for a shortcut later + certCount++; + + // make a copy of the certificate data + //certCopy = gsimalloc(certLength); + //if (certCopy == NULL) + //{ + // gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Memory, GSIDebugLevel_WarmError, + // "SSL failed to allocate certificate #%d (out of memory)\r\n", certCount); + // return GHIEncryptionResult_Error; + //} + //memcpy(certCopy, &data[browsePos], certLength); + //ArrayAppend(sslInterface->certificateArray, &certCopy); + + // The first certificate holds the server's public key + if (certCount == 1) + { + // X.509 format is rather convoluted. Since we only support + // one variation anyways, I'm hardcoding the specific values + // we require. Anything else is a protocol error. + // 0x30 marks the start of a sequence. next byte is a length field size + // 0x82 is a length tag, meaning the next two bytes contain the length + // 0x81 is the same thing, only the next one byte contains the length + // The other values usually denote required types + + // Certificate SEQUENCE + int seqLen = 0; + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + // todo: verify reported length of this sequence + + // TBSCertificate SEQUENCE + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + // todo: verify reported length of this sequence + + // EXPLICIT Version (must be one of: 0x03,0x02,0x01) + if (5 > (data->len - data->pos)) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0xa0) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x03) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x02) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x01) return GHIEncryptionResult_Error; + version = (unsigned char)data->data[data->pos++]; + + // Serial Number (variable length, with 2-byte length field) + if ((unsigned char)data->data[data->pos++] != 0x02) return GHIEncryptionResult_Error; + temp = (unsigned char)data->data[data->pos++]; // len of serial number + if (data->pos + temp > certListEndPos) return GHIEncryptionResult_Error; + data->pos += temp; // skip the serial number + + // Signature algorithm identifier SEQUENCE + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + data->pos += seqLen; // skip algorithm ID (todo: verify signatures) + + // Issuer Name + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + data->pos += seqLen; // skip the issuer name sequence + + // Validity + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + data->pos += seqLen; // skip the validity sequence + + // Subject Name + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + data->pos += seqLen; // skip the subject name sequence + + // Subject Public Key Info + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + // AlgorithmIdentifier + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + if (seqLen != 0x0d) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x06) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x09) return GHIEncryptionResult_Error; + if (0 != memcmp(&data->data[data->pos], gsSslRsaOid, sizeof(gsSslRsaOid))) + return GHIEncryptionResult_Error; // only RSA certs are supported + data->pos += sizeof(gsSslRsaOid); + if ((unsigned char)data->data[data->pos++] != 0x05) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x00) return GHIEncryptionResult_Error; + + // Bitstring (subject public key) + if (2 > (certListEndPos - data->pos)) return GHIEncryptionResult_Error; + if ((unsigned char)data->data[data->pos++] != 0x03) return GHIEncryptionResult_Error; // bitstring + if ((unsigned char)data->data[data->pos++] != 0x81) return GHIEncryptionResult_Error; // 1 byte len field + if (temp > (certListEndPos - data->pos)) return GHIEncryptionResult_Error; + temp = (unsigned char)data->data[data->pos++]; // remaining data size (check or ignore) + + if ((unsigned char)data->data[data->pos++] != 0x00) return GHIEncryptionResult_Error; + + // Start of the public key modulus + CHECK(ghiEncryptorParseASN1Sequence(data, &seqLen)); + + // Read out the public key modulus + if (data->data[data->pos++] != 0x02) return GHIEncryptionResult_Error; // integer tag + if ((data->data[data->pos]&0x80)==0x80) // ASN1 variable length field + { + int lensize = data->data[data->pos++]&0x7f; + if (lensize > 4) + return GHIEncryptionResult_Error; + temp = 0; + while(lensize-- > 0) + temp = (temp << 8) | (unsigned char)data->data[data->pos++]; + } + else + { + temp = (unsigned char)data->data[data->pos++]; + } + if (data->pos + temp > certListEndPos) return GHIEncryptionResult_Error; + if (data->data[data->pos++] != 0x00) return GHIEncryptionResult_Error; // ignore bits must be 0x00 + if (temp-1 > GS_LARGEINT_BINARY_SIZE/sizeof(char)) return GHIEncryptionResult_Error; + sslInterface->serverpub.modulus.mLength = (unsigned int)((temp-1)/GS_LARGEINT_DIGIT_SIZE_BYTES); //-1 to subtract the previous 0x00 byte + gsLargeIntSetFromMemoryStream(&sslInterface->serverpub.modulus, (const gsi_u8*)&data->data[data->pos], (gsi_u32)temp-1); + data->pos += temp-1; + + // Read out the public key exponent + if (data->data[data->pos++] != 0x02) return GHIEncryptionResult_Error; // integer + if ((data->data[data->pos]&0x80)==0x80) + { + int lensize = data->data[data->pos++]&0x7f; + if (lensize > 4) + return GHIEncryptionResult_Error; + temp = 0; + while(lensize-- > 0) + temp = (temp << 8) | (unsigned char)data->data[data->pos++]; + } + else + { + temp = (unsigned char)data->data[data->pos++]; + } + if (data->pos + temp > certListEndPos) return GHIEncryptionResult_Error; + if (temp == 0) return GHIEncryptionResult_Error; // no exponent? + if (temp > GS_LARGEINT_BINARY_SIZE/sizeof(char)) return GHIEncryptionResult_Error; + sslInterface->serverpub.exponent.mLength = (unsigned int)(((temp-1)/GS_LARGEINT_DIGIT_SIZE_BYTES)+1); // ceiling of temp/4 + gsLargeIntSetFromMemoryStream(&sslInterface->serverpub.exponent, (const gsi_u8*)&data->data[data->pos], (gsi_u32)temp); + data->pos += temp; + } + + // update the position + data->pos = certStartPos + certLength; + + GSI_UNUSED(version); + } + if (data->pos != certListEndPos) + return GHIEncryptionResult_Error; // bytes hanging off the end! + + // todo: verify certificate chain + // first certificate is the server's, the rest likely belong to CA + if (GHTTPFalse == ghiCertificateChainIsValid(sslInterface)) + return GHIEncryptionResult_Error; + + // add it to the running handshake hash + totalMsgLen = data->pos - messageStart; + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)&data->data[messageStart], (unsigned int)totalMsgLen); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)&data->data[messageStart], (unsigned int)totalMsgLen); + } + else if (messageType == GS_SSL_HANDSHAKE_SERVERHELLODONE) + { + // Process the hello done + // Respond with 3 messages + // ClientKeyExchange + // ChangeCipherSpec + // Finished (final handshake) + int i=0; + + gsSSLClientKeyExchangeMsg* clientKeyExchange = NULL; + gsSSLRecordHeaderMsg* changeCipherSpec = NULL; + gsSSLRecordHeaderMsg* finalHandshake = NULL; + + unsigned char temp[7]; + unsigned char hashTempMD5[GS_CRYPT_MD5_HASHSIZE]; + unsigned char hashTempSHA1[GS_CRYPT_SHA1_HASHSIZE]; + int tempInt = 0; + + // ServerHelloDone has a zero length data field + CHECK(ghiEncryptorReadNBOLength(data, &tempInt, 3)); + if (tempInt != 0x00) return GHIEncryptionResult_Error; + + // add it to the running handshake hash + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)&data->data[messageStart], (unsigned int)(data->pos - messageStart)); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)&data->data[messageStart], (unsigned int)(data->pos - messageStart)); + + // Make sure there is room in the send buffer for the response messages + tempInt = (int)(sizeof(gsSSLClientKeyExchangeMsg) + sslInterface->serverpub.modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES); + while (connection->sendBuffer.size - connection->sendBuffer.len < tempInt) + { + // not enough room in send buffer, try to grow it + if (GHTTPFalse == ghiResizeBuffer(&connection->sendBuffer, connection->sendBuffer.sizeIncrement)) + return GHIEncryptionResult_Error; + } + + // 1) Client key exchange, + // create the pre-master-secret + sslInterface->premastersecret[0] = GS_SSL_VERSION_MAJOR; + sslInterface->premastersecret[1] = GS_SSL_VERSION_MINOR; + for (i=2; ipremastersecret[i] = 0; // rand() + #else + Util_RandSeed(current_time()); + sslInterface->premastersecret[i] = (unsigned char)(Util_RandInt(0, 0x0100)); // range = [0...FF] + #endif + } + + clientKeyExchange = (gsSSLClientKeyExchangeMsg*)&connection->sendBuffer.data[connection->sendBuffer.len]; + connection->sendBuffer.len += sizeof(gsSSLClientKeyExchangeMsg); + clientKeyExchange->header.contentType = GS_SSL_CONTENT_HANDSHAKE; + clientKeyExchange->header.versionMajor = GS_SSL_VERSION_MAJOR; + clientKeyExchange->header.versionMinor = GS_SSL_VERSION_MINOR; + ghiEncryptorWriteNBOLength(clientKeyExchange->header.lengthNBO, (int)(sslInterface->serverpub.modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES+4), 2); + clientKeyExchange->handshakeType = GS_SSL_HANDSHAKE_CLIENTKEYEXCHANGE; + ghiEncryptorWriteNBOLength(clientKeyExchange->lengthNBO, (int)(sslInterface->serverpub.modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES), 3); + // encrypt the preMasterSecret using the server's public key (store result in sendbuffer) + gsCryptRSAEncryptBuffer(&sslInterface->serverpub, sslInterface->premastersecret, + GS_SSL_MASTERSECRET_LEN, (unsigned char*)&connection->sendBuffer.data[connection->sendBuffer.len]); + connection->sendBuffer.len += sslInterface->serverpub.modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES; + + // add it to the running handshake hash + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)clientKeyExchange+sizeof(gsSSLRecordHeaderMsg), + sizeof(gsSSLClientKeyExchangeMsg) - sizeof(gsSSLRecordHeaderMsg) + + sslInterface->serverpub.modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)clientKeyExchange+sizeof(gsSSLRecordHeaderMsg), + sizeof(gsSSLClientKeyExchangeMsg) - sizeof(gsSSLRecordHeaderMsg) + + sslInterface->serverpub.modulus.mLength*GS_LARGEINT_DIGIT_SIZE_BYTES); + + + // 2) change cipher spec + changeCipherSpec = (gsSSLRecordHeaderMsg*)&connection->sendBuffer.data[connection->sendBuffer.len]; + changeCipherSpec->contentType = GS_SSL_CONTENT_CHANGECIPHERSPEC; + changeCipherSpec->versionMajor = GS_SSL_VERSION_MAJOR; + changeCipherSpec->versionMinor = GS_SSL_VERSION_MINOR; + changeCipherSpec->lengthNBO[0] = 0; + changeCipherSpec->lengthNBO[1] = 1; // always one byte length + connection->sendBuffer.len += sizeof(gsSSLRecordHeaderMsg); + connection->sendBuffer.data[connection->sendBuffer.len++] = 0x01; // always set to 0x01 + // DO NOT add it to the running handshake hash (its content is not GS_SSL_CONTENT_HANDSHAKE) + + // Calculate the encryption keys + ghiEncryptorGenerateEncryptionKeys(sslInterface); + + // 3) final handshake message (encrypted) + finalHandshake = (gsSSLRecordHeaderMsg*)&connection->sendBuffer.data[connection->sendBuffer.len]; + finalHandshake->contentType = GS_SSL_CONTENT_HANDSHAKE; + finalHandshake->versionMajor = GS_SSL_VERSION_MAJOR; + finalHandshake->versionMinor = GS_SSL_VERSION_MINOR; + finalHandshake->lengthNBO[0] = 0; + finalHandshake->lengthNBO[1] = 56; // handshake type(1)+handshake lenNBO(3)+SHA1(20)+MD5(16)+MAC(16) + connection->sendBuffer.len += sizeof(gsSSLRecordHeaderMsg); + connection->sendBuffer.data[connection->sendBuffer.len++] = GS_SSL_HANDSHAKE_FINISHED; + ghiEncryptorWriteNBOLength((unsigned char*)&connection->sendBuffer.data[connection->sendBuffer.len], 36, 3); + connection->sendBuffer.len += 3; + + + // MD5(master_secret + pad2 + MD5(handshake_messages+"CLNT"+master_secret+pad1)) + // SHA1(master_secret + pad2 + SHA1(handshake_messages+"CLNT"+master_secret+pad1)) + // prepare the final hashes (inner hashes) + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)GS_SSL_CLIENT_FINISH_VALUE, 4); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)GS_SSL_PAD_ONE, GS_SSL_MD5_PAD_LEN); + MD5Final(hashTempMD5, &sslInterface->finishHashMD5); + + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)GS_SSL_CLIENT_FINISH_VALUE, 4); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)GS_SSL_PAD_ONE, GS_SSL_SHA1_PAD_LEN); + SHA1Result(&sslInterface->finishHashSHA1, hashTempSHA1); + + // prepare the final hashes (outer hashes) + MD5Init(&sslInterface->finishHashMD5); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)GS_SSL_PAD_TWO, GS_SSL_MD5_PAD_LEN); + MD5Update(&sslInterface->finishHashMD5, hashTempMD5, GS_CRYPT_MD5_HASHSIZE); + MD5Final(hashTempMD5, &sslInterface->finishHashMD5); + + SHA1Reset(&sslInterface->finishHashSHA1); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)sslInterface->mastersecret, GS_SSL_MASTERSECRET_LEN); + SHA1Input(&sslInterface->finishHashSHA1, (unsigned char*)GS_SSL_PAD_TWO, GS_SSL_SHA1_PAD_LEN); + SHA1Input(&sslInterface->finishHashSHA1, hashTempSHA1, GS_CRYPT_SHA1_HASHSIZE); + SHA1Result(&sslInterface->finishHashSHA1, hashTempSHA1); + + // copy results into the sendbuffer + memcpy(&connection->sendBuffer.data[connection->sendBuffer.len], hashTempMD5, GS_CRYPT_MD5_HASHSIZE); + connection->sendBuffer.len += GS_CRYPT_MD5_HASHSIZE; + memcpy(&connection->sendBuffer.data[connection->sendBuffer.len], hashTempSHA1, GS_CRYPT_SHA1_HASHSIZE); + connection->sendBuffer.len += GS_CRYPT_SHA1_HASHSIZE; + + // output the message MAC (hash(MAC_write_secret+pad_2+ hash(MAC_write_secret+pad_1+seq_num+length+content))); + // Re-using the finishHashMD5 since it has already been allocated + MD5Init(&sslInterface->finishHashMD5); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)sslInterface->clientWriteMACSecret, GS_CRYPT_MD5_HASHSIZE); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)GS_SSL_PAD_ONE, GS_SSL_MD5_PAD_LEN); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)sslInterface->sendSeqNBO, 8); + temp[0] = 0x16; + temp[1] = (unsigned char)((GS_CRYPT_MD5_HASHSIZE+GS_CRYPT_SHA1_HASHSIZE+4)>>8); + temp[2] = (unsigned char)((GS_CRYPT_MD5_HASHSIZE+GS_CRYPT_SHA1_HASHSIZE+4)); + //temp[1] = (unsigned char)(htons(GS_CRYPT_MD5_HASHSIZE+GS_CRYPT_SHA1_HASHSIZE)); + //temp[2] = (unsigned char)(htons(GS_CRYPT_MD5_HASHSIZE+GS_CRYPT_SHA1_HASHSIZE+4)>>8); + temp[3] = 0x14; // 20-bytes of data (MD5+SHA1) + temp[4] = 0x00; // 3-byte length NBO + temp[5] = 0x00; // .. + temp[6] = 0x24; // .. + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)&temp, 7); + MD5Update(&sslInterface->finishHashMD5, hashTempMD5, GS_CRYPT_MD5_HASHSIZE); // content part 1 + MD5Update(&sslInterface->finishHashMD5, hashTempSHA1, GS_CRYPT_SHA1_HASHSIZE); // content part 2 + MD5Final(hashTempMD5, &sslInterface->finishHashMD5); + MD5Init(&sslInterface->finishHashMD5); // reset for outer hash + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)sslInterface->clientWriteMACSecret, GS_CRYPT_MD5_HASHSIZE); + MD5Update(&sslInterface->finishHashMD5, (unsigned char*)GS_SSL_PAD_TWO, GS_SSL_MD5_PAD_LEN); + MD5Update(&sslInterface->finishHashMD5, hashTempMD5, GS_CRYPT_MD5_HASHSIZE); + MD5Final(hashTempMD5, &sslInterface->finishHashMD5); + + memcpy(&connection->sendBuffer.data[connection->sendBuffer.len], hashTempMD5, GS_CRYPT_MD5_HASHSIZE); + connection->sendBuffer.len += GS_CRYPT_MD5_HASHSIZE; + + // increment sequence each time we send a message + // ...assume NBO is bigendian for simplicity + memset(sslInterface->sendSeqNBO, 0, sizeof(sslInterface->sendSeqNBO)); + ghiEncryptorWriteNBOLength(&sslInterface->sendSeqNBO[4], 1, 4); + + // now encrypt the message (not including record header) + RC4Encrypt(&sslInterface->sendRC4, + ((unsigned char*)finalHandshake)+sizeof(gsSSLRecordHeaderMsg), + ((unsigned char*)finalHandshake)+sizeof(gsSSLRecordHeaderMsg), + 56); + } + else if (messageType == GS_SSL_HANDSHAKE_FINISHED) + { + // process server finished and verify hashes + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_Notice, + "SSL: todo - verify server finished hash\r\n"); + data->pos = data->len; + } + else + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_WarmError, + "SSL received unexpected handshake message type: %d\r\n", messageType); + return GHIEncryptionResult_Error; // abort connection + } + } + + GSI_UNUSED(connection); + + if (data->pos == data->len) + return GHIEncryptionResult_Success; + else + return GHIEncryptionResult_Error; // too many or too few bytes, protocol error! +} + +GHIEncryptionResult ghiEncryptorSslEncryptSend(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + int * theBytesSentOut) +{ + GS_FAIL(); // Should never call this for GameSpy SSL! It uses encrypt on buffer + + GSI_UNUSED(connection); + GSI_UNUSED(theEncryptor); + GSI_UNUSED(thePlainTextBuffer); + GSI_UNUSED(thePlainTextLength); + GSI_UNUSED(theBytesSentOut); + + return GHIEncryptionResult_Error; +} + +GHIEncryptionResult ghiEncryptorSslDecryptRecv(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + char * theDecryptedBuffer, + int * theDecryptedLength) +{ + GS_FAIL(); // Should never call this for GameSpy SSL! It uses decrypt on buffer + + GSI_UNUSED(connection); + GSI_UNUSED(theEncryptor); + GSI_UNUSED(theDecryptedBuffer); + GSI_UNUSED(theDecryptedLength); + + return GHIEncryptionResult_Error; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // encryption engine switch + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpEncryption.h b/xrGameSpy/gamespy/ghttp/ghttpEncryption.h new file mode 100644 index 00000000000..f0c0ea005cd --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpEncryption.h @@ -0,0 +1,137 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __GHTTPENCRYPTION_H__ +#define __GHTTPENCRYPTION_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//#include "ghttpCommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Encryption method +typedef enum +{ + GHIEncryptionMethod_None, + GHIEncryptionMethod_Encrypt, // encrypt raw data written to buffer + GHIEncryptionMethod_Decrypt // decrypt raw data written to buffer +} GHIEncryptionMethod; + +// Encryption results +typedef enum +{ + GHIEncryptionResult_None, + GHIEncryptionResult_Success, // successfully encrypted/decrypted + GHIEncryptionResult_BufferTooSmall, // buffer was too small to hold converted data + GHIEncryptionResult_Error // some other kind of error +} GHIEncryptionResult; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +struct GHIEncryptor; // forward declare for callbacks +struct GHIConnection; + +// Called to init the encryption engine +typedef GHIEncryptionResult (*GHTTPEncryptorInitFunc) (struct GHIConnection * theConnection, + struct GHIEncryptor * theEncryptor); + +// Called to connect the socket (some engines do this internally) +typedef GHIEncryptionResult (*GHTTPEncryptorConnectFunc)(struct GHIConnection * theConnection, + struct GHIEncryptor * theEncryptor); + +// Called to start the handshake process engine +typedef GHIEncryptionResult (*GHTTPEncryptorStartFunc)(struct GHIConnection * theConnection, + struct GHIEncryptor * theEncryptor); + +// Called to destroy the encryption engine +typedef GHIEncryptionResult (*GHTTPEncryptorCleanupFunc)(struct GHIConnection * theConnection, + struct GHIEncryptor * theEncryptor); + +// Called when data needs to be encrypted +// - entire plain text buffer will be encrypted +typedef GHIEncryptionResult (*GHTTPEncryptorEncryptFunc)(struct GHIConnection * theConnection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, // [in] + char * theEncryptedBuffer, + int * theEncryptedLength); // [in/out] + +// Called when data needs to be decrypted +// - encrypted data may be left in the buffer +// - decrypted buffer is appended to, not overwritten +typedef GHIEncryptionResult (*GHTTPEncryptorDecryptFunc)(struct GHIConnection * theConnection, + struct GHIEncryptor* theEncryptor, + const char * theEncryptedBuffer, + int * theEncryptedLength, // [in/out] + char * theDecryptedBuffer, + int * theDecryptedLength);// [in/out] + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct GHIEncryptor +{ + void* mInterface; // only SSL is currently supported + GHTTPEncryptionEngine mEngine; + GHTTPBool mInitialized; + GHTTPBool mSessionStarted; // handshake started? + GHTTPBool mSessionEstablished; // handshake completed? + + // (As coded, these two are exclusive!) + // pattern 1 = manually encrypt the buffer, then send using normal socket functions + // pattern 2 = send plain text through the encryption engine, it will send + GHTTPBool mEncryptOnBuffer; // engine encrypts when writing to a buffer? (pattern 1) + GHTTPBool mEncryptOnSend; // engine encrypts when sending over socket? (pattern 2) + + // If GHTTPTrue, the SSL library handles sending/receiving handshake messages + GHTTPBool mLibSendsHandshakeMessages; + + // Functions for engine use + GHTTPEncryptorInitFunc mInitFunc; + GHTTPEncryptorCleanupFunc mCleanupFunc; + GHTTPEncryptorStartFunc mStartFunc; // start the handshake process + GHTTPEncryptorEncryptFunc mEncryptFunc; + GHTTPEncryptorDecryptFunc mDecryptFunc; +} GHIEncryptor; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// ssl encryption +GHIEncryptionResult ghiEncryptorSslInitFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor); +GHIEncryptionResult ghiEncryptorSslCleanupFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor); + +GHIEncryptionResult ghiEncryptorSslStartFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor); + +GHIEncryptionResult ghiEncryptorSslEncryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + char * theEncryptedBuffer, + int * theEncryptedLength); +GHIEncryptionResult ghiEncryptorSslDecryptFunc(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * theEncryptedBuffer, + int * theEncryptedLength, + char * theDecryptedBuffer, + int * theDecryptedLength); +GHIEncryptionResult ghiEncryptorSslEncryptSend(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + const char * thePlainTextBuffer, + int thePlainTextLength, + int * theBytesSent); +GHIEncryptionResult ghiEncryptorSslDecryptRecv(struct GHIConnection * connection, + struct GHIEncryptor * theEncryptor, + char * theDecryptedBuffer, + int * theDecryptedLength); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __GHTTPENCRYPTION_H__ diff --git a/xrGameSpy/gamespy/ghttp/ghttpMain.c b/xrGameSpy/gamespy/ghttp/ghttpMain.c new file mode 100644 index 00000000000..ddbc3bda0fe --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpMain.c @@ -0,0 +1,1485 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2001 GameSpy Industries, Inc + +18002 Skypark Circle +Irvine, California 92614 +949.798.4200 (Tel) +949.798.4299 (Fax) +devsupport@gamespy.com +*/ + +#include "ghttpMain.h" +#include "ghttpASCII.h" +#include "ghttpConnection.h" +#include "ghttpCallbacks.h" +#include "ghttpProcess.h" +#include "ghttpPost.h" +#include "ghttpCommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Ascii versions which must be available even in the unicode build +GHTTPRequest ghttpGetExA(const char * URL, const char * headers, char * buffer, int bufferSize, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param); +GHTTPRequest ghttpSaveExA(const char * URL, const char * filename, const char * headers, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param); +GHTTPRequest ghttpStreamExA(const char * URL, const char * headers, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param); +GHTTPRequest ghttpHeadExA(const char * URL, const char * headers, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param); +GHTTPRequest ghttpPostExA(const char * URL, const char * headers, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param); + + + +// Reference count. +/////////////////// +static int ghiReferenceCount; + +// Called right before callback is called. +// Sets result based on response status code. +///////////////////////////////////////////// +static void ghiHandleStatus +( + GHIConnection * connection +) +{ + // Check the status code. + ///////////////////////// + switch(connection->statusCode / 100) + { + case 1: // Informational. + return; + case 2: // Successful. + return; + case 3: // Redirection. + return; + case 4: // Client Error. + switch(connection->statusCode) + { + case 401: + connection->result = GHTTPUnauthorized; + break; + case 403: + connection->result = GHTTPForbidden; + break; + case 404: + case 410: + connection->result = GHTTPFileNotFound; + break; + default: + connection->result = GHTTPRequestRejected; + break; + } + return; + case 5: // Internal Server Error. + connection->result = GHTTPServerError; + return; + } +} + +// Processes a single connection based on its state. +// Returns true if the connection is finished. +//////////////////////////////////////////////////// +static GHTTPBool ghiProcessConnection +( + GHIConnection * connection +) +{ + GHTTPBool completed; + + assert(connection); + assert(ghiRequestToConnection(connection->request) == connection); + + // Don't process if already processing this connection. + // Happens if, for example, ghttpThink is called from a callback. + ///////////////////////////////////////////////////////////////// + if(connection->processing) + return GHTTPFalse; + + // We're now processing. + //////////////////////// + connection->processing = GHTTPTrue; + + // Process based on state. + // else-if is not used so that if one ghiDo*() + // finishes the one after it can start. + ////////////////////////////////////////////// + + if(connection->state == GHTTPSocketInit) + ghiDoSocketInit(connection); + if(connection->state == GHTTPHostLookup) + ghiDoHostLookup(connection); + if(connection->state == GHTTPLookupPending) + ghiDoLookupPending(connection); + if(connection->state == GHTTPConnecting) + ghiDoConnecting(connection); + if(connection->state == GHTTPSecuringSession) + ghiDoSecuringSession(connection); + if(connection->state == GHTTPSendingRequest) + ghiDoSendingRequest(connection); + if(connection->state == GHTTPPosting) + ghiDoPosting(connection); + if(connection->state == GHTTPWaiting) + ghiDoWaiting(connection); + if(connection->state == GHTTPReceivingStatus) + ghiDoReceivingStatus(connection); + if(connection->state == GHTTPReceivingHeaders) + ghiDoReceivingHeaders(connection); + if(connection->state == GHTTPReceivingFile) + ghiDoReceivingFile(connection); + + // Check for a redirect. + //////////////////////// + if(connection->redirectURL) + ghiRedirectConnection(connection); + + // Grab completed before we possibly free it. + ///////////////////////////////////////////// + completed = connection->completed; + + // Graceful shutdown support. + // Close connection when there is no more data + if (connection->result == GHTTPRequestCancelled && !connection->completed && !CanReceiveOnSocket(connection->socket)) + { + connection->completed = GHTTPTrue; + } + + // Is it finished? + ////////////////// + if(connection->completed) + { + // Set result based on status code. + /////////////////////////////////// + ghiHandleStatus(connection); + + // If we're saving to file, close it before the callback. + ///////////////////////////////////////////////////////// +#ifndef NOFILE + if(connection->saveFile) + { + fclose(connection->saveFile); + connection->saveFile = NULL; + } +#endif + // Log buffer data + ghiLogResponse(connection->getFileBuffer.data, connection->getFileBuffer.len); + + // Call the callback. + ///////////////////// + ghiCallCompletedCallback(connection); + + // Free it. + /////////// + ghiFreeConnection(connection); + } + else + { + // Done processing. This is in the else, + // because we don't want to set it if the + // connection has already been freed. + ///////////////////////////////////////// + connection->processing = GHTTPFalse; + } + + return completed; +} + +void ghttpStartup +( + void +) +{ + // This will just return if we haven't created the lock yet. + //////////////////////////////////////////////////////////// + ghiLock(); + + // One more startup. + //////////////////// + ghiReferenceCount++; + + // Check if we are the first. + ///////////////////////////// + if(ghiReferenceCount == 1) + { + // Create the lock. + /////////////////// + ghiCreateLock(); + + // Set some defaults. + ///////////////////// + ghiThrottleBufferSize = GHI_DEFAULT_THROTTLE_BUFFER_SIZE; + ghiThrottleTimeDelay = GHI_DEFAULT_THROTTLE_TIME_DELAY; + } + else + { + // Unlock the lock. + /////////////////// + ghiUnlock(); + } +} + +void ghttpCleanup +( + void +) +{ + // Lockdown for cleanup. + //////////////////////// + ghiLock(); + + // One less. + //////////// + ghiReferenceCount--; + + // Should we cleanup? + ///////////////////// + if(!ghiReferenceCount) + { + // Cleanup the connections. + /////////////////////////// + ghiCleanupConnections(); + + // Cleanup proxy. + ///////////////// + if(ghiProxyAddress) + { + gsifree(ghiProxyAddress); + ghiProxyAddress = NULL; + } + + // Unlock the lock before freeing it. + ///////////////////////////////////// + ghiUnlock(); + + // Free the lock. + ///////////////// + ghiFreeLock(); + } + else + { + // Unlock our lock. + /////////////////// + ghiUnlock(); + } +} + +GHTTPRequest ghttpGetA +( + const char * URL, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + return ghttpGetExA(URL, NULL, NULL, 0, NULL, GHTTPFalse, blocking, NULL, completedCallback, param); +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpGetW +( + const unsigned short * URL, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024]; + + assert(URL != NULL); + UCS2ToAsciiString(URL, (char*)URL_A); + return ghttpGetA(URL_A, blocking, completedCallback, param); +} +#endif + +GHTTPRequest ghttpGetExA +( + const char * URL, + const char * headers, + char * buffer, + int bufferSize, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + GHTTPBool bResult; + GHIConnection * connection; + + assert(URL && URL[0]); + assert(bufferSize >= 0); + assert(!buffer || bufferSize); + + // Check args. + ////////////// + if(!URL || !URL[0]) + return GHTTPInvalidURL; + if(bufferSize < 0) + return GHTTPInvalidBufferSize; + if(buffer && !bufferSize) + return GHTTPInvalidBufferSize; + + // Startup if it hasn't been done. + ////////////////////////////////// + if(!ghiReferenceCount) + ghttpStartup(); + + // Get a new connection object. + /////////////////////////////// + connection = ghiNewConnection(); + if(!connection) + return GHTTPInsufficientMemory; + + // Fill in the necessary info. + ////////////////////////////// + connection->type = GHIGET; + connection->URL = goastrdup(URL); + if(!connection->URL) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + if(headers && *headers) + { + connection->sendHeaders = goastrdup(headers); + if(!connection->sendHeaders) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + } + connection->post = post; + connection->blocking = blocking; + connection->progressCallback = progressCallback; + connection->completedCallback = completedCallback; + connection->callbackParam = param; + connection->throttle = throttle; + connection->userBufferSupplied = (buffer != NULL)?GHTTPTrue:GHTTPFalse; + if(connection->userBufferSupplied) + bResult = ghiInitFixedBuffer(connection, &connection->getFileBuffer, buffer, bufferSize); + else + bResult = ghiInitBuffer(connection, &connection->getFileBuffer, GET_FILE_BUFFER_INITIAL_SIZE, GET_FILE_BUFFER_INCREMENT_SIZE); + if(!bResult) + { + ghiFreeConnection(connection); + return GHTTPUnspecifiedError; + } + + // Setup the post state if needed. + ////////////////////////////////// + if(post && !ghiPostInitState(connection)) + { + ghiFreeConnection(connection); + return GHTTPInvalidPost; + } + + // Check blocking. + ////////////////// + if(blocking) + { + // Loop until completed. + //////////////////////// + while(!ghiProcessConnection(connection)) + msleep(10); + + // Done. + //////// + return 0; + } + + return connection->request; +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpGetExW +( + const unsigned short * URL, + const unsigned short * headers, + char * buffer, + int bufferSize, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024]; + char headers_A[1024] = { '\0' }; + + assert(URL != NULL); + UCS2ToAsciiString(URL, (char*)URL_A); + if (headers != NULL) + UCS2ToAsciiString(headers, headers_A); + return ghttpGetExA((char*)URL_A, (char*)headers_A, buffer, bufferSize, post, throttle, blocking, progressCallback, completedCallback, param); +} +#endif + +GHTTPRequest ghttpSaveA +( + const char * URL, + const char * filename, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + return ghttpSaveExA(URL, filename, NULL, NULL, GHTTPFalse, blocking, NULL, completedCallback, param); +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpSaveW +( + const unsigned short * URL, + const unsigned short * filename, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024] = { '\0' }; + char filename_A[1024] = { '\0' }; + + assert(URL != NULL); + UCS2ToAsciiString(URL, URL_A); + UCS2ToAsciiString(filename, filename_A); + return ghttpSaveA(URL_A, filename_A, blocking, completedCallback, param); +} +#endif + +static GHTTPRequest _ghttpSaveEx +( + const char * URL, + const gsi_char * filename, + const char * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + GHIConnection * connection; + + assert(URL && URL[0]); + assert(filename && filename[0]); + + // Check args. + ////////////// + if(!URL || !URL[0]) + return GHTTPInvalidURL; + if(!filename || !filename[0]) + return GHTTPInvalidFileName; + + // Startup if it hasn't been done. + ////////////////////////////////// + if(!ghiReferenceCount) + ghttpStartup(); + + // Get a new connection object. + /////////////////////////////// + connection = ghiNewConnection(); + if(!connection) + return GHTTPInsufficientMemory; + + // Fill in the necessary info. + ////////////////////////////// + connection->type = GHISAVE; + connection->URL = goastrdup(URL); + if(!connection->URL) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + if(headers && *headers) + { + connection->sendHeaders = goastrdup(headers); + if(!connection->sendHeaders) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + } + connection->post = post; + connection->blocking = blocking; + connection->progressCallback = progressCallback; + connection->completedCallback = completedCallback; + connection->callbackParam = param; + connection->throttle = throttle; + + // Setup the post state if needed. + ////////////////////////////////// + if(post && !ghiPostInitState(connection)) + { + ghiFreeConnection(connection); + return GHTTPInvalidPost; + } + + // Open the file we're saving to. + ///////////////////////////////// +#ifdef NOFILE + connection->saveFile = NULL; +#else + connection->saveFile = _tfopen(filename, _T("wb")); +#endif + if(!connection->saveFile) + { + ghiFreeConnection(connection); + return GHTTPFailedToOpenFile; + } + + // Check blocking. + ////////////////// + if(blocking) + { + // Loop until completed. + //////////////////////// + while(!ghiProcessConnection(connection)) + msleep(10); + + // Done. + //////// + return 0; + } + + return connection->request; +} + +GHTTPRequest ghttpSaveExA +( + const char * URL, + const char * filename, + const char * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + #ifdef GSI_UNICODE + unsigned short filename_W[1024]; + AsciiToUCS2String(filename, filename_W); + return _ghttpSaveEx(URL, filename_W, headers, post, throttle, blocking, progressCallback, completedCallback, param); + #else + return _ghttpSaveEx(URL, filename, headers, post, throttle, blocking, progressCallback, completedCallback, param); + #endif +} + +#ifdef GSI_UNICODE +GHTTPRequest ghttpSaveExW +( + const unsigned short * URL, + const unsigned short * filename, + const unsigned short * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024]; + //char filename_A[1024] = { '\0' }; + char headers_A[1024] = { '\0' }; + + assert(URL_A != NULL); + UCS2ToAsciiString(URL, URL_A); + //if (filename != NULL) + // UCS2ToAsciiString(filename, filename_A); + if (headers != NULL) + UCS2ToAsciiString(headers, headers_A); + + return _ghttpSaveEx(URL_A, filename, headers_A, post, throttle, blocking, progressCallback, completedCallback, param); +} +#endif + +GHTTPRequest ghttpStreamA +( + const char * URL, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + return ghttpStreamExA(URL, NULL, NULL, GHTTPFalse, blocking, progressCallback, completedCallback, param); +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpStreamW +( + const unsigned short * URL, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char* URL_A = { '\0' }; + UCS2ToAsciiString(URL, URL_A); + return ghttpStreamA(URL_A, blocking, progressCallback, completedCallback, param); +} +#endif + +GHTTPRequest ghttpStreamExA +( + const char * URL, + const char * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + GHIConnection * connection; + + assert(URL && URL[0]); + + // Check args. + ////////////// + if(!URL || !URL[0]) + return GHTTPInvalidURL; + + // Startup if it hasn't been done. + ////////////////////////////////// + if(!ghiReferenceCount) + ghttpStartup(); + + // Get a new connection object. + /////////////////////////////// + connection = ghiNewConnection(); + if(!connection) + return GHTTPInsufficientMemory; + + // Fill in the necessary info. + ////////////////////////////// + connection->type = GHISTREAM; + connection->URL = goastrdup(URL); + if(!connection->URL) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + if(headers && *headers) + { + connection->sendHeaders = goastrdup(headers); + if(!connection->sendHeaders) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + } + connection->post = post; + connection->blocking = blocking; + connection->progressCallback = progressCallback; + connection->completedCallback = completedCallback; + connection->callbackParam = param; + connection->throttle = throttle; + + // Setup the post state if needed. + ////////////////////////////////// + if(post && !ghiPostInitState(connection)) + { + ghiFreeConnection(connection); + return GHTTPInvalidPost; + } + + // Check blocking. + ////////////////// + if(blocking) + { + // Loop until completed. + //////////////////////// + while(!ghiProcessConnection(connection)) + msleep(10); + + // Done. + //////// + return 0; + } + + return connection->request; +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpStreamExW +( + const unsigned short * URL, + const unsigned short * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024] = {'\0'}; + char headers_A[1024] = {'\0'}; + UCS2ToAsciiString(URL, URL_A); + if(headers != NULL) + UCS2ToAsciiString(headers, headers_A); + return ghttpStreamExA(URL_A, headers_A, post, throttle, blocking, progressCallback, completedCallback, param); +} +#endif + +GHTTPRequest ghttpHeadA +( + const char * URL, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + return ghttpHeadExA(URL, NULL, GHTTPFalse, blocking, NULL, completedCallback, param); +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpHeadW +( + const unsigned short * URL, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024] = {'\0'}; + UCS2ToAsciiString(URL, URL_A); + return ghttpHeadA(URL_A, blocking, completedCallback, param); +} +#endif + +GHTTPRequest ghttpHeadExA +( + const char * URL, + const char * headers, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + GHIConnection * connection; + + assert(URL && URL[0]); + + // Check args. + ////////////// + if(!URL || !URL[0]) + return GHTTPInvalidURL; + + // Startup if it hasn't been done. + ////////////////////////////////// + if(!ghiReferenceCount) + ghttpStartup(); + + // Get a new connection object. + /////////////////////////////// + connection = ghiNewConnection(); + if(!connection) + return GHTTPInsufficientMemory; + + // Fill in the necessary info. + ////////////////////////////// + connection->type = GHIHEAD; + connection->URL = goastrdup(URL); + if(!connection->URL) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + if(headers && *headers) + { + connection->sendHeaders = goastrdup(headers); + if(!connection->sendHeaders) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + } + connection->blocking = blocking; + connection->progressCallback = progressCallback; + connection->completedCallback = completedCallback; + connection->callbackParam = param; + connection->throttle = throttle; + + // Check blocking. + ////////////////// + if(blocking) + { + // Loop until completed. + //////////////////////// + while(!ghiProcessConnection(connection)) + msleep(10); + + // Done. + //////// + return 0; + } + + return connection->request; +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpHeadExW +( + const unsigned short * URL, + const unsigned short * headers, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024] = {'\0'}; + char headers_A[1024] = {'\0'}; + if (URL != NULL) + UCS2ToAsciiString(URL, URL_A); + if (headers != NULL) + UCS2ToAsciiString(headers, headers_A); + return ghttpHeadExA(URL_A, headers_A, throttle, blocking, progressCallback, completedCallback, param); +} +#endif + +GHTTPRequest ghttpPostA +( + const char * URL, + GHTTPPost post, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + return ghttpPostExA(URL, NULL, post, GHTTPFalse, blocking, NULL, completedCallback, param); +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpPostW +( + const unsigned short * URL, + GHTTPPost post, + GHTTPBool blocking, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024] = {'\0'}; + UCS2ToAsciiString(URL, URL_A); + return ghttpPostA(URL_A, post, blocking, completedCallback, param); +} +#endif + +GHTTPRequest ghttpPostExA +( + const char * URL, + const char * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + GHIConnection * connection; + + assert(URL && URL[0]); + assert(post); + + // Check args. + ////////////// + if(!URL || !URL[0]) + return GHTTPInvalidURL; + if(!post) + return GHTTPInvalidPost; + + // Startup if it hasn't been done. + ////////////////////////////////// + if(!ghiReferenceCount) + ghttpStartup(); + + // Get a new connection object. + /////////////////////////////// + connection = ghiNewConnection(); + if(!connection) + return GHTTPInsufficientMemory; + + // Fill in the necessary info. + ////////////////////////////// + connection->type = GHIPOST; + connection->URL = goastrdup(URL); + if(!connection->URL) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + if(headers && *headers) + { + connection->sendHeaders = goastrdup(headers); + if(!connection->sendHeaders) + { + ghiFreeConnection(connection); + return GHTTPInsufficientMemory; + } + } + connection->post = post; + connection->blocking = blocking; + connection->progressCallback = progressCallback; + connection->completedCallback = completedCallback; + connection->callbackParam = param; + connection->throttle = throttle; + + // Setup the post state if needed. + ////////////////////////////////// + if(post && !ghiPostInitState(connection)) + { + ghiFreeConnection(connection); + return GHTTPInvalidPost; + } + + // Check blocking. + ////////////////// + if(blocking) + { + // Loop until completed. + //////////////////////// + while(!ghiProcessConnection(connection)) + msleep(10); + + // Done. + //////// + return 0; + } + + return connection->request; +} +#ifdef GSI_UNICODE +GHTTPRequest ghttpPostExW +( + const unsigned short * URL, + const unsigned short * headers, + GHTTPPost post, + GHTTPBool throttle, + GHTTPBool blocking, + ghttpProgressCallback progressCallback, + ghttpCompletedCallback completedCallback, + void * param +) +{ + char URL_A[1024] = {'\0'}; + char headers_A[1024] = {'\0'}; + UCS2ToAsciiString(URL, URL_A); + if (headers != NULL) + UCS2ToAsciiString(headers, headers_A); + return ghttpPostExA(URL_A, headers_A, post, throttle, blocking, progressCallback, completedCallback, param); +} +#endif + +void ghttpThink +( + void +) +{ + // Process all the connections. + /////////////////////////////// + ghiEnumConnections(ghiProcessConnection); +} + +GHTTPBool ghttpRequestThink +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return GHTTPFalse; + + // Think. + ///////// + ghiProcessConnection(connection); + return GHTTPTrue; +} + +void ghttpCancelRequest +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return; + + // Free it. + /////////// + ghiFreeConnection(connection); +} + +#if !defined(INSOCK) +// INSOCK does not support partial shutdown +void ghttpCloseRequest +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + connection = ghiRequestToConnection(request); + if (!connection) + return; + + if (connection->socket) + { + // Gracefully close the connection + // SDK will dispatch a "request cancelled" callback when all data + // has been received + shutdown(connection->socket, 1); + connection->result = GHTTPRequestCancelled; + } +} +#endif + +GHTTPState ghttpGetState +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return (GHTTPState)0; + + return connection->state; +} + +const char * ghttpGetResponseStatus +( + GHTTPRequest request, + int * statusCode +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return NULL; + + // Check if we don't have the status yet. + ///////////////////////////////////////// + if(connection->state <= GHTTPReceivingStatus) + return NULL; + + // Set the status code. + /////////////////////// + if(statusCode) + *statusCode = connection->statusCode; + + return (connection->recvBuffer.data + connection->statusStringIndex); +} + +const char * ghttpGetHeaders +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return NULL; + + // Check if we don't have the headers yet. + ////////////////////////////////////////// + if(connection->state < GHTTPReceivingHeaders) + return NULL; + + // Verify we have headers. + ////////////////////////// + if(connection->headerStringIndex >= connection->recvBuffer.len) + return NULL; + + return (connection->recvBuffer.data + connection->headerStringIndex); +} + +const char * ghttpGetURL +( + GHTTPRequest request +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return NULL; + + return connection->URL; +} + +GHTTPBool ghttpSetProxy +( + const char * server +) +{ + return ghiSetProxy(server); +} + +GHTTPBool ghttpSetRequestProxy +( + GHTTPRequest request, + const char * server +) +{ + return ghiSetRequestProxy(request, server); +} + + +void ghttpSetThrottle +( + GHTTPRequest request, + GHTTPBool throttle +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return; + + connection->throttle = throttle; + + // Set the buffer size based on the throttle setting. + ///////////////////////////////////////////////////// + if(connection->socket != INVALID_SOCKET) + SetReceiveBufferSize(connection->socket, throttle?ghiThrottleBufferSize:(8 * 1024)); +} + +void ghttpThrottleSettings +( + int bufferSize, + gsi_time timeDelay +) +{ + ghiThrottleSettings(bufferSize, timeDelay); +} + +void ghttpSetMaxRecvTime +( + GHTTPRequest request, + gsi_time maxRecvTime +) +{ + GHIConnection* connection = ghiRequestToConnection(request); + if (connection == NULL) + return; + + connection->maxRecvTime = maxRecvTime; +} + +// Internal prototypes for persistent HTTP connections +// Prevents warnings from strict compilers +////////////////////////////////////////////////////// +SOCKET ghttpGetSocket(GHTTPRequest request); +GHTTPBool ghttpReuseSocket(GHTTPRequest request, SOCKET socket); + +// For use in persistent HTTP connections +// Call this in the completed callback to obtain the socket, which can be used with +// ghttpReuseSocket to make a second request to the same host +/////////////////////////////////////////////////////////////////// +SOCKET ghttpGetSocket +( + GHTTPRequest request +) +{ + GHIConnection * connection; + SOCKET ret; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return INVALID_SOCKET; + + // Only allow them to grab the socket during the competion callback (not while a request is in process) + ///////////////////////////////////////////////////////// + if (!connection->completed) + return INVALID_SOCKET; + + ret = connection->socket; + // Mark the connection as invalid so that it doesn't get closed + connection->socket = INVALID_SOCKET; + + return ret; +} + +// For use in persistent HTTP connections +// Call this after creating a request, but before calling think the first time in order to reuse +// an existing connection to the same server +// If the socket passed is INVALID_SOCKET, a new connection will be created and marked as persistent +/////////////////////////////////////////////////////////////////// +GHTTPBool ghttpReuseSocket +( + GHTTPRequest request, + SOCKET socket +) +{ + GHIConnection * connection; + + // Get the connection object for this request. + ////////////////////////////////////////////// + connection = ghiRequestToConnection(request); + if(!connection) + return GHTTPFalse; + if (connection->state != GHTTPSocketInit) + return GHTTPFalse; + if (connection->socket != INVALID_SOCKET) + return GHTTPFalse; + + connection->persistConnection = GHTTPTrue; + connection->socket = socket; + + + /* + if (socket == INVALID_SOCKET) + { + // The connection is marked as persistent, but we still need to lookup and connect, so don't advance the state + ///////////////////////////////////////////////////////////////////// + return GHTTPTrue; + } + + // Skip the host lookup & connect - send data once the socket is writable + ////////////////////////////////////////////// + connection->state = GHTTPConnecting; + */ + return GHTTPTrue; +} + + +GHTTPPost ghttpNewPost +( + void +) +{ + return ghiNewPost(); +} + +void ghttpPostSetAutoFree +( + GHTTPPost post, + GHTTPBool autoFree +) +{ + assert(post); + if(!post) + return; + + ghiPostSetAutoFree(post, autoFree); +} + +void ghttpFreePost +( + GHTTPPost post +) +{ + assert(post); + if(!post) + return; + + ghiFreePost(post); +} + +GHTTPBool ghttpPostAddStringA +( + GHTTPPost post, + const char * name, + const char * string +) +{ + assert(post); + assert(name && name[0]); + + if(!post) + return GHTTPFalse; + if(!name || !name[0]) + return GHTTPFalse; + if(!string) + string = ""; + + return ghiPostAddString(post, name, string); +} +#ifdef GSI_UNICODE +GHTTPBool ghttpPostAddStringW +( + GHTTPPost post, + const unsigned short * name, + const unsigned short * string +) +{ + char name_A[1024] = {'\0'}; + char string_A[1024] = {'\0'}; + if (name != NULL) + UCS2ToAsciiString(name, name_A); + if (string != NULL) + UCS2ToAsciiString(string, string_A); + return ghttpPostAddStringA(post, name_A, string_A); +} +#endif + +GHTTPBool ghttpPostAddFileFromDiskA +( + GHTTPPost post, + const char * name, + const char * filename, + const char * reportFilename, + const char * contentType +) +{ + assert(post); + assert(name && name[0]); + assert(filename && filename[0]); + + if(!post) + return GHTTPFalse; + if(!name || !name[0]) + return GHTTPFalse; + if(!filename || !filename[0]) + return GHTTPFalse; + if(!reportFilename || !reportFilename[0]) + reportFilename = filename; + if(!contentType) + contentType = "application/octet-stream"; + + return ghiPostAddFileFromDisk(post, name, filename, reportFilename, contentType); +} +#ifdef GSI_UNICODE +GHTTPBool ghttpPostAddFileFromDiskW +( + GHTTPPost post, + const unsigned short * name, + const unsigned short * filename, + const unsigned short * reportFilename, + const unsigned short * contentType +) +{ + char name_A[1024] = {'\0'}; + char filename_A[1024] = {'\0'}; + char reportFilename_A[1024] = {'\0'}; + char contentType_A[1024] = {'\0'}; + if (name != NULL) UCS2ToAsciiString(name, name_A); + if (filename != NULL) UCS2ToAsciiString(filename, filename_A); + if (reportFilename != NULL) UCS2ToAsciiString(reportFilename, reportFilename_A); + if (contentType != NULL) UCS2ToAsciiString(contentType, contentType_A); + return ghttpPostAddFileFromDiskA(post, name_A, filename_A, reportFilename_A, contentType_A); +} +#endif + +GHTTPBool ghttpPostAddFileFromMemoryA +( + GHTTPPost post, + const char * name, + const char * buffer, + int bufferLen, + const char * reportFilename, + const char * contentType +) +{ + assert(post); + assert(name && name[0]); + assert(bufferLen >= 0); +#ifdef _DEBUG + if(bufferLen > 0) + assert(buffer); +#endif + assert(reportFilename && reportFilename[0]); + + if(!post) + return GHTTPFalse; + if(!name || !name[0]) + return GHTTPFalse; + if(bufferLen < 0) + return GHTTPFalse; + if(!bufferLen && !buffer) + return GHTTPFalse; + if(!contentType) + contentType = "application/octet-stream"; + + return ghiPostAddFileFromMemory(post, name, buffer, bufferLen, reportFilename, contentType); +} +#ifdef GSI_UNICODE +GHTTPBool ghttpPostAddFileFromMemoryW +( + GHTTPPost post, + const unsigned short * name, + const char * buffer, + int bufferLen, + const unsigned short * reportFilename, + const unsigned short * contentType +) +{ + char name_A[1024] = { '\0' }; + char reportFilename_A[1024] = { '\0' }; + char contentType_A[1024] = { '\0' }; + if (name != NULL) + UCS2ToAsciiString(name, name_A); + if (reportFilename != NULL) + UCS2ToAsciiString(reportFilename, reportFilename_A); + if (contentType != NULL) + UCS2ToAsciiString(contentType, contentType_A); + + + return ghttpPostAddFileFromMemoryA(post, name_A, buffer, bufferLen, reportFilename_A, contentType_A); + + GSI_UNUSED(reportFilename); + GSI_UNUSED(contentType); +} +#endif + +GHTTPBool ghttpPostAddXml +( + GHTTPPost post, + GSXmlStreamWriter soap +) +{ + GS_ASSERT(post != NULL); + GS_ASSERT(soap != NULL); + + return ghiPostAddXml(post, soap); +} + +void ghttpPostSetCallback +( + GHTTPPost post, + ghttpPostCallback callback, + void * param +) +{ + assert(post); + + if(!post) + return; + + ghiPostSetCallback(post, callback, param); +} + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpMain.h b/xrGameSpy/gamespy/ghttp/ghttpMain.h new file mode 100644 index 00000000000..0b19a7cd84c --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpMain.h @@ -0,0 +1,19 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPMAIN_H_ +#define _GHTTPMAIN_H_ + +#include +#include "ghttp.h" +#include "../common/gsCommon.h" +#include "../common/gsStringUtil.h" + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpPost.c b/xrGameSpy/gamespy/ghttp/ghttpPost.c new file mode 100644 index 00000000000..fd4d05afddc --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpPost.c @@ -0,0 +1,1647 @@ +/* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 1334, 1344, 1400, 1410 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + +#include "ghttpPost.h" +#include "ghttpMain.h" +#include "ghttpConnection.h" +#include "ghttpCommon.h" + +#include "../common/gsCrypt.h" +#include "../common/gsSSL.h" +#include "../common/gsXML.h" + + +// The border between parts in a file send. +/////////////////////////////////////////// +#define GHI_MULTIPART_BOUNDARY "Qr4G823s23d---<<><><<<>--7d118e0536" +#define GHI_MULTIPART_BOUNDARY_BASE "--" GHI_MULTIPART_BOUNDARY +#define GHI_MULTIPART_BOUNDARY_FIRST GHI_MULTIPART_BOUNDARY_BASE CRLF +#define GHI_MULTIPART_BOUNDARY_NORMAL CRLF GHI_MULTIPART_BOUNDARY_BASE CRLF +#define GHI_MULTIPART_BOUNDARY_END CRLF GHI_MULTIPART_BOUNDARY_BASE "--" CRLF + +#define GHI_LEGAL_URLENCODED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_@-.*" +#define GHI_DIGITS "0123456789ABCDEF" + +// DIME header settings + // first byte is a combination of VERSION + first/last/chunked +#define GHI_DIME_VERSION (0x1<<3) // 5th bit (from the left) +#define GHI_DIMEFLAG_FIRSTRECORD (1<<2) +#define GHI_DIMEFLAG_LASTRECORD (1<<1) +#define GHI_DIMEFLAG_CHUNKED (1<<0) + // second byte is combination of TYPE_T and reserved (4bits = 0) +#define GHI_DIMETYPE_T_UNCHANGED (0x0 << 4) +#define GHI_DIMETYPE_T_MEDIA (0x1 << 4) +#define GHI_DIMETYPE_T_URI (0x2 << 4) +#define GHI_DIMETYPE_T_UNKNOWN (0x3 << 4) +#define GHI_DIMETYPE_T_EMPTY (0x4 << 4) // lengths must be set to 0 + +//#define GHI_DIME_SOAPID "gsi:soap" +#define GHI_DIME_SOAPID "cid:id0" +#define GHI_DIME_SOAPTYPE "http://schemas.xmlsoap.org/soap/envelope/" + +typedef struct GSIDimeHeader +{ + gsi_u8 mVersionAndFlags; + gsi_u8 mTypeT; + gsi_u16 mOptionsLength; + gsi_u16 mIdLength; + gsi_u16 mTypeLength; + gsi_u32 mDataLength; + // gsi_u8 mOptions[mOptionsLength]; + // gsi_u8 mId[mIdLength]; + // gsi_u8 mType[mTypeLength]; + // gsi_u8 mData[mDataLength]; +} GHIDimeHeader; + +// POST TYPES. +////////////// +typedef enum +{ + GHIString, // A regular string. + GHIFileDisk, // A file from disk. + GHIFileMemory, // A file from memory. + GHIXmlData // XML Soap. (long string) +} GHIPostDataType; + +// POST OBJECT. +/////////////// +typedef struct GHIPost +{ + DArray data; + ghttpPostCallback callback; + void * param; + GHTTPBool hasFiles; + GHTTPBool hasSoap; + GHTTPBool useDIME; + GHTTPBool autoFree; +} GHIPost; + +// POST DATA. +///////////// +typedef struct GHIPostStringData +{ + char * string; + int len; + GHTTPBool invalidChars; + int extendedChars; +} GHIPostStringData; + +typedef struct GHIPostFileDiskData +{ + char * filename; + char * reportFilename; + char * contentType; +} GHIPostFileDiskData; + +typedef struct GHIPostFileMemoryData +{ + const char * buffer; + int len; + char * reportFilename; + char * contentType; +} GHIPostFileMemoryData; + +typedef struct GHIPostXmlData +{ + GSXmlStreamWriter xml; +} GHIPostXmlData; + +typedef struct GHIPostData +{ + GHIPostDataType type; + char * name; + union + { + GHIPostStringData string; + GHIPostFileDiskData fileDisk; + GHIPostFileMemoryData fileMemory; + GHIPostXmlData xml; + } data; +} GHIPostData; + +// POST STATE. +////////////// +//typedef struct GHIPostStringState +//{ +//} GHIPostStringState; + +typedef struct GHIPostFileDiskState +{ + FILE * file; + long len; +} GHIPostFileDiskState; + +//typedef struct GHIPostFileMemoryState +//{ +//} GHIPostFileMemoryState; + + +//typedef struct GHIPostSoapState +//{ +//} GHIPostSoapState; + +typedef struct GHIPostState +{ + GHIPostData * data; + int pos; + union + { + //GHIPostStringState string; + GHIPostFileDiskState fileDisk; + //GHIPostFileMemoryState fileMemory; + //GHIPostSoapState soap; + } state; +} GHIPostState; + +// FUNCTIONS. +///////////// +static void ghiPostDataFree +( + void * elem +) +{ + GHIPostData * data = (GHIPostData *)elem; + + // Free the name. + ///////////////// + if (data->type != GHIXmlData) + gsifree(data->name); + + // Free based on type. + ////////////////////// + if(data->type == GHIString) + { + // Free the string string. + ///////////////////////// + gsifree(data->data.string.string); + } + else if(data->type == GHIFileDisk) + { + // Free the strings. + //////////////////// + gsifree(data->data.fileDisk.filename); + gsifree(data->data.fileDisk.reportFilename); + gsifree(data->data.fileDisk.contentType); + } + else if(data->type == GHIFileMemory) + { + // Free the strings. + //////////////////// + gsifree(data->data.fileMemory.reportFilename); + gsifree(data->data.fileMemory.contentType); + } + else if(data->type == GHIXmlData) + { + gsXmlFreeWriter(data->data.xml.xml); + } + else + { + // The type didn't match any known types. + ///////////////////////////////////////// + assert(0); + } +} + +GHTTPPost ghiNewPost +( + void +) +{ + GHIPost * post; + + // Allocate the post object. + //////////////////////////// + post = (GHIPost *)gsimalloc(sizeof(GHIPost)); + if(!post) + return NULL; + + // Initialize it. + ///////////////// + memset(post, 0, sizeof(GHIPost)); + post->autoFree = GHTTPTrue; + + // Create the array of data objects. + //////////////////////////////////// + post->data = ArrayNew(sizeof(GHIPostData), 0, ghiPostDataFree); + if(!post->data) + { + gsifree(post); + return NULL; + } + + return (GHTTPPost)post; +} + +void ghiPostSetAutoFree +( + GHTTPPost _post, + GHTTPBool autoFree +) +{ + GHIPost * post = (GHIPost *)_post; + + post->autoFree = autoFree; +} + +GHTTPBool ghiIsPostAutoFree +( + GHTTPPost _post +) +{ + GHIPost * post = (GHIPost *)_post; + + return post->autoFree; +} + +void ghiFreePost +( + GHTTPPost _post +) +{ + GHIPost * post = (GHIPost *)_post; + + // Free the array of data objects. + ////////////////////////////////// + ArrayFree(post->data); + + // Free the post object. + //////////////////////// + gsifree(post); +} + +GHTTPBool ghiPostAddString +( + GHTTPPost _post, + const char * name, + const char * string +) +{ + GHIPost * post = (GHIPost *)_post; + GHIPostData data; + int len; + int rcode; + + // Copy the strings. + //////////////////// + name = goastrdup(name); + string = goastrdup(string); + if(!name || !string) + { + gsifree((char *)name); + gsifree((char *)string); + return GHTTPFalse; + } + + // Set the data. + //////////////// + memset(&data, 0, sizeof(GHIPostData)); + data.type = GHIString; + data.name = (char *)name; + data.data.string.string = (char *)string; + len = (int)strlen(string); + data.data.string.len = len; + data.data.string.invalidChars = GHTTPFalse; + + // Are there any invalid characters? + //////////////////////////////////// + rcode = (int)strspn(string, GHI_LEGAL_URLENCODED_CHARS); + if(rcode != len) + { + int i; + int count = 0; + + data.data.string.invalidChars = GHTTPTrue; + + // Count the number, not including spaces. + ////////////////////////////////////////// + for(i = 0 ; string[i] ; i++) + if(!strchr(GHI_LEGAL_URLENCODED_CHARS, string[i]) && (string[i] != ' ')) + count++; + + data.data.string.extendedChars = count; + } + + // Add it. + ////////// + ArrayAppend(post->data, &data); + + return GHTTPTrue; +} + +GHTTPBool ghiPostAddFileFromDisk +( + GHTTPPost _post, + const char * name, + const char * filename, + const char * reportFilename, + const char * contentType +) +{ + GHIPost * post = (GHIPost *)_post; + GHIPostData data; + + // Copy the strings. + //////////////////// + name = goastrdup(name); + filename = goastrdup(filename); + reportFilename = goastrdup(reportFilename); + contentType = goastrdup(contentType); + if(!name || !filename || !reportFilename || !contentType) + { + gsifree((char *)name); + gsifree((char *)filename); + gsifree((char *)reportFilename); + gsifree((char *)contentType); + return GHTTPFalse; + } + + // Set the data. + //////////////// + memset(&data, 0, sizeof(GHIPostData)); + data.type = GHIFileDisk; + data.name = (char *)name; + data.data.fileDisk.filename = (char *)filename; + data.data.fileDisk.reportFilename = (char *)reportFilename; + data.data.fileDisk.contentType = (char *)contentType; + + // Add it. + ////////// + ArrayAppend(post->data, &data); + + // We have files. + ///////////////// + post->hasFiles = GHTTPTrue; + + // if we have both soap and a file we MUST use DIME + if (post->hasSoap == GHTTPTrue) + post->useDIME = GHTTPTrue; + + return GHTTPTrue; +} + +GHTTPBool ghiPostAddFileFromMemory +( + GHTTPPost _post, + const char * name, + const char * buffer, + int bufferLen, + const char * reportFilename, + const char * contentType +) +{ + GHIPost * post = (GHIPost *)_post; + GHIPostData data; + + // Copy the strings. + //////////////////// + name = goastrdup(name); + reportFilename = goastrdup(reportFilename); + contentType = goastrdup(contentType); + if(!name || !reportFilename || !contentType) + { + gsifree((char *)name); + gsifree((char *)reportFilename); + gsifree((char *)contentType); + return GHTTPFalse; + } + + // Set it. + ////////// + memset(&data, 0, sizeof(GHIPostData)); + data.type = GHIFileMemory; + data.name = (char *)name; + data.data.fileMemory.buffer = (char *)buffer; + data.data.fileMemory.len = bufferLen; + data.data.fileMemory.reportFilename = (char *)reportFilename; + data.data.fileMemory.contentType = (char *)contentType; + + // Add it. + ////////// + ArrayAppend(post->data, &data); + + // We have a file. + ////////////////// + post->hasFiles = GHTTPTrue; + + // if we have both soap and a file we MUST use DIME + if (post->hasSoap == GHTTPTrue) + post->useDIME = GHTTPTrue; + + return GHTTPTrue; +} + +GHTTPBool ghiPostAddXml +( + GHTTPPost _post, + GSXmlStreamWriter xml +) +{ + GHIPostData data; + //unsigned int rcode = 0; + + GHIPost * post = (GHIPost *)_post; + + data.type = GHIXmlData; + data.data.xml.xml = xml; + ArrayAppend(post->data, &data); + post->hasSoap = GHTTPTrue; + + // if we have both soap and a file we MUST use DIME + if (post->hasFiles == GHTTPTrue) + post->useDIME = GHTTPTrue; + + return GHTTPTrue; +} + +void ghiPostSetCallback +( + GHTTPPost _post, + ghttpPostCallback callback, + void * param +) +{ + GHIPost * post = (GHIPost *)_post; + + // Set the callback and param. + ////////////////////////////// + post->callback = callback; + post->param = param; +} + +const char * ghiPostGetContentType +( + struct GHIConnection * connection +) +{ + GHIPost * post = connection->post; + + assert(post); + if(!post) + return ""; + + // Report content-type based on if we are sending files or not. + /////////////////////////////////////////////////////////////// + if(post->useDIME) + return ("application/dime"); + else if (post->hasFiles) + { + GS_ASSERT(!post->hasSoap); + return ("multipart/form-data; boundary=" GHI_MULTIPART_BOUNDARY); + } + else if (post->hasSoap) + { + GS_ASSERT(!post->hasFiles); + return ("text/xml"); + } + else + { + GS_ASSERT(!post->hasSoap); + GS_ASSERT(!post->hasFiles); + return "application/x-www-form-urlencoded"; + } +} + +static int ghiPostGetNoFilesContentLength +( + struct GHIConnection * connection +) +{ + GHIPost * post = connection->post; + GHIPostData * data; + int i; + int num; + int total = 0; + int foundSoapAlready = 0; + + num = ArrayLength(post->data); + if(!num) + return 0; + + for(i = 0 ; i < num ; i++) + { + data = (GHIPostData *)ArrayNth(post->data, i); + + GS_ASSERT(data->type == GHIString || data->type == GHIXmlData); + + if (data->type == GHIString) + { + total += (int)strlen(data->name); + total += data->data.string.len; + total += (data->data.string.extendedChars * 2); + total++; // '=' + } + else if (data->type == GHIXmlData) + { + GS_ASSERT(foundSoapAlready == 0); // only support one soap object per request + foundSoapAlready = 1; + total += gsXmlWriterGetDataLength(data->data.xml.xml); + } + } + + total += (num - 1); // '&' + + GSI_UNUSED(foundSoapAlready); + return total; +} + +static int ghiPostGetHasFilesContentLength +( + struct GHIConnection * connection +) +{ + GHIPost * post = connection->post; + GHIPostData * data; + int i; + int num; + int total = 0; + int foundSoapAlready = 0; + static int boundaryLen; + static int stringBaseLen; + static int fileBaseLen; + static int endLen; + static int xmlBaseLen; + + if(!boundaryLen) + { + if (post->useDIME) + { + GS_ASSERT(post->hasSoap); + GS_ASSERT(post->hasFiles); + boundaryLen = sizeof(GHIDimeHeader); + stringBaseLen = boundaryLen; + fileBaseLen = boundaryLen; + xmlBaseLen = boundaryLen; + endLen = 0; + } + else + { + GS_ASSERT(!post->hasSoap); + boundaryLen = (int)strlen(GHI_MULTIPART_BOUNDARY_BASE); + stringBaseLen = (boundaryLen + 47); // + name + string + fileBaseLen = (boundaryLen + 76); // + name + filename + content-type + file + xmlBaseLen = 0; // no boundaries for text/xml type soap + endLen = (boundaryLen + 4); + } + } + + num = ArrayLength(post->data); + + for(i = 0 ; i < num ; i++) + { + data = (GHIPostData *)ArrayNth(post->data, i); + + if(data->type == GHIString) + { + total += stringBaseLen; + total += (int)strlen(data->name); + total += data->data.string.len; + } + else if(data->type == GHIFileDisk) + { + GHIPostState * state; + + total += fileBaseLen; + total += (int)strlen(data->name); + total += (int)strlen(data->data.fileDisk.contentType); + state = (GHIPostState *)ArrayNth(connection->postingState.states, i); + assert(state); + total += (int)state->state.fileDisk.len; + + if (!post->useDIME) + total += (int)strlen(data->data.fileDisk.reportFilename); + + if (post->useDIME) + { + // have to include padding bytes! + int padBytes = 0; + + padBytes = 4-(int)strlen(data->name)%4; + if (padBytes != 4) + total += padBytes; + padBytes = 4-(int)strlen(data->data.fileDisk.contentType)%4; + if (padBytes != 4) + total += padBytes; + padBytes = 4-(int)state->state.fileDisk.len%4; + if (padBytes != 4) + total += padBytes; + } + } + else if(data->type == GHIFileMemory) + { + total += fileBaseLen; + total += (int)strlen(data->name); + total += (int)strlen(data->data.fileMemory.contentType); + total += data->data.fileMemory.len; + + if (!post->useDIME) + total += (int)strlen(data->data.fileMemory.reportFilename); + + if (post->useDIME) + { + // have to include padding bytes! + int padBytes = 0; + + padBytes = 4-(int)strlen(data->name)%4; + if (padBytes != 4) + total += padBytes; + padBytes = 4-(int)strlen(data->data.fileMemory.contentType)%4; + if (padBytes != 4) + total += padBytes; + padBytes = 4-(int)data->data.fileMemory.len%4; + if (padBytes != 4) + total += padBytes; + } + } + else if(data->type == GHIXmlData) + { + int padBytes = 0; + + GS_ASSERT(foundSoapAlready == 0); // only one soap envelope per request + GS_ASSERT(post->useDIME); // soap+file = use DIME + foundSoapAlready = 1; + total += xmlBaseLen; + total += gsXmlWriterGetDataLength(data->data.xml.xml); + + // have to include padding bytes! + padBytes = 4-(int)gsXmlWriterGetDataLength(data->data.xml.xml)%4; + if (padBytes != 4) + total += padBytes; + total += (int)strlen(GHI_DIME_SOAPID); + padBytes = 4-(int)strlen(GHI_DIME_SOAPID)%4; + if (padBytes != 4) + total += padBytes; + total += (int)strlen(GHI_DIME_SOAPTYPE); + padBytes = 4-(int)strlen(GHI_DIME_SOAPTYPE)%4; + if (padBytes != 4) + total += padBytes; + } + else + { + assert(0); + return 0; + } + } + + // Add the end. + /////////////// + total += endLen; + + GSI_UNUSED(foundSoapAlready); + return total; +} + +static int ghiPostGetContentLength +( + struct GHIConnection * connection +) +{ + GHIPost * post = connection->post; + + assert(post); + if(!post) + return 0; + + if(post->hasFiles) + return ghiPostGetHasFilesContentLength(connection); + + return ghiPostGetNoFilesContentLength(connection); +} + +static GHTTPBool ghiPostStateInit +( + GHIPostState * state +) +{ + GHIPostDataType type; + + // The type. + //////////// + type = state->data->type; + + // Set the position to sending header. + ////////////////////////////////////// + state->pos = -1; + + // Init based on type. + ////////////////////// + if(type == GHIString) + { + } + else if(type == GHIFileDisk) + { + // Open the file. + ///////////////// +#ifndef NOFILE + state->state.fileDisk.file = fopen(state->data->data.fileDisk.filename, "rb"); +#endif + if(!state->state.fileDisk.file) + return GHTTPFalse; + + // Get the file length. + /////////////////////// + if(fseek(state->state.fileDisk.file, 0, SEEK_END) != 0) + return GHTTPFalse; + state->state.fileDisk.len = ftell(state->state.fileDisk.file); + if(state->state.fileDisk.len == EOF) + return GHTTPFalse; + rewind(state->state.fileDisk.file); + } + else if(type == GHIFileMemory) + { + } + else if(type == GHIXmlData) + { + } + else + { + // The type didn't match any known types. + ///////////////////////////////////////// + assert(0); + + return GHTTPFalse; + } + + return GHTTPTrue; +} + +static void ghiPostStateCleanup +( + GHIPostState * state +) +{ + GHIPostDataType type; + + // The type. + //////////// + type = state->data->type; + + // Init based on type. + ////////////////////// + if(type == GHIString) + { + } + else if(type == GHIFileDisk) + { + if(state->state.fileDisk.file) + fclose(state->state.fileDisk.file); + state->state.fileDisk.file = NULL; + } + else if(type == GHIFileMemory) + { + } + else if(type == GHIXmlData) + { + } + else + { + // The type didn't match any known types. + ///////////////////////////////////////// + assert(0); + } +} + +GHTTPBool ghiPostInitState +( + struct GHIConnection * connection +) +{ + int i; + int len; + GHIPostData * data; + GHIPostState state; + GHIPostState * pState; + + assert(connection->post); + if(!connection->post) + return GHTTPFalse; + + // Create an array for the states. + ////////////////////////////////// + connection->postingState.index = 0; + connection->postingState.bytesPosted = 0; + connection->postingState.totalBytes = 0; + connection->postingState.completed = GHTTPFalse; + connection->postingState.callback = connection->post->callback; + connection->postingState.param = connection->post->param; + len = ArrayLength(connection->post->data); + connection->postingState.states = ArrayNew(sizeof(GHIPostState), len, NULL); + if(!connection->postingState.states) + return GHTTPFalse; + + // Setup all the states. + //////////////////////// + for(i = 0 ; i < len ; i++) + { + // Get the data object for this index. + ////////////////////////////////////// + data = (GHIPostData *)ArrayNth(connection->post->data, i); + + // Initialize the state's members. + ////////////////////////////////// + memset(&state, 0, sizeof(GHIPostState)); + state.data = data; + + // Call the init function. + ////////////////////////// + if(!ghiPostStateInit(&state)) + { + // We need to cleanup everything we just initialized. + ///////////////////////////////////////////////////// + for(i-- ; i >= 0 ; i--) + { + pState = (GHIPostState *)ArrayNth(connection->postingState.states, i); + ghiPostStateCleanup(pState); + } + + // Free the array. + ////////////////// + ArrayFree(connection->postingState.states); + connection->postingState.states = NULL; + + return GHTTPFalse; + } + + // Add it to the array. + /////////////////////// + ArrayAppend(connection->postingState.states, &state); + } + + // If this asserts, there aren't the same number of state objects as data objects. + // There should be a 1-to-1 mapping between data and states. + ////////////////////////////////////////////////////////////////////////////////// + assert(ArrayLength(connection->post->data) == ArrayLength(connection->postingState.states)); + + // Get the total number of bytes. + ///////////////////////////////// + connection->postingState.totalBytes = ghiPostGetContentLength(connection); + + // Wait for continue before posting. + // -- Enabled for Soap messages only + // -- Disabled for all other content because many web servers do not support it + ////////////////////////////////////////////////////// + if (connection->post->hasSoap == GHTTPTrue) + connection->postingState.waitPostContinue = GHTTPTrue; + else + connection->postingState.waitPostContinue = GHTTPFalse; + + return GHTTPTrue; +} + +void ghiPostCleanupState +( + struct GHIConnection * connection +) +{ + int i; + int len; + GHIPostState * state; + + // Loop through and call the cleanup function. + ////////////////////////////////////////////// + if(connection->postingState.states) + { + len = ArrayLength(connection->postingState.states); + for(i = 0 ; i < len ; i++) + { + state = (GHIPostState *)ArrayNth(connection->postingState.states, i); + ghiPostStateCleanup(state); + } + + // Free the array. + ////////////////// + ArrayFree(connection->postingState.states); + connection->postingState.states = NULL; + } + + // Free the post. + ///////////////// + if(connection->post && connection->post->autoFree) + { + ghiFreePost(connection->post); + connection->post = NULL; + } +} + +static GHIPostingResult ghiPostStringStateDoPosting +( + GHIPostState * state, + GHIConnection * connection +) +{ + //GHTTPBool result; + + assert(state->pos >= 0); + + // Is this an empty string? + /////////////////////////// + if(state->data->data.string.len == 0) + return GHIPostingDone; + + assert(state->pos < state->data->data.string.len); + + // If we're doing a simple post, we need to fix invalid characters. + // - only applies to simple posts + /////////////////////////////////////////////////////////////////// + if(!connection->post->hasFiles && !connection->post->hasSoap && state->data->data.string.invalidChars) + { + int i; + int c; + const char * string = state->data->data.string.string; + char hex[4] = "%00"; + GHIBuffer *writeBuffer; + + // When encrypting, we need space for two copies + if (connection->encryptor.mEngine == GHTTPEncryptionEngine_None) + writeBuffer = &connection->sendBuffer; + else + writeBuffer = &connection->encodeBuffer; + + // This could probably be done a lot better. + //////////////////////////////////////////// + for(i = 0 ; (c = string[i]) != 0 ; i++) + { + if(strchr(GHI_LEGAL_URLENCODED_CHARS, c)) + { + // Legal. + ///////// + //result = ghiAppendCharToBuffer(writeBuffer, c); + ghiAppendCharToBuffer(writeBuffer, c); + } + else if(c == ' ') + { + // Space. + ///////// + //result = ghiAppendCharToBuffer(writeBuffer, '+'); + ghiAppendCharToBuffer(writeBuffer, '+'); + } + else + { + // To hex. + ////////// + assert((c / 16) < 16); + hex[1] = GHI_DIGITS[c / 16]; + hex[2] = GHI_DIGITS[c % 16]; + //result = ghiAppendDataToBuffer(writeBuffer, hex, 3); + ghiAppendDataToBuffer(writeBuffer, hex, 3); + } + } + } + else + { + // copy the string as-is, encrypting if necessary + GHITrySendResult result = ghiTrySendThenBuffer(connection, + state->data->data.string.string, state->data->data.string.len); + if (result == GHITrySendError) + return GHIPostingError; + else + return GHIPostingDone; + } + + // Send the URL fixed string + //////////////////////////// + if (connection->encryptor.mEngine == GHTTPEncryptionEngine_None) + { + // The URL fixed string was written to the send buffer, so send it! + if (!ghiSendBufferedData(connection)) + return GHIPostingError; + + if (connection->sendBuffer.pos == connection->sendBuffer.len) + ghiResetBuffer(&connection->sendBuffer); + return GHIPostingDone; + } + else + { + // SSL data is in the "to be encrypted" buffer, so wait until + // we have the full MIME form before encrypting (for efficiency) + return GHIPostingDone; + } +} + +static GHIPostingResult ghiPostXmlStateDoPosting +( + GHIPostState * state, + GHIConnection * connection +) +{ + GSXmlStreamWriter xml = state->data->data.xml.xml; + char pad[3] = { '\0', '\0', '\0' }; + int padlen = 0; + + // make sure state is valid + GS_ASSERT(state->pos >= 0); + GS_ASSERT(connection->post != NULL); + + // when using a DIME, we have to pad to multiple of 4 + if (connection->post->useDIME) + { + padlen = 4-(gsXmlWriterGetDataLength(xml)%4); + if (padlen == 4) + padlen = 0; + } + + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + // Copy to encode buffer before encrypting + GS_ASSERT(connection->encodeBuffer.len >= 0); // there must be a header for this soap data! + if (!ghiAppendDataToBuffer(&connection->encodeBuffer, gsXmlWriterGetData(xml), gsXmlWriterGetDataLength(xml)) || + !ghiAppendDataToBuffer(&connection->encodeBuffer, pad, padlen) || + !ghiEncryptDataToBuffer(&connection->sendBuffer, connection->encodeBuffer.data, connection->encodeBuffer.len) + ) + { + return GHIPostingError; + } + + // Clear out our temporary buffer + ghiResetBuffer(&connection->encodeBuffer); + + // Send what we can now + if (GHTTPFalse == ghiSendBufferedData(connection)) + return GHIPostingError; + + // is there more to send? + if (connection->sendBuffer.pos == connection->sendBuffer.len) + ghiResetBuffer(&connection->sendBuffer); + + return GHIPostingDone; + } + else + { + GHITrySendResult result; + + // plain text - send immediately + result = ghiTrySendThenBuffer(connection, gsXmlWriterGetData(xml), gsXmlWriterGetDataLength(xml)); + if (result == GHITrySendError) + return GHIPostingError; + result = ghiTrySendThenBuffer(connection, pad, padlen); + if (result == GHITrySendError) + return GHIPostingError; + return GHIPostingDone; + } +} + +static GHIPostingResult ghiPostFileDiskStateDoPosting +( + GHIPostState * state, + GHIConnection * connection +) +{ + char buffer[4096]; + int len; + GHITrySendResult result; + + assert(state->pos >= 0); + assert(state->pos < state->state.fileDisk.len); + assert(state->pos == (int)ftell(state->state.fileDisk.file)); + + // Loop while data is being sent. + ///////////////////////////////// + do + { + // Read some data from the file. + //////////////////////////////// + len = (int)fread(buffer, 1, sizeof(buffer), state->state.fileDisk.file); + if(len <= 0) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPFileReadFailed; + return GHIPostingError; + } + + // Update our position. + /////////////////////// + state->pos += len; + + // Check for too much. + ////////////////////// + if(state->pos > state->state.fileDisk.len) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPFileReadFailed; + return GHIPostingError; + } + + // Send. + //////// + result = ghiTrySendThenBuffer(connection, buffer, len); + if(result == GHITrySendError) + return GHIPostingError; + + // Check if we've handled everything. + ///////////////////////////////////// + if(state->pos == state->state.fileDisk.len) + { + // when using a DIME, we have to pad to multiple of 4 + if (connection->post->useDIME) + { + char pad[3] = { '\0', '\0', '\0' }; + int padlen = 4-state->state.fileDisk.len%4; + if (padlen != 4 && padlen > 0) + { + if (GHITrySendError == ghiTrySendThenBuffer(connection, pad, padlen)) + return GHIPostingError; + } + } + return GHIPostingDone; + } + } + while(result == GHITrySendSent); + + return GHIPostingPosting; +} + +static GHIPostingResult ghiPostFileMemoryStateDoPosting +( + GHIPostState * state, + GHIConnection * connection +) +{ + int rcode; + int len; + + assert(state->pos >= 0); + + // Is this an empty file? + ///////////////////////// + if(state->data->data.fileMemory.len == 0) + return GHIPostingDone; + + assert(state->pos < state->data->data.fileMemory.len); + + // Send what we can. + //////////////////// + if (connection->encryptor.mEngine == GHTTPEncryptionEngine_None) + { + // Plain text: Send directly from memory + do + { + len = (state->data->data.fileMemory.len - state->pos); + rcode = ghiDoSend(connection, state->data->data.fileMemory.buffer + state->pos, len); + if(gsiSocketIsError(rcode)) + return GHIPostingError; + + // Update the pos. + ////////////////// + state->pos += rcode; + + // Did we send it all? + ////////////////////// + if(state->data->data.fileMemory.len == state->pos) + { + // when using a DIME, we have to pad to multiple of 4 + if (connection->post->useDIME) + { + char pad[3] = { '\0', '\0', '\0' }; + int padlen = 4-state->data->data.fileMemory.len%4; + if (padlen != 4 && padlen > 0) + { + if (GHITrySendError == ghiTrySendThenBuffer(connection, pad, padlen)) + return GHIPostingError; + } + } + return GHIPostingDone; + } + } + while(rcode); + return GHIPostingPosting; // (rcode == 0) ? + } + else + { + // Encrypted: can't avoid the copy due to encryption+MAC + GHITrySendResult result; + do + { + len = (state->data->data.fileMemory.len - state->pos); + len = min(len, GS_SSL_MAX_CONTENTLENGTH); + result = ghiTrySendThenBuffer(connection, state->data->data.fileMemory.buffer + state->pos, len); + if (result == GHITrySendError) + return GHIPostingError; + + // Update the pos. + ////////////////// + state->pos += len; + + // Did we send it all? + ////////////////////// + if(state->data->data.fileMemory.len == state->pos) + { + // when using a DIME, we have to pad to multiple of 4 + if (connection->post->useDIME) + { + char pad[3] = { '\0', '\0', '\0' }; + int padlen = 4-state->data->data.fileMemory.len%4; + if (padlen != 4 && padlen > 0) + { + if (GHITrySendError == ghiTrySendThenBuffer(connection, pad, padlen)) + return GHIPostingError; + } + } + return GHIPostingDone; + } + } + while(result == GHITrySendSent); + return GHIPostingPosting; + } +} + +static GHIPostingResult ghiPostStateDoPosting +( + GHIPostState * state, + GHIConnection * connection, + GHTTPBool first, + GHTTPBool last +) +{ + int len = 0; + GHITrySendResult result; + + // Check for sending the header. + //////////////////////////////// + if(state->pos == -1) + { + char buffer[2048]; + + // Bump up the position so we only send the header once. + //////////////////////////////////////////////////////// + state->pos = 0; + + // Check if this is a simple post. + ////////////////////////////////// + if(!connection->post->hasFiles && !connection->post->hasSoap) + { + // Simple post only supports strings. + ///////////////////////////////////// + assert(state->data->type == GHIString); + + // Format the header. + ///////////////////// + if(first) + sprintf(buffer, "%s=", state->data->name); + else + sprintf(buffer, "&%s=", state->data->name); + } + else + { + // Format the header based on string or file. + ///////////////////////////////////////////// + if(state->data->type == GHIString) + { + sprintf(buffer, + "%s" + "Content-Disposition: form-data; " + "name=\"%s\"" CRLF + CRLF, + first?GHI_MULTIPART_BOUNDARY_FIRST:GHI_MULTIPART_BOUNDARY_NORMAL, + state->data->name); + } + else if(state->data->type == GHIXmlData) + { + if (connection->post->useDIME) + { + // use DIME header + // Copy from a temp struct to circumvent alignment issues + int writePos = 0; + int padBytes = 0; + GHIDimeHeader header; + + header.mVersionAndFlags = GHI_DIME_VERSION; + if (first) + header.mVersionAndFlags |= GHI_DIMEFLAG_FIRSTRECORD; + if (last) + header.mVersionAndFlags |= GHI_DIMEFLAG_LASTRECORD; + header.mTypeT = GHI_DIMETYPE_T_URI; + header.mOptionsLength = 0; + header.mIdLength = htons((short)strlen(GHI_DIME_SOAPID)); + header.mTypeLength = htons((short)strlen(GHI_DIME_SOAPTYPE)); + header.mDataLength = htonl(gsXmlWriterGetDataLength(state->data->data.xml.xml)); + + memcpy(&buffer[writePos], &header, sizeof(GHIDimeHeader)); + writePos += sizeof(GHIDimeHeader); + + // id + strcpy(&buffer[writePos], GHI_DIME_SOAPID); + writePos += strlen(GHI_DIME_SOAPID); + padBytes = (int)(4-strlen(GHI_DIME_SOAPID)%4); + if (padBytes != 4) + { + while(padBytes-- > 0) + buffer[writePos++] = '\0'; + } + + // type + strcpy(&buffer[writePos], GHI_DIME_SOAPTYPE); + writePos += strlen(GHI_DIME_SOAPTYPE); + padBytes = (int)(4-strlen(GHI_DIME_SOAPTYPE)%4); + if (padBytes != 4) + { + while(padBytes-- > 0) + buffer[writePos++] = '\0'; + } + + len = writePos; + } + else + buffer[0] = '\0'; + } + else if((state->data->type == GHIFileDisk) || (state->data->type == GHIFileMemory)) + { + const char * filename; + const char * contentType; + int filelen; + + if(state->data->type == GHIFileDisk) + { + filelen = state->state.fileDisk.len; + filename = state->data->data.fileDisk.reportFilename; + contentType = state->data->data.fileDisk.contentType; + } + else + { + filelen = state->data->data.fileMemory.len; + filename = state->data->data.fileMemory.reportFilename; + contentType = state->data->data.fileMemory.contentType; + } + + if (connection->post->useDIME) + { + // use DIME header + // Copy from a temp struct to circumvent alignment issues + int writePos = 0; + int padBytes = 0; + GHIDimeHeader header; + + header.mVersionAndFlags = GHI_DIME_VERSION; + if (first) + header.mVersionAndFlags |= GHI_DIMEFLAG_FIRSTRECORD; + if (last) + header.mVersionAndFlags |= GHI_DIMEFLAG_LASTRECORD; + header.mTypeT = GHI_DIMETYPE_T_MEDIA; + header.mOptionsLength = 0; + header.mIdLength = htons((short)strlen(state->data->name)); + header.mTypeLength = htons((short)strlen(contentType)); + header.mDataLength = htonl(filelen); + + memcpy(&buffer[writePos], &header, sizeof(GHIDimeHeader)); + writePos += sizeof(GHIDimeHeader); + + // id + strcpy(&buffer[writePos], state->data->name); + writePos += strlen(state->data->name); + padBytes = (int)(4-strlen(state->data->name)%4); + if (padBytes != 4) + { + while(padBytes-- > 0) + buffer[writePos++] = '\0'; + } + + // type + strcpy(&buffer[writePos], contentType); + writePos += strlen(contentType); + padBytes = (int)(4-strlen(contentType)%4); + if (padBytes != 4) + { + while(padBytes-- > 0) + buffer[writePos++] = '\0'; + } + + len = writePos; + } + else + { + // use MIME header + sprintf(buffer, + "%s" + "Content-Disposition: form-data; " + "name=\"%s\"; " + "filename=\"%s\"" CRLF + "Content-Type: %s" CRLF CRLF, + first?GHI_MULTIPART_BOUNDARY_FIRST:GHI_MULTIPART_BOUNDARY_NORMAL, + state->data->name, + filename, + contentType); + } + } + else + { + assert(0); + } + } + + // SSL: encrypt and send + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + if (len == 0) + len = (int)strlen(buffer); + if (GHTTPFalse == ghiEncryptDataToBuffer(&connection->sendBuffer, buffer, len)) + return GHIPostingError; + if (GHTTPFalse == ghiSendBufferedData(connection)) + return GHIPostingError; + + // any data remaining? + if (connection->sendBuffer.pos < connection->sendBuffer.len) + return GHIPostingPosting; + + // We sent everything, reset the send buffer to conserve space + ghiResetBuffer(&connection->sendBuffer); + } + // If sending plain text, send right away + else + { + // Try sending. (the one-time header) + ///////////////////////////////////// + if (len == 0) + len = (int)strlen(buffer); + result = ghiTrySendThenBuffer(connection, buffer, len); + if(result == GHITrySendError) + return GHIPostingError; + + // If it was buffered, don't try anymore. + ///////////////////////////////////////// + if(result == GHITrySendBuffered) + return GHIPostingPosting; + + // We sent everything, reset the send buffer to conserve space + ghiResetBuffer(&connection->sendBuffer); + } + } + + // Post based on type. + ////////////////////// + if(state->data->type == GHIString) + return ghiPostStringStateDoPosting(state, connection); + + if(state->data->type == GHIXmlData) + return ghiPostXmlStateDoPosting(state, connection); + + if(state->data->type == GHIFileDisk) + return ghiPostFileDiskStateDoPosting(state, connection); + + assert(state->data->type == GHIFileMemory); + return ghiPostFileMemoryStateDoPosting(state, connection); +} + +GHIPostingResult ghiPostDoPosting +( + struct GHIConnection * connection +) +{ + GHIPostingResult postingResult; + GHITrySendResult trySendResult; + GHIPostingState * postingState; + GHIPostState * postState; + int len; + + assert(connection); + assert(connection->post); + assert(connection->postingState.states); + assert(ArrayLength(connection->post->data) == ArrayLength(connection->postingState.states)); + assert(connection->postingState.index >= 0); + assert(connection->postingState.index <= ArrayLength(connection->postingState.states)); + + // Cache some stuff. + //////////////////// + postingState = &connection->postingState; + len = ArrayLength(postingState->states); + + // Check for buffered data. + /////////////////////////// + if(connection->sendBuffer.pos < connection->sendBuffer.len) + { + // Send the buffered data. + ////////////////////////// + if(!ghiSendBufferedData(connection)) + return GHIPostingError; + + // Check if we couldn't send it all. + //////////////////////////////////// + if(connection->sendBuffer.pos < connection->sendBuffer.len) + return GHIPostingPosting; + + // We sent it all, so reset the buffer. + /////////////////////////////////////// + ghiResetBuffer(&connection->sendBuffer); + + // If uploading a DIME attachment, wait for HTTP continue. + ////////////////////////////////////////////////////////// + if (connection->postingState.waitPostContinue) + return GHIPostingWaitForContinue; + + // Was that all that's left? + //////////////////////////// + if(connection->postingState.index == len) + return GHIPostingDone; + } + + // When posting soap and DIME attachments, we should terminate the + // header and wait for a response. This will either be a continue or + // a server error. + if (connection->postingState.waitPostContinue) + { + if (connection->post->hasFiles || connection->post->hasSoap) + { + // terminate the header and wait for a response + GS_ASSERT(connection->encodeBuffer.len == 0); + trySendResult = ghiTrySendThenBuffer(connection, CRLF, (int)strlen(CRLF)); + if(trySendResult == GHITrySendError) + return GHIPostingError; + else if (trySendResult == GHITrySendBuffered) + return GHIPostingPosting; + else + { + if (connection->postingState.waitPostContinue == GHTTPTrue) + return GHIPostingWaitForContinue; + //else + // fall through + } + } + else + { + // simple posts don't have to wait + connection->postingState.waitPostContinue = GHTTPFalse; + // fall through + } + } + + // Loop while there's data to upload. + ///////////////////////////////////// + while(postingState->index < len) + { + // Get the current data state. + ////////////////////////////// + postState = (GHIPostState *)ArrayNth(postingState->states, postingState->index); + assert(postState); + + // Upload the current data. + /////////////////////////// + postingResult = ghiPostStateDoPosting(postState, connection, + (postingState->index == 0)?GHTTPTrue:GHTTPFalse, + (postingState->index == (ArrayLength(postingState->states)-1))?GHTTPTrue:GHTTPFalse); + + // Check for error. + /////////////////// + if(postingResult == GHIPostingError) + { + // Make sure we already set the error stuff. + //////////////////////////////////////////// + assert(connection->completed && connection->result); + + return GHIPostingError; + } + + // Check for still posting. + /////////////////////////// + if(postingResult == GHIPostingPosting) + return GHIPostingPosting; + + // One more done. + ///////////////// + postingState->index++; + } + + // Encrypt and send anything left in the encode buffer + // -- for example, when posting string data we don't encrypt until we have the entire string (for efficiency only) + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None) + { + if (connection->encodeBuffer.len > 0) + { + GS_ASSERT(connection->encodeBuffer.pos == 0); // if you hit this, it means you forgot the clear the buffer + if (GHTTPFalse == ghiEncryptDataToBuffer(&connection->sendBuffer, + connection->encodeBuffer.data, connection->encodeBuffer.len)) + { + return GHIPostingError; + } + ghiResetBuffer(&connection->encodeBuffer); + } + } + + // Send or buffer the end marker. + ///////////////////////////////// + if(connection->post->hasFiles && !connection->post->useDIME) + { + GS_ASSERT(!connection->post->hasSoap); + + // send MIME boundary end + trySendResult = ghiTrySendThenBuffer(connection, GHI_MULTIPART_BOUNDARY_END, (int)strlen(GHI_MULTIPART_BOUNDARY_END)); + if(trySendResult == GHITrySendError) + return GHIPostingError; + } + + // We're not done if there's stuff in the buffer. + ///////////////////////////////////////////////// + if(connection->sendBuffer.pos < connection->sendBuffer.len) + return GHIPostingPosting; + + return GHIPostingDone; +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpPost.h b/xrGameSpy/gamespy/ghttp/ghttpPost.h new file mode 100644 index 00000000000..1fab2a832fb --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpPost.h @@ -0,0 +1,126 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPPOST_H_ +#define _GHTTPPOST_H_ + +#include "ghttp.h" +#include "ghttpBuffer.h" +#include "../darray.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + GHIPostingError, + GHIPostingDone, + GHIPostingPosting, + GHIPostingWaitForContinue +} GHIPostingResult; + +typedef struct GHIPostingState +{ + DArray states; + int index; + int bytesPosted; + int totalBytes; + ghttpPostCallback callback; + void * param; + GHTTPBool waitPostContinue; // does DIME need to wait for continue? + GHTTPBool completed; // prevent re-post in the event of a redirect. +} GHIPostingState; + +GHTTPPost ghiNewPost +( + void +); + +void ghiPostSetAutoFree +( + GHTTPPost post, + GHTTPBool autoFree +); + +GHTTPBool ghiIsPostAutoFree +( + GHTTPPost post +); + +void ghiFreePost +( + GHTTPPost post +); + +GHTTPBool ghiPostAddString +( + GHTTPPost post, + const char * name, + const char * string +); + +GHTTPBool ghiPostAddFileFromDisk +( + GHTTPPost post, + const char * name, + const char * filename, + const char * reportFilename, + const char * contentType +); + +GHTTPBool ghiPostAddFileFromMemory +( + GHTTPPost post, + const char * name, + const char * buffer, + int bufferLen, + const char * reportFilename, + const char * contentType +); + +GHTTPBool ghiPostAddXml +( + GHTTPPost post, + GSXmlStreamWriter xmlSoap +); + +void ghiPostSetCallback +( + GHTTPPost post, + ghttpPostCallback callback, + void * param +); + +const char * ghiPostGetContentType +( + struct GHIConnection * connection +); + +GHTTPBool ghiPostInitState +( + struct GHIConnection * connection +); + +void ghiPostCleanupState +( + struct GHIConnection * connection +); + +GHIPostingResult ghiPostDoPosting +( + struct GHIConnection * connection +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttpProcess.c b/xrGameSpy/gamespy/ghttp/ghttpProcess.c new file mode 100644 index 00000000000..5d9df87e365 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpProcess.c @@ -0,0 +1,1745 @@ +/* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 980, 1202, 1207, 1298, 1447, 1451 +#pragma warning(disable: 4267) //lines: 1071 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + +#include "ghttpProcess.h" +#include "ghttpCallbacks.h" +#include "ghttpPost.h" +#include "ghttpMain.h" +#include "ghttpCommon.h" + +// Parse the URL into: +// server address (and IP) +// server port +// request path. +///////////////////////////// +static GHTTPBool ghiParseURL +( + GHIConnection * connection +) +{ + char * URL; + int nIndex; + char tempChar; + char * str; + + assert(connection); + if(!connection) + return GHTTPFalse; + + // 2002.Apr.18.JED - Make sure we have an URL + ///////////////////////////////////////////// + assert(connection->URL); + if(!connection->URL) + return GHTTPFalse; + + URL = connection->URL; + + // Check for "http://". + ////////////////////// + if(strncmp(URL, "http://", 7) == 0) + { + connection->protocol = GHIHttp; + URL += 7; + } + else if (strncmp(URL, "https://", 8) == 0) + { + connection->protocol = GHIHttps; + URL += 8; + } + else + { + return GHTTPFalse; + } + + // Read the address. + //////////////////// + nIndex = (int)strcspn(URL, ":/"); + tempChar = URL[nIndex]; + URL[nIndex] = '\0'; + connection->serverAddress = goastrdup(URL); + if(!connection->serverAddress) + return GHTTPFalse; + URL[nIndex] = tempChar; + URL += nIndex; + + // Read the port. + ///////////////// + if(*URL == ':') + { + URL++; + connection->serverPort = (unsigned short)atoi(URL); + if(!connection->serverPort) + return GHTTPFalse; + do + { + URL++; + }while(*URL && (*URL != '/')); + } + else + { + if (connection->protocol == GHIHttps) + connection->serverPort = GHI_DEFAULT_SECURE_PORT; + else + connection->serverPort = GHI_DEFAULT_PORT; + } + + // Read the path. + ///////////////// + if(!*URL) + URL = "/"; + connection->requestPath = goastrdup(URL); + while((str = strchr(connection->requestPath, ' ')) != NULL) + *str = '+'; + if(!connection->requestPath) + return GHTTPFalse; + + return GHTTPTrue; +} + +/**************** +** SOCKET INIT ** +****************/ +void ghiDoSocketInit +( + GHIConnection * connection +) +{ + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Socket Initialization\n"); + + // Progress. + //////////// + ghiCallProgressCallback(connection, NULL, 0); + + // Init sockets. + //////////////// + SocketStartUp(); + + // Parse the URL. + ///////////////// + if(!ghiParseURL(connection)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPParseURLFailed; + return; + } + + // Check if an encryption type was set. + /////////////////////////////////////// + if((connection->protocol == GHIHttps) && (connection->encryptor.mEngine == GHTTPEncryptionEngine_None)) + { + // default to gamespy engine + //ghttpSetRequestEncryptionEngine(connection->request, GHTTPEncryptionEngine_GameSpy); + + // 02OCT07 BED: Design changed so that only one engine can be active at a time + // Use the active engine rather than GameSpy + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Encryption engine not set for HTTPS. Using default engine\r\n"); + ghttpSetRequestEncryptionEngine(connection->request, GHTTPEncryptionEngine_Default); + } + else if ((connection->protocol != GHIHttps) && (connection->encryptor.mEngine != GHTTPEncryptionEngine_None)) + { + // URL is not secured + ghttpSetRequestEncryptionEngine(connection->request, GHTTPEncryptionEngine_None); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Encryption engine set for unsecured URL. Removing encryption.\r\n"); + } + + // Init the encryption engine. + ////////////////////////////// + if ((connection->protocol == GHIHttps) && connection->encryptor.mInitialized == GHTTPFalse) + { + GHIEncryptionResult aResult; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Debug, "Initializing SSL engine\n"); + aResult = (connection->encryptor.mInitFunc)(connection, &connection->encryptor); + if (aResult == GHIEncryptionResult_Error) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_WarmError, "Failed to initialize SSL engine\n"); + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + } + + // Progress. + //////////// + connection->state = GHTTPHostLookup; + ghiCallProgressCallback(connection, NULL, 0); +} + +/**************** +** HOST LOOKUP ** +****************/ +void ghiDoHostLookup +( + GHIConnection * connection +) +{ + HOSTENT * host = NULL; + const char * server = NULL; + +#if !defined(GSI_NO_THREADS) + // Check to see if asynch lookup is taking place + //////////////////////////////////////////////// + if (connection->handle) + { + GSI_UNUSED(host); + GSI_UNUSED(server); + + // Lookup incomplete - set to lookupPending state + ///////////////////////////////////////////////// + connection->state = GHTTPLookupPending; + ghiCallProgressCallback(connection, NULL, 0); + return; + } +#endif + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Host Lookup\n"); + + + // Check for using a proxy. + /////////////////////////// + if (connection->proxyOverrideServer) // request specific proxy + server = connection->proxyOverrideServer; + else if(ghiProxyAddress) + server = ghiProxyAddress; + else + server = connection->serverAddress; + + // Try resolving the address as an IP a.b.c.d number. + ///////////////////////////////////////////////////// + connection->serverIP = inet_addr(server); + if(connection->serverIP == INADDR_NONE) + { + // Try resolving with DNS - asynchronously if possible + ////////////////////////// + +#if defined(GSI_NO_THREADS) + //blocking version - no threads + host = gethostbyname(server); + + if(host == NULL) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_HotError, + "Host Lookup failed\n"); + connection->completed = GHTTPTrue; + connection->result = GHTTPHostLookupFailed; + return; + } + + // Get the IP. + ////////////// + connection->serverIP = *(unsigned int *)host->h_addr_list[0]; +#else + + //threaded version + if (gsiStartResolvingHostname(server, &(connection->handle)) == -1) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_HotError, + "Thread Creation Failed\n"); + + //make sure to set it back to NULL + connection->handle = NULL; + + //exit with Host Lookup Failed error message + connection->completed = GHTTPTrue; + connection->result = GHTTPHostLookupFailed; + return; + } + else + { + //thread created properly - continue into lookupPending state + GSI_UNUSED(host); + } +#endif + } + + // Progress. + //////////// + + //check to see if lookup is complete + if (connection->serverIP == INADDR_NONE) + { + //lookup incomplete - set to lookupPending state + connection->state = GHTTPLookupPending; + ghiCallProgressCallback(connection, NULL, 0); + } + else + { + //lookup complete - proceed with connection stage + connection->state = GHTTPConnecting; + ghiCallProgressCallback(connection, NULL, 0); + } +} + +/****************** +** LOOKUP PENDING** +******************/ +void ghiDoLookupPending +( + GHIConnection * connection +) +{ +#if !defined(GSI_NO_THREADS) + //check if lookup is complete + connection->serverIP = gsiGetResolvedIP(connection->handle); + + //make sure there were no problems with the IP + if (connection->serverIP == GSI_ERROR_RESOLVING_HOSTNAME) + { + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_HotError, + "Error resolving hostname\n"); + + //set to NULL + connection->handle = NULL; + + //notify that the lookup failed + connection->completed = GHTTPTrue; + connection->result = GHTTPHostLookupFailed; + return; + } + + if (connection->serverIP == GSI_STILL_RESOLVING_HOSTNAME) + { + //lookup incomplete - keep calling this function + connection->state = GHTTPLookupPending; + ghiCallProgressCallback(connection, NULL, 0); + } + else + { + //set to NULL + connection->handle = NULL; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, + "DNS lookup complete\n"); + //looks like we got ourselves a server! proceed with connection phase + connection->state = GHTTPConnecting; + ghiCallProgressCallback(connection, NULL, 0); + } +#endif +} + +/*************** +** CONNECTING ** +***************/ +void ghiDoConnecting +( + GHIConnection * connection +) +{ + int rcode; + SOCKADDR_IN address; + int writeFlag; + int exceptFlag; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Connecting\n"); + + // If we don't have a socket yet, set it up. + //////////////////////////////////////////// + if(connection->socket == INVALID_SOCKET) + { + // Create the socket. + ///////////////////// + connection->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(connection->socket == INVALID_SOCKET) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPSocketFailed; + connection->socketError = GOAGetLastError(connection->socket); + return; + } + + // Set the socket to non-blocking. + ////////////////////////////////// + if(!SetSockBlocking(connection->socket, 0)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPSocketFailed; + connection->socketError = GOAGetLastError(connection->socket); + return; + } + + // If throttling, use a small receive buffer. + ///////////////////////////////////////////// + if(connection->throttle) + SetReceiveBufferSize(connection->socket, ghiThrottleBufferSize); + + // Setup the server address. + //////////////////////////// + memset(&address, 0, sizeof(SOCKADDR_IN)); + address.sin_family = AF_INET; + if (connection->proxyOverrideServer) + address.sin_port = htons(connection->proxyOverridePort); + else if(ghiProxyAddress) + address.sin_port = htons(ghiProxyPort); + else + address.sin_port = htons(connection->serverPort); + address.sin_addr.s_addr = connection->serverIP; + + // Start the connect. + ///////////////////// + rcode = connect(connection->socket, (SOCKADDR *)&address, sizeof(address)); + if(gsiSocketIsError(rcode)) + { + int socketError = GOAGetLastError(connection->socket); + if((socketError != WSAEWOULDBLOCK) && (socketError != WSAEINPROGRESS) && (socketError != WSAETIMEDOUT)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPConnectFailed; + connection->socketError = socketError; + return; + } + } + } + + // Check if the connect has completed. + ////////////////////////////////////// + rcode = GSISocketSelect(connection->socket, NULL, &writeFlag, &exceptFlag); + if((gsiSocketIsError(rcode)) || ((rcode == 1) && exceptFlag)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPConnectFailed; + if(gsiSocketIsError(rcode)) + connection->socketError = GOAGetLastError(connection->socket); + else + connection->socketError = 0; + return; + } + + // Check if we're connected. + //////////////////////////// + if((rcode == 1) && writeFlag) + { + // Progress. + //////////// + if (connection->encryptor.mEngine == GHTTPEncryptionEngine_None) + connection->state = GHTTPSendingRequest; + else + connection->state = GHTTPSecuringSession; + ghiCallProgressCallback(connection, NULL, 0); + } +} + +/****************** +** SSL HANDSHAKE ** +*******************/ +void ghiDoSecuringSession +( + GHIConnection * connection +) +{ + // Client sends hello + // Server sends hello, [certificate], [certificate request], [server key exchange] + // Client sends client , , [certificate], [certificate verify] + // Server sends finished + + // skip the ghiDoSecuringSession step... + // - when not using encryption or + // - if the connection is already secure + + GHIRecvResult result; + + // This buffer must be large enough to receive any handshake messages. + char buffer[1025]; + int bufferLen; + + // Start the handshake process + if (connection->encryptor.mSessionStarted == GHTTPFalse) + { + GHIEncryptionResult aResult; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Securing Session\n"); + + GS_ASSERT(connection->encryptor.mStartFunc != NULL); + if (connection->encryptor.mStartFunc != NULL) + { + aResult = (connection->encryptor.mStartFunc)(connection, &connection->encryptor); + if (aResult == GHIEncryptionResult_Error) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + } + + // Check for session established + if (connection->encryptor.mSessionEstablished) + { + connection->state = GHTTPSendingRequest; + ghiCallProgressCallback(connection, NULL, 0); + return; + } + } + + // if the SSL lib controls the handshake, just keep calling + // start until the session has been established + GS_ASSERT(connection->encryptor.mSessionEstablished == GHTTPFalse); + if (connection->encryptor.mLibSendsHandshakeMessages) + { + GS_ASSERT(connection->encryptor.mStartFunc != NULL); + if (connection->encryptor.mStartFunc != NULL) + { + GHIEncryptionResult aResult = (connection->encryptor.mStartFunc)(connection, &connection->encryptor); + if (aResult == GHIEncryptionResult_Error) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + } + + // Check for session established + if (connection->encryptor.mSessionEstablished) + { + connection->state = GHTTPSendingRequest; + ghiCallProgressCallback(connection, NULL, 0); + } + } + else + { + // Continue to send and receive handshake messages until the session has been secured + // Send any session messages + if (connection->sendBuffer.pos < connection->sendBuffer.len) + { + if (!ghiSendBufferedData(connection)) + return; // Todo: handle error? + + // Check for data still buffered. + ///////////////////////////////// + if(connection->sendBuffer.pos < connection->sendBuffer.len) + return; + + ghiResetBuffer(&connection->sendBuffer); + } + + // Get data + bufferLen = sizeof(buffer); + result = ghiDoReceive(connection, buffer, &bufferLen); + + // Handle error or conn closed. + /////////////////////////////// + if((result == GHIError) || (result == GHIConnClosed)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + + // check for received data + if(result == GHIRecvData) + { + // Append new encrypted data to anything we've held over + // We have to do this because we can't decrypt partial SSL messages + if (!ghiAppendDataToBuffer(&connection->decodeBuffer, buffer, bufferLen)) + return; + + // Decrypt as much as we can + if (!ghiDecryptReceivedData(connection)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + + // Check for session established (handshake complete) + if (connection->encryptor.mSessionEstablished) + { + connection->state = GHTTPSendingRequest; + ghiCallProgressCallback(connection, NULL, 0); + return; + } + } + } +} + + +/******************** +** SENDING REQUEST ** +********************/ +void ghiDoSendingRequest +( + GHIConnection * connection +) +{ + char * requestType; + int oldPos; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Sending Request\n"); + + // If we haven't filled the send buffer yet, do that first. + /////////////////////////////////////////////////////////// + if(!connection->sendBuffer.len) + { + // Using a pointer so we can pipe output to a different destination + // (e.g. for efficiency and testing purposes we may want to encrypt in larger blocks) + GHIBuffer* writeBuffer = NULL; + if (connection->encryptor.mEngine == GHTTPEncryptionEngine_None || + connection->encryptor.mEncryptOnBuffer == GHTTPFalse) + { + // write directly to send buffer + writeBuffer = &connection->sendBuffer; + } + else + { + // write to temp buffer so it can be encrypted before sending + writeBuffer = &connection->encodeBuffer; + } + + // Fill in the request line. + //////////////////////////// + if(connection->post && !connection->postingState.completed) + requestType = "POST "; + else if(connection->type == GHIHEAD) + requestType = "HEAD "; + else + requestType = "GET "; + ghiAppendDataToBuffer(writeBuffer, requestType, 0); + if (connection->proxyOverrideServer || ghiProxyAddress) + ghiAppendDataToBuffer(writeBuffer, connection->URL, 0); + else + ghiAppendDataToBuffer(writeBuffer, connection->requestPath, 0); + ghiAppendDataToBuffer(writeBuffer, " HTTP/1.1" CRLF, 0); + + // Add the host header. + /////////////////////// + if(connection->serverPort == GHI_DEFAULT_PORT) + { + ghiAppendHeaderToBuffer(writeBuffer, "Host", connection->serverAddress); + } + else + { + ghiAppendDataToBuffer(writeBuffer, "Host: ", 0); + ghiAppendDataToBuffer(writeBuffer, connection->serverAddress, 0); + ghiAppendCharToBuffer(writeBuffer, ':'); + ghiAppendIntToBuffer(writeBuffer, connection->serverPort); + ghiAppendDataToBuffer(writeBuffer, CRLF, 2); + } + + // Add the user-agent header. + ///////////////////////////// + if (connection->sendHeaders == NULL || strstr(connection->sendHeaders, "User-Agent")==NULL) + ghiAppendHeaderToBuffer(writeBuffer, "User-Agent", "GameSpyHTTP/1.0"); + + // Check for persistant connections. + ////////////////////////////////////// + if (connection->persistConnection) + ghiAppendHeaderToBuffer(writeBuffer, "Connection", "Keep-Alive"); + else + ghiAppendHeaderToBuffer(writeBuffer, "Connection", "close"); + + // Post needs extra headers. + //////////////////////////// + if(connection->post && !connection->postingState.completed) + { + char buf[16]; + + // Add the content-length header. + ///////////////////////////////// + sprintf(buf, "%d", connection->postingState.totalBytes); + ghiAppendHeaderToBuffer(writeBuffer, "Content-Length", buf); + + // Add the content-type header. + /////////////////////////////// + ghiAppendHeaderToBuffer(writeBuffer, "Content-Type", ghiPostGetContentType(connection)); + } + + // Not supported by all servers + //ghiAppendHeaderToBuffer(writeBuffer, "Expect", "100-continue"); + + // Add user-headers. + //////////////////// + if(connection->sendHeaders) + ghiAppendDataToBuffer(writeBuffer, connection->sendHeaders, 0); + + // Add the blank line to finish it off. + /////////////////////////////////////// + ghiAppendDataToBuffer(writeBuffer, CRLF, 2); + + // Encrypt it, if necessary. This copy is unfortunate since matrixSsl can't encrypt in place + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + GS_ASSERT(writeBuffer == &connection->encodeBuffer); + if (!ghiEncryptDataToBuffer(&connection->sendBuffer, writeBuffer->data, writeBuffer->len)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + ghiResetBuffer(writeBuffer); + } + } + + // Store the old position. + ////////////////////////// + oldPos = connection->sendBuffer.pos; + + // Send what we can. + //////////////////// + if(!ghiSendBufferedData(connection)) + return; + + // Log anything we sent. + //////////////////////// + #ifdef HTTP_LOG + if(connection->sendBuffer.pos != oldPos) + ghiLogRequest(connection->sendBuffer.data + oldPos, connection->sendBuffer.pos - oldPos); + #endif + + // Check for data still buffered. + ///////////////////////////////// + if(connection->sendBuffer.pos < connection->sendBuffer.len) + return; + + // Clear the send buffer. + ///////////////////////// + ghiResetBuffer(&connection->sendBuffer); + + // Finished sending. + //////////////////// + if(connection->post && !connection->postingState.completed) + connection->state = GHTTPPosting; + else + connection->state = GHTTPWaiting; + ghiCallProgressCallback(connection, NULL, 0); + + GSI_UNUSED(oldPos); +} + +/************ +** POSTING ** +************/ +void ghiDoPosting +( + GHIConnection * connection +) +{ + GHIPostingResult result; + int oldBytesPosted; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Posting\n"); + + // Store the old bytes posted. + ////////////////////////////// + oldBytesPosted = connection->postingState.bytesPosted; + + // Do some posting. + /////////////////// + result = ghiPostDoPosting(connection); + + // Check for an error. + ////////////////////// + if(result == GHIPostingError) + { + int rcode = 0; + int readFlag = 0; + + // Make sure we already set the error stuff. + //////////////////////////////////////////// + assert(connection->completed && connection->result); + + // Cleanup the posting state. + ///////////////////////////// + ghiPostCleanupState(connection); + + // Is there a server response? + rcode = GSISocketSelect(connection->socket, &readFlag, NULL, NULL); + if((rcode == 1) && readFlag) + { + // Ready to receive. + //////////////////// + connection->state = GHTTPReceivingStatus; + ghiCallProgressCallback(connection, NULL, 0); + } + return; + } + + // When sending DIME wait for initial + // continue before uploading + ///////////////////////////////////////// + if (result == GHIPostingWaitForContinue) + { + // Disable by skipping the wait + connection->postingState.waitPostContinue = GHTTPFalse; + return; + + //connection->state = GHTTPWaiting; + //return; + } + + // Call the callback if we sent anything. + ///////////////////////////////////////// + if(oldBytesPosted != connection->postingState.bytesPosted) + ghiCallPostCallback(connection); + + // Check for done. + ////////////////// + if(result == GHIPostingDone) + { + // Cleanup the posting state. + ///////////////////////////// + ghiPostCleanupState(connection); + connection->postingState.completed = GHTTPTrue; + + // Set the new connection state. + //////////////////////////////// + connection->state = GHTTPWaiting; + ghiCallProgressCallback(connection, NULL, 0); + + return; + } +} + +/************ +** WAITING ** +************/ +void ghiDoWaiting +( + GHIConnection * connection +) +{ + int readFlag; + int exceptFlag; + int rcode; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Waiting\n"); + + // We're waiting to receive something. + ////////////////////////////////////// + rcode = GSISocketSelect(connection->socket, &readFlag, NULL, &exceptFlag); + if((gsiSocketIsError(rcode)) || ((rcode == 1) && exceptFlag)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPSocketFailed; + if(gsiSocketIsError(rcode)) + connection->socketError = GOAGetLastError(connection->socket); + else + connection->socketError = 0; + return; + } + + // Check for waiting data. + ////////////////////////// + if((rcode == 1) && readFlag) + { + // Ready to receive. + //////////////////// + connection->state = GHTTPReceivingStatus; + ghiCallProgressCallback(connection, NULL, 0); + } +} + +// Parse the status line. +///////////////////////// +static GHTTPBool ghiParseStatus +( + GHIConnection * connection +) +{ + int majorVersion; + int minorVersion; + int statusCode; + int statusStringIndex; + int rcode; + char c; + + GS_ASSERT(connection); + GS_ASSERT(connection->recvBuffer.len > 0); + +#if defined(_X360) + //Xbox 360 needs "%n" to be manually enabled + { + int oldPrintCountValue = _set_printf_count_output(1); +#endif + + // Parse the string. + //////////////////// + rcode = sscanf(connection->recvBuffer.data, "HTTP/%d.%d %d%n", + &majorVersion, + &minorVersion, + &statusCode, + &statusStringIndex); + +#if defined(_X360) + _set_printf_count_output(oldPrintCountValue); + } +#endif + + // Check what we got. + ///////////////////// + if((rcode != 3) || // Not all fields read. + //!*statusString || // No status string. PANTS|9.16.02 - apparently some servers don't return a status string + (majorVersion < 1) || // Major version is less than 1. + (statusCode < 100) || // 1xx is lowest status code. + (statusCode >= 600)) // 5xx is highest status code. + { + connection->completed = GHTTPTrue; + connection->result = GHTTPBadResponse; + return GHTTPFalse; + } + + // Figure out where the status string starts. + ///////////////////////////////////////////// + while((c = connection->recvBuffer.data[statusStringIndex]) != '\0' && isspace(c)) + statusStringIndex++; + + // Set connection members. + ////////////////////////// + connection->statusMajorVersion = majorVersion; + connection->statusMinorVersion = minorVersion; + connection->statusCode = statusCode; + connection->statusStringIndex = statusStringIndex; + + return GHTTPTrue; +} + +/********************* +** RECEIVING STATUS ** +*********************/ +void ghiDoReceivingStatus +( + GHIConnection * connection +) +{ + char buffer[1024]; + int bufferLen; + GHIRecvResult result; + char * endOfStatus; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Receiving Status\n"); + + // Get data. + //////////// + bufferLen = sizeof(buffer); + result = ghiDoReceive(connection, buffer, &bufferLen); + + // Handle error or no data. + /////////////////////////// + if(result == GHIError) + return; + if(result == GHINoData) + return; + + // Only append data if we got data. + /////////////////////////////////// + if(result == GHIRecvData) + { + // Check for encryption. + //////////////////////// + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + // Append new encrypted data to anything we've held over + // We have to do this because we can't decrypt partial SSL messages + if (!ghiAppendDataToBuffer(&connection->decodeBuffer, buffer, bufferLen)) + return; + + // Decrypt as much as we can + if (!ghiDecryptReceivedData(connection)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + } + else + { + // Add the data directly to the buffer. + /////////////////////////////////////// + if(!ghiAppendDataToBuffer(&connection->recvBuffer, buffer, bufferLen)) + return; + } + } + + // Check if the status is finished. + ///////////////////////////////////// + endOfStatus = strstr(connection->recvBuffer.data, CRLF); + if(endOfStatus) + { + int statusLength; + + // Cap the status. + ////////////////// + *endOfStatus = '\0'; + + // Get the status length. + ///////////////////////// + statusLength = (endOfStatus - connection->recvBuffer.data); + + // Log it. + ////////// + ghiLogResponse(connection->recvBuffer.data, statusLength); + ghiLogResponse("\n", 1); + + // Parse the status line. + ///////////////////////// + if(!ghiParseStatus(connection)) + return; + + // Store the position of the start of the headers. + ////////////////////////////////////////////////// + connection->headerStringIndex = (statusLength + 2); + + + if (connection->statusCode == 100 && connection->postingState.waitPostContinue) + { + // DIME uploads must wait for initial continue before posting + connection->postingState.waitPostContinue = GHTTPFalse; + ghiResetBuffer(&connection->recvBuffer); // clear the continue + connection->state = GHTTPPosting; + ghiCallProgressCallback(connection, NULL, 0); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_Comment, + "Got HTTP continue\r\n"); + } + else + { + // We're receiving headers now. + /////////////////////////////// + connection->state = GHTTPReceivingHeaders; + ghiCallProgressCallback(connection, NULL, 0); + } + } + else if(result == GHIConnClosed) + { + // Connection closed. + ///////////////////// + connection->completed = GHTTPTrue; + connection->result = GHTTPBadResponse; + connection->socketError = GOAGetLastError(connection->socket); + return; + } +} + +// Delivers incoming file data to the appropriate place, +// then calls the progress callback. +// For GetFile, adds to buffer. +// For SaveFile, writes to disk. +// For StreamFile, does nothing. +// Returns false on error. +//////////////////////////////////////////////////////// +static GHTTPBool ghiDeliverIncomingFileData +( + GHIConnection * connection, + char * data, + int len +) +{ + char * buffer = NULL; + int bufferLen = 0; + + // Add this to the total. + ///////////////////////// + connection->fileBytesReceived += len; + + // Do we have the whole thing? + ////////////////////////////// + if(connection->fileBytesReceived == connection->totalSize || connection->connectionClosed) + connection->completed = GHTTPTrue; + + // Handle based on type. + //////////////////////// + if(connection->type == GHIGET) + { + // Put this in the buffer. + ////////////////////////// + if(!ghiAppendDataToBuffer(&connection->getFileBuffer, data, len)) + return GHTTPFalse; + + // Set the callback parameters. + /////////////////////////////// + buffer = connection->getFileBuffer.data; + bufferLen = connection->getFileBuffer.len; + } + else if(connection->type == GHISAVE) + { + int bytesWritten = 0; +#ifndef NOFILE + bytesWritten = fwrite(data, 1, len, connection->saveFile); +#endif + if(bytesWritten != len) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPFileWriteFailed; + return GHTTPFalse; + } + + // Set the callback parameters. + /////////////////////////////// + buffer = data; + bufferLen = len; + } + else if(connection->type == GHISTREAM) + { + // Set the callback parameters. + /////////////////////////////// + buffer = data; + bufferLen = len; + } + + // Call the callback. + ///////////////////// + ghiCallProgressCallback(connection, buffer, bufferLen); + + return GHTTPTrue; +} + +// Gets the size of a chunk from a chunk header. +// Returns -1 on error. +//////////////////////////////////////////////// +static int ghiParseChunkSize +( + GHIConnection * connection +) +{ + char * header; + int len; + int num; + int rcode; + + header = connection->chunkHeader; + len = connection->chunkHeaderLen; + + assert(len); + GSI_UNUSED(len); + + rcode = sscanf(header, "%x", &num); + if(rcode != 1) + return -1; + + return num; +} + +// Appends the data to the chunk header buffer. +/////////////////////////////////////////////// +static void ghiAppendToChunkHeaderBuffer +( + GHIConnection * connection, + char * data, + int len +) +{ + assert(connection); + assert(data); + assert(len >= 0); + + // This can happen at the end of a header. + ////////////////////////////////////////// + if(len == 0) + return; + + // Is there room in the buffer? If not, just + // skip, we most likely already have the chunk size. + //////////////////////////////////////////////////// + if(connection->chunkHeaderLen < CHUNK_HEADER_SIZE) + { + int numBytes; + + // How many bytes are we copying? + ///////////////////////////////// + numBytes = min(CHUNK_HEADER_SIZE - connection->chunkHeaderLen, len); + + // Move the (possibly partial) header into the buffer. + ////////////////////////////////////////////////////// + memcpy(connection->chunkHeader + connection->chunkHeaderLen, data, (unsigned int)numBytes); + + // Cap off the buffer. + ////////////////////// + connection->chunkHeaderLen += numBytes; + connection->chunkHeader[connection->chunkHeaderLen] = '\0'; + } +} + +// Does any neccessary processing to incoming file data +// before it gets delivered. This includes un-chunking. +// Returns false on error. +//////////////////////////////////////////////////////// +static GHTTPBool ghiProcessIncomingFileData +( + GHIConnection * connection, + char * data, + int len +) +{ + assert(connection); + assert(data); + assert(len > 0); + + // Is this a chunked transfer? + ////////////////////////////// + if(connection->chunkedTransfer) + { + // Loop while there's stuff to process. + /////////////////////////////////////// + while(len > 0) + { + // Reading a header? + //////////////////// + if(connection->chunkReadingState == CRHeader) + { + char * endOfHeader; + + // Have we hit the LF (as in the CRLF ending the header)? + ///////////////////////////////////////////////////////// + endOfHeader = strchr(data, 0xA); + if(endOfHeader) + { + // Append what we have to the buffer. + ///////////////////////////////////// + ghiAppendToChunkHeaderBuffer(connection, data, endOfHeader - data); + + // Adjust data and len. + /////////////////////// + endOfHeader++; + len -= (endOfHeader - data); + data = endOfHeader; + + // Read the chunk size. + /////////////////////// + connection->chunkBytesLeft = ghiParseChunkSize(connection); + if(connection->chunkBytesLeft == -1) + { + // There was an error reading the chunk size. + ///////////////////////////////////////////// + connection->completed = GHTTPTrue; + connection->result = GHTTPBadResponse; + return GHTTPFalse; + } + + // Set the chunk reading state. + /////////////////////////////// + if(connection->chunkBytesLeft == 0) + { + connection->chunkReadingState = CRFooter; + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "Reading footer\n"); + } + else + { + connection->chunkReadingState = CRChunk; + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "Reading %d byte chunk\n", connection->chunkBytesLeft); + } + } + else + { + // Move it all into the buffer. + /////////////////////////////// + ghiAppendToChunkHeaderBuffer(connection, data, len); + + // Nothing else we can do now. + ////////////////////////////// + return GHTTPTrue; + } + } + // Reading a chunk? + /////////////////// + else if(connection->chunkReadingState == CRChunk) + { + int numBytes; + + // How many bytes of data are we dealing with? + ////////////////////////////////////////////// + numBytes = min(connection->chunkBytesLeft, len); + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "Read %d bytes of chunk\n", numBytes); + + // Deliver the bytes. + ///////////////////// + if(!ghiDeliverIncomingFileData(connection, data, numBytes)) + return GHTTPFalse; + + // Adjust data and len. + /////////////////////// + data += numBytes; + len -= numBytes; + + // Figure out how many bytes left in chunk. + /////////////////////////////////////////// + connection->chunkBytesLeft -= numBytes; + + // Did we finish the chunk? + /////////////////////////// + if(connection->chunkBytesLeft == 0) + connection->chunkReadingState = CRCRLF; + } + // Reading a chunk footer (CRLF)? + ///////////////////////////////// + else if(connection->chunkReadingState == CRCRLF) + { + char * endOfFooter; + + // Did we get an LF? + //////////////////// + endOfFooter = strchr(data, 0xA); + + // The footer hasn't ended yet. + /////////////////////////////// + if(!endOfFooter) + return GHTTPTrue; + + // Adjust data and len. + /////////////////////// + endOfFooter++; + len -= (endOfFooter - data); + data = endOfFooter; + + // Set up for reading the next header. + ////////////////////////////////////// + connection->chunkHeader[0] = '\0'; + connection->chunkHeaderLen = 0; + connection->chunkBytesLeft = 0; + connection->chunkReadingState = CRHeader; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "Read chunk footer\n"); + } + // Reading the footer? + ////////////////////// + else if(connection->chunkReadingState == CRFooter) + { + // We're done. + ////////////// + connection->completed = GHTTPTrue; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_Network, GSIDebugLevel_RawDump, + "Finished reading chunks\n"); + + return GHTTPTrue; + } + // Bad state! + ///////////// + else + { + assert(0); + return GHTTPFalse; + } + } + + return GHTTPTrue; + } + + // Regular transfer, just deliver it. + ///////////////////////////////////// + return ghiDeliverIncomingFileData(connection, data, len); +} + +/********************** +** RECEIVING HEADERS ** +**********************/ +void ghiDoReceivingHeaders +( + GHIConnection * connection +) +{ + char buffer[4096]; + int bufferLen; + GHIRecvResult result; + GHTTPBool hasHeaders = GHTTPTrue; + char * headers; + char * endOfHeaders = NULL; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Receiving Headers\n"); + + // Get data. + //////////// + bufferLen = sizeof(buffer); + result = ghiDoReceive(connection, buffer, &bufferLen); + + // Handle error, no data, conn closed. + ////////////////////////////////////// + if(result == GHIError) + return; + if(result == GHINoData) + return; + + // Only append data if we got data. + /////////////////////////////////// + if(result == GHIRecvData) + { + // Check for encryption. + //////////////////////// + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + // Append new encrypted data to anything we've held over + // We have to do this because we can't decrypt partial SSL messages + if (!ghiAppendDataToBuffer(&connection->decodeBuffer, buffer, bufferLen)) + return; + + // Decrypt as much as we can + if (!ghiDecryptReceivedData(connection)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + } + else + { + // Add the data directly to the buffer. + /////////////////////////////////////// + if(!ghiAppendDataToBuffer(&connection->recvBuffer, buffer, bufferLen)) + return; + } + } + + // Cache a pointer to the front of the headers. + /////////////////////////////////////////////// + headers = (connection->recvBuffer.data + connection->headerStringIndex); + + // Check if the headers are finished. + ///////////////////////////////////// + if( ((connection->statusCode / 100) == 1) && + (strncmp(headers, "\r\n", 2) == 0 || strncmp(headers, "\xA\xA", 2) == 0) + ) + { + // If a continue doesn't have a header (immediate CRLF) move on to next status + endOfHeaders = headers; + hasHeaders = GHTTPFalse; + } + else + { + endOfHeaders = strstr(headers, CRLF CRLF); + } + if(!endOfHeaders) + { + endOfHeaders = strstr(headers, "\xA\xA"); // some servers seem to use LFs only?! Seen in 302 redirect. (28may01/bgw) + } + if(endOfHeaders) + { + char * fileStart; + int fileLength; + //int headersLength; + char * contentLength; + +#ifdef HTTP_LOG + int headersLength; +#endif + + // Clear off the empty line. + //////////////////////////// + if (GHTTPTrue == hasHeaders) + endOfHeaders += 2; + *endOfHeaders = '\0'; + + // Figure out where the file starts, and how many bytes. + //////////////////////////////////////////////////////// +#ifdef HTTP_LOG + headersLength = (endOfHeaders - headers); +#endif + + fileStart = (endOfHeaders + 2); + fileLength = (connection->recvBuffer.len - (fileStart - connection->recvBuffer.data)); + + // Set the headers buffer's new length. + /////////////////////////////////////// + connection->recvBuffer.len = (endOfHeaders - connection->recvBuffer.data + 1); + connection->recvBuffer.pos = connection->recvBuffer.len; + + // Log it. + ////////// +#ifdef HTTP_LOG + ghiLogResponse(headers, headersLength); + ghiLogResponse("\n", 1); +#endif + + // Check for continue. + ////////////////////// + if((connection->statusCode / 100) == 1) + { + if(fileLength) + { + // Move any data to the front of the buffer. + //////////////////////////////////////////// + memmove(connection->recvBuffer.data, fileStart, (unsigned int)fileLength + 1); + connection->recvBuffer.len = fileLength; + } + else + { + // Reset the buffer. + ///////////////////////// + ghiResetBuffer(&connection->recvBuffer); + } + + // Some posts must wait for continue before uploading + // Check if we should return to posting + if (connection->postingState.waitPostContinue) + { + connection->postingState.waitPostContinue = GHTTPFalse; + connection->state = GHTTPPosting; + ghiCallProgressCallback(connection, NULL, 0); + } + + // We're back to receiving status. + ////////////////////////////////// + connection->state = GHTTPReceivingStatus; + ghiCallProgressCallback(connection, NULL, 0); + + return; + } + + // Check for redirection. + ///////////////////////// + if((connection->statusCode / 100) == 3) + { + char * location; + + // Are we over our redirection count? + ///////////////////////////////////// + if(connection->redirectCount > 10) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPFileNotFound; + return; + } + + // Find the new location. + ///////////////////////// + location = strstr(headers, "Location:"); + if(location) + { + char * end; + + // Find the start of the URL. + ///////////////////////////// + location += 9; + while(isspace(*location)) + location++; + + // Find the end. + //////////////// + for(end = location; *end && !isspace(*end) ; end++) { }; + *end = '\0'; + + // Check if this is not a full URL. + /////////////////////////////////// + if(*location == '/') + { + int len; + + // Recompose the URL ourselves. + /////////////////////////////// + len = (int)(strlen(connection->serverAddress) + 13 + strlen(location) + 1); + connection->redirectURL = (char *)gsimalloc((unsigned int)len); + if(!connection->redirectURL) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPOutOfMemory; + } + sprintf(connection->redirectURL, "http://%s:%d%s", connection->serverAddress, connection->serverPort, location); + } + else + { + // Set the redirect URL. + //////////////////////// + connection->redirectURL = goastrdup(location); + if(!connection->redirectURL) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPOutOfMemory; + } + } + + return; + } + } + + // If we know the file-length, set it. + ////////////////////////////////////// + contentLength = strstr(headers, "Content-Length:"); + if(contentLength) + { + // Verify that the download size is something we can handle + /////////////////////////////////////////////////////////// +#if (GSI_MAX_INTEGRAL_BITS >= 64) + char szMaxSize[] = "9223372036854775807"; // == GSI_MAX_I64 +#else + char szMaxSize[] = "2147483647"; // == GSI_MAX_I32 +#endif + char* pStart = contentLength+16; + char* pEnd = pStart; + int nMaxLen = (int)strlen(szMaxSize); + + // Skip to the end of the line + while( pEnd && *pEnd != '\0' && *pEnd != '\n' && *pEnd != '\r' && *pEnd != ' ' ) + pEnd++; + + if( pEnd-pStart > nMaxLen ) + { + // Wow, that IS a big number + connection->completed = GHTTPTrue; + connection->result = GHTTPFileToBig; + return; + } + else + if( pEnd-pStart == nMaxLen ) + { + // Same length, maybe a bigger number + if( strncmp(pStart,szMaxSize,(unsigned int)(pEnd-pStart)) >= 0 ) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPFileToBig; + return; + } + } + + // Record the full size of the expected download + //////////////////////////////////////////////// +#if (GSI_MAX_INTEGRAL_BITS >= 64) + connection->totalSize = _atoi64(pStart); +#else + connection->totalSize = atoi(pStart); +#endif + } + + // Check the chunky. + //////////////////// + connection->chunkedTransfer = (strstr(headers, "Transfer-Encoding: chunked") != NULL)?GHTTPTrue:GHTTPFalse; + if(connection->chunkedTransfer) + { + connection->chunkHeader[0] = '\0'; + connection->chunkHeaderLen = 0; + connection->chunkBytesLeft = 0; + connection->chunkReadingState = CRHeader; + } + + // If we're just getting headers, or only posting data, we're done. + /////////////////////////////////////////////////////////////////// + if((connection->type == GHIHEAD) || (connection->type == GHIPOST)) + { + connection->completed = GHTTPTrue; + return; + } + + // We're receiving file data now. + ///////////////////////////////// + connection->state = GHTTPReceivingFile; + + // Is this an empty file? + ///////////////////////// + if(contentLength && !connection->totalSize) + { + connection->completed = GHTTPTrue; + return; + } + + // If any of the body has arrived, handle it. + ///////////////////////////////////////////// + if(fileLength > 0) + ghiProcessIncomingFileData(connection, fileStart, fileLength); + + // Don't reset the buffer -- we store status and header info + //ghiResetBuffer(&connection->recvBuffer); + } + else if(result == GHIConnClosed) + { + // The conn was closed, and we didn't finish the headers - bad. + /////////////////////////////////////////////////////////////// + connection->completed = GHTTPTrue; + connection->result = GHTTPBadResponse; + connection->socketError = GOAGetLastError(connection->socket); + } +} + +/******************* +** RECEIVING FILE ** +*******************/ +void ghiDoReceivingFile +( + GHIConnection * connection +) +{ + char buffer[8192]; + int bufferLen; + GHIRecvResult result; + gsi_time start_time = current_time(); + gsi_time running_time = 0; + + gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment, "Receiving File\n"); + + while(!connection->completed && (running_time < connection->maxRecvTime)) + { + // Get data. + //////////// + bufferLen = sizeof(buffer); + result = ghiDoReceive(connection, buffer, &bufferLen); + + // Handle error, no data, conn closed. + ////////////////////////////////////// + if(result == GHIError) + return; + if(result == GHINoData) + return; + if(result == GHIConnClosed) + { + // The file is done (hopefully). + //////////////////////////////// + connection->completed = GHTTPTrue; + + if (connection->totalSize > 0 && connection->fileBytesReceived < connection->totalSize) + connection->result = GHTTPFileIncomplete; + return; + } + + // Check for encryption. + //////////////////////// + if (connection->encryptor.mEngine != GHTTPEncryptionEngine_None && + connection->encryptor.mEncryptOnBuffer == GHTTPTrue) + { + char * decryptedData; + int decryptedLen; + + // Append new encrypted data to anything we've held over + // We have to do this because we can't decrypt partial SSL messages + if (!ghiAppendDataToBuffer(&connection->decodeBuffer, buffer, bufferLen)) + return; + + // Previously decrypted parts of the file have already been handled. + connection->recvBuffer.len = connection->recvBuffer.pos; + + // Decrypt as much as we can + if (!ghiDecryptReceivedData(connection)) + { + connection->completed = GHTTPTrue; + connection->result = GHTTPEncryptionError; + return; + } + + // Check for decrypted data. + //////////////////////////// + decryptedLen = (connection->recvBuffer.len - connection->recvBuffer.pos); + if(decryptedLen) + { + // Process the data. + //////////////////// + decryptedData = (connection->recvBuffer.data + connection->recvBuffer.pos); + if(!ghiProcessIncomingFileData(connection, decryptedData, decryptedLen)) + return; + } + } + else + { + // Process the data. + //////////////////// + if(!ghiProcessIncomingFileData(connection, buffer, bufferLen)) + return; + } + + running_time = current_time() - start_time; + } +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpProcess.h b/xrGameSpy/gamespy/ghttp/ghttpProcess.h new file mode 100644 index 00000000000..6710b7970d7 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpProcess.h @@ -0,0 +1,37 @@ +/* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GHTTPPROCESS_H_ +#define _GHTTPPROCESS_H_ + +#include "ghttpMain.h" +#include "ghttpConnection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void ghiDoSocketInit (GHIConnection * connection); +void ghiDoHostLookup (GHIConnection * connection); +void ghiDoLookupPending (GHIConnection * connection); +void ghiDoConnecting (GHIConnection * connection); +void ghiDoSecuringSession (GHIConnection * connection); +void ghiDoSendingRequest (GHIConnection * connection); +void ghiDoPosting (GHIConnection * connection); +void ghiDoWaiting (GHIConnection * connection); +void ghiDoReceivingStatus (GHIConnection * connection); +void ghiDoReceivingHeaders(GHIConnection * connection); +void ghiDoReceivingFile (GHIConnection * connection); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/ghttp/ghttp_vs2005.sln b/xrGameSpy/gamespy/ghttp/ghttp_vs2005.sln new file mode 100644 index 00000000000..fbe71b5f905 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttp_vs2005.sln @@ -0,0 +1,35 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghttpc_vs2005", "ghttpc\ghttpc_vs2005.vcproj", "{C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghttpmfc_vs2005", "ghttpmfc\ghttpmfc_vs2005.vcproj", "{0DC21D1C-D515-43C9-969C-29B89E0A8A20}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Debug|Win32.ActiveCfg = Debug|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Debug|Win32.Build.0 = Debug|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Release|Win32.ActiveCfg = Release|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Release|Win32.Build.0 = Release|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {C6D52E9E-FA4B-4654-829D-9D12A1B29AA6}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Debug|Win32.ActiveCfg = Debug|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Debug|Win32.Build.0 = Debug|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Release|Win32.ActiveCfg = Release|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Release|Win32.Build.0 = Release|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {0DC21D1C-D515-43C9-969C-29B89E0A8A20}.Unicode Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc.c b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc.c new file mode 100644 index 00000000000..68696b04823 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc.c @@ -0,0 +1,313 @@ + /* +GameSpy GHTTP SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "../../common/gsCommon.h" +#include "../ghttp.h" + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define MAX_REQUESTS 20 + +typedef struct Result +{ + GHTTPBool started; + gsi_time startTime; + gsi_time stopTime; + GHTTPResult result; +} Result; + +static int pendingRequests; +static Result results[MAX_REQUESTS]; + +static gsi_char * stateStrings[] = +{ + _T("Socket Init"), + _T("Host Lookup"), + _T("Lookup Pending"), + _T("Connecting"), + _T("Securing Session"), + _T("Sending Request"), + _T("Posting"), + _T("Waiting"), + _T("Receiving Status"), + _T("Receiving Headers"), + _T("Receiving File") +}; + +static gsi_char * resultStrings[] = +{ + _T("GHTTPSuccess"), + _T("GHTTPOutOfMemory"), + _T("GHTTPBufferOverflow"), + _T("GHTTPParseURLFailed"), + _T("GHTTPHostLookupFailed"), + _T("GHTTPSocketFailed"), + _T("GHTTPConnectFailed"), + _T("GHTTPBadResponse"), + _T("GHTTPRequestRejected"), + _T("GHTTPUnauthorized"), + _T("GHTTPForbidden"), + _T("GHTTPFileNotFound"), + _T("GHTTPServerError"), + _T("GHTTPFileWriteFailed"), + _T("GHTTPFileReadFailed"), + _T("GHTTPFileIncomplete"), + _T("GHTTPFileToBig"), + _T("GHTTPEncryptionError"), + _T("GHTTPRequestCancelled") +}; + + +#ifdef __MWERKS__ // CodeWarrior will warn if function not prototyped +int test_main(int argc, char **argv); +#endif + +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + vprintf(theTokenStr, theParamList); + +#if defined(_WIN32) && !defined(_XBOX) + { + static char buffer[4098]; + sprintf(buffer, "[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + OutputDebugString(buffer); + vsprintf(buffer, theTokenStr, theParamList); + OutputDebugString(buffer); + } +#endif + } +#endif + +static GHTTPBool CompletedCallback +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + int index = (int)param; + + pendingRequests--; + + // Save off the result. + /////////////////////// + results[index].result = result; + + // Save the time. + ///////////////// + results[index].stopTime = current_time(); + + // Check the result and print out some info. + //////////////////////////////////////////// + if(result == GHTTPSuccess) + _tprintf(_T("%d finished\n"), index); + else + _tprintf(_T("%d failed: %s\n"), index, resultStrings[result]); + + // Don't free this buffer, its from the stack. + ////////////////////////////////////////////// + if(index == 1) + return GHTTPFalse; + + // Free the buffer (if there is one). + ///////////////////////////////////// + GSI_UNUSED(request); + GSI_UNUSED(buffer); + GSI_UNUSED(bufferLen); + + return GHTTPTrue; +} + +static void ProgressCallback +( + GHTTPRequest request, + GHTTPState state, + const char * buffer, + GHTTPByteCount bufferLen, + GHTTPByteCount bytesReceived, + GHTTPByteCount totalSize, + void * param +) +{ + int index = (int)param; + + // Show the current state. + ////////////////////////// + _tprintf(_T("%d state: %s"), index, stateStrings[state]); + + // If we're receiving the file, show the progress. + ////////////////////////////////////////////////// + if(state == GHTTPReceivingFile) + { + // Display based on if we know the total size. + ////////////////////////////////////////////// + if(totalSize != -1) + _tprintf(_T(" (%d / %d bytes)\n"), bytesReceived, totalSize); + else + _tprintf(_T(" (%d bytes)\n"), bytesReceived); + } + else + _tprintf(_T("\n")); + + GSI_UNUSED(request); + GSI_UNUSED(buffer); + GSI_UNUSED(bufferLen); +} + +static void CheckRequest(GHTTPRequest request, int index) +{ + assert(index < MAX_REQUESTS); + results[index].started = (request < 0)?GHTTPFalse:GHTTPTrue; + if(results[index].started) + results[index].startTime = current_time(); +} + +int test_main(int argc, char **argv) +{ + int i; + static char buffer[10000] = ""; + GHTTPRequest request; + int numRequests; + +#ifdef GSI_COMMON_DEBUG + // Define GSI_COMMON_DEBUG if you want to view the SDK debug output + // Set the SDK debug log file, or set your own handler using gsSetDebugCallback + //gsSetDebugFile(stdout); // output to console + gsSetDebugCallback(DebugCallback); + + // Set some debug levels + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Hardcore); + //gsSetDebugLevel(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Verbose); // Show Detailed data on network traffic + //gsSetDebugLevel(GSIDebugCat_App, GSIDebugType_All, GSIDebugLevel_Hardcore); // Show All app comment +#endif + + // get a file + request = ghttpGet( + _T("http://www.gamespy.net/images/dev_serv_main.jpg"), + GHTTPFalse, + CompletedCallback, + (void *)pendingRequests); + CheckRequest(request, pendingRequests); + pendingRequests++; + + // put a file into our own buffer, with progress updates + // also gets redirected + request = ghttpGetEx( + _T("http://google.com/intl/en_ALL/images/logo.gif"), + NULL, + buffer, sizeof(buffer), + NULL, + GHTTPFalse, + GHTTPFalse, + ProgressCallback, + CompletedCallback, + (void *)pendingRequests); + CheckRequest(request, pendingRequests); + pendingRequests++; + + // download a file +#if !defined(NOFILE) + request = ghttpSave( + _T("http://www.gamespy.net/images/dev_serv_logo.jpg"), + _T("logo.jpg"), + GHTTPFalse, + CompletedCallback, + (void *)pendingRequests); + CheckRequest(request, pendingRequests); + pendingRequests++; +#endif + + // stream a page + request = ghttpStreamEx( + _T("http://www.gamespy.net"), + NULL, + NULL, + GHTTPFalse, + GHTTPFalse, + ProgressCallback, + CompletedCallback, + (void *)pendingRequests); + CheckRequest(request, pendingRequests); + pendingRequests++; + + // get a header + request = ghttpHead( + _T("http://sdkdev.gamespy.com/games/st_ladder/web/index.html"), + GHTTPFalse, + CompletedCallback, + (void *)pendingRequests); + CheckRequest(request, pendingRequests); + pendingRequests++; + + // stream a secure page + request = ghttpStreamEx( +#if defined(_REVOLUTION) + _T("https://mariokartwii.race.gs.nintendowifi.net/RaceService/test.txt"), +#else + _T("https://www.gamespyid.com/"), +#endif + NULL, + NULL, + GHTTPFalse, + GHTTPFalse, + ProgressCallback, + CompletedCallback, + (void *)pendingRequests); + + //if(!IS_GHTTP_ERROR(request)) + // ghttpSetRequestEncryptionEngine(request, GHTTPEncryptionEngine_GameSpy); + CheckRequest(request, pendingRequests); + pendingRequests++; + + // store the number of requests + numRequests = pendingRequests; + + do + { + ghttpThink(); + msleep(20); + } + while(pendingRequests); + + ghttpCleanup(); + + _tprintf(_T("Results:\n")); + for(i = 0 ; i < numRequests ; i++) + { + if(results[i].started == GHTTPFalse) + _tprintf(_T("%d: Failed to start\n"), i); + else + _tprintf(_T("%d: %s [%dms]\n"), i, resultStrings[results[i].result], results[i].stopTime - results[i].startTime); + } + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + return 0; +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc.dsp b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc.dsp new file mode 100644 index 00000000000..c49764fe869 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc.dsp @@ -0,0 +1,364 @@ +# Microsoft Developer Studio Project File - Name="ghttpc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ghttpc - Win32 Unicode 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 "ghttpc.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 "ghttpc.mak" CFG="ghttpc - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ghttpc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpc - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpc - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/ghttp/ghttpc", BUZAAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ghttpc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 wsock32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "ghttpc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "ghttpc - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ghttpc___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "ghttpc___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# ADD CPP /nologo /MT /W3 /WX /GX /O2 /D "GSI_UNICODE" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 wsock32.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:console /machine:I386 +# ADD LINK32 wsock32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "ghttpc - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ghttpc___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "ghttpc___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ghttpc - Win32 Release" +# Name "ghttpc - Win32 Debug" +# Name "ghttpc - Win32 Unicode Release" +# Name "ghttpc - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ghttpc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpProcess.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc_vs2005.vcproj b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc_vs2005.vcproj new file mode 100644 index 00000000000..859e75a8733 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpc_vs2005.vcproj @@ -0,0 +1,942 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttplinux/Makefile b/xrGameSpy/gamespy/ghttp/ghttpc/ghttplinux/Makefile new file mode 100644 index 00000000000..e42d6417ad9 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttplinux/Makefile @@ -0,0 +1,66 @@ +# HTTP SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=ghttplinux + +CC=gcc +BASE_CFLAGS=-D_LINUX -DGSI_COMMON_DEBUG -D_DEBUG + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread + +#use these when debugging +DEBUG_CFLAGS=$(BASE_CFLAGS) -g -lpthread -march=i486 -O6 + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/linux/LinuxCommon.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../ghttpBuffer.o\ + ../../ghttpCallbacks.o\ + ../../ghttpConnection.o\ + ../../ghttpEncryption.o\ + ../../ghttpMain.o\ + ../../ghttpProcess.o\ + ../../ghttpCommon.o\ + ../../ghttpPost.o\ + ../ghttpc.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# +ghttp_debug: $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpmacosx/Makefile b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpmacosx/Makefile new file mode 100644 index 00000000000..098ac1a461c --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpmacosx/Makefile @@ -0,0 +1,38 @@ +# HTTP SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=ghttpc + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../ghttpBuffer.o\ + ../../ghttpCallbacks.o\ + ../../ghttpConnection.o\ + ../../ghttpEncryption.o\ + ../../ghttpMain.o\ + ../../ghttpProcess.o\ + ../../ghttpCommon.o\ + ../../ghttpPost.o\ + ../ghttpc.o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/Nitro.lcf b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/ghttpnitrocw.mcp b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/ghttpnitrocw.mcp new file mode 100644 index 00000000000..68c5fd58798 Binary files /dev/null and b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpnitrocw/ghttpnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2/Makefile b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2/Makefile new file mode 100644 index 00000000000..a04bef91975 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2/Makefile @@ -0,0 +1,30 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = ghttpc + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o\ + ../../../stringutil.o\ + ../../ghttpBuffer.o \ + ../../ghttpCallbacks.o \ + ../../ghttpConnection.o \ + ../../ghttpMain.o \ + ../../ghttpProcess.o \ + ../../ghttpCommon.o \ + ../../ghttpPost.o \ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2cw/ghttpps2cw.mcp b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2cw/ghttpps2cw.mcp new file mode 100644 index 00000000000..a6078d64be6 Binary files /dev/null and b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2cw/ghttpps2cw.mcp differ diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.dsp b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.dsp new file mode 100644 index 00000000000..d72929bc7cc --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.dsp @@ -0,0 +1,444 @@ +# Microsoft Developer Studio Project File - Name="ghttpps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ghttpps2prodg - Win32 PS2 EE Debug Insock +!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 "ghttpps2prodg.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 "ghttpps2prodg.mak" CFG="ghttpps2prodg - Win32 PS2 EE Debug Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ghttpps2prodg - Win32 PS2 EE Debug EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpps2prodg - Win32 PS2 EE Debug Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpps2prodg - Win32 PS2 EE Debug SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpps2prodg - Win32 PS2 EE Release EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpps2prodg - Win32 PS2 EE Release Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "ghttpps2prodg - Win32 PS2 EE Release SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/ghttp/ghttpc/ghttpps2prodg", JSEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ghttpps2prodg - Win32 PS2 EE Debug EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Debug EENet" +# PROP BASE Intermediate_Dir "PS2 EE Debug EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\ghttpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 ent_smap.a ent_eth.a ent_ppp.a eenetctl.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\ghttpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ghttpps2prodg - Win32 PS2 EE Debug Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ghttpps2prodg___Win32_PS2_EE_Debug_Insock" +# PROP BASE Intermediate_Dir "ghttpps2prodg___Win32_PS2_EE_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "INSOCK" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 ent_smap.a ent_eth.a ent_ppp.a eenetctl.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\ghttpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\ghttpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ghttpps2prodg - Win32 PS2 EE Debug SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Debug SNSystems" +# PROP BASE Intermediate_Dir "PS2 EE Debug SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\ghttpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libcdvd.a sneetcp.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\ghttpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ghttpps2prodg - Win32 PS2 EE Release EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Release EENet" +# PROP BASE Intermediate_Dir "PS2 EE Release EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\ghttpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 ent_smap.a ent_eth.a ent_ppp.a eenetctl.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\ghttpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ghttpps2prodg - Win32 PS2 EE Release Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ghttpps2prodg___Win32_PS2_EE_Release_Insock" +# PROP BASE Intermediate_Dir "ghttpps2prodg___Win32_PS2_EE_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libcdvd.a sneetcp.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\ghttpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\ghttpps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ghttpps2prodg - Win32 PS2 EE Release SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PS2 EE Release SNSystems" +# PROP BASE Intermediate_Dir "PS2 EE Release SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\ghttpps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libcdvd.a sneetcp.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\ghttpps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "ghttpps2prodg - Win32 PS2 EE Debug EENet" +# Name "ghttpps2prodg - Win32 PS2 EE Debug Insock" +# Name "ghttpps2prodg - Win32 PS2 EE Debug SNSystems" +# Name "ghttpps2prodg - Win32 PS2 EE Release EENet" +# Name "ghttpps2prodg - Win32 PS2 EE Release Insock" +# Name "ghttpps2prodg - Win32 PS2 EE Release SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\ghttpc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttpProcess.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.dsw b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.dsw new file mode 100644 index 00000000000..01bdfc75283 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ghttpps2prodg"=.\ghttpps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp/ghttpc/ghttpps2prodg", JSEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/ghttp/ghttpc/ghttpps2prodg", JSEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.sln b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.sln new file mode 100644 index 00000000000..07701f7afe4 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.sln @@ -0,0 +1,43 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghttpps2prodg", "ghttpps2prodg.vcproj", "{2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = ghttpps2prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {2ED3F6B0-2F00-40B7-ADDF-5F489BD0300D}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.vcproj b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.vcproj new file mode 100644 index 00000000000..bea43f672a7 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps2prodg/ghttpps2prodg.vcproj @@ -0,0 +1,744 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3/Makefile b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3/Makefile new file mode 100644 index 00000000000..d0934737f4a --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3/Makefile @@ -0,0 +1,36 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = ghttpc + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsAvailable.o \ + ../../../common/gsDebug.o \ + ../../../common/gsMemory.o \ + ../../../common/gsStringUtil.o \ + ../../../darray.o \ + ../../ghttpBuffer.o \ + ../../ghttpCallbacks.o \ + ../../ghttpConnection.o \ + ../../ghttpMain.o \ + ../../ghttpProcess.o \ + ../../ghttpCommon.o \ + ../../ghttpPost.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3prodg/ghttpps3prodg.sln b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3prodg/ghttpps3prodg.sln new file mode 100644 index 00000000000..83f27d78558 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3prodg/ghttpps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghttpps3prodg", "ghttpps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = ghttpps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3prodg/ghttpps3prodg.vcproj b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3prodg/ghttpps3prodg.vcproj new file mode 100644 index 00000000000..5054885652f --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpps3prodg/ghttpps3prodg.vcproj @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttppspprodg/ghttppspprodg.sln b/xrGameSpy/gamespy/ghttp/ghttpc/ghttppspprodg/ghttppspprodg.sln new file mode 100644 index 00000000000..e2c2d87afba --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttppspprodg/ghttppspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghttppspprodg", "ghttppspprodg.vcproj", "{14A2AE0A-2925-4605-924B-8558FBB37F2F}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = ghttppspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {14A2AE0A-2925-4605-924B-8558FBB37F2F}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {14A2AE0A-2925-4605-924B-8558FBB37F2F}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {14A2AE0A-2925-4605-924B-8558FBB37F2F}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {14A2AE0A-2925-4605-924B-8558FBB37F2F}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {14A2AE0A-2925-4605-924B-8558FBB37F2F}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {14A2AE0A-2925-4605-924B-8558FBB37F2F}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttppspprodg/ghttppspprodg.vcproj b/xrGameSpy/gamespy/ghttp/ghttpc/ghttppspprodg/ghttppspprodg.vcproj new file mode 100644 index 00000000000..bfb4f2f7769 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttppspprodg/ghttppspprodg.vcproj @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttprevolutioncw/ghttprevolutioncw.mcp b/xrGameSpy/gamespy/ghttp/ghttpc/ghttprevolutioncw/ghttprevolutioncw.mcp new file mode 100644 index 00000000000..a495034d17d Binary files /dev/null and b/xrGameSpy/gamespy/ghttp/ghttpc/ghttprevolutioncw/ghttprevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpx360/ghttpx360.sln b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpx360/ghttpx360.sln new file mode 100644 index 00000000000..8bc12353076 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpx360/ghttpx360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghttpx360", "ghttpx360.vcproj", "{71B578A2-4F9A-4DD0-A406-74F11FDAF91B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {71B578A2-4F9A-4DD0-A406-74F11FDAF91B}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/ghttp/ghttpc/ghttpx360/ghttpx360.vcproj b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpx360/ghttpx360.vcproj new file mode 100644 index 00000000000..d026d614cda --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpc/ghttpx360/ghttpx360.vcproj @@ -0,0 +1,632 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ReadMe.txt b/xrGameSpy/gamespy/ghttp/ghttpmfc/ReadMe.txt new file mode 100644 index 00000000000..68dd40ecef6 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ReadMe.txt @@ -0,0 +1,88 @@ +======================================================================== + MICROSOFT FOUNDATION CLASS LIBRARY : ghttpmfc +======================================================================== + + +AppWizard has created this ghttpmfc application for you. This application +not only demonstrates the basics of using the Microsoft Foundation classes +but is also a starting point for writing your application. + +This file contains a summary of what you will find in each of the files that +make up your ghttpmfc application. + +ghttpmfc.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +ghttpmfc.h + This is the main header file for the application. It includes other + project specific headers (including Resource.h) and declares the + CGhttpmfcApp application class. + +ghttpmfc.cpp + This is the main application source file that contains the application + class CGhttpmfcApp. + +ghttpmfc.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +ghttpmfc.clw + This file contains information used by ClassWizard to edit existing + classes or add new classes. ClassWizard also uses this file to store + information needed to create and edit message maps and dialog data + maps and to create prototype member functions. + +res\ghttpmfc.ico + This is an icon file, which is used as the application's icon. This + icon is included by the main resource file ghttpmfc.rc. + +res\ghttpmfc.rc2 + This file contains resources that are not edited by Microsoft + Visual C++. You should place all resources not editable by + the resource editor in this file. + + + + +///////////////////////////////////////////////////////////////////////////// + +AppWizard creates one dialog class: + +ghttpmfcDlg.h, ghttpmfcDlg.cpp - the dialog + These files contain your CGhttpmfcDlg class. This class defines + the behavior of your application's main dialog. The dialog's + template is in ghttpmfc.rc, which can be edited in Microsoft + Visual C++. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named ghttpmfc.pch and a precompiled types file named StdAfx.obj. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +If your application uses MFC in a shared DLL, and your application is +in a language other than the operating system's current language, you +will need to copy the corresponding localized resources MFC42XXX.DLL +from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, +and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. +For example, MFC42DEU.DLL contains resources translated to German.) If you +don't do this, some of the UI elements of your application will remain in the +language of the operating system. + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/StdAfx.cpp b/xrGameSpy/gamespy/ghttp/ghttpmfc/StdAfx.cpp new file mode 100644 index 00000000000..652cfa41d1a --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ghttpmfc.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/StdAfx.h b/xrGameSpy/gamespy/ghttp/ghttpmfc/StdAfx.h new file mode 100644 index 00000000000..445888962f4 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/StdAfx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__5ED40F92_A7FA_40E2_B911_E0DA573FB72A__INCLUDED_) +#define AFX_STDAFX_H__5ED40F92_A7FA_40E2_B911_E0DA573FB72A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "../ghttp.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__5ED40F92_A7FA_40E2_B911_E0DA573FB72A__INCLUDED_) diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.cpp b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.cpp new file mode 100644 index 00000000000..bd40f5fba0b --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.cpp @@ -0,0 +1,72 @@ +// ghttpmfc.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "ghttpmfc.h" +#include "ghttpmfcDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcApp + +BEGIN_MESSAGE_MAP(CGhttpmfcApp, CWinApp) + //{{AFX_MSG_MAP(CGhttpmfcApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcApp construction + +CGhttpmfcApp::CGhttpmfcApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CGhttpmfcApp object + +CGhttpmfcApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcApp initialization + +BOOL CGhttpmfcApp::InitInstance() +{ + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CGhttpmfcDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.dsp b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.dsp new file mode 100644 index 00000000000..e249c78a30b --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.dsp @@ -0,0 +1,377 @@ +# Microsoft Developer Studio Project File - Name="ghttpmfc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ghttpmfc - 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 "ghttpmfc.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 "ghttpmfc.mak" CFG="ghttpmfc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ghttpmfc - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ghttpmfc - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/ghttp/ghttpmfc", PUZAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ghttpmfc - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 wsock32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ghttpmfc - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "HTTP_LOG" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ghttpmfc - Win32 Release" +# Name "ghttpmfc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ghttpmfc.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghttpmfc.rc +# End Source File +# Begin Source File + +SOURCE=.\ghttpmfcDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ghttpmfc.h +# End Source File +# Begin Source File + +SOURCE=.\ghttpmfcDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\ghttpmfc.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ghttpmfc.rc2 +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpCommon.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpConnection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpPost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\ghttpProcess.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ghttpProcess.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "c,h" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.h b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.h new file mode 100644 index 00000000000..f2ebcbaea8a --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.h @@ -0,0 +1,49 @@ +// ghttpmfc.h : main header file for the GHTTPMFC application +// + +#if !defined(AFX_GHTTPMFC_H__30518F92_6CEC_4512_AC74_EF31A5DE2D1C__INCLUDED_) +#define AFX_GHTTPMFC_H__30518F92_6CEC_4512_AC74_EF31A5DE2D1C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcApp: +// See ghttpmfc.cpp for the implementation of this class +// + +class CGhttpmfcApp : public CWinApp +{ +public: + CGhttpmfcApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGhttpmfcApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CGhttpmfcApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GHTTPMFC_H__30518F92_6CEC_4512_AC74_EF31A5DE2D1C__INCLUDED_) diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.rc b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.rc new file mode 100644 index 00000000000..e636e8070ea --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc.rc @@ -0,0 +1,240 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\ghttpmfc.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\ghttpmfc.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_GHTTPMFC_DIALOG DIALOGEX 0, 0, 320, 262 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "ghttp mfc test" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Get File",IDC_GET_FILE,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,7,78,40,10 + CONTROL "Save File",IDC_SAVE_FILE,"Button",BS_AUTORADIOBUTTON,7, + 92,45,10 + CONTROL "Stream File",IDC_STREAM_FILE,"Button", + BS_AUTORADIOBUTTON,7,106,51,10 + CONTROL "Head File",IDC_HEAD_FILE,"Button",BS_AUTORADIOBUTTON,7, + 120,46,10 + CONTROL "Post",IDC_POST,"Button",BS_AUTORADIOBUTTON,7,134,30,10 + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | + WS_BORDER | WS_GROUP,8,154,230,8 + CONTROL "Host Lookup",IDC_HOST_LOOKUP,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,240,154,57,10 + CONTROL "Connecting",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,240, + 167,52,10 + CONTROL "Sending Request",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON, + 240,180,71,10 + CONTROL "Posting",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON,240,193, + 39,10 + CONTROL "Waiting",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,240,206, + 40,10 + CONTROL "Receiving Status",IDC_RADIO7,"Button", + BS_AUTORADIOBUTTON,240,219,70,10 + CONTROL "Receiving Headers",IDC_RADIO8,"Button", + BS_AUTORADIOBUTTON,240,232,77,10 + CONTROL "Receiving File",IDC_RADIO9,"Button",BS_AUTORADIOBUTTON, + 240,245,61,10 + DEFPUSHBUTTON "Quit",IDOK,260,7,50,14,WS_GROUP + EDITTEXT IDC_URL,32,7,214,12,ES_AUTOHSCROLL + EDITTEXT IDC_HEADERS,44,22,202,22,ES_MULTILINE | ES_AUTOHSCROLL + CONTROL "Blocking",IDC_BLOCKING,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,8,64,43,10 + CONTROL "Progress Callback",IDC_PROGRESS_CALLBACK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,53,64,73,10 + CONTROL "Completed Callback",IDC_COMPLETED_CALLBACK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,128,64,79,10 + CONTROL "Throttle",IDC_THROTTLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,209,64,40,10 + CONTROL "User Buffer",IDC_USER_BUFFER,"Button",BS_AUTOCHECKBOX | + WS_GROUP | WS_TABSTOP,68,78,51,10 + EDITTEXT IDC_BUFFER_SIZE,151,77,94,12,ES_AUTOHSCROLL + EDITTEXT IDC_SAVE_AS,104,92,94,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "Start",IDC_START,260,26,50,14 + DEFPUSHBUTTON "Cancel",IDC_CANCEL,260,45,50,14 + EDITTEXT IDC_FILE,8,218,230,36,ES_MULTILINE | ES_AUTOHSCROLL | + ES_READONLY | WS_VSCROLL + LTEXT "URL:",IDC_STATIC,9,8,18,8 + LTEXT "Headers:",IDC_STATIC,9,23,30,8 + LTEXT "Size:",IDC_STATIC,129,79,16,8 + LTEXT "Save as:",IDC_STATIC,70,93,29,8 + LTEXT "X/X",IDC_SO_FAR,8,144,225,8 + EDITTEXT IDC_HEADERS_RECV,8,178,230,37,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL + EDITTEXT IDC_STATUS,8,163,230,12,ES_MULTILINE | ES_AUTOHSCROLL | + ES_READONLY + DEFPUSHBUTTON "Think",IDC_THINK,258,108,50,14 + CONTROL "Step Think",IDC_STEP_THINK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,258,93,51,10 + CONTROL "Post File",IDC_POST_FILE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,68,134,43,10 + LTEXT "Objects:",IDC_STATIC,118,135,27,8 + LTEXT "X/X",IDC_POST_OBJECTS,149,135,24,8 + LTEXT "Bytes:",IDC_STATIC,182,135,20,8 + LTEXT "X/X",IDC_POST_BYTES,209,135,99,8 + EDITTEXT IDC_PROXY,30,48,112,12,ES_AUTOHSCROLL + LTEXT "Proxy:",IDC_STATIC,7,49,20,8 + DEFPUSHBUTTON "IE Settings",IDC_IE_SETTINGS,196,48,50,12 + DEFPUSHBUTTON "Set Proxy",IDC_SET_PROXY,144,48,50,12 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "ghttpmfc MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "ghttpmfc\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "ghttpmfc.EXE\0" + VALUE "ProductName", "ghttpmfc Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_GHTTPMFC_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 255 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\ghttpmfc.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfcDlg.cpp b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfcDlg.cpp new file mode 100644 index 00000000000..ce8990922b7 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfcDlg.cpp @@ -0,0 +1,577 @@ +// ghttpmfcDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ghttpmfc.h" +#include "ghttpmfcDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#include "InetReg.h" + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcDlg dialog + +CGhttpmfcDlg::CGhttpmfcDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGhttpmfcDlg::IDD, pParent) +{ + char buffer[512]; + int rcode; + FILE * fp; + fp = fopen("url.cache", "rt"); + if(fp) + { + rcode = fread(buffer, 1, 511, fp); + buffer[rcode] = '\0'; + m_url = buffer; + fclose(fp); + } + else + m_url = _T("http://planetquake.com/excessive"); + + fp = fopen("saveas.cache", "rt"); + if(fp) + { + rcode = fread(buffer, 1, 511, fp); + buffer[rcode] = '\0'; + m_saveAs = buffer; + fclose(fp); + } + else + m_saveAs = _T("file.html"); + + //{{AFX_DATA_INIT(CGhttpmfcDlg) + m_blocking = FALSE; + m_completedCallback = TRUE; + m_headers = _T(""); + m_progressCallback = TRUE; + m_bufferSize = 0; + m_userBuffer = FALSE; + m_type = 0; + m_file = _T(""); + m_soFar = _T(""); + m_state = -1; + m_throttle = FALSE; + m_headersRecv = _T(""); + m_status = _T(""); + m_stepThink = FALSE; + m_postFile = FALSE; + m_postObjects = _T(""); + m_postBytes = _T(""); + m_proxy = _T(""); + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CGhttpmfcDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGhttpmfcDlg) + DDX_Control(pDX, IDC_PROGRESS, m_progress); + DDX_Check(pDX, IDC_BLOCKING, m_blocking); + DDX_Check(pDX, IDC_COMPLETED_CALLBACK, m_completedCallback); + DDX_Text(pDX, IDC_HEADERS, m_headers); + DDX_Check(pDX, IDC_PROGRESS_CALLBACK, m_progressCallback); + DDX_Text(pDX, IDC_URL, m_url); + DDX_Text(pDX, IDC_BUFFER_SIZE, m_bufferSize); + DDX_Text(pDX, IDC_SAVE_AS, m_saveAs); + DDX_Check(pDX, IDC_USER_BUFFER, m_userBuffer); + DDX_Radio(pDX, IDC_GET_FILE, m_type); + DDX_Text(pDX, IDC_FILE, m_file); + DDX_Text(pDX, IDC_SO_FAR, m_soFar); + DDX_Radio(pDX, IDC_HOST_LOOKUP, m_state); + DDX_Check(pDX, IDC_THROTTLE, m_throttle); + DDX_Text(pDX, IDC_HEADERS_RECV, m_headersRecv); + DDX_Text(pDX, IDC_STATUS, m_status); + DDX_Check(pDX, IDC_STEP_THINK, m_stepThink); + DDX_Check(pDX, IDC_POST_FILE, m_postFile); + DDX_Text(pDX, IDC_POST_OBJECTS, m_postObjects); + DDX_Text(pDX, IDC_POST_BYTES, m_postBytes); + DDX_Text(pDX, IDC_PROXY, m_proxy); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CGhttpmfcDlg, CDialog) + //{{AFX_MSG_MAP(CGhttpmfcDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_START, OnStart) + ON_BN_CLICKED(IDC_CANCEL, OnCancel_) + ON_WM_TIMER() + ON_WM_DESTROY() + ON_BN_CLICKED(IDC_THROTTLE, OnThrottle) + ON_BN_CLICKED(IDC_THINK, OnThink) + ON_BN_CLICKED(IDC_SET_PROXY, OnSetProxy) + ON_BN_CLICKED(IDC_IE_SETTINGS, OnIeSettings) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcDlg message handlers + +BOOL CGhttpmfcDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + m_request = -1; + m_memFile = NULL; + SetTimer(50, 50, NULL); + + return TRUE; // return TRUE unless you set the focus to a control +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CGhttpmfcDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CGhttpmfcDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +static GHTTPBool CompletedCallback +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + CGhttpmfcDlg * dlg = (CGhttpmfcDlg *)param; + + static char * resultStrings[] = + { + "GHTTPSuccess", + "GHTTPOutOfMemory", + "GHTTPBufferOverflow", + "GHTTPParseURLFailed", + "GHTTPHostLookupFailed", + "GHTTPSocketFailed", + "GHTTPConnectFailed", + "GHTTPBadResponse", + "GHTTPRequestRejected", + "GHTTPUnauthorized", + "GHTTPForbidden", + "GHTTPFileNotFound", + "GHTTPServerError", + "GHTTPFileWriteFailed", + "GHTTPFileReadFailed", + "GHTTPFileIncomplete", + "GHTTPFileToBig", + "GHTTPEncryptionError", + "GHTTPRequestCancelled" + }; + + CString msg; + + if( GHTTPSuccess == result ) + { + msg = "File received successfully"; + } + else + { + msg.Format("Error: (%d) ", result); + if( result < 0 || result >= sizeof(resultStrings)/sizeof(resultStrings[0]) ) + msg += "Unknown - local error table may be out of date"; + else + msg += resultStrings[(int)result]; + } + + dlg->MessageBox(msg); + + dlg->m_request = -1; + + return GHTTPTrue; + + GSI_UNUSED(bufferLen); + GSI_UNUSED(buffer); + GSI_UNUSED(request); +} + +void ProgressCallback +( + GHTTPRequest request, + GHTTPState state, + const char * buffer, + GHTTPByteCount bufferLen, + GHTTPByteCount bytesReceived, + GHTTPByteCount totalSize, + void * param +) +{ + CGhttpmfcDlg * dlg = (CGhttpmfcDlg *)param; + + dlg->UpdateData(); + + dlg->m_state = state; + + //added new states for asynch DNS lookup - set all to HOST_LOOKUP for radio buttons + if (dlg->m_state == GHTTPSocketInit || dlg->m_state == GHTTPHostLookup || dlg->m_state == GHTTPLookupPending) + dlg->m_state = 0; + + if(state == GHTTPReceivingFile) + { + if(totalSize == -1) + dlg->m_soFar.Format("%d bytes", bytesReceived); + else + { + int percent = (int)((bytesReceived * 100) / totalSize); + dlg->m_soFar.Format("%d%% (%d / %d bytes)", percent, bytesReceived, totalSize); + dlg->m_progress.SetPos(percent); + } + if((dlg->m_type == 0) || (dlg->m_type == 4)) + dlg->m_file = buffer; + } + + dlg->UpdateData(FALSE); + + GSI_UNUSED(bufferLen); + GSI_UNUSED(request); +} + +void PostCallback +( + GHTTPRequest request, + int bytesPosted, + int totalBytes, + int objectsPosted, + int totalObjects, + void * param +) +{ + CGhttpmfcDlg * dlg = (CGhttpmfcDlg *)param; + + dlg->UpdateData(); + + int percent = ((bytesPosted * 100) / totalBytes); + dlg->m_postObjects.Format("%d / %d", objectsPosted, totalObjects); + dlg->m_postBytes.Format("%d%% (%d / %d)", percent, bytesPosted, totalBytes); + + dlg->UpdateData(FALSE); + + GSI_UNUSED(request); +} + +void CGhttpmfcDlg::OnStart() +{ + UpdateData(); + + if(m_type == 0) + { + m_request = ghttpGetEx( + m_url, + m_headers, + NULL, + 0, + NULL, + (GHTTPBool)m_throttle, + (GHTTPBool)m_blocking, + ProgressCallback, + CompletedCallback, + this); + } + else if(m_type == 1) + { + m_request = ghttpSaveEx( + m_url, + m_saveAs, + m_headers, + NULL, + (GHTTPBool)m_throttle, + (GHTTPBool)m_blocking, + ProgressCallback, + CompletedCallback, + this); + } + else if(m_type == 2) + { + m_request = ghttpStreamEx( + m_url, + m_headers, + NULL, + (GHTTPBool)m_throttle, + (GHTTPBool)m_blocking, + ProgressCallback, + CompletedCallback, + this); + } + else if(m_type == 3) + { + m_request = ghttpHeadEx( + m_url, + m_headers, + (GHTTPBool)m_throttle, + (GHTTPBool)m_blocking, + ProgressCallback, + CompletedCallback, + this); + } + else if(m_type == 4) + { + GHTTPPost post; + post = ghttpNewPost(); + ghttpPostSetCallback(post, PostCallback, this); + ghttpPostAddString(post, "test1", "bag"); + ghttpPostAddString(post, "test2", "test%test!@#) $(%^(*&test"); + if(m_postFile) + { + static int memFileSize = 100000; + if(!m_memFile) + m_memFile = (char *)malloc(memFileSize); + memset(m_memFile, 0, memFileSize); + sprintf(m_memFile, "steve"); + ghttpPostAddFileFromMemory(post, "memfile", m_memFile, memFileSize, "steve.txt", NULL); + ghttpPostAddFileFromDisk(post, "diskfile", "../ghttpMain.c", "main.c", "text/html"); + } + +#if 1 + m_request = ghttpGetEx( + m_url, + m_headers, + NULL, + 0, + post, + (GHTTPBool)m_throttle, + (GHTTPBool)m_blocking, + ProgressCallback, + CompletedCallback, + this); +#else + m_request = ghttpPostEx( + m_url, + m_headers, + post, + (GHTTPBool)m_throttle, + (GHTTPBool)m_blocking, + ProgressCallback, + CompletedCallback, + this); +#endif + } + + if(m_request == -1) + MessageBox("Unable to start request"); + else if(m_url.Left(8).Compare("https://") == 0) + ghttpSetRequestEncryptionEngine(m_request, GHTTPEncryptionEngine_GameSpy); + + m_state = 0; + m_soFar = ""; + m_file = ""; + m_postObjects = ""; + m_postBytes = ""; + + UpdateData(FALSE); +} + +void CGhttpmfcDlg::OnCancel_() +{ + if(m_request >= 0) + ghttpCancelRequest(m_request); +} + +void CGhttpmfcDlg::OnTimer(UINT nIDEvent) +{ + if(nIDEvent == 50) + { + UpdateData(); + + if(!m_stepThink) + ghttpThink(); + + if(m_request >= 0) + { + const char * statusString; + int statusCode; + statusString = ghttpGetResponseStatus(m_request, &statusCode); + if(statusString) + m_status.Format("%d: %s", statusCode, statusString); + else + m_status.Empty(); + + const char * headers; + headers = ghttpGetHeaders(m_request); + if(headers) + m_headersRecv = headers; + else + m_headersRecv.Empty(); + + m_state = (int)ghttpGetState(m_request); + //added new states for asynch DNS lookup - set all to HOST_LOOKUP for radio buttons + if (m_state == GHTTPSocketInit || m_state == GHTTPHostLookup || m_state == GHTTPLookupPending) + m_state = 0; + UpdateData(FALSE); + } + } + + CDialog::OnTimer(nIDEvent); +} + +void CGhttpmfcDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + FILE * fp; + fp = fopen("url.cache", "wt"); + if(fp) + { + fprintf(fp, "%s", m_url); + fclose(fp); + } + + fp = fopen("saveas.cache", "wt"); + if(fp) + { + fprintf(fp, "%s", m_saveAs); + fclose(fp); + } + + ghttpCleanup(); + + if(m_memFile) + free(m_memFile); + m_memFile = NULL; +} + +void CGhttpmfcDlg::OnThrottle() +{ + UpdateData(); + + if(m_request >= 0) + ghttpSetThrottle(m_request, (GHTTPBool)m_throttle); +} + +void CGhttpmfcDlg::OnThink() +{ + if(m_request >= 0) + ghttpThink(); +} + +void CGhttpmfcDlg::OnSetProxy() +{ + UpdateData(); + + ghttpSetProxy(m_proxy); +} + +// Copied from JED's ProxyInfo. Edited down for this app's purposes. +void CGhttpmfcDlg::OnIeSettings() +{ + HKEY key; + LONG result; + DWORD type; + DWORD data; + DWORD len; + CString str; + int nStart; + int nEnd; + + UpdateData(); + + // Open the IE settings in the registry. + //////////////////////////////////////// + result = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_INTERNETSETTINGS, 0, KEY_READ, &key); + if(SUCCEEDED(result)) + { + // Is the proxy enabled? + //////////////////////// + len = sizeof(DWORD); + data = 0; + result = RegQueryValueEx(key, REGSTR_VAL_PROXYENABLE, 0, &type, (LPBYTE)&data, &len); + if(SUCCEEDED(result) && data) + { + //---------------------------------------------------------------------- + // + // The list of proxy servers to use + // + len = 0; + result = RegQueryValueEx(key, REGSTR_VAL_PROXYSERVER, 0, &type, NULL, &len); + result = RegQueryValueEx(key, REGSTR_VAL_PROXYSERVER, 0, &type, (LPBYTE)str.GetBuffer(len), &len); + str.ReleaseBuffer(); + if(SUCCEEDED(result) && (len > 0)) + { + // Find the http proxy. + // + // Use the same proxy for all protocols: "single_proxy_address:13" + // read as: server:port + // individualized protocols: "ftp=ftp_address;gopher=gopher_address:4;http=http_address:1;https=secure_address:2;socks=socks_address:5" + // read as: protocol=server:port;protocol=server:port + // If only protocol is to use proxy: "socks=socks_address:5" + // Apparently, ports are optional - I would presume that you should revert to the default port when it is missing + // + // First search for "http=[:port]". + /////////////////////////////////////////// + nStart = str.Find("http="); + if(nStart != -1) + { + nStart += 5; + nEnd = str.Find(';', nStart); + if(nEnd == -1) + nEnd = str.GetLength(); + } + else if(str.Find('=') == -1) + { + nStart = 0; + nEnd = str.GetLength(); + } + else + { + nStart = -1; + nEnd = 0; //won't be used; need to initialize to prevent compiler warning + } + + if((nStart != -1) && (nStart != nEnd)) + str = str.Mid(nStart, nEnd - nStart); + else + str = ""; + } + } + + // Cleanup. + /////////// + RegCloseKey(key); + } + + m_proxy = str; + + UpdateData(FALSE); + + OnSetProxy(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfcDlg.h b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfcDlg.h new file mode 100644 index 00000000000..11681d5df84 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfcDlg.h @@ -0,0 +1,79 @@ +// ghttpmfcDlg.h : header file +// + +#if !defined(AFX_GHTTPMFCDLG_H__14B35CAF_3960_4669_972D_59B741AA032C__INCLUDED_) +#define AFX_GHTTPMFCDLG_H__14B35CAF_3960_4669_972D_59B741AA032C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CGhttpmfcDlg dialog + +class CGhttpmfcDlg : public CDialog +{ +// Construction +public: + CGhttpmfcDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CGhttpmfcDlg) + enum { IDD = IDD_GHTTPMFC_DIALOG }; + CProgressCtrl m_progress; + BOOL m_blocking; + BOOL m_completedCallback; + CString m_headers; + BOOL m_progressCallback; + CString m_url; + int m_bufferSize; + CString m_saveAs; + BOOL m_userBuffer; + int m_type; + CString m_file; + CString m_soFar; + int m_state; + BOOL m_throttle; + CString m_headersRecv; + CString m_status; + BOOL m_stepThink; + BOOL m_postFile; + CString m_postObjects; + CString m_postBytes; + CString m_proxy; + //}}AFX_DATA + + GHTTPRequest m_request; + char * m_memFile; + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGhttpmfcDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CGhttpmfcDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnStart(); + afx_msg void OnCancel_(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnDestroy(); + afx_msg void OnThrottle(); + afx_msg void OnThink(); + afx_msg void OnSetProxy(); + afx_msg void OnIeSettings(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GHTTPMFCDLG_H__14B35CAF_3960_4669_972D_59B741AA032C__INCLUDED_) diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc_vs2005.vcproj b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc_vs2005.vcproj new file mode 100644 index 00000000000..d65aea56260 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/ghttpmfc_vs2005.vcproj @@ -0,0 +1,712 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/res/ghttpmfc.ico b/xrGameSpy/gamespy/ghttp/ghttpmfc/res/ghttpmfc.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/ghttp/ghttpmfc/res/ghttpmfc.ico differ diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/res/ghttpmfc.rc2 b/xrGameSpy/gamespy/ghttp/ghttpmfc/res/ghttpmfc.rc2 new file mode 100644 index 00000000000..b5533ab2e4f --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/res/ghttpmfc.rc2 @@ -0,0 +1,13 @@ +// +// GHTTPMFC.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/ghttp/ghttpmfc/resource.h b/xrGameSpy/gamespy/ghttp/ghttpmfc/resource.h new file mode 100644 index 00000000000..bc4776ba1b5 --- /dev/null +++ b/xrGameSpy/gamespy/ghttp/ghttpmfc/resource.h @@ -0,0 +1,54 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ghttpmfc.rc +// +#define IDD_GHTTPMFC_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_URL 1000 +#define IDC_HEADERS 1001 +#define IDC_BLOCKING 1002 +#define IDC_PROGRESS_CALLBACK 1003 +#define IDC_COMPLETED_CALLBACK 1004 +#define IDC_USER_BUFFER 1005 +#define IDC_GET_FILE 1006 +#define IDC_SAVE_FILE 1007 +#define IDC_STREAM_FILE 1008 +#define IDC_BUFFER_SIZE 1009 +#define IDC_FILE 1010 +#define IDC_SAVE_AS 1011 +#define IDC_SO_FAR 1012 +#define IDC_HEAD_FILE 1013 +#define IDC_HOST_LOOKUP 1014 +#define IDC_RADIO3 1015 +#define IDC_RADIO4 1016 +#define IDC_RADIO5 1017 +#define IDC_RADIO6 1018 +#define IDC_PROGRESS 1019 +#define IDC_THROTTLE 1020 +#define IDC_RADIO7 1021 +#define IDC_RADIO8 1022 +#define IDC_RADIO9 1023 +#define IDC_HEADERS_RECV 1024 +#define IDC_STATUS 1025 +#define IDC_POST 1026 +#define IDC_STEP_THINK 1027 +#define IDC_POST_FILE 1028 +#define IDC_POST_OBJECTS 1029 +#define IDC_POST_BYTES 1030 +#define IDC_PROXY 1031 +#define IDC_START 1050 +#define IDC_CANCEL 1051 +#define IDC_THINK 1052 +#define IDC_IE_SETTINGS 1053 +#define IDC_SET_PROXY 1054 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1029 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/gstats/changelog.txt b/xrGameSpy/gamespy/gstats/changelog.txt new file mode 100644 index 00000000000..f39098e6d12 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/changelog.txt @@ -0,0 +1,102 @@ +Changelog for: GameSpy Stats & Tracking / Persistent Storage SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.19.00 RMV RELEASE Released to Developer Site +12-10-2007 1.18.02 RMV OTHER Created VS2005 projects for persisttest and gstats +12-07-2007 1.18.01 SAH OTHER Fixed projects that were missing dependencies +08-06-2007 1.18.00 RMV RELEASE Released to Developer Site +12-15-2006 1.17.00 MJW RELEASE Released to Developer Site +10-05-2006 1.16.43 SAH FIX Updated MacOSX Makefile +09-28-2006 1.16.42 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-24-2006 1.16.41 SAH FIX Fixed VC7 project file +08-23-2006 1.16.40 SAH FIX Added a fix for len == -1 in RecvSessionKey function. +08-02-2006 1.16.39 SAH RELEASE Releasing to developer site +07-31-2006 1.16.38 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 1.16.37 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-06-2006 1.16.36 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +06-30-2006 1.16.35 SAH FIX Fixed NITRO projects & linker command files (to work with CW 2.0/NitroSDK 3.1) + SAH FIX Fixed Linux makefiles +05-31-2006 1.16.34 SAH RELEASE Releasing to developer site +05-30-2006 1.16.33 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) +05-25-2006 1.16.32 SAH FIX Changed PSP project warning levels +05-19-2006 1.16.31 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-15-2006 1.16.30 SAH FIX Added "PS3 Release" configuration(s) to project +05-11-2006 1.16.29 SN FIX Modified the update game message to include the connid so that games aren't discarded when a disconnect occurs +04-25-2006 1.16.28 SAH RELEASE Releasing to developer site +04-24-2006 1.16.28 SAH FIX Fixed Nitro project files to work on build machine +04-20-2006 1.16.27 SAH FIX Removed unused variables, moved GSI_UNUSED above return calls +01-27-2006 1.16.26 SN RELEASE Releasing to developer site +01-27-2006 1.16.26 SN FIX Added PSP to test_main define in statstest + SN OTHER Added psp prodg project and solution to sgv for statstest +01-27-2006 1.16.25 SN FIX Added PSP to test_main define in persisttest + SN OTHER Added psp prodg project and solution to sgv for persisttest +12-19-2005 1.16.24 SN OTHER Cleaned up projects, adding any missing common code. + Replaced gstats project with statstest in its subdirectory +11-17-2005 1.16.23 DES FIX Updated Nitro Makefile. +11-14-2005 1.16.22 DES FIX Updated the OSX Makefiles. + DES FEATURE Added GSI_DOMAIN_NAME support. +09-23-2005 1.16.21 DES FEATURE Updated DS support +07-28-2005 1.16.20 SN RELEASE Releasing to developer site. +07-28-2005 1.16.20 SN FIX fixed PS2 projects to use new common code +06-03-2005 1.16.19 SN RELEASE Releasing to developer site. +05-05-2005 1.16.19 BED FIX Updated project files to use new common folder. +05-03-2005 1.16.18 SN FIX Removed deprecated MFC code for Visual Studio .NET projects + SN OTHER Created Visual Studio .NET projects +04-28-2005 1.16.17 SN RELEASE Releasing to developer site. +04-27-2005 1.16.17 DES RELEASE Limited release to Nintendo DS developers. +04-27-2005 1.16.17 DES FIX Changed the default connect timeout to 20 seconds for the DS. + DES FIX Added extra printfs to statstest. +04-25-2005 1.16.16 DES FIX Check for socket error when receiving the challenge. + DES CLEANUP Removed printf()s from gstats.c +04-04-2005 1.16.15 SN RELEASE Releasing to developer site. +04-03-2005 1.16.15 SN FIX Added a StatsThink function due to socket api buffer clogging +03-25-2005 1.16.14 SN FIX Fixed bug to clean g_statsgame when FreeGame was called with local statsgame_t and both were the same object. +03-16-2005 1.16.13 SN FIX Fixed PS2 bug not being able to print hex chars correctly. +03-14-2005 1.16.13 DES FEATURE Nintendo DS support +12-28-2004 1.16.12 SN FIX Added const qualifiers to unmodified formal function parameters +09-16-2004 1.16.11 SN RELEASE Releasing to developer site. +09-16-2004 1.16.11 SN FIX Renamed a global variable to avoid MacOS X naming confliction +09-09-2004 1.16.10 BED FEATURE Added InitStatsAsync and InitStatsThink. +08-27-2004 1.16.09 DES CLEANUP Removed MacOS style includes + DES CLEANUP Updated Win32 project configurations + DES CLEANUP General Unicode cleanup + DES CLEANUP Fixed warnings under OSX + DES CLEANUP Updated OSX Makefile +08-05-2004 1.16.08 BED RELEASE Releasing to developer site. +08-05-2004 1.16.08 BED FIX Updated samples to use GT2 instead of legacy GT1 SDK +07-20-2004 1.16.07 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +07-20-2004 1.16.06 BED FEATURE Added Remote Auth hooks +06-18-2004 1.16.05 BED RELEASE Releasing to developer site. + FEATURE Added PS2 Insock support +11-10-2003 1.16.04 DES RELEASE Releasing to developer site. +11-07-2003 1.16.04 BED FIX Removed CodeWarrior strictest warnings. +11-07-2003 1.16.03 DES FIX Updated the linux and PS2 makefiles. +11-04-2003 1.16.02 DES FEATURE Added availability check code. +10-30-2003 1.16.01 DES FIX Updated gp_stats to work with the latest versions of GP and stats. +10-21-2003 1.16.00 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-01-2003 1.16.00 DDW FEATURE Added modified time checking/reporting to persistent storage + NOTE: Persistent Storage callbacks modified w/ additional parameter + Prepend hostname with gamename for unique DNS names +09-08-2003 1.15.11 BED FEATURE Added UTF-8 wrapper for UNICODE support. +07-24-2003 1.15.10 DES RELEASE Releasing to developer site. +07-18-2003 1.15.10 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 1.15.09 DES CLEANUP Cleaned up the PS2 Makefiles, they now use Makefile.commmon. +07-14-2003 1.15.08 DES FIX ALLOW_DISK is now undef'd whenever NOFILE is defined. + FIX Changed __mips64 check to _PS2 check. + CLEANUP No need to make remove() an empty define on systems with NOFILE defined. + BED FEATURE Added ProDG sample project files to gstats and persistest +07-03-2003 1.15.07 BED FIX Added gtUtility.c to the ladderTrack sample. +05-09-2003 1.15.06 DES CLEANUP Removed Dreamcast support. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +03-03-2003 1.15.05 DES CLEANUP General cleanup to remove warnings. +12-19-2002 1.15.04 DES RELEASE Releasing to developer site. +12-19-2002 1.15.04 DES CLEANUP Removed assert.h include. +12-13-2002 1.15.03 DES FEATURE Added PS2 eenet stack support. +11-22-2002 1.15.02 DES RELEASE Releasing to developer site. +11-20-2002 1.15.02 DES CLEANUP Cleaned up to remove PS2 compiler warnings. +11-15-2002 1.15.01 DES CLEANUP Updated persisttest PS2 Makefile +09-25-2002 1.15.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/gstats/gbucket.c b/xrGameSpy/gamespy/gstats/gbucket.c new file mode 100644 index 00000000000..6c14eb9d19b --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gbucket.c @@ -0,0 +1,401 @@ +/****** +gbucket.c +GameSpy Stats/Tracking SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +******/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 260, 357 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +/******** +INCLUDES +********/ +#include "../common/gsCommon.h" +#include "gbucket.h" +#include "../hashtable.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/******** +TYPEDEFS +********/ +struct bucketset_s +{ + HashTable buckets; +}; + + +typedef struct bucket_s +{ + char *name; + BucketType type; + int nvals; //for averaging + union + { + int ival; + double fval; + char *sval; + } vals; +} bucket_t; + +typedef struct dumpdata_s +{ + char *data; + unsigned int maxlen; + unsigned int len; +} dumpdata_t; + +/******** +PROTOTYPES +********/ +static void DumpMap(void *elem, void *clientData); +static void BucketFree(void *elem); +static int BucketCompare(const void *entry1, const void *entry2); +static int BucketHash(const void *elem, int numbuckets); +static void *DoSet(bucket_t *pbucket, void *value); +static void *DoGet(bucket_t *pbucket); +static bucket_t *DoFind(bucketset_t set, char *name); + + +/******** +VARS +********/ +bucketset_t g_buckets; + +/****************************************************************************/ +/* PUBLIC FUNCTIONS */ +/****************************************************************************/ +bucketset_t NewBucketSet(void) +{ + bucketset_t set; + + set = (bucketset_t)gsimalloc(sizeof (struct bucketset_s)); + assert(set); + set->buckets = TableNew(sizeof(bucket_t),32,BucketHash, BucketCompare, BucketFree); + + g_buckets = set; + return set; +} + +void FreeBucketSet(bucketset_t set) +{ + assert(set); + assert(set->buckets); + TableFree(set->buckets); + gsifree(set); +} + +char *DumpBucketSet(bucketset_t set) +{ + dumpdata_t data; + if (set == NULL) + set = g_buckets; + assert(set); + data.data = (char *)gsimalloc(128); //alloc an initial buffer + data.data[0] = 0; + data.len = 0; + data.maxlen = 128; + TableMap(set->buckets,DumpMap, &data); + return data.data; +} + +void *BucketNew(bucketset_t set, char *name, BucketType type, void *initialvalue) +{ + bucket_t bucket; + + if (set == NULL) + set = g_buckets; + assert(set); + bucket.name = goastrdup(name); + bucket.type = type; + bucket.vals.sval = NULL; + bucket.nvals = 1; + DoSet(&bucket, initialvalue); + TableEnter(set->buckets,&bucket); + return DoGet(DoFind(set, name)); +} + +void *BucketSet(bucketset_t set, char *name,void *value) +{ + bucket_t *pbucket = DoFind(set, name); + if (!pbucket) + return NULL; + + pbucket->nvals = 0; + return DoSet(pbucket,value); +} + +void *BucketGet(bucketset_t set, char *name) +{ + return DoGet(DoFind(set,name)); +} + +void *BucketAdd(bucketset_t set, char *name, void *value) +{ + bucket_t *pbucket = DoFind(set, name); + if (!pbucket) + return NULL; + + if (pbucket->type == bt_int) + return DoSet(pbucket, bint( (*(int *)DoGet(pbucket)) + (*(int *)value))); + if (pbucket->type == bt_float) + return DoSet(pbucket, bfloat( (*(double *)DoGet(pbucket)) + (*(double *)value))); + //else, string -- just concat + return BucketConcat(set, name, value); +} + +void *BucketSub(bucketset_t set, char *name, void *value) +{ + bucket_t *pbucket = DoFind(set, name); + if (!pbucket) + return NULL; + + if (pbucket->type == bt_int) + return DoSet(pbucket, bint( (*(int *)DoGet(pbucket)) - (*(int *)value))); + if (pbucket->type == bt_float) + return DoSet(pbucket, bfloat( (*(double *)DoGet(pbucket)) - (*(double *)value))); + //else, string -- just ignore + return DoGet(pbucket); + +} + +void *BucketMult(bucketset_t set, char *name, void *value) +{ + bucket_t *pbucket = DoFind(set, name); + if (!pbucket) + return NULL; + + if (pbucket->type == bt_int) + return DoSet(pbucket, bint( (*(int *)DoGet(pbucket)) * (*(int *)value))); + if (pbucket->type == bt_float) + return DoSet(pbucket, bfloat( (*(double *)DoGet(pbucket)) * (*(double *)value))); + //else, string -- just ignore + return DoGet(pbucket); +} + +void *BucketDiv(bucketset_t set, char *name, void *value) +{ + bucket_t *pbucket = DoFind(set, name); + if (!pbucket) + return NULL; + + if (pbucket->type == bt_int) + return DoSet(pbucket, bint( (*(int *)DoGet(pbucket)) / (*(int *)value))); + if (pbucket->type == bt_float) + return DoSet(pbucket, bfloat( (*(double *)DoGet(pbucket)) / (*(double *)value))); + //else, string -- just ignore + return DoGet(pbucket); +} + +void *BucketConcat(bucketset_t set, char *name, void *value) +{ + bucket_t *pbucket = DoFind(set, name); + char *temp, *s; + if (!pbucket) + return NULL; + + assert(pbucket->type == bt_string); + s = DoGet(pbucket); + temp = (char *)gsimalloc(strlen(s) + strlen(value) + 1); + strcpy(temp,s); + strcat(temp, value); + + DoSet(pbucket, temp); + gsifree(temp); + + return DoGet(pbucket); +} + +#define AVG(cur, new, num) (((cur * num) + new) / (++num)) +void *BucketAvg(bucketset_t set, char *name, void *value) +{ + bucket_t *pbucket = DoFind(set, name); + if (!pbucket) + return NULL; + + if (pbucket->type == bt_int) + return DoSet(pbucket, bint( AVG((*(int *)DoGet(pbucket)), (*(int *)value), pbucket->nvals))); + if (pbucket->type == bt_float) + return DoSet(pbucket, bfloat( AVG((*(double *)DoGet(pbucket)), (*(double *)value), pbucket->nvals))); + //else, string -- just ignore + return DoGet(pbucket); +} + +/* Note: these are NOT thread safe! */ +void *bint(int i) +{ + static int j; + j=i; + return &j; +} + +void *bfloat(double f) +{ + static double g; + g=f; + return &g; +} + + + +/*********** + * UTILITY FUNCTIONS + **********/ +static void DumpMap(void *elem, void *clientData) +{ + bucket_t *bucket = (bucket_t *)elem; + dumpdata_t *data = (dumpdata_t *)clientData; + unsigned int minlen; + + //find out if we need to resize! + minlen = strlen(bucket->name) + 3; + if (bucket->type == bt_int || bucket->type == bt_float) + minlen += data->len + 16; + else if (bucket->type == bt_string) + minlen += data->len + strlen(bucket->vals.sval); + + if (data->maxlen <= minlen) + { + if (data->maxlen == 0) + data->maxlen = minlen * 2; + else + data->maxlen *= 2; + data->data = gsirealloc(data->data, data->maxlen); + + } + + switch (bucket->type) + { + case bt_int: + data->len += (unsigned int)sprintf(data->data + data->len,"\\%s\\%d",bucket->name,bucket->vals.ival); + break; + case bt_float: + data->len += (unsigned int)sprintf(data->data + data->len,"\\%s\\%f",bucket->name,bucket->vals.fval); + break; + case bt_string: + data->len += (unsigned int)sprintf(data->data + data->len,"\\%s\\%s",bucket->name,bucket->vals.sval); + break; + + } +} + + +static char *stripchars(char *s) +{ + char *p = s; + while (*s) + { + if (*s == '\\') + *s = '/'; + s++; + } + return p; +} + +static void *DoSet(bucket_t *pbucket, void *value) +{ + if (pbucket->type == bt_int) + pbucket->vals.ival = *(int*)value; + else if (pbucket->type == bt_float) + pbucket->vals.fval = *(double *)value; + else if (pbucket->type == bt_string) + { + if (pbucket->vals.sval != NULL) + gsifree(pbucket->vals.sval); + pbucket->vals.sval = (value == NULL ? NULL : stripchars(goastrdup((char *)value))); + } + return DoGet(pbucket); +} + +static void *DoGet(bucket_t *pbucket) +{ + if (!pbucket) + return NULL; + if (pbucket->type == bt_string) + return pbucket->vals.sval; + else //since it's a union, we can return any member + return &pbucket->vals.sval; + +} + +static bucket_t *DoFind(bucketset_t set, char *name) +{ + bucket_t tbucket; + + if (set == NULL) + set = g_buckets; + assert(set); + + tbucket.name = name; + return (bucket_t *)TableLookup(set->buckets,&tbucket); +} + + + +/* NonTermHash + * ---------- + * The hash code is computed using a method called "linear congruence." + * This hash function has the additional feature of being case-insensitive, + */ +#define MULTIPLIER -1664117991 +static int BucketHash(const void *elem, int numbuckets) +{ + unsigned int i; + unsigned int len; + unsigned int hashcode = 0; + + char *s = ((bucket_t *)elem)->name; + len = strlen(s); + for (i = 0; i < len ; i++) { + hashcode = (unsigned int)((int)hashcode * MULTIPLIER + tolower(s[i])); + } + return (int)(hashcode % numbuckets); +} + + +/* CaseInsensitiveCompare + * ---------------------- + * Comparison function passed to qsort to sort an array of + * strings in alphabetical order. It uses strcasecmp which is + * identical to strcmp, except that it doesn't consider case of the + * characters when comparing them, thus it sorts case-insensitively. + */ +static int CaseInsensitiveCompare(const void *entry1, const void *entry2) +{ + return strcasecmp(*(char **)entry1,*(char **)entry2); +} + +/* keyval + * Compares two buckets (case insensative) + */ +static int BucketCompare(const void *entry1, const void *entry2) +{ + + return CaseInsensitiveCompare(&((bucket_t *)entry1)->name, + &((bucket_t *)entry2)->name); +} + + +/* KeyValFree + * Frees the memory INSIDE a Bucket structure + */ +static void BucketFree(void *elem) +{ + gsifree(((bucket_t *)elem)->name); + if (((bucket_t *)elem)->type == bt_string && ((bucket_t *)elem)->vals.sval != NULL) + gsifree(((bucket_t *)elem)->vals.sval); + +} + +#ifdef __cplusplus +} +#endif diff --git a/xrGameSpy/gamespy/gstats/gbucket.h b/xrGameSpy/gamespy/gstats/gbucket.h new file mode 100644 index 00000000000..add085f6436 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gbucket.h @@ -0,0 +1,52 @@ +/****** +gbucket.h +GameSpy Stats/Tracking SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + +Please see the GameSpy Stats and Tracking SDK for more info +You should not need to use the functions in this file, they +are used to manage the buckets by the gstats SDK. +Use the type-safe bucket functions in the gstats SDK instead. +******/ + + +#ifndef _GBUCKET_H_ +#define _GBUCKET_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct bucketset_s *bucketset_t; +typedef enum {bt_int, bt_float, bt_string} BucketType; + +bucketset_t NewBucketSet(void); +void FreeBucketSet(bucketset_t set); +char *DumpBucketSet(bucketset_t set); + +void *BucketNew(bucketset_t set, char *name, BucketType type, void *initialvalue); +void *BucketSet(bucketset_t set, char *name,void *value); +void *BucketAdd(bucketset_t set, char *name, void *value); +void *BucketSub(bucketset_t set, char *name, void *value); +void *BucketMult(bucketset_t set, char *name, void *value); +void *BucketDiv(bucketset_t set, char *name, void *value); +void *BucketConcat(bucketset_t set, char *name, void *value); +void *BucketAvg(bucketset_t set, char *name, void *value); +void *BucketGet(bucketset_t set, char *name); + +/* Helper functions */ +void *bint(int i); +void *bfloat(double f); +#define bstring(a) ((void *)a) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/gstats/gp_stats/StdAfx.cpp b/xrGameSpy/gamespy/gstats/gp_stats/StdAfx.cpp new file mode 100644 index 00000000000..9b9d9667714 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// gp_stats.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/gstats/gp_stats/StdAfx.h b/xrGameSpy/gamespy/gstats/gp_stats/StdAfx.h new file mode 100644 index 00000000000..840a0e6b491 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/StdAfx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__14D457F1_07B9_4AB5_97B4_B82E57AFA0D4__INCLUDED_) +#define AFX_STDAFX_H__14D457F1_07B9_4AB5_97B4_B82E57AFA0D4__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__14D457F1_07B9_4AB5_97B4_B82E57AFA0D4__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.cpp b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.cpp new file mode 100644 index 00000000000..51822d839c2 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.cpp @@ -0,0 +1,74 @@ +// gp_stats.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "gp_stats.h" +#include "gp_statsDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsApp + +BEGIN_MESSAGE_MAP(CGp_statsApp, CWinApp) + //{{AFX_MSG_MAP(CGp_statsApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsApp construction + +CGp_statsApp::CGp_statsApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CGp_statsApp object + +CGp_statsApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsApp initialization + +BOOL CGp_statsApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CGp_statsDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.dsp b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.dsp new file mode 100644 index 00000000000..843b76aa6d0 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.dsp @@ -0,0 +1,840 @@ +# Microsoft Developer Studio Project File - Name="gp_stats" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=gp_stats - 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 "gp_stats.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 "gp_stats.mak" CFG="gp_stats - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gp_stats - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "gp_stats - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/gp_stats", RUFBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 wsock32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# 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 /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gp_stats - Win32 Release" +# Name "gp_stats - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gp_stats.cpp + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +# ADD CPP /Yu"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gp_stats.rc +# End Source File +# Begin Source File + +SOURCE=.\gp_statsDlg.cpp +# ADD CPP /Yu"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gp_stats.h +# End Source File +# Begin Source File + +SOURCE=.\gp_statsDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\gp_stats.ico +# End Source File +# Begin Source File + +SOURCE=.\res\gp_stats.rc2 +# End Source File +# End Group +# Begin Group "PersistentStorageSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gbucket.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\gstats.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\gstats.h +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gp\gp.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c + +!IF "$(CFG)" == "gp_stats - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "gp_stats - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.h b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.h new file mode 100644 index 00000000000..63b5a7f26d4 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.h @@ -0,0 +1,49 @@ +// gp_stats.h : main header file for the GP_STATS application +// + +#if !defined(AFX_GP_STATS_H__90B1DDCE_A86E_49A8_B136_0B29EA43F6B4__INCLUDED_) +#define AFX_GP_STATS_H__90B1DDCE_A86E_49A8_B136_0B29EA43F6B4__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsApp: +// See gp_stats.cpp for the implementation of this class +// + +class CGp_statsApp : public CWinApp +{ +public: + CGp_statsApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGp_statsApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CGp_statsApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GP_STATS_H__90B1DDCE_A86E_49A8_B136_0B29EA43F6B4__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.rc b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.rc new file mode 100644 index 00000000000..dee94b3586d --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.rc @@ -0,0 +1,201 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\gp_stats.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\gp_stats.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_GP_STATS_DIALOG DIALOGEX 0, 0, 197, 266 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Tracking Stats by Account" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Quit",IDOK,105,85,50,14 + GROUPBOX "Account",IDC_STATIC,10,10,175,95 + LTEXT "E-mail:",IDC_STATIC,20,23,22,8 + LTEXT "Nick:",IDC_STATIC,20,38,18,8 + LTEXT "Password:",IDC_STATIC,20,53,34,8 + LTEXT "Profile ID:",IDC_STATIC,20,68,32,8 + EDITTEXT IDC_EMAIL,65,20,110,12,ES_AUTOHSCROLL + EDITTEXT IDC_NICK,65,35,110,12,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,65,50,110,12,ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT IDC_PROFILE_ID,65,65,110,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Authenticate",IDC_AUTHENTICATE,35,85,50,14 + GROUPBOX "Persistant Data",IDC_STATIC,10,115,175,140 + CONTROL "Private Read/Write",IDC_PRIVATE_RW,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,20,130,77,10 + CONTROL "Private Read-Only",IDC_PRIVATE_RO,"Button", + BS_AUTORADIOBUTTON,20,145,73,10 + CONTROL "Public Read/Write",IDC_PUBLIC_RW,"Button", + BS_AUTORADIOBUTTON,100,130,75,10 + CONTROL "Public Read-Only",IDC_PUBLIC_RO,"Button", + BS_AUTORADIOBUTTON,100,145,71,10 + PUSHBUTTON "Get",IDC_GET,35,160,50,14,WS_GROUP + PUSHBUTTON "Set",IDC_SET,110,160,50,14 + LTEXT "Key:",IDC_STATIC,20,199,15,8 + LTEXT "Value:",IDC_STATIC,20,181,21,8 + EDITTEXT IDC_VALUE,50,180,125,12,ES_AUTOHSCROLL + LISTBOX IDC_KEYS,50,195,70,50,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add Key",IDC_ADD,125,200,50,14 + EDITTEXT IDC_NEW_KEY,125,215,50,14,ES_AUTOHSCROLL +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "gp_stats MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "gp_stats\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "gp_stats.EXE\0" + VALUE "ProductName", "gp_stats Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_GP_STATS_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 190 + TOPMARGIN, 7 + BOTTOMMARGIN, 259 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\gp_stats.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.vcproj b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.vcproj new file mode 100644 index 00000000000..5459a97471e --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.vcproj @@ -0,0 +1,1173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.vcproj.vspscc b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_statsDlg.cpp b/xrGameSpy/gamespy/gstats/gp_stats/gp_statsDlg.cpp new file mode 100644 index 00000000000..6abd7325f41 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_statsDlg.cpp @@ -0,0 +1,733 @@ +// gp_statsDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "gp_stats.h" +#include "gp_statsDlg.h" +#include "../gpersist.h" +#include "../../ghttp/ghttp.h" +#include "../../common/gsAvailable.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +// These are controls that are enabled when authenticated, +// and disabled when not authenticated. +////////////////////////////////////////////////////////// +CWnd * ToggleControls[64]; + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsDlg dialog + +CGp_statsDlg::CGp_statsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGp_statsDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CGp_statsDlg) + m_email = _T("dan@gamespy.com"); + m_nick = _T("mrpants"); + m_password = _T("mrpants"); + m_profileID = 0; + m_type = 0; + m_value = _T(""); + m_newKey = _T(""); + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CGp_statsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGp_statsDlg) + DDX_Control(pDX, IDC_KEYS, m_keys); + DDX_Text(pDX, IDC_EMAIL, m_email); + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_PASSWORD, m_password); + DDX_Text(pDX, IDC_PROFILE_ID, m_profileID); + DDX_Radio(pDX, IDC_PRIVATE_RW, m_type); + DDX_Text(pDX, IDC_VALUE, m_value); + DDX_Text(pDX, IDC_NEW_KEY, m_newKey); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CGp_statsDlg, CDialog) + //{{AFX_MSG_MAP(CGp_statsDlg) + ON_BN_CLICKED(IDC_AUTHENTICATE, OnAuthenticate) + ON_WM_DESTROY() + ON_BN_CLICKED(IDC_GET, OnGet) + ON_BN_CLICKED(IDC_SET, OnSet) + ON_BN_CLICKED(IDC_ADD, OnAdd) + ON_LBN_SELCHANGE(IDC_KEYS, OnSelchangeKeys) + ON_EN_CHANGE(IDC_VALUE, OnChangeValue) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsDlg message handlers + +BOOL CGp_statsDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // Build the list of toggle controls. + ///////////////////////////////////// + int num = 0; +#define ADD_TOGGLE(id) ToggleControls[num++] = this->GetDlgItem(id) + ADD_TOGGLE(IDC_PRIVATE_RW); + ADD_TOGGLE(IDC_PRIVATE_RO); + ADD_TOGGLE(IDC_PUBLIC_RW); + ADD_TOGGLE(IDC_PUBLIC_RO); + ADD_TOGGLE(IDC_GET); + ADD_TOGGLE(IDC_SET); + ADD_TOGGLE(IDC_VALUE); + ADD_TOGGLE(IDC_KEYS); + ADD_TOGGLE(IDC_ADD); + ADD_TOGGLE(IDC_NEW_KEY); + ToggleControls[num++] = NULL; + + // Init data. + ///////////// + m_authenticated = FALSE; + m_gp = NULL; + + // Put ourselves in the unauthenticated stats. + ////////////////////////////////////////////// + UnAuthenticate(); + + // Init the connection to the stats manager. + //////////////////////////////////////////// + CheckStatsConnection(); + + // Init GP. + /////////// + if(gpInitialize(&m_gp, 0, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR) + MessageBox("FAILED TO INITIALIZE GP!!!"); + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CGp_statsDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + ClearKeys(); + + // Close the stats connection. + ////////////////////////////// + CloseStatsConnection(); + + // Shutdown GP. + /////////////// + gpDestroy(&m_gp); + + // Shutdown GHTTP. + ////////////////// + ghttpCleanup(); +} + +void CGp_statsDlg::Authenticated() +{ + m_authenticated = TRUE; + + // Enable controls. + /////////////////// + int i; + for(i = 0 ; ToggleControls[i] ; i++) + ToggleControls[i]->EnableWindow(); +} + +void CGp_statsDlg::UnAuthenticate() +{ + m_authenticated = FALSE; + m_profileID = 0; + + // Disable controls. + //////////////////// + int i; + for(i = 0 ; ToggleControls[i] ; i++) + ToggleControls[i]->EnableWindow(FALSE); +} + +BOOL CGp_statsDlg::CheckStatsConnection() +{ + // Are we connected? + //////////////////// + if(IsStatsConnected()) + return TRUE; + + // Set the gamename and secret key. + /////////////////////////////////// +#if 1 + strcpy(gcd_gamename, "gmtest"); + gcd_secret_key[0] = 'H'; + gcd_secret_key[1] = 'A'; + gcd_secret_key[2] = '6'; + gcd_secret_key[3] = 'z'; + gcd_secret_key[4] = 'k'; + gcd_secret_key[5] = 'S'; + gcd_secret_key[7] = '\0'; +#else + strcpy(gcd_gamename, "excessive"); + gcd_secret_key[0] = 'G'; + gcd_secret_key[1] = 'n'; + gcd_secret_key[2] = '3'; + gcd_secret_key[3] = 'a'; + gcd_secret_key[4] = 'Y'; + gcd_secret_key[5] = '9'; + gcd_secret_key[7] = '\0'; +#endif + + // check that the game's backend is available + GSIACResult ac_result; + GSIStartAvailableCheck(gcd_gamename); + while((ac_result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(ac_result != GSIACAvailable) + { + MessageBox("The backend is not available\n"); + return TRUE; + } + + // Try to connect. + ////////////////// + int result = InitStatsConnection(0); + if(result == GE_NOERROR) + return TRUE; + + // Error! + ///////// + CString message; + if(result == GE_NOSOCKET) + message = "Unable to create a socket."; + else if(result == GE_NODNS) + message = "Unable to resolve a DNS name."; + else if(result == GE_NOCONNECT) + message = "Unable to connect to stats server, or connection lost."; + else if(result == GE_DATAERROR) + message = "Bad data from the stats server."; + else + message = "Error."; + MessageBox(message, "Error connecting to the stats server"); + + return FALSE; +} + +void CGp_statsDlg::SendPassword() +{ + // Form the URL for the request. + //////////////////////////////// + CString URL = "http://gamespyarcade.com/software/reqemail.asp?email="; + URL += m_email; + + // Set the wait cursor. + /////////////////////// + HCURSOR hPrevCursor = GetCursor(); + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + // Do the request. + ////////////////// + ghttpGetFile(URL, GHTTPTrue, NULL, NULL); + + // Reset the previous cursor. + ///////////////////////////// + SetCursor(hPrevCursor); +} + +void CreateAccountCallback(GPConnection * connection, void * arg_, void * param) +{ + GPNewUserResponseArg * arg = (GPNewUserResponseArg *)arg_; + int * pid = (int *)param; + + // Store the result. + //////////////////// + if(arg->result == GP_NO_ERROR) + *pid = arg->profile; + else + { + // If the nick was already in use, just pretend we created it. + ////////////////////////////////////////////////////////////// + GPErrorCode errorCode; + gpGetErrorCode(connection, &errorCode); + if(errorCode == GP_NEWUSER_BAD_NICK) + *pid = arg->profile; + else + *pid = 0; + } +} + +BOOL CGp_statsDlg::CreateAccount() +{ + int pid; + int rcode; + + // Create the account. + ////////////////////// + GPResult result = gpNewUser( + &m_gp, + m_nick, + NULL, + m_email, + m_password, + NULL, + GP_BLOCKING, + CreateAccountCallback, + &pid); + if(result != GP_NO_ERROR) + { + MessageBox("There was an error creating the account."); + return FALSE; + } + + // Check for success. + ///////////////////// + if(pid) + { + m_profileID = pid; + return TRUE; + } + + // Get the error code. + ////////////////////// + GPErrorCode errorCode; + gpGetErrorCode(&m_gp, &errorCode); + + // Handle the error code. + ///////////////////////// + if(errorCode == GP_NEWUSER_BAD_PASSWORD) + { + rcode = MessageBox( + "You have entered an incorrect password for this e-mail address\n" + "Would you like the password sent to the e-mail address?", + NULL, + MB_YESNO); + + // If no, we're done. + ///////////////////// + if(rcode == IDNO) + return FALSE; + + // Send the password. + ///////////////////// + SendPassword(); + + return FALSE; + } + + // An unknown error code. + ///////////////////////// + MessageBox("There was an error creating the account."); + return FALSE; +} + +void CheckAccountCallback(GPConnection * connection, void * arg_, void * param) +{ + GPCheckResponseArg * arg = (GPCheckResponseArg *)arg_; + int * pid = (int *)param; + + // Store the result. + //////////////////// + if(arg->result == GP_NO_ERROR) + *pid = arg->profile; + else + *pid = 0; +} + +BOOL CGp_statsDlg::CheckAccount() +{ + int pid; + int rcode; + + // Check for the account. + ///////////////////////// + GPResult result = gpCheckUser( + &m_gp, + m_nick, + m_email, + m_password, + GP_BLOCKING, + CheckAccountCallback, + &pid); + if(result != GP_NO_ERROR) + { + MessageBox("There was an error authenticating the account."); + return FALSE; + } + + // Check for success. + ///////////////////// + if(pid) + { + m_profileID = pid; + return TRUE; + } + + // Get the error code. + ////////////////////// + GPErrorCode errorCode; + gpGetErrorCode(&m_gp, &errorCode); + + // Handle the error code. + ///////////////////////// + if(errorCode == GP_CHECK_BAD_EMAIL) + { + // Ask if they want to create the account. + ////////////////////////////////////////// + rcode = MessageBox( + "This account does not exist.\n" + "Would you like to create it?", + NULL, + MB_YESNO); + + // If no, we're done. + ///////////////////// + if(rcode == IDNO) + return FALSE; + + // Create the account. + ////////////////////// + return CreateAccount(); + } + else if(errorCode == GP_CHECK_BAD_NICK) + { + rcode = MessageBox( + "There are no profiles under this account with the nick you have entered\n" + "Would you like to create one?", + NULL, + MB_YESNO); + + // If no, we're done. + ///////////////////// + if(rcode == IDNO) + return FALSE; + + // Create the account. + ////////////////////// + return CreateAccount(); + } + else if(errorCode == GP_CHECK_BAD_PASSWORD) + { + rcode = MessageBox( + "You have entered an incorrect password for this e-mail address\n" + "Would you like the password sent to the e-mail address?", + NULL, + MB_YESNO); + + // If no, we're done. + ///////////////////// + if(rcode == IDNO) + return FALSE; + + // Send the password. + ///////////////////// + SendPassword(); + + return FALSE; + } + + // An unknown error code. + ///////////////////////// + MessageBox("There was an error authenticating the account."); + return FALSE; +} + +BOOL statsAuthFinished; +void StatsAuthenticationCallback(int localid, int profileid, int authenticated, char *errmsg, void *instance) +{ + int * result = (int *)instance; + + *result = authenticated; + + if(authenticated != 1) + MessageBox(NULL, errmsg, "Error authenticating with the stats backend", MB_OK); + + statsAuthFinished = TRUE; +} + +BOOL CGp_statsDlg::StatsAuthentication() +{ + char response[33]; + int result; + + // The auth call. + ///////////////// + statsAuthFinished = FALSE; + PreAuthenticatePlayerPM( + 0, + m_profileID, + GenerateAuth(GetChallenge(NULL), (char *)(LPCSTR)m_password, response), + StatsAuthenticationCallback, + &result); + + // Wait for it to finish. + ///////////////////////// + while(!statsAuthFinished) + if(!PersistThink()) + CheckStatsConnection(); + + return (result == 1); +} + +void CGp_statsDlg::OnAuthenticate() +{ + // Update dialog members. + ///////////////////////// + UpdateData(); + + // Sanity check args. + ///////////////////// + if(!m_email.GetLength() || !m_nick.GetLength() || !m_password.GetLength()) + { + MessageBox("E-mail, nick, and password must not be blank."); + return; + } + + // If we're authenticated, unauthenticate. + ////////////////////////////////////////// + if(m_authenticated) + UnAuthenticate(); + + // Check the account. + ///////////////////// + if(!CheckAccount()) + return; + + // Do stats authentication. + /////////////////////////// + if(!StatsAuthentication()) + return; + + // We're authenticated. + /////////////////////// + Authenticated(); + + // Update dialog display. + ///////////////////////// + UpdateData(FALSE); +} + +persisttype_t TypeConversion(int type) +{ + if(type == 0) + return pd_private_rw; + if(type == 1) + return pd_private_ro; + if(type == 2) + return pd_public_rw; + return pd_public_ro; +} + +BOOL GetKeyValue(LPCSTR src, CString & key, CString & value) +{ + const char * str; + const char * keyStart; + const char * valueStart; + int keyLen; + int valueLen; + + // Check for no input. + ////////////////////// + if(!src) + return FALSE; + + // Check the starting \. + //////////////////////// + if(src[0] != '\\') + return FALSE; + + // Clear the key and value. + /////////////////////////// + key.Empty(); + value.Empty(); + + // Find the key and value, plus lengths. + //////////////////////////////////////// + keyStart = (src + 1); + valueStart = strchr(keyStart, '\\'); + if(!valueStart || (valueStart == keyStart)) + return FALSE; + keyLen = (valueStart - keyStart); + valueStart++; + str = strchr(valueStart, '\\'); + if(str) + valueLen = (str - valueStart); + else + valueLen = strlen(valueStart); + + // Copy off the key. + //////////////////// + char * keyStr = key.GetBuffer(keyLen); + memcpy(keyStr, keyStart, keyLen); + key.ReleaseBuffer(keyLen); + + // Copy off the value. + //////////////////// + char * valueStr = value.GetBuffer(valueLen); + memcpy(valueStr, valueStart, valueLen); + value.ReleaseBuffer(valueLen); + + return TRUE; +} + +void CGp_statsDlg::ClearKeys() +{ + int count = m_keys.GetCount(); + int i; + for(i = 0 ; i < count ; i++) + delete (CString *)m_keys.GetItemDataPtr(i); + m_keys.ResetContent(); +} + +void CGp_statsDlg::GotData(LPCSTR data) +{ + CString key; + CString value; + int nIndex; + + // Go through the keys/values. + ////////////////////////////// + while(GetKeyValue(data, key, value)) + { + // Adjust the data based on the key and value lengths. + ////////////////////////////////////////////////////// + data += (key.GetLength() + value.GetLength() + 2); + + // Add the new key/value. + ///////////////////////// + nIndex = m_keys.AddString(key); + if(nIndex != -1) + m_keys.SetItemDataPtr(nIndex, new CString(value)); + } +} + +BOOL getDataFinished; +void GetDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance) +{ + getDataFinished = TRUE; + + if(success) + { + CGp_statsDlg * dlg = (CGp_statsDlg *)instance; + dlg->GotData(data); + } +} + +void CGp_statsDlg::OnGet() +{ + // Update dialog members. + ///////////////////////// + UpdateData(); + + // Clear the keys and value. + //////////////////////////// + ClearKeys(); + m_value.Empty(); + + // Make sure we're connected to the stats server. + ///////////////////////////////////////////////// + if(!CheckStatsConnection()) + return; + + // Get the data. + //////////////// + getDataFinished = FALSE; + GetPersistDataValues(0, m_profileID, TypeConversion(m_type), 0, "", GetDataCallback, this); + while(!getDataFinished) + if(!PersistThink()) + CheckStatsConnection(); + + // Update dialog display. + ///////////////////////// + UpdateData(FALSE); +} + +BOOL setDataFinished; +void SetDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, void *instance) +{ + setDataFinished = TRUE; +} + +void CGp_statsDlg::OnSet() +{ + // Update dialog members. + ///////////////////////// + UpdateData(); + + // Make sure we're connected to the stats server. + ///////////////////////////////////////////////// + if(!CheckStatsConnection()) + return; + + // Build the data string. + ///////////////////////// + int count = m_keys.GetCount(); + int i; + CString data; + CString key; + CString * value; + for(i = 0 ; i < count ; i++) + { + m_keys.GetText(i, key); + value = (CString *)m_keys.GetItemDataPtr(i); + + data += '\\'; + data += key; + data += '\\'; + data += *value; + } + + // Set some data. + ///////////////// + setDataFinished = FALSE; + SetPersistDataValues(0, m_profileID, TypeConversion(m_type), 0, (char *)(LPCSTR)data, SetDataCallback, this); + while(!setDataFinished) + if(!PersistThink()) + CheckStatsConnection(); +} + +void CGp_statsDlg::OnSelchangeKeys() +{ + UpdateData(); + + // Get the new key/value. + ///////////////////////// + int nIndex = m_keys.GetCurSel(); + if(nIndex != -1) + m_value = *(CString *)m_keys.GetItemDataPtr(nIndex); + + UpdateData(FALSE); +} + +void CGp_statsDlg::OnAdd() +{ + UpdateData(); + + if(m_newKey.IsEmpty()) + return; + + int nIndex = m_keys.AddString(m_newKey); + if(nIndex != -1) + m_keys.SetItemDataPtr(nIndex, new CString); + + m_newKey.Empty(); + + UpdateData(FALSE); +} + +void CGp_statsDlg::OnChangeValue() +{ + UpdateData(); + int nIndex = m_keys.GetCurSel(); + if(nIndex != -1) + { + CString * string = (CString *)m_keys.GetItemDataPtr(nIndex); + *string = m_value; + } +} diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_statsDlg.h b/xrGameSpy/gamespy/gstats/gp_stats/gp_statsDlg.h new file mode 100644 index 00000000000..b5646418048 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_statsDlg.h @@ -0,0 +1,77 @@ +// gp_statsDlg.h : header file +// + +#if !defined(AFX_GP_STATSDLG_H__B7B25B2A_61E9_4BFE_BBD7_D7C4D7242B7D__INCLUDED_) +#define AFX_GP_STATSDLG_H__B7B25B2A_61E9_4BFE_BBD7_D7C4D7242B7D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "../../gp/gp.h" + +///////////////////////////////////////////////////////////////////////////// +// CGp_statsDlg dialog + +class CGp_statsDlg : public CDialog +{ +// Construction +public: + CGp_statsDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CGp_statsDlg) + enum { IDD = IDD_GP_STATS_DIALOG }; + CListBox m_keys; + CString m_email; + CString m_nick; + CString m_password; + int m_profileID; + int m_type; + CString m_value; + CString m_newKey; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGp_statsDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +public: + void GotData(LPCSTR data); + +// Implementation +protected: + HICON m_hIcon; + + BOOL m_authenticated; + GPConnection m_gp; + + void Authenticated(); + void UnAuthenticate(); + BOOL CheckStatsConnection(); + BOOL CheckAccount(); + BOOL CreateAccount(); + void SendPassword(); + BOOL StatsAuthentication(); + void ClearKeys(); + + // Generated message map functions + //{{AFX_MSG(CGp_statsDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnAuthenticate(); + afx_msg void OnDestroy(); + afx_msg void OnGet(); + afx_msg void OnSet(); + afx_msg void OnAdd(); + afx_msg void OnSelchangeKeys(); + afx_msg void OnChangeValue(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GP_STATSDLG_H__B7B25B2A_61E9_4BFE_BBD7_D7C4D7242B7D__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats_vs2005.vcproj b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats_vs2005.vcproj new file mode 100644 index 00000000000..8660320219d --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats_vs2005.vcproj @@ -0,0 +1,1622 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/gp_stats/gp_stats_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/gp_stats_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/gp_stats/res/gp_stats.ico b/xrGameSpy/gamespy/gstats/gp_stats/res/gp_stats.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/gp_stats/res/gp_stats.ico differ diff --git a/xrGameSpy/gamespy/gstats/gp_stats/res/gp_stats.rc2 b/xrGameSpy/gamespy/gstats/gp_stats/res/gp_stats.rc2 new file mode 100644 index 00000000000..0cd2a66d926 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/res/gp_stats.rc2 @@ -0,0 +1,13 @@ +// +// GP_STATS.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/gstats/gp_stats/resource.h b/xrGameSpy/gamespy/gstats/gp_stats/resource.h new file mode 100644 index 00000000000..85b0316f271 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gp_stats/resource.h @@ -0,0 +1,33 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gp_stats.rc +// +#define IDD_GP_STATS_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_EMAIL 1000 +#define IDC_NICK 1001 +#define IDC_PASSWORD 1002 +#define IDC_PROFILE_ID 1003 +#define IDC_AUTHENTICATE 1004 +#define IDC_PRIVATE_RW 1005 +#define IDC_PRIVATE_RO 1006 +#define IDC_PUBLIC_RW 1007 +#define IDC_PUBLIC_RO 1008 +#define IDC_GET 1009 +#define IDC_SET 1010 +#define IDC_VALUE 1012 +#define IDC_KEYS 1014 +#define IDC_ADD 1015 +#define IDC_NEW_KEY 1016 +#define IDC_EDIT1 1016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1017 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/gstats/gpersist.h b/xrGameSpy/gamespy/gstats/gpersist.h new file mode 100644 index 00000000000..cb3b28ed9bb --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gpersist.h @@ -0,0 +1,415 @@ +/****** +gpersist.h +GameSpy Persistent Storage SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +****** + +Please see the GameSpy Persistent Storage SDK for more info + +*****/ +//todo: get/set @ offset / length + +#ifndef _GPERSIST_H_ +#define _GPERSIST_H_ + +#include "gstats.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/************************* +The following defines and prototypes are included +inside the "gstats.h" file, but listed here as well for easy reference +since they are also used by the Persistent Storage SDK. +The comments for them have also been changed to reflect their +specific use inside the Persistent Storage SDK. +**************************/ +#if 0 + /* Error codes */ + #define GE_NOERROR 0 + #define GE_NOSOCKET 1 /* Unable to create a socket */ + #define GE_NODNS 2 /* Unable to resolve a DNS name */ + #define GE_NOCONNECT 3 /* Unable to connect to stats server, or connection lost */ + #define GE_BUSY 4 /* Not used */ + #define GE_DATAERROR 5 /* Bad data from the stats server */ + + /* You need to fill these in with your game-specific info */ + extern char gcd_secret_key[256]; + extern char gcd_gamename[256]; + + /******** + InitStatsConnection + + DESCRIPTION + Opens a connection to the stats / persistent storage server. Should be done before calling + any of the other persistent storage functions. May block for 1-2 secs + while the connection is established so you will want to do this before + gameplay starts or in another thread. + + PARAMETERS + gameport: integer port associated with your server (may be the same as + your developer spec query port). If not appropriate for your game, pass in 0. + + RETURNS + GE_NODNS: Unable to resolve stats server DNS + GE_NOSOCKET: Unable to create data socket + GE_NOCONNECT: Unable to connect to stats server + GE_DATAERROR: Unable to receive challenge from stats server, or bad challenge + GE_NOERROR: Connected to stats server and ready to send data + + Note: If the connection fails, all Persistent Storage functions will fail. + *********/ + int InitStatsConnection(int gameport); + + /******** + IsStatsConnected + + DESCRIPTION + Returns whether or not you are currently connected to the stats server. Even + if your initial connection was successful, you may lose connection later and + want to try to reconnnect. + If a callback returns unsuccessfully, check this function to see if it was + because of a disconnection. + + RETURNS + 1 if connected, 0 otherwise + *********/ + int IsStatsConnected(); + + /******** + CloseStatsConnection + + DESCRIPTION + Closes the connection to the stats server. You should do this when done + with the connection. + *********/ + void CloseStatsConnection(void); + + /******** + GetChallenge + + DESCRIPTION + Returns the string to pass as the challenge to the GenerateAuth function. + + PARAMETERS + game: Pass in NULL (or your current game, if you are also using the Stats SDK) + + RETURNS + A string to pass to GenerateAuth to create the authentication hash + *********/ + char *GetChallenge(statsgame_t game); + + /******** + GenerateAuth + + DESCRIPTION + Used to generate on the "challengeresponse" parameter for the PreAuthenticatePlayer + functions. + + PARAMETERS + challenge: The challenge string generated by GetChallange. + password: The CD Key (un-hashed) or profile password + response: The output authentication string + + RETURNS + A pointer to response + *********/ + char *GenerateAuth(char *challenge, gsi_char *password,/*[out]*/char response[33]); +#endif //#ifdef 0 section from gstats.h + +/************************* +The rest of the prototypes in this file are specific to +the Persistent Storage SDK +**************************/ + +#ifndef GSI_UNICODE +#define GenerateAuth GenerateAuthA +#define PreAuthenticatePlayerCD PreAuthenticatePlayerCDA +#define GetProfileIDFromCD GetProfileIDFromCDA +#define GetPersistDataValues GetPersistDataValuesA +#define GetPersistDataValuesModified GetPersistDataValuesModifiedA +#define SetPersistDataValues SetPersistDataValuesA +#else +#define GenerateAuth GenerateAuthW +#define PreAuthenticatePlayerCD PreAuthenticatePlayerCDW +#define GetProfileIDFromCD GetProfileIDFromCDW +#define GetPersistDataValues GetPersistDataValuesW +#define GetPersistDataValuesModified GetPersistDataValuesModifiedW +#define SetPersistDataValues SetPersistDataValuesW +#endif + +/******** +persisttype_t +There are 4 types of persistent data stored for each player: +pd_private_ro: Readable only by the authenticated client it belongs to, can only by set on the server +pd_private_rw: Readable only by the authenticated client it belongs to, set by the authenticated client it belongs to +pd_public_ro: Readable by any client, can only be set on the server +pd_public_rw: Readable by any client, set by the authenicated client is belongs to +*********/ +typedef enum {pd_private_ro, pd_private_rw, pd_public_ro, pd_public_rw} persisttype_t; + +/***************** +CALLBACK FUNCTIONS +*****************/ + +/**************** +PersAuthCallbackFn + +DESCRIPTION +This type of function is passed to the two PreAuthentication functions. +It returns the result of the Authentication request. + +PARAMETERS +localid: The localid number passed into the PreAuthenticate function +profileid: If authentication was successful, the profileid for this user +authenticated: 1 if the player was authenticated < 1 otherwise +errmsg: Error returned by the server to indicate why the player was not authenticated +instance: Opaque value passed into the PreAuthenticate function (for your use) +*****************/ +typedef void (*PersAuthCallbackFn)(int localid, int profileid, int authenticated, gsi_char *errmsg, void *instance); + + +/**************** +PersDataCallbackFn + +DESCRIPTION +This type of function is passed to the two GetPersistData functions. +It returns the result of the data request. +localid + +PARAMETERS +localid: The localid number passed into the GetPersistData function +profileid: The profileid of the user who the data was requested for +type: The type of persistent data being returned +index: The persistent data index +success: 1 if the data was retrieved successfully + 2 if the data had not been modified since the time requested + < 1 if there was an error +modified: The last time the data for this index was modified (any persist type) + Only returned if success is 1 +data: Pointer to the data being returned. Note: you must use or copy + off the data before returning from the callback, as it may be freed or overwritten + once the callback is complete. +len: Length of the data being returned. 0 indicates that no data was stored on the server + (if success was 1) +instance: Opaque value passed into the GetPersistData function (for your use) +*****************/ +typedef void (*PersDataCallbackFn)(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance); + +/**************** +PersDataSaveCallbackFn + +DESCRIPTION +This type of function is passed to the two SetPersistData functions. +It returns the result of the set data request. + +PARAMETERS +localid: The localid number passed into the SetPersistData function +profileid: The profileid of the user who the data is being saved for +success: 1 if the data was saved successfully, < 1 otherwise +modified: The time recorded on the backend for last modification +instance: Opaque value passed into the SetPersistData function (for your use) +*****************/ +typedef void (*PersDataSaveCallbackFn)(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, void *instance); + +/**************** +ProfileCallbackFn + +DESCRIPTION +This type of function is passed to the GetProfileIDFromCD function. +It returns the result of the lookup request. + +PARAMETERS +localid: The localid number passed into the GetProfileIDFromCD function +profileid: The profileid of the requested user, if the lookup was successful +success: 1 if the lookup was successful, < 1 otherwise +instance: Opaque value passed into the GetProfileIDFromCD function (for your use) +*****************/ +typedef void (*ProfileCallbackFn)(int localid, int profileid, int success, void *instance); + + +/*************************** +PERSISTENT STORAGE FUNCTIONS +****************************/ + +/**************** +PreAuthenticatePlayerPM +PreAuthenticatePlayerCD + +DESCRIPTION +These two functions are used to authenticate a player on the Stats server. +A player MUST be authenticated before getting private persistent data, or +setting public or private data. +If the StatsServer connection is ever lost and reconnected (using InitStatsConnection) +the player must be reauthenticated before reading / writing their data. +PreAuthenticatePlayerPM authenticates players using the Presence & Messaging SDK account info +PreAuthenticatePlayerCD authenticates players using the CDKey SDK CD Key. +Typically you will only use one of these in your game (depending on whether you use +the Presence & Messaging SDK, or the CD Key SDK), however they can both be used in the +same game if needed. + +PARAMETERS +localid: Your game-specific reference number for this player, returned in the callback + to allow you to identify which player it is referring to. +profileid: (PreAuthenticatePlayerPM) The profileid of the player being authenicated. This can be obtained in the + Presence & Messaging SDK through gpIDFromProfile() +nick: (PreAuthenticatePlayerCD) Nickname of the player to authenticate. Note that the nickname is not actually + authenticated, it is simply used to determine which profile under the authenticated CD Key to use. + Each CD Key can have mutiple profiles, each using a different nick. +keyhash: (PreAuthenticatePlayerCD) Hash of the player's CD Key. If used on the server, this can be obtained from gcd_getkeyhash + On the client, you can easily get the hash by calling GenerateAuth() with challenge as an empty string ("") + and the CD Key has the password parameter. +challengeresponse: Result of the GenerateAuth() call, after passing in the challenge and the client's + password or CD Key +PersAuthCallbackFn: Callback to be called after the authentication is complete +instance: Pointer that will be passed to the callback function (for your use) + Typically used for passing an object or structure pointer into the callback. +*****************/ +void PreAuthenticatePlayerPartner(int localid, const char* authtoken, const char *challengeresponse, PersAuthCallbackFn callback, void *instance); +void PreAuthenticatePlayerPM(int localid, int profileid, const char *challengeresponse, PersAuthCallbackFn callback, void *instance); +void PreAuthenticatePlayerCD(int localid, const gsi_char *nick, const char *keyhash, const char *challengeresponse, PersAuthCallbackFn callback, void *instance); + +/**************** +GetProfileIDFromCD + +DESCRIPTION +Given a nickname and CD Key hash, this will lookup the profileid for the user. +If the user has never authenticated (and has no persistent data associated with them), +the callback will indicate a failure. No persistent data can be retreived for the user, +since they don't have any stored. Persistent data can be stored, but only after authenticating +with PreAuthenticatePlayerCD. + +PARAMETERS +localid: Your game-specific reference number for this player, returned in the callback + to allow you to identify which player it is referring to. +nick: The nick of the user whose profileid you are looking up +keyhash: The CD Key Hash of the user whose profileid you are looking up +ProfileCallbackFn: Callback to be called when the lookup is completed +instance: Pointer that will be passed to the callback function (for your use) +*****************/ +void GetProfileIDFromCD(int localid, const gsi_char *nick, const char *keyhash, ProfileCallbackFn callback, void *instance); + +/**************** +GetPersistData[Modified] + +DESCRIPTION +Gets the entire block of persistent data for a user. +The data and length are returned in the callback function. +Note that only an authenticated player can get their private data. Any +player can get any other player's public data. + +PARAMETERS +localid: Your game-specific reference number for this player, returned in the callback + to allow you to identify which player it is referring to. +profileid: The profileid of the player whose data you are looking up. + Returned by gpIDFromProfile() in the Presence & Messaging SDK, or using GetProfileIDFromCD +type: The type of persistent data you are looking up +index: Each profile can have multiple persistent data records associated with them. Usually you + just want to use index 0. +modifiedsince: A time value to limit the request for data. Data will only be returned if it has been + modified since the time provided. If data has not been modified since that time, the callback will be + called with a success value that indicates it is unmodified. + Note: modification time is tracked for the given profileid/index, not on a per persisttype basis +PersDataCallbackFn: Callback that will be called with the data when it is returned +ProfileCallbackFn: Callback to be called when the lookup is completed +instance: Pointer that will be passed to the callback function (for your use) +*****************/ +void GetPersistData(int localid, int profileid, persisttype_t type, int index, PersDataCallbackFn callback, void *instance); +void GetPersistDataModified(int localid, int profileid, persisttype_t type, int index, time_t modifiedsince, PersDataCallbackFn callback, void *instance); + +/**************** +GetPersistDataValues[Modified] + +DESCRIPTION +If you store your data in key\value delimited pairs, GetPersistDataValues will +allow you to easily retrieve a subset of the stored data. To retrieve the entire +data set, use GetPersistData. The data will be returned as a null-terminated string, +unless no data is available (in which case len will be 0 in the callback). + +PARAMETERS +localid: Your game-specific reference number for this player, returned in the callback + to allow you to identify which player it is referring to. +profileid: The profileid of the player whose data you are looking up. + Returned by gpIDFromProfile() in the Presence & Messaging SDK, or using GetProfileIDFromCD +type: The type of persistent data you are looking up +index: Each profile can have multiple persistent data records associated with them. Usually you + just want to use index 0. +modifiedsince: A time value to limit the request for data. Data will only be returned if it has been + modified since the time provided. If data has not been modified since that time, the callback will be + called with a success value that indicates it is unmodified. + Note: modification time is tracked for the given profileid/index, not on a per-persisttype or per-key basis +keys: A "\" delimited list of the keys you want returned (for example: "\clan\color\homepage\birthday") +PersDataCallbackFn: Callback that will be called with the data when it is returned +instance: Pointer that will be passed to the callback function (for your use) +*****************/ +void GetPersistDataValues(int localid, int profileid, persisttype_t type, int index, gsi_char *keys, PersDataCallbackFn callback, void *instance); +void GetPersistDataValuesModified(int localid, int profileid, persisttype_t type, int index, time_t modifiedsince, gsi_char *keys, PersDataCallbackFn callback, void *instance); + +/**************** +SetPersistData + +DESCRIPTION +Sets the entire block of persistent data for a user. +The profileid for whom the data is being set MUST have been authenticated already. + +PARAMETERS +localid: Your game-specific reference number for this player, returned in the callback + to allow you to identify which player it is referring to. +profileid: The profileid of the player whose data you are setting. + The player must have already been authenticated with one of the PreAuthenticatePlayer functions. +type: The type of persistent data you are setting. Only rw data is setable. +index: Each profile can have multiple persistent data records associated with them. Usually you + just want to use index 0. +data: The persistent data to be saved +len: The length of the data. If you are setting key\value delimited data, make + sure the "len" parameter includes length of the null terminator +PersDataSaveCallbackFn: Callback that will be called with the data save is complete +instance: Pointer that will be passed to the callback function (for your use) +*****************/ +void SetPersistData(int localid, int profileid, persisttype_t type, int index, const char *data, int len, PersDataSaveCallbackFn callback, void *instance); + +/**************** +SetPersistDataValues + +DESCRIPTION +If you are saving data in key\value delimited format, you can use this function +to only set SOME of the key\value pairs. Only the key value pairs you include in +they keyvalues parameter will be updated, the other pairs will stay the same. + +PARAMETERS +localid: Your game-specific reference number for this player, returned in the callback + to allow you to identify which player it is referring to. +profileid: The profileid of the player whose data you are setting. + The player must have already been authenticated with one of the PreAuthenticatePlayer functions. +type: The type of persistent data you are setting. Only rw data is setable. +index: Each profile can have multiple persistent data records associated with them. Usually you + just want to use index 0. +keyvalues: The key\value pairs to be updated (for example: \clan\The A-Team\homepage\http://www.myclan.net\age\15) +PersDataSaveCallbackFn: Callback that will be called with the data save is complete +instance: Pointer that will be passed to the callback function (for your use) +*****************/ +void SetPersistDataValues(int localid, int profileid, persisttype_t type, int index, const gsi_char *keyvalues, PersDataSaveCallbackFn callback, void *instance); + +/**************** +PersistThink + +DESCRIPTION +This function needs to be called any time a asynchronous operation is in progress. It will +check for the incoming replies and call the callbacks associated with them as needed. +It's recommened that you call this in your main loop at all times while you are connected +to the stats server, so that if the stats server disconnects it can be detected immediately. + +RETURNS +0 if the connection to the stats server is lost, 1 otherwise +*****************/ +int PersistThink(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/gstats/gstats.c b/xrGameSpy/gamespy/gstats/gstats.c new file mode 100644 index 00000000000..f5577250df4 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gstats.c @@ -0,0 +1,1687 @@ +/****** +gstats.c +GameSpy Stats/Tracking SDK +GameSpy Persistent Storage SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +****** + +Please see the GameSpy Stats and Tracking SDK documentation for more info + +******/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4267) //lines: 207 +#pragma warning(disable: 4244) //lines: 1536, 1537, 1538 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +/******** +INCLUDES +********/ +#include "gstats.h" +#include "gpersist.h" +#include "../common/gsAvailable.h" +#include "../darray.h" +#include "../md5.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/******** +TYPEDEFS +********/ +struct statsgame_s +{ + int connid; + int sesskey; + int usebuckets; + bucketset_t buckets; + char challenge[9]; + DArray playernums; //for player number translation + DArray teamnums; //for team number translation + int totalplayers, totalteams; + gsi_time sttime; + +}; + +typedef enum {rt_authcb, rt_datacb, rt_savecb, rt_profilecb} reqtype_t; +typedef struct +{ + reqtype_t reqtype; + int localid; + int profileid; + persisttype_t pdtype; + int pdindex; + void *instance; + void *callback; + +} serverreq_t; + + +/******** +PROTOTYPES +********/ +static int ServerOpInt(statsgame_t game,char *name, BucketFunc func, int value, int index); +static double ServerOpFloat(statsgame_t game,char *name, BucketFunc func, double value, int index); +static char *ServerOpString(statsgame_t game,char *name, BucketFunc func, char *value, int index); + +static int TeamOpInt(statsgame_t game,char *name, BucketFunc func, int value, int index); +static double TeamOpFloat(statsgame_t game,char *name, BucketFunc func, double value, int index); +static char *TeamOpString(statsgame_t game,char *name, BucketFunc func, char *value, int index); + +static int PlayerOpInt(statsgame_t game,char *name, BucketFunc func, int value, int index); +static double PlayerOpFloat(statsgame_t game,char *name, BucketFunc func, double value, int index); +static char *PlayerOpString(statsgame_t game,char *name, BucketFunc func, char *value, int index); + +static char *CreateBucketSnapShot(bucketset_t buckets); + +#ifdef ALLOW_DISK +static void CheckDiskFile(); +static void DiskWrite(char *line, int len); +#endif +static void InternalInit(); +static int SendChallengeResponse(const char *indata, int gameport); +static int RecvSessionKey(); +static int DoSend(char *data, int len); +static void xcode_buf(char *buf, int len); +static int g_crc32(char *s, int len); +static void create_challenge(int challenge, char chstr[9]); +static char *value_for_key(const char *s, const char *key); +static char *value_for_key_safe(const char *s, const char *key); +static int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent); +/************** +PERSISTENT STORAGE PROTOTYPES +**************/ +static void AddRequestCallback(reqtype_t reqtype, int localid, int profileid, persisttype_t pdtype, int pdindex, void *callback, void *instance); +static void SendPlayerAuthRequest(char *data, int len, int localid, PersAuthCallbackFn callback, void *instance); +static void SendPlayerAuthRequest(char *data, int len, int localid, PersAuthCallbackFn callback, void *instance); +static int SocketReadable(SOCKET s); +static char *FindFinal(char *buff, int len); +static int FindRequest(reqtype_t reqtype, int localid, int profileid); +static void ProcessPlayerAuth(const char *buf, int len); +static void ProcessGetPid(const char *buf, int len); +static void ProcessGetData(const char *buf, int len); +static void ProcessSetData(const char *buf, int len); +static void ProcessStatement(char *buff, int len); +static int ProcessInBuffer(char *buff, int len); +static void CallReqCallback(int reqindex, int success, time_t modified, char *data, int length); +static void ClosePendingCallbacks(); +static void SetPersistDataHelper(int localid, int profileid, persisttype_t type, int index, const char *data, int len, PersDataSaveCallbackFn callback, void *instance, int kvset); +void GetPersistDataValuesA(int localid, int profileid, persisttype_t type, int index, char *keys, PersDataCallbackFn callback, void *instance); +void GetPersistDataValuesModifiedA(int localid, int profileid, persisttype_t type, int index, time_t modifiedsince, char *keys, PersDataCallbackFn callback, void *instance); + +/******** +DEFINES +********/ +//#define SSHOST "207.199.80.230" +#define SSHOST "gamestats." GSI_DOMAIN_NAME +#define SSPORT 29920 + +#define FIXGAME(g,r) if (g == NULL) g = g_statsgame; if (g == NULL) return r; +#define DoFunc(f,g, n, v, t, r) \ + if (g == NULL) g = g_statsgame; \ + if (!g) r = v; \ + else { \ + r = f(g->buckets, n, v); \ + if (!r) \ + r = BucketNew(g->buckets, n, t, v); } +#define DOXCODE(b, l, e) enc = e; xcode_buf(b,l); + + +/******** +VARS +********/ +char gcd_gamename[256] = ""; +char gcd_secret_key[256] = ""; +static statsgame_t g_statsgame = NULL; +static int connid = 0; +static int sesskey = 0; +static SOCKET sock = INVALID_SOCKET; +/* #define enc1 "GameSpy 3D" + #define enc2 "Industries" + #define enc3 "ProjectAphex" + #define STATSFILE "gstats.dat" */ +/* A couple vars to help avoid the string table */ +static char enc1[16] = {'\0','a','m','e','S','p','y','3','D','\0'}; +static char enc3[16] = {'\0','r','o','j','e','c','t','A','p','h','e','x','\0'}; + +#ifdef ALLOW_DISK +static char statsfile[16] = {'\0','s','t','a','t','s','.','d','a','t','\0'}; +static char enc2[16]= {'\0','n','d','u','s','t','r','i','e','s','\0'}; +#endif + +static char finalstr[10] = {'\0','f','i','n','a','l','\\','\0'}; +static char *enc = enc1; +static int internal_init = 0; +static char *rcvbuffer = NULL; +static int rcvmax = 0; +static int rcvlen = 0; +// Changed By Saad Nader, 09-16-2004 +// Due to confliction with MacOS X +/////////////////////////////////////////// +static int stats_initstate = init_none; +static int gameport = 0; + +static gsi_time initstart = 0; +static gsi_time inittimeout = 20000; // 20 seconds + +char StatsServerHostname[64] = SSHOST; + +static DArray serverreqs = NULL; //for pre-authentication requests + + +BucketFunc bucketfuncs[NUMOPS] = +{BucketSet, BucketAdd, BucketSub, BucketMult, BucketDiv, BucketConcat, BucketAvg}; + +void * bopfuncs[][3] = +{ + {ServerOpInt, ServerOpFloat, ServerOpString}, + {TeamOpInt, TeamOpFloat, TeamOpString}, + {PlayerOpInt, PlayerOpFloat, PlayerOpString}, +}; + +/****************************************************************************/ +/* PUBLIC FUNCTIONS */ +/****************************************************************************/ +#define RAWSIZE 128 +char *GenerateAuthA(const char *challenge, const char *password, char response[33]) +{ + char rawout[RAWSIZE]; + + /* check to make sure we weren't passed a huge pass/challenge */ + if (strlen(password) + strlen(challenge) + 20>= RAWSIZE) + { + strcpy(response,"CD Key or challenge too long"); + return response; + } + + /* response = MD5(pass + challenge) */ + sprintf(rawout, "%s%s",password, challenge ); + + /* do the response md5 */ + MD5Digest((unsigned char *)rawout, strlen(rawout), response); + return response; +} +#ifdef GSI_UNICODE +char *GenerateAuthW(const char* challenge, const unsigned short *password, char response[33]) +{ + char* password_A = UCS2ToUTF8StringAlloc(password); + GenerateAuthA(challenge, password_A, response); + gsifree(password_A); + return response; +} +#endif + +/****************************************************************************/ +int InitStatsAsync(int theGamePort, gsi_time theInitTimeout) +{ + struct sockaddr_in saddr; + char tempHostname[128]; + int ret; + + gameport = theGamePort; + + if (theInitTimeout != 0) + inittimeout = theInitTimeout; + + /* check if the backend is available */ + if(__GSIACResult != GSIACAvailable) + return GE_NOSOCKET; + + /* Init our hidden strings if needed */ + if (!internal_init) + InternalInit(); + + SocketStartUp(); + sesskey = (int)current_time(); + + /* Get connected */ + if (sock != INVALID_SOCKET) + CloseStatsConnection(); + + rcvlen = 0; //make sure ther receive buffer is cleared + + if (inet_addr(StatsServerHostname) == INADDR_NONE) + { + strcpy(tempHostname, gcd_gamename); + strcat(tempHostname,"."); + strcat(tempHostname,StatsServerHostname); + } else + strcpy(tempHostname, StatsServerHostname); //it's already been resolved + + if (get_sockaddrin(tempHostname,SSPORT,&saddr,NULL) == 0) + return GE_NODNS; + +#ifdef INSOCK + sock = socket ( AF_INET, SOCK_STREAM, 0 ); +#else + sock = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP ); +#endif + if (sock == INVALID_SOCKET) + return GE_NOSOCKET; + + SetSockBlocking(sock, 0); + + ret = connect(sock, (struct sockaddr*)&saddr, sizeof(saddr)); + if (gsiSocketIsError(ret)) + { + int anError = GOAGetLastError(sock); + if ((anError != WSAEWOULDBLOCK) && (anError != WSAETIMEDOUT) && (anError != WSAEINPROGRESS)) + { + stats_initstate = init_failed; + closesocket(sock); + return GE_NOCONNECT; + } + } + + // allocate the recv buffer + rcvbuffer = gsimalloc(64); + if (rcvbuffer == NULL) + return GE_NOCONNECT; // add a new error code for out of mem? + + rcvmax = 64; + rcvlen = 0; + + initstart = current_time(); + stats_initstate = init_connecting; + return GE_CONNECTING; +} + +/****************************************************************************/ +int InitStatsThink() +{ + switch(stats_initstate) + { + case init_failed: return GE_NOCONNECT; + case init_connecting: + { + // Check if socket is writeable yet + int aWriteFlag = 0; + int aExceptFlag = 0; + int aResult = GSISocketSelect(sock, NULL, &aWriteFlag, &aExceptFlag); + if ((gsiSocketIsError(aResult)) || // socket error + (aResult == 1 && aExceptFlag == 1)) // exception + { + stats_initstate = init_failed; + CloseStatsConnection(); + return GE_NOCONNECT; + } + else if (aResult == 0) // no progress yet + { + // Should we continue to wait? + if (current_time() - initstart > inittimeout) + { + stats_initstate = init_failed; + CloseStatsConnection(); + return GE_TIMEDOUT; + } + else + return GE_CONNECTING; + } + + // Otherwise connected + assert(aResult == 1 && aWriteFlag == 1); + stats_initstate = init_awaitchallenge; + // fall through + } + case init_awaitchallenge: + { + int ret = 0; + + // Try to receive data + if (!CanReceiveOnSocket(sock)) + { + // should we continue to wait? + if (current_time() - initstart > inittimeout) + { + stats_initstate = init_failed; + CloseStatsConnection(); + return GE_TIMEDOUT; + } + return GE_CONNECTING; + } + + // Receive the 38 byte challenge + ret = recv(sock, rcvbuffer+rcvlen, rcvmax-rcvlen, 0); + if (gsiSocketIsError(ret)) + { + stats_initstate = init_failed; + CloseStatsConnection(); + return GE_NOCONNECT; + } + rcvlen += ret; + rcvmax -= ret; + + // need at least 38 bytes + if (rcvlen < 38) + return GE_CONNECTING; + + // Process challenge + rcvbuffer[rcvlen] = '\0'; + stats_initstate = init_awaitsessionkey; + + /* Decode it */ + DOXCODE(rcvbuffer, rcvlen, enc1); + /* Send a response */ + ret = SendChallengeResponse(rcvbuffer, gameport); + if (ret != GE_NOERROR) + { + stats_initstate = init_failed; + CloseStatsConnection(); + return ret; + } + + stats_initstate = init_awaitsessionkey; + + // clear receive buffer for next stage + rcvmax += rcvlen; // reclaim the used bytes as free space + rcvlen = 0; + memset(rcvbuffer, 0, (unsigned int)rcvmax); + + // fall through + } + case init_awaitsessionkey: + { + int ret = 0; + + // Try to receive data + if (!CanReceiveOnSocket(sock)) + { + // should we continue to wait? + if (current_time() - initstart > inittimeout) + { + stats_initstate = init_failed; + CloseStatsConnection(); + return GE_TIMEDOUT; + } + return GE_CONNECTING; + } + + ret = RecvSessionKey(); + if (ret != GE_NOERROR) + { + stats_initstate = init_failed; + CloseStatsConnection(); + return ret; + } + + // Init complete + // Clear the receive buffer + rcvmax += rcvlen; + rcvlen = 0; + memset(rcvbuffer, 0, (unsigned int)rcvmax); + + #ifdef ALLOW_DISK + /* Check for old data */ + CheckDiskFile(); + #endif + + stats_initstate = init_complete; + + // fall through + } + case init_complete: + return GE_NOERROR; + + default: + return GE_NOCONNECT; + }; +} + + +/****************************************************************************/ +// Blocking version of InitStatsAsync, for backwards compatability +int InitStatsConnection(int gameport) +{ + int aResult = InitStatsAsync(gameport, 0); + while (aResult == GE_CONNECTING) + { + aResult = InitStatsThink(); + msleep(5); + } + return aResult; +} + +/****************************************************************************/ +void CloseStatsConnection() +{ + if (sock != INVALID_SOCKET) + { + shutdown(sock,2); + closesocket(sock); + } + sock = INVALID_SOCKET; + //call any pending callbacks with the data as lost + ClosePendingCallbacks(); + if (rcvbuffer != NULL) + { + gsifree(rcvbuffer); + rcvbuffer = NULL; + rcvmax = 0; + rcvlen = 0; + } + +} + +/****************************************************************************/ +int IsStatsConnected() +{ + return (sock != INVALID_SOCKET); +} + +/****************************************************************************/ +#define CHALLENGEXOR 0x38F371E6 +char *GetChallenge(statsgame_t game) +{ + static char challenge[9]; + if (game == NULL) + game = g_statsgame; + if (game == NULL) + { + create_challenge(connid ^ CHALLENGEXOR,challenge); + return challenge; + } + return game->challenge; +} + +/****************************************************************************/ +statsgame_t NewGame(int usebuckets) +{ + statsgame_t game = (statsgame_t)gsimalloc(sizeof (struct statsgame_s)); + char data[256]; + int len; + + if (!internal_init) + InternalInit(); + game->connid = connid; + game->sesskey = sesskey++; + game->buckets = NULL; + game->playernums = NULL; + game->teamnums = NULL; + game->usebuckets = usebuckets; + /* If connected, try to send */ + if (sock != INVALID_SOCKET) + { + char respformat[] = "\xC\x1C\xA\x1D\x2\x2\x19\x24\x2C\x34\x6\x17\x3E\x1C\x6\xE\x39\x46\x10\x1D\x3\xD\x16\xB\x3B\x17\x16\x36\x40\x7"; + //"\newgame\\connid\%d\sesskey\%d" + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data,respformat,game->connid, game->sesskey); + len = DoSend(data, len); + if (len <= 0) + { + CloseStatsConnection(); + } + create_challenge(game->connid ^ CHALLENGEXOR,game->challenge); + } + /* If send failed then write to disk */ + if (sock == INVALID_SOCKET) + { +#ifdef ALLOW_DISK + char respformat[] = "\xC\x1C\xA\x1D\x2\x2\x19\x24\x2C\x34\x16\x1D\x23\x1\x4\xF\x1C\x3F\x51\x25\x2C\xB\xD\x19\x3C\x1E\xA\x4\x2\x6\x28\x64\x14"; + // "\newgame\\sesskey\%d\challenge\%d"; + + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data,respformat,game->sesskey, game->sesskey ^ CHALLENGEXOR); + DiskWrite(data, len); + game->connid = 0; + create_challenge(game->sesskey ^ CHALLENGEXOR,game->challenge); + +#else + gsifree(game); + game = NULL; +#endif + + } + + if (game && game->usebuckets) + { + game->buckets = NewBucketSet(); + game->playernums = ArrayNew(sizeof(int),32,NULL); + game->teamnums = ArrayNew(sizeof(int),2,NULL); + game->totalplayers = game->totalteams = 0; + } + if (game) + game->sttime = current_time(); + g_statsgame = game; + return game; + +} + + +/****************************************************************************/ +void FreeGame(statsgame_t game) +{ + if (!game || game == g_statsgame) + { + game = g_statsgame; + g_statsgame = NULL; + } + if (!game) + return; + if (game->usebuckets) + { + if (game->buckets != NULL) + FreeBucketSet(game->buckets); + if (game->playernums != NULL) + ArrayFree(game->playernums); + if (game->teamnums != NULL) + ArrayFree(game->teamnums); + } + gsifree(game); +} + +/****************************************************************************/ +int SendGameSnapShotA(statsgame_t game, const char *snapshot, int final) +{ + int snaplen; + int len; + int ret = GE_NOERROR; + char *snapcopy; + char *data; + FIXGAME(game, GE_DATAERROR); + + /* If using buckets, get the data out of the buckets */ + if (game->usebuckets) + snapcopy = CreateBucketSnapShot(game->buckets); + else + snapcopy = goastrdup(snapshot); + snaplen = (int)strlen(snapcopy); + + data = (char *)gsimalloc((unsigned int)snaplen + 256); + + /* Escape the data */ + while (snaplen--) + if (snapcopy[snaplen] == '\\') + snapcopy[snaplen] = '\x1'; + + /* If connected, try to send it */ + if (sock != INVALID_SOCKET) + { + // Updated response format to contain connid + //char respformat[] = "\xC\x7\x1F\xE\x2\x2\x19\x24\x2C\x34\x16\x1D\x23\x1\x4\xF\x1C\x3F\x51\x25\x2C\xC\xA\x16\x35\x2E\x4A\xE\x39\x4\x15\x2C\x15\xC\x4\xC\x31\x2E\x4A\x19"; + char respformat[] = "\xC\x7\x1F\xE\x2\x2\x19\x24\x2C\x34\x16\x1D\x23\x1\x4\xF\x1C\x3F\x51\x25\x2C\xB\xA\x16\x3E\x1B\xB\x36\x40\x7\x28\x25\x1F\x6\x00\x24\x75\x16\x33\xD\x4\xE\x11\x25\x11\x1C\x4\x24\x75\x1"; + // "\updgame\\sesskey\%d\done\%d\gamedata\%s" + // The above string is now: + // "\updgame\\sesskey\%d\connid\%d\done\%d\gamedata\%s" + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data, respformat, game->sesskey, game->connid, final, snapcopy); + snaplen = DoSend(data, len); + /* If the send failed, close the socket */ + if (snaplen <= 0) + { + CloseStatsConnection(); + } + } + /* If not connected, or send failed, return error or log to disk */ + if (sock == INVALID_SOCKET) + { +#ifdef ALLOW_DISK + char respformat[] = "\xC\x7\x1F\xE\x2\x2\x19\x24\x2C\x34\x16\x1D\x23\x1\x4\xF\x1C\x3F\x51\x25\x2C\xB\xA\x16\x3E\x1B\xB\x36\x40\x7\x28\x25\x1F\x6\x0\x24\x75\x16\x33\xD\x4\xE\x11\x25\x11\x1C\x4\x24\x75\x1\x33\xE\x9\x3F\x45"; + //"\updgame\\sesskey\%d\connid\%d\done\%d\gamedata\%s\dl\1" + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data, respformat, game->sesskey, game->connid, final, snapcopy); + DiskWrite(data, len); +#else + ret = GE_NOCONNECT; +#endif + } + gsifree(snapcopy); + gsifree(data); + return ret; +} +#ifdef GSI_UNICODE +int SendGameSnapShotW(statsgame_t game, const unsigned short*snapshot, int final) +{ + char* snapshot_A = UCS2ToUTF8StringAlloc(snapshot); + int result = SendGameSnapShotA(game, snapshot_A, final); + gsifree(snapshot_A); + return result; +} +#endif + +/****************************************************************************/ +void NewPlayerA(statsgame_t game, int pnum, char *name) +{ + int i = -1; + FIXGAME(game, ;) + while (pnum >= ArrayLength(game->playernums)) + ArrayAppend(game->playernums, &i); + i = game->totalplayers++; + /* update the pnum array */ + ArrayReplaceAt(game->playernums,&i, pnum); + BucketIntOp(game, "ctime",bo_set,(int)(current_time() - game->sttime) / 1000,bl_player,pnum); + BucketStringOp(game,"player",bo_set,name, bl_player,pnum); + +} +#ifdef GSI_UNICODE +void NewPlayerW(statsgame_t game, int pnum, unsigned short *name) +{ + char* name_A = UCS2ToUTF8StringAlloc(name); + NewPlayerA(game, pnum, name_A); + gsifree(name_A); +} +#endif + +/****************************************************************************/ +void RemovePlayer(statsgame_t game,int pnum) +{ + FIXGAME(game, ;); + BucketIntOp(game,"dtime",bo_set,(int)(current_time() - game->sttime) / 1000, bl_player, pnum); +} + +/****************************************************************************/ +void NewTeamA(statsgame_t game,int tnum, char *name) +{ + int i = -1; + FIXGAME(game, ;) + while (tnum >= ArrayLength(game->teamnums)) + ArrayAppend(game->teamnums, &i); + i = game->totalteams++; + /* update the tnum array */ + ArrayReplaceAt(game->teamnums,&i, tnum); + BucketIntOp(game, "ctime",bo_set,(int)(current_time() - game->sttime) / 1000,bl_team,tnum); + BucketStringOp(game,"team",bo_set,name, bl_team,tnum); +} +#ifdef GSI_UNICODE +void NewTeamW(statsgame_t game,int tnum, unsigned short *name) +{ + char* name_A = UCS2ToUTF8StringAlloc(name); + NewTeamA(game, tnum, name_A); + gsifree(name_A); +} +#endif + +/****************************************************************************/ +void RemoveTeam(statsgame_t game, int tnum) +{ + FIXGAME(game, ;); + BucketIntOp(game,"dtime",bo_set,(int)(current_time() - game->sttime) / 1000, bl_team, tnum); +} + +/**************************************************************************** + * PERSISTENT STORAGE FUNCTIONS + ****************************************************************************/ + +/****************************************************************************/ +void PreAuthenticatePlayerPartner(int localid, const char * authtoken, const char *challengeresponse, PersAuthCallbackFn callback, void *instance) +{ + char respformat[] = "\xC\x13\x1A\x1E\xD\x13\x28\x1D\x11\x1D\x11\x10\x24\x1D\x04\x0F\x0B\x3F\x51\x32\x2C\x1A\x00\x0B\x20\x2E\x4A\x19\x39\x0F\x1D\x25\x2C\x4D\x01"; + //\authp\\authtoken\%s\resp\%s\lid\%d"; + int len; + char data[256]; + + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data, respformat, authtoken, challengeresponse, localid); + + SendPlayerAuthRequest(data, len, localid, callback, instance); +} + + +/****************************************************************************/ +void PreAuthenticatePlayerPM(int localid, int profileid, const char *challengeresponse, PersAuthCallbackFn callback, void *instance) +{ + char respformat[] = "\xC\x13\x1A\x1E\xD\x13\x28\x1D\x0\x1\x1\x24\x75\x16\x33\x18\x0\x10\x4\x1D\x55\x1B\x39\x14\x39\x16\x33\x4F\x1"; + //\authp\\pid\%d\resp\%s\lid\%d + int len; + char data[256]; + + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data, respformat, profileid, challengeresponse,localid); + + SendPlayerAuthRequest(data, len, localid, callback, instance); + +} + +/****************************************************************************/ +void PreAuthenticatePlayerCDA(int localid, const char *nick, const char *keyhash, const char *challengeresponse, PersAuthCallbackFn callback, void *instance) +{ + char respformat[] = "\xC\x13\x1A\x1E\xD\x13\x28\x1D\x1E\x1\x6\x13\xC\x57\x1C\x36\xE\x6\xD\x29\x11\x1B\xD\x24\x75\x1\x33\x18\x0\x10\x4\x1D\x55\x1B\x39\x14\x39\x16\x33\x4F\x1"; + //\authp\\nick\%s\keyhash\%s\resp\%s\lid\%d + int len; + char data[256]; + + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data, respformat, nick, keyhash, challengeresponse,localid); + + SendPlayerAuthRequest(data, len, localid, callback, instance); + +} +#ifdef GSI_UNICODE +void PreAuthenticatePlayerCDW(int localid, const unsigned short *nick, const char *keyhash, const char *challengeresponse, PersAuthCallbackFn callback, void *instance) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + PreAuthenticatePlayerCDA(localid, nick_A, keyhash, challengeresponse, callback, instance); + gsifree(nick_A); +} +#endif + +/****************************************************************************/ +void GetProfileIDFromCDA(int localid, const char *nick, const char *keyhash, ProfileCallbackFn callback, void *instance) +{ + char respformat[] = "\xC\x15\xA\x1E\x15\xA\x10\x1D\x2C\x6\xC\x1B\x3B\x2E\x4A\x19\x39\x8\x11\x38\x18\x9\x16\x10\xC\x57\x1C\x36\x9\xA\x10\x1D\x55\xC"; + //\getpid\\nick\%s\keyhash\%s\lid\%d + int len; + char data[512]; + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(data, respformat, nick, keyhash,localid); + + if (sock != INVALID_SOCKET) + len = DoSend(data, len); + + /* If the send failed, close the socket */ + if (len <= 0) + { + CloseStatsConnection(); + if (callback) + callback(0,-1,0,instance); + } else + { /* set up the callback */ + AddRequestCallback(rt_profilecb, localid, 0,(persisttype_t)0,0,callback, instance); + } +} +#ifdef GSI_UNICODE +void GetProfileIDFromCDW(int localid, const unsigned short *nick, const char *keyhash, ProfileCallbackFn callback, void *instance) +{ + char* nick_A = UCS2ToUTF8StringAlloc(nick); + GetProfileIDFromCDA(localid, nick_A, keyhash, callback, instance); + gsifree(nick_A); +} +#endif + +/****************************************************************************/ +void GetPersistData(int localid, int profileid, persisttype_t type, int index, PersDataCallbackFn callback, void *instance) +{ + GetPersistDataValuesModifiedA(localid,profileid, type,index,0,"",callback, instance); +} + +void GetPersistDataModified(int localid, int profileid, persisttype_t type, int index, time_t modifiedsince, PersDataCallbackFn callback, void *instance) +{ + GetPersistDataValuesModifiedA(localid,profileid, type,index, modifiedsince, "",callback, instance); +} + +/****************************************************************************/ +void SetPersistData(int localid, int profileid, persisttype_t type, int index, const char *data, int len, PersDataSaveCallbackFn callback, void *instance) +{ + SetPersistDataHelper(localid, profileid, type, index, data, len, callback, instance, 0); +} + +/****************************************************************************/ +void GetPersistDataValuesModifiedA(int localid, int profileid, persisttype_t type, int index, time_t modifiedsince, char *keys, PersDataCallbackFn callback, void *instance) +{ + char respformat[] = "\xC\x15\xA\x1E\x15\x7\x28\x1D\x0\x1\x1\x24\x75\x16\x33\x1A\x11\x1A\x4\x24\x2C\x4D\x1\x24\x34\x1B\x1\xE\x0\x1B\x28\x64\x14\x34\xE\x1D\x29\x1\x33\x4F\x16\x3F\x18\x28\x14\x34\x40\x1C"; + char modformat[] = {'\\','m','o','d','\\','%','d','\0'}; //\\mod\\%d + //\getpd\\pid\%d\ptype\%d\dindex\%d\keys\%s\lid\%d + int len; + char data[512]; + char tempkeys[256]; + char *p; + + DOXCODE(respformat, sizeof(respformat)-1, enc3); + strcpy(tempkeys, keys); + //replace the \ chars with #1 + for (p = tempkeys; *p != 0; p++) + if (*p == '\\') + *p = '\x1'; + + len = sprintf(data, respformat, profileid, type, index, tempkeys, localid); + if (modifiedsince != 0) //append it + { + len += sprintf(data + len, modformat, modifiedsince); + } + + if (sock != INVALID_SOCKET) + len = DoSend(data, len); + + /* If the send failed, close the socket */ + if (len <= 0) + { + CloseStatsConnection(); + if (callback) + callback(localid, profileid,type, index, 0,0,"",0,instance); + } else + { /* set up the callback */ + AddRequestCallback(rt_datacb, localid, profileid,type, index, callback, instance); + } +} + +void GetPersistDataValuesA(int localid, int profileid, persisttype_t type, int index, char *keys, PersDataCallbackFn callback, void *instance) +{ + GetPersistDataValuesModifiedA(localid,profileid, type,index, 0, keys,callback, instance); +} + +#ifdef GSI_UNICODE +void GetPersistDataValuesModifiedW(int localid, int profileid, persisttype_t type, int index, time_t modifiedsince, unsigned short*keys, PersDataCallbackFn callback, void *instance) +{ + char* keys_A = UCS2ToUTF8StringAlloc(keys); + GetPersistDataValuesModifiedA(localid, profileid, type, index, modifiedsince, keys_A, callback, instance); + gsifree(keys_A); +} +#endif + +#ifdef GSI_UNICODE +void GetPersistDataValuesW(int localid, int profileid, persisttype_t type, int index, unsigned short*keys, PersDataCallbackFn callback, void *instance) +{ + GetPersistDataValuesModifiedW(localid,profileid, type,index, 0, keys,callback, instance); +} +#endif + +/****************************************************************************/ +void SetPersistDataValuesA(int localid, int profileid, persisttype_t type, int index, const char *keyvalues, PersDataSaveCallbackFn callback, void *instance) +{ + SetPersistDataHelper(localid, profileid, type, index, keyvalues, (int)strlen(keyvalues) + 1, callback, instance, 1); +} +#ifdef GSI_UNICODE +void SetPersistDataValuesW(int localid, int profileid, persisttype_t type, int index, const unsigned short *keyvalues, PersDataSaveCallbackFn callback, void *instance) +{ + char* keyvalues_A = UCS2ToUTF8StringAlloc(keyvalues); + SetPersistDataValuesA(localid, profileid, type, index, keyvalues_A, callback, instance); + gsifree(keyvalues_A); +} +#endif + +/****************************************************************************/ +int PersistThink() +{ + int len; + int processed; + + if (sock == INVALID_SOCKET) + return 0; + + if (stats_initstate != init_complete) + return 0; + + while (SocketReadable(sock)) + { + if (rcvmax - rcvlen < 128) //make sure there are at least 128 bytes gsifree in the buffer + { + if (rcvmax < 256) + rcvmax = 256; + else + rcvmax *= 2; + rcvbuffer = gsirealloc(rcvbuffer, (unsigned int)(rcvmax+1)); + if (rcvbuffer == NULL) + return 0; //errcon + } + len = recv(sock, rcvbuffer + rcvlen, rcvmax - rcvlen, 0); + if (len <= 0) //lost the connection + { + CloseStatsConnection(); + return 0; + } + rcvlen += len; + rcvbuffer[rcvlen] = 0; + + processed = ProcessInBuffer(rcvbuffer, rcvlen); + if (processed == rcvlen) //then we can just zero it + rcvlen = 0; + else + { + //shift the remaining data down + memmove(rcvbuffer,rcvbuffer + processed, (unsigned int)(rcvlen - processed)); + rcvlen -= processed; + } + + + } + if (sock == INVALID_SOCKET) + return 0; + else + return 1; + +} + +/****************************************************************************/ +int StatsThink() +{ + return PersistThink(); +} + +/**************************************************************************** + * UTILITY FUNCTIONS + ****************************************************************************/ + +void InternalInit() +{ + internal_init = 1; + enc1[0] = 'G'; + enc3[0] = 'P'; + finalstr[0] = '\\'; + +#ifdef ALLOW_DISK + statsfile[0] = 'g'; + enc2[0] = 'I'; +#endif +} + + +static int SendChallengeResponse(const char *indata, int gameport) +{ + static char challengestr[] = {'\0','h','a','l','l','e','n','g','e','\0'}; + char *challenge; + char resp[128]; + char md5val[33]; + + /* make this harder to find in the string table */ + char respformat[] = "\xC\x13\x1A\x1E\xD\x3F\x28\x26\x11\x5\x0\x16\x31\x1F\xA\x36\x40\x10\x28\x33\x15\x1B\x15\x17\x3E\x1\xA\x36\x40\x10\x28\x31\x1F\x1A\x11\x24\x75\x16\x33\x3\x1\x3F\x45"; + /* \auth\\gamename\%s\response\%s\port\%d\id\1 */ + int len; + + challengestr[0] = 'c'; + challenge = value_for_key(indata,challengestr ); + if (challenge == NULL) + { + closesocket(sock); + return GE_DATAERROR; + } + + len = sprintf(resp, "%d%s",g_crc32(challenge,(int)strlen(challenge)), gcd_secret_key); + + MD5Digest((unsigned char *)resp, (unsigned int)len, md5val); + DOXCODE(respformat, sizeof(respformat)-1, enc3); + len = sprintf(resp,respformat,gcd_gamename, md5val, gameport); + + if ( DoSend(resp, len) <= 0 ) + { + closesocket(sock); + return GE_NOCONNECT; + } + + return GE_NOERROR; +} + + +// 09-13-2004 BED Unused parameter removed +static int RecvSessionKey() +{ + /* get the response */ + static char sesskeystr[] = {'\0','e','s','s','k','e','y','\0'}; + char resp[128]; + char *stext; + int len = (int)recv(sock, resp,128,0); + if (gsiSocketIsError(len)) + { + int anError = GOAGetLastError(sock); + closesocket(sock); + + if ((anError != WSAEWOULDBLOCK) && (anError != WSAETIMEDOUT) && (anError != WSAEINPROGRESS)) + return GE_NOCONNECT; + else + return GE_DATAERROR; //temp fix in case len == -1, SOCKET_ERROR + } + + resp[len] = 0; + DOXCODE(resp, len, enc1); + sesskeystr[0] = 's'; + stext = value_for_key(resp, sesskeystr); + if (stext == NULL) + { + closesocket(sock); + return GE_DATAERROR; + } else + connid = atoi(stext); + + return GE_NOERROR; +} + + + +static int DoSend(char *data, int len) +{ + int sent = 0; + + DOXCODE(data,len, enc1); + strcpy(data+len,finalstr); + + // Loop to make sure async send goes through! + while(sent < (len+7)) + { + // Send remaining data + int ret = send(sock, (data+sent), (len+7-sent), 0); + if (gsiSocketIsError(ret)) + { + int anError = GOAGetLastError(sock); + if ((anError != WSAEWOULDBLOCK) && (anError != WSAETIMEDOUT) && (anError != WSAEINPROGRESS)) + return anError; + } + else if (ret == 0) + { + // socket was closed + return -1; + } + else + sent += ret; + }; + + return sent; +} + + + +#ifdef ALLOW_DISK +/* Note: lots of this is byte order and type size specific, but it shouldn't +matter since the data is read/written always on the same machine */ +#define DISKLENXOR 0x70F33A5F +static void CheckDiskFile() +{ + FILE *f; + char *line; + char *alldata; + int len, check, alllen, fsize; + char filemode[3]; + /* hide our file access from the string table */ + filemode[0] = 'r'; filemode[1] = 'b'; filemode[2] = 0; + f = fopen(statsfile,filemode); + if (!f) + return; + /* get the size */ + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + /* make room for the whole thing */ + alldata = (char *)gsimalloc(fsize + 2); + alldata[0] = 0; + alllen = 0; + while (!feof(f) && !ferror(f)) + { + /* read the check and line values */ + if (fread(&check,sizeof(check),1,f) == 0 || + fread(&len,sizeof(len),1,f) == 0) + break; + len ^= DISKLENXOR; + line = (char *)gsimalloc(len + 1); + /* read the data */ + if (fread(line, 1, len, f) != (size_t)len) + break; + line[len] = 0; + /* decode for checking */ + DOXCODE(line, len, enc2); + /* double "check" */ + if (check != g_crc32(line, len)) + { + gsifree(line); + break; + } + /* encode for xmission */ + DOXCODE(line, len, enc1); + memcpy(alldata + alllen, line, len); + alllen += len; + memcpy(alldata + alllen, finalstr, 7); + alllen += 7; + gsifree(line); + } + fclose(f); + /* try to send */ + len = send(sock, alldata, alllen, 0); + if (len <= 0) + { + closesocket(sock); + sock = INVALID_SOCKET; + } else + remove(statsfile); +} + +static void DiskWrite(char *line, int len) +{ + FILE *f; + int check; + int temp; + char filemode[3]; + /* hide our file access from the string table */ + filemode[0] = 'a'; filemode[1] = 'b'; filemode[2] = 0; + f = fopen(statsfile,filemode); + if (!f) + return; + check = g_crc32(line, len); + fwrite(&check, sizeof(check),1,f); + temp = len ^ DISKLENXOR; + fwrite(&temp, sizeof(temp), 1, f); + DOXCODE(line, len, enc2); + fwrite(line, 1, len, f); + fclose(f); +} + +#endif /* ALLOW_DISK */ + +/* simple xor encoding */ +static void xcode_buf(char *buf, int len) +{ + int i; + char *pos = enc; + + for (i = 0 ; i < len ; i++) + { + buf[i] ^= *pos++; + if (*pos == 0) + pos = enc; + } +} + +#define MULTIPLIER -1664117991 +static int g_crc32(char *s, int len) +{ + int i; + int hashcode = 0; + + for (i = 0; i < len; i++) + hashcode = hashcode * MULTIPLIER + s[i]; + return hashcode; +} + +static void create_challenge(int challenge, char chstr[9]) +{ + char *p = chstr; + sprintf(chstr, "%08x",challenge); + + while (*p != 0) + { + *p = (char)((*p) + ('A' - '0') + (p-chstr)); + p++; + } +} + +/* value_for_key: this returns a value for a certain key in s, where s is a string +containing key\value pairs. If the key does not exist, it returns NULL. +Note: the value is stored in a common buffer. If you want to keep it, make a copy! */ +static char *value_for_key(const char *s, const char *key) +{ + static int valueindex; + char *pos,*pos2; + char keyspec[256]="\\"; + static char value[2][256]; + + valueindex ^= 1; + strcat(keyspec,key); + strcat(keyspec,"\\"); + pos = strstr(s,keyspec); + if (!pos) + return NULL; + pos += strlen(keyspec); + pos2 = value[valueindex]; + while (*pos && *pos != '\\') + *pos2++ = *pos++; + *pos2 = '\0'; + return value[valueindex]; +} + +/* like value_for_key, but returns an empty string instead of NULL in the not-found case */ +static char *value_for_key_safe(const char *s, const char *key) +{ + char *temp; + + temp = value_for_key(s, key); + if (!temp) + return ""; + else + return temp; +} + +/* Return a sockaddrin for the given host (numeric or DNS) and port) +Returns the hostent in savehent if it is not NULL */ +static int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent) +{ + struct hostent *hent = NULL; + + memset(saddr,0,sizeof(struct sockaddr_in)); + saddr->sin_family = AF_INET; + saddr->sin_port = htons((unsigned short)port); + if (host == NULL) + saddr->sin_addr.s_addr = INADDR_ANY; + else + saddr->sin_addr.s_addr = inet_addr(host); + + if (saddr->sin_addr.s_addr == INADDR_NONE) + { + hent = gethostbyname(host); + if (!hent) + return 0; + saddr->sin_addr.s_addr = *(unsigned int *)hent->h_addr_list[0]; + } + if (savehent != NULL) + *savehent = hent; + return 1; +} + +/* adds a request callback to the list */ +static void AddRequestCallback(reqtype_t reqtype, int localid, int profileid, persisttype_t pdtype, int pdindex, void *callback, void *instance) +{ + serverreq_t req; + + req.callback = callback; + req.instance = instance; + req.localid = localid; + req.reqtype = reqtype; + req.profileid = profileid; + req.pdtype = pdtype; + req.pdindex = pdindex; + if (serverreqs == NULL) //create the callback array + { + serverreqs = ArrayNew(sizeof(serverreq_t),2,NULL); + } + ArrayAppend(serverreqs,&req); +} + +/* sends the player authentication request (GP or CD) */ +static void SendPlayerAuthRequest(char *data, int len, int localid, PersAuthCallbackFn callback, void *instance) +{ + int sentlen = 0; + char connerror[] = "\x13\x1D\x1\x4\x0\x0\x0\x28\x1F\x6\x45\x34\x3F\x1\x1B"; + //"Connection Lost" + + if (sock != INVALID_SOCKET) + sentlen = DoSend(data, len); + + /* If the send failed, close the socket */ + if (sentlen <= 0) + { + CloseStatsConnection(); + DOXCODE(connerror, sizeof(connerror)-1, enc3); + if (callback) + { +#ifndef GSI_UNICODE + callback(localid, 0,0, connerror ,instance); +#else + unsigned short connerror_W[] = L"\x13\x1D\x1\x4\x0\x0\x0\x28\x1F\x6\x45\x34\x3F\x1\x1B"; + callback(localid, 0, 0, connerror_W, instance); +#endif + } + } else + { /* set up the callback */ + AddRequestCallback(rt_authcb, localid, 0,(persisttype_t)0,0,callback, instance); + } +} + +/* send a set request, if kvset, then only those keys/values will bet updated */ +static void SetPersistDataHelper(int localid, int profileid, persisttype_t type, int index, const char *data, int len, PersDataSaveCallbackFn callback, void *instance, int kvset) +{ + char respformat[] = "\xC\x1\xA\x1E\x15\x7\x28\x1D\x0\x1\x1\x24\x75\x16\x33\x1A\x11\x1A\x4\x24\x2C\x4D\x1\x24\x34\x1B\x1\xE\x0\x1B\x28\x64\x14\x34\xE\xE\xC\x57\xB\x36\x9\xA\x10\x1D\x55\xC\x39\x14\x35\x1C\x8\x1E\xD\x3F\x51\x25\x2C\xC\x4\xC\x31\x2E"; + //\setpd\\pid\%d\ptype\%d\dindex\%d\kv\%d\lid\%d\length\%d\data\ -- + int tlen; + char tdata[512]; + char *senddata; + + DOXCODE(respformat, sizeof(respformat)-1, enc3); + + if (type == pd_private_ro || type == pd_public_ro) + { //can't set read-only types, check that client side + if (callback) + callback(localid, profileid, type, index, 0, 0, instance); + return; + } + + tlen = sprintf(tdata, respformat, profileid, type, index, kvset, localid, len); + if (tlen + len < 480) //we have enough room to put it in the data block + { + memcpy(tdata + tlen, data, (unsigned int)len); + senddata = tdata; + + } else //need to alloc a temp buffer + { + senddata = (char *)gsimalloc((unsigned int)(len + tlen + 256)); + memcpy(senddata, tdata, (unsigned int)tlen); + memcpy(senddata + tlen, data, (unsigned int)len); + } + + if (sock != INVALID_SOCKET) + tlen = DoSend(senddata, tlen + len); + + /* If the send failed, close the socket */ + if (tlen <= 0) + { + CloseStatsConnection(); + if (callback) + callback(localid, profileid, type, index, 0, 0, instance); + } else + { /* set up the callback */ + AddRequestCallback(rt_savecb, localid, profileid,type, index, callback, instance); + } + if (senddata != tdata) //if we alloc'd before sending + gsifree(senddata); +} + +/* returns 1 if the socket is readable, 0 otherwise */ +static int SocketReadable(SOCKET s) +{ + return CanReceiveOnSocket(s); +/* + fd_set set; + struct timeval tv = {0,0}; + int n; + + if (s == INVALID_SOCKET) + return 0; + + FD_ZERO(&set); + FD_SET(s, &set); + + n = select(FD_SETSIZE, &set, NULL, NULL, &tv); + + return n; +*/ +} + +/* find the \final\ string */ +static char *FindFinal(char *buff, int len) +{ + char *pos = buff; + + while (pos - buff < len - 6) + { + if (pos[0] == '\\' && + pos[1] == 'f' && + pos[2] == 'i' && + pos[3] == 'n' && + pos[4] == 'a' && + pos[5] == 'l' && + pos[6] == '\\') + { + return pos; + } else + pos++; + } + return NULL; +} + +/* find the request in the callback list */ +static int FindRequest(reqtype_t reqtype, int localid, int profileid) +{ + int i; + serverreq_t *req; + + if (serverreqs == NULL) + return -1; + for (i = 0 ; i < ArrayLength(serverreqs); i++) + { + req = (serverreq_t *)ArrayNth(serverreqs, i); + if (req->reqtype == reqtype && req->localid == localid && req->profileid == profileid) + return i; + } + return -1; + +} + +/* process the playerauth result */ +static void ProcessPlayerAuth(const char *buf, int len) +{ + // \\pauthr\\100000\\lid\\1 + int reqindex; + char *errmsg; + int pid; + int lid; + pid = atoi(value_for_key_safe(buf,"pauthr")); + lid = atoi(value_for_key_safe(buf,"lid")); + errmsg = value_for_key_safe(buf,"errmsg"); + reqindex = FindRequest(rt_authcb,lid,0); + if (reqindex == -1) + return; + ((serverreq_t *)ArrayNth(serverreqs, reqindex))->profileid = pid; + CallReqCallback(reqindex,(pid > 0),0, errmsg,0); + + GSI_UNUSED(len); +} + +/* process the get profileid result */ +static void ProcessGetPid(const char *buf, int len) +{ + // \\getpidr\\100000\\lid\\1 + int reqindex; + int pid; + int lid; + pid = atoi(value_for_key_safe(buf,"getpidr")); + lid = atoi(value_for_key_safe(buf,"lid")); + reqindex = FindRequest(rt_profilecb,lid,0); + if (reqindex == -1) + return; + ((serverreq_t *)ArrayNth(serverreqs, reqindex))->profileid = pid; + CallReqCallback(reqindex,(pid > 0),0,NULL,0); + + GSI_UNUSED(len); +} + +/* process the get data result */ +static void ProcessGetData(const char *buf, int len) +{ + // \\getpdr\\1\\lid\\1\\mod\\1234\\length\\5\\data\\mydata\\final + int reqindex; + int pid; + int lid; + int success; + int length; + time_t modified; + char *data; + success = atoi(value_for_key_safe(buf,"getpdr")); + lid = atoi(value_for_key_safe(buf,"lid")); + pid = atoi(value_for_key_safe(buf,"pid")); + modified = atoi(value_for_key_safe(buf,"mod")); + reqindex = FindRequest(rt_datacb,lid,pid); + if (reqindex == -1) + return; + length = atoi(value_for_key_safe(buf,"length")); + data = strstr(buf,"\\data\\"); + if (!data) + { + length = 0; + data = ""; + } else + data += 6; //skip the key + CallReqCallback(reqindex,success,modified, data,length); + + GSI_UNUSED(len); +} + +/* process the set data result */ +static void ProcessSetData(const char *buf, int len) +{ + // \\setpdr\\1\\lid\\2\\pid\\100000\\mod\\12345 + int reqindex; + int pid; + int lid; + int success; + int modified; + success = atoi(value_for_key_safe(buf,"setpdr")); + pid = atoi(value_for_key_safe(buf,"pid")); + lid = atoi(value_for_key_safe(buf,"lid")); + modified = atoi(value_for_key_safe(buf,"mod")); + reqindex = FindRequest(rt_savecb,lid,pid); + if (reqindex == -1) + return; + CallReqCallback(reqindex,success,modified,NULL,0); + + GSI_UNUSED(len); +} + +/* process a single statement */ +static void ProcessStatement(char *buff, int len) +{ + //determine the type + + buff[len] = 0; + // printf("GOT: %s\n",buff); + if (strncmp(buff,"\\pauthr\\",8) == 0) + { + ProcessPlayerAuth(buff, len); + } else if (strncmp(buff,"\\getpidr\\",9) == 0) + { + ProcessGetPid(buff, len); + } else if (strncmp(buff,"\\getpidr\\",9) == 0) + { + ProcessGetPid(buff, len); + } else if (strncmp(buff,"\\getpdr\\",8) == 0) + { + ProcessGetData(buff, len); + } else if (strncmp(buff,"\\setpdr\\",8) == 0) + { + ProcessSetData(buff, len); + } + +} + + +/* processes statements in the buffer and returns amount processed */ +// 09-13-2004 BED Modified loop to silence compiler warning +static int ProcessInBuffer(char *buff, int len) +{ + char *pos; + int oldlen = len; + + pos = FindFinal(buff, len); + //while (len > 0 && (pos = FindFinal(buff, len))) + while ((len > 0) && (pos != NULL)) + { + DOXCODE(buff,pos - buff, enc1); + ProcessStatement(buff, pos - buff); + len -= (pos - buff) + 7; + buff = pos + 7; //skip the final + if (len>0) + pos = FindFinal(buff, len); + } + return oldlen - len; //amount processed +} + +/* call a single callback function */ +static void CallReqCallback(int reqindex, int success, time_t modified, char *data, int length) +{ + serverreq_t *req; + if (reqindex < 0 || reqindex >= ArrayLength(serverreqs)) + return; + req = (serverreq_t *)ArrayNth(serverreqs, reqindex); + if (req->callback) + switch (req->reqtype) + { + case rt_authcb: +#ifndef GSI_UNICODE + ((PersAuthCallbackFn )req->callback)(req->localid, req->profileid, success, data, req->instance); +#else + { + unsigned short* data_W = UTF8ToUCS2StringAlloc(data); + ((PersAuthCallbackFn )req->callback)(req->localid, req->profileid, success, data_W, req->instance); + gsifree(data_W); + } +#endif + break; + case rt_datacb: + ((PersDataCallbackFn )req->callback)(req->localid,req->profileid,req->pdtype, req->pdindex, success, modified, data, length, req->instance); + break; + case rt_savecb: + ((PersDataSaveCallbackFn )req->callback)(req->localid, req->profileid, req->pdtype, req->pdindex,success, modified, req->instance); + break; + case rt_profilecb: + ((ProfileCallbackFn )req->callback)(req->localid, req->profileid, success, req->instance); + break; + } + ArrayDeleteAt(serverreqs,reqindex); +} + +/* if we get disconnected while callbacks are still pending, make sure we +call all of them, with a success of 0 */ +static void ClosePendingCallbacks() +{ + int i; + + if (serverreqs == NULL) + return; + for (i = ArrayLength(serverreqs) - 1 ; i >= 0 ; i--) + { + char connerror[] = "\x13\x1D\x1\x4\x0\x0\x0\x28\x1F\x6\x45\x34\x3F\x1\x1B"; + //"Connection Lost" + DOXCODE(connerror, sizeof(connerror)-1, enc3); + + CallReqCallback(i,0,0,connerror,0); + + } + ArrayFree(serverreqs); + serverreqs = NULL; +} + + + +/****************************************************************************/ +/* BUCKET FUNCTIONS */ +/****************************************************************************/ +int GetTeamIndex(statsgame_t game, int tnum) +{ + FIXGAME(game, tnum); + return *(int *)ArrayNth(game->teamnums,tnum); +} +int GetPlayerIndex(statsgame_t game, int pnum) +{ + FIXGAME(game, pnum); + return *(int *)ArrayNth(game->playernums,pnum); +} + +static int ServerOpInt(statsgame_t game,char *name, BucketFunc func, int value, int index) +{ + int *ret; + DoFunc(func, game, name, &value, bt_int, ret); + + GSI_UNUSED(index); + return *(int *)ret; +} +static double ServerOpFloat(statsgame_t game,char *name, BucketFunc func, double value, int index) +{ + double *ret; + DoFunc(func, game, name, &value, bt_float, ret); + + GSI_UNUSED(index); + return *(double *)ret; +} +static char *ServerOpString(statsgame_t game,char *name, BucketFunc func, char *value, int index) +{ + char *ret; + DoFunc(func, game, name, value, bt_string, ret); + + GSI_UNUSED(index); + return ret; +} + +static int TeamOpInt(statsgame_t game,char *name, BucketFunc func, int value, int index) +{ + char fullname[64]; + sprintf(fullname, "%s_t%d",name, GetTeamIndex(game, index)); + return ServerOpInt(game, fullname, func, value, index); +} +static double TeamOpFloat(statsgame_t game,char *name, BucketFunc func, double value, int index) +{ + char fullname[64]; + sprintf(fullname, "%s_t%d",name, GetTeamIndex(game, index)); + return ServerOpFloat(game, fullname, func, value, index); +} +static char *TeamOpString(statsgame_t game,char *name, BucketFunc func, char *value, int index) +{ + char fullname[64]; + sprintf(fullname, "%s_t%d",name, GetTeamIndex(game, index)); + return ServerOpString(game, fullname, func, value, index); +} + +static int PlayerOpInt(statsgame_t game,char *name, BucketFunc func, int value, int index) +{ + char fullname[64]; + sprintf(fullname, "%s_%d",name, GetPlayerIndex(game, index)); + return ServerOpInt(game, fullname, func, value, index); +} +static double PlayerOpFloat(statsgame_t game,char *name, BucketFunc func, double value, int index) +{ + char fullname[64]; + sprintf(fullname, "%s_%d",name, GetPlayerIndex(game, index)); + return ServerOpFloat(game, fullname, func, value, index); +} +static char *PlayerOpString(statsgame_t game,char *name, BucketFunc func, char *value, int index) +{ + char fullname[64]; + sprintf(fullname, "%s_%d",name, GetPlayerIndex(game, index)); + return ServerOpString(game, fullname, func, value, index); +} + +static char *CreateBucketSnapShot(bucketset_t buckets) +{ + return DumpBucketSet(buckets); +} + +#ifdef __cplusplus +} +#endif diff --git a/xrGameSpy/gamespy/gstats/gstats.dsw b/xrGameSpy/gamespy/gstats/gstats.dsw new file mode 100644 index 00000000000..2552d7e0bfa --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gstats.dsw @@ -0,0 +1,117 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gp_stats"=.\gp_stats\gp_stats.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/gp_stats", RUFBAAAA + .\gp_stats + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ladderTrack"=.\ladderTrack\ladderTrack.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/ladderTrack", YNHCAAAA + .\laddertrack + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "multiTrack"=.\multiTrack\multiTrack.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/multiTrack", VYZBAAAA + .\multitrack + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "persisttest"=.\persisttest\persisttest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/persisttest", BBVAAAAA + .\persisttest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "statstest"=.\statstest\statstest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/gstats/statstest + .\statstest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "track"=.\track\track.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/track", OAACAAAA + .\track + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats", BSGAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/gstats/gstats.h b/xrGameSpy/gamespy/gstats/gstats.h new file mode 100644 index 00000000000..b1f69bfb125 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gstats.h @@ -0,0 +1,389 @@ +/****** +gstats.h +GameSpy Stats/Tracking SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +****** + +Please see the GameSpy Stats and Tracking SDK documentation for more info + +08-23-00 - DDW +Fixed a problem that prevented opening/closing/re-opening of the connection within +a single session. + +*****/ + +#ifndef _GSTATS_H_ +#define _GSTATS_H_ + + +/******** +INCLUDES +********/ +#include "../common/gsCommon.h" +#include "gbucket.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) + // Warnings are generated because we store function ptrs into a void* array +#pragma warning(disable: 4152) // function to data ptr +#pragma warning(disable: 4055) // data to function ptr +#endif + + +/******** +TYPEDEFS +********/ + + +/* The abstracted "game" structure */ +typedef struct statsgame_s *statsgame_t; + +/* All of the operations you can do on a bucket */ +typedef enum {bo_set, bo_add, bo_sub, bo_mult, bo_div, bo_concat, bo_avg} bucketop_t; +#define NUMOPS 7 + +/* The types of buckets (server info, team info, or player info) */ +typedef enum {bl_server, bl_team, bl_player} bucketlevel_t; + +/* Init states for async initialization */ +typedef enum {init_none, init_failed, init_connecting, init_awaitchallenge, init_awaitsessionkey, init_complete} initstate_t; + +/* Used by the bucket operation macros */ +typedef void *(*BucketFunc)(bucketset_t set, char *name,void *value); +typedef int (*SetIntFunc)(statsgame_t game,char *name, BucketFunc func, int value, int index); +typedef double (*SetFloatFunc)(statsgame_t game,char *name, BucketFunc func, double value, int index); +typedef char *(*SetStringFunc)(statsgame_t game,char *name, BucketFunc func, char *value, int index); +extern BucketFunc bucketfuncs[NUMOPS]; +extern void * bopfuncs[][3]; + +/******** +DEFINES +********/ +/* Error codes */ +#define GE_NOERROR 0 +#define GE_NOSOCKET 1 /* Unable to create a socket */ +#define GE_NODNS 2 /* Unable to resolve a DNS name */ +#define GE_NOCONNECT 3 /* Unable to connect to stats server, or connection lost */ +#define GE_BUSY 4 /* Not used */ +#define GE_DATAERROR 5 /* Bad data from the stats server */ +#define GE_CONNECTING 6 /* Connect did no immediately complete. Call InitStatsThink() */ +#define GE_TIMEDOUT 7 /* Connect attempt timed out */ + +/* Types of snapshots, update (any snapshot that is not final) or final */ +#define SNAP_UPDATE 0 +#define SNAP_FINAL 1 + +/* If you want to allow disk logging in case the stats server isn't available. +This has SERIOUS security repercussions, so please read the docs before turning this on */ +#define ALLOW_DISK + +#if defined(NOFILE) + #undef ALLOW_DISK +#endif /* make sure it's never defined on platforms with no disk! */ + +/******** +VARS +********/ + +/* You need to fill these in with your game-specific info */ +extern char gcd_secret_key[256]; +extern char gcd_gamename[256]; + +/* The hostname of the stats server. +If the app resolves the hostname, an +IP can be stored here before calling +InitStatsConnection */ +extern char StatsServerHostname[64]; + + +/******** +PROTOTYPES +********/ +#ifndef GSI_UNICODE +#define GenerateAuth GenerateAuthA +#define SendGameSnapShot SendGameSnapShotA +#define NewPlayer NewPlayerA +#define NewTeam NewTeamA +#else +#define GenerateAuth GenerateAuthW +#define SendGameSnapShot SendGameSnapShotW +#define NewPlayer NewPlayerW +#define NewTeam NewTeamW +#endif + +/******** +InitStatsConnection + +DESCRIPTION +Opens a connection to the stats server. Should be done before calling +NewGame or any of the bucket/snapshot functions. May block for 1-2 secs +while the connection is established so you will want to do this before +gameplay starts or in another thread. + +PARAMETERS +gameport: integer port associated with your server (may be the same as + your developer spec query port). Used only to help players differentiate + between servers on the same machine (no queries are done on it). If not + appropriate for your game, pass in 0. + +RETURNS +GE_NODNS: Unable to resolve stats server DNS +GE_NOSOCKET: Unable to create data socket +GE_NOCONNECT: Unable to connect to stats server +GE_DATAERROR: Unable to receive challenge from stats server, or bad challenge +GE_NOERROR: Connected to stats server and ready to send data + +Note: You can still call ANY of the other Stats SDK functions, even if the +connection fails. If you have disk logging enabled, these calls will be logged +for future sending, otherwise they will be discarded. +*********/ +int InitStatsConnection(int gameport); +int InitStatsAsync(int gameport, gsi_time theInitTimeout); +int InitStatsThink(); + + +/******** +StatsThink + +DESCRIPTION +Eats up any incoming keep-alive messages that are sent by the stats server. +Returns any errors occur because of a socket problem or if the SDK was +not completely initialized. + +RETURNS +1 if no errors occured during read, 0 on all other errors +********/ +int StatsThink(); + +/******** +IsStatsConnected + +DESCRIPTION +Returns whether or not you are currently connected to the stats server. Even +if your initial connection was successful, you may lose connection later and +want to try to reconnnect + +RETURNS +1 if connected, 0 otherwise +*********/ +int IsStatsConnected(); + +/******** +CloseStatsConnection + +DESCRIPTION +Closes the connection to the stats server. You should do this when done +with the connection. +*********/ +void CloseStatsConnection(void); + +/******** +GetChallenge + +DESCRIPTION +Returns a string that should be sent to clients for authentication +(using GenerateAuth). You do not have to free the string when done. +This string will be constant for the entire length of the game and is +generated during the call to NewGame. + +PARAMETERS +game: Game to return the challenge string for. If game is NULL, the last + game created with NewGame will be used. + +RETURNS +A string to send to clients so they can authorize. If you game is NULL and +you haven't created a game with NewGame, it returns "NULLGAME". +*********/ +char *GetChallenge(statsgame_t game); + +/******** +GenerateAuth + +DESCRIPTION +Should be used on the CLIENT SIDE to generate an authentication reply +(auth_N) for a given challenge and password (CD Key or Profile password) + +PARAMETERS +challenge: The challenge string sent by the server. On the server this + should be generated with GetChallenge +password: The CD Key (un-hashed) or profile password +response: The output authentication string + +RETURNS +A pointer to response +*********/ +char *GenerateAuth(const char *challenge, const gsi_char *password,/*[out]*/char response[33]); + +/******** +NewGame + +DESCRIPTION +Creates a new game for logging and registers it with the stats server. +Creates all the game structures, including buckets if needed. + +PARAMETERS +usebuckets: Set to 1 for bucket based logging, 0 if you are going to create + the snapshots yourself. See the SDK for more info. + +RETURNS +A pointer to the new game. If you are not connected, and disk logging is +disabled, this will be NULL. You can still pass NULL to any function without +causing any errors. +Note: The last game created by NewGame is stored internally. +If you only create / use one game at a time, you can simply discard +the return value and pass NULL for game into all of the bucket and snapshot functions. +*********/ +statsgame_t NewGame(int usebuckets); + +/******** +FreeGame + +DESCRIPTION +Frees a game and its associated structures (including buckets). You should +send a final snapshot for the game (using SendGameSnapShot with SNAP_FINAL) +before freeing the game. + +PARAMETERS +game: The game you want to free. If set to NULL, it will free the last + game created with NewGame. +*********/ +void FreeGame(statsgame_t game); + +/******** +SendGameSnapShot + +DESCRIPTION +Sends a snapshot of information about the current game. If bucket based +logging is enabled the snapshot will be generated from the buckets, otherwise +you should provide it in "snapshot". + +PARAMETERS +game: The game to send a snapshot for. If set to NULL, the last game + created with NewGame will be used. +snapshot: The snapshot to send. If you are using buckets, this will not be + used, so you can pass in NULL +final: If this is SNAP_UPDATE, the game is marked as in progress, if it + is SNAP_FINAL, the game is marked as complete. + +RETURNS +GE_DATAERROR: If game is NULL and the last game created by NewGame failed + (because the connection was lost and disk logging is disabled) +GE_NOCONNECT: If the connection is lost and disk logging is disabled +GE_NOERROR: The update was sent, or disk logging is enabled and the game was logged +*********/ +int SendGameSnapShot(statsgame_t game, const gsi_char *snapshot, int final); + +/****************************** +BUCKET FUNCTION PROTOTYPES +These functions are only used for bucket-based logging +*******************************/ + +/******** +Bucket_____Op + +DESCRIPTION +Performs an operation on a bucket for a game. If the bucket doesn't exist already, +the call will set the bucket to whatever "value" is. +You can always create each bucket explicitly by using bo_set with whatever initial +value you want the bucket to have. +Valid operations include set, add, subtract, multiply, divide, concat, and average. +Each bucket type (int, float, or string) has its own operation function, always call +the same one for each bucket (i.e. don't create a bucket with BucketIntOp then try to +add a float with BucketFloatOp). + +PARAMETERS +game: The game to send containing the bucket you want to operate on. + If set to NULL, the last game created with NewGame will be used. +name: The name of the bucket to update. Note that for player or team buckets, this name + does NOT include the "_" or "_t" (e.g. "score" for player score, not "score_N"). The underscore + and number will be added automatically. +operation: One of the bucketop_t enums defined above +value: Argument for the operation (bucket OP= value, e.g. bucket += value, bucket *= value) +bucketlevel: One of the bucketlevel_t enums defined above. Determines whether you are + referring to a server, player, or team bucket. Note that you can have seperate buckets of + each type with the same name (e.g. "score" player bucket for each player and "score" team + bucket for each team) +index: For player or team buckets, the game index of the player or team (as passed to NewPlayer or + NewTeam). This will be translated to the actual index internally. + Not used for server buckets (bl_server). +*********/ +#define BucketIntOp(game, name, operation, value, bucketlevel, index) (((SetIntFunc)bopfuncs[bucketlevel][bt_int])(game,name,bucketfuncs[operation],value,index) ) +#define BucketFloatOp(game, name, operation, value, bucketlevel, index) (((SetFloatFunc)bopfuncs[bucketlevel][bt_float])(game,name,bucketfuncs[operation],value,index) ) +#define BucketStringOp(game, name, operation, value, bucketlevel, index) (((SetStringFunc)bopfuncs[bucketlevel][bt_string])(game,name,bucketfuncs[operation],value,index) ) + +/******** +NewPlayer + +DESCRIPTION +Adds a "player" to the game and assigns them an internal player number. Sets +their connect time to the number of seconds since NewGame was called. + +PARAMETERS +game: The game to add the player to. If set to NULL, the last game created + with NewGame will be used. +pnum: Your internal reference for this player, use this value in any calls + to the Bucket___Op functions. +name: The name for this player. If you don't have one yet, set it to empty ("") + then call: BucketStringOp(game,"player",bo_set,realplayername, bl_player, pnum) + when you get a realplayername. +**********/ +void NewPlayer(statsgame_t game,int pnum, gsi_char *name); + +/******** +RemovePlayer + +DESCRIPTION +Removes a "player" from the game and sets their disconnect time to the +number of seconds since NewGame was called. + +PARAMETERS +game: The game to remove the player from. If set to NULL, the last game created + with NewGame will be used. +pnum: Your internal reference for this player, use this value in any calls + to the Bucket___Op functions. +**********/ +void RemovePlayer(statsgame_t game,int pnum); + +/********* +NewTeam +RemoveTeam + +DESCRIPTION +See the player functions above. These function the same, except for teams +**********/ +void NewTeam(statsgame_t game,int tnum, gsi_char *name); +void RemoveTeam(statsgame_t game,int tnum); + +/********* +GetPlayerIndex +GetTeamIndex + +DESCRIPTION +Gets the gstats reference number for that player or team. For +example, if you start the game and players 0, 1, and 2 join, then player 1 +leaves, and another player 1 joins, the new player 1 will be referenced +by gstats as 3. If player 3 joins, it will be referenced as player 4, and so on. +Normally this doesn't matter to you, but if you want to do a key name or key value +that references a player or team number (for example, setting a player's team number), +you need to use the translated values. + +PARAMETERS +game: The game to retrieve the translated value for. If set to NULL,the last game created + with NewGame will be used. +pnum/tnum: Your internal player or team number (as sent to NewTeam/NewPlayer) +**********/ +int GetPlayerIndex(statsgame_t game, int pnum); +int GetTeamIndex(statsgame_t game, int tnum); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/gstats/gstats.sln b/xrGameSpy/gamespy/gstats/gstats.sln new file mode 100644 index 00000000000..79e5f8c7ee5 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gstats.sln @@ -0,0 +1,125 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gp_stats", "gp_stats\gp_stats.vcproj", "{498F506A-B4A6-41C7-897F-5327D3557E5A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ladderTrack", "ladderTrack\ladderTrack.vcproj", "{4E864039-AD93-4493-ACDE-836F3C15E240}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multiTrack", "multiTrack\multiTrack.vcproj", "{844143D4-0F5E-4943-852C-1FD3DA5F83FF}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "persisttest", "persisttest\persisttest.vcproj", "{DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "track", "track\track.vcproj", "{43D71A90-1415-4DBE-B0B1-6FF03337C3B3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "statstest", "statstest\statstest.vcproj", "{B6D667C1-66B2-446D-97AA-06CB110E9D3B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 7 + SccProjectUniqueName0 = gp_stats\\gp_stats.vcproj + SccProjectName0 = $/IGNCP/Gamespy/GOA + SccLocalPath0 = .. + CanCheckoutShared = true + SccProjectFilePathRelativizedFromConnection0 = gstats\\gp_stats\\ + SccProjectUniqueName1 = ladderTrack\\ladderTrack.vcproj + SccProjectName1 = $/IGNCP/Gamespy/GOA + SccLocalPath1 = .. + CanCheckoutShared = true + SccProjectFilePathRelativizedFromConnection1 = gstats\\ladderTrack\\ + SccProjectUniqueName2 = multiTrack\\multiTrack.vcproj + SccProjectName2 = $/IGNCP/Gamespy/GOA + SccLocalPath2 = .. + CanCheckoutShared = true + SccProjectFilePathRelativizedFromConnection2 = gstats\\multiTrack\\ + SccProjectUniqueName3 = persisttest\\persisttest.vcproj + SccProjectName3 = $/IGNCP/Gamespy/GOA + SccLocalPath3 = .. + CanCheckoutShared = true + SccProjectFilePathRelativizedFromConnection3 = gstats\\persisttest\\ + SccProjectUniqueName4 = track\\track.vcproj + SccProjectName4 = $/IGNCP/Gamespy/GOA + SccLocalPath4 = .. + CanCheckoutShared = true + SccProjectFilePathRelativizedFromConnection4 = gstats\\track\\ + SccProjectUniqueName5 = statstest\\statstest.vcproj + SccProjectName5 = $/IGNCP/Gamespy/GOA + SccLocalPath5 = .. + CanCheckoutShared = true + SccProjectFilePathRelativizedFromConnection5 = gstats\\statstest\\ + SccLocalPath6 = . + CanCheckoutShared = true + SolutionUniqueID = {044D4624-4E67-40C7-BE5A-5ACB63B52977} + EndGlobalSection + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + Unicode Debug = Unicode Debug + Unicode Release = Unicode Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Debug.ActiveCfg = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Debug.Build.0 = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Release.ActiveCfg = Release|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Release.Build.0 = Release|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Debug.ActiveCfg = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Debug.Build.0 = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Release.ActiveCfg = Release|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Release.Build.0 = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Debug.ActiveCfg = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Debug.Build.0 = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Release.ActiveCfg = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Release.Build.0 = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Debug.ActiveCfg = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Debug.Build.0 = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Release.ActiveCfg = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Release.Build.0 = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Debug.ActiveCfg = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Debug.Build.0 = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Release.ActiveCfg = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Release.Build.0 = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Debug.ActiveCfg = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Debug.Build.0 = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Release.ActiveCfg = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Release.Build.0 = Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Debug.ActiveCfg = Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Debug.Build.0 = Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Release.ActiveCfg = Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Release.Build.0 = Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Debug.ActiveCfg = Unicode Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Debug.Build.0 = Unicode Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Release.ActiveCfg = Unicode Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Release.Build.0 = Unicode Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Debug.ActiveCfg = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Debug.Build.0 = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Release.ActiveCfg = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Release.Build.0 = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Debug.ActiveCfg = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Debug.Build.0 = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Release.ActiveCfg = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Release.Build.0 = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Debug.ActiveCfg = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Debug.Build.0 = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Release.ActiveCfg = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Release.Build.0 = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Debug.ActiveCfg = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Debug.Build.0 = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Release.ActiveCfg = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/gstats.vssscc b/xrGameSpy/gamespy/gstats/gstats.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gstats.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/gstats_vs2005.ncb b/xrGameSpy/gamespy/gstats/gstats_vs2005.ncb new file mode 100644 index 00000000000..8393f2506e3 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/gstats_vs2005.ncb differ diff --git a/xrGameSpy/gamespy/gstats/gstats_vs2005.sln b/xrGameSpy/gamespy/gstats/gstats_vs2005.sln new file mode 100644 index 00000000000..5edb2b69e49 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/gstats_vs2005.sln @@ -0,0 +1,75 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gp_stats_vs2005", "gp_stats\gp_stats_vs2005.vcproj", "{498F506A-B4A6-41C7-897F-5327D3557E5A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ladderTrack_vs2005", "ladderTrack\ladderTrack_vs2005.vcproj", "{4E864039-AD93-4493-ACDE-836F3C15E240}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multiTrack_vs2005", "multiTrack\multiTrack_vs2005.vcproj", "{844143D4-0F5E-4943-852C-1FD3DA5F83FF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "persisttest_vs2005", "persisttest\persisttest_vs2005.vcproj", "{DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "statstest_vs2005", "statstest\statstest_vs2005.vcproj", "{B6D667C1-66B2-446D-97AA-06CB110E9D3B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "track_vs2005", "track\track_vs2005.vcproj", "{43D71A90-1415-4DBE-B0B1-6FF03337C3B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Debug|Win32.ActiveCfg = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Debug|Win32.Build.0 = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Release|Win32.ActiveCfg = Release|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Release|Win32.Build.0 = Release|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {498F506A-B4A6-41C7-897F-5327D3557E5A}.Unicode Release|Win32.Build.0 = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Debug|Win32.Build.0 = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Release|Win32.ActiveCfg = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Release|Win32.Build.0 = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {4E864039-AD93-4493-ACDE-836F3C15E240}.Unicode Release|Win32.Build.0 = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Debug|Win32.Build.0 = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Release|Win32.ActiveCfg = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Release|Win32.Build.0 = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {844143D4-0F5E-4943-852C-1FD3DA5F83FF}.Unicode Release|Win32.Build.0 = Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Debug|Win32.Build.0 = Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Release|Win32.ActiveCfg = Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Release|Win32.Build.0 = Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {DA5847A1-9526-43D4-B1C5-9CBBB5526AEF}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Debug|Win32.Build.0 = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Release|Win32.ActiveCfg = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Release|Win32.Build.0 = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {B6D667C1-66B2-446D-97AA-06CB110E9D3B}.Unicode Release|Win32.Build.0 = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Debug|Win32.ActiveCfg = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Debug|Win32.Build.0 = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Release|Win32.ActiveCfg = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Release|Win32.Build.0 = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {43D71A90-1415-4DBE-B0B1-6FF03337C3B3}.Unicode Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/gstats_vs2005.suo b/xrGameSpy/gamespy/gstats/gstats_vs2005.suo new file mode 100644 index 00000000000..b052c62beb2 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/gstats_vs2005.suo differ diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/HostOrJoinDlg.cpp b/xrGameSpy/gamespy/gstats/ladderTrack/HostOrJoinDlg.cpp new file mode 100644 index 00000000000..85de2c74146 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/HostOrJoinDlg.cpp @@ -0,0 +1,69 @@ +// HostOrJoinDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ladderTrack.h" +#include "HostOrJoinDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg dialog + + +CHostOrJoinDlg::CHostOrJoinDlg(CWnd* pParent /*=NULL*/) + : CDialog(CHostOrJoinDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CHostOrJoinDlg) + m_joinAddress = _T(""); + m_hostOrJoin = 0; + //}}AFX_DATA_INIT +} + + +void CHostOrJoinDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CHostOrJoinDlg) + DDX_Text(pDX, IDC_JOIN_ADDRESS, m_joinAddress); + DDX_Radio(pDX, IDC_HOST, m_hostOrJoin); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CHostOrJoinDlg, CDialog) + //{{AFX_MSG_MAP(CHostOrJoinDlg) + ON_EN_SETFOCUS(IDC_JOIN_ADDRESS, OnSetfocusJoinAddress) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg message handlers + +void CHostOrJoinDlg::OnOK() +{ + UpdateData(); + + // Check for no join address. + ///////////////////////////// + if((m_hostOrJoin == HOSTORJOIN_JOIN) && m_joinAddress.IsEmpty()) + { + MessageBox("Please enter the address of the host to connect to"); + return; + } + + CDialog::OnOK(); +} + +void CHostOrJoinDlg::OnSetfocusJoinAddress() +{ + // Make sure its on join. + ///////////////////////// + UpdateData(); + m_hostOrJoin = HOSTORJOIN_JOIN; + UpdateData(FALSE); +} diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/HostOrJoinDlg.h b/xrGameSpy/gamespy/gstats/ladderTrack/HostOrJoinDlg.h new file mode 100644 index 00000000000..98fbc34eab6 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/HostOrJoinDlg.h @@ -0,0 +1,51 @@ +#if !defined(AFX_HOSTORJOINDLG_H__7A7BDB42_5AA8_45CD_9DD1_0EA7FC3A723F__INCLUDED_) +#define AFX_HOSTORJOINDLG_H__7A7BDB42_5AA8_45CD_9DD1_0EA7FC3A723F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// HostOrJoinDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg dialog + +#define HOSTORJOIN_HOST 0 +#define HOSTORJOIN_JOIN 1 + +class CHostOrJoinDlg : public CDialog +{ +// Construction +public: + CHostOrJoinDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CHostOrJoinDlg) + enum { IDD = IDD_HOST_OR_JOIN }; + CString m_joinAddress; + int m_hostOrJoin; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CHostOrJoinDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CHostOrJoinDlg) + virtual void OnOK(); + afx_msg void OnSetfocusJoinAddress(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_HOSTORJOINDLG_H__7A7BDB42_5AA8_45CD_9DD1_0EA7FC3A723F__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/LoginDlg.cpp b/xrGameSpy/gamespy/gstats/ladderTrack/LoginDlg.cpp new file mode 100644 index 00000000000..d8c7ef749dd --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/LoginDlg.cpp @@ -0,0 +1,188 @@ +// LoginDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ladderTrack.h" +#include "LoginDlg.h" +#include "../../common/gsAvailable.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + + +CLoginDlg::CLoginDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLoginDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoginDlg) + m_email = _T(""); + m_nick = _T(""); + m_password = _T(""); + //}}AFX_DATA_INIT +} + + +void CLoginDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoginDlg) + DDX_Text(pDX, IDC_EMAIL, m_email); + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_PASSWORD, m_password); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoginDlg, CDialog) + //{{AFX_MSG_MAP(CLoginDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg message handlers + +GPResult checkResult; +int checkProfile; + +void CheckUserCallback(GPConnection * connection, void * _arg, void * param) +{ + GPCheckResponseArg * arg = (GPCheckResponseArg *)_arg; + + checkResult = arg->result; + checkProfile = arg->profile; +} + +void CLoginDlg::OnOK() +{ + GPConnection connection; + HCURSOR hourglass; + HCURSOR lastCursor; + GPResult result; + + UpdateData(); + + // CHECK FOR NO ACCOUNT INFO + //////////////////////////// + if(m_email.IsEmpty() || m_nick.IsEmpty() || m_password.IsEmpty()) + { + MessageBox("Please fill in all the account information."); + return; + } + + // Make sure the backend is available + GSIACResult aResult = GSIACWaiting; + GSIStartAvailableCheck(gcd_gamename); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + msleep(5); + } + + if (aResult == GSIACUnavailable) + { + MessageBox("GameSpy backend services are not available."); + return; + } + + // INITIALIZE GP + //////////////// + if(gpInitialize(&connection, 535, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR) + { + MessageBox("Error initializing the login system."); + return; + } + + // wait cursor on + ///////////////// + hourglass = LoadCursor(NULL, IDC_WAIT); + if(hourglass) + lastCursor = SetCursor(hourglass); + + // CHECK FOR THE ACCOUNT SPECIFIED + ////////////////////////////////// + result = gpCheckUser(&connection, m_nick, m_email, m_password, GP_BLOCKING, CheckUserCallback, NULL); + + // wait cursor off + ////////////////// + if(hourglass) + SetCursor(lastCursor); + + // DESTROY THE GP OBJECT + //////////////////////// + gpDestroy(&connection); + + // CHECK FOR AN ERROR + ///////////////////// + if(result != GP_NO_ERROR) + { + MessageBox("Error verifying the account."); + return; + } + + // CHECK THE RESULT + /////////////////// + if(checkResult != GP_NO_ERROR) + { + if(checkResult == GP_CHECK_BAD_EMAIL) + MessageBox("Invalid e-mail."); + else if(checkResult == GP_CHECK_BAD_NICK) + MessageBox("Invalid nick."); + else if(checkResult == GP_CHECK_BAD_PASSWORD) + MessageBox("Invalid password."); + else + MessageBox("Error verifying the account."); + return; + } + + // save the login info for next time + //////////////////////////////////// + FILE * file; + file = fopen("login.txt", "wt"); + if(file) + { + fprintf(file, "%s\n%s\n%s", m_email, m_nick, m_password); + fclose(file); + } + + // STORE THE PROFILE ID + /////////////////////// + m_profile = checkProfile; + + CDialog::OnOK(); +} + +BOOL CLoginDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // load login info + ////////////////// + FILE * file; + file = fopen("login.txt", "rt"); + if(file) + { + char buffer[512]; + + if(fgets(buffer, sizeof(buffer), file)) + m_email = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_nick = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_password = buffer; + + fclose(file); + + m_email.Remove('\n'); + m_nick.Remove('\n'); + m_password.Remove('\n'); + } + + UpdateData(FALSE); + + return TRUE; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/LoginDlg.h b/xrGameSpy/gamespy/gstats/ladderTrack/LoginDlg.h new file mode 100644 index 00000000000..26d4d1f1f03 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/LoginDlg.h @@ -0,0 +1,50 @@ +#if !defined(AFX_LOGINDLG_H__58A8C6B5_2AD3_4C62_882E_DC1F8D104CC5__INCLUDED_) +#define AFX_LOGINDLG_H__58A8C6B5_2AD3_4C62_882E_DC1F8D104CC5__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LoginDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + +class CLoginDlg : public CDialog +{ +// Construction +public: + int m_profile; + CLoginDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoginDlg) + enum { IDD = IDD_LOGIN }; + CString m_email; + CString m_nick; + CString m_password; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoginDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoginDlg) + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOGINDLG_H__58A8C6B5_2AD3_4C62_882E_DC1F8D104CC5__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/StdAfx.cpp b/xrGameSpy/gamespy/gstats/ladderTrack/StdAfx.cpp new file mode 100644 index 00000000000..96d55a4b4c0 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ladderTrack.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/StdAfx.h b/xrGameSpy/gamespy/gstats/ladderTrack/StdAfx.h new file mode 100644 index 00000000000..83d5a02b563 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/StdAfx.h @@ -0,0 +1,32 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__207466EE_5E75_4F57_8FC6_639F9C33B505__INCLUDED_) +#define AFX_STDAFX_H__207466EE_5E75_4F57_8FC6_639F9C33B505__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "../gstats.h" +#include "../../gp/gp.h" +#include "../../ghttp/ghttp.h" +//#include "../../gt/gt.h" +//#include "../../gt/gtEncode.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__207466EE_5E75_4F57_8FC6_639F9C33B505__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/WaitingDlg.cpp b/xrGameSpy/gamespy/gstats/ladderTrack/WaitingDlg.cpp new file mode 100644 index 00000000000..60eeffc116c --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/WaitingDlg.cpp @@ -0,0 +1,43 @@ +// WaitingDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ladderTrack.h" +#include "WaitingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg dialog + + +CWaitingDlg::CWaitingDlg(CWnd* pParent /*=NULL*/) + : CDialog(CWaitingDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CWaitingDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CWaitingDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CWaitingDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CWaitingDlg, CDialog) + //{{AFX_MSG_MAP(CWaitingDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg message handlers diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/WaitingDlg.h b/xrGameSpy/gamespy/gstats/ladderTrack/WaitingDlg.h new file mode 100644 index 00000000000..e5d262bd9cf --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/WaitingDlg.h @@ -0,0 +1,46 @@ +#if !defined(AFX_WAITINGDLG_H__874B6CC6_8058_4BDF_B714_8FE3610A12B4__INCLUDED_) +#define AFX_WAITINGDLG_H__874B6CC6_8058_4BDF_B714_8FE3610A12B4__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// WaitingDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg dialog + +class CWaitingDlg : public CDialog +{ +// Construction +public: + CWaitingDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CWaitingDlg) + enum { IDD = IDD_WAITING }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CWaitingDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CWaitingDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_WAITINGDLG_H__874B6CC6_8058_4BDF_B714_8FE3610A12B4__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.cpp b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.cpp new file mode 100644 index 00000000000..a2542dd0f21 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.cpp @@ -0,0 +1,63 @@ +// ladderTrack.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "ladderTrack.h" +#include "ladderTrackDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp + +BEGIN_MESSAGE_MAP(CLadderTrackApp, CWinApp) + //{{AFX_MSG_MAP(CLadderTrackApp) + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp construction + +CLadderTrackApp::CLadderTrackApp() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CLadderTrackApp object + +CLadderTrackApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp initialization + +BOOL CLadderTrackApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CLadderTrackDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + } + else if (nResponse == IDCANCEL) + { + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.dsp b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.dsp new file mode 100644 index 00000000000..9c7c727280f --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.dsp @@ -0,0 +1,679 @@ +# Microsoft Developer Studio Project File - Name="ladderTrack" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ladderTrack - 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 "ladderTrack.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 "ladderTrack.mak" CFG="ladderTrack - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ladderTrack - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ladderTrack - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/ladderTrack", YNHCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ladderTrack - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ladderTrack - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "RECV_LOG" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ladderTrack - Win32 Release" +# Name "ladderTrack - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\HostOrJoinDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\ladderTrack.cpp +# End Source File +# Begin Source File + +SOURCE=.\ladderTrack.rc +# End Source File +# Begin Source File + +SOURCE=.\ladderTrackDlg.cpp + +!IF "$(CFG)" == "ladderTrack - Win32 Release" + +!ELSEIF "$(CFG)" == "ladderTrack - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\LoginDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\WaitingDlg.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\HostOrJoinDlg.h +# End Source File +# Begin Source File + +SOURCE=.\ladderTrack.h +# End Source File +# Begin Source File + +SOURCE=.\ladderTrackDlg.h +# End Source File +# Begin Source File + +SOURCE=.\LoginDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\WaitingDlg.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\ladderTrack.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ladderTrack.rc2 +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gp\gp.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.h +# End Source File +# End Group +# Begin Group "StatsSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gbucket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\gstats.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gstats.h +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.h b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.h new file mode 100644 index 00000000000..04348d51ebe --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.h @@ -0,0 +1,47 @@ +// ladderTrack.h : main header file for the LADDERTRACK application +// + +#if !defined(AFX_LADDERTRACK_H__E9856F44_580A_48C0_ABFF_6FFA9BA944A3__INCLUDED_) +#define AFX_LADDERTRACK_H__E9856F44_580A_48C0_ABFF_6FFA9BA944A3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp: +// See ladderTrack.cpp for the implementation of this class +// + +class CLadderTrackApp : public CWinApp +{ +public: + CLadderTrackApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLadderTrackApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CLadderTrackApp) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LADDERTRACK_H__E9856F44_580A_48C0_ABFF_6FFA9BA944A3__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.rc b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.rc new file mode 100644 index 00000000000..6592521ef67 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.rc @@ -0,0 +1,241 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\ladderTrack.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\ladderTrack.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_LADDERTRACK_DIALOG DIALOGEX 0, 0, 212, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "ladderTrack" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Exit",IDOK,155,5,50,14 + PUSHBUTTON "Logout",IDC_LOGOUT,155,21,50,14 + PUSHBUTTON "Start Race",IDC_START_RACE,10,15,50,14 + LTEXT "Info",IDC_INFO,70,15,80,8 + CONTROL "Progress1",IDC_LOCAL_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,7,48,80,14 + CONTROL "Progress1",IDC_REMOTE_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,113,48,80,14 + LTEXT "You:",IDC_STATIC,7,38,16,8 + LTEXT "Opponent:",IDC_STATIC,113,38,34,8 + LTEXT "Use Z && X to race",IDC_STATIC,70,25,57,8 + LTEXT "Ladder Position:",IDC_STATIC,7,68,52,8 + LTEXT "Ladder Position:",IDC_STATIC,113,68,52,8 + LTEXT "123",IDC_LOCAL_POSITION,63,68,25,8 + LTEXT "123",IDC_REMOTE_POSITION,167,68,35,8 + PUSHBUTTON "Update Positions",IDC_UPDATE_POSITIONS,73,79,65,14 +END + +IDD_HOST_OR_JOIN DIALOG DISCARDABLE 0, 0, 165, 50 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Host or Join?" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Host",IDC_HOST,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7, + 7,31,10 + CONTROL "Join",IDC_JOIN,"Button",BS_AUTORADIOBUTTON,7,31,29,10 + EDITTEXT IDC_JOIN_ADDRESS,52,28,106,14,ES_AUTOHSCROLL | WS_GROUP + DEFPUSHBUTTON "OK",IDOK,52,7,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,108,7,50,14 +END + +IDD_WAITING DIALOG DISCARDABLE 0, 0, 64, 45 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ladderTrack" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,7,24,50,14 + LTEXT "Please Wait...",IDC_STATIC,9,7,45,8 +END + +IDD_LOGIN DIALOG DISCARDABLE 0, 0, 147, 76 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GameSpy Login" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_EMAIL,51,8,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_NICK,51,23,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,51,38,84,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "Login",IDOK,15,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,80,55,50,14 + LTEXT "email:",IDC_STATIC,10,10,19,8 + LTEXT "nick:",IDC_STATIC,10,25,16,8 + LTEXT "password:",IDC_STATIC,10,40,33,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "ladderTrack MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "ladderTrack\0" + VALUE "LegalCopyright", "Copyright (C) 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "ladderTrack.EXE\0" + VALUE "ProductName", "ladderTrack Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_LADDERTRACK_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 93 + END + + IDD_HOST_OR_JOIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 158 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_WAITING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 57 + TOPMARGIN, 7 + BOTTOMMARGIN, 38 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\ladderTrack.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.vcproj b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.vcproj new file mode 100644 index 00000000000..c9e0118de35 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.vcproj @@ -0,0 +1,1359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.vcproj.vspscc b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrackDlg.cpp b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrackDlg.cpp new file mode 100644 index 00000000000..1ce4f1e16ea --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrackDlg.cpp @@ -0,0 +1,989 @@ +// ladderTrackDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ladderTrack.h" +#include "ladderTrackDlg.h" +#include "waitingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackDlg dialog + +CLadderTrackDlg::CLadderTrackDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLadderTrackDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLadderTrackDlg) + m_localPosition = _T(""); + m_remotePosition = _T(""); + m_info = _T("Ready"); + //}}AFX_DATA_INIT + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CLadderTrackDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLadderTrackDlg) + DDX_Control(pDX, IDC_START_RACE, m_startRace); + DDX_Control(pDX, IDC_REMOTE_PROGRESS, m_remoteProgress); + DDX_Control(pDX, IDC_LOCAL_PROGRESS, m_localProgress); + DDX_Text(pDX, IDC_LOCAL_POSITION, m_localPosition); + DDX_Text(pDX, IDC_REMOTE_POSITION, m_remotePosition); + DDX_Text(pDX, IDC_INFO, m_info); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CLadderTrackDlg, CDialog) + //{{AFX_MSG_MAP(CLadderTrackDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_START_RACE, OnStart) + ON_WM_DESTROY() + ON_WM_TIMER() + ON_BN_CLICKED(IDC_LOGOUT, OnLogout) + ON_BN_CLICKED(IDC_UPDATE_POSITIONS, OnUpdatePositions) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackDlg message handlers + +#define MSG_CONNECT "is" // client-pid, nick +#define MSG_CHALLENGE "is" // host-pid, challenge +#define MSG_CHALLENGE_TYPE 1 +#define MSG_RESPONSE "s" // response +#define MSG_RESPONSE_TYPE 2 +#define MSG_COUNTDOWN "i" // count +#define MSG_COUNTDOWN_TYPE 3 +#define MSG_START_RACE "" +#define MSG_START_RACE_TYPE 5 +#define MSG_PROGRESS "i" // progress +#define MSG_PROGRESS_TYPE 6 +#define MSG_END_RACE "i" // time +#define MSG_END_RACE_TYPE 7 +#define MSG_CHAT "s" // message +#define MSG_CHAT_TYPE 8 + +//#define HOST_PORT 38466 +#define HOST_PORT_STRING ":38466" +#define CLIENT_PORT_STRING ":38467" // so you can run both +#define COUNTDOWN_START 5 + +#define TIMER_THINK 100 +#define TIMER_COUNTDOWN 101 + +CLadderTrackDlg * Dlg; + +void ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + if(result == GT2Success) + Dlg->m_state = JOIN_WAITING; + else + { + Dlg->m_state = JOIN_ERROR; + Dlg->m_GT2Connection = NULL; + } +} + +void ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + if(!message || !len) + return; + + GTMessageType type; + + type = gtEncodedMessageType((char*)message); + + if(type == MSG_CHALLENGE_TYPE) + { + ASSERT(!Dlg->m_hosting && (Dlg->m_state == JOIN_WAITING)); + + int pid; + char challenge[64]; + char response[33]; + if(gtDecode(MSG_CHALLENGE, (char*)message, len, &pid, challenge) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + GenerateAuth(challenge, (char *)(LPCSTR)Dlg->m_loginDlg.m_password, response); + + // Send the response. + ///////////////////// + char message[64]; + int rcode; + rcode = gtEncode(MSG_RESPONSE_TYPE, MSG_RESPONSE, message, sizeof(message), response); + ASSERT(rcode != -1); + gt2Send(connection, (const GT2Byte *)message, rcode, GT2True); + + Dlg->m_remoteProfile = pid; + Dlg->m_state = JOIN_CONNECTED; + } + else if(type == MSG_RESPONSE_TYPE) + { + ASSERT(Dlg->m_hosting && (Dlg->m_state == HOST_CHALLENGING)); + + char response[33]; + if(gtDecode(MSG_RESPONSE, (char*)message, len, response) == -1) + { + Dlg->m_state = HOST_ERROR; + return; + } + Dlg->m_remoteResponse = response; + Dlg->m_state = HOST_CONNECTED; + } + else if(type == MSG_COUNTDOWN_TYPE) + { + ASSERT(!Dlg->m_hosting); + + if(gtDecode(MSG_COUNTDOWN, (char*)message, len, &Dlg->m_countdown) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + Dlg->Countdown(); + } + else if(type == MSG_START_RACE_TYPE) + { + ASSERT(!Dlg->m_hosting); + + Dlg->StartRace(); + } + else if(type == MSG_PROGRESS_TYPE) + { + if(Dlg->m_racing) + { + int progress; + if(gtDecode(MSG_PROGRESS, (char*)message, len, &progress) != -1) + Dlg->m_remoteProgress.SetPos(progress); + } + } + else if(type == MSG_END_RACE_TYPE) + { + if(Dlg->m_racing) + { + gtDecode(MSG_END_RACE, (char*)message, len, &Dlg->m_remoteTime); + } + } +} + +void ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + // Logout triggers this function when it's a local close + // so we need to make sure we don't loop + if (reason != GT2LocalClose) + { + Dlg->MessageBox("Connection closed"); + Dlg->Logout(); + } + else + Dlg->m_GT2Connection = NULL; +} + +void ConnectAttemptCallback +( + GT2Socket listener, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + int pid = 0; + char nick[128]; + + // Only allow one connection. + ///////////////////////////// + if(Dlg->m_GT2Connection) + { + gt2Reject(connection, NULL, 0); + return; + } + + // Decode the pid. + ////////////////// + if(message && len) + { + if(gtDecodeNoType(MSG_CONNECT, (char*)message, len, &pid, nick) == -1) + pid = 0; + } + + // If we didn't/couldn't get the pid, reject the attempt. + ///////////////////////////////////////////////////////// + if(!pid) + { + gt2Reject(connection, NULL, 0); + return; + } + + // Accept the connection. + ///////////////////////// + GT2ConnectionCallbacks callbacks; + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + if(!gt2Accept(connection, &callbacks)) + return; + + // Set some states. + /////////////////// + Dlg->m_remoteProfile = pid; + Dlg->m_GT2Connection = connection; + Dlg->m_state = HOST_CHALLENGING; + Dlg->m_challenged = FALSE; + Dlg->m_remoteNick = nick; +} + +/*void StoppedCallback +( + GT2Socket listener, + GTStopReason reason +) +{ + if(reason != GTStopped) + { + Dlg->MessageBox("Listener stopped"); + Dlg->Logout(); + } +}*/ + +void SocketErrorCallback +( + GT2Socket socket +) +{ + Dlg->MessageBox("Socket Error!"); + Dlg->Logout(); +} + + +BOOL CLadderTrackDlg::SetupHosting() +{ + int rcode; + CString str; + + if(!IsStatsConnected()) + { + // Use the development system. + ////////////////////////////// + strcpy(StatsServerHostname, "sdkdev.gamespy.com"); + + // Set the gamename and secret key. + /////////////////////////////////// + strcpy(gcd_gamename, "st_ladder"); + gcd_secret_key[0] = 'K'; + gcd_secret_key[1] = 'w'; + gcd_secret_key[2] = 'F'; + gcd_secret_key[3] = 'J'; + gcd_secret_key[4] = '2'; + gcd_secret_key[5] = 'X'; + + // Init the connection to the backend. + ////////////////////////////////////// + rcode = InitStatsConnection(0); + if(rcode != GE_NOERROR) + { + str.Format("Failed to connect to the stats server (%d).", rcode); + MessageBox(str); + PostQuitMessage(1); + return TRUE; + } + + // Get the challenge. + ///////////////////// + m_challenge = GetChallenge(NULL); + + //FakeStats(); + } + + /* + // Setup the listener's callbacks. + ////////////////////////////////// + GTListenerCallbacks callbacks; + memset(&callbacks, 0, sizeof(GTListenerCallbacks)); + callbacks.connectAttempt = ConnectAttemptCallback; + callbacks.stopped = StoppedCallback; + + // Create the listener. + /////////////////////// + + m_listener = gtListen(gtAddressToString(0, HOST_PORT, NULL), &callbacks); + if(!m_listener) + return FALSE;*/ + + GT2ConnectionCallbacks connectionCallbacks; + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.received = ReceivedCallback; + connectionCallbacks.closed = ClosedCallback; + + GT2Result aResult = gt2CreateSocket(&m_GT2Socket, HOST_PORT_STRING, 0, 0, SocketErrorCallback); + if (GT2Success != aResult) + return FALSE; + + gt2Listen(m_GT2Socket, ConnectAttemptCallback); + m_state = HOST_LISTENING; + + // Bring up the "waiting" dialog. + ///////////////////////////////// + rcode = m_waitingDlg.DoModal(); + + // If it was cancelled, try again. + ////////////////////////////////// + if(rcode != IDOK) + Logout(); + + return TRUE; +} + +BOOL CLadderTrackDlg::SetupJoining() +{ + int rcode; + + // Setup the address to connect to. + /////////////////////////////////// + CString remoteAddress; + remoteAddress.Format("%s%s", m_hostOrJoinDlg.m_joinAddress, HOST_PORT_STRING); + + // Encode the profile id. + ///////////////////////// + char buffer[64]; + rcode = gtEncodeNoType(MSG_CONNECT, buffer, sizeof(buffer), m_loginDlg.m_profile, m_loginDlg.m_nick); + ASSERT(rcode != -1); + + // Setup the callbacks. + /////////////////////// + GT2ConnectionCallbacks callbacks; + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.connected = ConnectedCallback; + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + + // Create the socket + GT2Result aResult = gt2CreateSocket(&m_GT2Socket, CLIENT_PORT_STRING, 0, 0, SocketErrorCallback); + if (aResult != GT2Success) + { + MessageBox("Failed to create socket!"); + return FALSE; + } + + // Connect. + /////////// + m_state = JOIN_CONNECTING; + GT2Result result; + result = gt2Connect(m_GT2Socket, &m_GT2Connection, remoteAddress, (const GT2Byte *)buffer, sizeof(buffer), -1, &callbacks, GT2False); + if(!m_GT2Connection) + return FALSE; + + // Bring up the "waiting" dialog. + ///////////////////////////////// + rcode = m_waitingDlg.DoModal(); + + // If it was cancelled, try again. + ////////////////////////////////// + if(rcode != IDOK) + Logout(); + + return TRUE; +} + +GHTTPBool PlayerPositionPageCompleted +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + __int64 bufferLen, + void * param +) +{ + if(result == GHTTPSuccess) + { + BOOL localPlayer; + int position; + + Dlg->UpdateData(); + + localPlayer = (BOOL)param; + position = atoi(buffer); + + if(localPlayer) + Dlg->m_localPosition.Format("%d", position); + else + Dlg->m_remotePosition.Format("%d", position); + + Dlg->UpdateData(FALSE); + } + + return GHTTPTrue; +} + +void CLadderTrackDlg::UpdatePlayerPositions() +{ + CString url; + url.Format("http://sdkdev.gamespy.com/games/st_ladder/web/playerposition.asp?pid=%d", m_loginDlg.m_profile); + ghttpGet(url, GHTTPFalse, PlayerPositionPageCompleted, (void *)TRUE); + url.Format("http://sdkdev.gamespy.com/games/st_ladder/web/playerposition.asp?pid=%d", m_remoteProfile); + ghttpGet(url, GHTTPFalse, PlayerPositionPageCompleted, (void *)FALSE); +} + +BOOL CLadderTrackDlg::SetupMatch() +{ + int rcode; + BOOL result; + + m_state = SETTING_UP; + + ASSERT(!m_GT2Connection); + ASSERT(!m_GT2Socket); + + m_state = 0; + m_remoteResponse.Empty(); + m_remoteProfile = 0; + m_GT2Connection = NULL; + m_startRace.EnableWindow(FALSE); + m_start = 0; + m_countdown = 0; + m_racing = FALSE; + m_numSteps = 0; + m_step = NONE; + + do + { + // Login the user (actually just verifying the login). + ////////////////////////////////////////////////////// + rcode = m_loginDlg.DoModal(); + if(rcode != IDOK) + { + PostQuitMessage(1); + return FALSE; + } + + // See if they want to host or join. + //////////////////////////////////// + rcode = m_hostOrJoinDlg.DoModal(); + } + while(rcode != IDOK); + + m_GT2Connection = NULL; + m_hosting = (m_hostOrJoinDlg.m_hostOrJoin == HOSTORJOIN_HOST); + + CString str; + str.Format("ladderTrack%s", m_hosting?" (hosting)":""); + SetWindowText(str); + + if(m_hosting) + result = SetupHosting(); + else + result = SetupJoining(); + + if(result && m_hosting) + { + m_startRace.EnableWindow(); + } + + UpdatePlayerPositions(); + + return result; +} + +BOOL CLadderTrackDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIcon, FALSE); + + // Basic initialization. + //////////////////////// + Dlg = this; + m_GT2Connection = NULL; + m_GT2Socket = NULL; + m_state = LOGGED_OUT; + m_countdown = 0; + m_racing = FALSE; + + // Init gt. + /////////// + //gtStartup(); + + // Set a think timer. + ///////////////////// + SetTimer(TIMER_THINK, 50, NULL); + + return TRUE; +} + +void CLadderTrackDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +HCURSOR CLadderTrackDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CLadderTrackDlg::OnLogout() +{ + // Clean stuff up. + ////////////////// + if(m_GT2Connection) + { + gt2CloseConnection(m_GT2Connection); + m_GT2Connection = NULL; + } + if(m_GT2Socket) + { + gt2CloseSocket(m_GT2Socket); + m_GT2Socket = NULL; + } + if(m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + { + m_waitingDlg.EndDialog(IDCANCEL); + } + + m_state = LOGGED_OUT; +} + +void CLadderTrackDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + if(IsStatsConnected()) + CloseStatsConnection(); + + ghttpCleanup(); + + //gt2Cleanup(GTFalse); + if (m_GT2Connection) + { + gt2CloseConnection(m_GT2Connection); + m_GT2Connection = NULL; + } + if (m_GT2Socket) + { + gt2CloseSocket(m_GT2Socket); + m_GT2Socket = NULL; + } +} + +void CLadderTrackDlg::OnTimer(UINT nIDEvent) +{ + char buffer[64]; + int rcode; + + if(nIDEvent == TIMER_THINK) + { + static BOOL thinking; + + if(!thinking) + { + thinking = TRUE; + + if (m_GT2Socket) + gt2Think(m_GT2Socket); + ghttpThink(); + + if(m_state == HOST_CHALLENGING) + { + if(!m_challenged) + { + // Send the challenge string and our profile. + ///////////////////////////////////////////// + rcode = gtEncode(MSG_CHALLENGE_TYPE, MSG_CHALLENGE, buffer, sizeof(buffer), m_loginDlg.m_profile, (LPCSTR)m_challenge); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + m_challenged = TRUE; + } + } + else if(m_state == HOST_CONNECTED) + { + m_waitingDlg.EndDialog(IDOK); + m_state = RACING; + } + else if(m_state == HOST_ERROR) + { + MessageBox("Error setting up hosting"); + m_waitingDlg.EndDialog(IDCANCEL); + } + else if(m_state == JOIN_CONNECTED) + { + if(m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + m_waitingDlg.EndDialog(IDOK); + } + else if(m_state == JOIN_ERROR) + { + MessageBox("Error joining a game"); + m_waitingDlg.EndDialog(IDCANCEL); + } + + thinking = FALSE; + } + + if(m_state == LOGGED_OUT) + { + if(!Dlg->SetupMatch()) + { + MessageBox("Error setting up the match"); + Logout(); + } + } + + // Are we racing? + ///////////////// + if(m_racing) + { + // Did we finish? + ///////////////// + if(m_localTime) + { + // Did we both finish? + ////////////////////// + if(m_remoteTime) + { + // Done racing. + /////////////// + m_racing = FALSE; + + m_info = "Race Complete"; + UpdateData(FALSE); + + // Report the stats. + //////////////////// + if(m_hosting) + ReportStats(); + + // Show the times. + ////////////////// + CString message; + if(m_localTime < m_remoteTime) + message.Format("You won!\n%0.3fs to %0.3fs", m_localTime / 1000.0, m_remoteTime / 1000.0); + else if(m_remoteTime < m_localTime) + message.Format("You lost!\n%0.3fs to %0.3fs", m_localTime / 1000.0, m_remoteTime / 1000.0); + else + message.Format("You tied!\n%0.3fs", m_localTime / 1000.0); + MessageBox(message); + + m_localProgress.SetPos(0); + m_remoteProgress.SetPos(0); + } + } + else + { + // Let our opponent know how far we are. + //////////////////////////////////////// + rcode = gtEncode(MSG_PROGRESS_TYPE, MSG_PROGRESS, buffer, sizeof(buffer), m_numSteps); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2False); + } + } + } + else if(nIDEvent == TIMER_COUNTDOWN) + { + m_countdown--; + if(m_countdown <= 0) + KillTimer(TIMER_COUNTDOWN); + + if(m_countdown < 0) + return; + + Countdown(); + if(!m_countdown) + StartRace(); + } + + CDialog::OnTimer(nIDEvent); +} + +void CLadderTrackDlg::Logout() +{ + OnLogout(); +} + +void CLadderTrackDlg::Countdown() +{ + if(m_hosting) + { + int rcode; + char message[32]; + rcode = gtEncode(MSG_COUNTDOWN_TYPE, MSG_COUNTDOWN, message, sizeof(message), m_countdown); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)message, rcode, GT2True); + } + + if(m_countdown) + { + UpdateData(); + + m_info.Format("Race starts in %ds", m_countdown); + + UpdateData(FALSE); + } +} + +void CLadderTrackDlg::OnStart() +{ + // Start the countdown. + /////////////////////// + m_countdown = COUNTDOWN_START; + SetTimer(TIMER_COUNTDOWN, 1000, NULL); + Countdown(); +} + +BOOL CLadderTrackDlg::PreTranslateMessage(MSG* pMsg) +{ + if(pMsg->message == WM_KEYDOWN) + { + int nChar = pMsg->wParam; + if((nChar == 'Z') || (nChar == 'X')) + { + if((pMsg->lParam & 0xFFFF) == 1) + { + CString str; + BOOL stepped = FALSE; + + if((nChar == 'Z') && (m_step != LEFT)) + { + m_step = LEFT; + m_numSteps++; + stepped = TRUE; + } + else if ((nChar == 'X') && (m_step != RIGHT)) + { + m_step = RIGHT; + m_numSteps++; + stepped = TRUE; + } + + if(stepped && m_racing) + { + m_localProgress.SetPos(m_numSteps); + if(m_numSteps == m_totalSteps) + { + m_localTime = (GetTickCount() - m_start); + str.Format("%0.3fs\n", m_localTime / 1000.0); + OutputDebugString(str); + //MessageBox(str); + + if(!m_remoteTime) + { + UpdateData(); + m_info = "Waiting for opponent"; + UpdateData(FALSE); + } + + // Let them know we finished. + ///////////////////////////// + char buffer[32]; + int rcode; + rcode = gtEncode(MSG_END_RACE_TYPE, MSG_END_RACE, buffer, sizeof(buffer), m_localTime); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + } + } + } + + return TRUE; + } + } + + return CDialog::PreTranslateMessage(pMsg); +} + +void CLadderTrackDlg::StartRace() +{ + if(m_hosting) + { + int rcode; + char buffer[32]; + rcode = gtEncode(MSG_START_RACE_TYPE, MSG_START_RACE, buffer, sizeof(buffer)); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + } + + m_localTime = 0; + m_remoteTime = 0; + m_racing = TRUE; + m_numSteps = 0; + m_step = NONE; + m_racing = TRUE; + m_start = GetTickCount(); + m_totalSteps = RACE_STEPS; + m_localProgress.SetRange(0, m_totalSteps); + m_localProgress.SetPos(0); + m_remoteProgress.SetRange(0, m_totalSteps); + m_remoteProgress.SetPos(0); + + UpdateData(); + m_info.Format("GO!"); + UpdateData(FALSE); +} + +void CLadderTrackDlg::ReportStats() +{ + char response[33]; + + // Game. + //////// + NewGame(1); + BucketStringOp(NULL, "hostname", bo_set, (char *)(LPCSTR)m_loginDlg.m_nick, bl_server, 0); + + // Local player (host). + /////////////////////// + NewPlayer(NULL, 0, (char *)(LPCSTR)m_loginDlg.m_nick); + BucketIntOp(NULL, "time", bo_set, m_localTime, bl_player, 0); + BucketIntOp(NULL, "pid", bo_set, m_loginDlg.m_profile, bl_player, 0); + GenerateAuth((char *)(LPCSTR)m_challenge, (char *)(LPCSTR)m_loginDlg.m_password, response); + BucketStringOp(NULL, "auth", bo_set, response, bl_player, 0); + + // Remote player (joined). + ////////////////////////// + NewPlayer(NULL, 1, (char *)(LPCSTR)m_remoteNick); + BucketIntOp(NULL, "time", bo_set, m_remoteTime, bl_player, 1); + BucketIntOp(NULL, "pid", bo_set, m_remoteProfile, bl_player, 1); + BucketStringOp(NULL, "auth", bo_set, (char *)(LPCSTR)m_remoteResponse, bl_player, 1); + + SendGameSnapShot(NULL, NULL, SNAP_FINAL); + FreeGame(NULL); +} + +struct FakeProfile +{ + int pid; + char password[32]; + char nick[32]; + DWORD minTime; + DWORD maxTime; +}; + +FakeProfile FakeProfiles[] = +{ + { 4933555, "mrpants", "ABCDEF", 4500, 6000}, + { 4903509, "mrpants", "BigFatty", 5500, 7000}, + { 4933502, "mrpants", "Colonel Op", 5500, 7000}, + { 4933634, "mrpants", "GHIJKL", 4500, 7000}, + { 3017545, "mrpants", "test1", 4500, 8000}, + { 3017574, "mrpants", "test2", 4500, 6000}, + { 3360407, "mrpants", "test3", 6500, 7000}, + { 4933752, "mrpants", "tester", 5500, 7000}, + { 2840651, "mrpants", "a,b,c", 6500, 8000}, + { 3410517, "mrpants", "abcabc", 4500, 6000}, + { 3652959, "mrpants", "bane", 6500, 8000}, + { 3654054, "mrpants", "cccccc", 6500, 7000}, + { 8696884, "mrpants", "Jimmy Page", 5500, 6000}, + { 100001, "mrpants", "Mr. Pants", 5500, 8000}, + { 2881317, "mrpants", "mrpants", 4500, 7000}, + { 3651362, "mrpants", "mrpantsz", 6500, 7000}, + { 3671851, "mrpants", "mrwasabi", 5500, 6000}, + { 3652930, "mrpants", "pants", 6500, 8000}, + { 2833041, "mrpants", "pants3", 6500, 7000}, + { 2833042, "mrpants", "pants4", 5500, 7000}, + { 2833043, "mrpants", "pants5", 6500, 7000}, + { 2833045, "mrpants", "pants6", 4500, 7000}, + { 2833048, "mrpants", "pants7", 6500, 7000}, + { 2833049, "mrpants", "pants8", 4500, 6000}, + { 2833050, "mrpants", "pants9", 6500, 8000}, + { 2833074, "mrpants", "pants16", 7000, 8000}, + { 2833075, "mrpants", "pants17", 4500, 8000}, + { 2833076, "mrpants", "pants18", 6500, 7000}, + { 2833077, "mrpants", "pants19", 5500, 7000}, + { 2833079, "mrpants", "pants20", 6500, 7000}, + { 2833080, "mrpants", "pants21", 6500, 8000}, + { 2833081, "mrpants", "pants22", 4500, 6000}, + { 3654074, "mrpants", "sdfrrr", 4500, 6000}, + { 3733688, "mrpants", "Skeletor", 4500, 7000}, + { 2977286, "mrpants", "testtesttest", 6500, 8000}, + { 3654019, "mrpants", "tttttest", 4500, 6000} +}; + +void CLadderTrackDlg::FakeStats() +{ + int num = (sizeof(FakeProfiles) / sizeof(FakeProfile)); + int total = 1000; + int p1; + int p2; + int i; + char response[33]; + CString msg; + + srand(time(NULL)); + + for(i = 0 ; i < total ; i++) + { + p1 = (rand() % num); + p2 = (rand() % num); + + if(p1 == p2) + continue; + + m_loginDlg.m_nick = FakeProfiles[p1].nick; + m_loginDlg.m_profile = FakeProfiles[p1].pid; + m_loginDlg.m_password = FakeProfiles[p1].password; + m_localTime = (DWORD)(FakeProfiles[p1].minTime + ((rand() / (float)RAND_MAX) * (FakeProfiles[p1].maxTime - FakeProfiles[p1].minTime))); + + m_remoteNick = FakeProfiles[p2].nick; + m_remoteProfile = FakeProfiles[p2].pid; + GenerateAuth((char *)(LPCSTR)m_challenge, FakeProfiles[p2].password, response); + m_remoteResponse = response; + m_remoteTime = (DWORD)(FakeProfiles[p2].minTime + ((rand() / (float)RAND_MAX) * (FakeProfiles[p2].maxTime - FakeProfiles[p2].minTime))); + + ReportStats(); + + msg.Format("game %d reported\n", i); + OutputDebugString(msg); + + Sleep(1200); + } + + exit(1); +} + +void CLadderTrackDlg::OnUpdatePositions() +{ + UpdatePlayerPositions(); +} diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrackDlg.h b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrackDlg.h new file mode 100644 index 00000000000..0929139e86d --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrackDlg.h @@ -0,0 +1,117 @@ +// ladderTrackDlg.h : header file +// + +#if !defined(AFX_LADDERTRACKDLG_H__82121F55_1FDB_427A_B616_B59EB16C5E6D__INCLUDED_) +#define AFX_LADDERTRACKDLG_H__82121F55_1FDB_427A_B616_B59EB16C5E6D__INCLUDED_ + +#include "LoginDlg.h" +#include "HostOrJoinDlg.h" +#include "..\..\GT2\gt2.h" // Added by ClassView +#include "..\..\GT2\gt2Encode.h" +#include "WaitingDlg.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackDlg dialog + +#define LOGGED_OUT 1 +#define SETTING_UP 2 +#define RACING 3 + +#define HOST_LISTENING 11 +#define HOST_CHALLENGING 12 +#define HOST_CONNECTED 13 +#define HOST_ERROR 14 + +#define JOIN_CONNECTING 21 +#define JOIN_WAITING 22 +#define JOIN_CONNECTED 23 +#define JOIN_ERROR 24 + +#define NONE -1 +#define LEFT 0 +#define RIGHT 1 + +#define RACE_STEPS 60 + +class CLadderTrackDlg : public CDialog +{ +// Construction +public: + void FakeStats(); + CString m_remoteNick; + DWORD m_remoteTime; + DWORD m_localTime; + int m_totalSteps; + int m_step; + int m_numSteps; + DWORD m_start; + BOOL m_racing; + int m_countdown; + BOOL m_challenged; + CString m_remoteResponse; + int m_state; + BOOL m_hosting; + CString m_challenge; + int m_remoteProfile; + CLoginDlg m_loginDlg; + CHostOrJoinDlg m_hostOrJoinDlg; + CWaitingDlg m_waitingDlg; + + GT2Socket m_GT2Socket; // raw socket + GT2Connection m_GT2Connection; // established connection + + BOOL SetupHosting(); + BOOL SetupJoining(); + BOOL SetupMatch(); + void UpdatePlayerPositions(); + void Countdown(); + void Logout(); + void StartRace(); + void ReportStats(); + CLadderTrackDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLadderTrackDlg) + enum { IDD = IDD_LADDERTRACK_DIALOG }; + CButton m_startRace; + CProgressCtrl m_remoteProgress; + CProgressCtrl m_localProgress; + CString m_localPosition; + CString m_remotePosition; + CString m_info; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLadderTrackDlg) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CLadderTrackDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnStart(); + afx_msg void OnDestroy(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnLogout(); + afx_msg void OnUpdatePositions(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LADDERTRACKDLG_H__82121F55_1FDB_427A_B616_B59EB16C5E6D__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack_vs2005.vcproj b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack_vs2005.vcproj new file mode 100644 index 00000000000..cb6533e35ff --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack_vs2005.vcproj @@ -0,0 +1,1577 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/ladderTrack_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/res/ladderTrack.ico b/xrGameSpy/gamespy/gstats/ladderTrack/res/ladderTrack.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/ladderTrack/res/ladderTrack.ico differ diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/res/ladderTrack.rc2 b/xrGameSpy/gamespy/gstats/ladderTrack/res/ladderTrack.rc2 new file mode 100644 index 00000000000..c70ab2ee29e --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/res/ladderTrack.rc2 @@ -0,0 +1,13 @@ +// +// LADDERTRACK.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/gstats/ladderTrack/resource.h b/xrGameSpy/gamespy/gstats/ladderTrack/resource.h new file mode 100644 index 00000000000..8cc94c9f840 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/ladderTrack/resource.h @@ -0,0 +1,34 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ladderTrack.rc +// +#define IDD_LADDERTRACK_DIALOG 102 +#define IDC_EMAIL 103 +#define IDC_NICK 104 +#define IDC_PASSWORD 105 +#define IDR_MAINFRAME 128 +#define IDD_LOGIN 129 +#define IDD_HOST_OR_JOIN 130 +#define IDD_WAITING 132 +#define IDC_HOST 1000 +#define IDC_LOCAL_POSITION 1000 +#define IDC_JOIN 1001 +#define IDC_REMOTE_POSITION 1001 +#define IDC_JOIN_ADDRESS 1002 +#define IDC_LOGOUT 1004 +#define IDC_START_RACE 1005 +#define IDC_INFO 1006 +#define IDC_LOCAL_PROGRESS 1007 +#define IDC_REMOTE_PROGRESS 1008 +#define IDC_UPDATE_POSITIONS 1009 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/gstats/multiTrack/HostOrJoinDlg.cpp b/xrGameSpy/gamespy/gstats/multiTrack/HostOrJoinDlg.cpp new file mode 100644 index 00000000000..2988012ad85 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/HostOrJoinDlg.cpp @@ -0,0 +1,70 @@ +// HostOrJoinDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "multiTrack.h" +#include "HostOrJoinDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg dialog + + +CHostOrJoinDlg::CHostOrJoinDlg(CWnd* pParent /*=NULL*/) + : CDialog(CHostOrJoinDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CHostOrJoinDlg) + m_hostOrJoin = 0; + m_joinAddress = _T(""); + //}}AFX_DATA_INIT +} + + +void CHostOrJoinDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CHostOrJoinDlg) + DDX_Radio(pDX, IDC_HOST, m_hostOrJoin); + DDX_Text(pDX, IDC_JOIN_ADDRESS, m_joinAddress); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CHostOrJoinDlg, CDialog) + //{{AFX_MSG_MAP(CHostOrJoinDlg) + ON_EN_SETFOCUS(IDC_JOIN_ADDRESS, OnSetfocusJoinAddress) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg message handlers + + +void CHostOrJoinDlg::OnOK() +{ + UpdateData(); + + // Check for no join address. + ///////////////////////////// + if((m_hostOrJoin == HOSTORJOIN_JOIN) && m_joinAddress.IsEmpty()) + { + MessageBox("Please enter the address of the host to connect to"); + return; + } + + CDialog::OnOK(); +} + +void CHostOrJoinDlg::OnSetfocusJoinAddress() +{ + // Make sure its on join. + ///////////////////////// + UpdateData(); + m_hostOrJoin = HOSTORJOIN_JOIN; + UpdateData(FALSE); +} diff --git a/xrGameSpy/gamespy/gstats/multiTrack/HostOrJoinDlg.h b/xrGameSpy/gamespy/gstats/multiTrack/HostOrJoinDlg.h new file mode 100644 index 00000000000..1041829bae9 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/HostOrJoinDlg.h @@ -0,0 +1,51 @@ +#if !defined(AFX_HOSTORJOINDLG_H__7D7ACBE1_D82A_4CB0_B070_368D4263332E__INCLUDED_) +#define AFX_HOSTORJOINDLG_H__7D7ACBE1_D82A_4CB0_B070_368D4263332E__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// HostOrJoinDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg dialog + +#define HOSTORJOIN_HOST 0 +#define HOSTORJOIN_JOIN 1 + +class CHostOrJoinDlg : public CDialog +{ +// Construction +public: + CHostOrJoinDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CHostOrJoinDlg) + enum { IDD = IDD_HOST_OR_JOIN }; + int m_hostOrJoin; + CString m_joinAddress; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CHostOrJoinDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CHostOrJoinDlg) + virtual void OnOK(); + afx_msg void OnSetfocusJoinAddress(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_HOSTORJOINDLG_H__7D7ACBE1_D82A_4CB0_B070_368D4263332E__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/multiTrack/LoginDlg.cpp b/xrGameSpy/gamespy/gstats/multiTrack/LoginDlg.cpp new file mode 100644 index 00000000000..13ecf2d1291 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/LoginDlg.cpp @@ -0,0 +1,186 @@ +// LoginDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "multiTrack.h" +#include "LoginDlg.h" +#include "../../common/gsAvailable.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + + +CLoginDlg::CLoginDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLoginDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoginDlg) + m_email = _T(""); + m_nick = _T(""); + m_password = _T(""); + //}}AFX_DATA_INIT +} + + +void CLoginDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoginDlg) + DDX_Text(pDX, IDC_EMAIL, m_email); + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_PASSWORD, m_password); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoginDlg, CDialog) + //{{AFX_MSG_MAP(CLoginDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg message handlers + +GPResult checkResult; +int checkProfile; + +void CheckUserCallback(GPConnection * connection, void * _arg, void * param) +{ + GPCheckResponseArg * arg = (GPCheckResponseArg *)_arg; + + checkResult = arg->result; + checkProfile = arg->profile; +} + +void CLoginDlg::OnOK() +{ + GPConnection connection; + HCURSOR hourglass; + HCURSOR lastCursor; + GPResult result; + const char* aGameName = "gmtest"; + + UpdateData(); + + // CHECK FOR NO ACCOUNT INFO + //////////////////////////// + if(m_email.IsEmpty() || m_nick.IsEmpty() || m_password.IsEmpty()) + { + MessageBox("Please fill in all the account information."); + return; + } + + // AVAILABILITY CHECK + GSIStartAvailableCheck(aGameName); + GSIACResult ac_result = GSIACWaiting;; + while((ac_result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(ac_result != GSIACAvailable) + { + printf("The backend is not available\n"); + return ;; + } + + + // INITIALIZE GP + //////////////// + if(gpInitialize(&connection, 502, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR) + { + MessageBox("Error initializing the login system."); + return; + } + + // wait cursor on + ///////////////// + hourglass = LoadCursor(NULL, IDC_WAIT); + if(hourglass) + lastCursor = SetCursor(hourglass); + + // CHECK FOR THE ACCOUNT SPECIFIED + ////////////////////////////////// + result = gpCheckUser(&connection, m_nick, m_email, m_password, GP_BLOCKING, CheckUserCallback, NULL); + + // wait cursor off + ////////////////// + if(hourglass) + SetCursor(lastCursor); + + // DESTROY THE GP OBJECT + //////////////////////// + gpDestroy(&connection); + + // CHECK FOR AN ERROR + ///////////////////// + if(result != GP_NO_ERROR) + { + MessageBox("Error verifying the account."); + return; + } + + // CHECK THE RESULT + /////////////////// + if(checkResult != GP_NO_ERROR) + { + if(checkResult == GP_CHECK_BAD_EMAIL) + MessageBox("Invalid e-mail."); + else if(checkResult == GP_CHECK_BAD_NICK) + MessageBox("Invalid nick."); + else if(checkResult == GP_CHECK_BAD_PASSWORD) + MessageBox("Invalid password."); + else + MessageBox("Error verifying the account."); + return; + } + + // save the login info for next time + //////////////////////////////////// + FILE * file; + file = fopen("login.txt", "wt"); + if(file) + { + fprintf(file, "%s\n%s\n%s", m_email, m_nick, m_password); + fclose(file); + } + + // STORE THE PROFILE ID + /////////////////////// + m_profile = checkProfile; + + CDialog::OnOK(); +} + +BOOL CLoginDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // load login info + ////////////////// + FILE * file; + file = fopen("login.txt", "rt"); + if(file) + { + char buffer[512]; + + if(fgets(buffer, sizeof(buffer), file)) + m_email = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_nick = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_password = buffer; + + fclose(file); + + m_email.Remove('\n'); + m_nick.Remove('\n'); + m_password.Remove('\n'); + } + + UpdateData(FALSE); + + return TRUE; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gstats/multiTrack/LoginDlg.h b/xrGameSpy/gamespy/gstats/multiTrack/LoginDlg.h new file mode 100644 index 00000000000..11a5e2a797d --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/LoginDlg.h @@ -0,0 +1,50 @@ +#if !defined(AFX_LOGINDLG_H__E77DE9BB_5AB3_4731_B26A_403169643353__INCLUDED_) +#define AFX_LOGINDLG_H__E77DE9BB_5AB3_4731_B26A_403169643353__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LoginDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + +class CLoginDlg : public CDialog +{ +// Construction +public: + int m_profile; + CLoginDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoginDlg) + enum { IDD = IDD_LOGIN }; + CString m_email; + CString m_nick; + CString m_password; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoginDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoginDlg) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOGINDLG_H__E77DE9BB_5AB3_4731_B26A_403169643353__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/multiTrack/StdAfx.cpp b/xrGameSpy/gamespy/gstats/multiTrack/StdAfx.cpp new file mode 100644 index 00000000000..aacf2ef25d0 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// multiTrack.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/gstats/multiTrack/StdAfx.h b/xrGameSpy/gamespy/gstats/multiTrack/StdAfx.h new file mode 100644 index 00000000000..4c8d2878d42 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/StdAfx.h @@ -0,0 +1,31 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__535325A8_F784_4AFE_827C_AF35A881DD77__INCLUDED_) +#define AFX_STDAFX_H__535325A8_F784_4AFE_827C_AF35A881DD77__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "../gstats.h" +#include "../../gp/gp.h" +#include "../../ghttp/ghttp.h" +#include "../../gt2/gt2.h" +#include "../../gt2/gt2Encode.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__535325A8_F784_4AFE_827C_AF35A881DD77__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/multiTrack/WaitingDlg.cpp b/xrGameSpy/gamespy/gstats/multiTrack/WaitingDlg.cpp new file mode 100644 index 00000000000..5b6b322c42e --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/WaitingDlg.cpp @@ -0,0 +1,43 @@ +// WaitingDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "multiTrack.h" +#include "WaitingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg dialog + + +CWaitingDlg::CWaitingDlg(CWnd* pParent /*=NULL*/) + : CDialog(CWaitingDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CWaitingDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CWaitingDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CWaitingDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CWaitingDlg, CDialog) + //{{AFX_MSG_MAP(CWaitingDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg message handlers + diff --git a/xrGameSpy/gamespy/gstats/multiTrack/WaitingDlg.h b/xrGameSpy/gamespy/gstats/multiTrack/WaitingDlg.h new file mode 100644 index 00000000000..594f33f7d02 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/WaitingDlg.h @@ -0,0 +1,45 @@ +#if !defined(AFX_WAITINGDLG_H__E9C283EE_68D1_40E9_83C6_AAB81D13ED25__INCLUDED_) +#define AFX_WAITINGDLG_H__E9C283EE_68D1_40E9_83C6_AAB81D13ED25__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// WaitingDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg dialog + +class CWaitingDlg : public CDialog +{ +// Construction +public: + CWaitingDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CWaitingDlg) + enum { IDD = IDD_WAITING }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CWaitingDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CWaitingDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_WAITINGDLG_H__E9C283EE_68D1_40E9_83C6_AAB81D13ED25__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.cpp b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.cpp new file mode 100644 index 00000000000..5300e019eaa --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.cpp @@ -0,0 +1,61 @@ +// multiTrack.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "multiTrack.h" +#include "multiTrackDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackApp + +BEGIN_MESSAGE_MAP(CMultiTrackApp, CWinApp) + //{{AFX_MSG_MAP(CMultiTrackApp) + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackApp construction + +CMultiTrackApp::CMultiTrackApp() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CMultiTrackApp object + +CMultiTrackApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackApp initialization + +BOOL CMultiTrackApp::InitInstance() +{ + // Standard initialization +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CMultiTrackDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + } + else if (nResponse == IDCANCEL) + { + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.dsp b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.dsp new file mode 100644 index 00000000000..b539bd6bbf9 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.dsp @@ -0,0 +1,658 @@ +# Microsoft Developer Studio Project File - Name="multiTrack" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=multiTrack - 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 "multiTrack.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 "multiTrack.mak" CFG="multiTrack - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "multiTrack - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "multiTrack - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/multiTrack", VYZBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "multiTrack - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "multiTrack - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "multiTrack - Win32 Release" +# Name "multiTrack - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\HostOrJoinDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\LoginDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\multiTrack.cpp +# End Source File +# Begin Source File + +SOURCE=.\multiTrack.rc +# End Source File +# Begin Source File + +SOURCE=.\multiTrackDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\WaitingDlg.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\HostOrJoinDlg.h +# End Source File +# Begin Source File + +SOURCE=.\LoginDlg.h +# End Source File +# Begin Source File + +SOURCE=.\multiTrack.h +# End Source File +# Begin Source File + +SOURCE=.\multiTrackDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\WaitingDlg.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\multiTrack.ico +# End Source File +# Begin Source File + +SOURCE=.\res\multiTrack.rc2 +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\GP\gp.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpi.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuddy.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiCallback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiConnect.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiInfo.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiOperation.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiPeer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiProfile.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiSearch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiTransfer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUtility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.h +# End Source File +# End Group +# Begin Group "StatsSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gbucket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\gstats.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gstats.h +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.h b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.h new file mode 100644 index 00000000000..3c41b2294c9 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.h @@ -0,0 +1,47 @@ +// multiTrack.h : main header file for the MULTITRACK application +// + +#if !defined(AFX_MULTITRACK_H__6EF40CA1_83C8_448A_883A_63AF15457C5E__INCLUDED_) +#define AFX_MULTITRACK_H__6EF40CA1_83C8_448A_883A_63AF15457C5E__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackApp: +// See multiTrack.cpp for the implementation of this class +// + +class CMultiTrackApp : public CWinApp +{ +public: + CMultiTrackApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CMultiTrackApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CMultiTrackApp) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_MULTITRACK_H__6EF40CA1_83C8_448A_883A_63AF15457C5E__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.rc b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.rc new file mode 100644 index 00000000000..735ea833e0f --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.rc @@ -0,0 +1,253 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\multiTrack.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\multiTrack.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MULTITRACK_DIALOG DIALOGEX 0, 0, 252, 135 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "multiTrack" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Exit",IDOK,195,5,50,14 + PUSHBUTTON "Logout",IDC_LOGOUT,195,21,50,14 + PUSHBUTTON "Start 50m",IDC_START_50,10,15,50,14 + LTEXT "Info",IDC_INFO,10,35,80,8 + CONTROL "Progress1",IDC_LOCAL_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,10,70,80,14 + CONTROL "Progress1",IDC_REMOTE_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,10,105,80,14 + PUSHBUTTON "Start 100m",IDC_START_100,70,15,50,14 + PUSHBUTTON "Start 200m",IDC_START_200,130,15,50,14 + CTEXT "8888888888",IDC_LOCAL_INFO_OVERALL,145,70,41,8 + CTEXT "8888888888",IDC_REMOTE_INFO_OVERALL,195,70,41,8 + GROUPBOX "Rating",IDC_STATIC,105,45,140,85 + LTEXT "Opponent",IDC_STATIC,201,55,32,8 + LTEXT "Overall",IDC_STATIC,111,70,23,8 + LTEXT "50m",IDC_STATIC,111,85,14,8 + LTEXT "100m",IDC_STATIC,111,100,18,8 + LTEXT "200m",IDC_STATIC,111,115,18,8 + LTEXT "You",IDC_STATIC,161,55,14,8 + CTEXT "8888888888",IDC_LOCAL_INFO_50,145,85,41,8 + CTEXT "8888888888",IDC_LOCAL_INFO_100,145,100,41,8 + CTEXT "8888888888",IDC_LOCAL_INFO_200,145,115,41,8 + CTEXT "8888888888",IDC_REMOTE_INFO_100,195,100,41,8 + CTEXT "8888888888",IDC_REMOTE_INFO_50,195,85,41,8 + CTEXT "8888888888",IDC_REMOTE_INFO_200,195,115,41,8 + LTEXT "You:",IDC_STATIC,10,60,16,8 + LTEXT "Opponent:",IDC_STATIC,10,95,34,8 + LTEXT "Use Z && X to race",IDC_STATIC,10,45,57,8 +END + +IDD_LOGIN DIALOG DISCARDABLE 0, 0, 147, 76 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GameSpy Login" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_EMAIL,51,8,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_NICK,51,23,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,51,38,84,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "Login",IDOK,15,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,80,55,50,14 + LTEXT "email:",IDC_STATIC,10,10,19,8 + LTEXT "nick:",IDC_STATIC,10,25,16,8 + LTEXT "password:",IDC_STATIC,10,40,33,8 +END + +IDD_HOST_OR_JOIN DIALOG DISCARDABLE 0, 0, 165, 50 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Host or Join?" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Host",IDC_HOST,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7, + 7,31,10 + CONTROL "Join",IDC_JOIN,"Button",BS_AUTORADIOBUTTON,7,31,29,10 + EDITTEXT IDC_JOIN_ADDRESS,52,28,106,14,ES_AUTOHSCROLL | WS_GROUP + DEFPUSHBUTTON "OK",IDOK,52,7,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,108,7,50,14 +END + +IDD_WAITING DIALOG DISCARDABLE 0, 0, 64, 45 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "multiTrack" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,7,24,50,14 + LTEXT "Please Wait...",IDC_STATIC,9,7,45,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "multiTrack MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "multiTrack\0" + VALUE "LegalCopyright", "Copyright (C) 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "multiTrack.EXE\0" + VALUE "ProductName", "multiTrack Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_MULTITRACK_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 245 + TOPMARGIN, 7 + BOTTOMMARGIN, 128 + END + + IDD_HOST_OR_JOIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 158 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_WAITING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 57 + TOPMARGIN, 7 + BOTTOMMARGIN, 38 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\multiTrack.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.vcproj b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.vcproj new file mode 100644 index 00000000000..0b89ecf9453 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.vcproj @@ -0,0 +1,1285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.vcproj.vspscc b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrackDlg.cpp b/xrGameSpy/gamespy/gstats/multiTrack/multiTrackDlg.cpp new file mode 100644 index 00000000000..ed0dcdf321b --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrackDlg.cpp @@ -0,0 +1,1028 @@ +// multiTrackDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "multiTrack.h" +#include "multiTrackDlg.h" +#include "waitingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackDlg dialog + +CMultiTrackDlg::CMultiTrackDlg(CWnd* pParent /*=NULL*/) + : CDialog(CMultiTrackDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CMultiTrackDlg) + m_info = _T("Ready"); + m_localInfo100 = _T(""); + m_localInfo200 = _T(""); + m_localInfo50 = _T(""); + m_localInfoOverall = _T(""); + m_remoteInfo100 = _T(""); + m_remoteInfo200 = _T(""); + m_remoteInfo50 = _T(""); + m_remoteInfoOverall = _T(""); + //}}AFX_DATA_INIT + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CMultiTrackDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CMultiTrackDlg) + DDX_Control(pDX, IDC_START_100, m_start100); + DDX_Control(pDX, IDC_START_200, m_start200); + DDX_Control(pDX, IDC_REMOTE_PROGRESS, m_remoteProgress); + DDX_Control(pDX, IDC_LOCAL_PROGRESS, m_localProgress); + DDX_Control(pDX, IDC_START_50, m_start50); + DDX_Text(pDX, IDC_INFO, m_info); + DDX_Text(pDX, IDC_LOCAL_INFO_100, m_localInfo100); + DDX_Text(pDX, IDC_LOCAL_INFO_200, m_localInfo200); + DDX_Text(pDX, IDC_LOCAL_INFO_50, m_localInfo50); + DDX_Text(pDX, IDC_LOCAL_INFO_OVERALL, m_localInfoOverall); + DDX_Text(pDX, IDC_REMOTE_INFO_100, m_remoteInfo100); + DDX_Text(pDX, IDC_REMOTE_INFO_200, m_remoteInfo200); + DDX_Text(pDX, IDC_REMOTE_INFO_50, m_remoteInfo50); + DDX_Text(pDX, IDC_REMOTE_INFO_OVERALL, m_remoteInfoOverall); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CMultiTrackDlg, CDialog) + //{{AFX_MSG_MAP(CMultiTrackDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_LOGOUT, OnLogout) + ON_WM_DESTROY() + ON_WM_TIMER() + ON_BN_CLICKED(IDC_START_50, OnStart50) + ON_BN_CLICKED(IDC_START_100, OnStart100) + ON_BN_CLICKED(IDC_START_200, OnStart200) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackDlg message handlers + +#define MSG_CONNECT "is" // client-pid, nick +#define MSG_CHALLENGE "is" // host-pid, challenge +#define MSG_CHALLENGE_TYPE 1 +#define MSG_RESPONSE "s" // response +#define MSG_RESPONSE_TYPE 2 +#define MSG_COUNTDOWN "ii" // event, count +#define MSG_COUNTDOWN_TYPE 3 +#define MSG_START_RACE "" +#define MSG_START_RACE_TYPE 5 +#define MSG_PROGRESS "i" // progress +#define MSG_PROGRESS_TYPE 6 +#define MSG_END_RACE "i" // time +#define MSG_END_RACE_TYPE 7 +#define MSG_CHAT "s" // message +#define MSG_CHAT_TYPE 8 + +#define HOST_PORT 38465 +#define HOST_PORT_STRING ":38465" +#define CLIENT_PORT_STRING ":38446" +#define COUNTDOWN_START 5 + +#define TIMER_THINK 100 +#define TIMER_COUNTDOWN 101 + +#define DEFRATING 1400 +#define POINTSWIN 16 +#define POINTSLOSS -16 + +CMultiTrackDlg * Dlg; + +void ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + if(result == GT2Success) + Dlg->m_state = JOIN_WAITING; + else + { + Dlg->m_state = JOIN_ERROR; + Dlg->m_connection = NULL; + } +} + +void ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + if(!message || !len) + return; + + GTMessageType type; + + type = gtEncodedMessageType((char*)message); + + if(type == MSG_CHALLENGE_TYPE) + { + ASSERT(!Dlg->m_hosting && (Dlg->m_state == JOIN_WAITING)); + + int pid; + char challenge[64]; + char response[33]; + if(gtDecode(MSG_CHALLENGE, (char*)message, len, &pid, challenge) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + GenerateAuth(challenge, (char *)(LPCSTR)Dlg->m_loginDlg.m_password, response); + + // Send the response. + ///////////////////// + char message[64]; + int rcode; + rcode = gtEncode(MSG_RESPONSE_TYPE, MSG_RESPONSE, message, sizeof(message), response); + ASSERT(rcode != -1); + gt2Send(connection, (const GT2Byte*)message, rcode, GT2True); + + Dlg->m_remoteProfile = pid; + Dlg->m_state = JOIN_CONNECTED; + } + else if(type == MSG_RESPONSE_TYPE) + { + ASSERT(Dlg->m_hosting && (Dlg->m_state == HOST_CHALLENGING)); + + char response[33]; + if(gtDecode(MSG_RESPONSE, (char*)message, len, response) == -1) + { + Dlg->m_state = HOST_ERROR; + return; + } + Dlg->m_remoteResponse = response; + Dlg->m_state = HOST_CONNECTED; + } + else if(type == MSG_COUNTDOWN_TYPE) + { + ASSERT(!Dlg->m_hosting); + + if(gtDecode(MSG_COUNTDOWN, (char*)message, len, &Dlg->m_event, &Dlg->m_countdown) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + Dlg->Countdown(); + } + else if(type == MSG_START_RACE_TYPE) + { + ASSERT(!Dlg->m_hosting); + + Dlg->StartRace(); + } + else if(type == MSG_PROGRESS_TYPE) + { + if(Dlg->m_racing) + { + int progress; + if(gtDecode(MSG_PROGRESS, (char*)message, len, &progress) != -1) + Dlg->m_remoteProgress.SetPos(progress); + } + } + else if(type == MSG_END_RACE_TYPE) + { + if(Dlg->m_racing) + { + gtDecode(MSG_END_RACE, (char*)message, len, &Dlg->m_remoteTime); + } + } +} + +void ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + if(reason != GT2LocalClose) + { + Dlg->MessageBox("Connection closed"); + Dlg->Logout(); + } +} + +void ConnectAttemptCallback +( + GT2Socket listener, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + int pid = 0; + char nick[128]; + + // Only allow one connection. + ///////////////////////////// + if(Dlg->m_connection) + { + gt2Reject(connection, NULL, 0); + return; + } + + // Decode the pid. + ////////////////// + if(message && len) + { + if(gtDecodeNoType(MSG_CONNECT, (char*)message, len, &pid, nick) == -1) + pid = 0; + } + + // If we didn't/couldn't get the pid, reject the attempt. + ///////////////////////////////////////////////////////// + if(!pid) + { + gt2Reject(connection, NULL, 0); + return; + } + + // Accept the connection. + ///////////////////////// + GT2ConnectionCallbacks callbacks; + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + if(!gt2Accept(connection, &callbacks)) + return; + + // Set some states. + /////////////////// + Dlg->m_remoteProfile = pid; + Dlg->m_connection = connection; + Dlg->m_state = HOST_CHALLENGING; + Dlg->m_challenged = FALSE; + Dlg->m_remoteNick = nick; +} + +/*void StoppedCallback +( + GTListener listener, + GTStopReason reason +) +{ + if(reason != GTStopped) + { + Dlg->MessageBox("Listener stopped"); + Dlg->Logout(); + } +}*/ + +void SocketErrorCallback +( + GT2Socket socket +) +{ + Dlg->MessageBox("Socket Error!"); + Dlg->Logout(); +} + +BOOL CMultiTrackDlg::SetupHosting() +{ + int rcode; + CString str; + + if(!IsStatsConnected()) + { + // Use the development system. + ////////////////////////////// + strcpy(StatsServerHostname, "sdkdev.gamespy.com"); + + // Set the gamename and secret key. + /////////////////////////////////// + strcpy(gcd_gamename, "st_rank"); + gcd_secret_key[0] = '5'; + gcd_secret_key[1] = '3'; + gcd_secret_key[2] = 'J'; + gcd_secret_key[3] = 'x'; + gcd_secret_key[4] = '7'; + gcd_secret_key[5] = 'W'; + + // Init the connection to the backend. + ////////////////////////////////////// + rcode = InitStatsConnection(0); + if(rcode != GE_NOERROR) + { + str.Format("Failed to connect to the stats server (%d).", rcode); + MessageBox(str); + PostQuitMessage(1); + return TRUE; + } + + // Get the challenge. + ///////////////////// + m_challenge = GetChallenge(NULL); + } + + /* + // Setup the listener's callbacks. + ////////////////////////////////// + GTListenerCallbacks callbacks; + memset(&callbacks, 0, sizeof(GTListenerCallbacks)); + callbacks.connectAttempt = ConnectAttemptCallback; + callbacks.stopped = StoppedCallback; + + // Create the listener. + /////////////////////// + m_listener = gtListen(gtAddressToString(0, HOST_PORT, NULL), &callbacks); + if(!m_listener) + return FALSE; + */ + + GT2ConnectionCallbacks connectionCallbacks; + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.received = ReceivedCallback; + connectionCallbacks.closed = ClosedCallback; + + GT2Result aResult = gt2CreateSocket(&m_socket, HOST_PORT_STRING, 0, 0, SocketErrorCallback); + if (GT2Success != aResult) + return FALSE; + + gt2Listen(m_socket, ConnectAttemptCallback); + + m_state = HOST_LISTENING; + + // Bring up the "waiting" dialog. + ///////////////////////////////// + rcode = m_waitingDlg.DoModal(); + + // If it was cancelled, try again. + ////////////////////////////////// + if(rcode != IDOK) + Logout(); + + return TRUE; +} + +BOOL CMultiTrackDlg::SetupJoining() +{ + int rcode; + + // Setup the address to connect to. + /////////////////////////////////// + CString remoteAddress; + remoteAddress.Format("%s:%d", m_hostOrJoinDlg.m_joinAddress, HOST_PORT); + + // Encode the profile id. + ///////////////////////// + char buffer[64]; + rcode = gtEncodeNoType(MSG_CONNECT, buffer, sizeof(buffer), m_loginDlg.m_profile, m_loginDlg.m_nick); + ASSERT(rcode != -1); + + // Setup the callbacks. + /////////////////////// + GT2ConnectionCallbacks callbacks; + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.connected = ConnectedCallback; + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + + // Create the socket + GT2Result aResult = gt2CreateSocket(&m_socket, CLIENT_PORT_STRING, 0, 0, SocketErrorCallback); + if (aResult != GT2Success) + { + MessageBox("Failed to create socket!"); + return FALSE; + } + + // Connect. + /////////// + m_state = JOIN_CONNECTING; + aResult = gt2Connect(m_socket, &m_connection, remoteAddress, (const GT2Byte*)buffer, sizeof(buffer), -1, &callbacks, GT2False); + if(!m_connection) + return FALSE; + + // Bring up the "waiting" dialog. + ///////////////////////////////// + rcode = m_waitingDlg.DoModal(); + + // If it was cancelled, try again. + ////////////////////////////////// + if(rcode != IDOK) + Logout(); + + return TRUE; +} + +void CMultiTrackDlg::UpdateRatingsDisplay() +{ + Dlg->UpdateData(); + + m_localInfoOverall.Format("%d", m_localRatings[0]); + m_localInfo50.Format("%d", m_localRatings[1]); + m_localInfo100.Format("%d", m_localRatings[2]); + m_localInfo200.Format("%d", m_localRatings[3]); + + m_remoteInfoOverall.Format("%d", m_remoteRatings[0]); + m_remoteInfo50.Format("%d", m_remoteRatings[1]); + m_remoteInfo100.Format("%d", m_remoteRatings[2]); + m_remoteInfo200.Format("%d", m_remoteRatings[3]); + + Dlg->UpdateData(FALSE); +} + +GHTTPBool PlayerRatingsPageCompleted +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + __int64 bufferLen, + void * param +) +{ + if(result == GHTTPSuccess) + { + BOOL localPlayer = (BOOL)param; + int ratings[4]; + int rcode; + + // Scan out ratings. + //////////////////// + rcode = sscanf(buffer, "%d %d %d %d", &ratings[0], &ratings[1], &ratings[2], &ratings[3]); + if(rcode == 4) + { + if(localPlayer) + memcpy(Dlg->m_localRatings, ratings, sizeof(int) * 4); + else + memcpy(Dlg->m_remoteRatings, ratings, sizeof(int) * 4); + + Dlg->UpdateRatingsDisplay(); + } + } + + return GHTTPTrue; +} + +BOOL CMultiTrackDlg::SetupMatch() +{ + int rcode; + BOOL result; + + m_state = SETTING_UP; + + ASSERT(!m_connection); + ASSERT(!m_socket); + + m_state = 0; + m_remoteResponse.Empty(); + m_remoteProfile = 0; + m_connection = NULL; + m_start50.EnableWindow(FALSE); + m_start100.EnableWindow(FALSE); + m_start200.EnableWindow(FALSE); + m_start = 0; + m_countdown = 0; + m_racing = FALSE; + m_event = EVENT_NONE; + m_numSteps = 0; + m_step = NONE; + + do + { + // Login the user (actually just verifying the login). + ////////////////////////////////////////////////////// + rcode = m_loginDlg.DoModal(); + if(rcode != IDOK) + { + PostQuitMessage(1); + return FALSE; + } + + // See if they want to host or join. + //////////////////////////////////// + rcode = m_hostOrJoinDlg.DoModal(); + } + while(rcode != IDOK); + + m_connection = NULL; + m_hosting = (m_hostOrJoinDlg.m_hostOrJoin == HOSTORJOIN_HOST); + + CString str; + str.Format("multiTrack%s", m_hosting?" (hosting)":""); + SetWindowText(str); + + if(m_hosting) + result = SetupHosting(); + else + result = SetupJoining(); + + if(result && m_hosting) + { + m_start50.EnableWindow(); + m_start100.EnableWindow(); + m_start200.EnableWindow(); + } + + CString url; + url.Format("http://sdkdev.gamespy.com/games/st_rank/web/playerratings.asp?pid=%d", m_loginDlg.m_profile); + ghttpGet(url, GHTTPFalse, PlayerRatingsPageCompleted, (void *)TRUE); + url.Format("http://sdkdev.gamespy.com/games/st_rank/web/playerratings.asp?pid=%d", m_remoteProfile); + ghttpGet(url, GHTTPFalse, PlayerRatingsPageCompleted, (void *)FALSE); + + return result; +} + +BOOL CMultiTrackDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIcon, FALSE); + + // Basic initialization. + //////////////////////// + Dlg = this; + m_connection = NULL; + m_socket = NULL; + m_state = LOGGED_OUT; + m_countdown = 0; + m_racing = FALSE; + + // Init gt. + /////////// + //gt2Startup(); + + // Set a think timer. + ///////////////////// + SetTimer(TIMER_THINK, 50, NULL); + + return TRUE; +} + +void CMultiTrackDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +HCURSOR CMultiTrackDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CMultiTrackDlg::OnLogout() +{ + m_state = LOGGED_OUT; + + // Clean stuff up. + ////////////////// + if(m_connection) + { + gt2CloseConnection(m_connection); + m_connection = NULL; + } + if(m_socket) + { + gt2CloseSocket(m_socket); + m_socket = NULL; + } + if(m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + { + m_waitingDlg.EndDialog(IDCANCEL); + } +} + +void CMultiTrackDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + if(IsStatsConnected()) + CloseStatsConnection(); + + ghttpCleanup(); + + //gt2Cleanup(GT2False); + if (m_connection) + { + gt2CloseConnection(m_connection); + m_connection = NULL; + } + if (m_socket) + { + gt2CloseSocket(m_socket); + m_socket = NULL; + } + +} + +int CalculateHandicap(int rating1, int rating2) +{ + static int htable[] = { 12, 34, 56, 78, 101, 126, 151, 177, 206, 239, 273, 315, 366, 446, 471, 715 }; + int diff; + int i; + + diff = abs(rating1 - rating2); + + for(i = 0 ; i < 16 ; i++) + { + if(diff < htable[i]) + return i; + } + + return 16; +} + +void CMultiTrackDlg::UpdateStats() +{ + int handicap; + + handicap = CalculateHandicap(m_localRatings[0], m_remoteRatings[0]); + if(handicap) + { + if(m_localRatings[0] > m_remoteRatings[0]) + { + m_localRatings[0] -= handicap; + m_remoteRatings[0] += handicap; + } + else + { + m_localRatings[0] += handicap; + m_remoteRatings[0] -= handicap; + } + } + + handicap = CalculateHandicap(m_localRatings[m_event], m_remoteRatings[m_event]); + if(handicap) + { + if(m_localRatings[m_event] > m_remoteRatings[m_event]) + { + m_localRatings[m_event] -= handicap; + m_remoteRatings[m_event] += handicap; + } + else + { + m_localRatings[m_event] += handicap; + m_remoteRatings[m_event] -= handicap; + } + } + + if(m_localTime < m_remoteTime) + { + m_localRatings[0] += POINTSWIN; + m_localRatings[m_event] += POINTSWIN; + m_remoteRatings[0] += POINTSLOSS; + m_remoteRatings[m_event] += POINTSLOSS; + } + else if(m_remoteTime < m_localTime) + { + m_remoteRatings[0] += POINTSWIN; + m_remoteRatings[m_event] += POINTSWIN; + m_localRatings[0] += POINTSLOSS; + m_localRatings[m_event] += POINTSLOSS; + } + + UpdateRatingsDisplay(); +} + +void CMultiTrackDlg::OnTimer(UINT nIDEvent) +{ + char buffer[64]; + int rcode; + + if(nIDEvent == TIMER_THINK) + { + static BOOL thinking; + + if(!thinking) + { + thinking = TRUE; + + if (m_socket) + gt2Think(m_socket); + ghttpThink(); + + if(m_state == HOST_CHALLENGING) + { + if(!m_challenged) + { + // Send the challenge string and our profile. + ///////////////////////////////////////////// + rcode = gtEncode(MSG_CHALLENGE_TYPE, MSG_CHALLENGE, buffer, sizeof(buffer), m_loginDlg.m_profile, (LPCSTR)m_challenge); + ASSERT(rcode != -1); + gt2Send(m_connection, (const unsigned char*)buffer, rcode, GT2True); + m_challenged = TRUE; + } + } + else if(m_state == HOST_CONNECTED) + { + m_waitingDlg.EndDialog(IDOK); + m_state = RACING; + } + else if(m_state == HOST_ERROR) + { + MessageBox("Error setting up hosting"); + m_waitingDlg.EndDialog(IDCANCEL); + } + else if(m_state == JOIN_CONNECTED) + { + if(m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + m_waitingDlg.EndDialog(IDOK); + } + else if(m_state == JOIN_ERROR) + { + MessageBox("Error joining a game"); + m_waitingDlg.EndDialog(IDCANCEL); + } + + thinking = FALSE; + } + + if(m_state == LOGGED_OUT) + { + if(!Dlg->SetupMatch()) + { + MessageBox("Error setting up the match"); + Logout(); + } + } + + // Are we racing? + ///////////////// + if(m_racing) + { + // Did we finish? + ///////////////// + if(m_localTime) + { + // Did we both finish? + ////////////////////// + if(m_remoteTime) + { + // Done racing. + /////////////// + m_racing = FALSE; + + // Show the times. + ////////////////// + CString message; + if(m_localTime < m_remoteTime) + message.Format("You won!\n%0.3fs to %0.3fs", m_localTime / 1000.0, m_remoteTime / 1000.0); + else if(m_remoteTime < m_localTime) + message.Format("You lost!\n%0.3fs to %0.3fs", m_localTime / 1000.0, m_remoteTime / 1000.0); + else + message.Format("You tied!\n%0.3fs", m_localTime / 1000.0); + MessageBox(message); + + m_localProgress.SetPos(0); + m_remoteProgress.SetPos(0); + + // Report the stats. + //////////////////// + if(m_hosting) + ReportStats(); + + m_event = EVENT_NONE; + + UpdateStats(); + } + } + else + { + // Let our opponent know how far we are. + //////////////////////////////////////// + rcode = gtEncode(MSG_PROGRESS_TYPE, MSG_PROGRESS, buffer, sizeof(buffer), m_numSteps); + ASSERT(rcode != -1); + gt2Send(m_connection, (const GT2Byte*)buffer, rcode, GT2False); + } + } + } + else if(nIDEvent == TIMER_COUNTDOWN) + { + m_countdown--; + if(m_countdown <= 0) + KillTimer(TIMER_COUNTDOWN); + + if(m_countdown < 0) + return; + + Countdown(); + if(!m_countdown) + StartRace(); + } + + CDialog::OnTimer(nIDEvent); +} + +void CMultiTrackDlg::Logout() +{ + OnLogout(); +} + +void CMultiTrackDlg::Countdown() +{ + if(m_hosting) + { + int rcode; + char message[32]; + rcode = gtEncode(MSG_COUNTDOWN_TYPE, MSG_COUNTDOWN, message, sizeof(message), m_event, m_countdown); + ASSERT(rcode != -1); + gt2Send(m_connection, (const GT2Byte*)message, rcode, GT2True); + } + + if(m_countdown) + { + UpdateData(); + + CString strEvent; + if(m_event == EVENT_50) + strEvent = "50m"; + else if(m_event == EVENT_100) + strEvent = "100m"; + else if(m_event == EVENT_200) + strEvent = "200m"; + m_info.Format("%s starts in %ds", strEvent, m_countdown); + + UpdateData(FALSE); + } +} + +void CMultiTrackDlg::OnStart50() +{ + // Start the countdown. + /////////////////////// + m_countdown = COUNTDOWN_START; + SetTimer(TIMER_COUNTDOWN, 1000, NULL); + m_event = EVENT_50; + Countdown(); +} + +void CMultiTrackDlg::OnStart100() +{ + // Start the countdown. + /////////////////////// + m_countdown = COUNTDOWN_START; + SetTimer(TIMER_COUNTDOWN, 1000, NULL); + m_event = EVENT_100; + Countdown(); +} + +void CMultiTrackDlg::OnStart200() +{ + // Start the countdown. + /////////////////////// + m_countdown = COUNTDOWN_START; + SetTimer(TIMER_COUNTDOWN, 1000, NULL); + m_event = EVENT_200; + Countdown(); +} + +BOOL CMultiTrackDlg::PreTranslateMessage(MSG* pMsg) +{ + if(pMsg->message == WM_KEYDOWN) + { + int nChar = pMsg->wParam; + if((nChar == 'Z') || (nChar == 'X')) + { + if((pMsg->lParam & 0xFFFF) == 1) + { + CString str; + BOOL stepped = FALSE; + + if((nChar == 'Z') && (m_step != LEFT)) + { + m_step = LEFT; + m_numSteps++; + stepped = TRUE; + } + else if ((nChar == 'X') && (m_step != RIGHT)) + { + m_step = RIGHT; + m_numSteps++; + stepped = TRUE; + } + + if(stepped && m_racing) + { + m_localProgress.SetPos(m_numSteps); + if(m_numSteps == m_totalSteps) + { + m_localTime = (GetTickCount() - m_start); + str.Format("%0.3fs\n", m_localTime / 1000.0); + OutputDebugString(str); + //MessageBox(str); + + UpdateData(); + + m_info = "Race Complete"; + + // Let them know we finished. + ///////////////////////////// + char buffer[32]; + int rcode; + rcode = gtEncode(MSG_END_RACE_TYPE, MSG_END_RACE, buffer, sizeof(buffer), m_localTime); + ASSERT(rcode != -1); + gt2Send(m_connection, (const GT2Byte*)buffer, rcode, GT2True); + + UpdateData(FALSE); + } + } + } + + return TRUE; + } + } + + return CDialog::PreTranslateMessage(pMsg); +} + +void CMultiTrackDlg::StartRace() +{ + if(m_hosting) + { + int rcode; + char buffer[32]; + rcode = gtEncode(MSG_START_RACE_TYPE, MSG_START_RACE, buffer, sizeof(buffer)); + ASSERT(rcode != -1); + gt2Send(m_connection, (const GT2Byte*)buffer, rcode, GT2True); + } + + m_localTime = 0; + m_remoteTime = 0; + m_racing = TRUE; + m_numSteps = 0; + m_step = NONE; + m_racing = TRUE; + m_start = GetTickCount(); + if(m_event == EVENT_50) + m_totalSteps = RACE_STEPS_50; + else if(m_event == EVENT_100) + m_totalSteps = RACE_STEPS_100; + else if(m_event == EVENT_200) + m_totalSteps = RACE_STEPS_200; + m_localProgress.SetRange(0, m_totalSteps); + m_localProgress.SetPos(0); + m_remoteProgress.SetRange(0, m_totalSteps); + m_remoteProgress.SetPos(0); + + UpdateData(); + m_info.Format("GO!"); + UpdateData(FALSE); +} + +void CMultiTrackDlg::ReportStats() +{ + char response[33]; + + // Game. + //////// + NewGame(1); + BucketStringOp(NULL, "hostname", bo_set, (char *)(LPCSTR)m_loginDlg.m_nick, bl_server, 0); + BucketIntOp(NULL, "event", bo_set, m_event, bl_server, 0); + + // Local player (host). + /////////////////////// + NewPlayer(NULL, 0, (char *)(LPCSTR)m_loginDlg.m_nick); + BucketIntOp(NULL, "time", bo_set, m_localTime, bl_player, 0); + BucketIntOp(NULL, "pid", bo_set, m_loginDlg.m_profile, bl_player, 0); + GenerateAuth((char *)(LPCSTR)m_challenge, (char *)(LPCSTR)m_loginDlg.m_password, response); + BucketStringOp(NULL, "auth", bo_set, response, bl_player, 0); + + // Remote player (joined). + ////////////////////////// + NewPlayer(NULL, 1, (char *)(LPCSTR)m_remoteNick); + BucketIntOp(NULL, "time", bo_set, m_remoteTime, bl_player, 1); + BucketIntOp(NULL, "pid", bo_set, m_remoteProfile, bl_player, 1); + BucketStringOp(NULL, "auth", bo_set, (char *)(LPCSTR)m_remoteResponse, bl_player, 1); + + SendGameSnapShot(NULL, NULL, SNAP_FINAL); + FreeGame(NULL); +} diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrackDlg.h b/xrGameSpy/gamespy/gstats/multiTrack/multiTrackDlg.h new file mode 100644 index 00000000000..af84f899e37 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrackDlg.h @@ -0,0 +1,135 @@ +// multiTrackDlg.h : header file +// + +#if !defined(AFX_MULTITRACKDLG_H__4B977C2B_DD72_4B3A_B1F9_E95D26F0C328__INCLUDED_) +#define AFX_MULTITRACKDLG_H__4B977C2B_DD72_4B3A_B1F9_E95D26F0C328__INCLUDED_ + +#include "LoginDlg.h" +#include "HostOrJoinDlg.h" +#include "..\..\GT2\gt2.h" // Added by ClassView +#include "WaitingDlg.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CMultiTrackDlg dialog + +#define LOGGED_OUT 1 +#define SETTING_UP 2 +#define RACING 3 + +#define HOST_LISTENING 11 +#define HOST_CHALLENGING 12 +#define HOST_CONNECTED 13 +#define HOST_ERROR 14 + +#define JOIN_CONNECTING 21 +#define JOIN_WAITING 22 +#define JOIN_CONNECTED 23 +#define JOIN_ERROR 24 + +#define NONE -1 +#define LEFT 0 +#define RIGHT 1 + +#define RACE_STEPS_50 60 +#define RACE_STEPS_100 120 +#define RACE_STEPS_200 240 + +#define EVENT_NONE 0 +#define EVENT_50 1 +#define EVENT_100 2 +#define EVENT_200 3 + +class CMultiTrackDlg : public CDialog +{ +// Construction +public: + void UpdateRatingsDisplay(); + int m_localRatings[4]; + int m_remoteRatings[4]; + void UpdateStats(); + CString m_remoteNick; + void ReportStats(); + DWORD m_remoteTime; + DWORD m_localTime; + void StartRace(); + int m_totalSteps; + int m_event; + int m_step; + int m_numSteps; + DWORD m_start; + BOOL m_racing; + void Countdown(); + int m_countdown; + BOOL m_challenged; + void Logout(); + CWaitingDlg m_waitingDlg; + CString m_remoteResponse; + int m_state; + CLoginDlg m_loginDlg; + CHostOrJoinDlg m_hostOrJoinDlg; + BOOL m_hosting; + CString m_challenge; + int m_remoteProfile; + + GT2Connection m_connection; + GT2Socket m_socket; + + BOOL SetupJoining(); + BOOL SetupHosting(); + BOOL SetupMatch(); + CMultiTrackDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CMultiTrackDlg) + enum { IDD = IDD_MULTITRACK_DIALOG }; + CButton m_start100; + CButton m_start200; + CProgressCtrl m_remoteProgress; + CProgressCtrl m_localProgress; + CButton m_start50; + CString m_info; + CString m_localInfo100; + CString m_localInfo200; + CString m_localInfo50; + CString m_localInfoOverall; + CString m_remoteInfo100; + CString m_remoteInfo200; + CString m_remoteInfo50; + CString m_remoteInfoOverall; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CMultiTrackDlg) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CMultiTrackDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnLogout(); + afx_msg void OnDestroy(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnStart50(); + afx_msg void OnStart100(); + afx_msg void OnStart200(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_MULTITRACKDLG_H__4B977C2B_DD72_4B3A_B1F9_E95D26F0C328__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack_vs2005.vcproj b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack_vs2005.vcproj new file mode 100644 index 00000000000..90beb3ec0c7 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack_vs2005.vcproj @@ -0,0 +1,1652 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/multiTrack/multiTrack_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/multiTrack_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/multiTrack/res/multiTrack.ico b/xrGameSpy/gamespy/gstats/multiTrack/res/multiTrack.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/multiTrack/res/multiTrack.ico differ diff --git a/xrGameSpy/gamespy/gstats/multiTrack/res/multiTrack.rc2 b/xrGameSpy/gamespy/gstats/multiTrack/res/multiTrack.rc2 new file mode 100644 index 00000000000..948752730ff --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/res/multiTrack.rc2 @@ -0,0 +1,13 @@ +// +// MULTITRACK.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/gstats/multiTrack/resource.h b/xrGameSpy/gamespy/gstats/multiTrack/resource.h new file mode 100644 index 00000000000..96e71e413f3 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/multiTrack/resource.h @@ -0,0 +1,41 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by multiTrack.rc +// +#define IDD_MULTITRACK_DIALOG 102 +#define IDC_EMAIL 103 +#define IDC_NICK 104 +#define IDC_PASSWORD 105 +#define IDR_MAINFRAME 128 +#define IDD_LOGIN 129 +#define IDD_HOST_OR_JOIN 130 +#define IDD_WAITING 132 +#define IDC_HOST 1000 +#define IDC_JOIN 1001 +#define IDC_JOIN_ADDRESS 1002 +#define IDC_LOGOUT 1004 +#define IDC_START_50 1005 +#define IDC_INFO 1006 +#define IDC_LOCAL_PROGRESS 1007 +#define IDC_REMOTE_PROGRESS 1008 +#define IDC_START_100 1009 +#define IDC_START_200 1010 +#define IDC_LOCAL_INFO_OVERALL 1011 +#define IDC_LOCAL_INFO_50 1012 +#define IDC_LOCAL_INFO_100 1013 +#define IDC_LOCAL_INFO_200 1014 +#define IDC_REMOTE_INFO_100 1015 +#define IDC_REMOTE_INFO_50 1016 +#define IDC_REMOTE_INFO_200 1017 +#define IDC_REMOTE_INFO_OVERALL 1018 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1019 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistlinux/Makefile b/xrGameSpy/gamespy/gstats/persisttest/persistlinux/Makefile new file mode 100644 index 00000000000..28dfe48485b --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistlinux/Makefile @@ -0,0 +1,49 @@ +# Persistent Storage SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=persistsdk + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/linux/LinuxCommon.o\ + ../../gstats.o\ + ../../gbucket.o\ + ../persisttest.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistmacosx/Makefile b/xrGameSpy/gamespy/gstats/persisttest/persistmacosx/Makefile new file mode 100644 index 00000000000..3965b41f99a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistmacosx/Makefile @@ -0,0 +1,25 @@ +# Persistent Storage SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=persisttest + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../gstats.o\ + ../../gbucket.o\ + ../persisttest.o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/Nitro.lcf b/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/persistnitrocw.mcp b/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/persistnitrocw.mcp new file mode 100644 index 00000000000..2f65383100b Binary files /dev/null and b/xrGameSpy/gamespy/gstats/persisttest/persistnitrocw/persistnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps2/Makefile b/xrGameSpy/gamespy/gstats/persisttest/persistps2/Makefile new file mode 100644 index 00000000000..6d259efd503 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps2/Makefile @@ -0,0 +1,28 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = persisttest + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o \ + ../../../hashtable.o \ + ../../../md5c.o \ + ../../../stringutil.o \ + ../../../available.o \ + ../../gstats.o \ + ../../gbucket.o \ + crt0.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps2cw/persistps2cw.mcp b/xrGameSpy/gamespy/gstats/persisttest/persistps2cw/persistps2cw.mcp new file mode 100644 index 00000000000..49b30f7895d Binary files /dev/null and b/xrGameSpy/gamespy/gstats/persisttest/persistps2cw/persistps2cw.mcp differ diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.dsp b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.dsp new file mode 100644 index 00000000000..ed3101e3bef --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.dsp @@ -0,0 +1,356 @@ +# Microsoft Developer Studio Project File - Name="persistps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=persistps2prodg - Win32 Debug_Insock +!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 "persistps2prodg.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 "persistps2prodg.mak" CFG="persistps2prodg - Win32 Debug_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "persistps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "persistps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "persistps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "persistps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "persistps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "persistps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/persisttest/persistps2prodg", BTEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "persistps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "EENET" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\persistps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EEnet\persistps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "persistps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "persistps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "persistps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "EENET" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "INSOCK" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EEnet\persistps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\persistps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "persistps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\persistps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\persistps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "persistps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\persistps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\persistps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "persistps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "persistps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "persistps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\persistps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\persistps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "persistps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\persistps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\persistps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "persistps2prodg - Win32 Debug_EENet" +# Name "persistps2prodg - Win32 Debug_Insock" +# Name "persistps2prodg - Win32 Debug_SNSystems" +# Name "persistps2prodg - Win32 Release_EENet" +# Name "persistps2prodg - Win32 Release_Insock" +# Name "persistps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\persisttest.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "GSI" + +# PROP Default_Filter "" +# End Group +# Begin Group "PersistentStorageSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gbucket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\..\gstats.c +# End Source File +# Begin Source File + +SOURCE=..\..\gstats.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.dsw b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.dsw new file mode 100644 index 00000000000..42c98f878c4 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "persistps2prodg"=.\persistps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/persisttest/persistps2prodg", BTEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/persisttest/persistps2prodg", BTEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.sln b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.sln new file mode 100644 index 00000000000..b58644fd780 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "persistps2prodg", "persistps2prodg.vcproj", "{C75E9F01-A956-417E-A099-AFA7FD067460}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 1 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = persistps2prodg.vcproj + SccProjectName0 = . + SccAuxPath0 = http://tfsapp1:8080 + SccLocalPath0 = . + SccProvider0 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Release|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Release|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Debug|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 INET Release|Win32.Build.0 = PS2 INET Debug|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {C75E9F01-A956-417E-A099-AFA7FD067460}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.vcproj b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.vcproj new file mode 100644 index 00000000000..d0d1def5e46 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps2prodg/persistps2prodg.vcproj @@ -0,0 +1,640 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps3/Makefile b/xrGameSpy/gamespy/gstats/persisttest/persistps3/Makefile new file mode 100644 index 00000000000..5cc8bf94bfd --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps3/Makefile @@ -0,0 +1,33 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = persisttest + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsAvailable.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../../hashtable.o \ + ../../../darray.o \ + ../../../md5c.o \ + ../../gstats.o \ + ../../gbucket.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps3prodg/persistps3prodg.sln b/xrGameSpy/gamespy/gstats/persisttest/persistps3prodg/persistps3prodg.sln new file mode 100644 index 00000000000..68ea587aa9a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps3prodg/persistps3prodg.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "persistps3prodg", "persistps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = persistps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistps3prodg/persistps3prodg.vcproj b/xrGameSpy/gamespy/gstats/persisttest/persistps3prodg/persistps3prodg.vcproj new file mode 100644 index 00000000000..a0f1886af13 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistps3prodg/persistps3prodg.vcproj @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistpspprodg/persistpspprodg.sln b/xrGameSpy/gamespy/gstats/persisttest/persistpspprodg/persistpspprodg.sln new file mode 100644 index 00000000000..206bd72b86a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistpspprodg/persistpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "persistpspprodg", "persistpspprodg.vcproj", "{0EB79CD9-8076-44F4-AFD2-46E3C2067F70}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = persistpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0EB79CD9-8076-44F4-AFD2-46E3C2067F70}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {0EB79CD9-8076-44F4-AFD2-46E3C2067F70}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {0EB79CD9-8076-44F4-AFD2-46E3C2067F70}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {0EB79CD9-8076-44F4-AFD2-46E3C2067F70}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {0EB79CD9-8076-44F4-AFD2-46E3C2067F70}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {0EB79CD9-8076-44F4-AFD2-46E3C2067F70}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistpspprodg/persistpspprodg.vcproj b/xrGameSpy/gamespy/gstats/persisttest/persistpspprodg/persistpspprodg.vcproj new file mode 100644 index 00000000000..589fe9e1531 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persistpspprodg/persistpspprodg.vcproj @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persistrevolutioncw/persistrevolutioncw.mcp b/xrGameSpy/gamespy/gstats/persisttest/persistrevolutioncw/persistrevolutioncw.mcp new file mode 100644 index 00000000000..31801602cbb Binary files /dev/null and b/xrGameSpy/gamespy/gstats/persisttest/persistrevolutioncw/persistrevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/gstats/persisttest/persisttest.c b/xrGameSpy/gamespy/gstats/persisttest/persisttest.c new file mode 100644 index 00000000000..20ba9451206 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persisttest.c @@ -0,0 +1,375 @@ +/****** +persisttest.c +GameSpy Persistent Storage SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +****** + +Please see the GameSpy Persistent Storage SDK for more info + +*****/ + +#include +#include "../../common/gsCommon.h" +#include "../../common/gsAvailable.h" +#include "../gpersist.h" + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +/****** +We aren't actually hosting a game in this sample, so just set the gameport to 0 +*******/ +#define MY_GAMEPORT 0 + +/******* +A CD Key profile is defined by the combination of the nickname and cdkey +Here we have a nick and key to use +********/ +#define KEYNICK _T("crt") +#define VALIDCDKEY _T("2dd4-893a-ce85-6411") + +/*** +A Presence & Messaging account is identified by the profileid and password +These is the profileid for the test@test@gamespy.com account +***/ +#define PROFILEID 2446667 +#define VALIDPROFILEPASSWORD _T("test") + +//a sample data structure we will store on the server +typedef struct playerdata_s +{ + char modelnumber; + int hitpoints; + unsigned int totaltime; + char skin[9]; +} playerdata_t; + +static void PersAuthCallback(int localid, int profileid, int authenticated, gsi_char *errmsg, void *instance) +{ + _tprintf(_T("Auth callback: localid: %d profileid: %d auth: %d err: %s\n"),localid, profileid, authenticated, errmsg); + /********** + instance is a pointer to the authcount var. We increment it here to tell the main loop that + another authentication response came in. + **********/ + (*(int *)instance)++; + +} + +static void PersDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance) +{ + printf("Data get callback: localid: %d profileid: %d success: %d mod: %d len: %d data: %s\n",localid, profileid, success, (int)modified, len, data); + /********* + instance is a pointer to the callback counter, increment it + **********/ + (*(int *)instance)++; + + GSI_UNUSED(type); + GSI_UNUSED(index); +} + +static void PlayerDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance) +{ + playerdata_t pdata; + /* we copy it off, instead of reading directly, since the data may not be aligned correctly for the SH4/other processors */ + memcpy(&pdata,data, sizeof(playerdata_t)); + if (success) + printf("playerdata get callback: localid: %d profileid: %d success: %d modified: %d len: %d data:\n\tmodel:%d\n\thitpoints:%d\n\ttotaltime:%d\n\tskin:%s\n",localid, profileid, success, (int)modified, len,pdata.modelnumber,pdata.hitpoints,pdata.totaltime,pdata.skin); + else + printf("playerdata get callback: localid: %d profileid: %d success: %d len: %d (FAILED)\n",localid, profileid, success, len); + /********* + instance is a pointer to the callback counter, increment it + **********/ + (*(int *)instance)++; + + GSI_UNUSED(type); + GSI_UNUSED(index); +} + + +static void PersDataSaveCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, void *instance) +{ + printf("Data save callback: localid: %d profileid: %d success: %d mod: %d\n", localid, profileid, success, (int)modified); + /********* + instance is a pointer to the callback counter, increment it + **********/ + (*(int *)instance)++; + + GSI_UNUSED(type); + GSI_UNUSED(index); +} +static void ProfileCallback(int localid, int profileid, int success, void *instance) +{ + printf("Profile callback: localid: %d profileid: %d success: %d\n",localid, profileid, success); + /********** + instance is the player1pid var, lets put the profileid there, or -1 if it wasn't successful + ***********/ + if (success) + *(int *)instance = profileid; + else + *(int *)instance = -1; +} + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped + int test_main(int argc, char **argv); +#endif + +int test_main(int argc, char **argv) +{ + int result; + int authcount; + int callbackct; + char validate[33], cdkey_hash[33]; + int player1pid; + GSIACResult ac_result; + + playerdata_t playerdata; + + /********* + First step, set our game authentication info + We could do: + strcpy(gcd_gamename,"gmtest"); + strcpy(gcd_secret_key,"HA6zkS"); + ...but this is more secure: + **********/ + gcd_gamename[0]='g';gcd_gamename[1]='m';gcd_gamename[2]='t';gcd_gamename[3]='e'; + gcd_gamename[4]='s';gcd_gamename[5]='t';gcd_gamename[6]='\0'; + gcd_secret_key[0]='H';gcd_secret_key[1]='A';gcd_secret_key[2]='6';gcd_secret_key[3]='z'; + gcd_secret_key[4]='k';gcd_secret_key[5]='S';gcd_secret_key[6]='\0'; + + /********* + Before initializing the connection, + check that the backend is available. + *********/ + GSIStartAvailableCheck(_T("gmtest")); + while((ac_result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(ac_result != GSIACAvailable) + { + printf("The backend is not available\n"); + return 1; + } + + /********* + Next, open the stats connection. This may block for + a 1-2 seconds, so it should be done before the actual game starts. + **********/ + result = InitStatsConnection(MY_GAMEPORT); + + if (result != GE_NOERROR) + { + printf("InitStatsConnection returned %d\n",result); + return 1; + } + + /******** + Now, lets authenticate two players, one using the a Presence & Messaging + SDK profileid, and the other using a CDKey SDK CD Key. + The profile/password and CD Key/nick to use are defined at the top. + + Generally you will only use one method or the other, depending on your game. + *********/ + /************* + The first step to authenticate a player is to generate their Authentication token. + + If you are retrieving/setting persistent data on the server, you should first send + the challenge to the client, have them send back the validation, and then proceed + with the authentication. In this manner the client never has to send their password + or CD Key to the server -- only the validation hash. + If you are retrieving/setting persistent data on the client, it can all be done + locally, as shown below. + *************/ + + /************ + First, we will authenticate a player using the CD Key system. We pass in the + plaintext CD Key to GenerateAuth to get the validation token (validate). + *************/ + GenerateAuth(GetChallenge(NULL),VALIDCDKEY,validate); + + /************ + Next, we need to get the hash of the CD Key to along with the validation. + This can be done easily using GenerateAuth with an empty challenge string + ************/ + GenerateAuth("",VALIDCDKEY,cdkey_hash); + + /*********** + Now, we call PreAuthenticatePlayerCD with the hash and the validation token. + We pass in a callback that will be called when the operation is complete, along + with a integer that we will check to know its done. + We pass in the localid as 1, since we will be authenticating two players before + checking the return values. By using different localids we can tell them apart. + ************/ + authcount = 0; + PreAuthenticatePlayerCD(1,KEYNICK,cdkey_hash,validate,PersAuthCallback,&authcount); + + /*********** + While the first authentication is in progress, we'll go ahead and start the second + one, using a Presence & Messaging SDK profileid / password. + To generate the new validation token, we'll need to pass in the password for the + profile we are authenticating. + Again, if this is done in a client/server setting, with the Persistent Storage + access being done on the server, and the P&M SDK is used on the client, the + server will need to send the challenge (GetChallenge(NULL)) to the client, the + client will create the validation token using GenerateAuth, and send it + back to the server for use in PreAuthenticatePlayerPM + ***********/ + GenerateAuth(GetChallenge(NULL),VALIDPROFILEPASSWORD,validate); + + /************ + After we get the validation token, we pass it and the profileid of the user + we are authenticating into PreAuthenticatePlayerPM. + We pass the same authentication callback as for the first user, but a different + localid this time. + ************/ + PreAuthenticatePlayerPM(2,PROFILEID,validate,PersAuthCallback,&authcount); + + /*********** + Now that both authentication requests are sent, we need to wait for the results to + come back. If we were in a game we could continue with the main game loop at this + point, but since we're not, we'll just loop until we are disconnected or both + authentications come back + ************/ + while (authcount < 2 && IsStatsConnected()) + { + PersistThink(); + msleep(10); + } + + /********** + Both of the players have now been authenticated. + When the CD Key player (player 1) was authenticated, the profileid for him + was returned in the callback, but we didn't save it off. Since we'll need it + to get/set data for him, lets go ahead and retrieve it using the GetProfileIDFromCD + function + **********/ + player1pid = 0; + GetProfileIDFromCD(1,KEYNICK,cdkey_hash,ProfileCallback,&player1pid); + + /********** + Again we'll wait until the call completes. We check if player1pid is still 0, since + it gets set to the profileid in the callback (or -1 if a failure) + ***********/ + while (player1pid == 0 && IsStatsConnected()) + { + PersistThink(); + msleep(10); + } + + /********** + Now we have everything we need to start getting / setting data for the two + users. First we'll clear both user's public data, to make sure it's empty + before we continue + ***********/ + callbackct = 0; + SetPersistData(1,player1pid,pd_public_rw,0,"",0,PersDataSaveCallback,&callbackct); + SetPersistData(2,PROFILEID,pd_public_rw,0,"",0,PersDataSaveCallback,&callbackct); + + /********** + We'll use the callbackct var (passed in to the callbacks) as a way to easily determine + when the calls are complete + ***********/ + while (callbackct < 2 && IsStatsConnected()) + { + PersistThink(); + msleep(10); + } + + + /*********** + Lets read the data back, just to prove it's cleared + ************/ + callbackct = 0; + GetPersistData(1,player1pid,pd_public_rw,0,PersDataCallback,&callbackct); + GetPersistData(2,PROFILEID,pd_public_rw,0,PersDataCallback,&callbackct); + while (callbackct < 2 && IsStatsConnected()) + { + PersistThink(); + msleep(10); + } + + /************ + Now lets set some REAL data! + For player1 we will use ascii key\value pairs, for player2 we will store + binary structures. Note that if you store binary structures, YOU are responsible + for making sure things like byte order, structure size, and contents do not change + between versions or platforms of your game that may access the same data + ************/ + callbackct = 0; + playerdata.hitpoints = 600; + playerdata.modelnumber = 5; + playerdata.totaltime = 5000; + strcpy(playerdata.skin,"darkstar"); + SetPersistData(1,player1pid,pd_public_rw,0,(char *)&playerdata,sizeof(playerdata_t),PersDataSaveCallback,&callbackct); + SetPersistDataValues(2,PROFILEID,pd_public_rw,0,_T("\\key1\\value1\\key2\\value2\\key3\\value3"),PersDataSaveCallback,&callbackct); + while (callbackct < 2 && IsStatsConnected()) + { + PersistThink(); + msleep(10); + } + + /*********** + Lets read the data back, to see what's there! + We'll use a custom callback for player1 to print out the playerdata struct that's read back. + ************/ + callbackct = 0; + GetPersistData(1,player1pid,pd_public_rw,0,PlayerDataCallback,&callbackct); + GetPersistData(2,PROFILEID,pd_public_rw,0,PersDataCallback,&callbackct); + while (callbackct < 2 && IsStatsConnected()) + { + PersistThink(); + msleep(10); + } + + /*********** + Now, lets manipulate player2's data a bit using the SetPersistDataValues functions. + We'll also print it at each stage, so you can see the changes as they occur + + First, we'll update the values of key1 and key3 (but not key2) and add keys 4 and 5. + Your keys don't have to be numbered like this, this is just an example + ************/ + callbackct = 0; + SetPersistDataValues(2,PROFILEID,pd_public_rw,0,_T("\\key1\\valueA\\key3\\valueB\\key4\\value400\\key5\\value500"), + PersDataSaveCallback,&callbackct); + GetPersistData(2,PROFILEID,pd_public_rw,0,PersDataCallback,&callbackct); + + /*********** + Now we'll clear key 2, and update keys 3 and 4, and add two other keys + ************/ + SetPersistDataValues(2,PROFILEID,pd_public_rw,0,_T("\\key2\\\\key3\\valueC\\key4\\value401\\mykeyname\\mykeyvalue\\otherkey\\othervalue"), + PersDataSaveCallback,&callbackct); + GetPersistData(2,PROFILEID,pd_public_rw,0,PersDataCallback,&callbackct); + + /*********** + Finally, lets see how we can use GetPersistDataValues to only return a subset + of the keys that are stored. For example, we will only return keys 1,2,3,and 4 + The order you list them in does not matter + ************/ + GetPersistDataValues(2,PROFILEID,pd_public_rw,0,_T("\\key3\\key2\\key4\\key1"),PersDataCallback,&callbackct); + + /*********** + We've now sent off 5 requests without actually checking the results. The results are already coming in, + we just need to think a while to get them all + ************/ + while (callbackct < 5 && IsStatsConnected()) + { + PersistThink(); + msleep(100); + } + + /********** + When we're done we'll close off the connection + ***********/ + CloseStatsConnection(); + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + return 0; +} diff --git a/xrGameSpy/gamespy/gstats/persisttest/persisttest.dsp b/xrGameSpy/gamespy/gstats/persisttest/persisttest.dsp new file mode 100644 index 00000000000..617411fc8a5 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persisttest.dsp @@ -0,0 +1,289 @@ +# Microsoft Developer Studio Project File - Name="persisttest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=persisttest - Win32 Unicode 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 "persisttest.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 "persisttest.mak" CFG="persisttest - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "persisttest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "persisttest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "persisttest - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "persisttest - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/persisttest", BBVAAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "persisttest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "persisttest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /Fr /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "persisttest - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "persisttest___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "persisttest___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "persisttest - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "persisttest___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "persisttest___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# SUBTRACT BASE CPP /WX +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /FD /GZ /c +# SUBTRACT CPP /Fr /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "persisttest - Win32 Release" +# Name "persisttest - Win32 Debug" +# Name "persisttest - Win32 Unicode Release" +# Name "persisttest - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\persisttest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "PersistentStorageSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gbucket.c +# End Source File +# Begin Source File + +SOURCE=..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\gstats.c +# End Source File +# Begin Source File + +SOURCE=..\gstats.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/persisttest/persisttest.vcproj b/xrGameSpy/gamespy/gstats/persisttest/persisttest.vcproj new file mode 100644 index 00000000000..f3ce8d4dece --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persisttest.vcproj @@ -0,0 +1,567 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persisttest.vcproj.vspscc b/xrGameSpy/gamespy/gstats/persisttest/persisttest.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persisttest.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/persisttest/persisttest_vs2005.vcproj b/xrGameSpy/gamespy/gstats/persisttest/persisttest_vs2005.vcproj new file mode 100644 index 00000000000..c1964be7c8c --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persisttest_vs2005.vcproj @@ -0,0 +1,769 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/persisttest/persisttest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/gstats/persisttest/persisttest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..02d40d1f447 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/persisttest/persisttest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatslinux/Makefile b/xrGameSpy/gamespy/gstats/statstest/gstatslinux/Makefile new file mode 100644 index 00000000000..4fecc712ed1 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatslinux/Makefile @@ -0,0 +1,49 @@ +# Stats & Tracking SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=gstats + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../md5c.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../gstats.o\ + ../../gbucket.o\ + ../statstest.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsmacosx/Makefile b/xrGameSpy/gamespy/gstats/statstest/gstatsmacosx/Makefile new file mode 100644 index 00000000000..a3651e04747 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsmacosx/Makefile @@ -0,0 +1,25 @@ +# Stats & Tracking SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=statstest + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../gstats.o\ + ../../gbucket.o\ + ../statstest.o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/Nitro.lcf b/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/gstatsnitrocw.mcp b/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/gstatsnitrocw.mcp new file mode 100644 index 00000000000..1601bdf127e Binary files /dev/null and b/xrGameSpy/gamespy/gstats/statstest/gstatsnitrocw/gstatsnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps2/Makefile b/xrGameSpy/gamespy/gstats/statstest/gstatsps2/Makefile new file mode 100644 index 00000000000..a109aa204e0 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps2/Makefile @@ -0,0 +1,28 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = statstest + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o \ + ../../../hashtable.o \ + ../../../md5c.o \ + ../../../stringutil.o \ + ../../../available.o \ + ../../gstats.o \ + ../../gbucket.o \ + crt0.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps2cw/gstatsps2cw.mcp b/xrGameSpy/gamespy/gstats/statstest/gstatsps2cw/gstatsps2cw.mcp new file mode 100644 index 00000000000..dcf8a083056 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/statstest/gstatsps2cw/gstatsps2cw.mcp differ diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.dsp b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.dsp new file mode 100644 index 00000000000..c3acd7d852e --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.dsp @@ -0,0 +1,344 @@ +# Microsoft Developer Studio Project File - Name="gstatsps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gstatsps2prodg - Win32 Debug_Insock +!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 "gstatsps2prodg.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 "gstatsps2prodg.mak" CFG="gstatsps2prodg - Win32 Debug_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gstatsps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gstatsps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "gstatsps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "gstatsps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gstatsps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "gstatsps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/statstest/gstatsps2prodg", VSEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gstatsps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /w /W0 /Od /I "../.." /I "c:\usr\local\sce\ee\include\libeenet" /I "../../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gstatsps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gstatsps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gstatsps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gstatsps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "gstatsps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "../.." /I "c:\usr\local\sce\ee\include\libeenet" /I "../../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD CPP /nologo /w /W0 /Od /I "../.." /I "c:\usr\local\sce\ee\include\libeenet" /I "../../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "INSOCK" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gstatsps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\gstatsps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gstatsps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /w /W0 /Od /I "../.." /I "../../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gstatsps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\gstatsps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gstatsps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /w /W0 /O2 /I "../.." /I "c:\usr\local\sce\ee\include\libeenet" /I "../../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gstatsps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\gstatsps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gstatsps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gstatsps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "gstatsps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "../../.." /I "../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD CPP /nologo /w /W0 /O2 /I "../../.." /I "../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\gstatsps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\gstatsps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gstatsps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /w /W0 /O2 /I "../../.." /I "../.." /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gstatsps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\gstatsps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "gstatsps2prodg - Win32 Debug_EENet" +# Name "gstatsps2prodg - Win32 Debug_Insock" +# Name "gstatsps2prodg - Win32 Debug_SNSystems" +# Name "gstatsps2prodg - Win32 Release_EENet" +# Name "gstatsps2prodg - Win32 Release_Insock" +# Name "gstatsps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# Begin Source File + +SOURCE=..\statstest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "StatsSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gbucket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\..\gstats.c +# End Source File +# Begin Source File + +SOURCE=..\..\gstats.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.dsw b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.dsw new file mode 100644 index 00000000000..2f037f9f843 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gstatsps2prodg"=.\gstatsps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/statstest/gstatsps2prodg", VSEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gstats/statstest/gstatsps2prodg", VSEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.sln b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.sln new file mode 100644 index 00000000000..56cac1a2ff8 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gstatsps2prodg", "gstatsps2prodg.vcproj", "{0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 1 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = gstatsps2prodg.vcproj + SccProjectName0 = . + SccAuxPath0 = http://tfsapp1:8080 + SccLocalPath0 = . + SccProvider0 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {0B7B5EC8-6CC3-4419-B3EA-604F5E0E0788}.PS2 SN Systems Release|Win32.Build.0 = PS2 EENET Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.vcproj b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.vcproj new file mode 100644 index 00000000000..a09dfd79d7f --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps2prodg/gstatsps2prodg.vcproj @@ -0,0 +1,640 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps3/Makefile b/xrGameSpy/gamespy/gstats/statstest/gstatsps3/Makefile new file mode 100644 index 00000000000..81dbed6a43c --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps3/Makefile @@ -0,0 +1,33 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = statstest + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsAvailable.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../../hashtable.o \ + ../../../darray.o \ + ../../../md5c.o \ + ../../gstats.o \ + ../../gbucket.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps3prodg/gstatsps3prodg.sln b/xrGameSpy/gamespy/gstats/statstest/gstatsps3prodg/gstatsps3prodg.sln new file mode 100644 index 00000000000..de156ad3880 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps3prodg/gstatsps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gstatsps3prodg", "gstatsps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gstatsps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsps3prodg/gstatsps3prodg.vcproj b/xrGameSpy/gamespy/gstats/statstest/gstatsps3prodg/gstatsps3prodg.vcproj new file mode 100644 index 00000000000..58c70f0d779 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatsps3prodg/gstatsps3prodg.vcproj @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatspspprodg/gstatspspprodg.sln b/xrGameSpy/gamespy/gstats/statstest/gstatspspprodg/gstatspspprodg.sln new file mode 100644 index 00000000000..75f7b653b5c --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatspspprodg/gstatspspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gstatspspprodg", "gstatspspprodg.vcproj", "{0CF23F24-D9B9-405F-9D3F-7305246DC075}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gstatspspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0CF23F24-D9B9-405F-9D3F-7305246DC075}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {0CF23F24-D9B9-405F-9D3F-7305246DC075}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {0CF23F24-D9B9-405F-9D3F-7305246DC075}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {0CF23F24-D9B9-405F-9D3F-7305246DC075}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {0CF23F24-D9B9-405F-9D3F-7305246DC075}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {0CF23F24-D9B9-405F-9D3F-7305246DC075}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatspspprodg/gstatspspprodg.vcproj b/xrGameSpy/gamespy/gstats/statstest/gstatspspprodg/gstatspspprodg.vcproj new file mode 100644 index 00000000000..98f3409472c --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/gstatspspprodg/gstatspspprodg.vcproj @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/statstest/gstatsrevolutioncw/gstatsrevolutioncw.mcp b/xrGameSpy/gamespy/gstats/statstest/gstatsrevolutioncw/gstatsrevolutioncw.mcp new file mode 100644 index 00000000000..72357ed3e6f Binary files /dev/null and b/xrGameSpy/gamespy/gstats/statstest/gstatsrevolutioncw/gstatsrevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/gstats/statstest/statstest.c b/xrGameSpy/gamespy/gstats/statstest/statstest.c new file mode 100644 index 00000000000..d8ccddc4370 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/statstest.c @@ -0,0 +1,526 @@ +/****** +statstest.c +GameSpy Stats/Tracking SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + +Please see the GameSpy Stats and Tracking SDK for more info + +This file demonstrates usage of the various SDK functions by +simulating a game "host". + +******/ +#include +#include "../gstats.h" +#include "../../common/gsAvailable.h" + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define MY_GAMEPORT 2667 +#define MY_VERSION 1.23 +#define SNAPSHOT_LEN 1500 + +typedef struct +{ + gsi_char hostname[65]; + gsi_char mapname[30]; + gsi_char gametype[30]; + int numplayers; + float version; + //and other misc data + +} serverinfo_t; + +typedef struct +{ + gsi_char name[32]; + int points; + int deaths; + int profileid; + gsi_char auth[33]; + //and othem misc data +} playerinfo_t; + +static char *va(char *format, ...); +static gsi_char *CreateSnapShotFromData(gsi_char *snapshot, serverinfo_t *psinfo, playerinfo_t players[]); + +#ifdef __MWERKS__ // CodeWarrior warns if not protoyped + int test_main(int argc, char **argv); +#endif + +int test_main(int argc, char **argv) +{ + gsi_char snapshot[SNAPSHOT_LEN]; + serverinfo_t sinfo; + playerinfo_t players[64]; + statsgame_t g1, g2; + GSIACResult aResult = GSIACWaiting; + int anError = 0; + gsi_time startTime; + +/********* +First step, set our authentication info +We could do: + strcpy(gcd_gamename,"gmtest"); + strcpy(gcd_secret_key,"HA6zkS"); +...but this is more secure: +**********/ + gcd_gamename[0]='g';gcd_gamename[1]='m';gcd_gamename[2]='t';gcd_gamename[3]='e'; + gcd_gamename[4]='s';gcd_gamename[5]='t';gcd_gamename[6]='\0'; + gcd_secret_key[0]='H';gcd_secret_key[1]='A';gcd_secret_key[2]='6';gcd_secret_key[3]='z'; + gcd_secret_key[4]='k';gcd_secret_key[5]='S';gcd_secret_key[6]='\0'; + +/********* +Make sure we're using the development backend +**********/ + strcpy(StatsServerHostname, "sdkdev." GSI_DOMAIN_NAME); + +/********* +Make sure the GameSpy backend services are available +**********/ + GSIStartAvailableCheck(_T("gmtest")); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + msleep(50); + } + if (aResult == GSIACUnavailable) + { + printf("Backend services are not available\r\n"); + return 0; + } + +/********* +Next, open the stats connection. This may block for +a 1-2 seconds, so it should be done before the actual game starts. +**********/ + _tprintf(_T("Connecting to the stats server...\n")); + startTime = current_time(); + anError = InitStatsAsync(MY_GAMEPORT, 200000); // 20 second timeout + while(anError == GE_CONNECTING) + { + anError = InitStatsThink(); + msleep(50); + } + if (anError != GE_NOERROR) + { + _tprintf(_T("Failed to connect to stats server: %d\r\n"), anError); + return 0; + } + _tprintf(_T("Connected to stats server (%dms)\n"), current_time() - startTime); + + +/****************** +******************* +SAMPLE 1 +NON BUCKET BASED +******************* +******************/ + +/********* +Now we are ready to record a game. To start with, we'll assume that we are +only going to run one game at a time on this "server". That means we can +discard the return value of NewGame and pass NULL into anything that requires +a statsgame_t. + +The first example will not be bucket based, we'll generate the snapshot ourselves. +**********/ + NewGame(0); /* 0 = Not using buckets, manually generate snapshot */ +/******** +Now we'll "simulate" a server setting up by filling +in some of our structures +*********/ + _tcscpy(sinfo.hostname, _T("My l33t Server")); + _tcscpy(sinfo.mapname, _T("Level 33")); + _tcscpy(sinfo.gametype, _T("hunter")); + sinfo.numplayers = 0; + sinfo.version = (float)MY_VERSION; + +/******* +Lets simulate some players joining +If you are using authentication, you will need to send a challenge +to the player. You can get the challenge to send by calling GetChallenge +********/ + _tcscpy(players[sinfo.numplayers].name,_T("Bob!")); + players[sinfo.numplayers].points = 0; + players[sinfo.numplayers].deaths = 0; + players[sinfo.numplayers].profileid = 32432423; + //assume we got this value from a challenge reply + _tcscpy(players[sinfo.numplayers].auth,_T("7cca8e60a13781eebc820a50754f57cd")); + sinfo.numplayers++; + + _tcscpy(players[sinfo.numplayers].name,_T("Joey")); + players[sinfo.numplayers].points = 0; + players[sinfo.numplayers].deaths = 0; + players[sinfo.numplayers].profileid = 643423; + //assume we got this value from a challenge reply + _tcscpy(players[sinfo.numplayers].auth,_T("19ea14d9d92a7fcc635cf5716944d9bc")); + sinfo.numplayers++; + +/******* +Now simulate the players "playing" by giving them some points +********/ + //bob kills joey + players[0].points++; + players[1].deaths++; + //joey kills bob + players[1].points++; + players[0].deaths++; + //etc.. + players[0].points++; + players[1].deaths++; + players[1].points++; + players[0].deaths++; + players[0].points++; + players[1].deaths++; + players[0].points++; + players[1].deaths++; +/****** +Now we are in the middle of the game, so send a snapshot, in case we +"crash" before the game finishes. +******/ + CreateSnapShotFromData(snapshot, &sinfo, players); +/******* +Now send in the snapshot +*******/ + _tprintf(_T("Sending update snapshot\n")); + SendGameSnapShot(NULL, snapshot, SNAP_UPDATE); + +/****** +Simulate some more gameplay +*******/ + players[0].points++; + players[1].deaths++; + players[1].points++; + players[0].deaths++; + players[0].points++; + players[1].deaths++; +/****** +Game is now "done", create another snapshot and send it in as final +*******/ + CreateSnapShotFromData(snapshot, &sinfo, players); + _tprintf(_T("Sending final snapshot\n")); + SendGameSnapShot(NULL, snapshot, SNAP_FINAL); + +/******* +gsifree the game when done +*******/ + FreeGame(NULL); + +/********* +..and that's all there is. +*********/ + + +/****************** +******************* +SAMPLE 2 +BUCKET BASED +******************* +******************/ + +/******** +Now lets simulate the same thing +using bucket based snapshots instead of building them ourselves. + +We are already connected, so we can just create a new game. +**********/ + NewGame(1); /* this time we use buckets */ + +/******** +Now we'll set up the server and player info, this time using +buckets instead of internal structures. Note that you will probably +have copies of this stuff in internal structures as well. +********/ + BucketStringOp(NULL,"hostname",bo_set,"My L33t Server",bl_server, 0); + BucketStringOp(NULL,"mapname",bo_set,"Level 33",bl_server, 0); + BucketStringOp(NULL,"gametype",bo_set,"hunted",bl_server, 0); + BucketFloatOp(NULL,"gamever", bo_set,MY_VERSION, bl_server, 0); + + /* add the players */ + NewPlayer(NULL, 0, _T("Bob!")); + BucketIntOp(NULL,"pid",bo_set,32432423,bl_player, 0); + BucketStringOp(NULL,"auth",bo_set,"7cca8e60a13781eebc820a50754f57cd",bl_player, 0); + + NewPlayer(NULL, 1, _T("Joey!")); + BucketIntOp(NULL,"pid",bo_set,643423,bl_player, 1); + BucketStringOp(NULL,"auth",bo_set,"19ea14d9d92a7fcc635cf5716944d9bc",bl_player, 1); + +/******* +Again we simulate the game, this time updating values in the buckets +********/ + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 1); +/***** +Send our midway snapshot, this time the snapshot is +generated automatically by the buckets +******/ + SendGameSnapShot(NULL, NULL, SNAP_UPDATE); + + /* More of the game */ + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 1); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "score",bo_add, 1, bl_player, 0); + BucketIntOp(NULL, "deaths",bo_add, 1, bl_player, 1); +/***** +Send the final snapshot and gsifree the game, which frees +the buckets as well +******/ + _tprintf(_T("Sending final snapshot\n")); + SendGameSnapShot(NULL,NULL, SNAP_FINAL); + FreeGame(NULL); + + +/****************** +******************* +SAMPLE 3 +ADVANCED BUCKET BASED +******************* +******************/ + +/************** +Now lets show some of the advanced features of the system by: +1. Connecting and disconnecting clients +2. Using teams +3. Recording multiple, simultaneous games +4. Recording new types of data +**************/ + +/******* +Create a new bucket based game, this time save off the pointer, +since we'll be creating another game before this one is done +*******/ + g1 = NewGame(1); + +/********* +Start the game running... +*********/ + BucketStringOp(g1,"hostname",bo_set,"Advanced Server",bl_server, 0); + BucketStringOp(g1,"mapname",bo_set,"Level 39",bl_server, 0); + BucketStringOp(g1,"gametype",bo_set,"ctf",bl_server, 0); + BucketFloatOp(g1,"gamever", bo_set,MY_VERSION, bl_server, 0); + BucketIntOp(g1, "scorelimit", bo_set, 30,bl_server, 0); + BucketIntOp(g1, "timelimit",bo_set, 30, bl_server, 0); + + NewPlayer(g1, 0, _T("Bob!")); + BucketIntOp(g1,"pid",bo_set,32432423,bl_player, 0); + BucketStringOp(g1,"auth",bo_set,"7cca8e60a13781eebc820a50754f57cd",bl_player, 0); + + NewPlayer(g1, 1, _T("Joey")); + BucketIntOp(g1,"pid",bo_set,643423,bl_player, 1); + BucketStringOp(g1,"auth",bo_set,"19ea14d9d92a7fcc635cf5716944d9bc",bl_player, 1); + +/******** +This time create teams and assign the players to them. +Note that we use "GetTeamIndex" to get the translated index +for the team. +**********/ + NewTeam(g1,0, _T("Team number 1")); + NewTeam(g1,1, _T("Team number 2")); + + BucketIntOp(g1,"team",bo_set,GetTeamIndex(g1, 0),bl_player, 0); + BucketIntOp(g1,"team",bo_set,GetTeamIndex(g1, 1),bl_player, 1); + +/******* +Keep running the game, and watch as players join and leave, etc +********/ + BucketIntOp(g1, "score",bo_add, 1, bl_player, 0); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 0); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 1); + + NewPlayer(g1,2,_T("Jeronimo")); + BucketIntOp(g1,"pid",bo_set,54684,bl_player, 2); + BucketStringOp(g1,"auth",bo_set,"6a7d3fee261eb3db7f94f0f02c2c756b",bl_player, 2); + BucketIntOp(g1,"team",bo_set,GetTeamIndex(g1, 0),bl_player, 2); + + BucketIntOp(g1, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 1); + + RemovePlayer(g1, 0); + + BucketIntOp(g1, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 1); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 2); + + NewPlayer(g1,0,_T("Killer")); + BucketIntOp(g1,"pid",bo_set,32323,bl_player, 0); + BucketStringOp(g1,"auth",bo_set,"9e67d812bde48a6a29ee425c03b26894",bl_player, 0); + BucketIntOp(g1,"team",bo_set,GetTeamIndex(g1,0),bl_player, 0); + + BucketIntOp(g1, "suicides",bo_add, 1, bl_player, 0); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 1); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(g1, "suicides",bo_add, 1, bl_player, 0); + + RemovePlayer(g1, 1); + RemoveTeam(g1, 1); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 0); + + NewPlayer(g1,1,_T("Killer")); /* you can have two players with the same name */ + BucketIntOp(g1,"pid",bo_set,32323,bl_player, 1); + BucketStringOp(g1,"auth",bo_set,"dd975866a2c346814433e523bf8eda0e",bl_player, 1); + NewTeam(g1, 1, _T("Another Team")); + BucketIntOp(g1,"team",bo_set,GetTeamIndex(g1, 1),bl_player, 1); +/****** +Send a snapshot in the middle of the game.. +******/ + _tprintf(_T("Sending update snapshot\n")); + SendGameSnapShot(g1,NULL, SNAP_UPDATE); + BucketIntOp(g1, "captures",bo_add, 1, bl_team, 0); + + BucketIntOp(g1, "score",bo_add, 1, bl_player, 1); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 0); + +/********** +While this game is going on, create a new one! Keep updating +data for both games. For the second game we are going to keep +a "doom square" style kill list of who-killed-who +***********/ + g2 = NewGame(1); + + BucketStringOp(g2,"hostname",bo_set,"Another Server",bl_server, 0); + BucketStringOp(g2,"mapname",bo_set,"Level 40",bl_server, 0); + BucketStringOp(g2,"gametype",bo_set,"ctf",bl_server, 0); + BucketFloatOp(g2,"gamever", bo_set,MY_VERSION, bl_server, 0); + BucketIntOp(g2, "scorelimit", bo_set, 30,bl_server, 0); + BucketIntOp(g2, "timelimit",bo_set, 30, bl_server, 0); + + NewPlayer(g2, 0, _T("James")); + BucketIntOp(g2,"pid",bo_set,353352,bl_player, 0); + BucketStringOp(g2,"auth",bo_set,"eea4c47e3d4a2f68dffab1b084e382b7",bl_player, 0); + NewTeam(g2, 0, _T("Team Rocket")); + BucketIntOp(g2,"team",bo_set,GetTeamIndex(g2,0),bl_player, 0); + + + NewPlayer(g2, 1, _T("Jesse")); + BucketIntOp(g2,"pid",bo_set,5564554,bl_player, 1); + BucketStringOp(g2,"auth",bo_set,"d837be1371484bcbde9885dfc384b861",bl_player, 1); + BucketIntOp(g2,"team",bo_set,GetTeamIndex(g2,0),bl_player, 1); + + BucketIntOp(g1, "score",bo_add, 1, bl_player, 0); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g1, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(g1, "captures",bo_add, 1, bl_team, 0); + + NewPlayer(g2, 2, _T("Ash")); + BucketIntOp(g2,"pid",bo_set,6767565,bl_player, 2); + BucketStringOp(g2,"auth",bo_set,"417f3e186ca5ae0fa32665db3ddf54c8",bl_player, 2); + NewTeam(g2, 1, _T("Team Pika")); + BucketIntOp(g2,"team",bo_set,GetTeamIndex(g2,1),bl_player, 2); + + NewPlayer(g2, 3, _T("Pika")); + BucketIntOp(g2,"pid",bo_set,6767565,bl_player, 3); + BucketStringOp(g2,"auth",bo_set,"417f3e186ca5ae0fa32665db3ddf54c8",bl_player, 3); + BucketIntOp(g2,"team",bo_set,GetTeamIndex(g2,1),bl_player, 3); + + BucketIntOp(g2, "score",bo_add, 1, bl_player, 0); + BucketIntOp(g2, "deaths",bo_add, 1, bl_player, 2); + BucketIntOp(g2,va("kills%d",GetPlayerIndex(g2,2)), bo_add, 1, bl_player, 0); + BucketIntOp(g2, "score",bo_add, 1, bl_player, 2); + BucketIntOp(g2, "deaths",bo_add, 1, bl_player, 1); + BucketIntOp(g2,va("kills%d",GetPlayerIndex(g2,1)), bo_add, 1, bl_player, 2); + BucketIntOp(g2, "captures",bo_add, 1, bl_team, 1); + +/*********** +Close out the first game +***********/ + _tprintf(_T("Sending final snapshot\n")); + SendGameSnapShot(g1,NULL, SNAP_FINAL); + FreeGame(g1); + + /* more action in the second game */ + BucketIntOp(g2, "score",bo_add, 1, bl_player, 1); + BucketIntOp(g2, "deaths",bo_add, 1, bl_player, 2); + BucketIntOp(g2,va("kills%d",GetPlayerIndex(g2,2)), bo_add, 1, bl_player, 1); + BucketIntOp(g2, "score",bo_add, 1, bl_player, 3); + BucketIntOp(g2, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(g2,va("kills%d",GetPlayerIndex(g2,0)), bo_add, 1, bl_player, 3); + BucketIntOp(g2, "score",bo_add, 1, bl_player, 3); + BucketIntOp(g2, "deaths",bo_add, 1, bl_player, 0); + BucketIntOp(g2,va("kills%d",GetPlayerIndex(g2,0)), bo_add, 1, bl_player, 3); + BucketIntOp(g2, "captures",bo_add, 1, bl_team, 1); +/********** +Close out the second game +**********/ + _tprintf(_T("Sending final snapshot\n")); + SendGameSnapShot(g2,NULL, SNAP_FINAL); + FreeGame(g2); + +/**************** +Those are all the games for now, so go ahead and close +the connection +**************/ + + _tprintf(_T("Closing stats connection\n")); + CloseStatsConnection(); + + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + return 0; +} + + + +/* Helper for key name formatting */ +static char *va(char *format, ...) +{ + va_list argptr; + static char string[1024]; + va_start (argptr, format); + vsprintf (string, format,argptr); + va_end (argptr); + return string; +} + + +/* Helper function to create a snapshot from the above structures when not using +bucket based snapshots */ +static gsi_char *CreateSnapShotFromData(gsi_char *snapshot, serverinfo_t *psinfo, playerinfo_t players[]) +{ + int i; + size_t len; + + _tsnprintf(snapshot, SNAPSHOT_LEN, _T("\\hostname\\%s\\mapname\\%s\\gametype\\%s\\gamever\\%f"), + psinfo->hostname, psinfo->mapname, psinfo->gametype, psinfo->version); + for (i = 0 ; i < psinfo->numplayers ; i++) + { + len = _tcslen(snapshot); + _tsnprintf(snapshot + len, SNAPSHOT_LEN - len, + _T("\\player_%d\\%s\\points_%d\\%d\\deaths_%d\\%d\\pid_%d\\%d\\auth_%d\\%s"), + i, players[i].name, i, players[i].points, i, players[i].deaths, i, players[i].profileid,i, players[i].auth); + } + return snapshot; +} diff --git a/xrGameSpy/gamespy/gstats/statstest/statstest.dsp b/xrGameSpy/gamespy/gstats/statstest/statstest.dsp new file mode 100644 index 00000000000..425dd82da04 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/statstest.dsp @@ -0,0 +1,222 @@ +# Microsoft Developer Studio Project File - Name="statstest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=statstest - 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 "statstest.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 "statstest.mak" CFG="statstest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "statstest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "statstest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/gstats/statstest" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "statstest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 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:console /machine:I386 +# ADD LINK32 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:console /machine:I386 + +!ELSEIF "$(CFG)" == "statstest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "statstest - Win32 Release" +# Name "statstest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\statstest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "StatsSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gbucket.c +# End Source File +# Begin Source File + +SOURCE=..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\gstats.c +# End Source File +# Begin Source File + +SOURCE=..\gstats.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/statstest/statstest.vcproj b/xrGameSpy/gamespy/gstats/statstest/statstest.vcproj new file mode 100644 index 00000000000..e5a6ca0350b --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/statstest.vcproj @@ -0,0 +1,470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/statstest/statstest.vcproj.vspscc b/xrGameSpy/gamespy/gstats/statstest/statstest.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/statstest.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/statstest/statstest_vs2005.vcproj b/xrGameSpy/gamespy/gstats/statstest/statstest_vs2005.vcproj new file mode 100644 index 00000000000..4074cbee2f9 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/statstest_vs2005.vcproj @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/statstest/statstest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/gstats/statstest/statstest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/statstest/statstest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/track/LoginDlg.cpp b/xrGameSpy/gamespy/gstats/track/LoginDlg.cpp new file mode 100644 index 00000000000..c465d962bd3 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/LoginDlg.cpp @@ -0,0 +1,174 @@ +// LoginDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "track.h" +#include "LoginDlg.h" + +#include "../../gp/gp.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + + +CLoginDlg::CLoginDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLoginDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoginDlg) + m_email = _T(""); + m_nick = _T(""); + m_password = _T(""); + //}}AFX_DATA_INIT +} + + +void CLoginDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoginDlg) + DDX_Text(pDX, IDC_EMAIL, m_email); + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_PASSWORD, m_password); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoginDlg, CDialog) + //{{AFX_MSG_MAP(CLoginDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg message handlers + +GPResult checkResult; +int checkProfile; + +void CheckUserCallback(GPConnection * connection, void * _arg, void * param) +{ + GPCheckResponseArg * arg = (GPCheckResponseArg *)_arg; + + checkResult = arg->result; + checkProfile = arg->profile; +} + +void CLoginDlg::OnOK() +{ + GPConnection connection; + HCURSOR hourglass; + HCURSOR lastCursor; + GPResult result; + + UpdateData(); + + // CHECK FOR NO ACCOUNT INFO + //////////////////////////// + if(m_email.IsEmpty() || m_nick.IsEmpty() || m_password.IsEmpty()) + { + MessageBox("Please fill in all the account information."); + return; + } + + // INITIALIZE GP + //////////////// + if(gpInitialize(&connection, 488, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR) + { + MessageBox("Error initializing the login system."); + return; + } + + // wait cursor on + ///////////////// + hourglass = LoadCursor(NULL, IDC_WAIT); + if(hourglass) + lastCursor = SetCursor(hourglass); + + // CHECK FOR THE ACCOUNT SPECIFIED + ////////////////////////////////// + result = gpCheckUser(&connection, m_nick, m_email, m_password, GP_BLOCKING, CheckUserCallback, NULL); + + // wait cursor off + ////////////////// + if(hourglass) + SetCursor(lastCursor); + + // DESTROY THE GP OBJECT + //////////////////////// + gpDestroy(&connection); + + // CHECK FOR AN ERROR + ///////////////////// + if(result != GP_NO_ERROR) + { + MessageBox("Error verifying the account."); + return; + } + + // CHECK THE RESULT + /////////////////// + if(checkResult != GP_NO_ERROR) + { + if(checkResult == GP_CHECK_BAD_EMAIL) + MessageBox("Invalid e-mail."); + else if(checkResult == GP_CHECK_BAD_NICK) + MessageBox("Invalid nick."); + else if(checkResult == GP_CHECK_BAD_PASSWORD) + MessageBox("Invalid password."); + else + MessageBox("Error verifying the account."); + return; + } + + // save the login info for next time + //////////////////////////////////// + FILE * file; + file = fopen("login.txt", "wt"); + if(file) + { + fprintf(file, "%s\n%s\n%s", m_email, m_nick, m_password); + fclose(file); + } + + // STORE THE PROFILE ID + /////////////////////// + m_profile = checkProfile; + + CDialog::OnOK(); +} + +BOOL CLoginDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // load login info + ////////////////// + FILE * file; + file = fopen("login.txt", "rt"); + if(file) + { + char buffer[512]; + + if(fgets(buffer, sizeof(buffer), file)) + m_email = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_nick = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_password = buffer; + + fclose(file); + + m_email.Remove('\n'); + m_nick.Remove('\n'); + m_password.Remove('\n'); + } + + UpdateData(FALSE); + + return TRUE; +} diff --git a/xrGameSpy/gamespy/gstats/track/LoginDlg.h b/xrGameSpy/gamespy/gstats/track/LoginDlg.h new file mode 100644 index 00000000000..8d98d134880 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/LoginDlg.h @@ -0,0 +1,50 @@ +#if !defined(AFX_LOGINDLG_H__6C88CC46_47E9_420F_BC33_BA7F28711BAD__INCLUDED_) +#define AFX_LOGINDLG_H__6C88CC46_47E9_420F_BC33_BA7F28711BAD__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LoginDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + +class CLoginDlg : public CDialog +{ +// Construction +public: + int m_profile; + CLoginDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoginDlg) + enum { IDD = IDD_LOGIN }; + CString m_email; + CString m_nick; + CString m_password; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoginDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoginDlg) + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOGINDLG_H__6C88CC46_47E9_420F_BC33_BA7F28711BAD__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/track/StdAfx.cpp b/xrGameSpy/gamespy/gstats/track/StdAfx.cpp new file mode 100644 index 00000000000..5a50dd72a59 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// track.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/gstats/track/StdAfx.h b/xrGameSpy/gamespy/gstats/track/StdAfx.h new file mode 100644 index 00000000000..7b0d71917c5 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/StdAfx.h @@ -0,0 +1,26 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__1CD5EB62_03A4_40FF_8CFA_8AF283DA824A__INCLUDED_) +#define AFX_STDAFX_H__1CD5EB62_03A4_40FF_8CFA_8AF283DA824A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__1CD5EB62_03A4_40FF_8CFA_8AF283DA824A__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/track/res/track.ico b/xrGameSpy/gamespy/gstats/track/res/track.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/gstats/track/res/track.ico differ diff --git a/xrGameSpy/gamespy/gstats/track/res/track.rc2 b/xrGameSpy/gamespy/gstats/track/res/track.rc2 new file mode 100644 index 00000000000..e962277e3f0 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/res/track.rc2 @@ -0,0 +1,13 @@ +// +// TRACK.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/gstats/track/resource.h b/xrGameSpy/gamespy/gstats/track/resource.h new file mode 100644 index 00000000000..936c31540cf --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/resource.h @@ -0,0 +1,34 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by track.rc +// +#define IDC_EMAIL 101 +#define IDD_TRACK_DIALOG 102 +#define IDC_NICK 102 +#define IDC_PASSWORD 103 +#define IDR_MAINFRAME 128 +#define IDD_LOGIN 129 +#define IDC_LOGOUT 1003 +#define IDC_PROGRESS 1005 +#define IDC_INFO 1006 +#define IDC_START_100 1007 +#define IDC_START_50 1008 +#define IDC_START_200 1009 +#define IDC_RANDOM_STATS 1010 +#define IDC_BEST_50 1011 +#define IDC_BEST_100 1012 +#define IDC_BEST_200 1013 +#define IDC_TOP_50 1014 +#define IDC_TOP_100 1015 +#define IDC_TOP_200 1016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1012 +#define _APS_NEXT_SYMED_VALUE 104 +#endif +#endif diff --git a/xrGameSpy/gamespy/gstats/track/track.cpp b/xrGameSpy/gamespy/gstats/track/track.cpp new file mode 100644 index 00000000000..71d228d2157 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track.cpp @@ -0,0 +1,74 @@ +// track.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "track.h" +#include "trackDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTrackApp + +BEGIN_MESSAGE_MAP(CTrackApp, CWinApp) + //{{AFX_MSG_MAP(CTrackApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTrackApp construction + +CTrackApp::CTrackApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CTrackApp object + +CTrackApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CTrackApp initialization + +BOOL CTrackApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CTrackDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/gstats/track/track.dsp b/xrGameSpy/gamespy/gstats/track/track.dsp new file mode 100644 index 00000000000..efbb4980aa1 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track.dsp @@ -0,0 +1,686 @@ +# Microsoft Developer Studio Project File - Name="track" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=track - 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 "track.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 "track.mak" CFG="track - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "track - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "track - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gstats/track", OAACAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "track - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "track - Win32 Release" +# Name "track - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\LoginDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\track.cpp +# End Source File +# Begin Source File + +SOURCE=.\track.rc +# End Source File +# Begin Source File + +SOURCE=.\trackDlg.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\LoginDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\track.h +# End Source File +# Begin Source File + +SOURCE=.\trackDlg.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\track.ico +# End Source File +# Begin Source File + +SOURCE=.\res\track.rc2 +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c + +!IF "$(CFG)" == "track - Win32 Release" + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c + +!IF "$(CFG)" == "track - Win32 Release" + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c + +!IF "$(CFG)" == "track - Win32 Release" + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c + +!IF "$(CFG)" == "track - Win32 Release" + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c + +!IF "$(CFG)" == "track - Win32 Release" + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c + +!IF "$(CFG)" == "track - Win32 Release" + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\GP\gp.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpi.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuddy.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiCallback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiConnect.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiInfo.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiOperation.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiPeer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiProfile.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiSearch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiTransfer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c + +!IF "$(CFG)" == "track - Win32 Release" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "track - Win32 Debug" + +# ADD CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUtility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.h +# End Source File +# End Group +# Begin Group "StatsSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gbucket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gbucket.h +# End Source File +# Begin Source File + +SOURCE=..\gpersist.h +# End Source File +# Begin Source File + +SOURCE=..\gstats.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gstats.h +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gstats/track/track.h b/xrGameSpy/gamespy/gstats/track/track.h new file mode 100644 index 00000000000..721cf157216 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track.h @@ -0,0 +1,49 @@ +// track.h : main header file for the TRACK application +// + +#if !defined(AFX_TRACK_H__0DF04935_1FD6_4741_AEC5_5A40455C0C7F__INCLUDED_) +#define AFX_TRACK_H__0DF04935_1FD6_4741_AEC5_5A40455C0C7F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CTrackApp: +// See track.cpp for the implementation of this class +// + +class CTrackApp : public CWinApp +{ +public: + CTrackApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTrackApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CTrackApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TRACK_H__0DF04935_1FD6_4741_AEC5_5A40455C0C7F__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/track/track.rc b/xrGameSpy/gamespy/gstats/track/track.rc new file mode 100644 index 00000000000..e89ea5dae0f --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track.rc @@ -0,0 +1,214 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\track.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\track.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_TRACK_DIALOG DIALOGEX 0, 0, 312, 76 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "track" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Exit",IDOK,260,7,50,14 + PUSHBUTTON "Logout",IDC_LOGOUT,260,23,50,14 + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,15,50,80,14 + LTEXT "Info",IDC_INFO,100,55,60,8 + PUSHBUTTON "Start 100m",IDC_START_100,90,30,65,14 + PUSHBUTTON "Start 50m",IDC_START_50,15,30,65,14 + PUSHBUTTON "Start 200m",IDC_START_200,165,30,65,14 + LTEXT "88.888",IDC_BEST_50,55,10,23,8 + LTEXT "88.888",IDC_BEST_100,130,10,23,8 + LTEXT "88.888",IDC_BEST_200,205,10,23,8 + LTEXT "88.888",IDC_TOP_50,55,20,23,8 + LTEXT "88.888",IDC_TOP_100,130,20,23,8 + LTEXT "88.888",IDC_TOP_200,205,20,23,8 + LTEXT "Best Time:",IDC_STATIC,15,20,34,8 + LTEXT "Your Time:",IDC_STATIC,15,10,35,8 + LTEXT "Best Time:",IDC_STATIC,90,20,34,8 + LTEXT "Your Time:",IDC_STATIC,90,10,35,8 + LTEXT "Best Time:",IDC_STATIC,165,20,34,8 + LTEXT "Your Time:",IDC_STATIC,165,10,35,8 + LTEXT "Use Z && X to race",IDC_STATIC,165,55,75,8 +END + +IDD_LOGIN DIALOG DISCARDABLE 0, 0, 147, 76 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GameSpy Login" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_EMAIL,51,8,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_NICK,51,23,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,51,38,84,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "Login",IDOK,15,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,80,55,50,14 + LTEXT "email:",IDC_STATIC,10,10,19,8 + LTEXT "nick:",IDC_STATIC,10,25,16,8 + LTEXT "password:",IDC_STATIC,10,40,33,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "track MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "track\0" + VALUE "LegalCopyright", "Copyright (C) 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "track.EXE\0" + VALUE "ProductName", "track Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_TRACK_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 305 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_LOGIN, DIALOG + BEGIN + LEFTMARGIN, 7 + TOPMARGIN, 7 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\track.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/gstats/track/track.vcproj b/xrGameSpy/gamespy/gstats/track/track.vcproj new file mode 100644 index 00000000000..fde76c76632 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track.vcproj @@ -0,0 +1,1084 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/track/track.vcproj.vspscc b/xrGameSpy/gamespy/gstats/track/track.vcproj.vspscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gstats/track/trackDlg.cpp b/xrGameSpy/gamespy/gstats/track/trackDlg.cpp new file mode 100644 index 00000000000..2fc44c42c2d --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/trackDlg.cpp @@ -0,0 +1,441 @@ +// trackDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "track.h" +#include "trackDlg.h" + +#include "../gstats.h" +#include "../../common/gsAvailable.h" +#include "../../ghttp/ghttp.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define TIMER_ONE_SECOND 100 +#define TIMER_THINK 101 + +///////////////////////////////////////////////////////////////////////////// +// CTrackDlg dialog + +CTrackDlg::CTrackDlg(CWnd* pParent /*=NULL*/) + : CDialog(CTrackDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTrackDlg) + m_info = _T("Ready"); + m_best100 = _T(""); + m_best200 = _T(""); + m_best50 = _T(""); + m_top100 = _T(""); + m_top200 = _T(""); + m_top50 = _T(""); + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CTrackDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTrackDlg) + DDX_Control(pDX, IDC_PROGRESS, m_progress); + DDX_Text(pDX, IDC_INFO, m_info); + DDX_Text(pDX, IDC_BEST_100, m_best100); + DDX_Text(pDX, IDC_BEST_200, m_best200); + DDX_Text(pDX, IDC_BEST_50, m_best50); + DDX_Text(pDX, IDC_TOP_100, m_top100); + DDX_Text(pDX, IDC_TOP_200, m_top200); + DDX_Text(pDX, IDC_TOP_50, m_top50); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CTrackDlg, CDialog) + //{{AFX_MSG_MAP(CTrackDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_LOGOUT, OnLogout) + ON_WM_TIMER() + ON_BN_CLICKED(IDC_START_50, OnStart50) + ON_BN_CLICKED(IDC_START_100, OnStart100) + ON_BN_CLICKED(IDC_START_200, OnStart200) + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTrackDlg message handlers + +CTrackDlg * Dlg; + +GHTTPBool PlayerBestTimesPageCompleted +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + if(result == GHTTPSuccess) + { + int bestTimes[3]; + int rcode; + + // Scan out the best times. + /////////////////////////// + rcode = sscanf(buffer, "%d %d %d", &bestTimes[0], &bestTimes[1], &bestTimes[2]); + if(rcode == 3) + { + Dlg->UpdateData(); + Dlg->m_best50.Format("%0.3f", bestTimes[0] / 1000.0); + Dlg->m_best100.Format("%0.3f", bestTimes[1] / 1000.0); + Dlg->m_best200.Format("%0.3f", bestTimes[2] / 1000.0); + Dlg->UpdateData(FALSE); + } + } + + return GHTTPTrue; +} + +GHTTPBool TopTimePageCompleted +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + if(result == GHTTPSuccess) + { + int time = atoi(buffer); + if(time) + { + CString str; + str.Format("%0.3f", time / 1000.0); + + int event = (int)param; + Dlg->UpdateData(); + if(event == 1) + Dlg->m_top50 = str; + else if(event == 2) + Dlg->m_top100 = str; + else if(event == 3) + Dlg->m_top200 = str; + Dlg->UpdateData(FALSE); + } + } + + return GHTTPTrue; +} + +void CTrackDlg::SetupUser() +{ + CString title; + title.Format("track - best time (%s - %s - %d)", m_loginDlg.m_email, m_loginDlg.m_nick, m_loginDlg.m_profile); + SetWindowText(title); + + CString url; + int event; + url.Format("http://sdkdev.gamespy.com/games/st_highscore/web/playertimes.asp?pid=%d", m_loginDlg.m_profile); + ghttpGet(url, GHTTPFalse, PlayerBestTimesPageCompleted, NULL); + for(event = 1 ; event <= 3 ; event++) + { + url.Format("http://sdkdev.gamespy.com/games/st_highscore/web/top_%d.txt", event); + ghttpGet(url, GHTTPFalse, TopTimePageCompleted, (void *)event); + } + + m_start = 0; + m_count = -1; + m_racing = FALSE; + m_event = EVENT_NONE; + m_numSteps = 0; + m_step = NONE; +} + +BOOL CTrackDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + int rcode; + CString str; + + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIcon, FALSE); + + Dlg = this; + + // Use the development system. + ////////////////////////////// + strcpy(StatsServerHostname, "sdkdev.gamespy.com"); + + // Set the gamename and secret key. + /////////////////////////////////// + strcpy(gcd_gamename, "st_highscore"); + gcd_secret_key[0] = 'K'; + gcd_secret_key[1] = 'S'; + gcd_secret_key[2] = '3'; + gcd_secret_key[3] = 'p'; + gcd_secret_key[4] = '2'; + gcd_secret_key[5] = 'Q'; + + // Perform the availability check + ////////////////////////////////////// + GSIACResult aResult = GSIACWaiting; + GSIStartAvailableCheck(gcd_gamename); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + Sleep(50); + } + + // Init the connection to the backend. + ////////////////////////////////////// + rcode = InitStatsConnection(0); + if(rcode != GE_NOERROR) + { + str.Format("Failed to connect to the stats server (%d).", rcode); + MessageBox(str); + PostQuitMessage(1); + return TRUE; + } + + // Login the user (actually just verifying the login). + ////////////////////////////////////////////////////// + if(m_loginDlg.DoModal() != IDOK) + { + PostQuitMessage(1); + return TRUE; + } + + SetTimer(TIMER_ONE_SECOND, 1000, NULL); + SetTimer(TIMER_THINK, 50, NULL); + + SetupUser(); + + return TRUE; +} + +void CTrackDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +HCURSOR CTrackDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CTrackDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + if(IsStatsConnected()) + CloseStatsConnection(); + + ghttpCleanup(); +} + +void CTrackDlg::OnLogout() +{ + ShowWindow(SW_HIDE); + if(m_loginDlg.DoModal() != IDOK) + PostQuitMessage(1); + SetupUser(); + ShowWindow(SW_SHOW); +} + +void CTrackDlg::OnTimer(UINT nIDEvent) +{ + if(nIDEvent == TIMER_ONE_SECOND) + { + if(m_count) + { + UpdateData(TRUE); + + if(m_count == 3) + m_info = "READY"; + else if(m_count == 2) + m_info = "SET"; + else if(m_count == 1) + m_info = "GO"; + + UpdateData(FALSE); + + if(m_count == 1) + { + m_numSteps = 0; + m_step = NONE; + m_racing = TRUE; + m_start = GetTickCount(); + } + + m_count--; + } + } + else if(nIDEvent == TIMER_THINK) + { + ghttpThink(); + } + + CDialog::OnTimer(nIDEvent); +} + +void CTrackDlg::ReportStats(DWORD time) +{ + char response[33]; + + NewGame(1); + BucketStringOp(NULL, "hostname", bo_set, (char *)(LPCSTR)m_loginDlg.m_nick, bl_server, 0); + BucketIntOp(NULL, "event", bo_set, m_event, bl_server, 0); + + NewPlayer(NULL, 0, (char *)(LPCSTR)m_loginDlg.m_nick); + BucketIntOp(NULL, "time", bo_set, time, bl_player, 0); + BucketIntOp(NULL, "pid", bo_set, m_loginDlg.m_profile, bl_player, 0); + GenerateAuth(GetChallenge(NULL), (char *)(LPCSTR)m_loginDlg.m_password, response); + BucketStringOp(NULL, "auth", bo_set, response, bl_player, 0); + + SendGameSnapShot(NULL, NULL, SNAP_FINAL); + FreeGame(NULL); +} + +BOOL CTrackDlg::PreTranslateMessage(MSG* pMsg) +{ + if(pMsg->message == WM_KEYDOWN) + { + int nChar = pMsg->wParam; + if((nChar == 'Z') || (nChar == 'X')) + { + if((pMsg->lParam & 0xFFFF) == 1) + { + CString str; + BOOL stepped = FALSE; + + if((nChar == 'Z') && (m_step != LEFT)) + { + m_step = LEFT; + m_numSteps++; + stepped = TRUE; + } + else if ((nChar == 'X') && (m_step != RIGHT)) + { + m_step = RIGHT; + m_numSteps++; + stepped = TRUE; + } + + if(stepped && m_racing) + { + m_progress.SetPos(m_numSteps); + if(m_numSteps == m_totalSteps) + { + DWORD diff; + + m_racing = FALSE; + diff = (GetTickCount() - m_start); + str.Format("%0.3fs\n", diff / 1000.0); + OutputDebugString(str); + MessageBox(str); + + UpdateData(); + + m_info = "DONE"; + + // Report the stats. + //////////////////// + ReportStats(diff); + + // Update best time(s) if needed. + ///////////////////////////////// + CString * topStr; + CString * bestStr; + DWORD topTime; + DWORD bestTime; + if(m_event == EVENT_50) + { + topStr = &m_top50; + bestStr = &m_best50; + } + else if(m_event == EVENT_100) + { + topStr = &m_top100; + bestStr = &m_best100; + } + else + { + topStr = &m_top200; + bestStr = &m_best200; + } + + topTime = (DWORD)(atof(*topStr) * 1000); + bestTime = (DWORD)(atof(*bestStr) * 1000); + if(!bestTime || (diff < bestTime)) + { + bestStr->Format("%0.3f", diff / 1000.0); + if(diff < topTime) + *topStr = *bestStr; + } + + UpdateData(FALSE); + + m_event = EVENT_NONE; + } + } + } + + return TRUE; + } + } + + return CDialog::PreTranslateMessage(pMsg); +} + +void CTrackDlg::OnStart50() +{ + m_count = 3; + m_totalSteps = RACE_STEPS_50; + m_progress.SetRange(0, m_totalSteps); + m_progress.SetPos(0); + m_event = EVENT_50; +} + +void CTrackDlg::OnStart100() +{ + m_count = 3; + m_totalSteps = RACE_STEPS_100; + m_progress.SetRange(0, m_totalSteps); + m_progress.SetPos(0); + m_event = EVENT_100; +} + +void CTrackDlg::OnStart200() +{ + m_count = 3; + m_totalSteps = RACE_STEPS_200; + m_progress.SetRange(0, m_totalSteps); + m_progress.SetPos(0); + m_event = EVENT_200; +} diff --git a/xrGameSpy/gamespy/gstats/track/trackDlg.h b/xrGameSpy/gamespy/gstats/track/trackDlg.h new file mode 100644 index 00000000000..946821dcc1a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/trackDlg.h @@ -0,0 +1,90 @@ +// trackDlg.h : header file +// + +#if !defined(AFX_TRACKDLG_H__E16D2398_5E86_47A2_80DA_8F843E24C4A6__INCLUDED_) +#define AFX_TRACKDLG_H__E16D2398_5E86_47A2_80DA_8F843E24C4A6__INCLUDED_ + +#include "LoginDlg.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CTrackDlg dialog + +#define NONE -1 +#define LEFT 0 +#define RIGHT 1 + +#define RACE_STEPS_50 60 +#define RACE_STEPS_100 120 +#define RACE_STEPS_200 240 + +#define EVENT_NONE 0 +#define EVENT_50 1 +#define EVENT_100 2 +#define EVENT_200 3 + +class CTrackDlg : public CDialog +{ +// Construction +public: + void SetupUser(); + DWORD m_start; + int m_count; + int m_event; + BOOL m_racing; + int m_numSteps; + int m_step; + int m_totalSteps; + void ReportStats(DWORD time); + + CTrackDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CTrackDlg) + enum { IDD = IDD_TRACK_DIALOG }; + CProgressCtrl m_progress; + CString m_info; + CString m_best100; + CString m_best200; + CString m_best50; + CString m_top100; + CString m_top200; + CString m_top50; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTrackDlg) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + CLoginDlg m_loginDlg; + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CTrackDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnLogout(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnStart50(); + afx_msg void OnStart100(); + afx_msg void OnStart200(); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TRACKDLG_H__E16D2398_5E86_47A2_80DA_8F843E24C4A6__INCLUDED_) diff --git a/xrGameSpy/gamespy/gstats/track/track_vs2005.vcproj b/xrGameSpy/gamespy/gstats/track/track_vs2005.vcproj new file mode 100644 index 00000000000..bc8f18e0158 --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track_vs2005.vcproj @@ -0,0 +1,1504 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gstats/track/track_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/gstats/track/track_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..41454cbb37a --- /dev/null +++ b/xrGameSpy/gamespy/gstats/track/track_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/changelog.txt b/xrGameSpy/gamespy/gt2/changelog.txt new file mode 100644 index 00000000000..8d6dd70d914 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/changelog.txt @@ -0,0 +1,144 @@ +Changelog for: GameSpy Transport SDK 2 +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.09.00 RMV RELEASE Released to Developer Site +12-07-2007 2.08.03 SAH OTHER Fixed VC6 projects missing dependencies +12-07-2007 2.08.02 SN FIX Added check to sample app for PS3 maximum send size +11-27-2007 2.08.01 SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +08-06-2007 2.08.00 RMV RELEASE Released to Developer Site +07-11-2007 2.07.03 RMV FIX Fixed gt2testc Project files to get rid of Unicode warnings and fixed other compiler warnings +06-07-2007 2.07.02 SN RELEASE Released to Developer Site +04-16-2007 2.07.02 SN CLEANUP Put back a removed calling convention + 2.07.02 SN CLEANUP Added a check to the message handler to pass messages to unrecognized message callback + if a GT2Connection has not been complete. +01-16-2007 2.07.01 DES FEATURE Added X360 support +12-15-2006 2.07.00 MJW RELEASE Released to Developer Site +12-04-2006 2.06.78 SN FIX Added some checks to message size in test application for revolution +12-04-2006 2.06.77 SN FIX Changed the gti2MacToIP and gti2IpToMac functions to be public functions +11-10-2006 2.06.76 JR RELEASE Limited release +10-23-2006 2.06.76 DES RELEASE Limited release +10-05-2006 2.06.76 SAH FIX Updated MacOSX Makefile +09-28-2006 2.06.75 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +09-07-2006 2.06.74 DES FEATURE Added support for string arrays to gt2Encode + DES FIX Fixed potential to read past the end of a truncated buffer when decoding strings +08-24-2006 2.06.73 SAH FIX Fixed VC7 Project file +08-15-2006 2.06.72 SAH FIX Fixed VDP assertion in gt2main.c (call to gt2Send) +08-04-2006 2.06.71 SAH FIX Changed call in gt2proxy.c from ctime to gsiSecondsToString +08-02-2006 2.06.70 SAH RELEASE Releasing to developer site +07-31-2006 2.06.70 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 2.06.69 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-24-2006 2.06.68 SAH FIX Removed #ifdef _PS3 for socket calls (changed platformSocket.h to typecast calls) +07-06-2006 2.06.67 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +06-30-2006 2.06.66 SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) + SAH FIX Fixed Linux makefile +06-06-2006 2.06.65 MJ FEATURE Added Adhoc Support for PSP. +05-31-2006 2.06.64 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-30-2006 2.06.63 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) +05-25-2006 2.06.62 SAH FIX Changed PSP project warning levels +05-24-2006 2.06.61 SAH FIX Added (socklen_t) typecast for PS3 warnings to gt2socket.c +05-19-2006 2.06.60 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-19-2006 2.06.59 SAH FIX Added GS_STATIC_CALLBACK in front of 3 compare functions for __fastcall support +05-15-2006 2.06.58 SAH FIX Added "PS3 Release" configuration to project +05-05-2006 2.06.57 SAH FIX Fixed the gt2action.dsp project - needed to include a few encryption files for http +04-27-2006 2.06.56 MJ FEATURE Added gtEncodedMessageTypeSet +04-25-2006 2.06.55 SAH RELEASE Releasing to developer site +04-24-2006 2.06.55 SAH FIX Added function prototypes, fixed/added typecasts and Nitro project files +04-20-2006 2.06.54 SAH FIX Commented out unused variables, break; statements + FIX Commented out unncessary checks (if unsigned int > 0) +04-20-2006 2.06.53 SAH FIX Added _PS3 wrapper typecast for socket calls +04-14-2006 2.06.52 SAH FIX few more typecasts in gt2memcpy calls (forgot to do PC ones) +04-14-2006 2.06.51 SAH FIX Added some typecasts in gt2memcpy calls to get rid of warnings +01-27-2006 2.05.50 SN RELEASE Releasing to developer site +01-27-2006 2.05.50 SN FIX Updated test_main define for PSP + SN FIX PSP and PS2 only use messages smaller than 8K + SN OTHER Added psp prodg project and solution to sgv +01-26-2006 2.05.49 SN FIX Force gt2IPToHostInfo to return NULL for PSP since PSP doesn't have a gethostbyaddr +01-11-2006 2.05.49 SN FIX Added platform checks to socket error handlers + SN FIX Added visual studio .net project and solution +01-11-2006 2.05.48 SN FIX updated callling convention to only be WIN32 +12-20-2005 2.05.47 SN OTHER Cleaned up and added missing common code to projects if needed +12-20-2005 2.05.46 SN FIX Fixed VDP specific changes that caused messages to be truncated + Removed VDP checks in parts of code that previously had them +12-19-2005 2.05.45 SN FIX Added preprocessor directive around code creating a VDP socket + Changed buffer offset to use a constant +12-07-2005 2.05.44 DDW FEATURE Added Win64 build support +12-06-2005 2.05.43 SN FEATURE Added Xbox VDP support +11-17-2005 2.05.42 DES FIX Updated Nitro Makefile. +11-14-2005 2.05.41 DES FIX Updated the OSX Makefile. +10-11-2005 2.05.40 SN FIX Updated gt2test dsp to have new common code files gsassert and gsmemory +09-21-2005 2.05.39 DES FEATURE Updated DS support + DES FIX Updated to handle additional UDP sending errors + DES FIX Updated OSX Makefile +09-12-2005 2.05.38 SN FIX Fixed unhandled socket error code +07-28-2005 2.05.37 SN RELEASE Releasing to developer site. +07-28-2005 2.05.37 SN FIX Changed IP address to use local host for gt2testc +06-03-2005 2.05.36 SN RELEASE Releasing to developer site. +05-05-2005 2.05.36 BED FIX Updated project files to use new common folder. +05-04-2005 2.05.35 SN FIX Changes for XBox platform +05-03-2005 2.05.34 SN FIX Removed deprecated MFC code for VS .NET project + And fixed implicit cast performed in a callback + SN OTHER Created Visual Studio .NET projects +04-28-2005 2.05.33 SN RELEASE Releasing to developer site. +04-27-2005 2.05.33 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 2.05.33 DES FIX Limit the Nitro to a 1500 byte message buffer. + DES CLEANUP Disable Win32 linker warning. +04-19-2005 2.05.32 DES FEATURE Added the ability to send raw UDP datagrams through a GT2Socket. + This feature can also be used to send broadcast datagrams. +04-15-2005 2.05.31 DES FIX XBox fix. +04-08-2005 2.05.30 DES FEATURE Changes for XBox support. +04-04-2005 2.05.29 SN RELEASE Release to developer site. +03-14-2005 2.05.29 DES FIX Fixed buffering multiple copies of incoming reliable messages + FIX Fixed detection of incoming reliable message buffer overflow +03-14-2005 2.05.28 DES FEATURE Nintendo DS support +01-27-2003 2.05.27 DES FIX Fixed custom SN sendto and moved it to nonport +01-03-2005 2.05.26 SN FIX Added const qualifiers to unmodified formal function parameters +09-23-2004 2.05.25 DES FIX Changed IPs that were using unsigned long to unsigned int. + DES FIX Changed times that were using unsigned long to gsi_time. + DES FIX Sockets now correctly bind to a provided local IP when created. +09-17-2004 2.05.24 DES FEATURE Added functions for confirming receipt of reliable messages. +09-16-2004 2.05.23 SN RELEASE Releasing to developer site. +08-27-2004 2.05.23 DES CLEANUP General Unicode cleanup + DES CLEANUP Removed MacOS style includes + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Fixed warnings under OSX + DES FEATURE Added OSX Makefile +08-25-2004 2.05.22 DES FEATURE Added OSX makefile +08-16-2004 2.05.22 SN FEATURE Updated gt2hostmig and gt2nat to use QR2 instead of legacy Q & R +08-05-2004 2.05.21 SN RELEASE Releasing to developer site. +07-20-2004 2.05.21 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +06-18-2004 2.05.20 BED RELEASE Releasing to developer site. +06-18-2004 2.05.20 DES FIX Checking for trying to connect to an invalid IP range. +10-21-2003 2.05.19 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-21-2003 2.05.19 BED FIX Added #ifdef because SN_SYSTEMS doesn't support EHOSTDOWN +10-09-2003 2.05.18 BED FIX Switched to gsi_time type instead of unsinged long for PS2 compatibility +07-25-2003 2.05.17 DES FIX Ignoring EHOSTDOWN sendto error. +07-24-2003 2.05.16 DES RELEASE Releasing to developer site. +07-18-2003 2.05.16 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 2.05.15 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 2.05.14 DES FIX Changed a few __mips64 checks to _PS2 checks. + BED FEATURE Added ProDG sample project files. +07-11-2003 2.05.13 DES RELEASE Releasing to developer site. +05-12-2003 2.05.13 DES FIX Fixed a crashing bug that could occur on socket errors. +05-09-2003 2.05.12 DES CLEANUP Removed Dreamcast support. +03-24-2003 2.05.11 DES FIX Fixed assumption that messages passed to callbacks were always NUL terminated. +03-03-2003 2.05.10 DES CLEANUP General cleanup to remove warnings. +02-05-2003 2.05.09 DES RELEASE Releasing to developer site. +02-05-2003 2.05.09 DES CLEANUP Switched to use the common code CanReceiveOnSocket and CanSendOnSocket. +12-19-2002 2.05.08 DES RELEASE Releasing to developer site. +12-19-2002 2.05.08 DES CLEANUP Removed assert.h includes. +12-16-2002 2.05.07 DES OTHER Moved handling of SN Systems lack of support for gethostbyaddr() to nonport. + CLEANUP Removed call to GOAClearSocketError. +12-13-2002 2.05.06 DES FEATURE Added PS2 eenet stack support. +11-22-2002 2.05.05 DES RELEASE Releasing to developer site. +11-20-2002 2.05.05 DES CLEANUP Cleaned up code to remove PS2 compiler warnings. +11-18-2002 2.05.04 DES RELEASE Release to developer site. +11-18-2002 2.05.04 DES FIX Fixed alignment bug in gtEncodedMessageType. +11-14-2002 2.05.03 DES OTHER Removed BLOCKING_SOCKETS define from PS2 makefile, leftover from GT +11-14-2002 2.05.02 DES FIX Fixed gt2testc to stop sending messages at the correct time +11-13-2002 2.05.01 DES FIX Resends an ack if a duplicate message is received +09-25-2002 2.05.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/gt2/gt2.dsp b/xrGameSpy/gamespy/gt2/gt2.dsp new file mode 100644 index 00000000000..12c64bdaed7 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2.dsp @@ -0,0 +1,268 @@ +# Microsoft Developer Studio Project File - Name="gt2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=gt2 - 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 "gt2.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 "gt2.mak" CFG="gt2 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2 - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gt2 - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2", PSNCAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2 - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gt2 - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "gt2 - Win32 Release" +# Name "gt2 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=.\gt2Utility.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gt2.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=.\gt2Utility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\hashtable.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2.dsw b/xrGameSpy/gamespy/gt2/gt2.dsw new file mode 100644 index 00000000000..2d9aca774d1 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2.dsw @@ -0,0 +1,133 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gt2"=.\gt2.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2", PSNCAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2action"=.\gt2action\gt2action.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2action", DQOCAAAA + .\gt2action + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2hostmig"=.\gt2hostmig\gt2hostmig.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2hostmig", AQOCAAAA + .\gt2hostmig + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2nat"=.\gt2nat\gt2nat.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2nat", TTOCAAAA + .\gt2nat + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2proxy"=.\gt2proxy\gt2proxy.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2proxy", RSOCAAAA + .\gt2proxy + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2test"=.\gt2test\gt2test.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2test", IBOCAAAA + .\gt2test + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gt2testc"=.\gt2testc\gt2testc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2testc", LPOCAAAA + .\gt2testc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2", PSNCAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/gt2/gt2.h b/xrGameSpy/gamespy/gt2/gt2.h new file mode 100644 index 00000000000..5ef96914ba7 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2.h @@ -0,0 +1,664 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/**************************** +** GameSpy Transport SDK 2 ** +****************************/ + +/* +** see "configurable defines" in gt2Main.h for certain performance settings that can be changed +*/ + +#ifndef _GT2_H_ +#define _GT2_H_ + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/********** +** TYPES ** +**********/ + +// boolean +typedef int GT2Bool; +#define GT2False 0 +#define GT2True 1 + +// a byte +typedef unsigned char GT2Byte; + +// a handle to a socket object (can be used to accept connections and initiate connections) +typedef struct GTI2Socket * GT2Socket; + +// a handle to an object representing a connection to a specific IP and port +// the local endpoint is a GT2Socket +typedef struct GTI2Connection * GT2Connection; + +// the id of a reliably sent message +// unreliable messages don't have ids +typedef unsigned short GT2MessageID; + +// the result of a GT2 operation +// check individual function definitions to see possible results +// TODO: list possible results wherever this is used +typedef enum +{ + GT2Success, // success + // errors: + GT2OutOfMemory, // ran out of memory + GT2Rejected, // attempt rejected + GT2NetworkError, // networking error (could be local or remote) + GT2AddressError, // invalid or unreachable address + GT2DuplicateAddress, // a connection was attempted to an address that already has a connection on the socket + GT2TimedOut, // time out reached + GT2NegotiationError, // there was an error negotiating with the remote side + GT2InvalidConnection, // the connection didn't exist + GT2InvalidMessage, // used for vdp reliable messages containing voice data, no voice data in reliable messages + GT2SendFailed // the send failed, +} GT2Result; + +// possible states for any GT2Connection +typedef enum +{ + GT2Connecting, // negotiating the connection + GT2Connected, // the connection is active + GT2Closing, // the connection is being closed + GT2Closed // the connection has been closed and can no longer be used +} GT2ConnectionState; + +// The cause of the connection being closed. +typedef enum +{ + GT2LocalClose, // The connection was closed with gt2CloseConnection. + GT2RemoteClose, // The connection was closed remotely. + // errors: + GT2CommunicationError, // An invalid message was received (it was either unexpected or wrongly formatted). + GT2SocketError, // An error with the socket forced the connection to close. + GT2NotEnoughMemory // There wasn't enough memory to store an incoming or outgoing message. +} GT2CloseReason; + +/************ +** GLOBALS ** +************/ + +// The challenge key is a 32 character string +// that is used in the authentication process. +// The key can be set before GT2 is used so +// that the key will be application-specific. +extern char GT2ChallengeKey[33]; + +/********************* +** SOCKET CALLBACKS ** +*********************/ + +// this callback gets called when there was is an error that forces a socket to close +// all connections that use this socket are terminated, and their gt2CloseCallback callbacks +// will be called before this callback is called (with the reason set to GT2SocketError). +// the socket cannot be used again after this callback returns +typedef void (* gt2SocketErrorCallback) +( + GT2Socket socket +); + +/********************* +** SOCKET FUNCTIONS ** +*********************/ + +// creates a local socket +// if the IP of the local address is 0, then any/all ips will be bound. +// if the port of the local address is 0, then a port will be assigned. +// if either buffer sizes is set to 0, a default value will be used (currently 64K for PC, 4k for Xbox). +// the buffer needs to be able to hold all messages waiting for confirmation of delivery, +// and it needs to hold any messages that arrive out of order. if either buffer runs out +// of space the connection will be dropped. +GT2Result gt2CreateSocket +( + GT2Socket * socket, // if the result is GT2Success, the socket object handle will be stored at this address + const char * localAddress, // the local address to bind to + int outgoingBufferSize, // size of per-connection buffer where sent messages waiting to be confirmed are held, use 0 for default + int incomingBufferSize, // size of per-connection buffer where out-of-order received messages are held, use 0 for default + gt2SocketErrorCallback callback // a callback that is called if there is an error with the socket +); + +// AdHoc Sockets use MAC address instead of IP address. +GT2Result gt2CreateAdHocSocket +( + GT2Socket * socket, // if the result is GT2Success, the socket object handle will be stored at this address + const char * localAddress, // the local address to bind to + int outgoingBufferSize, // size of per-connection buffer where sent messages waiting to be confirmed are held, use 0 for default + int incomingBufferSize, // size of per-connection buffer where out-of-order received messages are held, use 0 for default + gt2SocketErrorCallback callback // a callback that is called if there is an error with the socket +); + +#ifdef _XBOX +// creates a local VDP socket on the Xbox platform +// if the IP of the local address is 0, then any/all ips will be bound. +// if the port of the local address is 0, then a port will be assigned. +// if either buffer sizes is set to 0, a default value will be used (currently 4K). +// the buffer needs to be able to hold all messages waiting for confirmation of delivery, +// and it needs to hold any messages that arrive out of order. if either buffer runs out +// of space the connection will be dropped. +GT2Result gt2CreateVDPSocket +( + GT2Socket * socket, // if the result is GT2Success, the socket object handle will be stored at this address + const char * localAddress, // the local address to bind to + int outgoingBufferSize, // size of per-connection buffer where sent messages waiting to be confirmed are held, use 0 for default + int incomingBufferSize, // size of per-connection buffer where out-of-order received messages are held, use 0 for default + gt2SocketErrorCallback callback // a callback that is called if there is an error with the socket +); +#endif + +// closes a local socket. +// all existing connections will be hard closed, as if gt2CloseAllConnectionsHard was +// called for this socket. all connections send a close message to the remote side, +// and any closed callbacks will be called from within this function +void gt2CloseSocket(GT2Socket socket); + +// processes a socket (and all associated connections) +void gt2Think(GT2Socket socket); + +// sends a raw UDP datagram through the socket +// this function bypasses the normal connection logic +// note that all messages sent this way will be unreliable +// to broadcast a datagram, omit the IP from the remoteAddress (e.g., ":12345") +GT2Result gt2SendRawUDP +( + GT2Socket socket, // the socket through which to send the raw UDP datagram + const char * remoteAddress, // the address to which to send the datagram + const GT2Byte * message, // the message to send, or NULL for an empty datagram + int len // the len of the message (0 for an empty message, ignored if message==NULL) +); + +/************************* +** CONNECTION CALLBACKS ** +*************************/ + +// Called when the connect has completed. +// If the result is GT2Rejected, +// then message is the message that the +// listener passed to gt2Reject. If the +// result is anything else, then message +// is NULL and len is 0. +typedef void (* gt2ConnectedCallback) +( + GT2Connection connection, // The connection object. + GT2Result result, // Result from connect attempt. + GT2Byte * message, // If result==GT2Rejected, the reason. Otherwise, NULL. + int len // If result==GT2Rejected, the length of the reason. Otherwise, 0. +); + +// Called when a message is received. +typedef void (* gt2ReceivedCallback) +( + GT2Connection connection, // The connection the message was received on. + GT2Byte * message, // The message that was received. Will be NULL if an empty message. + int len, // The length of the message in bytes. Will be 0 if an empty message. + GT2Bool reliable // True if this is was sent reliably. +); + +// Called when the connection is closed (remotely or locally). +// The connection can no longer be used after this callback returns. +typedef void (* gt2ClosedCallback) +( + GT2Connection connection, // The connection that was closed. + GT2CloseReason reason // The reason the connection was closed. +); + +// When a reply is received for a ping that was sent, this callback is called. +// The latency reported here is the amount of time between when the ping +// was first sent with gt2Ping and when the pong was received. +typedef void (* gt2PingCallback) +( + GT2Connection connection, // the connection the ping was sent on + int latency // the round-trip time for the ping, in milliseconds +); + +// Callbacks set for each connection. +// The connected callback is ignored +// when this is passed to gt2Accept. +typedef struct +{ + gt2ConnectedCallback connected; // Called when gt2Connect is complete. + gt2ReceivedCallback received; // Called when a message is received. + gt2ClosedCallback closed; // Called when the connection is closed (remotely or locally). + gt2PingCallback ping; // Called when a ping reply is received. +} GT2ConnectionCallbacks; + +/************************* +** CONNECTION FUNCTIONS ** +*************************/ + +// initiates a connection between a local socket and a remote socket +// if blocking is true, the return value signals the connection result: +// GT2Success means the connect attempt succeeded +// anything else means it failed +// if blocking is false, the return value signals the current status of the attempt +// GT2Success means the connection is being attempted +// anything else means there was an error and the connection attempt has been aborted +GT2Result gt2Connect +( + GT2Socket socket, // the local socket to use for the connection + GT2Connection * connection, // if the result is GT2Success, and blocking is false, the connection object handle is stored here + const char * remoteAddress, // the address to connect to + const GT2Byte * message, // an optional initial message (may be NULL) + int len, // length of the initial message (may be 0, or -1 for strlen) + int timeout, // timeout in milliseconds (may be 0 for infinite retries) + GT2ConnectionCallbacks * callbacks, // callbacks for connection related stuff + GT2Bool blocking // if true, don't return until complete (successfuly or unsuccessfuly) +); + +// sends data reliably or unreliably +// reliable messages are guaranteed to arrive, arrive in order, and arrive only once. +// unreliable messages are not guaranteed to arrive, arrive in order, or arrive only once. +// because messages may be held in the outgoing buffer (even unreliable messages may need +// to be put in the buffer), the message size cannot exceed +GT2Result gt2Send +( + GT2Connection connection, // the connection to send the message on + const GT2Byte * message, // the message to send, or NULL for an empty message0 + int len, // the len of the message (0 for an empty message, ignored if message==NULL) + GT2Bool reliable // if true, send the message reliably +); + +// sends a ping on a connection in an attempt to determine latency +// the ping is unreliable, and either it or the pong sent in reply +// could be dropped (resulting in the callback never being called), +// or it could even arrive multiple times (resulting in multiple +// calls to the callback). +void gt2Ping(GT2Connection connection); + +// starts an attempt to close the connection +// when the close is completed, the connection's closed callback will be called +void gt2CloseConnection(GT2Connection connection); + +// same as gt2CloseConnection, but doesn't wait for confirmation from the remote side of the connection +// the closed callback will be called from within this function +void gt2CloseConnectionHard(GT2Connection connection); + +// closes all of a socket's connections (essentially calls gt2CloseConnection on each of them). +void gt2CloseAllConnections(GT2Socket socket); + +// same as gt2CloseAllConnections, but does a hard close +// any closed callbacks will be called from within this function +void gt2CloseAllConnectionsHard(GT2Socket socket); + +/********************* +** LISTEN CALLBACKS ** +*********************/ + +// callback gets called when someone attempts to connect to a socket that is listening for new connections. +// in response to this callback the application should call gt2Accept or gt2Reject. they do not need +// to be called from inside the callback, however they should be called in a timely manner so that the +// remote side does not need to sit around indefinitely waiting for a response. +// the latency is an estimate of the round trip time between connections. +typedef void (* gt2ConnectAttemptCallback) +( + GT2Socket socket, // the socket the attempt came in on + GT2Connection connection, // a connection object for the incoming connection attempt + unsigned int ip, // the IP being used remotely for the connection attempt + unsigned short port, // the port being used remotely for the connection attempt + int latency, // the approximate latency on the connection + GT2Byte * message, // an optional message sent with the attempt. Will be NULL if an empty message. + int len // the length of the message, in characters. Will be 0 if an empty message. +); + +/********************* +** LISTEN FUNCTIONS ** +*********************/ + +// tells a socket to start listening for incoming connections +// any connections attempts will cause the callback to be called +// if the socket is already listening, this callback will replace the exsiting callback being used +// if the callback is NULL, this will cause the connection to stop listening +void gt2Listen(GT2Socket socket, gt2ConnectAttemptCallback callback); + +// after a socket's gt2ConnectAttemptCallback has been called, this function can be used to accept +// the incoming connection attempt. it can be called from either within the callback or some later time. +// as soon as it is called the connection is active, and messages can be sent and received. the remote side +// of the connection will have it's connected callback called with the result set to GT2Success. the callbacks +// that are passed in to this function are the same callbacks that get passed to gt2Connect, with the exception +// that the connected callback can be ignored, as the connection is already established. +// if this function returns GT2True, then the connection has been successfully accepted. if it returns +// GT2False, then the remote side has already closed the connection attempt. in that case, the connection +// is considered closed, and it cannot be referenced again. +GT2Bool gt2Accept(GT2Connection connection, GT2ConnectionCallbacks * callbacks); + +// after a socket's gt2ConnectAttemptCallback has been called, this function can be used to reject +// the incoming connection attempt. it can be called from either within the callback or some later time. +// once the function is called the connection is considered closed and cannot be referenced again. the remote +// side attempting the connection will have its connected callback called with the result set to GT2Rejected. +// if the message is not NULL and the len is not 0, the message will be sent with the rejection, and passed +// into the remote side's connected callback. +void gt2Reject(GT2Connection connection, const GT2Byte * message, int len); + +/************************* +** MESSAGE CONFIRMATION ** +*************************/ +// gets the message id for the last reliably sent message. unreliable messages do not have ids. +// this should be called immediately after gt2Send. waiting until after a call to gt2Think can result in +// an invalid message id being returned. +// note that the use of filters that can either drop or delay messages can complicate the process, because +// in those cases a call to gt2Send does not guarantee that a message will actually be sent. in those cases, +// gt2GetLastSentMessageID should be called after gt2FilteredSend, because the actual message will be sent +// from within that function. +GT2MessageID gt2GetLastSentMessageID(GT2Connection connection); + +// returns true if confirmation was received locally that the reliable message represented by the message id +// was received by the remote end of the connection. returns false if confirmation was not yet received. +// this should only be called on message ids that were returned by gt2GetLastSendMessageID, and should be +// used relatively soon after the message was sent, due to message ids wrapping around after a period of time. +GT2Bool gt2WasMessageIDConfirmed(GT2Connection connection, GT2MessageID messageID); + +/********************* +** FILTER CALLBACKS ** +*********************/ + +// Callback for filtering outgoing data. +// Call gt2FilteredSend with the filtered data, either from within the callback or later. +// the message points to the same memory location as the message passed to gt2Send (or gt2FilteredSend). +// so if the call to gt2FilteredSend is delayed, it is the filter's responsibility to make sure the +// data is still around when and if it is needed. +typedef void (* gt2SendFilterCallback) +( + GT2Connection connection, // The connection on which the message is being sent. + int filterID, // Pass this ID to gt2FilteredSend. + const GT2Byte * message, // The message being sent. Will be NULL if an empty message. + int len, // The length of the message being sent, in bytes. Will be 0 if an empty message. + GT2Bool reliable // If the message is being sent reliably. +); + +// Callback for filtering incoming data. +// Call gt2FilteredRecieve with the filtered data, +// either from within the callback or later. +// the message may point to a memory location supplied to gt2FilteredReceive by a previous filter. +// so if this filter's call to gt2FilteredReceive is delayed, it is the filter's responsibility +// to make sure the data is still around when and if it is needed. +typedef void (* gt2ReceiveFilterCallback) +( + GT2Connection connection, // The connection the message was received on. + int filterID, // Pass this ID to gtFilteredReceive. + GT2Byte * message, // The message that was received. Will be NULL if an empty message. + int len, // The length of the message in bytes. Will be 0 if an empty message. + GT2Bool reliable // True if this is a reliable message. +); + +/********************* +** FILTER FUNCTIONS ** +*********************/ + +// Adds a filter to the connection's outgoing data. +// Returns GT2False if there was an error adding the filter (due to no free memory) +GT2Bool gt2AddSendFilter +( + GT2Connection connection, // The connection on which to add the filter. + gt2SendFilterCallback callback // The callback the outgoing data is filtered through. +); + +// Removes a filter from the connection's outgoing data. +// if callback is NULL, all send filters are removed +void gt2RemoveSendFilter +( + GT2Connection connection, // The connection on which to remove the filter. + gt2SendFilterCallback callback // The callback to remove. +); + +// Called in response to a gt2SendFilterCallback being called. +// It can be called from within the callback, or at any later time. +void gt2FilteredSend +( + GT2Connection connection, // The connection on which the message is being sent. + int filterID, // The ID passed to the gt2SendFilterCallback. + const GT2Byte * message, // The message being sent. May be NULL. + int len, // The lengt2h of the message being sent, in bytes. May be 0 or -1. + GT2Bool reliable // If the message should be sent reliably. +); + +// Adds a filter to the connection's incoming data. +// Returns GT2False if there was an error adding the filter (due to no free memory) +GT2Bool gt2AddReceiveFilter +( + GT2Connection connection, // The connection on which to add the filter. + gt2ReceiveFilterCallback callback // The callback the incoming data is filtered through. +); + +// Removes a filter from the connection's incoming data. +// if callback is NULL, all receive filters are removed +void gt2RemoveReceiveFilter +( + GT2Connection connection, // The connection on which to remove the filter. + gt2ReceiveFilterCallback callback // The callback to remove. +); + +// Called in response to a gt2ReceiveFilterCallback being called. +// It can be called from within the callback, or at any later time. +void gt2FilteredReceive +( + GT2Connection connection, // The connection the message was received on. + int filterID, // The ID passed to the gt2ReceiveFilterCallback. + GT2Byte * message, // The message that was received. May be NULL. + int len, // The lengt2h of the message in bytes. May be 0. + GT2Bool reliable // True if this is a reliable message. +); + +/***************************** +** SOCKET SHARING CALLBACKS ** +*****************************/ + +// this callback gets called when the sock receives a message that it cannot match to an existing +// connection. if the callback recognizes the message and handles it, it should return GT2True, which +// will tell the socket to ignore the message. if the callback does not recognize the message, it +// should return GT2False, which tells the socket to let the other side know there is no connection. +typedef GT2Bool (* gt2UnrecognizedMessageCallback) +( + GT2Socket socket, // the socket the message was received on + unsigned int ip, // the ip of the remote machine the message came from (in network byte order) + unsigned short port, // the port on the remote machine (in host byte order) + GT2Byte * message, // the message (may be NULL for an empty message) + int len // the length of the message (may be 0) +); + +/***************************** +** SOCKET SHARING FUNCTIONS ** +*****************************/ + +// this function returns the actual underlying socket for a GT2Socket. +// this can be used for socket sharing purposes, along with the gt2UnrecognizedMessageCallback. +SOCKET gt2GetSocketSOCKET(GT2Socket socket); + +// sets a callback that all unrecognized messages are passed to. an unrecognized message is one +// that can't be matched up to a specific connection. if the callback handles the message, it +// returns true, and the GT2Socket ignores the message. if the callback does not recognize the message, +// it returns false, and the socket handles the message (by sending a message back indicating the connection +// is closed). if the callback is NULL, it removes any previously set callback. +void gt2SetUnrecognizedMessageCallback(GT2Socket socket, gt2UnrecognizedMessageCallback callback); + +/******************* +** INFO FUNCTIONS ** +*******************/ + +// gets the socket this connection exists on +GT2Socket gt2GetConnectionSocket(GT2Connection connection); + +// gets the connection's connection state +// GT2Connecting - the connection is still being negotiated +// GT2Connected - the connection is active (has successfully connected, and not yet closed) +// GT2Closing - the connection is in the process of closing (i.e., sent a close message and waiting for confirmation). +// GT2Closed - the connection has already been closed and will soon be freed +GT2ConnectionState gt2GetConnectionState(GT2Connection connection); + +// gets a connection's remote IP (in network byte order) +unsigned int gt2GetRemoteIP(GT2Connection connection); + +// gets a connection's remote port (in host byte order) +unsigned short gt2GetRemotePort(GT2Connection connection); + +// gets a socket's local IP (in network byte order) +unsigned int gt2GetLocalIP(GT2Socket socket); + +// gets a socket's local port (in host byte order) +unsigned short gt2GetLocalPort(GT2Socket socket); + +// gets the total size of the connection's incoming buffer. +int gt2GetIncomingBufferSize(GT2Connection connection); + +// gets the amount of available space in the connection's incoming buffer. +int gt2GetIncomingBufferFreeSpace(GT2Connection connection); + +// gets the total size of the connection's outgoing buffer. +int gt2GetOutgoingBufferSize(GT2Connection connection); + +// gets the amount of available space in the connection's outgoing buffer. +int gt2GetOutgoingBufferFreeSpace(GT2Connection connection); + +/************************ +** USER DATA FUNCTIONS ** +************************/ + +void gt2SetSocketData(GT2Socket socket, void * data); +void * gt2GetSocketData(GT2Socket socket); +void gt2SetConnectionData(GT2Connection connection, void * data); +void * gt2GetConnectionData(GT2Connection connection); + +/************************* +** BYTE ORDER FUNCTIONS ** +*************************/ + +unsigned int gt2NetworkToHostInt(unsigned int i); +unsigned int gt2HostToNetworkInt(unsigned int i); +unsigned short gt2HostToNetworkShort(unsigned short s); +unsigned short gt2NetworkToHostShort(unsigned short s); + +/********************** +** ADDRESS FUNCTIONS ** +**********************/ + +// Converts an IP and a port into a text string. The IP must be in network byte order, and the port +// in host byte order. The string must be able to hold at least 22 characters (including the NUL). +// "XXX.XXX.XXX.XXX:XXXXX" +// If both the IP and port are non-zero, the string will be of the form "1.2.3.4:5" (":"). +// If the port is zero, and the IP is non-zero, the string will be of the form "1.2.3.4" (""). +// If the IP is zero, and the port is non-zero, the string will be of the form ":5" (":"). +// If both the IP and port are zero, the string will be an empty string ("") +// The string is returned. If the string paramater is NULL, then an internal static string will be +// used. There are two internal strings that are alternated between. +const char * gt2AddressToString +( + unsigned int ip, // IP in network byte order. Can be 0. + unsigned short port, // Port in host byte order. Can be 0. + char string[22] // String will be placed in here. Can be NULL. +); + +// Converts a string address into an IP and a port. The IP is stored in network byte order, and the port +// is stored in host byte order. Returns false if there was an error parsing the string, or if a supplied +// hostname can't be resolved. +// Possible string forms: +// NULL => all IPs, any port (localAddress only). +// "" => all IPs, any port (localAddress only). +// "1.2.3.4" => 1.2.3.4 IP, any port (localAddress only). +// "host.com" => host.com's IP, any port (localAddress only). +// ":2786" => all IPs, 2786 port (localAddress only). +// "1.2.3.4:0" => 1.2.3.4 IP, any port (localAddress only). +// "host.com:0" => host.com's IP, any port (localAddress only). +// "0.0.0.0:2786" => all IPs, 2786 port (localAddress only). +// "1.2.3.4:2786" => 1.2.3.4 IP, 2786 port (localAddress or remoteAddress). +// "host.com:2786" => host.com's IP, 2786 port (localAddress or remoteAddress). +// If this function needs to resolve a hostname ("host.com") it may need to contact a DNS server, which can +// cause the function to block for an indefinite period of time. Usually it is < 2 seconds, but on certain +// systems, and under certain circumstances, it can take 30 seconds or longer. +GT2Bool gt2StringToAddress +( + const char * string, // The string to convert. + unsigned int * ip, // The IP is stored here, in network byte order. Can be NULL. + unsigned short * port // The port is stored here, in host byte order. Can be NULL. +); + +// Gets the host information for a machine on the Internet. The first version takes an IP in network byte order, +// and the second version takes a string that is either a dotted ip ("1.2.3.4"), or a hostname ("www.gamespy.com"). +// If the function can successfully lookup the host's info, the host's main hostname will be returned. If it +// cannot find the host's info, it returns NULL. +// For the aliases parameter, pass in a pointer to a variable of type (char **). If this parameter is not NULL, +// and the function succeeds, the variable will point to a NULL-terminated list of alternate names for the host. +// For the ips parameter, pass in a pointer to a variable of type (int **). If this parameter is not NULL, and +// the function succeeds, the variable will point to a NULL-terminated list of altername IPs for the host. Each +// element in the list is actually a pointer to an unsigned int, which is an IP address in network byte order. +// The return value, aliases, and IPs all point to an internal data structure, and none of these values should +// be modified directly. Also, the data is only valid until another call needs to use the same data structure +// (virtually ever internet address function will use this data structure). If the data will be needed in the +// future, it should be copied off. +// If this function needs to resolve a hostname ("host.com") it may need to contact a DNS server, which can +// cause the function to block for an indefinite period of time. Usually it is < 2 seconds, but on certain +// systems, and under certain circumstances, it can take 30 seconds or longer. +const char * gt2IPToHostInfo(unsigned int ip, char *** aliases, unsigned int *** ips); +const char * gt2StringToHostInfo(const char * string, char *** aliases, unsigned int *** ips); + +// The following functions are shortcuts for the above two functions (gt2*ToHostInfo()), and each performs a subset +// of the functionality. They are provided so that code that only needs certain information can be a little simpler. +// Before using these, read the comments for the gt2*ToHostInfo() functions, as the info also applies to these functions. +const char * gt2IPToHostname(unsigned int ip); +const char * gt2StringToHostname(const char * string); +char ** gt2IPToAliases(unsigned int ip); +char ** gt2StringToAliases(const char * string); +unsigned int ** gt2IPToIPs(unsigned int ip); +unsigned int ** gt2StringToIPs(const char * string); + +#ifdef _XBOX +unsigned int gt2XnAddrToIP(XNADDR theAddr, XNKID theKeyId); +GT2Bool gt2IPToXnAddr(int ip, XNADDR *theAddr, XNKID *theKeyId); +#endif + +// these are for getting around adhoc which requires a 48 bit address v.s. a 32 bit inet address +void gt2IpToMac(gsi_u32 ip,char *mac); +// change IP address to mac ethernet +gsi_u32 gt2MacToIp(const char *mac); +// change mac ethernet to IP address + +/******************* +** DUMP CALLBACKS ** +*******************/ + +// called with either sent or received data +// trying to send a message from within the send dump callback, or letting the socket think from within the receive +// dump callback can cause serious problems, and should not be done. +typedef void (* gt2DumpCallback) +( + GT2Socket socket, // the socket the message was on + GT2Connection connection, // the connection the message was on, or NULL if there is no connection for this message + unsigned int ip, // the remote ip, in network byte order + unsigned short port, // the remote port, in host byte order + GT2Bool reset, // if true, the connection has been reset (only used by the receive callback) + const GT2Byte * message, // the message (should not be modified) + int len // the length of the message +); + +/******************* +** DUMP FUNCTIONS ** +*******************/ + +// sets a callback to be called whenever a UDP datagram is sent or received, and when a connection reset is received. +// pass in a callback of NULL to remove the callback. the dumps sit at a lower level than the filters, and allow an +// app to keep an eye on exactly what datagrams are being sent and received, allowing for close monitoring. however +// the dumps cannot be used to modify data, only monitor it. the dumps are useful for debugging purposes, and +// to keep track of data send and receive rates (e.g., the Quake 3 engine's netgraph). +// note that these are the actual UDP datagrams being sent and received - datagrams may be dropped, repeated, or +// out-of-order. control datagrams (those used internally by the protocol) will be passed to the dump callbacks, +// and certain application messages will have a header at the beginning. +void gt2SetSendDump(GT2Socket socket, gt2DumpCallback callback); +void gt2SetReceiveDump(GT2Socket socket, gt2DumpCallback callback); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Auth.c b/xrGameSpy/gamespy/gt2/gt2Auth.c new file mode 100644 index 00000000000..6594e042de1 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Auth.c @@ -0,0 +1,102 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Main.h" +#include "gt2Auth.h" +#include + +#define CALCULATEODDMODE(buffer, i, oddmode) ((buffer[i-1] & 1) ^ (i & 1) ^ oddmode ^ (buffer[0] & 1) ^ ((buffer[0] < 79) ? 1 : 0) ^ ((buffer[i-1] < buffer[0]) ? 1 : 0)); + +char GT2ChallengeKey[33] = "3b8dd8995f7c40a9a5c5b7dd5b481341"; + +static int gti2VerifyChallenge(const GT2Byte *buffer) +{ + int oddmode = 0; + int i; + for (i = 1; i < GTI2_CHALLENGE_LEN ; i++) + { + oddmode = CALCULATEODDMODE(buffer,i, oddmode); + if ((oddmode && (buffer[i] & 1) == 0) || (!oddmode && ((buffer[i] & 1) == 1))) + return 0; //failed!! + } + return 1; +} + +GT2Byte * gti2GetChallenge +( + GT2Byte * buffer +) +{ + int i; + int oddmode; + assert(buffer); + + srand((unsigned int)current_time()); + buffer[0] = (GT2Byte)(33 + rand() % 93); //use chars in the range 33 - 125 + oddmode = 0; + for (i = 1; i < GTI2_CHALLENGE_LEN ; i++) + { + oddmode = CALCULATEODDMODE(buffer,i, oddmode); + buffer[i] = (GT2Byte)(33 + rand() % 93); //use chars in the range 33 - 125 + //if oddmode make sure the char is odd, otherwise make sure it's even + if ((oddmode && (buffer[i] & 1) == 0) || (!oddmode && ((buffer[i] & 1) == 1))) + buffer[i]++; + + } + return buffer; +} + +GT2Byte * gti2GetResponse +( + GT2Byte * buffer, + const GT2Byte * challenge +) +{ + int i; + int valid; + char cchar; + int keylen = (int)strlen(GT2ChallengeKey); + int chalrand; + valid = gti2VerifyChallenge(challenge); //it's an invalid challenge, give them a bogus response + //assert(GTI2_RESPONSE_LEN <= GTI2_CHALLENGE_LEN); + for (i = 0 ; i < GTI2_RESPONSE_LEN ; i++) + { + //use random vals for spots 0 and 13 + if (!valid || i == 0 || i == 13) + buffer[i] = (GT2Byte)(33 + rand() % 93); //use chars in the range 33 - 125 + else + { //set the character to look back at, never use the random ones! + if (i == 1 || i == 14) + cchar = (char)challenge[i]; + else + cchar = (char)challenge[i-1]; + chalrand = abs((challenge[((i * challenge[i]) + GT2ChallengeKey[(i + challenge[i]) % keylen]) % GTI2_CHALLENGE_LEN] ^ GT2ChallengeKey[(i * 17991 * cchar) % keylen])); + buffer[i] = (GT2Byte)(33 + chalrand % 93); + } + } + return buffer; +} + + +GT2Bool gti2CheckResponse +( + const GT2Byte * response1, + const GT2Byte * response2 +) +{ + int i; //when comparing ignore the ones that are random + for (i = 0 ; i < GTI2_RESPONSE_LEN ; i++) + { + if (i != 0 && i != 13 && response1[i] != response2[i]) + return GT2False; + } + return GT2True; +} + diff --git a/xrGameSpy/gamespy/gt2/gt2Auth.h b/xrGameSpy/gamespy/gt2/gt2Auth.h new file mode 100644 index 00000000000..8d3134d6427 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Auth.h @@ -0,0 +1,42 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_AUTH_H_ +#define _GT2_AUTH_H_ + +#define GTI2_CHALLENGE_LEN 32 +#define GTI2_RESPONSE_LEN 32 + +#ifdef __cplusplus +extern "C" { +#endif + +GT2Byte * gti2GetChallenge +( + GT2Byte * buffer +); + +GT2Byte * gti2GetResponse +( + GT2Byte * buffer, + const GT2Byte * challenge +); + +GT2Bool gti2CheckResponse +( + const GT2Byte * response1, + const GT2Byte * response2 +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Buffer.c b/xrGameSpy/gamespy/gt2/gt2Buffer.c new file mode 100644 index 00000000000..43821a41042 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Buffer.c @@ -0,0 +1,80 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Buffer.h" +#include + +GT2Bool gti2AllocateBuffer(GTI2Buffer * buffer, int size) +{ + buffer->buffer = (GT2Byte *)gsimalloc((unsigned int)size); + if(!buffer->buffer) + return GT2False; + buffer->size = size; + + return GT2True; +} + +int gti2GetBufferFreeSpace(const GTI2Buffer * buffer) +{ + return (buffer->size - buffer->len); +} + +void gti2BufferWriteByte(GTI2Buffer * buffer, GT2Byte b) +{ + assert(buffer->len < buffer->size); +#if 0 + if(buffer->len >= buffer->size) + return; +#endif + + buffer->buffer[buffer->len++] = b; +} + +void gti2BufferWriteUShort(GTI2Buffer * buffer, unsigned short s) +{ + assert((buffer->len + 2) <= buffer->size); +#if 0 + if((buffer->len + 2) > buffer->size) + return; +#endif + + buffer->buffer[buffer->len++] = (GT2Byte)((s >> 8) & 0xFF); + buffer->buffer[buffer->len++] = (GT2Byte)(s & 0xFF); +} + +void gti2BufferWriteData(GTI2Buffer * buffer, const GT2Byte * data, int len) +{ + if(!data || !len) + return; + + if(len == -1) + len = (int)strlen((const char *)data); + + assert((buffer->len + len) <= buffer->size); +#if 0 + if(buffer->len >= buffer->size) + return; +#endif + + memcpy(buffer->buffer + buffer->len, data, (unsigned int)len); + buffer->len += len; +} + +void gti2BufferShorten(GTI2Buffer * buffer, int start, int shortenBy) +{ + if(start == -1) + start = (buffer->len - shortenBy); + + assert(start <= buffer->len); + assert(shortenBy <= (buffer->len - start)); + + memmove(buffer->buffer + start, buffer->buffer + start + shortenBy, (unsigned int)(buffer->len - start - shortenBy)); + buffer->len -= shortenBy; +} diff --git a/xrGameSpy/gamespy/gt2/gt2Buffer.h b/xrGameSpy/gamespy/gt2/gt2Buffer.h new file mode 100644 index 00000000000..d93f39270f1 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Buffer.h @@ -0,0 +1,27 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_BUFFER_H_ +#define _GT2_BUFFER_H_ + +#include "gt2Main.h" + +GT2Bool gti2AllocateBuffer(GTI2Buffer * buffer, int size); + +int gti2GetBufferFreeSpace(const GTI2Buffer * buffer); + +void gti2BufferWriteByte(GTI2Buffer * buffer, GT2Byte b); +void gti2BufferWriteUShort(GTI2Buffer * buffer, unsigned short s); +void gti2BufferWriteData(GTI2Buffer * buffer, const GT2Byte * data, int len); + +// shortens the buffer by "shortenBy" (length, not size) +void gti2BufferShorten(GTI2Buffer * buffer, int start, int shortenBy); + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Callback.c b/xrGameSpy/gamespy/gt2/gt2Callback.c new file mode 100644 index 00000000000..b42e03651ff --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Callback.c @@ -0,0 +1,431 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Callback.h" +#include "gt2Socket.h" + +/********************* +** SOCKET CALLBACKS ** +*********************/ + +GT2Bool gti2SocketErrorCallback +( + GT2Socket socket +) +{ + assert(socket); + if(!socket) + return GT2True; + + if(!socket->socketErrorCallback) + return GT2True; + + socket->callbackLevel++; + + socket->socketErrorCallback(socket); + + socket->callbackLevel--; + + // check if the socket should be closed + if(socket->close && !socket->callbackLevel) + { + gti2CloseSocket(socket); + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2ConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + assert(socket && connection); + if(!socket || !connection) + return GT2True; + + if(!socket->connectAttemptCallback) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + socket->callbackLevel++; + connection->callbackLevel++; + + socket->connectAttemptCallback(socket, connection, ip, port, latency, message, len); + + socket->callbackLevel--; + connection->callbackLevel--; + + // check if the socket should be closed + if(socket->close && !socket->callbackLevel) + { + gti2CloseSocket(socket); + return GT2False; + } + + return GT2True; +} + +/************************* +** CONNECTION CALLBACKS ** +*************************/ + +GT2Bool gti2ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + assert(connection); + if(!connection) + return GT2True; + + // store the result + connection->connectionResult = result; + + if(!connection->callbacks.connected) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + connection->callbackLevel++; + connection->socket->callbackLevel++; + + connection->callbacks.connected(connection, result, message, len); + + connection->callbackLevel--; + connection->socket->callbackLevel--; + + // check if the socket should be closed + if(connection->socket->close && !connection->socket->callbackLevel) + { + gti2CloseSocket(connection->socket); + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + assert(connection); + if(!connection) + return GT2True; + + if(!connection->callbacks.received) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + connection->callbackLevel++; + connection->socket->callbackLevel++; + + connection->callbacks.received(connection, message, len, reliable); + + connection->callbackLevel--; + connection->socket->callbackLevel--; + + // check if the socket should be closed + if(connection->socket->close && !connection->socket->callbackLevel) + { + gti2CloseSocket(connection->socket); + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + assert(connection); + if(!connection) + return GT2True; + + if(!connection->callbacks.closed) + return GT2True; + + connection->callbackLevel++; + connection->socket->callbackLevel++; + + connection->callbacks.closed(connection, reason); + + connection->callbackLevel--; + connection->socket->callbackLevel--; + + // check if the socket should be closed + if(connection->socket->close && !connection->socket->callbackLevel) + { + gti2CloseSocket(connection->socket); + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2PingCallback +( + GT2Connection connection, + int latency +) +{ + assert(connection); + if(!connection) + return GT2True; + + if(!connection->callbacks.ping) + return GT2True; + + connection->callbackLevel++; + connection->socket->callbackLevel++; + + connection->callbacks.ping(connection, latency); + + connection->callbackLevel--; + connection->socket->callbackLevel--; + + // check if the socket should be closed + if(connection->socket->close && !connection->socket->callbackLevel) + { + gti2CloseSocket(connection->socket); + return GT2False; + } + + return GT2True; +} + +/********************* +** FILTER CALLBACKS ** +*********************/ + +GT2Bool gti2SendFilterCallback +( + GT2Connection connection, + int filterID, + const GT2Byte * message, + int len, + GT2Bool reliable +) +{ + gt2SendFilterCallback * callback; + + assert(connection); + if(!connection) + return GT2True; + + callback = (gt2SendFilterCallback *)ArrayNth(connection->sendFilters, filterID); + if(!callback) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + connection->callbackLevel++; + connection->socket->callbackLevel++; + + (*callback)(connection, filterID, message, len, reliable); + + connection->callbackLevel--; + connection->socket->callbackLevel--; + + // check if the socket should be closed + if(connection->socket->close && !connection->socket->callbackLevel) + { + gti2CloseSocket(connection->socket); + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2ReceiveFilterCallback +( + GT2Connection connection, + int filterID, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + gt2ReceiveFilterCallback * callback; + + assert(connection); + if(!connection) + return GT2True; + + callback = (gt2ReceiveFilterCallback *)ArrayNth(connection->receiveFilters, filterID); + if(!callback) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + connection->callbackLevel++; + connection->socket->callbackLevel++; + + (*callback)(connection, filterID, message, len, reliable); + + connection->callbackLevel--; + connection->socket->callbackLevel--; + + // check if the socket should be closed + if(connection->socket->close && !connection->socket->callbackLevel) + { + gti2CloseSocket(connection->socket); + return GT2False; + } + + return GT2True; +} + +/******************* +** DUMP CALLBACKS ** +*******************/ + +GT2Bool gti2DumpCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + GT2Bool reset, + const GT2Byte * message, + int len, + GT2Bool send +) +{ + gt2DumpCallback callback; + + assert(socket); + if(!socket) + return GT2True; + + if(send) + callback = socket->sendDumpCallback; + else + callback = socket->receiveDumpCallback; + + if(!callback) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + socket->callbackLevel++; + if(connection) + connection->callbackLevel++; + + callback(socket, connection, ip, port, reset, message, len); + + socket->callbackLevel--; + if(connection) + connection->callbackLevel--; + + // check if the socket should be closed + if(socket->close && !socket->callbackLevel) + { + gti2CloseSocket(socket); + return GT2False; + } + + return GT2True; +} + +/***************************** +** SOCKET SHARING CALLBACKS ** +*****************************/ + +GT2Bool gti2UnrecognizedMessageCallback +( + GT2Socket socket, + unsigned int ip, + unsigned short port, + GT2Byte * message, + int len, + GT2Bool * handled +) +{ + *handled = GT2False; + + assert(socket); + if(!socket) + return GT2True; + + if(!socket->unrecognizedMessageCallback) + return GT2True; + + // check for an empty message + if(!len || !message) + { + message = NULL; + len = 0; + } + + socket->callbackLevel++; + + *handled = socket->unrecognizedMessageCallback(socket, ip, port, message, len); + + socket->callbackLevel--; + + // check if the socket should be closed + if(socket->close && !socket->callbackLevel) + { + gti2CloseSocket(socket); + return GT2False; + } + + return GT2True; +} diff --git a/xrGameSpy/gamespy/gt2/gt2Callback.h b/xrGameSpy/gamespy/gt2/gt2Callback.h new file mode 100644 index 00000000000..f1a74cc5b95 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Callback.h @@ -0,0 +1,120 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_CALLBACK_H_ +#define _GT2_CALLBACK_H_ + +#include "gt2Main.h" + +/********************* +** SOCKET CALLBACKS ** +*********************/ + +GT2Bool gti2SocketErrorCallback +( + GT2Socket socket +); + +GT2Bool gti2ConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +); + +/************************* +** CONNECTION CALLBACKS ** +*************************/ + +GT2Bool gti2ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +); + +GT2Bool gti2ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +); + +GT2Bool gti2ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +); + +GT2Bool gti2PingCallback +( + GT2Connection connection, + int latency +); + +/********************* +** FILTER CALLBACKS ** +*********************/ + +GT2Bool gti2SendFilterCallback +( + GT2Connection connection, + int filterID, + const GT2Byte * message, + int len, + GT2Bool reliable +); + +GT2Bool gti2ReceiveFilterCallback +( + GT2Connection connection, + int filterID, + GT2Byte * message, + int len, + GT2Bool reliable +); + +/******************* +** DUMP CALLBACKS ** +*******************/ + +GT2Bool gti2DumpCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + GT2Bool reset, + const GT2Byte * message, + int len, + GT2Bool send +); + +/***************************** +** SOCKET SHARING CALLBACKS ** +*****************************/ + +GT2Bool gti2UnrecognizedMessageCallback +( + GT2Socket socket, + unsigned int ip, + unsigned short port, + GT2Byte * message, + int len, + GT2Bool * handled +); + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Connection.c b/xrGameSpy/gamespy/gt2/gt2Connection.c new file mode 100644 index 00000000000..a17d54bb193 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Connection.c @@ -0,0 +1,343 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Connection.h" +#include "gt2Socket.h" +#include "gt2Message.h" +#include "gt2Callback.h" +#include "gt2Utility.h" +#include + +GT2Result gti2NewOutgoingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port) +{ + GT2Result result; + + // create the object + result = gti2NewSocketConnection(socket, connection, ip, port); + if(result != GT2Success) + return result; + + // set initial states + (*connection)->state = GTI2AwaitingServerChallenge; + (*connection)->initiated = GT2True; + + return GT2Success; +} + +GT2Result gti2NewIncomingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port) +{ + GT2Result result; + + // create the object + result = gti2NewSocketConnection(socket, connection, ip, port); + if(result != GT2Success) + return result; + + // set initial states + (*connection)->state = GTI2AwaitingClientChallenge; + (*connection)->initiated = GT2False; + + return GT2Success; +} + +GT2Result gti2StartConnectionAttempt +( + GT2Connection connection, + const GT2Byte * message, + int len, + GT2ConnectionCallbacks * callbacks +) +{ + char challenge[GTI2_CHALLENGE_LEN]; + + // check the message and len + gti2MessageCheck(&message, &len); + + // copy off the message + if(len > 0) + { + connection->initialMessage = (char *)gsimalloc((unsigned int)len); + if(!connection->initialMessage) + return GT2OutOfMemory; + + memcpy(connection->initialMessage, message, (unsigned int)len); + connection->initialMessageLen = len; + } + + // copy the callbacks + if(callbacks) + connection->callbacks = *callbacks; + + // generate a challenge + gti2GetChallenge((GT2Byte *)challenge); + + // generate and store the expected response + gti2GetResponse((GT2Byte *)connection->response, (GT2Byte *)challenge); + + // send the client challenge + gti2SendClientChallenge(connection, challenge); + + // update our state + connection->state = GTI2AwaitingServerChallenge; + + return GT2Success; +} + +GT2Bool gti2AcceptConnection(GT2Connection connection, GT2ConnectionCallbacks * callbacks) +{ + // was the connection already closed? + if(connection->freeAtAcceptReject) + { + // clear the flag + connection->freeAtAcceptReject = GT2False; + + // let the app know if was already closed + return GT2False; + } + + // make sure this flag gets cleared + connection->freeAtAcceptReject = GT2False; + + // check that we're still awaiting this + if(connection->state != GTI2AwaitingAcceptReject) + return GT2False; + + // let the other side know + gti2SendAccept(connection); + + // update our state + connection->state = GTI2Connected; + + // store the callbacks + if(callbacks) + connection->callbacks = *callbacks; + + return GT2True; +} + +void gti2RejectConnection(GT2Connection connection, const GT2Byte * message, int len) +{ + // make sure this flag gets cleared + connection->freeAtAcceptReject = GT2False; + + // check that we're still awaiting this + if(connection->state != GTI2AwaitingAcceptReject) + return; + + // check the message and len + gti2MessageCheck(&message, &len); + + // let the other side know + gti2SendReject(connection, message, len); + + // update our state + connection->state = GTI2Closing; +} + +GT2Bool gti2ConnectionSendData(GT2Connection connection, const GT2Byte * message, int len) +{ + // send the data on the socket + if(!gti2SocketSend(connection->socket, connection->ip, connection->port, message, len)) + return GT2False; + + // mark the time (used for keep-alives) + connection->lastSend = current_time(); + + return GT2True; +} + +static GT2Bool gti2CheckTimeout(GT2Connection connection, gsi_time now) +{ + // are we still trying to connect? + if(connection->state < GTI2Connected) + { + GT2Bool timedOut = GT2False; + + // is this the initiator + if(connection->initiated) + { + // do we have a timeout? + if(connection->timeout) + { + // check the time taken against the timeout + if((now - connection->startTime) > connection->timeout) + timedOut = GT2True; + } + } + else + { + // don't time them out if they're waiting for us + if(connection->state < GTI2AwaitingAcceptReject) + { + // check the time taken against the timeout + if((now - connection->startTime) > GTI2_SERVER_TIMEOUT) + timedOut = GT2True; + } + } + + // check if we timed out + if(timedOut) + { + // let them know + gti2SendClosed(connection); + + // mark it as closed + gti2ConnectionClosed(connection); + + // call the callback + if(!gti2ConnectedCallback(connection, GT2TimedOut, NULL, 0)) + return GT2False; + } + } + + return GT2True; +} + +static GT2Bool gti2SendRetries(GT2Connection connection, gsi_time now) +{ + int i; + int len; + GTI2OutgoingBufferMessage * message; + + // go through the list of outgoing messages awaiting confirmation + len = ArrayLength(connection->outgoingBufferMessages); + for(i = 0 ; i < len ; i++) + { + // get the message + message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i); + + // check if it's time to resend it + if((now - message->lastSend) > GTI2_RESEND_TIME) + { + if(!gti2ResendMessage(connection, message)) + return GT2False; + } + } + + return GT2True; +} + +static GT2Bool gti2CheckPendingAck(GT2Connection connection, gsi_time now) +{ + // check for nothing pending + if(!connection->pendingAck) + return GT2True; + + // check how long it has been pending + if((now - connection->pendingAckTime) > GTI2_PENDING_ACK_TIME) + { + if(!gti2SendAck(connection)) + return GT2False; + } + + return GT2True; +} + +static GT2Bool gti2CheckKeepAlive(GT2Connection connection, gsi_time now) +{ + if((now - connection->lastSend) > GTI2_KEEP_ALIVE_TIME) + { + if(!gti2SendKeepAlive(connection)) + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2ConnectionThink(GT2Connection connection, gsi_time now) +{ + // check timeout + if(!gti2CheckTimeout(connection, now)) + return GT2False; + + // check keep alives + if(!gti2CheckKeepAlive(connection, now)) + return GT2False; + + // send retries + if(!gti2SendRetries(connection, now)) + return GT2False; + + // check the pending ack + if(!gti2CheckPendingAck(connection, now)) + return GT2False; + + return GT2True; +} + +void gti2CloseConnection(GT2Connection connection, GT2Bool hard) +{ + // check if it should be hard or soft closed + if(hard) + { + // check if it's already closed + if(connection->state >= GTI2Closed) + return; + + // mark it as closed + gti2ConnectionClosed(connection); + + // send a closed message + gti2SendClosed(connection); + + // call the callback + gti2ClosedCallback(connection, GT2LocalClose); + + // try and free it + gti2FreeSocketConnection(connection); + } + else + { + // mark it as closing + connection->state = GTI2Closing; + + // send the close + gti2SendClose(connection); + } +} + +void gti2ConnectionClosed(GT2Connection connection) +{ + // check for already closed + if(connection->state == GTI2Closed) + return; + + // mark the connection as closed + connection->state = GTI2Closed; + + // remove it from the connected list + TableRemove(connection->socket->connections, &connection); + + // add it to the closed list + ArrayAppend(connection->socket->closedConnections, &connection); +} + +void gti2ConnectionCleanup(GT2Connection connection) +{ + if(connection->initialMessage) + gsifree(connection->initialMessage); + + if(connection->incomingBuffer.buffer) + gsifree(connection->incomingBuffer.buffer); + if(connection->outgoingBuffer.buffer) + gsifree(connection->outgoingBuffer.buffer); + + if(connection->incomingBufferMessages) + ArrayFree(connection->incomingBufferMessages); + if(connection->outgoingBufferMessages) + ArrayFree(connection->outgoingBufferMessages); + + if(connection->sendFilters) + ArrayFree(connection->sendFilters); + if(connection->receiveFilters) + ArrayFree(connection->receiveFilters); + + gsifree(connection); +} diff --git a/xrGameSpy/gamespy/gt2/gt2Connection.h b/xrGameSpy/gamespy/gt2/gt2Connection.h new file mode 100644 index 00000000000..43423f348e5 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Connection.h @@ -0,0 +1,41 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_CONNECTION_H_ +#define _GT2_CONNECTION_H_ + +#include "gt2Main.h" + +GT2Result gti2NewOutgoingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port); +GT2Result gti2NewIncomingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port); + +GT2Result gti2StartConnectionAttempt +( + GT2Connection connection, + const GT2Byte * message, + int len, + GT2ConnectionCallbacks * callbacks +); + +GT2Bool gti2AcceptConnection(GT2Connection connection, GT2ConnectionCallbacks * callbacks); + +void gti2RejectConnection(GT2Connection connection, const GT2Byte * message, int len); + +GT2Bool gti2ConnectionSendData(GT2Connection connection, const GT2Byte * message, int len); + +GT2Bool gti2ConnectionThink(GT2Connection connection, gsi_time now); + +void gti2CloseConnection(GT2Connection connection, GT2Bool hard); + +void gti2ConnectionClosed(GT2Connection connection); + +void gti2ConnectionCleanup(GT2Connection connection); + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Encode.c b/xrGameSpy/gamespy/gt2/gt2Encode.c new file mode 100644 index 00000000000..aa2f2cea47b --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Encode.c @@ -0,0 +1,648 @@ +#include +#include +#include "gt2Encode.h" +#include "gt2Main.h" + + + +// This handles alignment issues and endianess +void gt2MemCopy16(char *out, char const *in) +{ + #ifdef _GT2_ENDIAN_CONVERT + *out = in[1]; + out[1] = *in; + #else + // straight copy + *out = *in; + out[1] = in[1]; + #endif +} + +// This handles alignment issues and endianess +void gt2MemCopy32(char *out, char const *in) +{ + #ifdef _GT2_ENDIAN_CONVERT + out[0] = in[3]; + out[1] = in[2]; + out[2] = in[1]; + out[3] = in[0]; + #else + // straight copy + *out = *in; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + #endif +} + +// This handles alignment issues and endianess +void gt2MemCopy64(char *out, char const *in) +{ + #ifdef _GT2_ENDIAN_CONVERT + out[0] = in[7]; + out[1] = in[6]; + out[2] = in[5]; + out[3] = in[4]; + out[4] = in[3]; + out[5] = in[2]; + out[6] = in[1]; + out[7] = in[0]; + #else + // straight copy + memcpy(out, in, 8); + #endif + +} +void gt2MemCopy(char *out, char const *in, int size) +{ + if (size == 2) + { + gt2MemCopy16(out, in); + } + else + if (size == 4) + { + gt2MemCopy32(out, in); + } + else + if (size == 8) + { + gt2MemCopy64(out, in); + } + else + { + // warning... no endianess decode. + memcpy(out,in,(size_t)size); + } +} +#if defined(_PS2) || defined(_UNIX) || defined(_PS3) || defined(_WIN64) || defined(_X360) + +#define GT_ENCODE_ELEM(TYPE,b,l,args) \ +{ \ + TYPE v; \ + if (l < sizeof(TYPE)) \ + return -1; \ + v = (TYPE)va_arg(*args, int); \ + gt2MemCopy(b, (const char *)&v, sizeof(TYPE)); \ + return (int)sizeof(TYPE); \ +} + +#define GT_DECODE_ELEM(TYPE,b,l,args) \ +{ \ + TYPE* v; \ + if (l < sizeof(TYPE)) \ + return -1; \ + v = va_arg(*args, TYPE*); \ + gt2MemCopy((char *)v, b, sizeof(TYPE)); \ + return (int)sizeof(TYPE); \ +} + +#define GT_ENCODE_ELEM_NC(TYPE,b,l,args) \ +{ \ + TYPE v; \ + if (l < sizeof(TYPE)) \ + return -1; \ + v = (TYPE)va_arg(*args, int); \ + memcpy(b, &v, sizeof(TYPE)); \ + return (int)sizeof(TYPE); \ +} + +#define GT_DECODE_ELEM_NC(TYPE,b,l,args) \ +{ \ + TYPE* v; \ + if (l < sizeof(TYPE)) \ + return -1; \ + v = va_arg(*args, TYPE*); \ + memcpy(v, b, sizeof(TYPE)); \ + return (int)sizeof(TYPE); \ +} + +#else + +#define GT_ENCODE_ELEM(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; gt2MemCopy(b,(const char *)&va_arg(*args,TYPE),sizeof(TYPE)); return sizeof(TYPE);} +#define GT_DECODE_ELEM(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; gt2MemCopy((char *)va_arg(*args,TYPE*),b,sizeof(TYPE)); return sizeof(TYPE);} +// nc = no endian convert +#define GT_ENCODE_ELEM_NC(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; memcpy(b,&va_arg(*args,TYPE),sizeof(TYPE)); return sizeof(TYPE);} +#define GT_DECODE_ELEM_NC(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; memcpy(va_arg(*args,TYPE*),b,sizeof(TYPE)); return sizeof(TYPE);} + +#endif /* _PS || _UNIX */ + +static int dbstrlen(GT_DBSTR_TYPE dbstr) +{ + int len = 0; +#ifdef ALIGNED_COPY + short achar; + do + { + memcpy(&achar, dbstr, sizeof(achar)); + dbstr++; + len++; + } while (achar != 0); + len--; +#else + while (*dbstr++) + len++; +#endif + return len; +} + +static short *dbstrcpy(GT_DBSTR_TYPE dest, GT_DBSTR_TYPE src) +{ + GT_DBSTR_TYPE hold = dest; + #ifdef ALIGNED_COPY + int len = dbstrlen(src); + memcpy(dest, src, (unsigned int)(len + 1) * 2); + #else + while ((*dest++ = *src++) != 0) ; + #endif + return hold; +} + +static int gtiDecodeBits(int bitcount, char *inBuffer, int inLength, va_list *args) +{ + char bucket; + int i; + + if (inLength < 1) + return -1; + bucket = *inBuffer; + for (i = 0 ; i < bitcount ; i++) + { + *va_arg(*args,char*) = (char)((bucket & (1 << i)) ? 1 : 0); + } + + return 1; +} + +static int gtiEncodeBits(int bitcount, char *outBuffer, int outLength, va_list *args) +{ + char bucket = 0; + int i; + + if (outLength < 1) + return -1; + for (i = 0 ; i < bitcount ; i++) + { + bucket |= (char)((va_arg(*args,int) ? 1 : 0) << i); + //bucket |= ((va_arg(*args,char) ? 1 : 0) << i); + } + *outBuffer = bucket; + return 1; +} + +// length in bytes including NUL, or -1 if error +static int gtiCheckStringLen(char *inBuffer, int inLength) +{ + int len = 0; + do + { + len++; + if(len > inLength) + return -1; + } + while(inBuffer[len - 1] != '\0'); + return len; +} + +// length in bytes (not chars) including NUL, or -1 if error +static int gtiCheckDoubleStringLen(char *inBuffer, int inLength) +{ + int len = 0; + do + { + len += 2; + if(len > inLength) + return -1; + } + while((inBuffer[len - 2] != '\0') || (inBuffer[len - 1] != '\0')); + return len; +} + +// length in bytes including NULs, or -1 if error +static int gtiCheckStringArrayLen(char *inBuffer, int inLength) +{ + int len = 0; + int strLen; + do + { + strLen = gtiCheckStringLen(inBuffer + len, inLength - len); + if(strLen == -1) + return -1; + len += strLen; + } + while(strLen > 1); + return len; +} + +static int gtiDecodeSingle(char elemType, char *inBuffer, int inLength, va_list *args) +{ + switch (elemType) + { + case GT_INT: + GT_DECODE_ELEM(GT_INT_TYPE,inBuffer, inLength, args); + //break; + case GT_UINT: + GT_DECODE_ELEM(GT_UINT_TYPE,inBuffer, inLength, args); + //break; + case GT_SHORT: + GT_DECODE_ELEM(GT_SHORT_TYPE,inBuffer, inLength, args); + //break; + case GT_USHORT: + GT_DECODE_ELEM(GT_USHORT_TYPE,inBuffer, inLength, args); + //break; + case GT_CHAR: + GT_DECODE_ELEM(GT_CHAR_TYPE,inBuffer, inLength, args); + //break; + case GT_UCHAR: + GT_DECODE_ELEM(GT_UCHAR_TYPE,inBuffer, inLength, args); + //break; + case GT_FLOAT: + { + #if(0) + // no endian convert + GT_FLOAT_TYPE* v; + if (inLength < sizeof(GT_FLOAT_TYPE)) + return -1; + v = va_arg(*args, GT_FLOAT_TYPE*); + v[0] = inBuffer[0]; + v[1] = inBuffer[1]; + v[2] = inBuffer[2]; + v[3] = inBuffer[3]; + return (int)sizeof(GT_FLOAT_TYPE); + #else + GT_DECODE_ELEM_NC(GT_FLOAT_TYPE,inBuffer, inLength, args); + #endif + } + case GT_DOUBLE: + #if(0) + // no endian convert + { GT_DOUBLE_TYPE* v; + if (inLength < sizeof(GT_DOUBLE_TYPE)) + return -1; + v = va_arg(*args, GT_DOUBLE_TYPE*); + v[0] = inBuffer[0]; + v[1] = inBuffer[1]; + v[2] = inBuffer[2]; + v[3] = inBuffer[3]; + v[4] = inBuffer[4]; + v[5] = inBuffer[5]; + v[6] = inBuffer[6]; + v[7] = inBuffer[7]; + return (int)sizeof(GT_DOUBLE_TYPE); + } + #else + GT_DECODE_ELEM_NC(GT_DOUBLE_TYPE,inBuffer, inLength, args); + #endif + //break; + case GT_BIT: + GT_DECODE_ELEM(GT_BIT_TYPE,inBuffer, inLength, args); + //break; + case GT_CSTR: + { + int len; + GT_CSTR_TYPE s = va_arg(*args, GT_CSTR_TYPE); + assert(s != NULL); + len = gtiCheckStringLen(inBuffer, inLength); + if(len == -1) + return -1; + memcpy(s, inBuffer, (size_t)len); + return len; + } + //break; + case GT_CSTR_PTR: + *va_arg(*args, GT_CSTR_PTR_TYPE) = (GT_CSTR_TYPE)inBuffer; + return gtiCheckStringLen(inBuffer, inLength); + //break; + case GT_DBSTR: + { + int len; + GT_DBSTR_TYPE s = va_arg(*args, GT_DBSTR_TYPE); + assert(s != NULL); + len = gtiCheckDoubleStringLen(inBuffer, inLength); + if (len == -1) + return -1; + memcpy(s, inBuffer, (size_t)len); + return len; + } + //break; + case GT_DBSTR_PTR: + *va_arg(*args, GT_DBSTR_PTR_TYPE) = (GT_DBSTR_TYPE)inBuffer; + return gtiCheckDoubleStringLen(inBuffer, inLength); + //break; + case GT_CSTR_ARRAY: + { + int len; + GT_CSTR_ARRAY_TYPE s = va_arg(*args, GT_CSTR_ARRAY_TYPE); + assert(s != NULL); + len = gtiCheckStringArrayLen(inBuffer, inLength); + if(len == -1) + return -1; + memcpy(s, inBuffer, (size_t)len); + return len; + } + //break; + case GT_CSTR_ARRAY_PTR: + *va_arg(*args, GT_CSTR_ARRAY_PTR_TYPE) = (GT_CSTR_ARRAY_TYPE)inBuffer; + return gtiCheckStringArrayLen(inBuffer, inLength); + //break; + case GT_RAW: + { + int *len, holdlen; + GT_RAW_TYPE data = va_arg(*args, GT_RAW_TYPE); + len = va_arg(*args, int *); + if (inLength < sizeof(*len)) + return -1; + holdlen = *len; + memcpy(len, inBuffer, sizeof(*len)); + if (*len > holdlen) //there isn't enough room in their dest! + return -1; + if (inLength < (int)sizeof(*len) + *len) + return -1; + memcpy(data, inBuffer + sizeof(*len), (unsigned int)*len); + return *len + (int)sizeof(*len); + } + case GT_RAW_PTR: + { + int *len; + *va_arg(*args, GT_RAW_PTR_TYPE) = (GT_RAW_TYPE)(inBuffer + sizeof(*len)); + len = va_arg(*args, int *); + if (inLength < sizeof(*len)) + return -1; + memcpy(len, inBuffer, sizeof(*len)); + return *len + (int)sizeof(*len); + } + //break; + + } + return -1; //bad type! +} + +static int gtiEncodeSingle(char elemType, char *outBuffer, int outLength, va_list *args) +{ + switch (elemType) + { + case GT_INT: + GT_ENCODE_ELEM(GT_INT_TYPE,outBuffer, outLength, args); + //break; + case GT_UINT: + GT_ENCODE_ELEM(GT_UINT_TYPE,outBuffer, outLength, args); + //break; + case GT_SHORT: + GT_ENCODE_ELEM(GT_SHORT_TYPE,outBuffer, outLength, args); + //break; + case GT_USHORT: + GT_ENCODE_ELEM(GT_USHORT_TYPE,outBuffer, outLength, args); + //break; + case GT_CHAR: + GT_ENCODE_ELEM(GT_CHAR_TYPE,outBuffer, outLength, args); + //break; + case GT_UCHAR: + GT_ENCODE_ELEM(GT_UCHAR_TYPE,outBuffer, outLength, args); + //break; + case GT_FLOAT: //floats are promoted to double in varargs, need to demote + { + double temp; + float f; + double v = va_arg(*args,double); + memcpy(&temp,&v,sizeof(double)); + f = (float)temp; + if (outLength < sizeof(float)) + return -1; + memcpy(outBuffer, &f, sizeof(float)); + return sizeof(float); + } + //break; + case GT_DOUBLE: + { + double v; + if(outLength < sizeof(double)) + return -1; + v = va_arg(*args, double); + memcpy(outBuffer, &v, sizeof(double)); + return sizeof(double); + } + //break; + case GT_BIT: + GT_ENCODE_ELEM(GT_BIT_TYPE,outBuffer, outLength, args); + //break; + case GT_CSTR: + case GT_CSTR_PTR: + { + int len; + GT_CSTR_TYPE s = va_arg(*args, GT_CSTR_TYPE); + assert(s != NULL); + len = (int)strlen(s) + 1; + if (outLength < len ) + return -1; + strcpy(outBuffer, s); + return len; + } + //break; + case GT_DBSTR: + case GT_DBSTR_PTR: + { + int len; + GT_DBSTR_TYPE s = va_arg(*args, GT_DBSTR_TYPE); + assert(s != NULL); + len = dbstrlen(s) + 1; + if (outLength < len * 2) + return -1; + dbstrcpy((short *)outBuffer, s); + return len * 2; + } + //break; + case GT_CSTR_ARRAY: + case GT_CSTR_ARRAY_PTR: + { + int len = 0; + int strLen; + GT_CSTR_ARRAY_TYPE s = va_arg(*args, GT_CSTR_ARRAY_TYPE); + assert(s != NULL); + do + { + strLen = (int)strlen(s + len) + 1; + len += strLen; + if(outLength < len) + return -1; + } + while(strLen != 1); + memcpy(outBuffer, s, (size_t)len); + return len; + } + //break; + case GT_RAW: + case GT_RAW_PTR: + { + int len; + GT_RAW_TYPE data = va_arg(*args, GT_RAW_TYPE); + len = va_arg(*args, int); + if (outLength < len + (int)sizeof(len)) + return -1; + memcpy(outBuffer, &len, sizeof(len)); + memcpy(outBuffer + sizeof(len), data, (unsigned int)len); + return len + (int)sizeof(len); + } + + } + return -1; //bad type! +} + +static int gtInternalEncodeV(int usetype, GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, va_list *args) +{ + int elemSize; + int totSize = outLength; + const char *bitCounter; + + //set the message type + if (usetype) + { + elemSize = sizeof(msgType); + if (outLength < elemSize) + return -1; + + gt2MemCopy(outBuffer, (const char *)&msgType, elemSize); + outBuffer += elemSize; + outLength -= elemSize; + } + while (*fmtString) + { + if (*fmtString == GT_BIT) //see how many + { + for (bitCounter = fmtString; *bitCounter == GT_BIT && bitCounter - fmtString <= 8; bitCounter++) + {}; + elemSize = gtiEncodeBits((int)(bitCounter - fmtString), outBuffer, outLength, args); + fmtString = bitCounter - 1; + } else + elemSize = gtiEncodeSingle(*fmtString, outBuffer, outLength, args); + if (elemSize < 0) + return -1; //out of space + outBuffer += elemSize; + outLength -= elemSize; + fmtString++; + } + return totSize - outLength; +} + +int gtEncodeNoTypeV(const char *fmtString, char *outBuffer, int outLength, va_list *args) +{ + return gtInternalEncodeV(0,0,fmtString, outBuffer, outLength, args); +} + +int gtEncodeV(GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, va_list *args) +{ + return gtInternalEncodeV(1,msgType,fmtString, outBuffer, outLength, args); +} + +int gtEncode(GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, ...) +{ + int rcode; + va_list args; + + //set the values + va_start(args, outLength); + rcode = gtEncodeV(msgType, fmtString, outBuffer, outLength, &args); + va_end(args); + + return rcode; +} + +int gtEncodeNoType(const char *fmtString, char *outBuffer, int outLength, ...) +{ + int rcode; + va_list args; + + //set the values + va_start(args, outLength); + rcode = gtEncodeNoTypeV(fmtString, outBuffer, outLength, &args); + va_end(args); + + return rcode; +} + +static int gtDecodeInternalV(int usetype, const char *fmtString, char *inBuffer, int inLength, va_list *args) +{ + int elemSize; + int totSize = inLength; + const char *bitCounter; + + //skip the message type + if (usetype) + { + inBuffer += sizeof(GTMessageType); + inLength -= sizeof(GTMessageType); + } + + while (*fmtString) + { + if (*fmtString == GT_BIT) //see how many + { + for (bitCounter = fmtString; *bitCounter == GT_BIT && bitCounter - fmtString <= 8; bitCounter++) + {}; + elemSize = gtiDecodeBits((int)(bitCounter - fmtString), inBuffer, inLength, args); + fmtString = bitCounter - 1; + } else + elemSize = gtiDecodeSingle(*fmtString, inBuffer, inLength, args); + if (elemSize < 0) + return -1; //out of space + inBuffer += elemSize; + inLength -= elemSize; + fmtString++; + } + //NOTE: inLength should be 0 here if we "ate" the whole message + //If it's not 0, then the encoding and decoding strings probably did not match + //which would generally indicate a bug + //PANTS - commented out because we could be decoding the rest with a gtDecodeNoType +// assert(inLength == 0); + return totSize - inLength; +} + +int gtDecodeV(const char *fmtString, char *inBuffer, int inLength, va_list *args) +{ + return gtDecodeInternalV(1,fmtString, inBuffer, inLength, args); +} + +int gtDecodeNoTypeV(const char *fmtString, char *inBuffer, int inLength, va_list *args) +{ + return gtDecodeInternalV(0,fmtString, inBuffer, inLength, args); +} + +int gtDecode(const char *fmtString, char *inBuffer, int inLength, ...) +{ + int rcode; + va_list args; + + //set the values + va_start(args, inLength); + rcode = gtDecodeV(fmtString, inBuffer, inLength, &args); + va_end(args); + + return rcode; +} + +int gtDecodeNoType(const char *fmtString, char *inBuffer, int inLength, ...) +{ + int rcode; + va_list args; + + //set the values + va_start(args, inLength); + rcode = gtDecodeNoTypeV(fmtString, inBuffer, inLength, &args); + va_end(args); + + return rcode; +} + +GTMessageType gtEncodedMessageType(char *inBuffer) +{ + GTMessageType type; + //GS_ASSERT(sizeof(GTMessageType) ==2 ) + gt2MemCopy16((char *)&type, inBuffer); + return type; +} + +// change the message type for an encoded message +void gtEncodedMessageTypeSet (char *inBuffer, GTMessageType newtype) +{ + gt2MemCopy16(inBuffer, (char *)&newtype); +} + diff --git a/xrGameSpy/gamespy/gt2/gt2Encode.h b/xrGameSpy/gamespy/gt2/gt2Encode.h new file mode 100644 index 00000000000..4e49fba5182 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Encode.h @@ -0,0 +1,180 @@ +//TODO: Address Byte order & Byte alignment issues +#ifndef _GT_ENCODE_H +#define _GT_ENCODE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(UNDER_CE) || defined(__mips64) || defined(_PSP) +#define ALIGNED_COPY +//the aligned copy code all needs to be optimized +#endif + + + + +// Used to identify the type of message so you can look up the correct format string +// and pass the correct parameters +// You should use 1 msgType for each unique format string/parameter combination +//////////////////////////////////////////////////////// +typedef unsigned short GTMessageType; + +// Encode a message into outBuffer +// Returns the length of the encoded message, or -1 to indicate insufficient space +// You must make sure the number of arguments match the fmtString list +//////////////////////////////////////////////////////// +int gtEncode(GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, ...); +int gtEncodeV(GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, va_list *args); +int gtEncodeNoType(const char *fmtString, char *outBuffer, int outLength, ...); +int gtEncodeNoTypeV(const char *fmtString, char *outBuffer, int outLength, va_list *args); + +// Decode the message from inBuffer into the vars provided +// Returns -1 if there was a problem with the buffer +// Vars should all be pointers (as if using scanf) +// You must make sure the number of arguments match the fmtString list +//////////////////////////////////////////////////////// +int gtDecode(const char *fmtString, char *inBuffer, int inLength, ...); +int gtDecodeV(const char *fmtString, char *inBuffer, int inLength, va_list *args); +int gtDecodeNoType(const char *fmtString, char *inBuffer, int inLength, ...); +int gtDecodeNoTypeV(const char *fmtString, char *inBuffer, int inLength, va_list *args); + +// Retrieve the message type for an encoded message +//////////////////////////////////////////////////////// +GTMessageType gtEncodedMessageType (char *inBuffer); +// change the message type for an encoded message +void gtEncodedMessageTypeSet (char *inBuffer, GTMessageType newtype); + +// This handles alignment issues and endianess +///////////////////////////////////////////////////////// +void gt2MemCopy16(char *out, char const *in); +void gt2MemCopy32(char *out, char const *in); +void gt2MemCopy64(char *out, char const *in); +void gt2MemCopy(char *out, char const *in, int size); + +/**************************** +Types that can be sent using the encode/decode functions +Most are self-explanatory, but the following require some clarification: + +GT_CSTR: This is a NUL terminated C-string. The length is determined automatically. +The NUL character is restored in decode. You simply pass the char * string as +the arguement for Encode. Note that in the pointer passed to Decode must have enough +memory allocated to it for the max string that will be encoded - otherwise +the destination may get trashed. If you cannot guarantee them max length of the +string, you should use GT_RAW (see below). + +GT_DBSTR: Same as a GT_CSTR, except with 2-byte characters instead of single byte. +String must be terminated with a double NUL character. + +GT_RAW: Use raw to send data blocks, structures, arrays, etc - although you must +make sure they're the same on all platforms! +Requires you to pass both a buffer and a length arguement to Encode and Decode. +You should pass the buffer first, then the length. +For Decode, you must initialize the length pointer to the max length of the buffer. +If the decoded data exceeds this length, the Decode function will return -1, and the +length pointer will be set to the actual length. You can then call Decode again with +a buffer that is at least the required length. +Example: +gtEncode(0, "r", buf, buflen, "somerawdata",10); +char *rawbuffer = malloc(5); +char rawlen = 5; +ret = gtDecode(0, "r", buf, buflen, rawbuffer, &rawlen); +//gtDecode will return -1, and rawlen will be set to 10 +if (ret == -1) +{ + rawbuffer = realloc(rawbuffer, rawlen); + gtDecode(0, "r", buf, buflen, rawbuffer, &rawlen); + //gtDecode will now succeed +} + +GT_CSTR_PTR, GT_DBSTR_PTR, GT_RAW_PTR: For Decode, instead of copying the data from +input buffer into the pointer provided, the pointer is simply set to the +offset of the data in the input buffer. This removes the need to allocate +memory for the pointers before hand, and elimantes an extra memory copy. +You will need to pass in double pointers (e.g. char **) so that the pointer +can be changed. +However, you must make sure you don't try to use the pointers after the +input buffer is freed/changed. +Note that the buffer passed in gtReceivedCallback must be copied off if +you want to continue using it after you return from the callback (or, you +can use the non-PTR versions that copy off into the buffers you provide +automatically) +You can pass the _PTR versions to Encode and they will behave exactly as +the regular versions. + +GT_CSTR_PTR, GT_CSTR_ARRAY_PTR: Same as GT_CSTR and GT_CSTR_PTR, but uses +an array of strings instead of a single string. The array of strings is +terminated by an empty string (a single NUL character). + +GT_BIT: If you pass all your bits together in the format string, they will be +packed together to save space. So, the format string "zzzzzzzz" will only take +1 byte for the data (+2 bytes for the message type). +Note that if you have other types between the bits, the packing will NOT occur, +e.g.: "ziz" will use 6 bytes (2 for the bits, 4 for the int), whereas "zzi" would use +only 5 bytes (1 for the bits, 4 for the int) +The argument type for bits is char for Encode and char * for Decode - +If the char is 0, the bit will not be set, if it's non-zero, the bit will be set. +Note that in Decode, the set bit will always be returned as 1 (not the non-zero value +you set) +*/ + +#define GT_INT 'i' +#define GT_INT_ "i" +#define GT_INT_TYPE int +#define GT_UINT 'u' +#define GT_UINT_ "u" +#define GT_UINT_TYPE unsigned int +#define GT_SHORT 'o' +#define GT_SHORT_ "o" +#define GT_SHORT_TYPE short +#define GT_USHORT 'p' +#define GT_USHORT_ "p" +#define GT_USHORT_TYPE unsigned short +#define GT_CHAR 'c' +#define GT_CHAR_ "c" +#define GT_CHAR_TYPE signed char +#define GT_UCHAR 'b' +#define GT_UCHAR_ "b" +#define GT_UCHAR_TYPE unsigned char +#define GT_FLOAT 'f' +#define GT_FLOAT_ "f" +#define GT_FLOAT_TYPE float +#define GT_DOUBLE 'd' +#define GT_DOUBLE_ "d" +#define GT_DOUBLE_TYPE double +#define GT_CSTR 's' +#define GT_CSTR_ "s" +#define GT_CSTR_TYPE char * +#define GT_CSTR_PTR 'S' +#define GT_CSTR_PTR_ "S" +#define GT_CSTR_PTR_TYPE char ** +#define GT_DBSTR 'w' +#define GT_DBSTR_ "w" +#define GT_DBSTR_TYPE short * +#define GT_DBSTR_PTR 'W' +#define GT_DBSTR_PTR_ "W" +#define GT_DBSTR_PTR_TYPE short ** +#define GT_CSTR_ARRAY 'a' +#define GT_CSTR_ARRAY_ "a" +#define GT_CSTR_ARRAY_TYPE char * +#define GT_CSTR_ARRAY_PTR 'A' +#define GT_CSTR_ARRAY_PTR_ "A" +#define GT_CSTR_ARRAY_PTR_TYPE char ** +#define GT_RAW 'r' //two parameters! (data, then length) +#define GT_RAW_ "r" //two parameters! +#define GT_RAW_TYPE char * +#define GT_RAW_PTR 'R' +#define GT_RAW_PTR_ "R" +#define GT_RAW_PTR_TYPE char ** +#define GT_BIT 'z' +#define GT_BIT_ "z" +#define GT_BIT_TYPE unsigned char + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Filter.c b/xrGameSpy/gamespy/gt2/gt2Filter.c new file mode 100644 index 00000000000..27195af7739 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Filter.c @@ -0,0 +1,191 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Filter.h" +#include "gt2Callback.h" +#include "gt2Message.h" +#include "gt2Utility.h" + +static int GS_STATIC_CALLBACK gti2SendFiltersCompare +( + const void * elem1, + const void * elem2 +) +{ + gt2SendFilterCallback * callback1 = (gt2SendFilterCallback *)elem1; + gt2SendFilterCallback * callback2 = (gt2SendFilterCallback *)elem2; + + if(*callback1 == *callback2) + return 0; + + return 1; +} + +static int GS_STATIC_CALLBACK gti2ReceiveFiltersCompare +( + const void * elem1, + const void * elem2 +) +{ + gt2ReceiveFilterCallback * callback1 = (gt2ReceiveFilterCallback *)elem1; + gt2ReceiveFilterCallback * callback2 = (gt2ReceiveFilterCallback *)elem2; + + if(*callback1 == *callback2) + return 0; + + return 1; +} + +GT2Bool gti2AddSendFilter(GT2Connection connection, gt2SendFilterCallback callback) +{ + // Check if we have a send filters list. + if(!connection->sendFilters) + return GT2False; + + // Add this callback to the list. + ArrayAppend(connection->sendFilters, &callback); + + // Return GT2True if it was added. + return (ArraySearch(connection->sendFilters, &callback, gti2SendFiltersCompare, 0, 0) != NOT_FOUND); +} + +GT2Bool gti2AddReceiveFilter(GT2Connection connection, gt2ReceiveFilterCallback callback) +{ + // Check if we have a receive filters list. + if(!connection->receiveFilters) + return GT2False; + + // Add this callback to the list. + ArrayAppend(connection->receiveFilters, &callback); + + // Return GT2True if it was added. + return (ArraySearch(connection->receiveFilters, &callback, gti2ReceiveFiltersCompare, 0, 0) != NOT_FOUND); +} + +void gti2RemoveSendFilter(GT2Connection connection, gt2SendFilterCallback callback) +{ + int index; + + // Check for no filters. + if(!connection->sendFilters) + return; + + // check for removing all + if(!callback) + { + // Remove all the filters. + ArrayClear(connection->sendFilters); + return; + } + + // Find it. + index = ArraySearch(connection->sendFilters, &callback, gti2SendFiltersCompare, 0, 0); + if(index == NOT_FOUND) + return; + + // Remove it. + ArrayRemoveAt(connection->sendFilters, index); +} + +void gti2RemoveReceiveFilter(GT2Connection connection, gt2ReceiveFilterCallback callback) +{ + int index; + + // Check for no filters. + if(!connection->receiveFilters) + return; + + // check for removing all + if(!callback) + { + // Remove all the filters. + ArrayClear(connection->receiveFilters); + return; + } + + // Find it. + index = ArraySearch(connection->receiveFilters, &callback, gti2ReceiveFiltersCompare, 0, 0); + if(index == NOT_FOUND) + return; + + // Remove it. + ArrayRemoveAt(connection->receiveFilters, index); +} + +GT2Bool gti2FilteredSend(GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable) +{ + int num; + + // Make sure we're connected. + if(connection->state != GTI2Connected) + return GT2True; + + // check the message and len + gti2MessageCheck(&message, &len); + + // Get the number of filters. + num = ArrayLength(connection->sendFilters); + + // Check if its a valid ID. + if(filterID < 0) + return GT2True; + if(filterID >= num) + return GT2True; + + // Is it the last one? + if(filterID == (num - 1)) + { + // Do the actual send. + if(!gti2Send(connection, message, len, reliable)) + return GT2False; + } + else + { + // Filter it. + if(!gti2SendFilterCallback(connection, ++filterID, message, len, reliable)) + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2FilteredReceive(GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable) +{ + int num; + + // Make sure we're connected. + if(connection->state != GTI2Connected) + return GT2True; + + // Get the number of filters. + num = ArrayLength(connection->receiveFilters); + + // Check if its a valid ID. + if(filterID < 0) + return GT2True; + if(filterID >= num) + return GT2True; + + // Is it the last one? + if(filterID == (num - 1)) + { + // call the callback + if(!gti2ReceivedCallback(connection, message, len, reliable)) + return GT2False; + } + else + { + // Filter it. + if(!gti2ReceiveFilterCallback(connection, ++filterID, message, len, reliable)) + return GT2False; + } + + return GT2True; +} diff --git a/xrGameSpy/gamespy/gt2/gt2Filter.h b/xrGameSpy/gamespy/gt2/gt2Filter.h new file mode 100644 index 00000000000..a3595d97228 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Filter.h @@ -0,0 +1,24 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_FILTER_H_ +#define _GT2_FILTER_H_ + +#include "gt2Main.h" + +GT2Bool gti2AddSendFilter(GT2Connection connection, gt2SendFilterCallback callback); +void gti2RemoveSendFilter(GT2Connection connection, gt2SendFilterCallback callback); +GT2Bool gti2FilteredSend(GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable); + +GT2Bool gti2AddReceiveFilter(GT2Connection connection, gt2ReceiveFilterCallback callback); +void gti2RemoveReceiveFilter(GT2Connection connection, gt2ReceiveFilterCallback callback); +GT2Bool gti2FilteredReceive(GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable); + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Main.c b/xrGameSpy/gamespy/gt2/gt2Main.c new file mode 100644 index 00000000000..9c688e2ee14 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Main.c @@ -0,0 +1,477 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Main.h" +#include "gt2Socket.h" +#include "gt2Connection.h" +#include "gt2Message.h" +#include "gt2Callback.h" +#include "gt2Filter.h" +#include "gt2Utility.h" + +#define GTI2_INVALID_IP_MASK 0xE0000000 + +/********************* +** SOCKET FUNCTIONS ** +*********************/ + +// Xbox VDP socket function(s). +#ifdef _XBOX +GT2Result gt2CreateVDPSocket +( + GT2Socket * socket, + const char * localAddress, + int outgoingBufferSize, + int incomingBufferSize, + gt2SocketErrorCallback callback +) +{ + return gti2CreateSocket(socket, localAddress, outgoingBufferSize, incomingBufferSize, callback, GTI2VdpProtocol); +} +#endif + + +GT2Result gt2CreateSocket +( + GT2Socket * socket, + const char * localAddress, + int outgoingBufferSize, + int incomingBufferSize, + gt2SocketErrorCallback callback +) +{ + return gti2CreateSocket(socket, localAddress, outgoingBufferSize, incomingBufferSize, callback, GTI2UdpProtocol); +} + +GT2Result gt2CreateAdHocSocket +( + GT2Socket * socket, + const char * localAddress, + int outgoingBufferSize, + int incomingBufferSize, + gt2SocketErrorCallback callback +) +{ + return gti2CreateSocket(socket, localAddress, outgoingBufferSize, incomingBufferSize, callback, GTI2AdHocProtocol); +} + + +void gt2CloseSocket(GT2Socket socket) +{ + // hard close the connections + gt2CloseAllConnectionsHard(socket); + + // close the socket + gti2CloseSocket(socket); +} + +void gt2Think(GT2Socket socket) +{ + // check for incoming messages + if(!gti2ReceiveMessages(socket)) + return; + + // let the connections think + if(!gti2SocketConnectionsThink(socket)) + return; + + // free closed connections + gti2FreeClosedConnections(socket); +} + +GT2Result gt2SendRawUDP +( + GT2Socket socket, + const char * remoteAddress, + const GT2Byte * message, + int len +) +{ + unsigned int ip; + unsigned short port; + + // get the ip and port + if(!gt2StringToAddress(remoteAddress, &ip, &port) || !port) + return GT2AddressError; + + // check for invalid IP ranges + // class D (224-239.*, multicast) and class E (240-255.*, experimental) + if((ntohl(ip) & GTI2_INVALID_IP_MASK) == GTI2_INVALID_IP_MASK) + return GT2AddressError; + + // check if this is for broadcast + if(!ip) + { + // check if broadcast is enable + if(!socket->broadcastEnabled) + { + if(!SetSockBroadcast(socket->socket)) + return GT2NetworkError; + socket->broadcastEnabled = GT2True; + } + + // set the broadcast ip + ip = gsiGetBroadcastIP(); + } + + // send the datagram + gti2SocketSend(socket, ip, port, message, len); + + return GT2Success; +} + +/********************* +** LISTEN FUNCTIONS ** +*********************/ + +void gt2Listen(GT2Socket socket, gt2ConnectAttemptCallback callback) +{ + gti2Listen(socket, callback); +} + +GT2Bool gt2Accept(GT2Connection connection, GT2ConnectionCallbacks * callbacks) +{ + return gti2AcceptConnection(connection, callbacks); +} + +void gt2Reject(GT2Connection connection, const GT2Byte * message, int len) +{ + gti2RejectConnection(connection, message, len); +} + +/************************* +** CONNECTION FUNCTIONS ** +*************************/ + +GT2Result gt2Connect +( + GT2Socket socket, + GT2Connection * connection, + const char * remoteAddress, + const GT2Byte * message, + int len, + int timeout, + GT2ConnectionCallbacks * callbacks, + GT2Bool blocking +) +{ + GT2Connection connectionTemp; + GT2Result result; + GT2Bool done; + unsigned int ip; + unsigned short port; + + { + // get the ip and port + if(!gt2StringToAddress(remoteAddress, &ip, &port) || !ip || !port) + return GT2AddressError; + } + + // check for invalid IP ranges + // class D (224-239.*, multicast) and class E (240-255.*, experimental) + if((ntohl(ip) & GTI2_INVALID_IP_MASK) == GTI2_INVALID_IP_MASK) + return GT2AddressError; + + // create the connection object + result = gti2NewOutgoingConnection(socket, &connectionTemp, ip, port); + if(result) + return result; + + // save the timeout value + connectionTemp->timeout = (unsigned int)timeout; + + // initiate the connection attempt + result = gti2StartConnectionAttempt(connectionTemp, message, len, callbacks); + if(result) + { + gti2FreeSocketConnection(connectionTemp); + return result; + } + + // if not blocking, return now + if(!blocking) + { + if(connection) + *connection = connectionTemp; + return GT2Success; + } + + // we're not really in a callback, but this will prevent the connection + // from being freed before the loop finishes. + connectionTemp->callbackLevel++; + + // if blocking, loop until the connect attempt is done + do + { + // think + gt2Think(socket); + + // check if we're done + done = (connectionTemp->state >= GTI2Connected); + + // if we're not done, take a rest + if(!done) + msleep(1); + } while(!done); + + // bring the callback level back down + connectionTemp->callbackLevel--; + + // is it success? + if(connectionTemp->state == GTI2Connected) + *connection = connectionTemp; + + return connectionTemp->connectionResult; +} + +GT2Result gt2Send +( + GT2Connection connection, + const GT2Byte * message, + int len, + GT2Bool reliable +) +{ + // used to check for voice data in reliable messages + unsigned short vdpDataLength; + + // can't send a message if not connected + if(connection->state != GTI2Connected) + return GT2InvalidConnection; + + // check the message and len + gti2MessageCheck(&message, &len); + + if (reliable && connection->socket->protocolType == GTI2VdpProtocol) + { + memcpy(&vdpDataLength, message, sizeof(unsigned short)); + assert(vdpDataLength + connection->socket->protocolOffset == len); + if (vdpDataLength + connection->socket->protocolOffset != len) + return GT2InvalidMessage; + } + + // do we need to filter it? + if(ArrayLength(connection->sendFilters)) + { + gti2SendFilterCallback(connection, 0, message, len, reliable); + return GT2Success; + } + + if (gti2Send(connection, message, len, reliable)) + return GT2Success; + + return GT2SendFailed; +} + +void gt2Ping(GT2Connection connection) +{ + gti2SendPing(connection); +} + +void gt2CloseConnection(GT2Connection connection) +{ + gti2CloseConnection(connection, GT2False); +} + +void gt2CloseConnectionHard(GT2Connection connection) +{ + gti2CloseConnection(connection, GT2True); +} + +static void gti2CloseAllConnectionsMap(void * elem, void * clientData) +{ + gt2CloseConnection(*(GT2Connection *)elem); + + GSI_UNUSED(clientData); +} + +void gt2CloseAllConnections(GT2Socket socket) +{ + TableMapSafe(socket->connections, gti2CloseAllConnectionsMap, NULL); +} + +static void gti2CloseAllConnectionsHardMap(void * elem, void * clientData) +{ + gt2CloseConnectionHard(*(GT2Connection *)elem); + + GSI_UNUSED(clientData); +} + +void gt2CloseAllConnectionsHard(GT2Socket socket) +{ + TableMapSafe(socket->connections, gti2CloseAllConnectionsHardMap, NULL); +} + +/************************* +** MESSAGE CONFIRMATION ** +*************************/ +GT2MessageID gt2GetLastSentMessageID(GT2Connection connection) +{ + return (GT2MessageID)(connection->serialNumber - 1); +} + +GT2Bool gt2WasMessageIDConfirmed(GT2Connection connection, GT2MessageID messageID) +{ + return gti2WasMessageIDConfirmed(connection, messageID); +} + +/********************* +** FILTER FUNCTIONS ** +*********************/ + +GT2Bool gt2AddSendFilter(GT2Connection connection, gt2SendFilterCallback callback) +{ + return gti2AddSendFilter(connection, callback); +} + +void gt2RemoveSendFilter(GT2Connection connection, gt2SendFilterCallback callback) +{ + gti2RemoveSendFilter(connection, callback); +} + +void gt2FilteredSend(GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable) +{ + gti2FilteredSend(connection, filterID, message, len, reliable); +} + +GT2Bool gt2AddReceiveFilter(GT2Connection connection, gt2ReceiveFilterCallback callback) +{ + return gti2AddReceiveFilter(connection, callback); +} + +void gt2RemoveReceiveFilter(GT2Connection connection, gt2ReceiveFilterCallback callback) +{ + gti2RemoveReceiveFilter(connection, callback); +} + +void gt2FilteredReceive(GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable) +{ + gti2FilteredReceive(connection, filterID, message, len, reliable); +} + +/******************* +** INFO FUNCTIONS ** +*******************/ + +GT2Socket gt2GetConnectionSocket(GT2Connection connection) +{ + return connection->socket; +} + +GT2ConnectionState gt2GetConnectionState(GT2Connection connection) +{ + if(connection->state < GTI2Connected) + return GT2Connecting; + if(connection->state == GTI2Connected) + return GT2Connected; + if(connection->state == GTI2Closing) + return GT2Closing; + return GT2Closed; +} + +unsigned int gt2GetRemoteIP(GT2Connection connection) +{ + return connection->ip; +} + +unsigned short gt2GetRemotePort(GT2Connection connection) +{ + return connection->port; +} + +unsigned int gt2GetLocalIP(GT2Socket socket) +{ + return socket->ip; +} + +unsigned short gt2GetLocalPort(GT2Socket socket) +{ + return socket->port; +} + +int gt2GetIncomingBufferSize(GT2Connection connection) +{ + return connection->incomingBuffer.size; +} + +int gt2GetIncomingBufferFreeSpace(GT2Connection connection) +{ + return (connection->incomingBuffer.size - connection->incomingBuffer.len); +} + +int gt2GetOutgoingBufferSize(GT2Connection connection) +{ + return connection->outgoingBuffer.size; +} + +int gt2GetOutgoingBufferFreeSpace(GT2Connection connection) +{ + return (connection->outgoingBuffer.size - connection->outgoingBuffer.len); +} + +/***************************** +** SOCKET SHARING FUNCTIONS ** +*****************************/ + +SOCKET gt2GetSocketSOCKET(GT2Socket socket) +{ + return socket->socket; +} + +void gt2SetUnrecognizedMessageCallback(GT2Socket socket, gt2UnrecognizedMessageCallback callback) +{ + socket->unrecognizedMessageCallback = callback; +} + +/************************ +** USER DATA FUNCTIONS ** +************************/ + +void gt2SetSocketData(GT2Socket socket, void * data) +{ + assert(socket); + + socket->data = data; +} + +void * gt2GetSocketData(GT2Socket socket) +{ + assert(socket); + + return socket->data; +} + +void gt2SetConnectionData(GT2Connection connection, void * data) +{ + assert(connection); + + connection->data = data; +} + +void * gt2GetConnectionData(GT2Connection connection) +{ + assert(connection); + + return connection->data; +} + +/******************* +** DUMP FUNCTIONS ** +*******************/ + +void gt2SetSendDump(GT2Socket socket, gt2DumpCallback callback) +{ + socket->sendDumpCallback = callback; +} + +void gt2SetReceiveDump(GT2Socket socket, gt2DumpCallback callback) +{ + socket->receiveDumpCallback = callback; +} diff --git a/xrGameSpy/gamespy/gt2/gt2Main.h b/xrGameSpy/gamespy/gt2/gt2Main.h new file mode 100644 index 00000000000..0915f45a1a0 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Main.h @@ -0,0 +1,255 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_MAIN_H_ +#define _GT2_MAIN_H_ + +#include "gt2.h" +#include "../darray.h" +#include "../hashtable.h" +#include "gt2Auth.h" + +/************************* +** CONFIGURABLE DEFINES ** +*************************/ + +// these defines are internal to GT2 and are NOT guaranteed to persist from version to version. + + +// If set, this will convert all big endian vars to little endian before sending accross the net +// And on big endian machines, convert little endian to big endian on recv +//#define _GT2_ENDIAN_CONVERT_ENABLE // add this to your compiler pre-processor options + +#if defined GSI_BIG_ENDIAN && defined _GT2_ENDIAN_CONVERT_ENABLE + #define _GT2_ENDIAN_CONVERT +#endif + + + +// any unreliable application message that starts with this magic string will have extra overhead. +// the string can be changed to something that your application will not use, or not use frequently. +// the only impact of this change will be to make your application incomatible with other application's +// using either the original or another different magic string. +// the string can consist of any number of characters, as long as there's at least one character, and the +// length define matches the string's length. +#define GTI2_MAGIC_STRING "\xFE\xFE" +#define GTI2_MAGIC_STRING_LEN 2 + +// the size of the buffer into which GT2 directly receives messages. this buffer is declared on the stack, +// and so can be fairly large on most systems without having any impact. however, on some systems with small +// stacks, this size can overflow the stack, in which case it should be lowered. +// note, this buffer size only needs to be slighty larger than the largest message that will be sent ("slighty +// larger" due to overhead with reliable messages, and unreliable messages starting with the magic string). +#if defined(_PS2) && defined(INSOCK) + #define GTI2_STACK_RECV_BUFFER_SIZE NETBUFSIZE // Max for Insock. Otherwise SOCKET_ERROR +#elif defined(_NITRO) + #define GTI2_STACK_RECV_BUFFER_SIZE 1500 +#elif defined (_XBOX) // Xbox packets are 1304, + #define GTI2_STACK_RECV_BUFFER_SIZE 4096 // when using VDP sockets, 2 bytes are used for data length +#else + #define GTI2_STACK_RECV_BUFFER_SIZE 65535 +#endif + +// a server will disconnect a client that doesn't not successfully connect within this time (in milliseconds). +// if the connectAttemptCallback has been called, and GT2 is awaiting an accept/reject, the attempt will +// not be timed-out (although the client may abort the attempt at any time). +#define GTI2_SERVER_TIMEOUT (1 * 60 * 1000) +// the time (in milliseconds) GT2 waits between resending a message whose delivery has not yet been confirmed. +#define GTI2_RESEND_TIME 1000 +// the time (in milliseconds) GT2 waits after receiving a message it must acknowledge before it actually sends +// the ack. this allows it to combine acks, or include acks as part of other reliable messages it sends. +// if an ack is pending, a new incoming message does not reset this timer. +#define GTI2_PENDING_ACK_TIME 100 +// if GT2 does not send a message for this amount of time (in milliseconds), it sends a keep-alive message. +#define GTI2_KEEP_ALIVE_TIME (30 * 1000) +// if this is defined, it sets the percentage of sent datagrams to drop. this is good for simulating what will +// happen on a high packet loss connection. +//#define GTI2_DROP_SEND_RATE 30 +typedef enum +{ + GTI2UdpProtocol, // UDP socket type for standard sockets + GTI2VdpProtocol = 2, // VDP socket type only used for Xbox VDP sockets + GTI2AdHocProtocol = 3 // socket type only used for PSP Adhoc sockets +} GTI2ProtocolType; + +// The Maximum offset of eiter UDP or VDP +// measured in bytes +// used as a buffer offset +#define MAX_PROTOCOL_OFFSET 2 + +/********** +** TYPES ** +**********/ + +typedef enum +{ + // client-only states + GTI2AwaitingServerChallenge, // sent challenge, waiting for server's challenge + GTI2AwaitingAcceptance, // sent response, waiting for accept/reject from server + + // server-only states + GTI2AwaitingClientChallenge, // receiving challenge from a new client + GTI2AwaitingClientResponse, // sent challenge, waiting for client's response + GTI2AwaitingAcceptReject, // got client's response, waiting for app to accept/reject + + // post-negotiation states + GTI2Connected, // connected + GTI2Closing, // sent a close message (GTI2Close or GTI2Reject), waiting for confirmation + GTI2Closed // connection has been closed, free it as soon as possible +} GTI2ConnectionState; + +// message types +typedef enum +{ + // reliable messages + // all start with + // type is 1 bytes, SN and ESN are 2 bytes each + GTI2MsgAppReliable, // reliable application message + GTI2MsgClientChallenge, // client's challenge to the server (initial connection request) + GTI2MsgServerChallenge, // server's response to the client's challenge, and his challenge to the client + GTI2MsgClientResponse, // client's response to the server's challenge + GTI2MsgAccept, // server accepting client's connection attempt + GTI2MsgReject, // server rejecting client's connection attempt + GTI2MsgClose, // message indicating the connection is closing + GTI2MsgKeepAlive, // keep-alive used to help detect dropped connections + + GTI2NumReliableMessages, + + // unreliable messages + GTI2MsgAck = 100, // acknowledge receipt of reliable message(s) + GTI2MsgNack, // alert sender to missing reliable message(s) + GTI2MsgPing, // used to determine latency + GTI2MsgPong, // a reply to a ping + GTI2MsgClosed // confirmation of connection closure (GTI2MsgClose or GTI2MsgReject) - also sent in response to bad messages from unknown addresses + + // unreliable messages don't really have a message type, just the magic string repeated at the start +} GTI2MessageType; + +/*************** +** STRUCTURES ** +***************/ + +typedef struct GTI2Buffer +{ + GT2Byte * buffer; // The buffer's bytes. + int size; // Number of bytes in buffer. + int len; // Length of actual data in buffer. +} GTI2Buffer; + +typedef struct GTI2IncomingBufferMessage +{ + int start; // the start of the message + int len; // the length of the message + GTI2MessageType type; // the type + unsigned short serialNumber; // the serial number +} GTI2IncomingBufferMessage; + +typedef struct GTI2OutgoingBufferMessage +{ + int start; // the start of the message + int len; // the length of the message + unsigned short serialNumber; // the serial number + gsi_time lastSend; // last time this message was sent +} GTI2OutgoingBufferMessage; + +typedef struct GTI2Socket +{ + SOCKET socket; // the network socket used for all network communication + + unsigned int ip; // the ip this socket is bound to + unsigned short port; // the port this socket is bound to + + HashTable connections; // the connections that are using this socket + DArray closedConnections; // connections that are closed no longer get a spot in the hash table + + GT2Bool close; // if true, a close was attempted inside a callback, and it should be closed as soon as possible + GT2Bool error; // if true, there was a socket error using this socket + + int callbackLevel; // if >0, then we're inside a callback (or recursive callbacks) + gt2ConnectAttemptCallback connectAttemptCallback; // if set, callback used to handle incoming connection attempts + gt2SocketErrorCallback socketErrorCallback; // if set, call this in case of an error + gt2DumpCallback sendDumpCallback; // if set, gets called for every datagram sent + gt2DumpCallback receiveDumpCallback; // if set, gets called for every datagram and connection reset received + gt2UnrecognizedMessageCallback unrecognizedMessageCallback; // if set, gets called for all unrecognized messages + + void * data; // user data + + int outgoingBufferSize; // per-connection buffer sizes + int incomingBufferSize; + + GTI2ProtocolType protocolType; // set to UDP or VDP protocol depending on the call to create socket + // also used as an offset for VDP sockets + int protocolOffset; + GT2Bool broadcastEnabled; // set to true if the socket has already been broadcast enabled +} GTI2Socket; + +typedef struct GTI2Connection +{ + // ip and port uniquely identify this connection on this socket + unsigned int ip; // the ip on the other side of this connection (network byte order) + unsigned short port; // the port on the other side of this connection (host byte order) + + GTI2Socket * socket; // the parent socket + + GTI2ConnectionState state; // connection state + + GT2Bool initiated; // if true, the local side of the connection initiated the connection (client) + + GT2Bool freeAtAcceptReject; // if true, don't free the connection until accept/reject is called + + GT2Result connectionResult; // the result of the connect attempt + + gsi_time startTime; // the time the connection was created + gsi_time timeout; // the timeout value passed into gt2Connect + + int callbackLevel; // if >0, then we're inside a callback (or recursive callbacks) + GT2ConnectionCallbacks callbacks; // connection callbacks + + char * initialMessage; // this is the initial message for the client + int initialMessageLen; // the initial message length + + void * data; // user data + + GTI2Buffer incomingBuffer; // buffer for incoming data + GTI2Buffer outgoingBuffer; // buffer for outgoing data + DArray incomingBufferMessages; // identifies incoming messages stored in the buffer + DArray outgoingBufferMessages; // identifies outgoing messages stored in the buffer + + unsigned short serialNumber; // serial number of the next message to be sent out + unsigned short expectedSerialNumber; // the next serial number we're expecting from the remote side + + char response[GTI2_RESPONSE_LEN]; // after the challenge is sent during negotiation, this is the response we're expecting + + gsi_time lastSend; // the last time something was sent on this connection + gsi_time challengeTime; // the time the challenge was sent + + GT2Bool pendingAck; // if true, there is an ack waiting to go out, either on its own or as part of a reliable message + + gsi_time pendingAckTime; // the time at which the pending ack was first set + + DArray sendFilters; // filters that apply to outgoing data + DArray receiveFilters; // filters that apply to incoming data + +} GTI2Connection; + +// store last 32 ip's in a ring buffer +#define MAC_TABLE_SIZE 32 // must be power of 2 +typedef struct +{ + gsi_u32 ip; + char mac[6]; +} GTI2MacEntry; + +#ifdef GSI_ADHOC +static int lastmactableentry = 0; +static GTI2MacEntry MacTable[MAC_TABLE_SIZE]; +#endif // GSI_ADHOC + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Message.c b/xrGameSpy/gamespy/gt2/gt2Message.c new file mode 100644 index 00000000000..2ae44d8b596 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Message.c @@ -0,0 +1,1802 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Message.h" +#include "gt2Buffer.h" +#include "gt2Connection.h" +#include "gt2Socket.h" +#include "gt2Callback.h" +#include "gt2Utility.h" +#include + +static unsigned short gti2UShortFromBuffer(const GT2Byte * buffer, int pos) +{ + unsigned short s; + s = (unsigned short)((buffer[pos] << 8) & 0xFF00); + pos++; + s |= buffer[pos]; + + return s; +} + + +static void gti2UShortToBuffer(GT2Byte * buffer, int pos, unsigned short s) +{ + buffer[pos++] = (GT2Byte)((s >> 8) & 0xFF); + buffer[pos] = (GT2Byte)(s & 0xFF); +} + +static int gti2SNDiff(unsigned short SN1, unsigned short SN2) +{ + return (short)(SN1 - SN2); +} + +static GT2Bool gti2ConnectionError(GT2Connection connection, GT2Result result, GT2CloseReason reason) +{ + // first check if we're still connecting + if(connection->state < GTI2Connected) + { + // check if the local side is the initiator + if(connection->initiated) + { + // mark it as closed + gti2ConnectionClosed(connection); + + // call the callback + if(!gti2ConnectedCallback(connection, result, NULL, 0)) + return GT2False; + } + else + { + // are we waiting for accept/reject? + if(connection->state == GTI2AwaitingAcceptReject) + connection->freeAtAcceptReject = GT2True; + + // mark it as closed + gti2ConnectionClosed(connection); + } + } + // report the close, as long as we're not already closed + else if(connection->state != GTI2Closed) + { + // mark it as closed + gti2ConnectionClosed(connection); + + // call the callback + if(!gti2ClosedCallback(connection, reason)) + return GT2False; + } + + return GT2True; +} + +static GT2Bool gti2ConnectionCommunicationError(GT2Connection connection) +{ + return gti2ConnectionError(connection, GT2NegotiationError, GT2CommunicationError); +} + +static GT2Bool gti2ConnectionMemoryError(GT2Connection connection) +{ + // let the other side know + if(!gti2SendClosed(connection)) + return GT2False; + + return gti2ConnectionError(connection, GT2OutOfMemory, GT2NotEnoughMemory); +} + + + + + +static GT2Bool gti2HandleESN(GT2Connection connection, unsigned short ESN) +{ + int len; + int i; + GTI2OutgoingBufferMessage * message; + int shortenBy; + + // get the number of messages in the outgoing queue + len = ArrayLength(connection->outgoingBufferMessages); + if(!len) + return GT2True; + + // loop through until we hit one we can't remove + for(i = 0 ; i < len ; i++) + { + // get the message + message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i); + + // don't stop until we get to the ESN + if(gti2SNDiff(message->serialNumber, ESN) >= 0) + break; + } + + // check for not removing any + if(i == 0) + return GT2True; + + // remove the message info structs + while(i--) + ArrayDeleteAt(connection->outgoingBufferMessages, i); + + // check how many messages are left + len = ArrayLength(connection->outgoingBufferMessages); + if(!len) + { + // buffer is empty + connection->outgoingBuffer.len = 0; + return GT2True; + } + + // figure out how much to move everything forward + message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, 0); + shortenBy = message->start; + + // do the move on the info structs + for(i = 0 ; i < len ; i++) + { + message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i); + message->start -= shortenBy; + } + + // move the actual data + gti2BufferShorten(&connection->outgoingBuffer, 0, shortenBy); + + return GT2True; +} + +static GT2Bool gti2HandleAppUnreliable(GT2Connection connection, GT2Byte * message, int len) +{ + // check the state + if((connection->state != GTI2Connected) && (connection->state != GTI2Closing)) + return GT2True; + + // do we need to filter it? + if(ArrayLength(connection->receiveFilters)) + { + if(!gti2ReceiveFilterCallback(connection, 0, message, len, GT2False)) + return GT2False; + return GT2True; + } + + // we received data, call the callback + if(!gti2ReceivedCallback(connection, message, len, GT2False)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleAppReliable(GT2Connection connection, GT2Byte * message, int len) +{ + // check the state + if((connection->state != GTI2Connected) && (connection->state != GTI2Closing)) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + } + else + { + // do we need to filter it? + if(ArrayLength(connection->receiveFilters)) + { + if(!gti2ReceiveFilterCallback(connection, 0, message, len, GT2True)) + return GT2False; + return GT2True; + } + + // we received data, call the callback + if(!gti2ReceivedCallback(connection, message, len, GT2True)) + return GT2False; + } + + return GT2True; +} + +static GT2Bool gti2HandleClientChallenge(GT2Connection connection, GT2Byte * message, int len) +{ + char response[GTI2_RESPONSE_LEN]; + char challenge[GTI2_CHALLENGE_LEN]; + + // check the state + if(connection->state != GTI2AwaitingClientChallenge) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // make sure the message is long enough + if(len < GTI2_CHALLENGE_LEN) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // generate a response to the challenge + gti2GetResponse((GT2Byte *)response, message); + + // generate our own challenge + gti2GetChallenge((GT2Byte *)challenge); + + // store what our response will be + gti2GetResponse((GT2Byte *)connection->response, (GT2Byte *)challenge); + + // send our own challenge + if(!gti2SendServerChallenge(connection, response, challenge)) + return GT2False; + + // new state + connection->state = GTI2AwaitingClientResponse; + + return GT2True; +} + + + +static GT2Bool gti2HandleServerChallenge(GT2Connection connection, GT2Byte * message, int len) +{ + char response[GTI2_RESPONSE_LEN]; + + // check the state + if(connection->state != GTI2AwaitingServerChallenge) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // make sure the message is long enough + if(len < (GTI2_RESPONSE_LEN + GTI2_CHALLENGE_LEN)) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // check the response + if(!gti2CheckResponse(message, (GT2Byte *)connection->response)) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // generate our response to the server's challenge + gti2GetResponse((GT2Byte *)response, message + GTI2_RESPONSE_LEN); + + // send the response, including our intial message + if(!gti2SendClientResponse(connection, response, connection->initialMessage, connection->initialMessageLen)) + return GT2False; + + // free the initial message + if(connection->initialMessage) + { + gsifree(connection->initialMessage); + connection->initialMessage = NULL; + } + + // new state + connection->state = GTI2AwaitingAcceptance; + + return GT2True; +} + +static GT2Bool gti2HandleClientResponse(GT2Connection connection, GT2Byte * message, int len) +{ + int latency; + + // check the state + if(connection->state != GTI2AwaitingClientResponse) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // make sure the message is long enough + if(len < (GTI2_RESPONSE_LEN)) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // check the response + if(!gti2CheckResponse(message, (GT2Byte *)connection->response)) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // need to make sure the connection didn't just stop listening + if(!connection->socket->connectAttemptCallback) + { + // send them a closed + if(!gti2SendClosed(connection)) + return GT2False; + + // mark it as closed + gti2ConnectionClosed(connection); + + return GT2True; + } + + // new state + connection->state = GTI2AwaitingAcceptReject; + + // calculate the approx. latency + latency = (int)(current_time() - connection->challengeTime); + + // it's up to the app now + if(!gti2ConnectAttemptCallback(connection->socket, connection, connection->ip, connection->port, latency, message + GTI2_RESPONSE_LEN, len - GTI2_RESPONSE_LEN)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleAccept(GT2Connection connection) +{ + // check the state + if(connection->state != GTI2AwaitingAcceptance) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // new state + connection->state = GTI2Connected; + + // call the callback + if(!gti2ConnectedCallback(connection, GT2Success, NULL, 0)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleReject(GT2Connection connection, GT2Byte * message, int len) +{ + // check the state + if(connection->state != GTI2AwaitingAcceptance) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // mark it as closed + gti2ConnectionClosed(connection); + + // send a closed reply + if(!gti2SendClosed(connection)) + return GT2False; + + // call the callback + if(!gti2ConnectedCallback(connection, GT2Rejected, message, len)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleClose(GT2Connection connection) +{ + GT2Bool localClose; + + // send a closed reply + if(!gti2SendClosed(connection)) + return GT2False; + + // were we attempting to close this connection? + localClose = (connection->state == GTI2Closing); + + // handle it as an error (so the right callbacks are called) + if(!gti2ConnectionError(connection, GT2Rejected, localClose?GT2LocalClose:GT2RemoteClose)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2DeliverReliableMessage(GT2Connection connection, GTI2MessageType type, GT2Byte * message, int len) +{ + // bump our ESN + connection->expectedSerialNumber++; + + if(type == GTI2MsgAppReliable) + { + if(!gti2HandleAppReliable(connection, message, len)) + return GT2False; + } + else if(type == GTI2MsgClientChallenge) + { + if(!gti2HandleClientChallenge(connection, message, len)) + return GT2False; + } + else if(type == GTI2MsgServerChallenge) + { + if(!gti2HandleServerChallenge(connection, message, len)) + return GT2False; + } + else if(type == GTI2MsgClientResponse) + { + if(!gti2HandleClientResponse(connection, message, len)) + return GT2False; + } + else if(type == GTI2MsgAccept) + { + if(!gti2HandleAccept(connection)) + return GT2False; + } + else if(type == GTI2MsgReject) + { + if(!gti2HandleReject(connection, message, len)) + return GT2False; + } + else if(type == GTI2MsgClose) + { + if(!gti2HandleClose(connection)) + return GT2False; + } + else if(type == GTI2MsgKeepAlive) + { + // ignore + } + + return GT2True; +} +#ifdef WIN32 +static int __cdecl gti2IncomingBufferMessageCompare(const void * elem1, const void * elem2) +#else +static int gti2IncomingBufferMessageCompare(const void * elem1, const void * elem2) +#endif +{ + const GTI2IncomingBufferMessage * message1 = (GTI2IncomingBufferMessage *)elem1; + const GTI2IncomingBufferMessage * message2 = (GTI2IncomingBufferMessage *)elem2; + + return gti2SNDiff(message1->serialNumber, message2->serialNumber); +} + +static GT2Bool gti2BufferIncomingMessage(GT2Connection connection, GTI2MessageType type, unsigned short SN, GT2Byte * message, int len, GT2Bool * overflow) +{ + GTI2IncomingBufferMessage messageInfo; + GTI2IncomingBufferMessage * bufferedMessage; + int num; + int i; + + // check the number of messages being held + num = ArrayLength(connection->incomingBufferMessages); + + // check if this message is already buffered + for(i = 0 ; i < num ; i++) + { + // get the message + bufferedMessage = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, i); + + // check if this is the same message + if(bufferedMessage->serialNumber == SN) + { + *overflow = GT2False; + return GT2True; + } + + // check if we've already past the target SN + if(gti2SNDiff(bufferedMessage->serialNumber, SN) > 0) + break; + } + + // check that there's enough space to store the message + if(gti2GetBufferFreeSpace(&connection->incomingBuffer) < len) + { + *overflow = GT2True; + return GT2True; + } + + // setup the message info + messageInfo.start = connection->incomingBuffer.len; + messageInfo.len = len; + messageInfo.type = type; + messageInfo.serialNumber = SN; + + // add it to the list + ArrayInsertSorted(connection->incomingBufferMessages, &messageInfo, gti2IncomingBufferMessageCompare); + + // make sure the length is one more + if(ArrayLength(connection->incomingBufferMessages) != (num + 1)) + { + *overflow = GT2True; + return GT2True; + } + + // copy the message into the buffer + gti2BufferWriteData(&connection->incomingBuffer, message, len); + + // check for sending a nack + // we want to send one when we think a message or messages were probably dropped + if(num == 0) + { + // if we're the only message in the hold, send a nack + if(!gti2SendNack(connection, connection->expectedSerialNumber, (unsigned short)(SN - 1))) + return GT2False; + } + else + { + GTI2IncomingBufferMessage * msg; + + // are we the highest message? + msg = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, num); + if(msg->serialNumber == SN) + { + GTI2IncomingBufferMessage * prev; + unsigned short diff; + + // if we're not right after the second-highest SN, the ones in between were probably dropped + prev = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, num - 1); + diff = (unsigned short)gti2SNDiff(SN, prev->serialNumber); + if(diff > 1) + { + if(!gti2SendNack(connection, (unsigned short)(prev->serialNumber + 1), (unsigned short)(SN - 1))) + return GT2False; + } + } + } + + *overflow = GT2False; + return GT2True; +} + +static void gti2RemoveHoldMessage(GT2Connection connection, GTI2IncomingBufferMessage * message, int index) +{ + int moveAfter; + int shortenBy; + int moveEnd = 0; + int num; + int i; + + // save off info about it + moveAfter = message->start; + shortenBy = message->len; + + // delete it + ArrayDeleteAt(connection->incomingBufferMessages, index); + + // loop through and fix up message's stored after this one in the buffer + // also figure out exactly how much data we'll need to move + num = ArrayLength(connection->incomingBufferMessages); + for(i = 0 ; i < num ; i++) + { + // check if this message needs to be moved forward + message = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, i); + if(message->start > moveAfter) + { + message->start -= shortenBy; + moveEnd = max(moveEnd, message->start + message->len); + } + } + + // fix up the buffer itself + gti2BufferShorten(&connection->incomingBuffer, moveAfter, shortenBy); +} + +static GT2Bool gti2DeliverHoldMessages(GT2Connection connection) +{ + GTI2IncomingBufferMessage * message; + int num; + int i; + +restart: + + // loop through the buffered messages, checking if there are any that can now be delivered + // loop through backwards to ease removal + num = ArrayLength(connection->incomingBufferMessages); + for(i = (num - 1) ; i >= 0 ; i--) + { + message = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, i); + + // we should deliver this if it's what we're expecting + if(message->serialNumber == connection->expectedSerialNumber) + { + // deliver it + if(!gti2DeliverReliableMessage(connection, message->type, connection->incomingBuffer.buffer + message->start, message->len)) + return GT2False; + + // remove it + gti2RemoveHoldMessage(connection, message, i); + + // we need to go through this loop again. + // goto's are evil, but a little evil is good here + goto restart; + } + } + + return GT2True; +} + +static void gti2SetPendingAck(GT2Connection connection) +{ + // if there's not a pending ack, set one + if(!connection->pendingAck) + { + connection->pendingAck = GT2True; + connection->pendingAckTime = current_time(); + } +} + +static GT2Bool gti2HandleReliableMessage(GT2Connection connection, GTI2MessageType type, GT2Byte * message, int len) +{ + unsigned short SN; + unsigned short ESN; + const int headerLength = connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1 + 2 + 2; + GT2Bool overflow; + + // check if it's long enough + if(len < (connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1 + 2 + 2)) // magic string + type + SN + ESN + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // get the SN + SN = gti2UShortFromBuffer(message + connection->socket->protocolOffset, GTI2_MAGIC_STRING_LEN + 1); + + // get the ESN + ESN = gti2UShortFromBuffer(message + connection->socket->protocolOffset, GTI2_MAGIC_STRING_LEN + 3); + + // update the message and length to point to the actual message + if (connection->socket->protocolType == GTI2VdpProtocol && type == GTI2MsgAppReliable) + { + message[connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 3] = message[0]; + message[connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 4] = message[1]; + message += headerLength - connection->socket->protocolOffset; + len -= headerLength - connection->socket->protocolOffset; + } + else + { + message += headerLength; + len -= headerLength; + } + + // handle the ESN + if(!gti2HandleESN(connection, ESN)) + return GT2False; + + // check if it's the SN we expected + if(SN == connection->expectedSerialNumber) + { + // make sure we ack this message + // do this before delivering, because we might send an ack as part of a reliable reply + gti2SetPendingAck(connection); + + // deliver the message + if(!gti2DeliverReliableMessage(connection, type, message, len)) + return GT2False; + + // check if there are any messages in the hold that can now be delivered + if(!gti2DeliverHoldMessages(connection)) + return GT2False; + + return GT2True; + } + + // check if the message is a duplicate + if(gti2SNDiff(SN, connection->expectedSerialNumber) < 0) + { + // it's a duplicate, ack it again + gti2SetPendingAck(connection); + + // ignore it + return GT2True; + } + + // we can't deliver this yet, so put it in the hold + if(!gti2BufferIncomingMessage(connection, type, SN, message, len, &overflow)) + return GT2False; + + // check for a buffer overflow + if(overflow) + { + if(!gti2ConnectionMemoryError(connection)) + return GT2False; + } + + return GT2True; +} + +static GT2Bool gti2HandleAck(GT2Connection connection, const GT2Byte * message, int len) +{ + unsigned short ESN; + + // make sure it has enough space for the ESN + if(len != 2) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // get the ESN + ESN = gti2UShortFromBuffer(message, 0); + + // handle it + if(!gti2HandleESN(connection, ESN)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleNack(GT2Connection connection, const GT2Byte * message, int len) +{ + unsigned short SNMin; + unsigned short SNMax; + int num; + int i; + GTI2OutgoingBufferMessage * messageInfo; + + // read based on length. + SNMin = gti2UShortFromBuffer(message, 0); + if(len == 2) + { + SNMax = SNMin; + } + else if(len == 4) + { + SNMax = gti2UShortFromBuffer(message, 2); + } + else + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + } + + // loop through the messages, resending any specified ones + num = ArrayLength(connection->outgoingBufferMessages); + for(i = 0 ; i < num ; i++) + { + messageInfo = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i); + if((gti2SNDiff(messageInfo->serialNumber, SNMin) >= 0) && (gti2SNDiff(messageInfo->serialNumber, SNMax) <= 0)) + { + if(!gti2ResendMessage(connection, messageInfo)) + return GT2False; + } + } + + return GT2True; +} + +static GT2Bool gti2HandlePing(GT2Connection connection, GT2Byte * message, int len) +{ + // send it right back + return gti2SendPong(connection, message, len); +} + +static GT2Bool gti2HandlePong(GT2Connection connection, const GT2Byte * message, int len) +{ + gsi_time startTime; + + // do we care about this? + if(!connection->callbacks.ping) + return GT2True; + + // is this a pong we're interested in? + // "time" + ping-sent-time + if(len != (4 + sizeof(gsi_time))) + return GT2True; + if(memcmp(message, "time", 4) != 0) + return GT2True; + + // get the start time + memcpy(&startTime, message + 4, sizeof(gsi_time)); + + // call the callback + if(!gti2PingCallback(connection, (int)(current_time() - startTime))) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleClosed(GT2Connection connection) +{ + GT2Bool localClose; + + // are we already closed? + if(connection->state == GTI2Closed) + return GT2True; + + // were we attempting to close this connection? + localClose = (connection->state == GTI2Closing); + + // handle it as an error (so the right callbacks are called) + if(!gti2ConnectionError(connection, GT2Rejected, localClose?GT2LocalClose:GT2RemoteClose)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2HandleUnreliableMessage(GT2Connection connection, GTI2MessageType type, GT2Byte * message, int len) +{ + int headerLength; + GT2Byte * dataStart; + int dataLen; + + // most unreliable messages don't need the header + headerLength = (connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1); + dataStart = (message + headerLength); + dataLen = (len - headerLength); + + // handle unreliable messages based on type + if(type == GTI2MsgAck) + { + if(!gti2HandleAck(connection, dataStart, dataLen)) + return GT2False; + } + else if(type == GTI2MsgNack) + { + if(!gti2HandleNack(connection, dataStart, dataLen)) + return GT2False; + } + else if(type == GTI2MsgPing) + { + if(!gti2HandlePing(connection, message, len)) + return GT2False; + } + else if(type == GTI2MsgPong) + { + if(!gti2HandlePong(connection, dataStart, dataLen)) + return GT2False; + } + else if(type == GTI2MsgClosed) + { + if(!gti2HandleClosed(connection)) + return GT2False; + } + + return GT2True; +} + +// VDP sockets have data length which needs to be stripped off +static GT2Bool gti2HandleMessage(GT2Socket socket, GT2Byte * message, int len, unsigned int ip, unsigned short port) +{ + GT2Connection connection; + GT2Bool magicString; + GT2Result result; + GTI2MessageType type; + GT2Bool handled; + int actualLength = len - socket->protocolOffset; + + // VDP messages have 2 byte header which is removed based on protocol + GT2Byte *actualMessage = message + socket->protocolOffset; + + // find out if we have an existing connection for this address + connection = gti2SocketFindConnection(socket, ip, port); + + // let the dump handle this + if(socket->receiveDumpCallback) + { + if(!gti2DumpCallback(socket, connection, ip, port, GT2False, message, len, GT2False)) + return GT2False; + } + + // check if the message starts with the magic string + // use greater than for the len compare because it also must have a type + magicString = ((actualLength > GTI2_MAGIC_STRING_LEN) && (memcmp(actualMessage, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN) == 0)); + + // check if we don't have a connection + if(!connection) + { + // if we don't know who this is from, let the unrecognized message callback have first crack at it + if(!gti2UnrecognizedMessageCallback(socket, ip, port, message, len, &handled)) + return GT2False; + + // if they handled it, we don't care about it. + if(handled) + return GT2True; + + // if this isn't a connection request, tell them the connection is closed + if(!magicString || (actualMessage[GTI2_MAGIC_STRING_LEN] != GTI2MsgClientChallenge)) + { + // if this is a closed message, don't send one back (to avoid recursion) + if(!magicString || (actualMessage[GTI2_MAGIC_STRING_LEN] != GTI2MsgClosed)) + { + if(!gti2SendClosedOnSocket(socket, ip, port)) + return GT2False; + } + return GT2True; + } + + // if we're not listening, we just ignore this + if(!socket->connectAttemptCallback) + return GT2True; + + // create a connection + result = gti2NewIncomingConnection(socket, &connection, ip, port); + if(result != GT2Success) + { + // as long as this wasn't a duplicate address error, tell them we're closed + // in the case of duplicates, we don't want to close the existing connection + if(result != GT2DuplicateAddress) + { + if(!gti2SendClosedOnSocket(socket, ip, port)) + return GT2False; + } + return GT2True; + } + } + + // is the connection already closed? + if(connection->state == GTI2Closed) + { + // if this is a closed message, don't send one back (to avoid recursion) + if(!magicString || (actualMessage[GTI2_MAGIC_STRING_LEN] != GTI2MsgClosed)) + { + if(!gti2SendClosed(connection)) + return GT2False; + } + + return GT2True; + } + + // check if this is an unreliable app message with a magic string header + if(magicString && ((actualLength >= (GTI2_MAGIC_STRING_LEN * 2)) && (memcmp(actualMessage + GTI2_MAGIC_STRING_LEN, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN) == 0))) + { + message[3] = message[1]; + message[2] = message[0]; + message = actualMessage; + actualMessage += socket->protocolOffset; + actualLength -= socket->protocolOffset; + len -= GTI2_MAGIC_STRING_LEN; + magicString = GT2False; + } + + // if it doesn't have a magic string it's an app unreliable + if(!magicString) + { + // First determine if the connection found has gone throught the internal challenge response + if (connection->state < GTI2Connected) + { + // pass any message that doesn't have a magic string to + // the app so that the SDK doesn't drop them + if(!gti2UnrecognizedMessageCallback(socket, ip, port, message, len, &handled)) + return GT2False; + } + else + { + if(!gti2HandleAppUnreliable(connection, message, len)) + return GT2False; + } + + return GT2True; + } + + // get the message type + type = (GTI2MessageType)actualMessage[GTI2_MAGIC_STRING_LEN]; + // check for a bad type + /*if(type < 0) + { + if(!gti2ConnectionCommunicationError(connection)) + return GT2False; + + return GT2True; + }*/ + + + // check if it's reliable + if(type < GTI2NumReliableMessages) + { + // handle it + if(!gti2HandleReliableMessage(connection, type, message, len)) + return GT2False; + return GT2True; + } + + // handle unreliable messages + if(!gti2HandleUnreliableMessage(connection, type, message, len)) + return GT2False; + + return GT2True; +} + + +GT2Bool gti2HandleConnectionReset(GT2Socket socket, unsigned int ip, unsigned short port) +{ + GT2Connection connection; + + // find the connection for the reset + connection = gti2SocketFindConnection(socket, ip, port); + + // let the dump know about this + if(socket->receiveDumpCallback) + { + if(!gti2DumpCallback(socket, connection, ip, port, GT2True, NULL, 0, GT2False)) + return GT2False; + } + + // there's no connection, so ignore it + if(!connection) + return GT2True; + + // are we waiting for a response from the server? + if(connection->state == GTI2AwaitingServerChallenge) + { + // are we still within the timeout time? + if(!connection->timeout || ((current_time() - connection->startTime) < connection->timeout)) + return GT2True; + + // report this as a timeout + if(!gti2ConnectionError(connection, GT2TimedOut, GT2RemoteClose)) + return GT2False; + } + else + { + // report the error + if(!gti2ConnectionError(connection, GT2Rejected, GT2RemoteClose)) + return GT2False; + } + + return GT2True; +} + +GT2Bool gti2HandleHostUnreachable(GT2Socket socket, unsigned int ip, unsigned short port, GT2Bool send) +{ + GT2Connection connection; + + // find the connection for the reset + connection = gti2SocketFindConnection(socket, ip, port); + + // let the dump know about this + if(socket->receiveDumpCallback) + { + if(!gti2DumpCallback(socket, connection, ip, port, GT2True, NULL, 0, send)) + return GT2False; + } + + // there's no connection, so ignore it + if(!connection) + return GT2True; + + + // report the error + if(!gti2ConnectionError(connection, GT2TimedOut, GT2RemoteClose)) + return GT2False; + + return GT2True; +} + + +#ifdef GSI_ADHOC + + + +// return length if successful +// <=0 on error +gsi_bool _NetworkAdHocSocketRecv(int socket_id, + char *buf, + int bufferlen, + int flags, + char *saddr, //struct SceNetEtherAddr = char[6]; + gsi_u16 *sport); + + + + + + + + +// return 0 if no data, -1 if error, >0 if data to read +int _NetworkAdHocCanReceiveOnSocket(int socket_id); + +GT2Bool gti2ReceiveAdHocMessages(GT2Socket socket,char *buffer, int buffersize) +{ + int rcode; + SOCKADDR_IN address; + int addressLen;//, datasize; + + // check for messages + while (1) + { + int datasize = _NetworkAdHocCanReceiveOnSocket(socket->socket); + if (datasize < 0) // error + { + gti2SocketError(socket); + return GT2False; + } + + if (datasize == 0) + break; // no data + { + // We have data to recv + // receive the message + char mac[6]; + gsi_u16 port; + //gsi_u32 ip; + + addressLen = sizeof(address); + + rcode = _NetworkAdHocSocketRecv(socket->socket, buffer,buffersize , 0, mac,&port); + if(rcode < 0) // fatal socket error + { + #if(0) // notes + if(0)//rcode == WSAECONNRESET) + { + // handle the reset + if(!gti2HandleConnectionReset(socket, address.sin_addr.s_addr, ntohs(address.sin_port))) + return GT2False; + } + else + if (rcode == WSAEHOSTUNREACH) + { + if (!gti2HandleHostUnreachable(socket, address.sin_addr.s_addr, ntohs(address.sin_port), GT2False)) + return GT2False; + } + else + #endif + { + gti2SocketError(socket); + return GT2False; + } + } + if(rcode == 0) // no data + { + return GT2False; + } + + // at this point we have valid data + + // change ethernet to IP address + address.sin_addr.s_addr = gt2MacToIp(mac); + address.sin_port = port; + + #ifdef RECV_LOG + // log it + gti2LogMessage(address.sin_addr.s_addr, ntohs(address.sin_port), + socket->ip, socket->port, + buffer, rcode); + #endif + // handle the message + if(!gti2HandleMessage(socket, (GT2Byte *)buffer, rcode, address.sin_addr.s_addr, address.sin_port)) + return GT2False; + } + } + + return GT2True; +} +#endif + +GT2Bool gti2ReceiveMessages(GT2Socket socket) +{ + int rcode; + SOCKADDR_IN address; + int addressLen; + + + // avoid overflowing stack + #if (GTI2_STACK_RECV_BUFFER_SIZE > 1600) + static char buffer[GTI2_STACK_RECV_BUFFER_SIZE]; + #else + char buffer[GTI2_STACK_RECV_BUFFER_SIZE]; + #endif + + + #ifdef GSI_ADHOC + if(socket->protocolType == GTI2AdHocProtocol) + { + return gti2ReceiveAdHocMessages(socket,buffer,GTI2_STACK_RECV_BUFFER_SIZE); + } + #endif + + // check for messages + while (CanReceiveOnSocket(socket->socket)) + { + // mj todo: get this plat specific stuff out of here. Belongs in play specific layer. + // abstract recvfrom + + // receive the message + addressLen = sizeof(address); + + rcode = recvfrom(socket->socket, buffer, sizeof(buffer), 0, (SOCKADDR *)&address, &addressLen); + + if (gsiSocketIsError(rcode)) + { + rcode = GOAGetLastError(socket->socket); + if(rcode == WSAECONNRESET) + { + // handle the reset + if(!gti2HandleConnectionReset(socket, address.sin_addr.s_addr, ntohs(address.sin_port))) + return GT2False; + } + #ifndef SN_SYSTEMS + else if (rcode == WSAEHOSTUNREACH) + { + if (!gti2HandleHostUnreachable(socket, address.sin_addr.s_addr, ntohs(address.sin_port), GT2False)) + return GT2False; + } + #endif + else if(rcode != WSAEMSGSIZE) + { + // fatal socket error + gti2SocketError(socket); + return GT2False; + } + } + else + { + #ifdef RECV_LOG + // log it + gti2LogMessage(address.sin_addr.s_addr, ntohs(address.sin_port), + socket->ip, socket->port, + buffer, rcode); + #endif + // handle the message + if(!gti2HandleMessage(socket, (GT2Byte *)buffer, rcode, address.sin_addr.s_addr, ntohs(address.sin_port))) + return GT2False; + } + } + + return GT2True; +} + +static GT2Bool gti2StoreOutgoingReliableMessageInfo(GT2Connection connection, unsigned short SN, int len) +{ + GTI2OutgoingBufferMessage messageInfo; + int num; + + // setup the message info + memset(&messageInfo, 0, sizeof(messageInfo)); + messageInfo.start = connection->outgoingBuffer.len; + messageInfo.len = len; + messageInfo.serialNumber = SN; + messageInfo.lastSend = current_time(); + + // check the number of messages before we do the add + num = ArrayLength(connection->outgoingBufferMessages); + + // add it to the list + ArrayAppend(connection->outgoingBufferMessages, &messageInfo); + + // make sure the length is one more + if(ArrayLength(connection->outgoingBufferMessages) != (num + 1)) + return GT2False; + + return GT2True; +} + +static GT2Bool gti2BeginReliableMessage(GT2Connection connection, GTI2MessageType type, int len, GT2Bool * overflow) +{ + int freeSpace; + + // VDP data length needed in the front of every packet + unsigned short vdpDataLength = (unsigned short)(len - connection->socket->protocolOffset); + + // check how much free space is in the outgoing buffer + freeSpace = gti2GetBufferFreeSpace(&connection->outgoingBuffer); + + // do we have the space to hold it? + if(freeSpace < len) + { + if(!gti2ConnectionMemoryError(connection)) + return GT2False; + + *overflow = GT2True; + return GT2True; + } + + // store the message's info + if(!gti2StoreOutgoingReliableMessageInfo(connection, connection->serialNumber, len)) + { + if(!gti2ConnectionMemoryError(connection)) + return GT2False; + + *overflow = GT2True; + return GT2True; + } + + // setup the header + if (connection->socket->protocolType == GTI2VdpProtocol) + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)&vdpDataLength, connection->socket->protocolOffset); + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN); + gti2BufferWriteByte(&connection->outgoingBuffer, (GT2Byte)type); + gti2BufferWriteUShort(&connection->outgoingBuffer, connection->serialNumber++); + gti2BufferWriteUShort(&connection->outgoingBuffer, connection->expectedSerialNumber); + + *overflow = GT2False; + return GT2True; +} + +static GT2Bool gti2EndReliableMessage(GT2Connection connection) +{ + GTI2OutgoingBufferMessage * message; + int len; + + // the message we're sending is the last one + len = ArrayLength(connection->outgoingBufferMessages); + assert(len > 0); + message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, len - 1); + + // send it + if(!gti2ConnectionSendData(connection, connection->outgoingBuffer.buffer + message->start, message->len)) + return GT2False; + + // we just did an ack (as part of the message) + connection->pendingAck = GT2False; + + return GT2True; +} + +GT2Bool gti2SendAppReliable(GT2Connection connection, const GT2Byte * message, int len) +{ + int totalLen; + GT2Bool overflow; + + // magic string + type + SN + ESN + message + totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + len); + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgAppReliable, totalLen, &overflow)) + return GT2False; + if(overflow) + return GT2True; + + // write the message + gti2BufferWriteData(&connection->outgoingBuffer, message, len); + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendClientChallenge(GT2Connection connection, const char challenge[GTI2_CHALLENGE_LEN]) +{ + // magic string + type + SN + ESN + challenge + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + GTI2_CHALLENGE_LEN); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgClientChallenge, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // write the challenge + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)challenge, GTI2_CHALLENGE_LEN); + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendServerChallenge(GT2Connection connection, const char response[GTI2_RESPONSE_LEN], const char challenge[GTI2_CHALLENGE_LEN]) +{ + // magic string + type + SN + ESN + response + challenge + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + GTI2_RESPONSE_LEN + GTI2_CHALLENGE_LEN); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgServerChallenge, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // write the response + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)response, GTI2_RESPONSE_LEN); + + // write the challenge + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)challenge, GTI2_CHALLENGE_LEN); + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + // save the time + connection->challengeTime = connection->lastSend; + + return GT2True; +} + +GT2Bool gti2SendClientResponse(GT2Connection connection, const char response[GTI2_RESPONSE_LEN], const char * message, int len) +{ + // magic string + type + SN + ESN + response + message + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + GTI2_RESPONSE_LEN + len); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgClientResponse, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // write the response + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)response, GTI2_RESPONSE_LEN); + + // write the message + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)message, len); + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendAccept(GT2Connection connection) +{ + // magic string + type + SN + ESN + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgAccept, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendReject(GT2Connection connection, const GT2Byte * message, int len) +{ + // magic string + type + SN + ESN + message + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + len); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgReject, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // write the message + gti2BufferWriteData(&connection->outgoingBuffer, message, len); + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendClose(GT2Connection connection) +{ + // magic string + type + SN + ESN + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgClose, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendKeepAlive(GT2Connection connection) +{ + // magic string + type + SN + ESN + int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2); + GT2Bool overflow; + + // begin the message + if(!gti2BeginReliableMessage(connection, GTI2MsgKeepAlive, totalLen + connection->socket->protocolOffset, &overflow)) + return GT2False; + + if(overflow) + return GT2True; + + // end the message + if(!gti2EndReliableMessage(connection)) + return GT2False; + + return GT2True; +} + +GT2Bool gti2SendAppUnreliable(GT2Connection connection, const GT2Byte * message, int len) +{ + int freeSpace; + int totalLen; + GT2Byte * start; + + // check if we can send it right away (unreliable that doesn't start with the magic string) + if((len < GTI2_MAGIC_STRING_LEN) || + (memcmp(message + connection->socket->protocolOffset, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN) != 0)) + { + if(!gti2ConnectionSendData(connection, message, len)) + return GT2False; + + return GT2True; + } + + // magic string + message + totalLen = (GTI2_MAGIC_STRING_LEN + len); + + // check how much free space is in the outgoing buffer + freeSpace = gti2GetBufferFreeSpace(&connection->outgoingBuffer); + + // do we have the space to hold it? + if(freeSpace < totalLen) + { + // just drop it + return GT2True; + } + + // store the start of the actual message in the buffer + start = (connection->outgoingBuffer.buffer + connection->outgoingBuffer.len); + + // Copy the VDP data length if necessary + if (connection->socket->protocolType == GTI2VdpProtocol) + gti2BufferWriteData(&connection->outgoingBuffer, message, 2); + + // copy it in, repeating the magic string at the beginning + gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN); + + // copy the data at the starting position + offset based on the protocol + gti2BufferWriteData(&connection->outgoingBuffer, message + connection->socket->protocolOffset, + (int)(len - connection->socket->protocolOffset)); + + // do the send + if(!gti2ConnectionSendData(connection, start, totalLen)) + return GT2False; + + // we don't need to save the message + gti2BufferShorten(&connection->outgoingBuffer, -1, totalLen); + + return GT2True; +} + +GT2Bool gti2SendAck(GT2Connection connection) +{ + // always allocate data length + magic string + type + ESN + // part of the buffer may not be used but more efficience to be on stack + char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1 + 2]; + int pos = 0; + + // write the VDP data length + if (connection->socket->protocolType == GTI2VdpProtocol) + { + short dataLength = (GTI2_MAGIC_STRING_LEN + 1 + 2); + memcpy(buffer, &dataLength, 2); + pos += 2; + } + + // write the magic string + memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN); + pos += GTI2_MAGIC_STRING_LEN; + + // write the type + buffer[pos++] = GTI2MsgAck; + + // write the ESN + gti2UShortToBuffer((GT2Byte *)buffer, pos, connection->expectedSerialNumber); + pos += 2; + + // send it + if(!gti2ConnectionSendData(connection, (const GT2Byte *)buffer, pos)) + return GT2False; + + // we just did an ack + connection->pendingAck = GT2False; + + return GT2True; +} + + +GT2Bool gti2SendNack(GT2Connection connection, unsigned short SNMin, unsigned short SNMax) +{ + // data length + magic string + type + SNMin [+ SNMax] + // part of the buffer may not be used but more efficience to be on stack + char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1 + 2 + 2]; + int pos = 0; + + // write the VDP data length + if (connection->socket->protocolType == GTI2VdpProtocol) + { + short dataLength = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2); + memcpy(buffer, &dataLength, 2); + pos += 2; + } + + // write the magic string + memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN); + pos += GTI2_MAGIC_STRING_LEN; + + // write the type + buffer[pos++] = GTI2MsgNack; + + // write the SNMin + gti2UShortToBuffer((GT2Byte *)buffer, pos, SNMin); + pos += 2; + + // write the SNMax if it's different + if(SNMin != SNMax) + { + gti2UShortToBuffer((GT2Byte *)buffer, pos, SNMax); + pos += 2; + } + + // send it + if(!gti2ConnectionSendData(connection, (const GT2Byte *)buffer, pos)) + return GT2False; + + return GT2True; +} + + +GT2Bool gti2SendPing(GT2Connection connection) +{ + // data length + magic string + type + "time" + current time + // part of the buffer may not be used but more efficience to be on stack + char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1 + 4 + sizeof(gsi_time)]; + int pos = 0; + gsi_time now; + + // write the VDP data length + if (connection->socket->protocolType == GTI2VdpProtocol) + { + short dataLength = (GTI2_MAGIC_STRING_LEN + 1 + 4 + sizeof(gsi_time)); + memcpy(buffer, &dataLength, 2); + pos += 2; + } + // write the magic string + memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN); + pos += GTI2_MAGIC_STRING_LEN; + + // write the type + buffer[pos++] = GTI2MsgPing; + + // copy the time id + memcpy(buffer + pos, "time", 4); + pos += 4; + + // write the current time + now = current_time(); + memcpy(buffer + pos, &now, sizeof(gsi_time)); + + pos += (int)sizeof(gsi_time); + // send it + if(!gti2ConnectionSendData(connection, (const GT2Byte *)buffer, pos)) + return GT2False; + + return GT2True; +} + + +GT2Bool gti2SendPong(GT2Connection connection, GT2Byte * message, int len) +{ + // change the ping to a pong + message[GTI2_MAGIC_STRING_LEN] = GTI2MsgPong; + + // send it + return gti2ConnectionSendData(connection, message, len); +} + +GT2Bool gti2SendClosed(GT2Connection connection) +{ + // normal close + return gti2SendClosedOnSocket(connection->socket, connection->ip, connection->port); +} + + +GT2Bool gti2SendClosedOnSocket(GT2Socket socket, unsigned int ip, unsigned short port) +{ + // Vdp data length (not including voice) + magic string + type + // part of the buffer may not be used but more efficience to be on stack + char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1]; + int pos = 0; + + // write the data length + if (socket->protocolType == GTI2VdpProtocol) + { + short dataLength = GTI2_MAGIC_STRING_LEN + 1; + memcpy(buffer, &dataLength, 2); + pos += 2; + } + + // write the magic string + memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN); + pos += GTI2_MAGIC_STRING_LEN; + + // write the type + buffer[pos++] = GTI2MsgClosed; + + // send it + if(!gti2SocketSend(socket, ip, port, (const GT2Byte *)buffer, pos)) + return GT2False; + + return GT2True; +} + + +GT2Bool gti2ResendMessage(GT2Connection connection, GTI2OutgoingBufferMessage * message) +{ + GTI2MessageType type; + int pos; + + // replace the ESN (it's after the magic string, the type, and the SN) + pos = (message->start + connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1 + 2); + + gti2UShortToBuffer(connection->outgoingBuffer.buffer, pos, connection->expectedSerialNumber); + + // send the message + if(!gti2ConnectionSendData(connection, connection->outgoingBuffer.buffer + message->start, message->len)) + return GT2False; + + // update the last time sent + message->lastSend = connection->lastSend; + + // if it was a server challenge, update that time too + type = (GTI2MessageType)connection->outgoingBuffer.buffer[message->start + connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN]; + + if(type == GTI2MsgServerChallenge) + connection->challengeTime = connection->lastSend; + + return GT2True; +} + +GT2Bool gti2Send(GT2Connection connection, const GT2Byte * message, int len, GT2Bool reliable) +{ + if (reliable) + return gti2SendAppReliable(connection, message, len); + //send unreliable messages + return gti2SendAppUnreliable(connection, message, len); +} + +GT2Bool gti2WasMessageIDConfirmed(const GT2Connection connection, GT2MessageID messageID) +{ + GTI2OutgoingBufferMessage * message; + int len; + + // if there are no reliable messages waiting confirmation, then this has already been confirmed + len = ArrayLength(connection->outgoingBufferMessages); + if(!len) + return GT2True; + + // get the oldest message waiting confirmation + message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, 0); + + // if the message id we are looking for is older than the first one waiting confirmation, + // then it has already been confirmed + if(gti2SNDiff(messageID, message->serialNumber) < 0) + return GT2True; + + // the message hasn't been confirmed yet + return GT2False; +} diff --git a/xrGameSpy/gamespy/gt2/gt2Message.h b/xrGameSpy/gamespy/gt2/gt2Message.h new file mode 100644 index 00000000000..96336bb1bf0 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Message.h @@ -0,0 +1,42 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_MESSAGE_H_ +#define _GT2_MESSAGE_H_ + +#include "gt2Main.h" + +GT2Bool gti2ReceiveMessages(GT2Socket socket); + +GT2Bool gti2Send(GT2Connection connection, const GT2Byte * message, int len, GT2Bool reliable); + +GT2Bool gti2SendAppReliable(GT2Connection connection, const GT2Byte * message, int len); +GT2Bool gti2SendAppUnreliable(GT2Connection connection, const GT2Byte * message, int len); +GT2Bool gti2SendClientChallenge(GT2Connection connection, const char challenge[GTI2_CHALLENGE_LEN]); +GT2Bool gti2SendServerChallenge(GT2Connection connection, const char response[GTI2_RESPONSE_LEN], const char challenge[GTI2_CHALLENGE_LEN]); +GT2Bool gti2SendClientResponse(GT2Connection connection, const char response[GTI2_RESPONSE_LEN], const char * message, int len); +GT2Bool gti2SendAccept(GT2Connection connection); +GT2Bool gti2SendReject(GT2Connection connection, const GT2Byte * message, int len); +GT2Bool gti2SendClose(GT2Connection connection); +GT2Bool gti2SendKeepAlive(GT2Connection connection); +GT2Bool gti2SendAck(GT2Connection connection); +GT2Bool gti2SendNack(GT2Connection connection, unsigned short SNMin, unsigned short SNMax); +GT2Bool gti2SendPing(GT2Connection connection); +GT2Bool gti2SendPong(GT2Connection connection, GT2Byte * message, int len); +GT2Bool gti2SendClosed(GT2Connection connection); +GT2Bool gti2SendClosedOnSocket(GT2Socket socket, unsigned int ip, unsigned short port); + +GT2Bool gti2ResendMessage(GT2Connection connection, GTI2OutgoingBufferMessage * message); + +GT2Bool gti2HandleConnectionReset(GT2Socket socket, unsigned int ip, unsigned short port); +GT2Bool gti2HandleHostUnreachable(GT2Socket socket, unsigned int ip, unsigned short port, GT2Bool send); +GT2Bool gti2WasMessageIDConfirmed(const GT2Connection connection, GT2MessageID messageID); + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Socket.c b/xrGameSpy/gamespy/gt2/gt2Socket.c new file mode 100644 index 00000000000..31ef7d58eee --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Socket.c @@ -0,0 +1,528 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#include "gt2Socket.h" +#include "gt2Buffer.h" +#include "gt2Message.h" +#include "gt2Connection.h" +#include "gt2Utility.h" +#include "gt2Callback.h" +#include + +#ifdef GSI_ADHOC +// External functions defined at the platform specific level +// to be moved to nonport or socket.h +extern int _NetworkAdHocSocketCreate(gsi_u16 port); +extern void _NetworkAdHocSocketDestroy ( int adhoc_socket); +extern int _NetworkAdHocSocketSendTo ( int adhoc_socket, + const void *data, + int len, + int flags, + const char *dest_addr, + gsi_u16 dest_port + ); +extern void NetAdhocMacGet(char *mac); +#endif + +#define GTI2_DEFAULT_INCOMING_BUFFER_SIZE (64 * 1024) +#define GTI2_DEFAULT_OUTGOING_BUFFER_SIZE (64 * 1024) + +#define STARTING_SERIAL_NUMBER 0 + +static int gti2ConnectionHash(const void * elem, int numBuckets) +{ + GT2Connection connection = *(GT2Connection *)elem; + + return (int)(((connection->ip * connection->port)) % numBuckets); +} + +static int GS_STATIC_CALLBACK gti2ConnectionCompare(const void * elem1, const void * elem2) +{ + GT2Connection connection1 = *(GT2Connection *)elem1; + GT2Connection connection2 = *(GT2Connection *)elem2; + + if(connection1->ip != connection2->ip) + return (int)(connection1->ip - connection2->ip); + + return (int)(short)(connection1->port - connection2->port); +} + +static void gti2ConnectionFree(void * elem) +{ + gti2ConnectionCleanup(*(GT2Connection *)elem); +} + +GT2Connection gti2SocketFindConnection(GT2Socket socket, unsigned int ip, unsigned short port) +{ + GTI2Connection connection; + GT2Connection connectionPtr; + GT2Connection * connectionPtrPtr; + + connection.ip = ip; + connection.port = port; + + connectionPtr = &connection; + connectionPtrPtr = (GT2Connection *)TableLookup(socket->connections, &connectionPtr); + if(connectionPtrPtr) + return *connectionPtrPtr; + + return NULL; +} + +GT2Result gti2CreateSocket +( + GT2Socket * sock, + const char * localAddress, + int outgoingBufferSize, + int incomingBufferSize, + gt2SocketErrorCallback callback, + GTI2ProtocolType type +) +{ + SOCKADDR_IN address; + GT2Socket socketTemp; + int rcode; + unsigned int ip; + unsigned short port; + int len; + + // startup the sockets engine if needed + SocketStartUp(); + + // check for using defaults + if(!incomingBufferSize) + incomingBufferSize = GTI2_DEFAULT_INCOMING_BUFFER_SIZE; + if(!outgoingBufferSize) + outgoingBufferSize = GTI2_DEFAULT_OUTGOING_BUFFER_SIZE; + + // convert the address to an IP and port + if(!gt2StringToAddress(localAddress, &ip, &port)) + return GT2AddressError; + + // allocate the object + socketTemp = (GT2Socket)gsimalloc(sizeof(GTI2Socket)); + if(!socketTemp) + return GT2OutOfMemory; + + // set initial values + memset(socketTemp, 0, sizeof(GTI2Socket)); + socketTemp->socket = INVALID_SOCKET; + socketTemp->incomingBufferSize = incomingBufferSize; + socketTemp->outgoingBufferSize = outgoingBufferSize; + socketTemp->socketErrorCallback = callback; + + // create the connections table + socketTemp->connections = TableNew2(sizeof(GT2Connection), 32, 2, gti2ConnectionHash, gti2ConnectionCompare, NULL); + if(!socketTemp->connections) + { + gsifree(socketTemp); + return GT2OutOfMemory; + } + + // create the closed connections list + socketTemp->closedConnections = ArrayNew(sizeof(GT2Connection), 4, gti2ConnectionFree); + if(!socketTemp->closedConnections) + { + TableFree(socketTemp->connections); + gsifree(socketTemp); + return GT2OutOfMemory; + } + + // create the socket + +#ifdef _XBOX + if (type == GTI2VdpProtocol) + + socketTemp->socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_VDP); + else +#endif +#ifdef GSI_ADHOC + if (type == GTI2AdHocProtocol) + { + socketTemp->socket = _NetworkAdHocSocketCreate( port); + } + else +#endif + socketTemp->socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + socketTemp->protocolType = type; + + if (type == GTI2AdHocProtocol) + { + socketTemp->protocolOffset = 0; + } + else + socketTemp->protocolOffset = type; + +#ifdef _XBOX + if (type == GTI2UdpProtocol) + { + SetSockBroadcast(socketTemp->socket); + socketTemp->protocolOffset = type; + } +#endif + + if(socketTemp->socket == INVALID_SOCKET) + { + TableFree(socketTemp->connections); + ArrayFree(socketTemp->closedConnections); + gsifree(socketTemp); + return GT2NetworkError; + } + + // bind it + memset(&address, 0, sizeof(SOCKADDR_IN)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = ip; + address.sin_port = htons(port); + if (type != GTI2AdHocProtocol) + { + rcode = bind(socketTemp->socket, (SOCKADDR *)&address, sizeof(SOCKADDR_IN)); + if (gsiSocketIsError(rcode)) + { + closesocket(socketTemp->socket); + TableFree(socketTemp->connections); + ArrayFree(socketTemp->closedConnections); + gsifree(socketTemp); + return GT2NetworkError; + } + } + + // get the ip and port we're bound to + #ifdef GSI_ADHOC + if (type == GTI2AdHocProtocol) + { + char mac[6]; + NetAdhocMacGet(mac); + + socketTemp->ip = gt2MacToIp(mac); + socketTemp->port = ntohs(address.sin_port); + } + else + #endif + { + len = sizeof(SOCKADDR_IN); + getsockname(socketTemp->socket, (SOCKADDR *)&address, &len); + socketTemp->ip = address.sin_addr.s_addr; + socketTemp->port = ntohs(address.sin_port); + } + + *sock = socketTemp; + + return GT2Success; +} + +void gti2CloseSocket(GT2Socket socket) +{ + + if(socket->callbackLevel) + { + socket->close = GT2True; + return; + } + +#ifdef GSI_ADHOC + if (socket->protocolType == GTI2AdHocProtocol) + { + _NetworkAdHocSocketDestroy(socket->socket); + } + else +#endif + { + closesocket(socket->socket); + } + + TableFree(socket->connections); + ArrayFree(socket->closedConnections); + gsifree(socket); + + SocketShutDown(); +} + +void gti2Listen(GT2Socket socket, gt2ConnectAttemptCallback callback) +{ + socket->connectAttemptCallback = callback; +} + +static GT2Connection gti2CreateConnectionObject(void) +{ + // mj todo: give options of allocating this from a static pool for games with known number of connections. + return (GT2Connection)gsimalloc(sizeof(GTI2Connection)); +} + +GT2Result gti2NewSocketConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port) +{ + GT2Connection connectionPtr = NULL; + + // check if this ip and port already exists + if(gti2SocketFindConnection(socket, ip, port)) + return GT2DuplicateAddress; + + // allocate a connection object + connectionPtr = gti2CreateConnectionObject(); + if(!connectionPtr) + goto out_of_memory; + + // set some basics + memset(connectionPtr, 0, sizeof(GTI2Connection)); + connectionPtr->ip = ip; + connectionPtr->port = port; + connectionPtr->socket = socket; + connectionPtr->startTime = current_time(); + connectionPtr->lastSend = connectionPtr->startTime; + connectionPtr->serialNumber = STARTING_SERIAL_NUMBER; + connectionPtr->expectedSerialNumber = STARTING_SERIAL_NUMBER; + + // allocate the buffers + if(!gti2AllocateBuffer(&connectionPtr->incomingBuffer, socket->incomingBufferSize)) + goto out_of_memory; + if(!gti2AllocateBuffer(&connectionPtr->outgoingBuffer, socket->outgoingBufferSize)) + goto out_of_memory; + + // allocate the message arrays + connectionPtr->incomingBufferMessages = ArrayNew(sizeof(GTI2IncomingBufferMessage), 64, NULL); + if(!connectionPtr->incomingBufferMessages) + goto out_of_memory; + connectionPtr->outgoingBufferMessages = ArrayNew(sizeof(GTI2OutgoingBufferMessage), 64, NULL); + if(!connectionPtr->outgoingBufferMessages) + goto out_of_memory; + + // allocate the filter arrays + connectionPtr->sendFilters = ArrayNew(sizeof(gt2SendFilterCallback), 2, NULL); + if(!connectionPtr->sendFilters) + goto out_of_memory; + connectionPtr->receiveFilters = ArrayNew(sizeof(gt2ReceiveFilterCallback), 2, NULL); + if(!connectionPtr->receiveFilters) + goto out_of_memory; + + // add it to the table + TableEnter(socket->connections, &connectionPtr); + + // check that it's in the table (and get the address) + *connection = gti2SocketFindConnection(socket, ip, port); + if(!*connection) + goto out_of_memory; + + return GT2Success; + +out_of_memory: + + // there wasn't enough memory, free everything and return the error + if(connectionPtr) + { + gsifree(connectionPtr->incomingBuffer.buffer); + gsifree(connectionPtr->outgoingBuffer.buffer); + if(connectionPtr->incomingBufferMessages) + ArrayFree(connectionPtr->incomingBufferMessages); + if(connectionPtr->outgoingBufferMessages) + ArrayFree(connectionPtr->outgoingBufferMessages); + if(connectionPtr->sendFilters) + ArrayFree(connectionPtr->sendFilters); + if(connectionPtr->receiveFilters) + ArrayFree(connectionPtr->receiveFilters); + gsifree(connectionPtr); + } + + return GT2OutOfMemory; +} + +void gti2FreeSocketConnection(GT2Connection connection) +{ + // check if we can actually free it + if(connection->freeAtAcceptReject || connection->callbackLevel) + return; + + // remove it from the correct list depending on the connect state + if(connection->state == GTI2Closed) + { + int len; + int i; + + len = ArrayLength(connection->socket->closedConnections); + for(i = 0 ; i < len ; i++) + { + if(connection == *(GT2Connection *)ArrayNth(connection->socket->closedConnections, i)) + { + ArrayDeleteAt(connection->socket->closedConnections, i); + return; + } + } + } + else + { + TableRemove(connection->socket->connections, &connection); + } +} + +GT2Bool gti2SocketSend(GT2Socket socket, unsigned int ip, unsigned short port, const GT2Byte * message, int len) +{ + SOCKADDR_IN address; + int rcode; + +#ifdef GTI2_DROP_SEND_RATE + // drop some percentage of packets and see what happens + if((rand() % 100) < GTI2_DROP_SEND_RATE) + return GT2True; +#endif + + // check the message and len + gti2MessageCheck(&message, &len); + + if (socket->protocolType != GTI2AdHocProtocol) + { + #ifndef INSOCK // insock never sets write flag for UDP sockets + // check if we can't send + if(!CanSendOnSocket(socket->socket)) + return GT2True; + #endif + } + + // do the send + #ifdef GSI_ADHOC + if (socket->protocolType == GTI2AdHocProtocol) + { + char mac[6]; + // convert to mac + gt2IpToMac(ip,mac); + // change IP address to mac ethernet + rcode = _NetworkAdHocSocketSendTo(socket->socket, (const char *)message, len, 0, mac, port); + if(rcode <0) + { + gti2SocketError(socket); + return gsi_false; + } + + // let the dump handle this + if(socket->sendDumpCallback) + { + if(!gti2DumpCallback(socket, gti2SocketFindConnection(socket, ip, port), ip, port, GT2False, message, len, GT2True)) + return GT2False; + } + return gsi_true; + } + + #endif + + // fill the address structure + memset(&address, 0, sizeof(SOCKADDR_IN)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = ip; + address.sin_port = htons(port); + rcode = sendto(socket->socket, (const char *)message, len, 0, (SOCKADDR *)&address, sizeof(SOCKADDR_IN)); + if (gsiSocketIsError(rcode)) + { + rcode = GOAGetLastError(socket->socket); + if(rcode == WSAECONNRESET) + { + // handle the reset + if(!gti2HandleConnectionReset(socket, ip, port)) + return GT2False; + } +#ifndef SN_SYSTEMS + else if (rcode == WSAEHOSTUNREACH) + { + if (!gti2HandleHostUnreachable(socket, ip, port, GT2True)) + return GT2False; + } +#endif + // some systems might return these errors + else if((rcode == WSAENOBUFS) || (rcode == WSAEWOULDBLOCK)) + { + return GT2True; + } +#if defined(SN_SYSTEMS) || defined(_NITRO) || defined(_REVOLUTION) + // for systems that don't support WSAEHOSTDOWN (EHOSTDOWN) + else if((rcode != WSAEMSGSIZE)) +#else + else if((rcode != WSAEMSGSIZE) && (rcode != WSAEHOSTDOWN)) +#endif + { + // fatal socket error + gti2SocketError(socket); + return GT2False; + } + } + else + { + // let the dump handle this + if(socket->sendDumpCallback) + { + if(!gti2DumpCallback(socket, gti2SocketFindConnection(socket, ip, port), ip, port, GT2False, message, len, GT2True)) + return GT2False; + } + } + + return GT2True; +} + +static int gti2SocketConnectionsThinkMap(void * elem, void * clientData) +{ + GT2Connection connection = *(GT2Connection *)elem; + gsi_time now = *(gsi_time *)clientData; + + // only think if we're not closed + if(connection->state != GTI2Closed) + { + // think + if(!gti2ConnectionThink(connection, now)) + return 0; + } + + // check for a closed connection + if((connection->state == GTI2Closed) && !connection->freeAtAcceptReject && !connection->callbackLevel) + gti2FreeSocketConnection(connection); + + return 1; +} + +GT2Bool gti2SocketConnectionsThink(GT2Socket socket) +{ + gsi_time now; + + // get the current time + now = current_time(); + + // go through the list of connections and let them think + if(TableMapSafe2(socket->connections, gti2SocketConnectionsThinkMap, &now)) + return GT2False; + + return GT2True; +} + +void gti2FreeClosedConnections(GT2Socket socket) +{ + int i; + int len; + + // loop through the closed connections, attempting to free them all + len = ArrayLength(socket->closedConnections); + for(i = (len - 1) ; i >= 0 ; i--) + gti2FreeSocketConnection(*(GT2Connection *)ArrayNth(socket->closedConnections, i)); +} + +void gti2SocketError(GT2Socket socket) +{ + // if there was already an error, don't go through this again + if(socket->error) + return; + + // flag the error + socket->error = GT2True; + + // first close all the socket's connections + gt2CloseAllConnectionsHard(socket); + + // call the error callback + if(!gti2SocketErrorCallback(socket)) + return; + + // close the socket + gti2CloseSocket(socket); +} diff --git a/xrGameSpy/gamespy/gt2/gt2Socket.h b/xrGameSpy/gamespy/gt2/gt2Socket.h new file mode 100644 index 00000000000..5975945e5d0 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Socket.h @@ -0,0 +1,45 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_SOCKET_H_ +#define _GT2_SOCKET_H_ + +#include "gt2Main.h" + +GT2Result gti2CreateSocket +( + GT2Socket * socket, + const char * localAddress, + int outgoingBufferSize, + int incomingBufferSize, + gt2SocketErrorCallback callback, + GTI2ProtocolType type +); + +void gti2CloseSocket(GT2Socket socket); + +void gti2Listen(GT2Socket socket, gt2ConnectAttemptCallback callback); + +GT2Result gti2NewSocketConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port); +void gti2FreeSocketConnection(GT2Connection connection); + +GT2Connection gti2SocketFindConnection(GT2Socket socket, unsigned int ip, unsigned short port); + +// ip is network byte order, port is host byte order +// returns false if there was a fatal error +GT2Bool gti2SocketSend(GT2Socket socket, unsigned int ip, unsigned short port, const GT2Byte * message, int len); + +GT2Bool gti2SocketConnectionsThink(GT2Socket socket); + +void gti2FreeClosedConnections(GT2Socket socket); + +void gti2SocketError(GT2Socket socket); + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Utility.c b/xrGameSpy/gamespy/gt2/gt2Utility.c new file mode 100644 index 00000000000..88224aea40b --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Utility.c @@ -0,0 +1,426 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 130 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +#include "gt2Main.h" +#include "gt2Utility.h" +#include +#include +#ifdef WIN32 +#include +#include +#endif + +#define GTI2_STACK_HOSTLEN_MAX 256 + + +/************************* +** BYTE ORDER FUNCTIONS ** +*************************/ + +unsigned int gt2NetworkToHostInt(unsigned int i) +{ + return (unsigned int)ntohl(i); +} + +unsigned int gt2HostToNetworkInt(unsigned int i) +{ + return (unsigned int)htonl(i); +} + +unsigned short gt2NetworkToHostShort(unsigned short s) +{ + return ntohs(s); +} + +unsigned short gt2HostToNetworkShort(unsigned short s) +{ + return htons(s); +} + +/******************************* +** INTERNET ADDRESS FUNCTIONS ** +*******************************/ + +const char * gt2AddressToString(unsigned int ip, unsigned short port, char string[22]) +{ + static char strAddressArray[2][22]; + static int nIndex; + char * strAddress; + + if(string) + strAddress = string; + else + { + nIndex ^= 1; + strAddress = strAddressArray[nIndex]; + } + + if(ip) + { + IN_ADDR inAddr; + + inAddr.s_addr = ip; + + if(port) + sprintf(strAddress, "%s:%d", inet_ntoa(inAddr), port); + else + sprintf(strAddress, "%s", inet_ntoa(inAddr)); + } + else if(port) + sprintf(strAddress, ":%d", port); + else + strAddress[0] = '\0'; + + return strAddress; +} + +GT2Bool gt2StringToAddress(const char * string, unsigned int * ip, unsigned short * port) +{ + unsigned int srcIP = 0; // avoid use uninit condition + unsigned short srcPort = 0; + + if(!string || !string[0]) + { + srcIP = 0; + srcPort = 0; + } + else + { + char stackHost[GTI2_STACK_HOSTLEN_MAX + 1]; + const char * colon; + const char * host; + + // Is there a port? + colon = strchr(string, ':'); + if(!colon) + { + // The string is the host. + host = string; + + // No port. + srcPort = 0; + } + else + { + int len; + const char * check; + int temp; + + // Is it just a port? + if(colon == string) + { + host = NULL; + srcIP = 0; + } + else + { + // Copy the host portion into the array on the stack. + len = (colon - string); + assert(len < GTI2_STACK_HOSTLEN_MAX); + memcpy(stackHost, string, (unsigned int)len); + stackHost[len] = '\0'; + host = stackHost; + } + + // Check the port. + for(check = (colon + 1) ; *check ; check++) + if(!isdigit(*check)) + return GT2False; + + // Get the port. + temp = atoi(colon + 1); + if((temp < 0) || (temp > 0xFFFF)) + return GT2False; + srcPort = (unsigned short)temp; + } + + // Is there a host? + if(host) + { + // Try dotted IP. + ///////////////// + srcIP = inet_addr(host); + if(srcIP == INADDR_NONE) + { +#if defined(_XBOX) + return GT2False; +#else + HOSTENT * hostent; + + hostent = gethostbyname(host); + if(hostent == NULL) + return GT2False; + + srcIP = *(unsigned int *)hostent->h_addr_list[0]; +#endif + } + } + } + + if(ip) + *ip = srcIP; + if(port) + *port = srcPort; + + return GT2True; +} + +#ifdef GSI_ADHOC +gsi_u32 gti2MacToIp(const char *mac) +// change mac ethernet to IP address +{ + // Mac (48 bit)<---> IP (32 bit) convertion. + // horrible hack. But the chances of a conflict are less then getting struck by lightning + // but in order to translate back, we will need to keep a table + // stick real value in table. + GTI2MacEntry *entry; + int i; + gsi_u32 ip; + memcpy(&ip,mac,4); // store rest in table + + + // find match in table + for (i=0;i< MAC_TABLE_SIZE;i++) + { + if(MacTable[i].ip == ip) + { + return ip; // already there, don't add to the table. + } + } + + + // if not found match, add it, overwriting oldest entry + entry = &MacTable[lastmactableentry]; + lastmactableentry = (lastmactableentry +1 ) & (MAC_TABLE_SIZE-1); + entry->ip = ip; + memcpy(entry->mac,mac,6); + + return ip; +} + +void gti2IpToMac(gsi_u32 ip,char *mac) +// change IP address to mac ethernet +{ + int i; + // find match in table + for (i=0;i< MAC_TABLE_SIZE;i++) + { + if(MacTable[i].ip == ip) + { + memcpy(mac,MacTable[i].mac,6); + return; + } + } + // error, can not find mac address + memset(mac,0,6); + GS_FAIL(); +} +#endif + +#if defined(_XBOX) + +// XBox doesn't support the address functions +static const char * gti2HandleHostInfo(HOSTENT * host, char *** aliases, unsigned int *** ips) { return NULL; } +const char * gt2IPToHostInfo(unsigned int ip, char *** aliases, unsigned int *** ips) { return NULL; } +const char * gt2StringToHostInfo(const char * string, char *** aliases, unsigned int *** ips) { return NULL; } + +unsigned int gt2XnAddrToIP(XNADDR theAddr, XNKID theKeyId) +{ + // String to fit ip address + : + port + IN_ADDR anAddr; + if (XNetXnAddrToInAddr(&theAddr, &theKeyId, &anAddr)== 0) + return anAddr.s_addr; + return 0; +} + +GT2Bool gt2IPToXnAddr(int ip, XNADDR *theAddr, XNKID *theKeyId) +{ + IN_ADDR anAddr; + anAddr.s_addr = ip; + if (XNetInAddrToXnAddr(anAddr, theAddr, theKeyId) == 0) + return GT2True; + return GT2False; +} + +#else + +static const char * gti2HandleHostInfo(HOSTENT * host, char *** aliases, unsigned int *** ips) +{ + if(!host || (host->h_addrtype != AF_INET) || (host->h_length != 4)) + return NULL; + + if(aliases) + *aliases = host->h_aliases; + if(ips) + *ips = (unsigned int **)host->h_addr_list; + + return host->h_name; +} + + +const char * gt2IPToHostInfo(unsigned int ip, char *** aliases, unsigned int *** ips) +{ +#ifdef _PSP + return NULL; +#else + HOSTENT * host; + + host = gethostbyaddr((const char *)&ip, 4, AF_INET); + + GSI_UNUSED(ip); + return gti2HandleHostInfo(host, aliases, ips); +#endif +} + +const char * gt2StringToHostInfo(const char * string, char *** aliases, unsigned int *** ips) +{ + HOSTENT * host; + unsigned int ip; + + if(!string || !string[0]) + return NULL; + + // Is the string actually a dotted IP? + ip = inet_addr(string); + if(ip != INADDR_NONE) + return gt2IPToHostInfo(ip, aliases, ips); + + host = gethostbyname(string); + + return gti2HandleHostInfo(host, aliases, ips); +} + +#endif + +const char * gt2IPToHostname(unsigned int ip) +{ + return gt2IPToHostInfo(ip, NULL, NULL); +} + +const char * gt2StringToHostname(const char * string) +{ + return gt2StringToHostInfo(string, NULL, NULL); +} + +char ** gt2IPToAliases(unsigned int ip) +{ + char ** aliases; + + if(!gt2IPToHostInfo(ip, &aliases, NULL)) + return NULL; + + return aliases; +} + +char ** gt2StringToAliases(const char * string) +{ + char ** aliases; + + if(!gt2StringToHostInfo(string, &aliases, NULL)) + return NULL; + + return aliases; +} + +unsigned int ** gt2IPToIPs(unsigned int ip) +{ + unsigned int ** ips; + + if(!gt2IPToHostInfo(ip, NULL, &ips)) + return NULL; + + return ips; +} + +unsigned int ** gt2StringToIPs(const char * string) +{ + unsigned int ** ips; + + if(!gt2StringToHostInfo(string, NULL, &ips)) + return NULL; + + return ips; +} + +/*********************** +** INTERNAL FUNCTIONS ** +***********************/ + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped +void gti2MessageCheck(const GT2Byte ** message, int * len); +#endif + +// Used from gt2main.c +void gti2MessageCheck(const GT2Byte ** message, int * len) +{ + // check for an empty message + if(!*message) + { + *message = (const GT2Byte *)""; + *len = 0; + } + // check for calculating the message length + else if(*len == -1) + { + *len = (int)(strlen((const char *)*message) + 1); + } +} + +#ifdef RECV_LOG +void gti2LogMessage +( + unsigned int fromIP, unsigned short fromPort, + unsigned int toIP, unsigned short toPort, + const GT2Byte * message, int len +) +{ + FILE * file; + IN_ADDR ip; + int i; +#ifdef WIN32 + struct _timeb utcTime; + struct tm * now; +#endif + + file = fopen("recv.log", "at"); + if(!file) + return; + + // date-time +#ifdef WIN32 + _ftime(&utcTime); + now = localtime(&utcTime.time); + fprintf(file, "%02d.%02d.%02d %02d:%02d:%02d.%03d\n", + now->tm_year - 100, now->tm_mon + 1, now->tm_mday, + now->tm_hour, now->tm_min, now->tm_sec, utcTime.millitm); +#endif + + // from + ip.s_addr = fromIP; + fprintf(file, "%s:%d -> ", inet_ntoa(ip), fromPort); + + // to + ip.s_addr = toIP; + fprintf(file, "%s:%d\n", inet_ntoa(ip), toPort); + + // data + fprintf(file, "%d: ", len); + for(i = 0 ; i < len ; i++) + fprintf(file, "%02X ", message[i]); + fprintf(file, "\n\n"); + + fclose(file); +} +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2Utility.h b/xrGameSpy/gamespy/gt2/gt2Utility.h new file mode 100644 index 00000000000..34a5e4399b9 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2Utility.h @@ -0,0 +1,28 @@ +/* +GameSpy GT2 SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _GT2_UTILITY_H_ +#define _GT2_UTILITY_H_ + +#include "gt2Main.h" + +void gti2MessageCheck(const GT2Byte ** message, int * len); + +#ifdef RECV_LOG +void gti2LogMessage +( + unsigned int fromIP, unsigned short fromPort, + unsigned int toIP, unsigned short toPort, + const GT2Byte * message, int len +); +#endif + + +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2_vs2005.sln b/xrGameSpy/gamespy/gt2/gt2_vs2005.sln new file mode 100644 index 00000000000..6ac6b91a120 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2_vs2005.sln @@ -0,0 +1,132 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2action_vs2005", "gt2action\gt2action_vs2005.vcproj", "{A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2hostmig_vs2005", "gt2hostmig\gt2hostmig_vs2005.vcproj", "{1CE7906B-6082-4042-B34F-9373D77DB425}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2nat_vs2005", "gt2nat\gt2nat_vs2005.vcproj", "{1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2proxy_vs2005", "gt2proxy\gt2proxy_vs2005.vcproj", "{48BE03E2-3540-4386-BC9E-7E4B9F35135F}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2test_vs2005", "gt2test\gt2test_vs2005.vcproj", "{666F1A4F-216F-40D3-900F-7BAA3FEC31A9}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2testc_vs2005", "gt2testc\gt2testc_vs2005.vcproj", "{40E74A60-8858-4463-BAF3-B4EC4E1962B1}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E7EB5AF1-6849-465B-BCEB-D21F2E882B7A}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(SolutionItems) = preProject + changelog.txt = changelog.txt + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 7 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gt2action\\gt2action_vs2005.vcproj + SccProjectName1 = gt2action + SccLocalPath1 = gt2action + SccProjectUniqueName2 = gt2hostmig\\gt2hostmig_vs2005.vcproj + SccProjectName2 = gt2hostmig + SccLocalPath2 = gt2hostmig + SccProjectUniqueName3 = gt2nat\\gt2nat_vs2005.vcproj + SccProjectName3 = gt2nat + SccLocalPath3 = gt2nat + SccProjectUniqueName4 = gt2proxy\\gt2proxy_vs2005.vcproj + SccProjectName4 = gt2proxy + SccLocalPath4 = gt2proxy + SccProjectUniqueName5 = gt2test\\gt2test_vs2005.vcproj + SccProjectName5 = gt2test + SccLocalPath5 = gt2test + SccProjectUniqueName6 = gt2testc\\gt2testc_vs2005.vcproj + SccProjectName6 = gt2testc + SccLocalPath6 = gt2testc + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Debug|Win32.ActiveCfg = Debug|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Debug|Win32.Build.0 = Debug|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Release|Win32.ActiveCfg = Release|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Release|Win32.Build.0 = Release|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {A982C0BF-D9A9-4CB3-91EA-C4D95CD96361}.Unicode Release|Win32.Build.0 = Release|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Debug|Win32.Build.0 = Debug|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Release|Win32.ActiveCfg = Release|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Release|Win32.Build.0 = Release|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {1CE7906B-6082-4042-B34F-9373D77DB425}.Unicode Release|Win32.Build.0 = Release|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Debug|Win32.Build.0 = Debug|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Release|Win32.ActiveCfg = Release|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Release|Win32.Build.0 = Release|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {1DDD5585-F0E6-45F3-92D6-BC671A9BA4E6}.Unicode Release|Win32.Build.0 = Release|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Debug|Win32.ActiveCfg = Debug|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Debug|Win32.Build.0 = Debug|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Release|Win32.ActiveCfg = Release|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Release|Win32.Build.0 = Release|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {48BE03E2-3540-4386-BC9E-7E4B9F35135F}.Unicode Release|Win32.Build.0 = Release|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Debug|Win32.ActiveCfg = Debug|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Debug|Win32.Build.0 = Debug|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Release|Win32.ActiveCfg = Release|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Release|Win32.Build.0 = Release|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {666F1A4F-216F-40D3-900F-7BAA3FEC31A9}.Unicode Release|Win32.Build.0 = Release|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Debug|Win32.Build.0 = Debug|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Release|Win32.ActiveCfg = Release|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Release|Win32.Build.0 = Release|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {40E74A60-8858-4463-BAF3-B4EC4E1962B1}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gt2/gt2_vs2005.vssscc b/xrGameSpy/gamespy/gt2/gt2_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/gt2/gt2action/TGAFile.cpp b/xrGameSpy/gamespy/gt2/gt2action/TGAFile.cpp new file mode 100644 index 00000000000..d65382e5023 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/TGAFile.cpp @@ -0,0 +1,1574 @@ +/* + + Modified by Chris Losinger for Smaller Animals Software's ImgLib/ImgDLL. + Esp. RGB->BGR and row order switches. 9/98 +*/ +#include +#include + +/* + TGADefs.h - Tye and Constant declaration file + This File defines the Types, and the Constant Values used by the + TGAFile Class. + + Created By: Timothy A. Bish + Created On: 08/18/98 +*/ + +#ifndef TGADEFSH +#define TGADEFSH + +#include + +#pragma pack(1) // Align the structure on byte boundries... + +// Possible Image Types +#define TGA_NOIMAGETYPE 0 // No Image Data Included in Image +#define TGA_MAPRGBTYPE 1 // Colormapped Image Data - No Compression +#define TGA_RAWRGBTYPE 2 // Truecolor Image Data - No Compression +#define TGA_RAWMONOTYPE 3 // Monochrome Image Data - No Compression +#define TGA_MAPENCODETYPE 9 // Colormapped Image Data - Compressed RLE +#define TGA_RAWENCODETYPE 10 // Truecolor Image Data - Compressed RLE +#define TGA_MONOENCODETYPE 11 // Monochrome Image Data - Compressed RLE +// Version Macro +#define TGA_VERSIONONE 1 // Version 1 File Format +#define TGA_VERSIONTWO 2 // Version 2 File Format +// File Read Write Modes +const int GREYSC = 0; // Image is Greyscale +const int COLOUR = 1; // Image is Color +const int MAPPED = 2; // Image has a Color Map +const int RLENCO = 4; // Image is RLE Encoded + +// 18 Byte Sturcture representin the basic definitions of +// the image +typedef struct _aTGAHEADER +{ + BYTE IDLength; // 00h Size of ID Field + BYTE ColorMapType; // 01h Color Map Type + BYTE ImageType; // 02h Image Type Code + WORD CMapStart; // 03h Color Map Origin + WORD CMapLength; // 05h Color Map Length + BYTE CMapDepth; // 07h Color Map Depth + WORD XOffset; // 08h X origin of Image + WORD YOffset; // 0Ah Y origin of Image + WORD Width; // 0Ch Width of Image + WORD Height; // 0Eh Height of Image + BYTE PixelDepth; // 10h Image Pixel Size + BYTE ImageDescriptor; // 11h Image Description Byte +} TGAHEADER; + +// The footer is 26 Bytes in length and is always at the end of a +// TGA v2.0 file. +typedef struct _aTGAFOOTER +{ + DWORD ExtensionOffset; // Extension Area Offset + DWORD DeveloperOffset; // Developer Directory Offset + CHAR Signature[18]; // TGA Signature +} TGAFOOTER; + +typedef struct _aTGATAG +{ + WORD TagNumber; // ID Number of the Tag + DWORD DataOffset; // Offset Location of the Tag + DWORD DataSize; // Size of the Tag Data in Bytes +} TGATAG; + +// The extension area is basically the second header in the TGA v2.0 +// file format. +typedef struct _aTGAEXTENSION +{ + WORD Size; // Extension Size + CHAR AuthorName[41]; // Author Name + CHAR AuthorComment[324]; // Author Comment + WORD StampMonth; // Date/Time Stamp: Month + WORD StampDay; // Date/Time Stamp: Day + WORD StampYear; // Date/Time Stamp: Year + WORD StampHour; // Date/Time Stamp: Hour + WORD StampMinute; // Date/Time Stamp: Minute + WORD StampSecond; // Date/Time Stamp: Second + CHAR JobName[41]; // Job Name/ID + WORD JobHour; // Job Time: Hours + WORD JobMinute; // Job Time: Minutes + WORD JobSecond; // Job Time: Seconds + CHAR SoftwareId[41]; // Software ID + WORD VersionNumber; // Version Number of Software + BYTE VersionLetter; // Version Letter of Software + DWORD KeyColor; // Key Color + WORD PixelNumerator; // Pixel Aspect Ratio + WORD PixelDenominator; // Pixel Aspect Ratio + WORD GammaNumerator; // Gamma Value + WORD GammaDenominator; // Gamma Value + DWORD ColorOffset; // Color Correction Offset + DWORD StampOffset; // Postage Stamp Offset + DWORD ScanOffset; // Scanline Table Offset + BYTE AttributesType; // Attributes Type +} TGAEXTENSION; + +// The Color Correction Table is an array of 2048 Bytes in length, which +// contians 256 entries used to store the values used for color remapping. +typedef struct _aTGACOLORCORRECTIONTABLE +{ + SHORT Alpha; // Alpha Channel Seldom Used + SHORT Red; // Red Value of Correction + SHORT Green; // Green Value of Correction + SHORT Blue; // Green Value of Correction +} TGACOLORCORRECTIONTABLE; + +#define TRIALVERSION -1 // LIB was not initialized with a registered key + +#define IMGOK 0 // no err +#define MEMERR 1 // out of mem +#define FILEOPENERR 2 // error on file open +#define FILEREADERR 3 // error on file read +#define FILEWRITEERR 4 // error on file write +#define BADPARAMERR 5 // bad user param +#define INVALIDBMPERR 6 // bad BMP file +#define BMPRLEERR 7 // we don't do compressed (RLE) BMP files +#define INVALIDGIFERR 8 // bad GIF file +#define INVALIDJPGERR 9 // bad JPG file +#define IMGDCERR 10 // error with device context +#define IMGDIBERR 11 // problem with a GetDIBits call +#define NOGIFERR 12 // GIF support disabled +#define IMGNORESOURCE 13 // resource not found +#define CALLBACKCANCEL 14 // callback returned FALSE - operation aborted +#define INVALIDPNGERR 15 // bad PNG file +#define PNGCREATEERR 16 // internal PNG lib behavior - contact smaller animals s.w. +#define IMGDLLINTERNAL 17 // misc unexpected behavior error - contact smaller animals s.w. +#define IMGFONTERR 18 // trouble creating a font object +#define INTTIFFERR 19 // misc internal TIFF error +#define INVALIDTIFFERR 20 // invalid TIFF file +#define TIFFLZWNOTSUPPORTED 21 // this will not read TIFF-LZW iamges +#define INVALIDPCXERR 22 // invalid PCX image +#define CREATEBMPERR 23 // a call to the fn CreateCompatibleBitmap failed +#define IMGNOLINES 24 // end of an image while using single-line de/compression +#define GETDIBERR 25 // error during a call to GetDIBits +#define DEVOPNOSUPPORT 26 // device does not support an operation required by this function +#define INVALIDWMF 27 // invalid windows metafile +#define DEPTHMISMATCHERR 28 // the file was not of the requested bit-depth +#define INVALIDTGAERR 35 // Invalid TGA File +#define NOTGATHUMBNAIL 36 // No TGA Thumbnail in the file + +#pragma pack() + +#endif + +class TGAFile +{ + +public: + + // parameters + __int32 m_error; + +public: + + // operations + + TGAFile(); + + BOOL IsFileTGA(const char * fileName); + + LPVOID LoadTGA( const char *fileName, // Name of file + UINT32 *width, // Width in Pixel + UINT32 *height); // Height + + HGLOBAL LoadTGA8Bit(const char *fileName, // Name of File + UINT32 *width, // Width in pixels + UINT32 *height, // Height + RGBQUAD *pal); // Palette of RGBQUADS + + BOOL GetTGADims(const char *fileName, + UINT32 *width, + UINT32 *height); + + BOOL SaveTGA32(const char * fileName, // output path + BYTE *inBuf, // RGB buffer + UINT32 width, // size + UINT32 height); + + BOOL Save8BitTGA(const char * fileName, // output path + BYTE *colormappedbuffer, // one BYTE per pixel colomapped image + UINT32 width, // Width of image + UINT32 height, // Height of image + __int32 colors, // number of colors (number of RGBQUADs) + RGBQUAD *colormap); // array of RGBQUADs + + HGLOBAL LoadTGAThumbnail(const char *fileName, // Name of file + UINT32 *width, // Width in Pixel + UINT32 *height); // Height + +private: + + // Parameters + + char TGA_ImageIDFeild[256];// Text in file + BYTE TGA_Attribute; // Number of attribute bytes per pixel + // i.e. 1 for T16 and 8 for T32 + UINT32 mode; // Mode of current Read or Write + + // RLE Decompression Variables + BYTE Red, // Stores pixel value for + Grn, // RLE series of oixels + Blu, + Alpha; + UINT32 l; // Used when 8 bit files use RLE + __int32 RLECount, RLEFlag; // Indicates whether the RLE series + // is still going or is finished + +private: + + // Operations + + __int32 TGA_GetFileVersion(FILE *fp); // Determines whether this is a V1.0 + // or V2.0 TGA File + BOOL TGA_GetMapEntry(BYTE *Red, // Get the Color Values out of the + BYTE *Green, // Color map in the TGA File + BYTE *Blue, // Return TRUE on Success + BYTE *Alpha, + FILE *fp, + UINT32 Depth); + + // version that takes a file ptr + BOOL TGA_GetPixelValue(BYTE *Red, // Get and parse a single pixel value + BYTE *Grn, // from the TGA file. Handles Unencoding + BYTE *Blu, // of RLE encoded files. + BYTE *Alp, // plus Alpha (08jan00/bgw) + FILE *fp, + UINT32 PixelDepth, + RGBQUAD *CMap); + + // version that takes a buffer ptr + BOOL TGA_GetPixelValue(BYTE *Red, // Get and parse a single pixel value + BYTE *Grn, // from the TGA file. Handles Unencoding + BYTE *Blu, // of RLE encoded files. + BYTE *Alp, // plus Alpha (08jan00/bgw) + BYTE ** ppTGAData, + UINT32 PixelDepth, + RGBQUAD *CMap); +}; + +//#define MAX_IMAGEREAD_BUFFER 65535 +//BYTE * gpImageReadBuffer = NULL; +//long glImageReadBufferSize = 0; +//BYTE * gpImageReadBufPos = NULL; +// +// +//typedef struct tagTGAColorComponents +// { +// BYTE red; +// BYTE green; +// BYTE blue; +// BYTE alpha; +// } TGAColorComponents; + +/* TGA File REader Classs Implementation File + This Implementation Allows the reading of TGA (Targa) Files + into an RGB buffer. Also the class allows an RGB Buffer to be + written to a TGA File. There is also a function to determine + the dimensions of a TGA file. + + Created By: Timothy A. Bish + Created On: 08/17/98 + +*/ +//////////////////////////////////////////////////////////////////////////// +// No Much going on here +TGAFile::TGAFile() + { + m_error = IMGOK; + } + + +//////////////////////////////////////////////////////////////////////////// +// GetTGADimns +// Find dims of the image in a TGA file +// Returns - TRUE on success +BOOL +TGAFile::GetTGADims(const char * fileName, UINT32 * width, UINT32 * height) + { + // for safety + *width = 0; + *height = 0; + FILE * fp; + TGAHEADER tgahd; + + // Init the file Header to all zeros + ZeroMemory(&tgahd, sizeof(tgahd)); + + // init + m_error = IMGOK; + fp = fopen(fileName, "rb"); + + if(fp == NULL) + { + m_error = FILEOPENERR; + return FALSE; + } + + // Get the Header + if(fread(&tgahd, 1, sizeof(TGAHEADER), fp) != sizeof(TGAHEADER)) + { + m_error = FILEREADERR; + fclose(fp); + return FALSE; + } + + // Check fo valid data in structure + if(tgahd.PixelDepth > 32) + { + // I don't do Pixel Depths Bigger than 32 + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Anything other than the standard TGA types + // and I quit + switch(tgahd.ImageType) + { + case TGA_MAPRGBTYPE: + case TGA_RAWRGBTYPE: + case TGA_RAWMONOTYPE: + case TGA_MAPENCODETYPE: + case TGA_RAWENCODETYPE: + case TGA_MONOENCODETYPE: + break; + + default: + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Grab the Image dimensions + *width = tgahd.Width; + *height = tgahd.Height; + fclose(fp); + return TRUE; + } + +/***************************************************************************** +* NAME: +* TGAFile::IsFileTGA +* +* DESCRIPTION: +* Description goes here... +* +*******************************************************************************/ +BOOL +TGAFile::IsFileTGA(const char * fileName) + { + TGAHEADER tgahd; + FILE * fp; + + ZeroMemory(&tgahd, sizeof(tgahd)); + fp = fopen(fileName, "rb"); + long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp); + fclose(fp); + + if( (rc == sizeof(TGAHEADER)) && // must be big enough for a header... + (tgahd.PixelDepth == 32) && // 32-bit TGAs only + (tgahd.ImageType == TGA_RAWRGBTYPE) ) // Raw RGBA format only + return(TRUE); + + return(FALSE); + } + +//////////////////////////////////////////////////////////////////////////// +// LoadTGA +// load a .TGA file - 1,4,8,24,32 bit +// allocates and returns an RGB buffer containing the image. +// modifies width and height accordingly - NULL, 0, 0 on error +LPVOID +TGAFile::LoadTGA(const char * fileName, UINT32 * width, UINT32 * height) + { + LPVOID pNew = NULL; + BYTE * pRGB = NULL; + BYTE Alpha; + + TGAHEADER tgahd; + + BYTE TGA_Origin = 0; + + RGBQUAD CColMap[256]; + + // for safety + *width = 0; + *height = 0; + + // init + m_error = IMGOK; + + // Init the file Header to all zeros + ZeroMemory(&tgahd, sizeof(tgahd)); + FILE * fp; + fp = fopen(fileName, "rb"); + + if(fp == NULL) + { + m_error = FILEOPENERR; + return FALSE; + } + + // Read the TGA Header + long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp); + + if(rc != sizeof(TGAHEADER)) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Check fo valid data in structure + if((tgahd.PixelDepth> 32) || (tgahd.PixelDepth<8)) + { + // I don't do Pixel Depths Bigger than 32 + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Anything other than the standard TGA types + // and I quit + switch(tgahd.ImageType) + { + case TGA_MAPRGBTYPE: + case TGA_RAWRGBTYPE: + case TGA_RAWMONOTYPE: + case TGA_MAPENCODETYPE: + case TGA_RAWENCODETYPE: + case TGA_MONOENCODETYPE: + break; + + default: + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Set the number of Color Planes + if(tgahd.ImageType == TGA_RAWMONOTYPE) + { + mode = GREYSC; + } + else + { + mode = COLOUR; + } + + // Read the ID Descriptor if present + if(tgahd.IDLength != 0) + { + // Read the TGA Comments + long rc = fread(&TGA_ImageIDFeild, 1, tgahd.IDLength, fp); + + if(rc != tgahd.IDLength) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + } + + // Parse the Image Descriptor + TGA_Attribute = (BYTE)(tgahd.ImageDescriptor & 0x0f); + TGA_Origin = (BYTE)((tgahd.ImageDescriptor & 0x20) / 32); + + // If present read the color map + if(tgahd.ColorMapType != 0) + { + // Get the color map + for(__int32 i = 0; i < (tgahd.CMapStart + tgahd.CMapLength); i++) + { + TGA_GetMapEntry(&CColMap[i].rgbRed, &CColMap[i].rgbGreen, &CColMap[i].rgbBlue, &Alpha, fp, tgahd.CMapDepth); + } + + // If the TGA file actually needs the color map + // Set the mode to show this + if((tgahd.ImageType != TGA_RAWRGBTYPE) && (tgahd.ImageType != TGA_RAWMONOTYPE) && (tgahd.ImageType != TGA_RAWENCODETYPE)) + mode = mode | MAPPED; + } + + // Check Run Length Encoding + if((tgahd.ImageType == TGA_MAPENCODETYPE) || (tgahd.ImageType == TGA_RAWENCODETYPE) || (tgahd.ImageType == TGA_MONOENCODETYPE)) + mode = mode | RLENCO; + + long lImgDataSize = (tgahd.Height * tgahd.Width) * (tgahd.PixelDepth / 8); + + // Allocate the memory buffers + pNew = malloc(lImgDataSize); +// pNew = (LPVOID) theApp.m_TGABuffer.GetBuffer((size_t)(tgahd.Width * tgahd.Height * 4)); + + if(pNew == NULL) + { + m_error = MEMERR; + fclose(fp); + return NULL; + } + else + pRGB = (BYTE *)pNew; + + // RGB from image Data + //DWORD destOffset = 0; + + RLECount = 0; + RLEFlag = 0; + +// // +// // (re-)alocate a local image buffer to read the TGA formatted +// // data into. this avoids the huge critical-section delays in +// // every call to getc(). +// // +// long lBufSize = lImgDataSize + 16; // slop +// if(lBufSize < MAX_IMAGEREAD_BUFFER) +// lBufSize = MAX_IMAGEREAD_BUFFER; +// if(glImageReadBufferSize < lBufSize) +// { +// if(gpImageReadBuffer) +// { +// free(gpImageReadBuffer); +// gpImageReadBuffer = NULL; // tidy +// gpImageReadBufPos = NULL; +// } +// +// glImageReadBufferSize = lBufSize; +// gpImageReadBuffer = (BYTE *) malloc(glImageReadBufferSize); +// +// if(!gpImageReadBuffer) +// { +// glImageReadBufferSize = 0; +// return NULL; // v. bad news. +// } +// TRACE("* (Re-)Allocated local TGA data buffer: %d bytes\n", glImageReadBufferSize); +// } + + // + // Read the TGA format data into the local buffer + // + long lTGABytesRead = fread(pRGB, 1, lImgDataSize, fp); + if(lTGABytesRead != lImgDataSize) + { +// ASSERT(0); + //free(pNew); + return NULL; + } + + // Grab the image dimensions + *width = tgahd.Width; + *height = tgahd.Height; + + // Clean Up + fclose(fp); + m_error = IMGOK; + return pNew; + +/////////////// +// all out...dorks didn't realize that TGA's memory format == DIBSections! +////////////// +#if 0 + // + // Read the TGA format data into the local buffer + // + long lTGABytesRead = fread(gpImageReadBuffer, 1, lImgDataSize, fp); + if(lTGABytesRead != lImgDataSize) + { + ASSERT(0); + return NULL; + } + + gpImageReadBufPos = gpImageReadBuffer; + + // copy DWORDs instead of bytes... + UINT32 * pPixel = (UINT32 *) pRGB; + UINT32 * pReadBufPixel = (UINT32 *) gpImageReadBufPos; + + for(UINT32 row = 0; row < tgahd.Height; row++) + { + for(UINT32 col = 0; col < tgahd.Width; col++) + { + + // Reset RLE Counters + BYTE Red, Grn, Blu, Alp; + TGA_GetPixelValue(&Red, &Grn, &Blu, &Alp, &gpImageReadBufPos, tgahd.PixelDepth, CColMap); + + // Invert if the image origin is in Bottom left + if(TGA_Origin != 0) + { // Bottom Left Origin + destOffset = ((tgahd.Height -1) -row) * tgahd.Width * 4 + col * 4; + *(pRGB + destOffset + 0) = Red; + *(pRGB + destOffset + 1) = Grn; + *(pRGB + destOffset + 2) = Blu; + *(pRGB + destOffset + 3) = Alp; + } + else + { // Top Left Origin + *(pRGB + destOffset + 0) = Red; + *(pRGB + destOffset + 1) = Grn; + *(pRGB + destOffset + 2) = Blu; + *(pRGB + destOffset + 3) = Alp; + destOffset += 4; + } + #if 0 // even faster! + // Red = *(gpImageReadBufPos++); + // Grn = *(gpImageReadBufPos++); + // Blu = *(gpImageReadBufPos++); + // Alp = *(gpImageReadBufPos++); + // + // *(pRGB + destOffset + 0) = Red; + // *(pRGB + destOffset + 1) = Grn; + // *(pRGB + destOffset + 2) = Blu; + // *(pRGB + destOffset + 3) = Alp; + // destOffset += 4; + + // TGAColorComponents rgbaPixel; + + *(pPixel++) = *(pReadBufPixel++); + + // BYTE * p = pRGB + destOffset; + // *(p++) = *(gpImageReadBufPos++); + // *(p++) = *(gpImageReadBufPos++); + // *(p++) = *(gpImageReadBufPos++); + // *(p++) = *(gpImageReadBufPos++); + // destOffset += 4; + #endif + } // loop col + } // loop row + + // Grab the image dimensions + *width = tgahd.Width; + *height = tgahd.Height; + + // Clean Up + fclose(fp); + m_error = IMGOK; + return pNew; +#endif + } + + +/////////////////////////////////////////////////////////////////////////////////// +// LoadTGA8Bit +// Loads in an 8 Bit buffer and the color palette that is +// associated with that buffer, if the image is 8 Bit, else +// it sets global error to DEPTHMISMATCHERR +HGLOBAL +TGAFile::LoadTGA8Bit(const char * fileName, // Name of File +UINT32 * width, // Width in pixels +UINT32 * height, // Height +RGBQUAD * pal) // Palette of RGBQUADS + { + HGLOBAL hNew = NULL; + BYTE * pRGB = NULL; + BYTE Alpha; + + TGAHEADER tgahd; + + BYTE TGA_Origin = 0; + + // for safety + *width = 0; + *height = 0; + + // init + m_error = IMGOK; + + // Init the file Header to all zeros + ZeroMemory(&tgahd, sizeof(tgahd)); + + // Init the Palette to all zeros + ZeroMemory(pal, sizeof(pal)); + FILE * fp; + fp = fopen(fileName, "rb"); + + if(fp == NULL) + { + m_error = FILEOPENERR; + return FALSE; + } + else + { + // Read the TGA Header + long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp); + + if(rc != sizeof(TGAHEADER)) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Check fo valid data in structure + if(tgahd.PixelDepth> 8) + { + // Not an 8bit Image + m_error = DEPTHMISMATCHERR; + fclose(fp); + return NULL; + } + + // Anything other than the standard TGA types + // and I quit + switch(tgahd.ImageType) + { + case TGA_MAPRGBTYPE: + case TGA_MAPENCODETYPE: + break; + + default: + m_error = DEPTHMISMATCHERR; + fclose(fp); + return NULL; + } + + // Set the Color Mode + if(tgahd.ImageType == TGA_RAWMONOTYPE) + { + mode = GREYSC; + } + else + { + mode = COLOUR; + } + + // Read the ID Descriptor if present + if(tgahd.IDLength != 0) + { + // Read the TGA Comments + long rc = fread(&TGA_ImageIDFeild, 1, tgahd.IDLength, fp); + + if(rc != tgahd.IDLength) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + } + + // Parse the Image Descriptor + TGA_Attribute = (BYTE)(tgahd.ImageDescriptor & 0x0f); + TGA_Origin = (BYTE)((tgahd.ImageDescriptor & 0x20) / 32); + + // If present read the color map + if(tgahd.ColorMapType != 0) + { + // Get the color map + for(__int32 i = 0; i < (tgahd.CMapStart + tgahd.CMapLength); i++) + { + TGA_GetMapEntry(&pal[i].rgbRed, &pal[i].rgbGreen, &pal[i].rgbBlue, &Alpha, fp, tgahd.CMapDepth); + } + } + else + { + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Check Run Length Encoding + if((tgahd.ImageType == TGA_MAPENCODETYPE) || (tgahd.ImageType == TGA_RAWENCODETYPE) || (tgahd.ImageType == TGA_MONOENCODETYPE)) + mode = mode | RLENCO; + + // Allocate the memory buffers + hNew = GlobalAlloc(GHND, tgahd.Width * tgahd.Height); + + if(hNew == NULL) + { + m_error = MEMERR; + fclose(fp); + return NULL; + } + else + { + pRGB = (BYTE *)GlobalLock(hNew); + + if(pRGB == NULL) + { + m_error = MEMERR; + fclose(fp); + return NULL; + } + } + + // RGB from image Data + DWORD destOffset = 0; + + RLECount = 0; + RLEFlag = 0; + + for(UINT32 row = 0; row < tgahd.Height; row++) + { + for(UINT32 col = 0; col < tgahd.Width; col++) + { + BYTE Red, Grn, Blu, Alp; + + // Reset RLE Counters + TGA_GetPixelValue(&Red, &Grn, &Blu, &Alp, fp, tgahd.PixelDepth, pal); + + // Invert if the image origin is in Bottom left + if(TGA_Origin == 0) + { // Bottom Left Origin + *(pRGB + destOffset) = Red; + destOffset = ((tgahd.Height -1) -row) * tgahd.Width + col; + } + else + { // Top Left Origin + *(pRGB + destOffset) = Red; + destOffset++; + } + } + } + } + + // Grab the image dimensions + *width = tgahd.Width; + *height = tgahd.Height; + + // Clean Up + GlobalUnlock(hNew); + fclose(fp); + m_error = IMGOK; + return hNew; + } + + +/////////////////////////////////////////////////////////////////////////////////// +// LoadTGAThumbNail +// Checks the TGA file for the existance of a thumbnail image +// Reads and returns it in a 24 Bit RGB Buffer if a thumbnail +// exists. Returns NULL if there isn't one sets TGANOTHUMBNAIL +HGLOBAL +TGAFile::LoadTGAThumbnail + ( + const char * fileName, // Name of file + UINT32 * width, // Width in Pixel + UINT32 * height // Height + ) + { + HGLOBAL hNew = NULL; + + TGAHEADER tgahd; + TGAFOOTER tgaft; + TGAEXTENSION tgaext; + + BYTE stampWidth = 0, stampHeight = 0; + long lResult; + + // for safety + *width = 0; + *height = 0; + + // init + m_error = IMGOK; + + // Init the file structs + ZeroMemory(&tgahd, sizeof(tgahd)); + ZeroMemory(&tgaft, sizeof(tgaft)); + ZeroMemory(&tgaext, sizeof(tgaext)); + FILE * fp; + fp = fopen(fileName, "rb"); + + if(fp == NULL) + { + m_error = FILEOPENERR; + return FALSE; + } + else + { + // Read the TGA Header + long rc = fread(&tgahd, 1, sizeof(TGAHEADER), fp); + + if(rc != sizeof(TGAHEADER)) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Check fo valid data in structure + if((tgahd.PixelDepth> 32) || (tgahd.PixelDepth<8)) + { + // I don't do Pixel Depths Bigger than 32 + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Anything other than the standard TGA types + // and I quit + switch(tgahd.ImageType) + { + case TGA_MAPRGBTYPE: + case TGA_RAWRGBTYPE: + case TGA_RAWMONOTYPE: + case TGA_MAPENCODETYPE: + case TGA_RAWENCODETYPE: + case TGA_MONOENCODETYPE: + break; + + default: + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + + // Set the number of Color Planes + if(tgahd.ImageType == TGA_RAWMONOTYPE) + { + mode = GREYSC; + } + else + { + mode = COLOUR; + } + + // Check for file Version + // Seek the last 26 bytes of the file + if(fseek(fp, -26, SEEK_END)) + { + // Error Quit + fclose(fp); + return NULL; + } + + // Read in the last 26 Bytes of the File + lResult = fread(&tgaft, 1, sizeof(TGAFOOTER), fp); + + if(lResult != sizeof(TGAFOOTER)) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Check for the Marker at the end of the file + lResult = strcmp(tgaft.Signature, "TRUEVISION-XFILE."); + + if(lResult != 0) + { + // Not V2.0 File no Thumbnail + m_error = NOTGATHUMBNAIL; + fclose(fp); + return NULL; + } + + // Check for the existance of an extension area + if(tgaft.ExtensionOffset == 0) + { + // No Thumbnail in this file + m_error = NOTGATHUMBNAIL; + fclose(fp); + return NULL; + } + + // Seek the extension area + if(fseek(fp, tgaft.ExtensionOffset, SEEK_SET)) + { + // Error Quit + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Read in the last 26 Bytes of the File + lResult = fread(&tgaext, 1, sizeof(TGAEXTENSION), fp); + + if(lResult != sizeof(TGAEXTENSION)) + { + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Seek the thumbnail image + if(fseek(fp, tgaext.StampOffset, SEEK_SET)) + { + // Error Quit + m_error = FILEREADERR; + fclose(fp); + return NULL; + } + + // Read the Width and Height from the first two bytes + // of the postage stamp data. + fread(&stampWidth, 1, 1, fp); + fread(&stampHeight, 1, 1, fp); + + if((stampWidth <= 0) || (stampWidth> 64) || (stampHeight <= 0) || (stampHeight> 64)) + { + m_error = INVALIDTGAERR; + fclose(fp); + return NULL; + } + } + + // Clean Up + *width = stampWidth; + *height = stampHeight; + fclose(fp); + + // Return Okay Image + return hNew; + } + + +/////////////////////////////////////////////////////////////////////////////////// +// SaveTGA32 +// Saves the buffer as a 32 bit True Color Image in TGA format +BOOL +TGAFile::SaveTGA32 + ( + const char * fileName, // output path + BYTE * inBuf, // BGR buffer + UINT32 width, // size in pixels + UINT32 height + ) + { + long lResult = 0; + + TGAHEADER tgahd; + m_error = IMGOK; + + // Init the file Header to all zeros + ZeroMemory(&tgahd, sizeof(tgahd)); + + if(inBuf == NULL) + { + m_error = BADPARAMERR; + return FALSE; + } + + if((width == 0) || (height == 0)) + { + m_error = BADPARAMERR; + return FALSE; + } + + // Initialize the Header for the File + tgahd.IDLength = 0; + tgahd.ColorMapType = 0; + tgahd.ImageType = TGA_RAWRGBTYPE; + tgahd.CMapStart = 0; + tgahd.CMapLength = 0; + tgahd.CMapDepth = 0; + tgahd.XOffset = 0; + tgahd.YOffset = 0; + tgahd.Width = (WORD)width; + tgahd.Height = (WORD)height; + tgahd.PixelDepth = 32; + tgahd.ImageDescriptor = 0; + + // Open a file to write + FILE * fp = fopen(fileName, "wb"); + + if(fp == NULL) + { + m_error = FILEOPENERR; + return FALSE; + } + + // Write the Header to File. + if((lResult = fwrite(&tgahd, 1, sizeof(TGAHEADER), fp)) != 18) + { + fclose(fp); + m_error = FILEWRITEERR; + return FALSE; + } + + // Wrte the Bytes to file + DWORD destOffset = 0; + BYTE temp = 0; + DWORD rowStride = tgahd.Width * 4; + + for(UINT32 row = 0; row < tgahd.Height; row++) + { + //DWORD rowOffset = rowStride * row; + DWORD rowOffset = rowStride *((tgahd.Height -1) -row); + + for(UINT32 col = 0; col < tgahd.Width; col++) + { + destOffset = rowOffset + 4 * col; + temp = *(inBuf + destOffset + 2); + + if(fwrite(&temp, 1, 1, fp) != 1) + { + m_error = FILEWRITEERR; + fclose(fp); + return FALSE; + } + temp = *(inBuf + destOffset + 1); + + if(fwrite(&temp, 1, 1, fp) != 1) + { + m_error = FILEWRITEERR; + fclose(fp); + return FALSE; + } + temp = *(inBuf + destOffset + 0); + + if(fwrite(&temp, 1, 1, fp) != 1) + { + m_error = FILEWRITEERR; + fclose(fp); + return FALSE; + } + + if(fwrite(&temp, 1, 1, fp) != 1) + { + m_error = FILEWRITEERR; + fclose(fp); + return FALSE; + } + } + } + + // Cleanup + fclose(fp); + m_error = IMGOK; + return TRUE; + } + + +/////////////////////////////////////////////////////////////////////////////////// +// Save8BitTGA +// Save's to an 8 Bit Color mapped file using the Palette +// passed in to the function. +BOOL +TGAFile::Save8BitTGA(const char * fileName, // output path +BYTE * inBuf, // one BYTE per pixel colomapped image +UINT32 width, // Width of Image +UINT32 height, // Height of Image +__int32 colors, // number of colors (number of RGBQUADs) +RGBQUAD * colormap) // array of RGBQUADs + { + long lResult = 0; + + TGAHEADER tgahd; + + // Init + m_error = IMGOK; + + // Init the file Header to all zeros + ZeroMemory(&tgahd, sizeof(tgahd)); + + if(inBuf == NULL) + { + m_error = BADPARAMERR; + return FALSE; + } + + if((width == 0) || (height == 0)) + { + m_error = BADPARAMERR; + return FALSE; + } + + if(colormap == NULL) + { + m_error = BADPARAMERR; + return FALSE; + } + + // Initialize the Header for the File + tgahd.IDLength = 0; + tgahd.ColorMapType = 1; + tgahd.ImageType = TGA_MAPRGBTYPE; + tgahd.CMapStart = 0; + tgahd.CMapLength = (SHORT)colors; + tgahd.CMapDepth = 24; + tgahd.XOffset = 0; + tgahd.YOffset = 0; + tgahd.Width = (WORD)width; + tgahd.Height = (WORD)height; + tgahd.PixelDepth = 8; + tgahd.ImageDescriptor = 0x28; + + // Open a file to write + FILE * fp = fopen(fileName, "wb"); + + if(fp == NULL) + { + m_error = FILEOPENERR; + return FALSE; + } + + // Write the Header to File. + if((lResult = fwrite(&tgahd, 1, sizeof(TGAHEADER), fp)) != 18) + { + m_error = FILEWRITEERR; + fclose(fp); + return FALSE; + } + + // Write out the Colormap + for(__int32 i = 0; i < colors; i++) + { + putc(colormap[i].rgbBlue, fp); + putc(colormap[i].rgbGreen, fp); + putc(colormap[i].rgbRed, fp); + } + + // Wrte the Bytes to file + DWORD destOffset = 0; + BYTE temp = 0; + + for(UINT32 row = 0; row < tgahd.Height; row++) + { + for(UINT32 col = 0; col < tgahd.Width; col++) + { + temp = *(inBuf + destOffset + 0); + + if(fwrite(&temp, 1, 1, fp) != 1) + { + m_error = FILEWRITEERR; + fclose(fp); + return FALSE; + } + destOffset += 1; + } + } + + // Cleanup + fclose(fp); + m_error = IMGOK; + return TRUE; + } + + +//////////////////////////////////////////////////////////////////////////////////// +// TGA_GetMapEntry +// Get the Color Values out of the +// Color map in the TGA File +// Return 0 on Success +BOOL +TGAFile::TGA_GetMapEntry(BYTE * Red, BYTE * Green, BYTE * Blue, BYTE * Alpha, FILE * fp, UINT32 Depth) + { + UINT32 j, k, l; + BYTE i, r, g, b, a = 0; + long lResult; + + switch(Depth) + { + case 8: // Greyscale Read and Triplicate + lResult = fread(&i, 1, 1, fp); + + // Check for error + if(lResult != 1) + { + m_error = FILEREADERR; + return FALSE; + } + + // Set RGB Values + r = i; + g = i; + b = i; + break; + + case 16: // 5 bits each of Red, Green, and Blue + + case 15: // Watch for the Byte order + lResult = fread(&j, 1, 1, fp); + lResult = lResult + fread(&k, 1, 1, fp); + + // Check for error + if(lResult != 2) + { + m_error = FILEREADERR; + return FALSE; + } + l = j + k * 256; + b = (BYTE)(((l >> 10) & 31) << 3); + g = (BYTE)(((l >> 5) & 31) << 3); + r = (BYTE)((l & 31) << 3); + break; + + case 32: // Read the Alpha bit a Throw it away + + case 24: // Eight bits for each Red, Green and Blue + lResult = fread(&i, 1, 1, fp); + r = i; + lResult = lResult + fread(&i, 1, 1, fp); + g = i; + lResult = lResult + fread(&i, 1, 1, fp); + b = i; + + // Check for error + if(lResult != 3) + { + m_error = FILEREADERR; + return FALSE; + } + + if(Depth == 32) + { + lResult = fread(&i, 1, 1, fp); + + if(lResult != 1) + { + m_error = FILEREADERR; + return FALSE; + } + + // Stroe Alpha bit + a = i; + } + break; + + default: + // Some Other Pixel Depth Which I don't support + return FALSE; + } + *Red = r; + *Green = g; + *Blue = b; + *Alpha = a; + + // Reutrn No Error + return TRUE; + } + + +//////////////////////////////////////////////////////////////////////////////////// +// TGA_GetFileVersion +// Retrieves the Version of the TGA File +// BYTES 8-23 of a Version 2.0 Footer will be equal +// to "TRUEVISION-XFILE" as ASCII +// Returns - Version number 1 or 2 +__int32 +TGAFile::TGA_GetFileVersion(FILE * fp) + { + long result; + fpos_t pos; + + TGAFOOTER tgaft; + + // Save the Current position of the File Stream + if(fgetpos(fp, &pos)) + { + // Error Quit + return FILEREADERR; + } + + // Seek the last 26 bytes of the file + if(fseek(fp, -26, SEEK_END)) + { + // Error Quit + return FILEREADERR; + } + + // Read in the last 26 Bytes of the File + result = fread(&tgaft, 1, sizeof(TGAFOOTER), fp); + + if(result != sizeof(TGAFOOTER)) + { + m_error = FILEREADERR; + return FILEREADERR; + } + + // Return the File Stream to its initial position + if(fsetpos(fp, &pos)) + { + // Error Quit + return FILEREADERR; + } + + // Check for the Marker at the end of the file + if(!strcspn(tgaft.Signature, "TRUEVISION-XFILE")) + { + // Marker found its V2.0 TGA + return TGA_VERSIONTWO; + } + + // No Marker was found Assume V1.0 TGA + return TGA_VERSIONONE; + } + + +//////////////////////////////////////////////////////////////////////////////////// +// TGA_getPixelValue +// Retreve a pixel value from the buffer and parse +// the value if its RLE encoded. Returns the RGB +// value of the pixel. +// Retruns - TRUE on success +BOOL +TGAFile::TGA_GetPixelValue + ( + BYTE * rRed, + BYTE * rGrn, + BYTE * rBlu, + BYTE * rAlp, + BYTE ** ppTGAData, + UINT32 PixelDepth, + RGBQUAD * CColMap + ) + { + // + // Buffered TGAs are always 32-bit, + // so go direct from file to RGBA + // + *rRed = *((*ppTGAData)++); + *rGrn = *((*ppTGAData)++); + *rBlu = *((*ppTGAData)++); + *rAlp = *((*ppTGAData)++); + + return TRUE; + } + +//////////////////////////////////////////////////////////////////////////////////// +// TGA_getPixelValue +// Retreve a pixel value from the file and parse +// the value if its RLE encoded. Returns the RGB +// value of the pixel. +// Retruns - TRUE on success +BOOL +TGAFile::TGA_GetPixelValue(BYTE * rRed, BYTE * rGrn, BYTE * rBlu, BYTE * rAlp, FILE * fp, UINT32 PixelDepth, RGBQUAD * CColMap) + { + BYTE i, j, k; + long lResult; + + // Check for Run Length Encoding + if((mode & RLENCO) != 0) + { + if(RLECount == 0) + { // Restrat the rum + lResult = fread(&i, 1, 1, fp); + + if(lResult != 1) + { + m_error = FILEREADERR; + return FALSE; + } + RLEFlag = (i & 0x80) >> 7; + + if(RLEFlag == 0) + { // Stream of unencoded pixels + RLECount = i + 1; + } + else + { // Single Pixel Replicated + RLECount = i-127; + } + RLECount--; // ecrement count and get pixel + } + else + { + // I have already read the count and at least the first pixel + RLECount--; + + if(RLEFlag != 0) + { + // Replicated Pixels + goto PixelEncode; + } + } + } + + // Rea the appropiate number of BYTES and break into RGB + switch(PixelDepth) + { + case 8: // Greyscale Read 1 Byte and Triplicate + lResult = fread(&i, 1, 1, fp); + + if(lResult != 1) + { + m_error = FILEREADERR; + return FALSE; + } + Red = i; + Grn = i; + Blu = i; + l = i; + break; + + case 16: // 1 Bit alpha not used + + case 15: // Five bits each for RGB watch byte ordering + lResult = fread(&j, 1, 1, fp); + lResult = lResult + fread(&k, 1, 1, fp); + + // Check for error + if(lResult != 2) + { + m_error = FILEREADERR; + return FALSE; + } + l = j + k * 256; + Blu = (BYTE)(((l >> 10) & 31) << 3); + Grn = (BYTE)(((l >> 5) & 31) << 3); + Red = (BYTE)((l & 31) << 3); + break; + + case 24: // Eight bits each for RGB + lResult = fread(&i, 1, 1, fp); + Red = i; + lResult = lResult + fread(&i, 1, 1, fp); + Grn = i; + lResult = lResult + fread(&i, 1, 1, fp); + Blu = i; + + // opaque alpha (08jan00/bgw) + Alpha = 0xFF; + + // Check for error + if(lResult != 3) + { + m_error = FILEREADERR; + return FALSE; + } + break; + + case 32: // With alpha (08jan00/bgw) + lResult = fread(&i, 1, 1, fp); + Red = i; + lResult = lResult + fread(&i, 1, 1, fp); + Grn = i; + lResult = lResult + fread(&i, 1, 1, fp); + Blu = i; + lResult = lResult + fread(&i, 1, 1, fp); + Alpha = i; + + // Check for error + if(lResult != 4) + { + m_error = FILEREADERR; + return FALSE; + } + break; + + default: // Unknown number of bis per pixel + m_error = INVALIDTGAERR; + return NULL; + } + +PixelEncode: // Set the actual pixel values + + if((mode & MAPPED) == MAPPED) + { + // Remap Color Mapped Pixels + *rRed = CColMap[l].rgbRed; + *rGrn = CColMap[l].rgbGreen; + *rBlu = CColMap[l].rgbBlue; + *rAlp = 0xFF; // opaque always (08jan00/bgw) + } + else + { + // Set Unmapped Values + *rRed = Red; + *rGrn = Grn; + *rBlu = Blu; + *rAlp = Alpha; + } + return TRUE; + } + +extern "C" unsigned char * LoadTGAFile +( + const char * filename, + int * width, + int * height +) +{ + TGAFile tgaFile; + return (unsigned char *)tgaFile.LoadTGA(filename, (UINT32 *)width, (UINT32 *)height); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/TGAFile.h b/xrGameSpy/gamespy/gt2/gt2action/TGAFile.h new file mode 100644 index 00000000000..1dfd7369bb6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/TGAFile.h @@ -0,0 +1,22 @@ +/* TGA File REader Classs Implementation File + This Implementation Allows the reading of TGA (Targa) Files + into an RGB buffer. Also the class allows an RGB Buffer to be + written to a TGA File. There is also a function to determine + the dimensions of a TGA file. + + Created By: Timothy A. Bish + Created On: 08/17/98 + +*/ + +#ifndef TGAFILEH +#define TGAFILEH + +unsigned char * LoadTGAFile +( + const char * filename, + int * width, + int * height +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aClient.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aClient.c new file mode 100644 index 00000000000..9c8c94d75b0 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aClient.c @@ -0,0 +1,715 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include +#include +#include "gt2aMain.h" +#include "gt2aClient.h" +#include "gt2aParse.h" +#include "gt2aDisplay.h" +#include "gt2aSound.h" + +#define CLIENT_THINK_TIME 30 + +static GT2Socket Socket; // The socket used to connect to the server +static GT2Connection Connection; // The connection to the server. +float localRotation; // The local rotation, >=0, <360. +char serverAddress[128]; // Address of the server. +int localMotion; // STILL, FORWARD, BACKWARD. +int localTurning; // STILL, LEFT, RIGHT. +Player players[MAX_PLAYERS]; // The list of players. +GT2Bool connected; // True once we received the start message. +int localIndex = -1; // The local player's index into the players table. +unsigned long lastServerUpdate; // The last time we received an update from the server. +char localNick[MAX_NICK] = "Player"; // The local player's nick. +CObject cObjects[MAX_OBJECTS]; // The list of objects. +UpdateInfo updateHistory[UPDATE_HISTORY_LEN]; // Time diff for past updates +int updateHistoryStart; // The starting index of the history. +int ClientNumAsteroids; // The number of asteroids we're holding. +static unsigned short nextServerUpdateID; // The expected ID of the next update. +static unsigned short nextClientUpdateID; // The ID of our next update. + +// Stats. +///////// +int reliableBytesSentClient; +int reliableBytesReceivedClient; +int unreliableBytesSentClient; +int unreliableBytesReceivedClient; +int reliableMessagesSentClient; +int reliableMessagesReceivedClient; +int unreliableMessagesSentClient; +int unreliableMessagesReceivedClient; + +static void ClientSocketErrorCallback +( + GT2Socket socket +) +{ + printf("Server socket error\n"); + GSI_UNUSED(socket); +} + +static void ClientConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + if(result != GT2Success) + { + printf("Connection failed (%d", result); + if(result == GT2Rejected) + printf(": %s)\n", message); + else + printf(")\n"); + exit(1); + } + GSI_UNUSED(len); + GSI_UNUSED(connection); +} + +static void ClientReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + char buffer[MAX_NICK + 16]; + GTMessageType type; + int rcode; + + // Check for no message. + //////////////////////// + if(!message) + return; + + // Get the message type. + //////////////////////// + type = gtEncodedMessageType((char *)message); + + // New client? + ////////////// + if(type == MSG_S_ADDCLIENT) + { + byte newPlayerIndex; + Player * newPlayer; + char nick[MAX_NICK]; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_S_ADDCLIENT_STR, (char *)message, len, + &newPlayerIndex, + nick); + if(rcode == -1) + return; + + // Check the index. + /////////////////// + assert((newPlayerIndex >= 0) && (newPlayerIndex < MAX_PLAYERS)); + if((newPlayerIndex < 0) || (newPlayerIndex >= MAX_PLAYERS)) + return; + assert(!players[newPlayerIndex].used); + + // Add the client. + ////////////////// + newPlayer = &players[newPlayerIndex]; + memset(newPlayer, 0, sizeof(Player)); + newPlayer->used = GT2True; + + // Set the nick. + //////////////// + strncpy(newPlayer->nick, nick, MAX_NICK); + newPlayer->nick[MAX_NICK - 1] = '\0'; + + // Display a join message. + ////////////////////////// + sprintf(buffer, "%s joined", newPlayer->nick); + DisplayChat(buffer); + } + // Delete client? + ///////////////// + else if(type == MSG_S_DELCLIENT) + { + byte delPlayerIndex; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_S_DELCLIENT_STR, (char *)message, len, + &delPlayerIndex); + if(rcode == -1) + return; + + // Check the index. + /////////////////// + assert((delPlayerIndex >= 0) && (delPlayerIndex < MAX_PLAYERS)); + if((delPlayerIndex < 0) || (delPlayerIndex >= MAX_PLAYERS)) + return; + assert(players[delPlayerIndex].used); + + // Display a part message. + ////////////////////////// + sprintf(buffer, "%s left", players[delPlayerIndex].nick); + DisplayChat(buffer); + + // Delete the client. + ///////////////////// + players[delPlayerIndex].used = GT2False; + } + // Connection attempt finished? + /////////////////////////////// + else if(type == MSG_S_START) + { + byte index; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_S_START_STR, (char *)message, len, + &index); + if(rcode == -1) + return; + + // Check the index. + /////////////////// + assert((index >= 0) && (index < MAX_PLAYERS)); + if((index < 0) || (index >= MAX_PLAYERS)) + return; + + // Set the local index. + /////////////////////// + localIndex = index; + + // We finished connecting. + ////////////////////////// + connected = GT2True; + } + // Server update? + ///////////////// + else if(type == MSG_S_UPDATE) + { + Player * player; + CObject * object; + byte updatedClients; + byte updatedObjects; + byte index; + unsigned short packedPosition[2]; + int score; + byte forward; + byte backward; + byte right; + byte left; + byte dead; + byte type; + int time; + int i; + unsigned long now; + unsigned long diff; + unsigned short updateID; + unsigned short packedRotation; + + // We got an update. + //////////////////// + now = current_time(); + diff = (now - lastServerUpdate); + lastServerUpdate = now; + + // Decode the header. + ///////////////////// + rcode = gtDecode(MSG_S_UPDATE_STR, (char *)message, len, + &updateID, + &updatedClients, + &updatedObjects); + if(rcode == -1) + return; + message += rcode; + len -= rcode; + + // Check for first update. + ////////////////////////// + if(updateHistoryStart == -1) + { + nextServerUpdateID = (updateID + 1); + updateHistoryStart = 0; + } + else + { + int numDropped; + UpdateInfo * info; + + // Check for out of order. + ////////////////////////// + if(updateID < nextServerUpdateID) + return; + + // Fill in the dropped updates. + /////////////////////////////// + numDropped = (updateID - nextServerUpdateID); + nextServerUpdateID = (updateID + 1); + + // Fill in the dropped updates. + /////////////////////////////// + while(numDropped--) + { + info = &updateHistory[updateHistoryStart++]; + updateHistoryStart %= UPDATE_HISTORY_LEN; + + info->diff = -1; + info->len = 0; + } + + // Fill in this update. + /////////////////////// + info = &updateHistory[updateHistoryStart++]; + updateHistoryStart %= UPDATE_HISTORY_LEN; + + info->diff = diff; + info->len = (len + rcode); + } + + // Go through each updated client. + ////////////////////////////////// + for(i = 0 ; i < updatedClients ; i++) + { + // Decode the update. + ///////////////////// + rcode = gtDecodeNoType(MSG_S_UPDATE_CLIENT_STR, (char *)message, len, + &index, + &packedPosition[0], + &packedPosition[1], + &packedRotation, + &score, + &forward, + &backward, + &right, + &left, + &dead); + if(rcode == -1) + return; + message += rcode; + len -= rcode; + + // Check the index. + /////////////////// + assert(index >= 0); + assert(index < MAX_PLAYERS); + if((index < 0) || (index >= MAX_PLAYERS)) + return; + + // Cache the player. + //////////////////// + player = &players[index]; + + // Copy the values in. + ////////////////////// + SetV2f( + player->position, + UnsignedShortToPosition(packedPosition[0]), + UnsignedShortToPosition(packedPosition[1])); + player->rotation = UnsignedShortToRotation(packedRotation); + player->score = score; + if(forward) + player->motion = FORWARD; + else if(backward) + player->motion = BACKWARD; + else + player->motion = STILL; + if(right) + player->turning = RIGHT; + else if(left) + player->turning = LEFT; + else + player->turning = STILL; + player->dead = dead; + + // Update the roll. + /////////////////// + if(player->dead) + { + player->roll = 0; + } + else if(left) + { + if(player->roll > -1) + { + player->roll -= (diff / 1000.0); + if(player->roll < -1) + player->roll = -1; + } + } + else if(right) + { + if(player->roll < 1) + { + player->roll += (diff / 1000.0); + if(player->roll > 1) + player->roll = 1; + } + } + else if(player->roll > 0) + { + player->roll -= (diff / 1000.0); + if(player->roll < 0) + player->roll = 0; + } + else if(player->roll < 0) + { + player->roll += (diff / 1000.0); + if(player->roll > 0) + player->roll = 0; + } + } + + // Go through the objects. + ////////////////////////// + for(i = 0 ; i < updatedObjects ; i++) + { + // Decode the object. + ///////////////////// + rcode = gtDecodeNoType(MSG_S_UPDATE_OBJECT_STR, (char *)message, len, + &type, + &packedPosition[0], + &packedPosition[1], + &packedRotation, + &time); + if(rcode == -1) + return; + message += rcode; + len -= rcode; + + // Cache the object. + //////////////////// + object = &cObjects[i]; + object->used = GT2True; + + // Copy in the values. + ////////////////////// + object->type = type; + SetV2f( + object->position, + UnsignedShortToPosition(packedPosition[0]), + UnsignedShortToPosition(packedPosition[1])); + object->rotation = UnsignedShortToRotation(packedRotation); + object->totalTime = time; + } + + // Mark the rest of the objects as unused. + ////////////////////////////////////////// + for( ; i < MAX_OBJECTS ; i++) + cObjects[i].used = GT2False; + } + // Chat? + //////// + else if(type == MSG_S_CHAT) + { + char buffer[256]; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_S_CHAT_STR, (char *)message, len, + &buffer); + if(rcode == -1) + return; + + // We got a chat message. + ///////////////////////// + DisplayChat(buffer); + } + // Sound? + ///////// + else if(type == MSG_S_SOUND) + { + byte sound; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_S_SOUND_STR, (char *)message, len, + &sound); + if(rcode == -1) + return; + + // We got a sound event. + //////////////////////// + PlaySoundEffect(sound); + } + // NumAsteroids? + //////////////// + else if(type == MSG_S_NUMASTEROIDS) + { + byte total; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_S_NUMASTEROIDS_STR, (char *)message, len, + &total); + if(rcode == -1) + return; + + // We got a new total. + ////////////////////// + ClientNumAsteroids = total; + } + GSI_UNUSED(reliable); + GSI_UNUSED(connection); +} + +static void ClientClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + printf("Connection closed (%d)\n", reason); + GSI_UNUSED(connection); +} + +void SendUpdate +( + void +) +{ + if(connected) + { + char buffer[64]; + int rcode; + + // Encode the messsage. + /////////////////////// + rcode = gtEncode(MSG_C_UPDATE, MSG_C_UPDATE_STR, buffer, sizeof(buffer), + nextClientUpdateID++, + RotationToUnsignedShort(localRotation), + localMotion == FORWARD ? 1 : 0, + localMotion == BACKWARD ? 1 : 0, + localTurning == RIGHT ? 1 : 0, + localTurning == LEFT ? 1 : 0); + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(Connection, (GT2Byte *)buffer, rcode, GT2False); + } + } +} + +void SendPress +( + const char * value +) +{ + if(connected) + { + char buffer[32]; + int rcode; + + // Encode the message. + ////////////////////// + rcode = gtEncode(MSG_C_PRESS, MSG_C_PRESS_STR, buffer, sizeof(buffer), + value); + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(Connection, (GT2Byte *)buffer, rcode, GT2True); + } + } +} + +void SendChat +( + const char * message +) +{ + if(connected) + { + char buffer[CHAT_MAX + 8]; + int rcode; + + // Encode the message. + ////////////////////// + rcode = gtEncode(MSG_C_CHAT, MSG_C_CHAT_STR, buffer, sizeof(buffer), + message); + + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(Connection, (GT2Byte *)buffer, rcode, GT2True); + } + } +} + +void ClientThink +( + unsigned long now +) +{ + static unsigned long lastUpdate; + static unsigned long lastTurn; + unsigned long diff; + + // Think. + ///////// + gt2Think(Socket); + + // Are we connected? + //////////////////// + if(!connected) + return; + + // For the first update, just set the time. + /////////////////////////////////////////// + if(!lastUpdate) + { + lastUpdate = now; + return; + } + + // How long since the last update? + ////////////////////////////////// + diff = (now - lastUpdate); + + // Check for an update. + /////////////////////// + if(diff >= CLIENT_THINK_TIME) + { + // Send an update. + ////////////////// + SendUpdate(); + + // Update the last send time. + ///////////////////////////// + lastUpdate = now; + } + + // How long since the last turn? + //////////////////////////////// + diff = (now - lastTurn); + + // Update our rotation. + /////////////////////// + if((localIndex != -1) && !players[localIndex].dead) + localRotation = ComputeNewRotation(localRotation, localTurning, diff, PLAYER_TURN_SPEED); + + // Update the last turn time. + ///////////////////////////// + lastTurn = now; +} + +static void ClientSendMonitor +( + GT2Connection connection, + int filterID, + const GT2Byte * message, + int len, + GT2Bool reliable +) +{ + // Update stats. + //////////////// + if(reliable) + { + reliableBytesSentClient += len; + reliableMessagesSentClient++; + } + else + { + unreliableBytesSentClient += len; + unreliableMessagesSentClient++; + } + + // We're done with the message. + /////////////////////////////// + gt2FilteredSend(connection, filterID, message, len, reliable); +} + +static void ClientReceiveMonitor +( + GT2Connection connection, + int filterID, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + // Update stats. + //////////////// + if(reliable) + { + reliableBytesReceivedClient += len; + reliableMessagesReceivedClient++; + } + else + { + unreliableBytesReceivedClient += len; + unreliableMessagesReceivedClient++; + } + + // We're done with the message. + /////////////////////////////// + gt2FilteredReceive(connection, filterID, message, len, reliable); +} + +GT2Bool InitializeClient +( + void +) +{ + GT2ConnectionCallbacks connectionCallbacks; + GT2Result result; + char buffer[256]; + int rcode; + + // Setup callback structs. + ////////////////////////// + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.connected = ClientConnectedCallback; + connectionCallbacks.received = ClientReceivedCallback; + connectionCallbacks.closed = ClientClosedCallback; + + // Init stuff. + ////////////// + lastServerUpdate = 0; + updateHistoryStart = -1; + nextServerUpdateID = 0; + nextClientUpdateID = 0; + + // If there was no server, we're connecting to ourselves. + ///////////////////////////////////////////////////////// + if(!serverAddress[0]) + strcpy(serverAddress, "127.0.0.1" PORT_STRING); + + // Create the socket. + ///////////////////// + result = gt2CreateSocket(&Socket, NULL, 0, 0, ClientSocketErrorCallback); + if(result != GT2Success) + return GT2False; + + // Setup the initial data. + ////////////////////////// + rcode = gtEncode(MSG_C_INITIAL, MSG_C_INITIAL_STR, buffer, sizeof(buffer), + localNick); + if(rcode == -1) + return GT2False; + + // Connect. + /////////// + result = gt2Connect(Socket, &Connection, serverAddress, (GT2Byte *)buffer, rcode, 0, &connectionCallbacks, GT2False); + if(result != GT2Success) + return GT2False; + + // Add our traffic monitors. + //////////////////////////// + gt2AddSendFilter(Connection, ClientSendMonitor); + gt2AddReceiveFilter(Connection, ClientReceiveMonitor); + + return (Connection != NULL); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aClient.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aClient.h new file mode 100644 index 00000000000..f6ef701e91d --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aClient.h @@ -0,0 +1,92 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2ACLIENT_H_ +#define _GT2ACLIENT_H_ + +#include "gt2aMath.h" +#include "gt2aLogic.h" + +#define UPDATE_HISTORY_LEN 250 + +typedef struct Player +{ + GT2Bool used; // If this slot is in use or not. + V2f position; // The current position (0 <= x,y < MAP_MAX). + float rotation; // Client's view angle (0 <= rotation < 360). + int motion; // The client's current motion (STILL, FORWARD, BACKWARD). + int turning; // The client's current tunring direction (STILL, LEFT, RIGHT). + char nick[MAX_NICK]; // The client's nick. + int score; // The client's score. + GT2Bool dead; // True if this client is currently dead. + float roll; // How much to roll them (-1->0->1). +} Player; + +typedef struct CObject +{ + GT2Bool used; // If this slot is in use or not. + ObjectType type; // The type of object. + V2f position; // The object's position. + float rotation; // The object's rotation. + unsigned long totalTime; // The amount of time this object has existed. +} CObject; + +typedef struct UpdateInfo +{ + int diff; // Time since the last update was received. + int len; // Length of the update, in bytes. +} UpdateInfo; + +extern float localRotation; +extern char serverAddress[128]; +extern int localMotion; +extern int localTurning; +extern Player players[MAX_PLAYERS]; +extern GT2Bool connected; +extern int localIndex; +extern unsigned long lastServerUpdate; +extern char localNick[MAX_NICK]; +extern CObject cObjects[MAX_OBJECTS]; +extern UpdateInfo updateHistory[UPDATE_HISTORY_LEN]; +extern int updateHistoryStart; +extern int ClientNumAsteroids; + +// Stats. +///////// +extern int reliableBytesSentClient; +extern int reliableBytesReceivedClient; +extern int unreliableBytesSentClient; +extern int unreliableBytesReceivedClient; +extern int reliableMessagesSentClient; +extern int reliableMessagesReceivedClient; +extern int unreliableMessagesSentClient; +extern int unreliableMessagesReceivedClient; + +GT2Bool InitializeClient +( + void +); + +void ClientThink +( + unsigned long now +); + +void SendPress +( + const char * value +); + +void SendChat +( + const char * message +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aDisplay.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aDisplay.c new file mode 100644 index 00000000000..c8173f393d2 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aDisplay.c @@ -0,0 +1,1655 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include "gt2aMain.h" +#include "gt2aDisplay.h" +#include "gt2aClient.h" +#include "gt2aMath.h" +#include "gt2aInput.h" +#include "gt2aLogic.h" +#include "TGAFile.h" + +#define TITLE "GameSpy GT2Action by Dan 'Mr. Pants' Schoenblum" +#define FONT GLUT_STROKE_ROMAN +#define TEXT_SCALE 10 +#define CHAT_LINES 3 +#define CHAT_SCROLL_TIME (3.5 * 1000) +#define NUM_STARS 1000 +#define FRAME_HISTORY_LEN 250 +#define NUM_ROCKET_TEXTURES 4 +#define NUM_EXPLOSION_TEXTURES 2 +#define NUM_SHIP_TEXTURES 2 +#define NUM_ASTEROID_TEXTURES 3 +#define NUM_MINE_TEXTURES 3 +#define NUM_SPINNER_TEXTURES 3 +#define WINDOW_MIN 0 +#define WINDOW_MAX 10000 +#define POSITION_HISTORY_LEN 5 +#define MAX_FLICKER 50 +#define STARS_SCALE 4 +#define RADAR_SIZE 1500 +#define FULL_VIEW (20000.0 * Zoom) +#define HALF_VIEW (FULL_VIEW / 2.0) +#define ZOOM_IN_SPEED 0.4 +#define ZOOM_OUT_SPEED 0.4 +#define ZOOM_MIN 1.0 +#define ZOOM_MAX 1.5 + +typedef struct Star +{ + V2f position; + V3b color; + byte alpha; + byte flicker; +} Star; + +GT2Bool fullScreen; + +GT2Bool DrawGraphsOption; +GT2Bool DrawUpdateTimeOption = GT2True; +GT2Bool DrawUpdateLengthOption = GT2True; +GT2Bool DrawFrameTimeOption = GT2True; +GT2Bool DrawMarksOption = GT2True; +GT2Bool DrawFPSOption; +GT2Bool DrawWithPredictionOption = GT2True; +GT2Bool DrawBackgroundOption = GT2True; +GT2Bool DrawStarsOption = GT2True; +GT2Bool DrawBoundingCirclesOption = GT2False; +GT2Bool DrawRadarOption = GT2True; +float RadarScaleOption = 1; +float RadarPointScaleOption = 2; +GT2Bool ViewClippingOption = GT2True; + +int screenWidth = 500; +int screenHeight = 500; + +static char chatLines[CHAT_LINES][CHAT_MAX]; +static unsigned long lastChatScroll; + +static unsigned long Now; +static unsigned long Diff; + +static GLuint backgroundTexture; +static GLuint shipTextures[NUM_SHIP_TEXTURES]; +static GLuint explosionTextures[NUM_EXPLOSION_TEXTURES]; +static GLuint rocketTextures[NUM_ROCKET_TEXTURES]; +static GLuint asteroidTextures[NUM_ASTEROID_TEXTURES]; +static GLuint mineTextures[NUM_MINE_TEXTURES]; +static GLuint spinnerTextures[NUM_SPINNER_TEXTURES]; + +static Star stars[NUM_STARS]; + +static int FrameHistory[FRAME_HISTORY_LEN]; +static int FrameHistoryStart; + +static V2f localPosition; + +static float Zoom = 1.0; + +static void ScrollChat +( + void +) +{ + int i; + + // First find where to start the copying. + ///////////////////////////////////////// + for(i = 0 ; i < (CHAT_LINES - 1) ; i++) + if(!chatLines[i][0]) + break; + + // Move all lines 1 step towards the end of the array. + ////////////////////////////////////////////////////// + for( ; i > 0 ; i--) + strcpy(chatLines[i], chatLines[i - 1]); + + // Clear the first line. + //////////////////////// + chatLines[0][0] = '\0'; +} + +static void RemoveOldestChat +( + void +) +{ + int i; + + // No lines? + //////////// + if(!chatLines[0][0]) + return; + + // Find the oldest line. + //////////////////////// + for(i = (CHAT_LINES - 1) ; !chatLines[i][0] && (i > 0) ; i--); + + // Remove it. + ///////////// + chatLines[i][0] = '\0'; +} + +static void AddChatLine +( + const char * message +) +{ + // Do scrolling. + //////////////// + ScrollChat(); + + // Copy in the new line. + //////////////////////// + strncpy(chatLines[0], message, CHAT_MAX); + chatLines[0][CHAT_MAX - 1] = '\0'; + + // Update the scroll time. + ////////////////////////// + lastChatScroll = current_time(); +} + +static int GetStringWidth +( + const char * string +) +{ + int width = 0; + + if(!string) + return 0; + + while(*string) + width += glutStrokeWidth(FONT, *string++); + + return (width * TEXT_SCALE); +} + +static void DrawString +( + const char * string, + int x, + int y, + const V3b color, + float scale +) +{ + scale *= TEXT_SCALE; + glColor3ubv(color); + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(scale, scale, 1); + while(*string) + glutStrokeCharacter(FONT, *string++); + glPopMatrix(); +} + +static int GetCharacterWidth +( + char ch +) +{ + int width; + + width = glutStrokeWidth(FONT, ch); + width *= TEXT_SCALE; + + return width; +} + +static void DrawCharacter +( + char ch, + int x, + int y, + const V3b color +) +{ + glColor3ubv(color); + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(TEXT_SCALE, TEXT_SCALE, 1); + glutStrokeCharacter(FONT, ch); + glPopMatrix(); +} + +void DisplayChat +( + const char * message +) +{ + // Add this to the chat buffer. + /////////////////////////////// + AddChatLine(message); +} + +static void DrawChat +( + void +) +{ + const char * str; + int x; + int y; + int i; + float scale; + + // Settings. + //////////// + x = 100; + y = 200; + scale = 0.3; + + // Draw all the chat messages. + ////////////////////////////// + for(i = 0 ; (i < CHAT_LINES) && chatLines[i][0] ; i++) + { + DrawString(chatLines[i], x, y, White, scale); + y += 500; + } + + // Get the current chat buffer. + /////////////////////////////// + str = GetChatBuffer(); + if(str) + DrawString(str, x, WINDOW_MAX - 500, White, scale); +} + +static void DrawBoundingCircle +( + float radius +) +{ + // Check the bounding circles option. + ///////////////////////////////////// + if(DrawBoundingCirclesOption) + { + int i; + V2f point; + + // Draw in white. + ///////////////// + glColor3f(1, 1, 1); + + // Draw the circle (circle, sphere, whatever). + ////////////////////////////////////////////// +#if 1 + glBegin(GL_LINE_LOOP); + for(i = 0 ; i < 360 ; i += 30) + { + RotationToVector(point, i); + ScaleV2f(point, point, radius); + glVertex2fv(point); + } + glEnd(); +#else + glutWireSphere(radius, 16, 16); +#endif + + // Draw the forward line. + ///////////////////////// + glBegin(GL_LINES); + glVertex2f(0, 0); + glVertex2f(0, radius * 2); + glEnd(); + } +} + +static void DrawPlayer +( + Player * player, + const V2f position, + float rotation +) +{ + int width; + static const float textScale = 0.25; + V2f textPosition; + float diff; + static char text[MAX_NICK + 32]; + + // Get the text to show. + //////////////////////// + sprintf(text, "%s: %d", player->nick, player->score); + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glTranslatef(position[0], position[1], 0); + + width = GetStringWidth(text); + width *= textScale; + textPosition[0] = -(width / 2); +#if 0 + textPosition[1] = 700; +#else + if((position[0] + textPosition[0]) < 20) + textPosition[0] = (20 - position[0]); + diff = (MAP_MAX - (position[0] + textPosition[0] + width)); + if(diff < 0) + textPosition[0] += diff; + if(position[1] < (MAP_MAX - 1000)) + textPosition[1] = 700; + else + textPosition[1] = -1000; +#endif + DrawString(text, textPosition[0], textPosition[1], White, textScale); + + if(!player->dead) + { + glRotatef(rotation, 0, 0, -1); + + glPushMatrix(); + if(player->roll) + { + glScalef(1, 1, .005); + glRotatef(35 * player->roll, 0, 1, 0); + } + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + + if(player->motion) + glBindTexture(GL_TEXTURE_2D, shipTextures[1]); + else + glBindTexture(GL_TEXTURE_2D, shipTextures[0]); + + glColor4f(1, 1, 1, 1); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-500, -300); + glTexCoord2f(1, 0); + glVertex2f(500, -300); + glTexCoord2f(1, 1); + glVertex2f(500, 700); + glTexCoord2f(0, 1); + glVertex2f(-500, 700); + glEnd(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glPopMatrix(); + } + + DrawBoundingCircle(PLAYER_RADIUS); + glPopMatrix(); +} + +static void Predict +( + V2f newPosition, + float * rotation, + Player * player +) +{ + GT2Bool local; + + assert(newPosition); + assert(rotation); + assert(player); + + // Is this the local player? + //////////////////////////// + local = (player == &players[localIndex]); + + // Should we predict? + ///////////////////// + if(DrawWithPredictionOption && !player->dead && player->motion) + { + // Predict new position. + //////////////////////// + ComputeNewPosition( + newPosition, + player->position, + player->motion, + player->rotation, + Diff, + PLAYER_SPEED, + GT2True); + + // Predict rotation if not local. + ///////////////////////////////// + if(!local) + *rotation = ComputeNewRotation(player->rotation, player->turning, Diff, PLAYER_TURN_SPEED); + } + else + { + // Just use the actual position. + //////////////////////////////// + CopyV2f(newPosition, player->position); + + // Use the real rotation if not local. + ////////////////////////////////////// + if(!local) + *rotation = player->rotation; + } + + // If local, use our rotation. + ////////////////////////////// + if(local) + *rotation = localRotation; +} + +static void DrawPlayers +( + void +) +{ + int i; + Player * player; + V2f position; + float rotation; + float distance; + + // First draw the other players. + //////////////////////////////// + for(i = 0 ; i < MAX_PLAYERS ; i++) + { + player = &players[i]; + + // Check if we need to draw the player. + /////////////////////////////////////// + if(player->used && (i != localIndex)) + { + // Predict the new position. + //////////////////////////// + Predict(position, &rotation, player); + + // Check if the players are close enough. + ///////////////////////////////////////// + if(ViewClippingOption) + { + distance = DistanceV2f(localPosition, position); + if(distance >= FULL_VIEW) + continue; + } + + // Do the actual drawing. + ///////////////////////// + DrawPlayer(player, position, rotation); + } + } + + // Draw the local player. + ///////////////////////// + assert((localIndex >= 0) && (localIndex < MAX_PLAYERS)); + player = &players[localIndex]; + + // Do the actual drawing. + // The position was already set in SetMapView. + ////////////////////////////////////////////// + DrawPlayer(player, localPosition, localRotation); +} + +static void DrawRocket +( + CObject * rocket +) +{ + V2f position; + + // Are we using prediction? + /////////////////////////// + if(DrawWithPredictionOption) + { + // Predict new position. + //////////////////////// + ComputeNewPosition( + position, + rocket->position, + FORWARD, + rocket->rotation, + Diff, + ROCKET_SPEED, + GT2False); + } + else + { + // Just use the actual position. + //////////////////////////////// + CopyV2f(position, rocket->position); + } + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glTranslatef(position[0], position[1], 0); + + glRotatef(rocket->rotation, 0, 0, -1); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + + glBindTexture(GL_TEXTURE_2D, rocketTextures[RandomInt(0, NUM_ROCKET_TEXTURES - 1)]); + + glColor4f(1, 1, 1, 1); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-350, -350); + glTexCoord2f(1, 0); + glVertex2f(350, -350); + glTexCoord2f(1, 1); + glVertex2f(350, 350); + glTexCoord2f(0, 1); + glVertex2f(-350, 350); + glEnd(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + + DrawBoundingCircle(ROCKET_RADIUS); + glPopMatrix(); +} + +static void DrawMine +( + CObject * mine +) +{ + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glTranslatef(mine->position[0], mine->position[1], 0); + + glRotatef(mine->rotation, 0, 0, -1); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + + glBindTexture(GL_TEXTURE_2D, mineTextures[(int)mine->position[0] % NUM_MINE_TEXTURES]); + + glColor4f(1, 1, 1, 1); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-800, -800); + glTexCoord2f(1, 0); + glVertex2f(800, -800); + glTexCoord2f(1, 1); + glVertex2f(800, 800); + glTexCoord2f(0, 1); + glVertex2f(-800, 800); + glEnd(); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + + DrawBoundingCircle(MINE_RADIUS); + glPopMatrix(); +} + +static void DrawAsteroid +( + CObject * asteroid +) +{ + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glTranslatef(asteroid->position[0], asteroid->position[1], 0); + + glRotatef(asteroid->rotation, 0, 0, -1); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + + //glBindTexture(GL_TEXTURE_2D, asteroidTextures[(int)asteroid->position[0] % NUM_ASTEROID_TEXTURES]); + glBindTexture(GL_TEXTURE_2D, asteroidTextures[1]); + + glColor4f(1, 1, 1, 1); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-800, -800); + glTexCoord2f(1, 0); + glVertex2f(800, -800); + glTexCoord2f(1, 1); + glVertex2f(800, 800); + glTexCoord2f(0, 1); + glVertex2f(-800, 800); + glEnd(); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + + DrawBoundingCircle(ASTEROID_RADIUS); + glPopMatrix(); +} + +static void DrawExplosion +( + CObject * explosion +) +{ + unsigned long totalTime; + + totalTime = (explosion->totalTime + Diff); + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glTranslatef(explosion->position[0], explosion->position[1], 0); + + glPushMatrix(); + glScalef(totalTime / 100.0, totalTime / 100.0, 1); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + + glColor4f(1, 1, 1, 1); + + glBindTexture(GL_TEXTURE_2D, explosionTextures[1]); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-700, -700); + glTexCoord2f(1, 0); + glVertex2f(700, -700); + glTexCoord2f(1, 1); + glVertex2f(700, 700); + glTexCoord2f(0, 1); + glVertex2f(-700, 700); + glEnd(); + + glRotatef(totalTime, 0, 0, -1); + + glBindTexture(GL_TEXTURE_2D, explosionTextures[0]); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-700, -700); + glTexCoord2f(1, 0); + glVertex2f(700, -700); + glTexCoord2f(1, 1); + glVertex2f(700, 700); + glTexCoord2f(0, 1); + glVertex2f(-700, 700); + glEnd(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glPopMatrix(); + + DrawBoundingCircle(EXPLOSION_RADIUS); + glPopMatrix(); +} + +static void DrawObjects +( + void +) +{ + int i; + CObject * object; + float distance; + + // Draw all the objects. + //////////////////////// + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + object = &cObjects[i]; + + // Is the object in use? + //////////////////////// + if(object->used) + { + if(ViewClippingOption) + { + // Is the player close enough to see it? + //////////////////////////////////////// + distance = DistanceV2f(localPosition, object->position); + if(distance >= FULL_VIEW) + continue; + } + + // Draw it based on type. + ///////////////////////// + if(object->type == ObjectRocket) + DrawRocket(object); + else if(object->type == ObjectMine) + DrawMine(object); + else if(object->type == ObjectAsteroid) + DrawAsteroid(object); + else if(object->type == ObjectExplosion) + DrawExplosion(object); + } + } +} + +static void DrawConnecting +( + void +) +{ + static const char * text = "Connecting"; + static int width = -1; + static const V3b textColor = { 0, 204, 0}; + static unsigned long lastSpin; + static int spinnerIndex = -1; + static const char * spinnerText = "|/-\\"; + static const V3b spinnerColor = { 0, 204, 0 }; + char spinnerChar; + int spinnerX; + + // Get the width of the string if we don't already have it. + /////////////////////////////////////////////////////////// + if(width == -1) + width = GetStringWidth(text); + + // Draw the string. + /////////////////// + DrawString(text, (WINDOW_MAX - width) / 2, (WINDOW_MAX / 2), textColor, 1); + + // Init if its the first time. + ////////////////////////////// + if(spinnerIndex == -1) + { + spinnerIndex = 0; + lastSpin = Now; + } + // Check if its time to spin the spinner. + ///////////////////////////////////////// + else if((Now - lastSpin) >= 250) + { + spinnerIndex++; + spinnerIndex %= 4; + lastSpin = Now; + } + + // Get the char to show. + //////////////////////// + spinnerChar = spinnerText[spinnerIndex]; + + // Get the x position of the char. + ////////////////////////////////// + spinnerX = ((WINDOW_MAX - GetCharacterWidth(spinnerChar)) / 2); + + // Draw the spinner. + //////////////////// + DrawCharacter(spinnerChar, spinnerX, 3000, spinnerColor); +} + +static int ReadLittleInt +( + FILE * file +) +{ + byte bytes[4]; + int i; + + if(fread(bytes, 1, 4, file) != 4) + return -1; + + i = bytes[0]; + i |= (bytes[1] << 8); + i |= (bytes[2] << 16); + i |= (bytes[3] << 24); + + return i; +} + +static GT2Bool LoadTexture +( + const char * filename, + GLuint * texture, + GT2Bool useAlpha +) +{ + int width; + int height; + GLubyte * bytes; + int len; + int i; + GLubyte temp; + int format; + + // Load the file. + ///////////////// + bytes = LoadTGAFile(filename, &width, &height); + if(!bytes) + return GT2False; + + // Convert from BGRA to RGBA. + ///////////////////////////// + len = (width * height * 4); + for(i = 0 ; i < len ; i += 4) + { + temp = bytes[i]; + bytes[i] = bytes[i + 2]; + bytes[i + 2] = temp; + } + + // Generate and bind the texture. + ///////////////////////////////// + glGenTextures(1, texture); + glBindTexture(GL_TEXTURE_2D, *texture); + + // Load it from memory. + /////////////////////// + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if(useAlpha) + format = 4; + else + format = 3; + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bytes); + + // Set to decal mode. + ///////////////////// + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // Setup the min/mag filters. + ///////////////////////////// + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + free(bytes); + + return GT2True; +} + +static void DrawBackground +( + void +) +{ + if(!DrawBackgroundOption) + return; + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, backgroundTexture); + + glColor4f(1, 1, 1, 1); + + glBegin(GL_QUADS); +#if 0 + glTexCoord2f(0, 0); + glVertex2f(MAP_MIN, MAP_MIN); + glTexCoord2f(1, 0); + glVertex2f(MAP_MAX, MAP_MIN); + glTexCoord2f(1, 1); + glVertex2f(MAP_MAX, MAP_MAX); + glTexCoord2f(0, 1); + glVertex2f(MAP_MIN, MAP_MAX); +#else + glTexCoord2f(0.01, 0.01); + glVertex2f(MAP_MIN, MAP_MIN); + glTexCoord2f(0.99, 0.01); + glVertex2f(MAP_MAX, MAP_MIN); + glTexCoord2f(0.99, 0.99); + glVertex2f(MAP_MAX, MAP_MAX); + glTexCoord2f(0.01, 0.99); + glVertex2f(MAP_MIN, MAP_MAX); +#endif + glEnd(); + + glDisable(GL_TEXTURE_2D); +} + +static void InitStar +( + unsigned long now, + Star * star +) +{ + int color; + + star->position[0] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + star->position[1] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + + color = RandomInt(0, 19); + if(color < 15) + CopyV3b(star->color, White); + else if(color < 17) + CopyV3b(star->color, Red); + else if(color < 19) + CopyV3b(star->color, Yellow); + else + CopyV3b(star->color, Blue); + star->alpha = RandomInt(0, 255); + star->flicker = RandomInt(1, MAX_FLICKER); +} + +static void DrawStars +( + void +) +{ + int i; + int alpha; + V2f position; + + if(!DrawStarsOption) + return; + + // Figure out the eye position. + /////////////////////////////// + CopyV2f(position, localPosition); + if(position[0] < HALF_VIEW) + position[0] = HALF_VIEW; + else if(position[0] > (MAP_MAX - HALF_VIEW)) + position[0] = (MAP_MAX - HALF_VIEW); + if(position[1] < HALF_VIEW) + position[1] = HALF_VIEW; + else if(position[1] > (MAP_MAX - HALF_VIEW)) + position[1] = (MAP_MAX - HALF_VIEW); + + // Draw the stars. + ////////////////// + glEnable(GL_BLEND); + glPushMatrix(); + glTranslatef(position[0] / STARS_SCALE, position[1] / STARS_SCALE, 0); + + glBegin(GL_POINTS); + for(i = 0 ; i < NUM_STARS ; i++) + { + alpha = stars[i].alpha; + alpha += RandomInt(-stars[i].flicker, stars[i].flicker); + alpha = ClampInt(alpha, 0, 255); + glColor4ub(stars[i].color[0], stars[i].color[1], stars[i].color[2], (byte)alpha); + glVertex2fv(stars[i].position); + } + glEnd(); + glPopMatrix(); + glDisable(GL_BLEND); +} + +static void DrawSpinner +( + void +) +{ + float rotation; + float scale; + + scale = (Now % 1001); + scale -= 50; + scale /= 50; + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glTranslatef(MAP_HALF, MAP_HALF, 0); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + +#if 1 + glPushMatrix(); + rotation = (Now % 360); + glRotatef(rotation, 0, 0, 1); + glBindTexture(GL_TEXTURE_2D, spinnerTextures[0]); + glColor4f(1, 1, 1, 1); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 0); + glVertex2f(SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 1); + glVertex2f(SPINNER_COORD, SPINNER_COORD); + glTexCoord2f(0, 1); + glVertex2f(-SPINNER_COORD, SPINNER_COORD); + glEnd(); + glPopMatrix(); +#endif + + glPushMatrix(); + rotation = (Now % (360 * 8)); + rotation /= 8; + glRotatef(rotation, 0, 0, 1); + glScalef(scale, -scale, 1); + glBindTexture(GL_TEXTURE_2D, spinnerTextures[2]); + glColor4f(1, 1, 1, 0.8); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 0); + glVertex2f(SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 1); + glVertex2f(SPINNER_COORD, SPINNER_COORD); + glTexCoord2f(0, 1); + glVertex2f(-SPINNER_COORD, SPINNER_COORD); + glEnd(); + glPopMatrix(); + + glPushMatrix(); + rotation = (Now % (360 * 7)); + rotation /= 7; + glRotatef(rotation, 0, 0, 1); + glScalef(scale, -scale, 1); + glBindTexture(GL_TEXTURE_2D, spinnerTextures[1]); + glColor4f(1, 1, 1, 0.8); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 0); + glVertex2f(SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 1); + glVertex2f(SPINNER_COORD, SPINNER_COORD); + glTexCoord2f(0, 1); + glVertex2f(-SPINNER_COORD, SPINNER_COORD); + glEnd(); + glPopMatrix(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + + DrawBoundingCircle(SPINNER_RADIUS); + glPopMatrix(); +} + +static void DrawGraphs +( + void +) +{ + int i; + int diff; + int len; + int maxDiff = 0; + int maxLen = 0; + + if(updateHistoryStart == -1) + return; + + if(!DrawGraphsOption) + return; + + glPushMatrix(); + glScalef(20, 20, 1); + if(DrawUpdateTimeOption) + { + glColor3ubv(Green); + glBegin(GL_LINE_STRIP); + for(i = 0 ; i < UPDATE_HISTORY_LEN ; i++) + { + diff = updateHistory[(updateHistoryStart + i) % UPDATE_HISTORY_LEN].diff; + + if(diff > maxDiff) + maxDiff = diff; + + if(diff == -1) + { + glColor3ubv(Red); + glVertex2f(i * 2, 50); + glColor3ubv(Green); + } + else + { + if(diff == -1) + diff = 0; + glVertex2f(i * 2, diff / 2); + } + } + glEnd(); + } + + if(DrawUpdateLengthOption) + { + glColor3ubv(Purple); + glBegin(GL_LINE_STRIP); + for(i = 0 ; i < UPDATE_HISTORY_LEN ; i++) + { + len = updateHistory[(updateHistoryStart + i) % UPDATE_HISTORY_LEN].len; + + if(len > maxLen) + maxLen = len; + + glVertex2f(i * 2, len / 8); + } + glEnd(); + } + + if(DrawFrameTimeOption) + { + glColor3ubv(Yellow); + glBegin(GL_LINE_STRIP); + for(i = 0 ; i < FRAME_HISTORY_LEN ; i++) + { + diff = FrameHistory[(FrameHistoryStart + i) % FRAME_HISTORY_LEN]; + glVertex2f(i * 2, diff / 2); + } + glEnd(); + } + + if(DrawMarksOption) + { + glColor3ubv(White); + glBegin(GL_LINES); + for(i = 0 ; i < screenHeight; i += 25) + { + glVertex2f(screenWidth - 10, i); + glVertex2f(screenWidth, i); + } + glEnd(); + } + + glPopMatrix(); +} + +static void DrawFPS +( + unsigned long diff +) +{ + if(DrawFPSOption && diff) + { + static int counter; + static char buf[64]; + if(++counter == 10) + { + counter = 0; + sprintf(buf, "FPS: %d", 1000 / diff); + } + DrawString(buf, WINDOW_MAX - 1500, 600, Grey, 0.2); + } + + { + char buf[64]; + sprintf(buf, "%d asteroid%s", ClientNumAsteroids, + (ClientNumAsteroids==1) ? "" : "s"); + DrawString(buf, WINDOW_MAX - 3500, 600, Grey, 0.2); + } +} + +static void DrawRadar +( + void +) +{ + int i; + Player * player; + CObject * object; + GLdouble plane0[4] = { 0, 1, 1, 0 }; + GLdouble plane1[4] = { 1, 0, 1, 0 }; + + if(!DrawRadarOption) + return; + + glPushMatrix(); + // Move to the upper-right corner. + ////////////////////////////////// + glTranslatef( + WINDOW_MAX - (RADAR_SIZE * RadarScaleOption), + WINDOW_MAX - (RADAR_SIZE * RadarScaleOption), + 0); + + // Scale so we can draw in map space. + ///////////////////////////////////// + glScalef( + RADAR_SIZE / MAP_MAX * RadarScaleOption, + RADAR_SIZE / MAP_MAX * RadarScaleOption, + 1); + +#if 1 + // Enable textures. + /////////////////// + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glColor4f(1, 1, 1, 0.5); + + // Draw a background. + ///////////////////// + glBindTexture(GL_TEXTURE_2D, backgroundTexture); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(0, 0); + glTexCoord2f(1, 0); + glVertex2f(MAP_MAX, 0); + glTexCoord2f(1, 1); + glVertex2f(MAP_MAX, MAP_MAX); + glTexCoord2f(0, 1); + glVertex2f(0, MAP_MAX); + glEnd(); + + // Draw the spinner. + //////////////////// + glPushMatrix(); + glTranslatef(MAP_HALF, MAP_HALF, 0); + glRotatef(Now % 3600, 0, 0, 1); + + glBindTexture(GL_TEXTURE_2D, spinnerTextures[0]); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(-SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 0); + glVertex2f(SPINNER_COORD, -SPINNER_COORD); + glTexCoord2f(1, 1); + glVertex2f(SPINNER_COORD, SPINNER_COORD); + glTexCoord2f(0, 1); + glVertex2f(-SPINNER_COORD, SPINNER_COORD); + glEnd(); + glPopMatrix(); + + // Disable textures. + //////////////////// + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); +#endif + + // Draw a box around the radar. + /////////////////////////////// + glColor3ubv(Yellow); + glBegin(GL_LINE_STRIP); + glVertex2f(0, MAP_MAX); + glVertex2f(0, 0); + glVertex2f(MAP_MAX, 0); + glEnd(); + + // Setup the clipping planes. + ///////////////////////////// + glEnable(GL_CLIP_PLANE0); + glEnable(GL_CLIP_PLANE1); + glClipPlane(GL_CLIP_PLANE0, plane0); + glClipPlane(GL_CLIP_PLANE1, plane1); + + // Scale points. + //////////////// + if(RadarPointScaleOption != 1) + glPointSize(RadarPointScaleOption); + + glBegin(GL_POINTS); + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + object = &cObjects[i]; + + if(!object->used) + continue; + + if(object->type == ObjectRocket) + glColor3ubv(Red); + else if(object->type == ObjectMine) + glColor3ubv(Yellow); + else if(object->type == ObjectAsteroid) + glColor3ubv(White); + else + continue; + + glVertex2fv(object->position); + } + + glColor3ubv(Orange); + for(i = 0 ; i < MAX_PLAYERS ; i++) + { + if(i == localIndex) + continue; + + player = &players[i]; + + if(!player->used) + continue; + + glVertex2fv(player->position); + } + + glColor3ubv(Green); + glVertex2fv(players[localIndex].position); + glEnd(); + + // Unscale points. + ////////////////// + if(RadarPointScaleOption != 1) + glPointSize(1); + glPopMatrix(); + + glDisable(GL_CLIP_PLANE0); + glDisable(GL_CLIP_PLANE1); +} + +static void SetMapView +( + void +) +{ + V2f corner; + Player * player; + float rotation; + static V2f positionHistory[POSITION_HISTORY_LEN]; + static int positionHistoryStart = -1; + int i; + + // Get the local player. + //////////////////////// + player = &players[localIndex]; + + // Predict the local player's position. + /////////////////////////////////////// + Predict(localPosition, &rotation, player); + + // Put this position in the history. + //////////////////////////////////// + if(positionHistoryStart == -1) + { + positionHistoryStart = 0; + for(i = 0 ; i < POSITION_HISTORY_LEN ; i++) + CopyV2f(positionHistory[i], localPosition); + } + else + { + CopyV2f(positionHistory[positionHistoryStart++], localPosition); + positionHistoryStart %= POSITION_HISTORY_LEN; + } + + // Average out the position history to get the display position. + //////////////////////////////////////////////////////////////// + SetV2f(localPosition, 0, 0); + for(i = 0 ; i < POSITION_HISTORY_LEN ; i++) + AddV2f(localPosition, localPosition, positionHistory[i]); + ScaleV2f(localPosition, localPosition, (1.0 / POSITION_HISTORY_LEN)); + + // Set the left and bottom of the view. + /////////////////////////////////////// + SubScalarV2f(corner, localPosition, HALF_VIEW); + + // Don't show anything outside the map. + /////////////////////////////////////// + ClampV2f(corner, corner, 0, MAP_MAX - FULL_VIEW); + + glLoadIdentity(); + glViewport(0, 0, screenWidth, screenHeight); + gluOrtho2D(corner[0], corner[0] + FULL_VIEW, corner[1], corner[1] + FULL_VIEW); +} + +static void SetWindowView +( + void +) +{ + glLoadIdentity(); + glViewport(0, 0, screenWidth, screenHeight); + gluOrtho2D(0, WINDOW_MAX, 0, WINDOW_MAX); +} + +static void Display +( + void +) +{ + static unsigned long lastDisplay; + unsigned long now; + unsigned long diff; + + // Get the current time. + //////////////////////// + now = current_time(); + + // Get the time difference. + /////////////////////////// + diff = (now - lastDisplay); + + // Update the history. + ////////////////////// + if(FrameHistoryStart == -1) + FrameHistoryStart = 0; + else + { + FrameHistory[FrameHistoryStart++] = diff; + FrameHistoryStart %= FRAME_HISTORY_LEN; + } + + // New last display. + //////////////////// + lastDisplay = now; + + // Set the zoom. + //////////////// + if(localMotion == STILL) + { + if(Zoom > ZOOM_MIN) + { + Zoom -= (ZOOM_IN_SPEED * diff / 1000); + if(Zoom < ZOOM_MIN) + Zoom = ZOOM_MIN; + } + } + else + { + if(Zoom < ZOOM_MAX) + { + Zoom += (ZOOM_OUT_SPEED * diff / 1000); + if(Zoom > ZOOM_MAX) + Zoom = ZOOM_MAX; + } + } + + // Clear the color buffer. + ////////////////////////// + glClear(GL_COLOR_BUFFER_BIT); + + // We want to know how long since the last server update. + ///////////////////////////////////////////////////////// + Now = now; + Diff = (now - lastServerUpdate); + + // Are we connected to the server? + ////////////////////////////////// + if(connected) + { + // Set the view for drawing in map space. + ///////////////////////////////////////// + SetMapView(); + + // Draw the ground. + /////////////////// + DrawBackground(); + + // Draw some stars. + /////////////////// + DrawStars(); + + // Draw the spinner. + //////////////////// + DrawSpinner(); + + // Draw all the objects. + //////////////////////// + DrawObjects(); + + // Draw all the players. + //////////////////////// + DrawPlayers(); + + // Set the view for drawing in window space. + //////////////////////////////////////////// + SetWindowView(); + + // Draw the radar. + ////////////////// + DrawRadar(); + + // Draw the chat. + ///////////////// + DrawChat(); + + // Draw graphs. + /////////////// + DrawGraphs(); + + // Show the framerate. + ////////////////////// + DrawFPS(diff); + } + else + { + // Set the view for drawing in window space. + //////////////////////////////////////////// + SetWindowView(); + + // Draw the connecting screen. + ////////////////////////////// + DrawConnecting(); + } + + // Saw the front and back buffers. + ////////////////////////////////// + glutSwapBuffers(); +} + +static void Reshape +( + int width, + int height +) +{ + screenWidth = width; + screenHeight = height; + + // Setup a simple 2D orthographic view. + /////////////////////////////////////// + glLoadIdentity(); + glViewport(0, 0, width, height); + gluOrtho2D(0, MAP_MAX, 0, MAP_MAX); +} + +void InitializeDisplay +( + void +) +{ + int i; + unsigned long now; + char buffer[32]; + + // Init glut window. + //////////////////// + + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA); + + if(fullScreen) + { + glutGameModeString("640x480:32"); + glutEnterGameMode(); + //glutFullScreen(); + glutSetCursor(GLUT_CURSOR_NONE); + } + else + { + glutInitWindowSize(screenWidth, screenHeight); + glutInitWindowPosition(200, 200); + glutCreateWindow(TITLE); + } + // Set display callbacks. + ///////////////////////// + glutDisplayFunc(Display); + glutReshapeFunc(Reshape); + + // Set the background color. + //////////////////////////// + glClearColor(0, 0, 0, 0); + + // Smooth points. + ///////////////// + glEnable(GL_POINT_SMOOTH); + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + + // Don't show the backs of polygons. + //////////////////////////////////// + glEnable(GL_CULL_FACE); + + // We always use the same blend. + //////////////////////////////// + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Load textures. + ///////////////// + printf("Loading textures..."); + LoadTexture("images/space.tga", &backgroundTexture, GT2False); + printf("."); + for(i = 0 ; i < NUM_SHIP_TEXTURES ; i++) + { + sprintf(buffer, "images/ship%d.tga", i); + LoadTexture(buffer, &shipTextures[i], GT2True); + printf("."); + } + for(i = 0 ; i < NUM_EXPLOSION_TEXTURES ; i++) + { + sprintf(buffer, "images/explosion%d.tga", i); + LoadTexture(buffer, &explosionTextures[i], GT2True); + printf("."); + } + for(i = 0 ; i < NUM_ROCKET_TEXTURES ; i++) + { + sprintf(buffer, "images/rocket%d.tga", i); + LoadTexture(buffer, &rocketTextures[i], GT2True); + printf("."); + } + for(i = 0 ; i < NUM_ASTEROID_TEXTURES ; i++) + { + sprintf(buffer, "images/asteroid%d.tga", i); + LoadTexture(buffer, &asteroidTextures[i], GT2True); + printf("."); + } + for(i = 0 ; i < NUM_MINE_TEXTURES ; i++) + { + sprintf(buffer, "images/mine%d.tga", i); + LoadTexture(buffer, &mineTextures[i], GT2True); + printf("."); + } + for(i = 0 ; i < NUM_MINE_TEXTURES ; i++) + { + sprintf(buffer, "images/spinner%d.tga", i); + LoadTexture(buffer, &spinnerTextures[i], GT2True); + printf("."); + } + printf("\n"); + + // Get the time. + //////////////// + now = current_time(); + + // Setup stars. + /////////////// + for(i = 0 ; i < NUM_STARS ; i++) + InitStar(now, &stars[i]); + + // Setup frame history. + /////////////////////// + FrameHistoryStart = -1; +} + +void ShutdownDisplay +( + void +) +{ + if(fullScreen) + { + glutLeaveGameMode(); + } +} + +void DisplayThink +( + unsigned long now +) +{ + static unsigned long last; + unsigned long diff; + + // Get the frame time. + ////////////////////// + now = current_time(); + diff = (now - last); + if(diff < 5) + return; + last = now; + + // Is it time to scroll the chat? + ///////////////////////////////// + if((now - lastChatScroll) > CHAT_SCROLL_TIME) + { + RemoveOldestChat(); + lastChatScroll = now; + } + + // Update the frame. + //////////////////// + glutPostRedisplay(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aDisplay.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aDisplay.h new file mode 100644 index 00000000000..885a989b729 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aDisplay.h @@ -0,0 +1,54 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2ADISPLAY_H_ +#define _GT2ADISPLAY_H_ + +extern GT2Bool fullScreen; + +extern GT2Bool DrawGraphsOption; +extern GT2Bool DrawUpdateTimeOption; +extern GT2Bool DrawUpdateLengthOption; +extern GT2Bool DrawFrameTimeOption; +extern GT2Bool DrawMarksOption; +extern GT2Bool DrawFPSOption; +extern GT2Bool DrawWithPredictionOption; +extern GT2Bool DrawBackgroundOption; +extern GT2Bool DrawStarsOption; +extern GT2Bool DrawBoundingCirclesOption; +extern GT2Bool DrawRadarOption; +extern float RadarScaleOption; +extern float RadarPointScaleOption; +extern GT2Bool ViewClippingOption; + +extern int screenWidth; +extern int screenHeight; + +void InitializeDisplay +( + void +); + +void ShutdownDisplay +( + void +); + +void DisplayThink +( + unsigned long now +); + +void DisplayChat +( + const char * message +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aInput.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aInput.c new file mode 100644 index 00000000000..b2a68bd5466 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aInput.c @@ -0,0 +1,634 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include +#include "gt2aMain.h" +#include "gt2aInput.h" +#include "gt2aClient.h" +#include "gt2aDisplay.h" +#include "gt2aSound.h" + +#define TOGGLE(b) { ((b) = !(b)); printf( #b " = %s\n", (b)?"ON":"OFF"); } + +GT2Bool upPressed; +GT2Bool downPressed; +GT2Bool leftPressed; +GT2Bool rightPressed; + +GT2Bool UseJoystick = GT2False; + +void SetKeyboardNormal(void); +void SetKeyboardChat(void); + +static char chatBuffer[CHAT_MAX]; +static int nChatChars; +static GT2Bool chatting; + +static void KeyboardPress +( + unsigned char key, + int x, + int y +) +{ + // Lowercase it. + //////////////// + key = tolower(key); + + switch(key) + { + case 0x1B: // esc + ShutdownDisplay(); + exit(1); + + case 't': + SetKeyboardChat(); + break; + + case 'p': + TOGGLE(DrawWithPredictionOption); + break; + + case 'c': + TOGGLE(ViewClippingOption); + break; + + case 'w': + if(localIndex != -1) + { + char buffer[32]; + Player * player; + + player = &players[localIndex]; + sprintf(buffer, "%.0f %.0f %.0f", player->position[0], player->position[1], player->rotation); + DisplayChat(buffer); + } + break; + + case 'j': + TOGGLE(UseJoystick); + break; + + case 'g': + TOGGLE(DrawGraphsOption); + break; + + case 'r': + TOGGLE(DrawBoundingCirclesOption); + break; + } +} + +static void KeyboardRelease +( + unsigned char key, + int x, + int y +) +{ + // Lowercase it. + //////////////// + key = tolower(key); + + switch(key) + { + case 'b': + SendPress("mine"); + break; + + case ' ': + SendPress("rocket"); + break; + } +} + +static void SpecialKeyboardPress +( + int key, + int dummyx, + int dummyy +) +{ + switch(key) + { + case GLUT_KEY_UP: + upPressed = GT2True; + localMotion = FORWARD; + break; + + case GLUT_KEY_DOWN: + downPressed = GT2True; + localMotion = BACKWARD; + break; + + case GLUT_KEY_LEFT: + leftPressed = GT2True; + localTurning = LEFT; + break; + + case GLUT_KEY_RIGHT: + rightPressed = GT2True; + localTurning = RIGHT; + break; + } +} + +static void SpecialKeyboardRelease +( + int key, + int dummyx, + int dummyy +) +{ + switch(key) + { + case GLUT_KEY_UP: + upPressed = GT2False; + if(downPressed) + localMotion = BACKWARD; + else + localMotion = STILL; + break; + + case GLUT_KEY_DOWN: + downPressed = GT2False; + if(upPressed) + localMotion = FORWARD; + else + localMotion = STILL; + break; + + case GLUT_KEY_LEFT: + leftPressed = GT2False; + if(rightPressed) + localTurning = RIGHT; + else + localTurning = STILL; + break; + + case GLUT_KEY_RIGHT: + rightPressed = GT2False; + if(leftPressed) + localTurning = LEFT; + else + localTurning = STILL; + break; + } +} + +const char * GetChatBuffer +( + void +) +{ + if(chatting) + return (const char *)chatBuffer; + + return NULL; +} + +static void ChatAddChar +( + char c +) +{ + if(nChatChars < (CHAT_MAX - 1)) + { + chatBuffer[nChatChars++] = c; + chatBuffer[nChatChars] = '\0'; + } +} + +static void ChatBackspace +( + void +) +{ + if(nChatChars) + chatBuffer[--nChatChars] = '\0'; +} + +static void ChatClear +( + void +) +{ + chatBuffer[0] = '\0'; + nChatChars = 0; +} + +static void ChatSend +( + void +) +{ + assert(nChatChars < CHAT_MAX); + + // Send it. + /////////// + if(nChatChars > 0) + SendChat(chatBuffer); +} + +static void ChatKeyboardPress +( + unsigned char key, + int x, + int y +) +{ + switch(key) + { + case 0x1B: // esc + // Back to normal keyboard handling. + //////////////////////////////////// + SetKeyboardNormal(); + + return; + + case 0x0D: // enter + // Send the current chat message. + ///////////////////////////////// + ChatSend(); + + // Back to normal keyboard handling. + //////////////////////////////////// + SetKeyboardNormal(); + + return; + + case 0x08: // backspace + case 0x7F: // delete + ChatBackspace(); + break; + } + + // Is it printable? + /////////////////// + if(isprint(key)) + { + // Add it to the buffer. + //////////////////////// + ChatAddChar(key); + } +} + +static void ChatKeyboardRelease +( + unsigned char key, + int x, + int y +) +{ + switch(key) + { + } +} + +void SetKeyboardNormal +( + void +) +{ + // Ignore key repeats. + ////////////////////// + glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); + + // Set glut callbacks. + ////////////////////// + glutKeyboardFunc(KeyboardPress); + glutKeyboardUpFunc(KeyboardRelease); + + // We're not chatting. + ////////////////////// + chatting = GT2False; +} + +void SetKeyboardChat +( + void +) +{ + // We don't care about key repeats now. + /////////////////////////////////////// + glutSetKeyRepeat(GLUT_KEY_REPEAT_DEFAULT); + + // Set glut callbacks. + ////////////////////// + glutKeyboardFunc(ChatKeyboardPress); + glutKeyboardUpFunc(ChatKeyboardRelease); + + // Clear the chat buffer. + ///////////////////////// + ChatClear(); + + // We're chatting. + ////////////////// + chatting = GT2True; +} +static void MouseMotionPassive(int x, int y) +{ + static int x_hold = 0; + static int y_hold = 0; + + if(x_hold) + { + localRotation += -(x_hold - x); + + } + + if( (x <= 0) || (x >= 639) ) + glutWarpPointer(320,240); + + x_hold = x; + y_hold = y; +} + +static void MouseButton(int button, int state, int x, int y) +{ + switch(button) + { + case GLUT_LEFT_BUTTON: + if(state == GLUT_DOWN) + SendPress("rocket"); + break; + case GLUT_RIGHT_BUTTON: + switch(state) + { + case GLUT_DOWN: + upPressed = GT2True; + localMotion = FORWARD; + break; + case GLUT_UP: + upPressed = GT2False; + localMotion = STILL; + break; + } + break; + case GLUT_MIDDLE_BUTTON: + switch(state) + { + case GLUT_DOWN: + upPressed = GT2True; + localMotion = BACKWARD; + break; + case GLUT_UP: + upPressed = GT2False; + localMotion = STILL; + break; + } + break; + } +} + + +static void JoystickProcess(unsigned int buttonMask, int x, int y, int z) +{ + static BYTE buttonA = GT2False; + + + if(!UseJoystick) + return; + + if(buttonMask & GLUT_JOYSTICK_BUTTON_A) + { + if(buttonA == GT2False) + { + SendPress("rocket"); + buttonA = GT2True; + } + } + else + buttonA = GT2False; + + if (x < -50) + localTurning = LEFT; + else if(x > 50) + localTurning = RIGHT; + else + localTurning = STILL; + + if(z < -300) + localMotion = FORWARD; + else if(z > 300) + localMotion = BACKWARD; + else + localMotion = STILL; + +} + +static int MainMenu; +enum +{ + MainToggleSound, + MainToggleViewClipping +}; +static void MainMenuCallback +( + int item +) +{ + switch(item) + { + case MainToggleSound: + ToggleSound(); + break; + case MainToggleViewClipping: + TOGGLE(ViewClippingOption); + break; + } +} + +static int GraphMenu; +enum +{ + GraphToggleGraphs, + GraphToggleUpdateTime, + GraphToggleUpdateLength, + GraphToggleFrameTime, + GraphToggleMarks +}; +static void GraphMenuCallback +( + int item +) +{ + switch(item) + { + case GraphToggleGraphs: + TOGGLE(DrawGraphsOption); + break; + case GraphToggleUpdateTime: + TOGGLE(DrawUpdateTimeOption); + break; + case GraphToggleUpdateLength: + TOGGLE(DrawUpdateLengthOption); + break; + case GraphToggleFrameTime: + TOGGLE(DrawFrameTimeOption); + break; + case GraphToggleMarks: + TOGGLE(DrawMarksOption); + break; + } +} + +static int DrawMenu; +enum +{ + DrawToggleFPS, + DrawTogglePrediction, + DrawToggleBackground, + DrawToggleStars, + DrawToggleBoundingCircles +}; +static void DrawMenuCallback +( + int item +) +{ + switch(item) + { + case DrawToggleFPS: + TOGGLE(DrawFPSOption); + break; + case DrawTogglePrediction: + TOGGLE(DrawWithPredictionOption); + break; + case DrawToggleBackground: + TOGGLE(DrawBackgroundOption); + break; + case DrawToggleStars: + TOGGLE(DrawStarsOption); + break; + case DrawToggleBoundingCircles: + TOGGLE(DrawBoundingCirclesOption); + break; + } +} + +static int RadarMenu; +enum +{ + RadarDrawRadar, + RadarSmallRadar, + RadarMediumRadar, + RadarLargeRadar, + RadarSmallPoints, + RadarMediumPoints, + RadarLargePoints +}; +static void RadarMenuCallback +( + int item +) +{ + switch(item) + { + case RadarDrawRadar: + TOGGLE(DrawRadarOption); + break; + case RadarSmallRadar: + RadarScaleOption = 0.5; + break; + case RadarMediumRadar: + RadarScaleOption = 1; + break; + case RadarLargeRadar: + RadarScaleOption = 2; + break; + case RadarSmallPoints: + RadarPointScaleOption = 1; + break; + case RadarMediumPoints: + RadarPointScaleOption = 2; + break; + case RadarLargePoints: + RadarPointScaleOption = 3; + break; + } +} + +void InitializeInput +( + void +) +{ + // Set the keyboard to normal. + ////////////////////////////// + SetKeyboardNormal(); + + // The glut handlers for "special" keys don't change. + ///////////////////////////////////////////////////// + glutSpecialFunc(SpecialKeyboardPress); + glutSpecialUpFunc(SpecialKeyboardRelease); + + + // The glut handlers for mouse input + //////////////////////////////////// + glutPassiveMotionFunc(MouseMotionPassive); + glutMotionFunc(MouseMotionPassive); + glutMouseFunc (MouseButton); + + // The glut handler for joystick input + ////////////////////////////////////// + glutJoystickFunc(JoystickProcess, 1); + + // Setup the menu. + ////////////////// + MainMenu = glutCreateMenu(MainMenuCallback); + + // Graph sub-menu. + ////////////////// + GraphMenu = glutCreateMenu(GraphMenuCallback); + glutSetMenu(GraphMenu); + glutAddMenuEntry("Toggle Graphs", GraphToggleGraphs); + glutAddMenuEntry("Toggle Update Time", GraphToggleUpdateTime); + glutAddMenuEntry("Toggle Update Length", GraphToggleUpdateLength); + glutAddMenuEntry("Toggle Frame Time", GraphToggleFrameTime); + glutAddMenuEntry("Toggle Marks", GraphToggleMarks); + glutSetMenu(MainMenu); + glutAddSubMenu("Graph", GraphMenu); + + // Draw sub-menu. + ///////////////// + DrawMenu = glutCreateMenu(DrawMenuCallback); + glutSetMenu(DrawMenu); + glutAddMenuEntry("Toggle FPS", DrawToggleFPS); + glutAddMenuEntry("Toggle Prediction", DrawTogglePrediction); + glutAddMenuEntry("Toggle Background", DrawToggleBackground); + glutAddMenuEntry("Toggle Stars", DrawToggleStars); + glutAddMenuEntry("Toggle Bounding Circles", DrawToggleBoundingCircles); + glutSetMenu(MainMenu); + glutAddSubMenu("Draw", DrawMenu); + + // Radar sub-menu. + ////////////////// + RadarMenu = glutCreateMenu(RadarMenuCallback); + glutSetMenu(RadarMenu); + glutAddMenuEntry("Draw Radar", RadarDrawRadar); + glutAddMenuEntry("Small Radar", RadarSmallRadar); + glutAddMenuEntry("Medium Radar", RadarMediumRadar); + glutAddMenuEntry("Large Radar", RadarLargeRadar); + glutAddMenuEntry("Small Points", RadarSmallPoints); + glutAddMenuEntry("Medium Points", RadarMediumPoints); + glutAddMenuEntry("Large Points", RadarLargePoints); + glutSetMenu(MainMenu); + glutAddSubMenu("Radar", RadarMenu); + + // Main menu. + ///////////// + glutAddMenuEntry("Toggle Sound", MainToggleSound); + glutAddMenuEntry("Toggle View Clipping", MainToggleViewClipping); + + // Attach the menu. + /////////////////// + glutAttachMenu(GLUT_RIGHT_BUTTON); +} diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aInput.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aInput.h new file mode 100644 index 00000000000..cadafa0c223 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aInput.h @@ -0,0 +1,24 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2AINPUT_H_ +#define _GT2AINPUT_H_ + +void InitializeInput +( + void +); + +const char * GetChatBuffer +( + void +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aLogic.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aLogic.c new file mode 100644 index 00000000000..14603fa7424 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aLogic.c @@ -0,0 +1,860 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include "gt2aMain.h" +#include "gt2aLogic.h" +#include "gt2aMath.h" +#include "gt2aSound.h" +#include "gt2aServer.h" + +#define DEATH_MESSAGES 0 + +SObject sObjects[MAX_OBJECTS]; +int numObjects; +static unsigned long Now; +static unsigned long Diff; +static int NumAsteroids; + +static void ExplodeObject(SObject * object); +static void InitAsteroid(SObject * asteroid); + +static SObject * AddObject +( + ObjectType type +) +{ + int i; + SObject * object; + + // Find an open slot. + ///////////////////// + for(i = 0 ; i < MAX_OBJECTS ; i++) + if(!sObjects[i].used) + break; + + // Nothing open? + //////////////// + if(i == MAX_OBJECTS) + return NULL; + + // Clear it. + //////////// + object = &sObjects[i]; + memset(object, 0, sizeof(SObject)); + object->used = GT2True; + object->type = type; + object->owner = -1; + + // Set the start time. + ////////////////////// + object->startTime = Now; + + // One more object. + /////////////////// + numObjects++; + assert(numObjects <= MAX_OBJECTS); + + return &sObjects[i]; +} + +static void RemoveObject +( + SObject * object +) +{ + assert(object); + if(!object) + return; + + // Mark this object for removal. + //////////////////////////////// + object->remove = GT2True; +} + +static void ClientKilled +( + Client * killed, + Client * killer +) +{ +#if DEATH_MESSAGES + char buffer[MAX_NICK + MAX_NICK + 32]; +#endif + + assert(killed); + + // Is there a killer? + ///////////////////// + if(killer) + { + // Self kill? + ///////////// + if(killer == killed) + { + // Subtract a point. + //////////////////// + killer->score--; + } + else + { + // Give the killer a point. + /////////////////////////// + killer->score++; + } + } + + // Kill the killed. + /////////////////// + killed->dead = GT2True; + killed->spawnTime = (Now + DEATH_TIME); + + // Play the death sound. + //////////////////////// + SendSound(SOUND_DIE, -1); + +#if DEATH_MESSAGES + // Let everyone know. + ///////////////////// + if(killer == killed) + sprintf(buffer, "%s killed himself", killed->nick); + else if(killer) + sprintf(buffer, "%s killed %s", killer->nick, killed->nick); + else + sprintf(buffer, "%s was killed", killed->nick); + BroadcastText(buffer, -1, GT2True); +#endif +} + +/////////// +//ROCKET // +/////////// + +static void RocketThink +( + SObject * rocket +) +{ + assert(rocket); + + // Move the rocket. + /////////////////// + ComputeNewPosition( + rocket->position, + rocket->position, + FORWARD, + rocket->rotation, + Diff, + ROCKET_SPEED, + GT2False); + + // Check if we should disappear. + //////////////////////////////// + if((rocket->position[0] < (MAP_MIN - MAP_EXTRA)) || + (rocket->position[0] > (MAP_MAX + MAP_EXTRA)) || + (rocket->position[1] < (MAP_MIN - MAP_EXTRA)) || + (rocket->position[1] > (MAP_MAX + MAP_EXTRA))) + { + RemoveObject(rocket); + } +} + +static void RocketTouchObject +( + SObject * rocket, + SObject * object +) +{ + // Don't explode if its another rocket with the same owner. + /////////////////////////////////////////////////////////// + if((object->type == ObjectRocket) && (object->owner == rocket->owner)) + return; + + // We pass through explosions. + ////////////////////////////// + if(object->type == ObjectExplosion) + return; + + // Explode the object. + ////////////////////// + ExplodeObject(object); + + // Remove the rocket. + ///////////////////// + RemoveObject(rocket); +} + +static void RocketTouchClient +( + SObject * rocket, + Client * client +) +{ + // Check for death. + /////////////////// + if(client->dead) + return; + + // Check for self. + ////////////////// + if(rocket->owner == client->index) + return; + + // Kill the client. + /////////////////// + if(rocket->owner == -1) + ClientKilled(client, NULL); + else + ClientKilled(client, &clients[rocket->owner]); + + // Explode the rocket. + ////////////////////// + ExplodeObject(rocket); +} + +////////// +// MINE // +////////// + +static void MineThink +( + SObject * mine +) +{ + // Check for detonate. + ////////////////////// + if((Now - mine->startTime) > MINE_TIME) + { + // Explode the mine. + //////////////////// + ExplodeObject(mine); + } + else + { + // Rotate the mine. + /////////////////// + mine->rotation = ComputeNewRotation(mine->rotation, RIGHT, Diff, MINE_TURN_SPEED); + + // Check if a second has passed. + //////////////////////////////// + if((int)((Now - mine->startTime) / 1000) > mine->count) + { + // One more full second. + //////////////////////// + mine->count++; + + // Make a sound during the last 3 seconds. + ////////////////////////////////////////// + if(mine->count >= ((MINE_TIME / 1000) - 3)) + SendSound(SOUND_MINE, -1); + } + } +} + +static void MineTouchObject +( + SObject * mine, + SObject * object +) +{ + // Ignore explosions. + ///////////////////// + if(object->type == ObjectExplosion) + return; + + // Blow up the object. + ////////////////////// + ExplodeObject(object); + + // Remove the mine. + /////////////////// + RemoveObject(mine); +} + +static void MineTouchClient +( + SObject * mine, + Client * client +) +{ + // Check if its armed itself. + ///////////////////////////// + if((Now - mine->startTime) < MINE_ARM_TIME) + return; + + // Check for death. + /////////////////// + if(client->dead) + return; + + // Kill the client. + /////////////////// + if(mine->owner == -1) + ClientKilled(client, NULL); + else + ClientKilled(client, &clients[mine->owner]); + + // Explode the mine. + //////////////////// + ExplodeObject(mine); +} + +////////////// +// ASTEROID // +////////////// + +static void AsteroidThink +( + SObject * asteroid +) +{ + // Rotate the asteroid. + /////////////////////// + asteroid->rotation = ComputeNewRotation(asteroid->rotation, LEFT, Diff, ASTEROID_TURN_SPEED); + + // Move the asteroid. + ///////////////////// + ComputeNewPosition(asteroid->position, asteroid->position, FORWARD, asteroid->heading, Diff, asteroid->speed, GT2False); + + // If it goes past the edge, loop it around. + //////////////////////////////////////////// + if(asteroid->position[0] > MAP_MAX + (2*asteroid->radius)) + asteroid->position[0] = MAP_MIN - (2*asteroid->radius); + if(asteroid->position[0] < MAP_MIN - (2*asteroid->radius)) + asteroid->position[0] = MAP_MAX + (2*asteroid->radius); + + if(asteroid->position[1] > MAP_MAX + (2*asteroid->radius)) + asteroid->position[1] = MAP_MIN - (2*asteroid->radius); + if(asteroid->position[1] < MAP_MIN - (2*asteroid->radius)) + asteroid->position[1] = MAP_MAX + (2*asteroid->radius); + +} + +static void AsteroidTouchObject +( + SObject * asteroid, + SObject * object +) +{ + // Explode on asteroid impact. + ////////////////////////////// + if(object->type == ObjectAsteroid) + { + ExplodeObject(asteroid); + ExplodeObject(object); + } +} + +static void AsteroidTouchClient +( + SObject * asteroid, + Client * client +) +{ + // Check for death. + /////////////////// + if(client->dead) + return; + + // Kill the client. + /////////////////// + ClientKilled(client, NULL); + + // Explode the asteroid. + //////////////////////// + ExplodeObject(asteroid); +} + +static void SpawnAsteroids +( + void +) +{ + SObject * asteroid; + int i; + + NumAsteroids = 0; + for(i = 0 ; i < NUM_ASTEROIDS ; i++) + { + asteroid = AddObject(ObjectAsteroid); + if(asteroid) + InitAsteroid(asteroid); + } +} + +static void AsteroidDie +( + SObject * asteroid +) +{ + // One less asteroid. + ///////////////////// + NumAsteroids--; + + // If they're all gone, make new ones. + ////////////////////////////////////// + if(!NumAsteroids) + SpawnAsteroids(); +} + +static void InitAsteroid +( + SObject * asteroid +) +{ + asteroid->position[0] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + asteroid->position[1] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + asteroid->rotation = RandomFloat(0, 360, GT2False); + asteroid->think = AsteroidThink; + asteroid->touchObject = AsteroidTouchObject; + asteroid->touchClient = AsteroidTouchClient; + asteroid->die = AsteroidDie; + asteroid->radius = ASTEROID_RADIUS; + asteroid->speed = RandomFloat(ASTEROID_SPEED_MIN, ASTEROID_SPEED_MAX, GT2False); + asteroid->heading = asteroid->rotation; + + NumAsteroids++; +} + +/////////////// +// EXPLOSION // +/////////////// + +static void ExplosionThink +( + SObject * explosion +) +{ + // Check for done. + ////////////////// + if((Now - explosion->startTime) > EXPLOSION_TIME) + { + // Delete the explosion. + //////////////////////// + RemoveObject(explosion); + } +} + +static void ExplosionTouchObject +( + SObject * explosion, + SObject * object +) +{ +} + +static void ExplosionTouchClient +( + SObject * explosion, + Client * client +) +{ + // Check if we're still dangerous. + ////////////////////////////////// + if((Now - explosion->startTime) > EXPLOSION_DANGER_TIME) + return; + + // Check for death. + /////////////////// + if(client->dead) + return; + + // Kill the client. + /////////////////// + if(explosion->owner == -1) + ClientKilled(client, NULL); + else + ClientKilled(client, &clients[explosion->owner]); +} + +static SObject * AddExplosion +( + V2f position, + int owner +) +{ + SObject * explosion; + + // Add an explosion. + //////////////////// + explosion = AddObject(ObjectExplosion); + if(!explosion) + return NULL; + + // Setup the explosion. + /////////////////////// + explosion->owner = owner; + CopyV2f(explosion->position, position); + explosion->rotation = RandomFloat(0, 360, GT2False); + explosion->think = ExplosionThink; + explosion->touchObject = ExplosionTouchObject; + explosion->touchClient = ExplosionTouchClient; + explosion->radius = EXPLOSION_RADIUS; + + // Send a sound effect. + /////////////////////// + SendSound(SOUND_EXPLOSION, -1); + + return explosion; +} + +static void ExplodeObject +( + SObject * object +) +{ + // Don't explode explosions. + //////////////////////////// + if(object->type == ObjectExplosion) + return; + + // Mark this object for explosion. + ////////////////////////////////// + object->explode = GT2True; + + if(object->type != ObjectAsteroid) + { + // Mark for removal. + //////////////////// + RemoveObject(object); + } +} + +static void ClientThink +( + Client * client +) +{ + // Dead? + //////// + if(client->dead) + { + // Time to spawn? + ///////////////// + if(Now > client->spawnTime) + ClientSpawn(client); + } + else if(client->numAsteroids) + { + static V2f spinnerPosition = { MAP_HALF, MAP_HALF }; + float distance; + + // Check for the spinner. + ///////////////////////// + distance = DistanceV2f(spinnerPosition, client->position); + if(distance < (PLAYER_RADIUS + SPINNER_RADIUS)) + { + // Drop off our asteroids. + ////////////////////////// + client->score += client->numAsteroids; + client->numAsteroids = 0; + SendNumAsteroids(client->numAsteroids, client->index); + SendSound(SOUND_PICKUP, client->index); + } + } +} + +void ClientPress +( + int clientIndex, + const char * button +) +{ + SObject * object; + Client * client; + V2f forward; + + assert(clientIndex >= 0); + assert(clientIndex < MAX_CLIENTS); + assert(clients[clientIndex].used); + + // Set the Now time. + //////////////////// + Now = current_time(); + + client = &clients[clientIndex]; + + // Check the button. + //////////////////// + if(strcasecmp(button, "mine") == 0) + { + // Add a mine object. + ///////////////////// + object = AddObject(ObjectMine); + if(object) + { + // Set its properties. + ////////////////////// + object->owner = clientIndex; + CopyV2f(object->position, client->position); + object->rotation = client->rotation; + object->think = MineThink; + object->touchObject = MineTouchObject; + object->touchClient = MineTouchClient; + object->radius = MINE_RADIUS; + + // Move it so its behind the client. + ////////////////////////////////////// + RotationToVector(forward, object->rotation); + ScaleV2f(forward, forward, -500); + AddV2f(object->position, object->position, forward); + + // Play the mine sound. + /////////////////////// + SendSound(SOUND_MINE, -1); + } + } + else if(strcasecmp(button, "rocket") == 0) + { + // Add a rocket object. + /////////////////////// + object = AddObject(ObjectRocket); + if(object) + { + // Set its properties. + ////////////////////// + object->owner = clientIndex; + CopyV2f(object->position, client->position); + object->rotation = client->rotation; + object->think = RocketThink; + object->touchObject = RocketTouchObject; + object->touchClient = RocketTouchClient; + object->radius = ROCKET_RADIUS; + + // Move it so its ahead of the client. + ////////////////////////////////////// + RotationToVector(forward, object->rotation); + ScaleV2f(forward, forward, 300); + AddV2f(object->position, object->position, forward); + + // Play the rocket sound. + ///////////////////////// + SendSound(SOUND_ROCKET, -1); + } + } +} + +void ObjectThink +( + SObject * object +) +{ + int i; + SObject * other; + Client * client; + + // Think. + ///////// + object->think(object); + + // Check for client touches. + //////////////////////////// + if(object->touchClient) + { + float range; + + range = (object->radius + PLAYER_RADIUS); + + for(i = 0 ; i < MAX_CLIENTS ; i++) + { + client = &clients[i]; + + // Check for in use. + //////////////////// + if(!client->used) + continue; + + // Check for a touch. + ///////////////////// + if(DistanceV2f(object->position, client->position) <= range) + { + // Touched. + /////////// + object->touchClient(object, client); + } + } + } + + // Check for object touches. + //////////////////////////// + if(object->touchObject) + { + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + other = &sObjects[i]; + + // Check for in use. + //////////////////// + if(!other->used) + continue; + + // Check for self. + ////////////////// + if(other == object) + continue; + + // Check for a touch. + ///////////////////// + if(DistanceV2f(object->position, other->position) <= (object->radius + other->radius)) + { + // Touched. + /////////// + object->touchObject(object, other); + } + } + } +} + +void ObjectsThink +( + unsigned long now, + unsigned long diff +) +{ + Client * client; + SObject * object; + int i; + + Now = now; + Diff = diff; + + // Go through the list of clients. + ////////////////////////////////// + for(i = 0 ; i < MAX_CLIENTS ; i++) + { + client = &clients[i]; + + // Is it a real client? + /////////////////////// + if(client->used) + { + // Think. + ///////// + ClientThink(client); + } + } + + // Think for all the objects. + ///////////////////////////// + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + object = &sObjects[i]; + + // Is the object in use? + //////////////////////// + if(object->used) + { + // Think. + ///////// + ObjectThink(object); + } + } + + // Check for exploding or removed objects. + ////////////////////////////////////////// + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + object = &sObjects[i]; + + // Is the object in use? + //////////////////////// + if(object->used) + { + // Explode the object? + ////////////////////// + if(object->explode) + { + // Create an explosion. + /////////////////////// + AddExplosion(object->position, object->owner); + + // It exploded. + /////////////// + object->explode = GT2False; + + + // If it is an asteroid, then move it to the edge + ///////////////////////////////////////////////// + if(object->type == ObjectAsteroid) + { + object->position[0] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + object->position[1] = MAP_MIN - object->radius; + } + + + } + + // Remove the object? + ///////////////////// + if(object->remove) + { + // Call its die function. + ///////////////////////// + if(object->die) + object->die(object); + + if(object->used) + { + // We're not using this object anymore. + /////////////////////////////////////// + object->used = GT2False; + + // One less object. + /////////////////// + numObjects--; + assert(numObjects >= 0); + } + } + } + } +} + +void ClientSpawn +( + Client * client +) +{ + SObject * asteroid; + + // Throw away his asteroids. + //////////////////////////// + for( ; client->numAsteroids ; client->numAsteroids--) + { + asteroid = AddObject(ObjectAsteroid); + if(asteroid) + { + InitAsteroid(asteroid); + asteroid->position[0] = client->position[0]; + asteroid->position[0] += RandomFloat(-5000, 5000, GT2True); + asteroid->position[1] = client->position[1]; + asteroid->position[1] += RandomFloat(-5000, 5000, GT2True); + ClampV2f(asteroid->position, asteroid->position, MAP_MIN, MAP_MAX); + } + } + SendNumAsteroids(client->numAsteroids, client->index); + + // Pick a random starting point. + //////////////////////////////// + client->position[0] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + client->position[1] = RandomFloat(MAP_MIN, MAP_MAX, GT2True); + + // Not dead. + //////////// + client->dead = GT2False; +} + +void InitializeLogic +( + void +) +{ + // Add a bunch of asteroids. + //////////////////////////// + SpawnAsteroids(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aLogic.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aLogic.h new file mode 100644 index 00000000000..b389d682146 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aLogic.h @@ -0,0 +1,119 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2ALOGIC_H_ +#define _GT2ALOGIC_H_ + +#include "gt2aServer.h" + +#define PLAYER_SPEED 7000 // units/second +#define PLAYER_TURN_SPEED 0.14 // degrees/millisecond +#define PLAYER_RADIUS 200 +#define PLAYER_MAX_ASTEROIDS 50 +#define DEATH_TIME 1000 +#define PRESS_TIME 100 // time between presses + +#define MAX_OBJECTS 256 +#define ROCKET_RADIUS 250 +#define ROCKET_SPEED 10500 +#define MINE_TIME 30000 +#define MINE_ARM_TIME 1000 +#define MINE_TURN_SPEED 0.36 // degrees/millisecond +#define MINE_RADIUS 200//141 +#define NUM_ASTEROIDS 50 +#define ASTEROID_TURN_SPEED 0.18 +#define ASTEROID_TURN_RANGE 0.24 +#define ASTEROID_RADIUS 350 +#define ASTEROID_SPEED_MIN 0 +#define ASTEROID_SPEED_MAX 5000 +#define EXPLOSION_RADIUS 900 +#define EXPLOSION_TIME 350 +#define EXPLOSION_DANGER_TIME 250 +#define SPINNER_RADIUS 5000 +#define SPINNER_COORD (SPINNER_RADIUS * 1.414) + +typedef enum +{ + ObjectRocket, + ObjectMine, + ObjectAsteroid, + ObjectExplosion, + NumObjects +} ObjectType; + +typedef void (* Think) +( + struct SObject * self +); + +typedef void (* TouchObject) +( + struct SObject * self, + struct SObject * object +); + +typedef void (* Die) +( + struct SObject * self +); + +typedef void (* TouchClient) +( + struct SObject * self, + struct Client * client +); + +typedef struct SObject +{ + GT2Bool used; // If this slot is in use or not. + ObjectType type; // The type of object. + int owner; // The client that owns this object, or -1. + V2f position; // The object's position. + float rotation; // The object's rotation. + unsigned long startTime; // The time this object was created. + Think think; // This object's think function. + TouchObject touchObject; // Called when touching another object. + TouchClient touchClient; // Called when touching a client. + Die die; // Called when the object dies. + int count; // Generic counter. + float radius; // This object's radius (for collision). + GT2Bool explode; // Explode this object when done thinking. + GT2Bool remove; // Remove this object when done thinking. + + float heading; // The direction the object is moving + float speed; // The speed of the object +} SObject; + +extern SObject sObjects[MAX_OBJECTS]; +extern int numObjects; + +void ObjectsThink +( + unsigned long now, + unsigned long diff +); + +void ClientPress +( + int clientIndex, + const char * button +); + +void ClientSpawn +( + Client * client +); + +void InitializeLogic +( + void +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aMain.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aMain.c new file mode 100644 index 00000000000..9584ee616e4 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aMain.c @@ -0,0 +1,276 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include +#include +#include +#include "gt2aMain.h" +#include "gt2aDisplay.h" +#include "gt2aClient.h" +#include "gt2aServer.h" +#include "gt2aInput.h" +#include "gt2aSound.h" +#include "../../ghttp/ghttp.h" + +const V3b Red = { 255, 0, 0 }; +const V3b Green = { 0, 255, 0 }; +const V3b Blue = { 0, 0, 255 }; +const V3b Yellow = { 255, 255, 0 }; +const V3b Orange = { 255, 128, 0 }; +const V3b Purple = { 255, 0, 255 }; +const V3b Black = { 0, 0, 0 }; +const V3b White = { 255, 255, 255 }; +const V3b Grey = { 128, 128, 128 }; + +static GT2Bool host = GT2True; +static GT2Bool dedicated; + +void Log +( + const char * format, + ... +) +{ +#if 1 + FILE * fp; + va_list args; + + va_start(args, format); + + fp = fopen("gt2a.log", "at"); + if(fp) + { + fprintf(fp, "%08d: ", (current_time() % 100000000)); + vfprintf(fp, format, args); + fclose(fp); + } + + va_end(args); +#endif +} + +static void Idle +( + void +) +{ + msleep(1); + glutPostRedisplay(); +} + +static void Timer +( + int value +) +{ + unsigned long now; + + // Reset the timer. + /////////////////// + glutTimerFunc(10, Timer, 0); + + // Get the current time. + //////////////////////// + now = current_time(); + + // Let the subsystems think. + //////////////////////////// + if(host) + ServerThink(now); + if(!dedicated) + ClientThink(now); + DisplayThink(now); +} + +static GHTTPBool NaminatorCallback +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + if(result == GHTTPSuccess) + { + char * str; + + // Set the nick. + //////////////// + strncpy(localNick, buffer, MAX_NICK); + localNick[MAX_NICK - 1] = '\0'; + + // Cap off the newline. + /////////////////////// + str = strchr(localNick, '\n'); + if(str) + *str = '\0'; + + // Strip out stuff that'll mess up our + // key\value message passing. + ////////////////////////////////////// + while(str = strchr(localNick, '\\')) + *str = '/'; + + printf("%s\n", localNick); + } + else + { + printf("Error\n"); + } + + return GHTTPTrue; +} + +static void ParseArgs +( + int argc, + char ** argv +) +{ + GT2Bool gotNick = GT2False; + int i; + + for(i = 1 ; i < argc ; i++) + { + // Connect. + /////////// + if(strncasecmp(argv[i], "-c", 2) == 0) + { + if(++i < argc) + { + // Get the address to connect to. + ///////////////////////////////// + strcpy(serverAddress, argv[i]); + if(!strchr(serverAddress, ':')) + strcat(serverAddress, PORT_STRING); + host = GT2False; + } + } + // Fullscreen. + ////////////// + else if(strcasecmp(argv[i], "-full") == 0) + { + fullScreen = GT2True; + } + // Nick. + //////// + else if((strcasecmp(argv[i], "-nick") == 0) || + (strcasecmp(argv[i], "-name") == 0)) + { + if(++i < argc) + { + char * str; + + // Set the nick. + //////////////// + strncpy(localNick, argv[i], MAX_NICK); + localNick[MAX_NICK - 1] = '\0'; + + // Strip out stuff that'll mess up our + // key\value message passing. + ////////////////////////////////////// + while(str = strchr(localNick, '\\')) + *str = '/'; + + // We got a nick. + ///////////////// + gotNick = GT2True; + } + } + // Dedicated server. + //////////////////// + else if(strcasecmp(argv[i], "-dedicated") == 0) + { + dedicated = GT2True; + } + // Width. + ///////// + else if(strcasecmp(argv[i], "-width") == 0) + { + if(++i < argc) + screenWidth = atoi(argv[i]); + } + // Height. + ////////// + else if(strcasecmp(argv[i], "-height") == 0) + { + if(++i < argc) + screenHeight = atoi(argv[i]); + } + } + + // If we didn't get a nick, get a naminator nick. + ///////////////////////////////////////////////// + if(!gotNick) + { + printf("Getting naminator name..."); + ghttpGetFile("http://www.planetquake.com/excessive/name.asp", GHTTPTrue, NaminatorCallback, NULL); + } +} + +static GT2Bool Initialize +( + void +) +{ + // Init the display. + //////////////////// + InitializeDisplay(); + + // Init input handling. + /////////////////////// + InitializeInput(); + + // Init sound. + ////////////// + InitializeSound(); + + // Start the server if we're hosting. + ///////////////////////////////////// + if(host) + { + if(!InitializeServer()) + { + printf("Failed to initialize server!\n"); + return GT2False; + } + } + + // Start the client if not dedicated. + ///////////////////////////////////// + if(!dedicated) + { + if(!InitializeClient()) + { + printf("Failed to initialize client!\n"); + return GT2False; + } + } + + return GT2True; +} + +int main +( + int argc, + char ** argv +) +{ + srand(time(NULL)); + glutInit(&argc, argv); + ParseArgs(argc, argv); + glutTimerFunc(10, Timer, 0); + glutIdleFunc(Idle); + if(!Initialize()) + return 1; + glutMainLoop(); + return 0; +} diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aMain.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aMain.h new file mode 100644 index 00000000000..555928a2bd2 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aMain.h @@ -0,0 +1,85 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2AMAIN_H_ +#define _GT2AMAIN_H_ + +#include +#include +#include "../../nonport.h" +#include "../gt2.h" +#include "../gt2Encode.h" + +#define PORT_STRING ":12345" + +#define MAX_PLAYERS 64 + +#define BACKWARD -1 +#define STILL 0 +#define FORWARD 1 + +#define LEFT -1 +#define RIGHT 1 + +#define MAP_MIN 0 +#define MAP_MAX 100000.0 +#define MAP_HALF (MAP_MAX / 2) +#define MAP_EXTRA (MAP_MAX / 10) + +#define MAX_NICK 32 + +#define CHAT_MAX 64 + +#define MSG_C_INITIAL 1 +#define MSG_C_INITIAL_STR "s" +#define MSG_C_UPDATE 2 +#define MSG_C_UPDATE_STR "ppzzzz" +#define MSG_C_PRESS 3 +#define MSG_C_PRESS_STR "s" +#define MSG_C_CHAT 4 +#define MSG_C_CHAT_STR "s" +#define MSG_S_ADDCLIENT 1001 +#define MSG_S_ADDCLIENT_STR "bs" +#define MSG_S_DELCLIENT 1002 +#define MSG_S_DELCLIENT_STR "b" +#define MSG_S_START 1003 +#define MSG_S_START_STR "b" +#define MSG_S_UPDATE 1004 +#define MSG_S_UPDATE_STR "pbb" +#define MSG_S_UPDATE_CLIENT_STR "bpppizzzzz" +#define MSG_S_UPDATE_OBJECT_STR "bpppi" +#define MSG_S_CHAT 1005 +#define MSG_S_CHAT_STR "s" +#define MSG_S_SOUND 1006 +#define MSG_S_SOUND_STR "b" +#define MSG_S_NUMASTEROIDS 1007 +#define MSG_S_NUMASTEROIDS_STR "b" + +typedef unsigned char byte; +typedef float V2f[2]; +typedef byte V3b[3]; + +extern const V3b Red; +extern const V3b Green; +extern const V3b Blue; +extern const V3b Yellow; +extern const V3b Orange; +extern const V3b Purple; +extern const V3b Black; +extern const V3b White; +extern const V3b Grey; + +void Log +( + const char * format, + ... +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aMath.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aMath.c new file mode 100644 index 00000000000..0ea17969cb9 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aMath.c @@ -0,0 +1,364 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include +#include +#include +#include "gt2aMain.h" +#include "gt2aMath.h" + +#define PI 3.1415926535897932384626433832795 +#define PI_DIV_180 (PI / 180) + +byte * CopyV3b +( + V3b dest, + const V3b src +) +{ + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + + return dest; +} + +byte * SetV3b +( + V3b dest, + byte src0, + byte src1, + byte src2 +) +{ + dest[0] = src0; + dest[1] = src1; + dest[2] = src2; + + return dest; +} + +float * CopyV2f +( + V2f dest, + const V2f src +) +{ + dest[0] = src[0]; + dest[1] = src[1]; + + return dest; +} + +float * SetV2f +( + V2f dest, + float src0, + float src1 +) +{ + dest[0] = src0; + dest[1] = src1; + + return dest; +} + +float * ScaleV2f +( + V2f dest, + const V2f src, + float scale +) +{ + dest[0] = (src[0] * scale); + dest[1] = (src[1] * scale); + + return dest; +} + +float * AddV2f +( + V2f dest, + const V2f src0, + const V2f src1 +) +{ + dest[0] = (src0[0] + src1[0]); + dest[1] = (src0[1] + src1[1]); + + return dest; +} + +float * SubV2f +( + V2f dest, + const V2f src0, + const V2f src1 +) +{ + dest[0] = (src0[0] - src1[0]); + dest[1] = (src0[1] - src1[1]); + + return dest; +} + +float * SubScalarV2f +( + V2f dest, + const V2f src, + float scalar +) +{ + dest[0] = (src[0] - scalar); + dest[1] = (src[1] - scalar); + + return dest; +} + +float LenV2f +( + const V2f src +) +{ + return (float)sqrt((src[0] * src[0]) + (src[1] * src[1])); +} + +float DistanceV2f +( + const V2f src0, + const V2f src1 +) +{ + V2f temp; + + SubV2f(temp, src0, src1); + + return LenV2f(temp); +} + +float * ClampV2f +( + V2f dest, + const V2f src, + float min, + float max +) +{ + float temp; + int i; + + for(i = 0 ; i < 2 ; i++) + { + temp = src[i]; + if(temp > max) + dest[i] = max; + else if(temp < min) + dest[i] = min; + else + dest[i] = temp; + } + + return dest; +} + +float ClampRotation +( + float rotation +) +{ + while(rotation >= 360) + rotation -= 360; + while(rotation < 0) + rotation += 360; + return rotation; +} + +int ClampInt +( + int num, + int min, + int max +) +{ + if(num < min) + num = min; + else if(num > max) + num = max; + return num; +} + +float * RotationToVector +( + V2f dest, + float rotation +) +{ + // Convert to radians. + ////////////////////// + rotation = (float)(rotation * PI_DIV_180); + + dest[0] = (float)sin(rotation); + dest[1] = (float)cos(rotation); + + return dest; +} + +float * ComputeNewPosition +( + V2f dest, + const V2f position, + int motion, + float rotation, + unsigned long diff, + int unitsPerSec, + GT2Bool clamp +) +{ + V2f forward; + float scale; + + // Check for no motion. + /////////////////////// + if(!motion) + { + CopyV2f(dest, position); + return dest; + } + + // Get the direction we're facing. + ////////////////////////////////// + RotationToVector(forward, rotation); + + // Scale it based on the amount of time. + //////////////////////////////////////// + scale = (float)(diff * unitsPerSec / 1000); + if(motion == BACKWARD) + scale = -scale; + ScaleV2f(forward, forward, scale); + + // Update the position. + /////////////////////// + AddV2f(dest, position, forward); + + // Clamp it. + //////////// + if(clamp) + ClampV2f(dest, dest, 0, MAP_MAX); + + return dest; +} + +float ComputeNewRotation +( + float rotation, + int turning, + unsigned long diff, + float degreesPerMilliSec +) +{ + // Turn. + //////// + rotation += (turning * (diff * degreesPerMilliSec)); + + // Clamp it to between 0 and 360. + ///////////////////////////////// + while(rotation >= 360) + rotation -= 360; + while(rotation < 0) + rotation += 360; + + return rotation; +} + +float RandomFloat +( + float minFloat, + float maxFloat, + GT2Bool maxInclusive +) +{ + float num; + + num = rand(); + num *= (maxFloat - minFloat); + num /= (RAND_MAX + (maxInclusive?0:1)); + num += minFloat; + + return num; +} + +int RandomInt +( + int minInt, + int maxInt +) +{ + return (minInt + ((rand() * (maxInt - minInt + 1)) / (RAND_MAX + 1))); +} + +unsigned short RotationToUnsignedShort +( + float rotation +) +{ + rotation *= 0xFFFF; + rotation /= 360; + if(rotation < 0) + rotation = 0; + if(rotation > 0xFFFF) + rotation = 0xFFFF; + + return (unsigned short)rotation; +} + +float UnsignedShortToRotation +( + unsigned short packedRotation +) +{ + float rotation; + + rotation = packedRotation; + rotation *= 360; + rotation /= 0xFFFF; + + return ClampRotation(rotation); +} + +unsigned short PositionToUnsignedShort +( + float position +) +{ + position += (MAP_EXTRA / 2); + position *= 0xFFFF; + position /= (MAP_MAX + MAP_EXTRA); + if(position < 0) + position = 0; + else if(position > USHRT_MAX) + position = USHRT_MAX; + + return (unsigned short)position; +} + +float UnsignedShortToPosition +( + unsigned short packedPosition +) +{ + float position; + + position = packedPosition; + position *= (MAP_MAX + MAP_EXTRA); + position /= 0xFFFF; + position -= (MAP_EXTRA / 2); + + return position; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aMath.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aMath.h new file mode 100644 index 00000000000..04e0a3fb82a --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aMath.h @@ -0,0 +1,161 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2AMATH_H_ +#define _GT2AMATH_H_ + +#include +#include "gt2aMain.h" + +byte * CopyV3b +( + V3b dest, + const V3b src +); + +byte * SetV3b +( + V3b dest, + byte src0, + byte src1, + byte src2 +); + +float * CopyV2f +( + V2f dest, + const V2f src +); + +float * SetV2f +( + V2f dest, + float src0, + float src1 +); + +float * ScaleV2f +( + V2f dest, + const V2f src, + float scale +); + +float * AddV2f +( + V2f dest, + const V2f src0, + const V2f src1 +); + +float * SubV2f +( + V2f dest, + const V2f src0, + const V2f src1 +); + +float * SubScalarV2f +( + V2f dest, + const V2f src, + float scalar +); + +float LenV2f +( + const V2f src +); + +float DistanceV2f +( + const V2f src0, + const V2f src1 +); + +float * ClampV2f +( + V2f dest, + const V2f src, + float min, + float max +); + +float ClampRotation +( + float rotation +); + +int ClampInt +( + int num, + int min, + int max +); + +float * RotationToVector +( + V2f dest, + float rotation +); + +float * ComputeNewPosition +( + V2f dest, + const V2f position, + int motion, + float rotation, + unsigned long diff, + int unitsPerMilliSec, + GT2Bool clamp +); + +float ComputeNewRotation +( + float rotation, + int turning, + unsigned long diff, + float degreesPerMilliSec +); + +float RandomFloat +( + float minFloat, + float maxFloat, + GT2Bool maxInclusive +); + +int RandomInt +( + int minInt, + int maxInt +); + +unsigned short RotationToUnsignedShort +( + float rotation +); + +float UnsignedShortToRotation +( + unsigned short packedRotation +); + +unsigned short PositionToUnsignedShort +( + float position +); + +float UnsignedShortToPosition +( + unsigned short packedPosition +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aParse.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aParse.c new file mode 100644 index 00000000000..472ade22d0f --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aParse.c @@ -0,0 +1,79 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include +#include "gt2aParse.h" + +static char buffer[256]; + +static char * StripKeyValue +( + char * input +) +{ + int i; + int c; + + // Get the key. + /////////////// + for(i = 0 ; i < (sizeof(buffer) - 1) ; i++) + { + c = *input++; + if((c == '\\') || (c == '\0')) + break; + buffer[i] = (char)c; + } + buffer[i] = '\0'; + + return buffer; +} + +char * ParseKeyValue +( + char * input, + const char * key +) +{ + char * str; + int len; + + if(!input) + return NULL; + + // Are we looking for the first key? + //////////////////////////////////// + if(!key) + { + // Does it start with a '\'? + //////////////////////////// + if(*input++ != '\\') + return NULL; + + // Get the key. + /////////////// + return StripKeyValue(input); + } + + // Find the key. + //////////////// + buffer[0] = '\\'; + len = strlen(key); + memcpy(buffer + 1, key, len); + buffer[++len] = '\\'; + buffer[++len] = '\0'; + str = strstr(input, buffer); + if(!str) + return NULL; + str += strlen(buffer); + + // Get the key. + /////////////// + return StripKeyValue(str); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aParse.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aParse.h new file mode 100644 index 00000000000..9ae3b12a9a2 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aParse.h @@ -0,0 +1,26 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2APARSE_H_ +#define _GT2APARSE_H_ + +// Search the input for "\key\". +// Returns the value following the key, +// or NULL if the key wasn't found. +// If key is NULL, returns the first key +// in input, or NULL if there's an error. +///////////////////////////////////////// +char * ParseKeyValue +( + char * input, + const char * key +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aServer.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aServer.c new file mode 100644 index 00000000000..e0b2eff87fb --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aServer.c @@ -0,0 +1,746 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include "gt2aMain.h" +#include "gt2aServer.h" +#include "gt2aParse.h" +#include "gt2aMath.h" +#include "gt2aSound.h" +#include "gt2aLogic.h" + +#define SERVER_THINK_TIME 30 + +static GT2Socket Socket; +Client clients[MAX_CLIENTS]; +static int numClients; +static GT2ConnectionCallbacks connectionCallbacks; +static unsigned short nextServerUpdateID; + +static void Broadcast +( + const char * message, + int len, + int exceptIndex, + GT2Bool reliable +) +{ + int i; + + for(i = 0 ; i < MAX_CLIENTS ; i++) + if(clients[i].used && (i != exceptIndex)) + gt2Send(clients[i].connection, (const GT2Byte *)message, len, reliable); +} + +void BroadcastText +( + const char * message, + int exceptIndex, + GT2Bool reliable +) +{ + static char messageCopy[CHAT_MAX]; + static char buffer[256]; + char * slash; + int rcode; + + // Copy off the chat message. + ///////////////////////////// + strncpy(messageCopy, message, CHAT_MAX); + messageCopy[CHAT_MAX - 1] = '\0'; + + // Because of the way gt2a is sending messages + // we need to change \ to /. + ////////////////////////////////////////////// + while(slash = strchr(messageCopy, '\\')) + *slash = '/'; + + // Encode the message. + ////////////////////// + rcode = gtEncode(MSG_S_CHAT, MSG_S_CHAT_STR, buffer, sizeof(buffer), + messageCopy); + if(rcode != -1) + { + // Send this chat message out to everyone. + ////////////////////////////////////////// + Broadcast(buffer, rcode, -1, reliable); + } +} + +static int AddClient +( + void +) +{ + int i; + + // Find an open slot. + ///////////////////// + for(i = 0 ; i < MAX_CLIENTS ; i++) + if(!clients[i].used) + break; + + // Nothing open? + //////////////// + if(i == MAX_CLIENTS) + return -1; + + // Clear it. + //////////// + memset(&clients[i], 0, sizeof(Client)); + clients[i].index = i; + clients[i].used = GT2True; + + // One more client. + /////////////////// + numClients++; + assert(numClients <= MAX_CLIENTS); + + return i; +} + +static void RemoveClient +( + int clientIndex +) +{ + // Not in use anymore. + ////////////////////// + clients[clientIndex].used = GT2False; + + // One less client. + /////////////////// + numClients--; + assert(numClients >= 0); +} + +static void SendAddClient +( + int sendClientIndex, + int newClientIndex +) +{ + char buffer[256]; + Client * sendClient; + Client * newClient; + int rcode; + + assert((sendClientIndex >= 0) && (sendClientIndex < MAX_CLIENTS)); + sendClient = &clients[sendClientIndex]; + assert(sendClient->used); + assert(sendClient->connection); + + assert((newClientIndex >= 0) && (newClientIndex < MAX_CLIENTS)); + newClient = &clients[newClientIndex]; + assert(newClient->used); + assert(newClient->connection); + + // Encode the message. + ///////////////////// + rcode = gtEncode(MSG_S_ADDCLIENT, MSG_S_ADDCLIENT_STR, buffer, sizeof(buffer), + newClientIndex, + newClient->nick); + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(sendClient->connection, (const GT2Byte *)buffer, rcode, GT2True); + } +} + +static void SendDelClient +( + int sendClient, + int delClient +) +{ + char buffer[32]; + int rcode; + + assert((sendClient >= 0) && (sendClient < MAX_CLIENTS)); + assert(clients[sendClient].used); + assert(clients[sendClient].connection); + assert((delClient >= 0) && (delClient < MAX_CLIENTS)); + + // Encode the message. + ///////////////////// + rcode = gtEncode(MSG_S_DELCLIENT, MSG_S_DELCLIENT_STR, buffer, sizeof(buffer), + delClient); + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(clients[sendClient].connection, (const GT2Byte *)buffer, rcode, GT2True); + } +} + +static void SendStart +( + int sendClient +) +{ + char buffer[32]; + int rcode; + + assert((sendClient >= 0) && (sendClient < MAX_CLIENTS)); + assert(clients[sendClient].used); + assert(clients[sendClient].connection); + + // Encode the message. + ///////////////////// + rcode = gtEncode(MSG_S_START, MSG_S_START_STR, buffer, sizeof(buffer), + sendClient); + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(clients[sendClient].connection, (const GT2Byte *)buffer, rcode, GT2True); + } +} + +void SendSound +( + int sound, + int sendClient +) +{ + char buffer[32]; + int rcode; + + assert(sendClient >= -1); + assert(sendClient < MAX_CLIENTS); +#ifdef _DEBUG + if(sendClient != -1) + { + assert(clients[sendClient].used); + assert(clients[sendClient].connection); + } +#endif + + // Encode the message. + ///////////////////// + rcode = gtEncode(MSG_S_SOUND, MSG_S_SOUND_STR, buffer, sizeof(buffer), + sound); + if(rcode != -1) + { + // Send the message. + //////////////////// + if(sendClient == -1) + Broadcast(buffer, rcode, -1, GT2False); + else + gt2Send(clients[sendClient].connection, (const GT2Byte *)buffer, rcode, GT2False); + } +} + +void SendNumAsteroids +( + int total, + int sendClient +) +{ + char buffer[32]; + int rcode; + + assert(sendClient >= -1); + assert(sendClient < MAX_CLIENTS); + assert(clients[sendClient].used); + assert(clients[sendClient].connection); + assert(total >= 0); + assert(total <= PLAYER_MAX_ASTEROIDS); + + // Encode the message. + ///////////////////// + rcode = gtEncode(MSG_S_NUMASTEROIDS, MSG_S_NUMASTEROIDS_STR, buffer, sizeof(buffer), + (byte)total);; + if(rcode != -1) + { + // Send the message. + //////////////////// + gt2Send(clients[sendClient].connection, (const GT2Byte *)buffer, rcode, GT2True); + } +} + +static void SendUpdates +( + void +) +{ + int i; + char * buffer; + int len; + static char update[1024 * 8]; + Client * client; + SObject * object; + unsigned long now; + int rcode; + + // Get the current time. + //////////////////////// + now = current_time(); + + // Setup the encoding parameters. + ///////////////////////////////// + buffer = update; + len = sizeof(update); + + // First encode the header. + /////////////////////////// + rcode = gtEncode(MSG_S_UPDATE, MSG_S_UPDATE_STR, buffer, len, + nextServerUpdateID++, + numClients, + numObjects); + if(rcode == -1) + return; + buffer += rcode; + len -= rcode; + + // Encode each client. + ////////////////////// + for(i = 0 ; i < MAX_CLIENTS ; i++) + { + if(clients[i].used) + { + client = &clients[i]; + + rcode = gtEncodeNoType(MSG_S_UPDATE_CLIENT_STR, buffer, len, + i, + PositionToUnsignedShort(client->position[0]), + PositionToUnsignedShort(client->position[1]), + RotationToUnsignedShort(client->rotation), + client->score, + client->motion == FORWARD ? 1 : 0, + client->motion == BACKWARD ? 1 : 0, + client->turning == RIGHT ? 1 : 0, + client->turning == LEFT ? 1 : 0, + client->dead); + if(rcode == -1) + return; + buffer += rcode; + len -= rcode; + } + } + + // Encode each object. + ////////////////////// + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + if(sObjects[i].used) + { + object = &sObjects[i]; + + rcode = gtEncodeNoType(MSG_S_UPDATE_OBJECT_STR, buffer, len, + object->type, + PositionToUnsignedShort(object->position[0]), + PositionToUnsignedShort(object->position[1]), + RotationToUnsignedShort(object->rotation), + (now - object->startTime)); + if(rcode == -1) + return; + buffer += rcode; + len -= rcode; + } + } + + // Send the update. + /////////////////// + Broadcast(update, sizeof(update) - len, -1, GT2False); +} + +static void ServerReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + int clientIndex; + Client * client; + GTMessageType type; + int rcode; + + // Check for no message. + //////////////////////// + if(!message) + return; + + // Which client was this? + ///////////////////////// + clientIndex = (int)gt2GetConnectionData(connection); + assert((clientIndex >= 0) && (clientIndex < MAX_CLIENTS)); + if((clientIndex < 0) || (clientIndex >= MAX_CLIENTS)) + return; + assert(clients[clientIndex].used); + if(!clients[clientIndex].used) + return; + client = &clients[clientIndex]; + + // Get the message type. + //////////////////////// + type = gtEncodedMessageType((char *)message); + + // Update? + ////////// + if(type == MSG_C_UPDATE) + { + unsigned short updateID; + unsigned long now; + byte forward; + byte backward; + byte right; + byte left; + unsigned short packedRotation; + + // Get the time we received it. + /////////////////////////////// + now = current_time(); + + // Decode it. + ///////////// + rcode = gtDecode(MSG_C_UPDATE_STR, (char *)message, len, + &updateID, + &packedRotation, + &forward, + &backward, + &right, + &left); + if(rcode == -1) + return; + + // Set the rotation. + //////////////////// + client->rotation = UnsignedShortToRotation(packedRotation); + + // Interpret the motion & turning bits. + /////////////////////////////////////// + if(forward) + client->motion = FORWARD; + else if(backward) + client->motion = BACKWARD; + else + client->motion = STILL; + if(right) + client->turning = RIGHT; + else if(left) + client->turning = LEFT; + else + client->turning = STILL; + + // Check if we should move the client. + ////////////////////////////////////// + if(client->lastUpdate && !client->dead && client->motion) + { + unsigned long diff; + + // Get how long since the last update. + ////////////////////////////////////// + diff = (now - client->lastUpdate); + + // Compute the new position. + //////////////////////////// + ComputeNewPosition( + client->position, + client->position, + client->motion, + client->rotation, + diff, + PLAYER_SPEED, + GT2True); + } + + // Set the last update time. + //////////////////////////// + client->lastUpdate = now; + } + // Press? + ///////// + else if(type == MSG_C_PRESS) + { + unsigned long now; + char press[64]; + + // A dead client can't fire. + //////////////////////////// + if(client->dead) + return; + + // Get the current time. + //////////////////////// + now = current_time(); + + // Is this too soon? + //////////////////// + if((now - client->lastPress) < PRESS_TIME) + return; + + // Decode it. + ///////////// + rcode = gtDecode(MSG_C_PRESS_STR, (char *)message, len, + press); + if(rcode == -1) + return; + + // The last press. + ////////////////// + client->lastPress = now; + + // Do the press. + //////////////// + ClientPress(clientIndex, press); + } + // Chat? + //////// + else if(type == MSG_C_CHAT) + { + char buffer[MAX_NICK + CHAT_MAX + 16]; + + // Start forming the outgoing chat message. + /////////////////////////////////////////// + sprintf(buffer, "%s: ", client->nick); + + // Decode the incoming message. + /////////////////////////////// + rcode = gtDecode(MSG_C_CHAT_STR, (char *)message, len, + buffer + strlen(buffer)); + if(rcode == -1) + return; + + // Send this chat message out to everyone. + ////////////////////////////////////////// + BroadcastText(buffer, -1, GT2True); + } +} + +static void ServerClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + int clientIndex; + int i; + SObject * object; + + // Which client was this? + ///////////////////////// + clientIndex = (int)gt2GetConnectionData(connection); + assert((clientIndex >= 0) && (clientIndex < MAX_CLIENTS)); + if((clientIndex < 0) || (clientIndex >= MAX_CLIENTS)) + return; + assert(clients[clientIndex].used); + if(!clients[clientIndex].used) + return; + + // Remove this client. + ////////////////////// + RemoveClient(clientIndex); + + // Send the remove client message. + ////////////////////////////////// + for(i = 0 ; i < MAX_CLIENTS ; i++) + if(clients[i].used) + SendDelClient(i, clientIndex); + + // Mark all owned objects as not owned. + /////////////////////////////////////// + for(i = 0 ; i < MAX_OBJECTS ; i++) + { + object = &sObjects[i]; + if(object->used && (object->owner == clientIndex)) + object->owner = -1; + } +} + +static void ServerConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + int newClientIndex; + Client * newClient; + int i; + char nick[MAX_NICK]; + int rcode; + + // Make sure we got a message. + ////////////////////////////// + if(!message) + { + gt2Reject(connection, (const GT2Byte *)"No initial data received", -1); + return; + } + + // Check the message type. + ////////////////////////// + if(gtEncodedMessageType((char *)message) != MSG_C_INITIAL) + { + gt2Reject(connection, (const GT2Byte *)"Bad message type", -1); + return; + } + + // Decode the data. + /////////////////// + rcode = gtDecode(MSG_C_INITIAL_STR, (char *)message, len, + nick); + if(rcode == -1) + { + gt2Reject(connection, (const GT2Byte *)"Bad message data", -1); + return; + } + + // Add the client to the list. + ////////////////////////////// + newClientIndex = AddClient(); + if(newClientIndex == -1) + { + gt2Reject(connection, (const GT2Byte *)"Server full", -1); + return; + } + newClient = &clients[newClientIndex]; + + // Accept the connection. + ///////////////////////// + if(!gt2Accept(connection, &connectionCallbacks)) + { + // Remove the client. + ///////////////////// + RemoveClient(newClientIndex); + return; + } + + // Set the connection's data to its index. + ////////////////////////////////////////// + gt2SetConnectionData(connection, (void *)newClientIndex); + + // Set some properties for the new client. + ////////////////////////////////////////// + newClient->connection = connection; + strncpy(newClient->nick, nick, MAX_NICK); + newClient->nick[MAX_NICK - 1] = '\0'; + + // Spawn the client. + //////////////////// + ClientSpawn(newClient); + + // Send new client message for the clients already connected. + // Also send new client messages for new client to other clients. + ///////////////////////////////////////////////////////////////// + for(i = 0 ; i < MAX_CLIENTS ; i++) + { + if(clients[i].used) + { + SendAddClient(i, newClientIndex); + if(i != newClientIndex) + SendAddClient(newClientIndex, i); + } + } + + // It has no asteroids. + /////////////////////// + SendNumAsteroids(0, newClientIndex); + + // Tell the new client it can start. + //////////////////////////////////// + SendStart(newClientIndex); +} + +static void ServerSocketErrorCallback +( + GT2Socket socket +) +{ + printf("Server socket error\n"); +} + +GT2Bool InitializeServer +( + void +) +{ + GT2Result result; + int i; + + // Setup callback structs. + ////////////////////////// + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.received = ServerReceivedCallback; + connectionCallbacks.closed = ServerClosedCallback; + + // Set client indices. + ////////////////////// + for(i = 0 ; i < MAX_CLIENTS ; i++) + clients[i].index = i; + + // Create the socket. + ///////////////////// + result = gt2CreateSocket(&Socket, PORT_STRING, 0, 0, ServerSocketErrorCallback); + if(result != GT2Success) + return GT2False; + + // Listen. + ////////// + gt2Listen(Socket, ServerConnectAttemptCallback); + + // Initialize the logic. + //////////////////////// + InitializeLogic(); + + return GT2True; +} + +void ServerThink +( + unsigned long now +) +{ + static GT2Bool firstTime = GT2True; + static unsigned long last; + unsigned long diff; + + // Think. + ///////// + gt2Think(Socket); + + // The first time through just store the time. + // This is so diff is accurate the second time through. + /////////////////////////////////////////////////////// + if(firstTime) + { + firstTime = GT2False; + last = now; + return; + } + + // How long since the last update? + ////////////////////////////////// + diff = (now - last); + + // Check for an update. + /////////////////////// + if(diff < SERVER_THINK_TIME) + return; + + // New last update. + /////////////////// + last = now; + + // Process objects. + /////////////////// + ObjectsThink(now, diff); + + // Send updates. + //////////////// + SendUpdates(); +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aServer.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aServer.h new file mode 100644 index 00000000000..d02b7a0cd20 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aServer.h @@ -0,0 +1,65 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2ASERVER_H_ +#define _GT2ASERVER_H_ + +#define MAX_CLIENTS MAX_PLAYERS + +typedef struct Client +{ + GT2Bool used; // If this slot is in use or not. + int index; // This client's clientIndex. + GT2Connection connection; // The GT2Connection for this client. + V2f position; // The current position (0 <= x,y < MAP_MAX). + float rotation; // Client's view angle (0 <= rotation < 360). + int motion; // Client's current motion (STILL, FORWARD, BACKWARD). + int turning; // Client's current turning direction (STILL, LEFT, RIGHT). + unsigned long lastUpdate; // Last update received from this client. + char nick[MAX_NICK]; // The client's nick. + int score; // The client's score. + GT2Bool dead; // True if this client was killed and not respawned. + unsigned long spawnTime; // If dead, spawn at this time. + unsigned long lastPress; // When the last press event was received. + int numAsteroids; // The number of asteroids being held by this player. +} Client; + +extern Client clients[MAX_CLIENTS]; + +GT2Bool InitializeServer +( + void +); + +void ServerThink +( + unsigned long now +); + +void SendSound +( + int sound, + int sendClient +); + +void SendNumAsteroids +( + int total, + int sendClient +); + +void BroadcastText +( + const char * message, + int exceptIndex, + GT2Bool reliable +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aSound.c b/xrGameSpy/gamespy/gt2/gt2action/gt2aSound.c new file mode 100644 index 00000000000..8a68fbceece --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aSound.c @@ -0,0 +1,543 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#include +#include +#include "gt2aMain.h" +#include "gt2aSound.h" +#include "gt2aMath.h" +#include "../../darray.h" + +#define MAX_DUPLICATES 8 + +static GT2Bool playSounds; +static LPDIRECTSOUND DirectSound; +static DArray SoundList; + +typedef struct SoundEffect +{ + LPDIRECTSOUNDBUFFER SoundBuffers[MAX_DUPLICATES]; + int numDuplicates; +} SoundEffect; + +// The order of this list must match up with the order +// of the SOUND_* enums in gt2aSound.h +////////////////////////////////////////////////////// +const char * soundFiles[] = +{ + "sounds\\explosion.wav", + "sounds\\mine.wav", + "sounds\\die.wav", + "sounds\\rocket.wav", + "sounds\\pickup.wav", + NULL +}; + +// Adapted from a Microsoft DirectSound sample. +/////////////////////////////////////////////// +static HRESULT ReadMMIO +( + HMMIO hmmioIn, + MMCKINFO * pckInRIFF, + WAVEFORMATEX ** ppwfxInfo +) +{ + MMCKINFO ckIn; // chunk info. for general use. + PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. + + *ppwfxInfo = NULL; + + if( ( 0 != mmioDescend( hmmioIn, pckInRIFF, NULL, 0 ) ) ) + return E_FAIL; + + if( (pckInRIFF->ckid != FOURCC_RIFF) || + (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E') ) ) + return E_FAIL; + + // Search the input file for for the 'fmt ' chunk. + ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); + if( 0 != mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK) ) + return E_FAIL; + + // Expect the 'fmt' chunk to be at least as large as ; + // if there are extra parameters at the end, we'll ignore them + if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) ) + return E_FAIL; + + // Read the 'fmt ' chunk into . + if( mmioRead( hmmioIn, (HPSTR) &pcmWaveFormat, + sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) ) + return E_FAIL; + + // Allocate the waveformatex, but if its not pcm format, read the next + // word, and thats how many extra bytes to allocate. + if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM ) + { + if( NULL == ( *ppwfxInfo = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX)))) + return E_FAIL; + + // Copy the bytes from the pcm structure to the waveformatex structure + memcpy( *ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat) ); + (*ppwfxInfo)->cbSize = 0; + } + else + { + // Read in length of extra bytes. + WORD cbExtraBytes = 0L; + if( mmioRead( hmmioIn, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) ) + return E_FAIL; + + *ppwfxInfo = (WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX) + cbExtraBytes); + if( NULL == *ppwfxInfo ) + return E_FAIL; + + // Copy the bytes from the pcm structure to the waveformatex structure + memcpy( *ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat) ); + (*ppwfxInfo)->cbSize = cbExtraBytes; + + // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. + if( mmioRead( hmmioIn, (CHAR*)(((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(WORD)), + cbExtraBytes ) != cbExtraBytes ) + { + free(*ppwfxInfo); + *ppwfxInfo = NULL; + return E_FAIL; + } + } + + // Ascend the input file out of the 'fmt ' chunk. + if( 0 != mmioAscend( hmmioIn, &ckIn, 0 ) ) + { + free(*ppwfxInfo); + *ppwfxInfo = NULL; + return E_FAIL; + } + + return S_OK; +} + +// Adapted from a Microsoft DirectSound sample. +/////////////////////////////////////////////// +static HRESULT WaveOpenFile +( + CHAR * strFileName, + HMMIO * phmmioIn, + WAVEFORMATEX ** ppwfxInfo, + MMCKINFO * pckInRIFF +) +{ + HRESULT hr; + HMMIO hmmioIn = NULL; + + if( NULL == ( hmmioIn = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF|MMIO_READ ) ) ) + return E_FAIL; + + if( FAILED( hr = ReadMMIO( hmmioIn, pckInRIFF, ppwfxInfo ) ) ) + { + mmioClose( hmmioIn, 0 ); + return hr; + } + + *phmmioIn = hmmioIn; + + return S_OK; +} + +// Adapted from a Microsoft DirectSound sample. +/////////////////////////////////////////////// +static HRESULT WaveStartDataRead +( + HMMIO * phmmioIn, + MMCKINFO * pckIn, + MMCKINFO * pckInRIFF +) +{ + // Seek to the data + if( -1 == mmioSeek( *phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC), + SEEK_SET ) ) + return E_FAIL; + + // Search the input file for for the 'data' chunk. + pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a'); + if( 0 != mmioDescend( *phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK ) ) + return E_FAIL; + + return S_OK; +} + +// Adapted from a Microsoft DirectSound sample. +/////////////////////////////////////////////// +static HRESULT WaveReadFile +( + HMMIO hmmioIn, + UINT cbRead, + BYTE * pbDest, + MMCKINFO * pckIn, + UINT * cbActualRead +) +{ + MMIOINFO mmioinfoIn; // current status of + UINT cbDataIn; + DWORD cT; + + *cbActualRead = 0; + + if( 0 != mmioGetInfo( hmmioIn, &mmioinfoIn, 0 ) ) + return E_FAIL; + + cbDataIn = cbRead; + if( cbDataIn > pckIn->cksize ) + cbDataIn = pckIn->cksize; + + pckIn->cksize -= cbDataIn; + + for(cT = 0; cT < cbDataIn; cT++ ) + { + // Copy the bytes from the io to the buffer. + if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead ) + { + if( 0 != mmioAdvance( hmmioIn, &mmioinfoIn, MMIO_READ ) ) + return E_FAIL; + + if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead ) + return E_FAIL; + } + + // Actual copy. + *((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext); + mmioinfoIn.pchNext++; + } + + if( 0 != mmioSetInfo( hmmioIn, &mmioinfoIn, 0 ) ) + return E_FAIL; + + *cbActualRead = cbDataIn; + return S_OK; +} + +// If restoreBuffer is not NULL, restore it! +//////////////////////////////////////////// +static GT2Bool LoadSound +( + int sound, + const char * filename, + LPDIRECTSOUNDBUFFER restoreBuffer +) +{ + int rcode; + HRESULT result; + LPWAVEFORMATEX waveFormat; + HMMIO IOHandle; + MMCKINFO dataChunkInfo; + MMCKINFO parentChunkInfo; + DSBUFFERDESC bufferDescriptor; + SoundEffect soundEffect; + LPVOID lockedBuffer; + DWORD lockedBufferLen; + UINT numBytes; + LPDIRECTSOUNDBUFFER soundBuffer; + + // Open the file. + ///////////////// + rcode = WaveOpenFile((char *)filename, &IOHandle, &waveFormat, &parentChunkInfo); + if(rcode) + return GT2False; + + // Prepare to read the data chunk. + ////////////////////////////////// + rcode = WaveStartDataRead(&IOHandle, &dataChunkInfo, &parentChunkInfo); + if(rcode) + return GT2False; + + // If we're not restoring, create the buffer. + ///////////////////////////////////////////// + if(!restoreBuffer) + { + // Clear our sound object. + ////////////////////////// + memset(&soundEffect, 0, sizeof(SoundEffect)); + soundEffect.numDuplicates = 1; + + // Describe the desired buffer. + /////////////////////////////// + memset(&bufferDescriptor, 0, sizeof(DSBUFFERDESC)); + bufferDescriptor.dwSize = sizeof(DSBUFFERDESC); + bufferDescriptor.dwFlags = DSBCAPS_STATIC; + bufferDescriptor.dwBufferBytes = dataChunkInfo.cksize; + bufferDescriptor.lpwfxFormat = waveFormat; + + // Create the buffer. + ///////////////////// + result = IDirectSound_CreateSoundBuffer( + DirectSound, + &bufferDescriptor, + &soundEffect.SoundBuffers[0], + NULL); + if(FAILED(result)) + { + mmioClose(IOHandle, 0); + return GT2False; + } + + // Set the sound buffer pointer. + //////////////////////////////// + soundBuffer = soundEffect.SoundBuffers[0]; + } + else + { + // Set the sound buffer pointer. + //////////////////////////////// + soundBuffer = restoreBuffer; + } + + // Lock the buffer. + /////////////////// + result = IDirectSoundBuffer_Lock( + soundBuffer, + 0, + 0, + &lockedBuffer, + &lockedBufferLen, + NULL, + NULL, + DSBLOCK_ENTIREBUFFER); + if(FAILED(result)) + { + mmioClose(IOHandle, 0); + return GT2False; + } + + // Read the data into the buffer. + ///////////////////////////////// + rcode = WaveReadFile( + IOHandle, + lockedBufferLen, + (BYTE *)lockedBuffer, + &dataChunkInfo, + &numBytes); + if(rcode) + { + mmioClose(IOHandle, 0); + return GT2False; + } + + // Unlock the buffer. + ///////////////////// + IDirectSoundBuffer_Unlock( + soundBuffer, + lockedBuffer, + lockedBufferLen, + NULL, + 0); + + // Close the file. + ////////////////// + mmioClose(IOHandle, 0); + + // Add this sound to the list if its new. + ///////////////////////////////////////// + if(!restoreBuffer) + ArrayAppend(SoundList, &soundEffect); + + return GT2True; +} + +GT2Bool InitializeSound +( + void +) +{ + HRESULT result; + HWND hWnd; + int i; + + // Init the sound list. + /////////////////////// + SoundList = ArrayNew(sizeof(SoundEffect), 0, NULL); + if(!SoundList) + return GT2False; + + // Init direct sound. + ///////////////////// + result = DirectSoundCreate(NULL, &DirectSound, NULL); + if(FAILED(result)) + return GT2False; + + // Get the window handle. + ///////////////////////// + hWnd = GetForegroundWindow(); + if(!hWnd) + hWnd = GetDesktopWindow(); + + // Set the cooperative level. + ///////////////////////////// + result = IDirectSound_SetCooperativeLevel(DirectSound, hWnd, DSSCL_PRIORITY); + if(FAILED(result)) + return GT2False; + + // Load the sounds. + /////////////////// + for(i = 0 ; i < NUM_SOUNDS ; i++) + { + assert(soundFiles[i]); + if(!soundFiles[i]) + return GT2False; + LoadSound(i, soundFiles[i], NULL); + } + assert(!soundFiles[i]); + + // Turn on sound. + ///////////////// + playSounds = GT2True; + + return GT2True; +} + +void CleanupSound +( + void +) +{ + // Cleanup the sound list. + ////////////////////////// + ArrayFree(SoundList); + + // Cleanup DirectSound. + /////////////////////// + if(DirectSound) + { + IDirectSound_Release(DirectSound); + DirectSound = NULL; + } + + // COM crap. + //////////// + CoUninitialize(); +} + +void ToggleSound +( + void +) +{ + playSounds = !playSounds; +} + +void PlaySoundEffect +( + int sound +) +{ + SoundEffect * soundEffect; + HRESULT result; + DWORD status; + int i; + + // Make sure we're playing sounds. + ////////////////////////////////// + if(!playSounds) + return; + + // Get the correct sound. + ///////////////////////// + soundEffect = (SoundEffect *)ArrayNth(SoundList, sound); + assert(soundEffect); + if(!soundEffect) + return; + + // Find a free buffer. + ////////////////////// + for(i = 0 ; i < soundEffect->numDuplicates ; i++) + { + // Get the current status. + ////////////////////////// + result = IDirectSoundBuffer_GetStatus(soundEffect->SoundBuffers[i], &status); + if(FAILED(result)) + return; + + // Did it lose its buffer? + ////////////////////////// + if(status & DSBSTATUS_BUFFERLOST) + { + // Restore the buffer. + ////////////////////// + result = IDirectSoundBuffer_Restore(soundEffect->SoundBuffers[i]); + if(FAILED(result)) + continue; + + // Fill the sound data back in. + /////////////////////////////// + if(!LoadSound(sound, soundFiles[sound], soundEffect->SoundBuffers[i])) + continue; + } + + // Is it free? + ////////////// + if(!(status & DSBSTATUS_PLAYING)) + break; + } + + // Did we not find anything? + //////////////////////////// + if(i == soundEffect->numDuplicates) + { + // Are we at max duplicates? + //////////////////////////// + if(i == MAX_DUPLICATES) + { + // Just use a random buffer. + //////////////////////////// + i = RandomInt(0, MAX_DUPLICATES - 1); + } + else + { + // Make a new duplicate. + //////////////////////// + result = IDirectSound_DuplicateSoundBuffer( + DirectSound, + soundEffect->SoundBuffers[0], + &soundEffect->SoundBuffers[i]); + if(FAILED(result)) + return; + + // One more duplicate. + ////////////////////// + soundEffect->numDuplicates++; + } + } + + // Make sure the buffer is rewound. + /////////////////////////////////// + IDirectSoundBuffer_SetCurrentPosition(soundEffect->SoundBuffers[i], 0); + + // Play it. + /////////// + result = IDirectSoundBuffer_Play(soundEffect->SoundBuffers[i], 0, 0, 0); + + // Check for a lost buffer. + /////////////////////////// + if(result == DSERR_BUFFERLOST) + { + // Restore the buffer. + ////////////////////// + result = IDirectSoundBuffer_Restore(soundEffect->SoundBuffers[i]); + if(FAILED(result)) + return; + + // Fill the sound data back in. + /////////////////////////////// + if(!LoadSound(sound, soundFiles[sound], soundEffect->SoundBuffers[i])) + return; + + // Try playing again. + ///////////////////// + IDirectSoundBuffer_Play(soundEffect->SoundBuffers[i], 0, 0, 0); + } +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2aSound.h b/xrGameSpy/gamespy/gt2/gt2action/gt2aSound.h new file mode 100644 index 00000000000..f5d3ca6cc33 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2aSound.h @@ -0,0 +1,44 @@ +/* +GameSpy GT2 SDK +GT2Action - sample app +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifndef _GT2ASOUND_H_ +#define _GT2ASOUND_H_ + +enum +{ + SOUND_EXPLOSION, + SOUND_MINE, + SOUND_DIE, + SOUND_ROCKET, + SOUND_PICKUP, + NUM_SOUNDS +}; + +GT2Bool InitializeSound +( + void +); + +void CleanupSound +( + void +); + +void ToggleSound +( + void +); + +void PlaySoundEffect +( + int sound +); + +#endif \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2action.dsp b/xrGameSpy/gamespy/gt2/gt2action/gt2action.dsp new file mode 100644 index 00000000000..74c5e35b5f5 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2action.dsp @@ -0,0 +1,591 @@ +# Microsoft Developer Studio Project File - Name="gt2action" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gt2action - 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 "gt2action.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 "gt2action.mak" CFG="gt2action - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2action - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2action - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2action", DQOCAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2action - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 dsound.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:console /machine:I386 /out:"gt2action.exe" /ignore:4089 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "gt2action - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 dsound.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:console /debug /machine:I386 /out:"gt2action.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gt2action - Win32 Release" +# Name "gt2action - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2aClient.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aDisplay.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aInput.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aLogic.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aMain.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aMath.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aParse.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aServer.c +# End Source File +# Begin Source File + +SOURCE=.\gt2aSound.c +# End Source File +# Begin Source File + +SOURCE=.\TGAFile.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gt2aClient.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aDisplay.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aInput.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aLogic.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aMain.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aMath.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aParse.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aServer.h +# End Source File +# Begin Source File + +SOURCE=.\gt2aSound.h +# End Source File +# Begin Source File + +SOURCE=.\TGAFile.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.h +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "Images" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\images\asteroid0.tga +# End Source File +# Begin Source File + +SOURCE=.\images\asteroid1.tga +# End Source File +# Begin Source File + +SOURCE=.\images\asteroid2.tga +# End Source File +# Begin Source File + +SOURCE=.\images\explosion0.tga +# End Source File +# Begin Source File + +SOURCE=.\images\explosion1.tga +# End Source File +# Begin Source File + +SOURCE=.\images\mine0.tga +# End Source File +# Begin Source File + +SOURCE=.\images\mine1.tga +# End Source File +# Begin Source File + +SOURCE=.\images\mine2.tga +# End Source File +# Begin Source File + +SOURCE=.\images\rocket0.tga +# End Source File +# Begin Source File + +SOURCE=.\images\rocket1.tga +# End Source File +# Begin Source File + +SOURCE=.\images\rocket2.tga +# End Source File +# Begin Source File + +SOURCE=.\images\rocket3.tga +# End Source File +# Begin Source File + +SOURCE=.\images\ship0.tga +# End Source File +# Begin Source File + +SOURCE=.\images\ship1.tga +# End Source File +# Begin Source File + +SOURCE=.\images\space.tga +# End Source File +# Begin Source File + +SOURCE=.\images\spinner0.tga +# End Source File +# Begin Source File + +SOURCE=.\images\spinner1.tga +# End Source File +# Begin Source File + +SOURCE=.\images\spinner2.tga +# End Source File +# End Group +# Begin Group "Sounds" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\sounds\die.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\explosion.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\mine.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\pickup.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\rocket.wav +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\messages.txt +# End Source File +# Begin Source File + +SOURCE=.\todo.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2action_vs2005.vcproj b/xrGameSpy/gamespy/gt2/gt2action/gt2action_vs2005.vcproj new file mode 100644 index 00000000000..3c63e2c434f --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2action_vs2005.vcproj @@ -0,0 +1,1259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2action/gt2action_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/gt2/gt2action/gt2action_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/gt2action_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/asteroid0.tga b/xrGameSpy/gamespy/gt2/gt2action/images/asteroid0.tga new file mode 100644 index 00000000000..4bb42e95e58 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/asteroid0.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/asteroid1.tga b/xrGameSpy/gamespy/gt2/gt2action/images/asteroid1.tga new file mode 100644 index 00000000000..f9a3dee83cf Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/asteroid1.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/asteroid2.tga b/xrGameSpy/gamespy/gt2/gt2action/images/asteroid2.tga new file mode 100644 index 00000000000..a3164341de5 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/asteroid2.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/explosion0.tga b/xrGameSpy/gamespy/gt2/gt2action/images/explosion0.tga new file mode 100644 index 00000000000..a47afbb690a Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/explosion0.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/explosion1.tga b/xrGameSpy/gamespy/gt2/gt2action/images/explosion1.tga new file mode 100644 index 00000000000..f857cd2e342 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/explosion1.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/mine0.tga b/xrGameSpy/gamespy/gt2/gt2action/images/mine0.tga new file mode 100644 index 00000000000..62f0fc078ce Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/mine0.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/mine1.tga b/xrGameSpy/gamespy/gt2/gt2action/images/mine1.tga new file mode 100644 index 00000000000..ecde8f6b07c Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/mine1.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/mine2.tga b/xrGameSpy/gamespy/gt2/gt2action/images/mine2.tga new file mode 100644 index 00000000000..3469a023fd0 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/mine2.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/rocket0.tga b/xrGameSpy/gamespy/gt2/gt2action/images/rocket0.tga new file mode 100644 index 00000000000..3f29b44eabb Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/rocket0.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/rocket1.tga b/xrGameSpy/gamespy/gt2/gt2action/images/rocket1.tga new file mode 100644 index 00000000000..0c3841ac9af Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/rocket1.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/rocket2.tga b/xrGameSpy/gamespy/gt2/gt2action/images/rocket2.tga new file mode 100644 index 00000000000..835dc2ca2b8 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/rocket2.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/rocket3.tga b/xrGameSpy/gamespy/gt2/gt2action/images/rocket3.tga new file mode 100644 index 00000000000..65350bbb2ba Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/rocket3.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/ship0.tga b/xrGameSpy/gamespy/gt2/gt2action/images/ship0.tga new file mode 100644 index 00000000000..f8948dcf6c3 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/ship0.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/ship1.tga b/xrGameSpy/gamespy/gt2/gt2action/images/ship1.tga new file mode 100644 index 00000000000..7581e35633a Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/ship1.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/space.tga b/xrGameSpy/gamespy/gt2/gt2action/images/space.tga new file mode 100644 index 00000000000..9ae59d86578 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/space.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/spinner0.tga b/xrGameSpy/gamespy/gt2/gt2action/images/spinner0.tga new file mode 100644 index 00000000000..50018bed0b2 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/spinner0.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/spinner1.tga b/xrGameSpy/gamespy/gt2/gt2action/images/spinner1.tga new file mode 100644 index 00000000000..424da03a9e6 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/spinner1.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/images/spinner2.tga b/xrGameSpy/gamespy/gt2/gt2action/images/spinner2.tga new file mode 100644 index 00000000000..550b672b861 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/images/spinner2.tga differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/messages.txt b/xrGameSpy/gamespy/gt2/gt2action/messages.txt new file mode 100644 index 00000000000..5f1122aa5cd --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/messages.txt @@ -0,0 +1,49 @@ +CLIENT-to-server messages: +=initial-data + byte[3] color + string nick +=update + unsigned short id + unsigned short packedRotation + bit forward + bit backward + bit right + bit left +=press + string button +=chat + string message + +SERVER-to-client messages: +=addclient + byte index + string nick +=delclient + byte index +=start + byte index +=update + unsigned short id + byte numclients + byte numobjects + for each client + byte index + unsigned short[2] packedPosition + unsigned short packedRotation + int score + bit forward + bit backward + bit right + bit left + bit dead + for each object + byte type + unsigned short[2] packedPosition + unsigned short packedRotation + int time +=chat + string message +=sound + byte index +=numasteroids + byte total diff --git a/xrGameSpy/gamespy/gt2/gt2action/sounds/die.wav b/xrGameSpy/gamespy/gt2/gt2action/sounds/die.wav new file mode 100644 index 00000000000..68fcdda1e04 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/sounds/die.wav differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/sounds/explosion.wav b/xrGameSpy/gamespy/gt2/gt2action/sounds/explosion.wav new file mode 100644 index 00000000000..d36b4a8d2d5 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/sounds/explosion.wav differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/sounds/mine.wav b/xrGameSpy/gamespy/gt2/gt2action/sounds/mine.wav new file mode 100644 index 00000000000..ea0f6645ca7 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/sounds/mine.wav differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/sounds/pickup.wav b/xrGameSpy/gamespy/gt2/gt2action/sounds/pickup.wav new file mode 100644 index 00000000000..a00a969f797 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/sounds/pickup.wav differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/sounds/rocket.wav b/xrGameSpy/gamespy/gt2/gt2action/sounds/rocket.wav new file mode 100644 index 00000000000..dd3102fdb5c Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2action/sounds/rocket.wav differ diff --git a/xrGameSpy/gamespy/gt2/gt2action/todo.txt b/xrGameSpy/gamespy/gt2/gt2action/todo.txt new file mode 100644 index 00000000000..56c11da22de --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2action/todo.txt @@ -0,0 +1,23 @@ +- add S->C event support ("\event\explosion\pos\280 640") +- save settings (nick, color, prediction, etc.) +- improve comments +- slow bouncy lasers +- map/walls +- safe spawns +- better feedback for dedicated server (not just "connecting") +- sound doesn't worked when launched from debugger but not debugging (Ctrl-F5) +- add bytes/sec to net graph +- write filter to analyze byte frequencies +- show message on server shutdown +- only send changed values for players/objects +- assert, darray.c, line 120 +- do prediction at start of frame, then use that for drawing and radar +- do adjustments based on when a server update should have arrived? +- second background moving at different speed? +- position smoothing causes weirdness when respawning +- cleaner menu setup system? +- random number and positions for spinner +- AddRocket, AddMine, etc. +- smarter server updates + - for each object, determine what values are dynamic + - pre-determine what values will be sent for each object-type diff --git a/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig.c b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig.c new file mode 100644 index 00000000000..0b4e6cf4997 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig.c @@ -0,0 +1,674 @@ +/****** +gt2hostmig.c +GameSpy Transport 2 SDK +GameSpy Query & Reporting 2 SDK + +Copyright 2000 GameSpy Industries, Inc + +****** + + This sample demonstrates the use of the Transport 2 SDK to do host migration. + It also uses the Query & Reporting 2 SDK to report the host to the + Master Server. + + Please see the GameSpy Transport 2 SDK documentation for more + information + +******/ + + +/************* +** INCLUDES ** +*************/ +#include +#include "../gt2.h" +// Needed for the QR2 portion of code +#include "../../qr2/qr2.h" + +/************ +** DEFINES ** +************/ +#define PORT 12345 +#define MAX_CLIENTS 8 +#define TIMEOUT (30 * 1000) +#define SEND_TIME 500// (10 * 1000) + +#define REPORT + +/************ +** GLOBALS ** +************/ +GT2Bool hosting; +GT2Bool quit; +GT2ConnectionCallbacks connectionCallbacks; +char messageKey[128]; +char messageValue[128]; +unsigned int backupHost; +int backupHostIndex; +GT2Bool gotBackupHost; + +#ifdef REPORT +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// +// Defines for QR2 +#define QR2_GAME_VERSION _T("2.00") +#define QR2_GAME_NAME _T("gmtest") +#define QR2_MAX_PLAYERS MAX_CLIENTS +#define QR2_BASE_PORT 11111 +#define QR2_HOSTNAME _T("My Host") +// end defines +#endif + +GT2Connection clients[MAX_CLIENTS]; +int numClients; + +/********************** +** UTILITY FUNCTIONS ** +**********************/ +GT2Bool ParseMessage +( + const char * message, + int len +) +{ + const char * keyStart; + const char * valueStart; + int copyLen; + int i; + + // Validate the message. + for(i = 0 ; i < (len - 1) ; i++) + { + if(!message[i]) + return GT2False; + } + if(message[i]) + return GT2False; + if(message[0] != '\\') + return GT2False; + + // Find the key/value starts. + keyStart = &message[1]; + valueStart = strchr(keyStart, '\\'); + if(!valueStart) + return GT2False; + valueStart++; + + // Copy in the key. + copyLen = (valueStart - keyStart - 1); + if(copyLen >= sizeof(messageKey)) + return GT2False; + memcpy(messageKey, keyStart, copyLen); + messageKey[copyLen] = '\0'; + + // Copy in the value. + if(strlen(valueStart) >= sizeof(messageValue)) + return GT2False; + strcpy(messageValue, valueStart); + + return GT2True; +} + +const char * GetConnectionName +( + GT2Connection connection +) +{ + return gt2AddressToString(gt2GetRemoteIP(connection), 0, NULL); +} + +void TellBackupHost +( + int index +) +{ + char buffer[32]; + GT2Connection connection = clients[index]; + + // Let him know who the backup host is. + sprintf(buffer, "\\backuphost\\%s", gt2AddressToString(backupHost, 0, NULL)); + gt2Send(connection, (const GT2Byte *)buffer, -1, GT2True); +} + +void NewBackupHost +( + int index +) +{ + int i; + GT2Connection connection = clients[index]; + + // Let him know. + gt2Send(connection, (const GT2Byte *)("\\backuphost\\"), -1, GT2True); + backupHost = gt2GetRemoteIP(connection); + backupHostIndex = index; + + // Let others know. + for(i = 0 ; i < MAX_CLIENTS ; i++) + { + if(clients[i] && (i != index)) + TellBackupHost(i); + } +} + +/****************** +** QR2 CALLBACKS ** +******************/ +#ifdef REPORT + +void server_key_callback(int keyid, qr2_buffer_t outbuf, void *userdata) +{ + switch (keyid) + { + case HOSTNAME_KEY: + qr2_buffer_add(outbuf, QR2_HOSTNAME); + break; + case GAMEVER_KEY: + qr2_buffer_add(outbuf, QR2_GAME_VERSION); + break; + case HOSTPORT_KEY: + qr2_buffer_add_int(outbuf, PORT); + break; + case NUMPLAYERS_KEY: + qr2_buffer_add_int(outbuf, numClients); + break; + case MAXPLAYERS_KEY: + qr2_buffer_add_int(outbuf, QR2_MAX_PLAYERS); + break; + + default: + qr2_buffer_add(outbuf, _T("")); + } + + GSI_UNUSED(userdata); +} + +// Called when a player key needs to be reported +void playerkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + //check for valid index + if (index >= numClients) + { + qr2_buffer_add(outbuf, _T("")); + return; + } + switch (keyid) + { + case PLAYER__KEY: + qr2_buffer_add(outbuf, GetConnectionName(clients[index])); + break; + default: + qr2_buffer_add(outbuf, _T("")); + break; + } + + GSI_UNUSED(userdata); +} + +// Called when a team key needs to be reported +void teamkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + qr2_buffer_add(outbuf, _T("")); + + GSI_UNUSED(userdata); + GSI_UNUSED(index); + GSI_UNUSED(keyid); +} + +// Called when we need to report the list of keys we report values for +void keylist_callback(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata) +{ + //need to add all the keys we support + switch (keytype) + { + case key_server: + qr2_keybuffer_add(keybuffer, HOSTNAME_KEY); + qr2_keybuffer_add(keybuffer, GAMEVER_KEY); + qr2_keybuffer_add(keybuffer, HOSTPORT_KEY); + qr2_keybuffer_add(keybuffer, NUMPLAYERS_KEY); + qr2_keybuffer_add(keybuffer, MAXPLAYERS_KEY); + break; + case key_player: + qr2_keybuffer_add(keybuffer, PLAYER__KEY); + break; + // no team keys are added since there is no team play in this game + case key_team: + break; + } + + GSI_UNUSED(userdata); +} + +// Called when we need to report the number of players and teams +int count_callback(qr2_key_type keytype, void *userdata) +{ + if (keytype == key_player) + return numClients; + else if (keytype == key_team) + // 0 = Zero teams + return 0; + else + return 0; + + GSI_UNUSED(userdata); +} + +// Called if our registration with the GameSpy master server failed +void adderror_callback(qr2_error_t error, gsi_char *errmsg, void *userdata) +{ + _tprintf(_T("Error adding server: %d, %s\n"), error, errmsg); + + GSI_UNUSED(userdata); +} + +#endif + +/********************* +** SOCKET CALLBACKS ** +*********************/ +void ConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + int i; + + // Do we have a spot open? + for(i = 0 ; i < MAX_CLIENTS ; i++) + { + if(!clients[i]) + break; + } + if(i == MAX_CLIENTS) + { + // Nothing open, reject. + gt2Reject(connection, (const GT2Byte *)("Server full"), -1); + printf("Rejected client, server full\n"); + return; + } + + // We have a spot. + if(!gt2Accept(connection, &connectionCallbacks)) + return; + + // Add him to the list. + clients[i] = connection; + numClients++; + + // Store the index in the connection data. + gt2SetConnectionData(connection, (void *)i); + + printf("Connection accepted from %s\n", GetConnectionName(connection)); + + // Is this the only client? + if(numClients == 1) + { + // He's the backup host. + NewBackupHost(i); + } + else + { + // Let him know who the backup host is. + TellBackupHost(i); + } + + GSI_UNUSED(len); + GSI_UNUSED(message); + GSI_UNUSED(latency); + GSI_UNUSED(port); + GSI_UNUSED(ip); + GSI_UNUSED(socket); +} + +void SocketErrorCallback +( + GT2Socket socket +) +{ + printf("socket error!\n"); + quit = GT2True; + + GSI_UNUSED(socket); +} + +/************************* +** CONNECTION CALLBACKS ** +*************************/ +void ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + if(result != GT2Success) + { + printf("Connection failed: "); + if(result == GT2OutOfMemory) + printf("OutOfMemory\n"); + else if(result == GT2Rejected) + printf("Rejected: %s\n", message); + else if(result == GT2NetworkError) + printf("NetworkError\n"); + else if(result == GT2AddressError) + printf("AddressError\n"); + else if(result == GT2DuplicateAddress) + printf("DuplicateAddress\n"); + else if(result == GT2TimedOut) + printf("TimedOut\n"); + else if(result == GT2NegotiationError) + printf("NegotiationError\n"); + else + printf("Unknown error\n"); + + quit = GT2True; + return; + } + + printf("Connection accepted\n"); + + GSI_UNUSED(len); + GSI_UNUSED(connection); +} + +void ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + if(!ParseMessage((const char *)message, len)) + { + printf("Error parsing incoming message from %s\n", GetConnectionName(connection)); + return; + } + + // Check for quit. + if(strcasecmp(messageKey, "quit") == 0) + { + printf("Got remote quit: %s\n", messageValue); + quit = GT2True; + return; + } + + // Are we the host? + if(hosting) + { + // Check for echo. + if(strcasecmp(messageKey, "echo") == 0) + { + // Send back the same. + gt2Send(connection, message, len, reliable); + return; + } + } + else + { + // Check for echo reply. + if(strcasecmp(messageKey, "echo") == 0) + return; + + // Check for a backup-host. + if(strcasecmp(messageKey, "backuphost") == 0) + { + printf("New backup host: %s\n", messageValue); + + // Get the backup IP. + gt2StringToAddress(messageValue, &backupHost, NULL); + gotBackupHost = GT2True; + return; + } + } + + // This is an unknown message type. + printf("Unknown message key: %s = %s\n", messageKey, messageValue); +} + +void ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + // Are we the host? + if(hosting) + { + int i; + + // Get the index. + i = (int)gt2GetConnectionData(connection); + + // Clear it from the list. + clients[i] = NULL; + numClients--; + + // Was this the backup host? + if(i == backupHostIndex) + { + // Pick a new backup host. + if(numClients) + { + for(i = 0 ; i < MAX_CLIENTS ; i++) + if(clients[i]) + { + NewBackupHost(i); + break; + } + } + } + + printf("Client connection with %s closed: %d\n", GetConnectionName(connection), reason); + } + else + { + printf("Connection closed\n"); + + // Quit out of here, we'll check for a backup host in main(). + quit = GT2True; + } +} + +/************** +** FUNCTIONS ** +**************/ +GT2Bool StartHosting +( + void +) +{ + qr2_error_t rcode; + GT2Socket socket; + GT2Result result; + + // Clear. + quit = GT2False; + hosting = GT2True; + numClients = 0; + memset(clients, 0, sizeof(GT2Connection) * MAX_CLIENTS); + + + // create the socket + result = gt2CreateSocket(&socket, gt2AddressToString(0, PORT, NULL), 0, 0, SocketErrorCallback); + if(result != GT2Success) + { + printf("Failed to create socket (%d)\n", result); + return GT2False; + } + + // start listening + printf("Starting to listen...\n"); + gt2Listen(socket, ConnectAttemptCallback); + +#ifdef REPORT + // Start reporting. + printf("Starting reporting...\n"); + + rcode = qr2_init(NULL, NULL, QR2_BASE_PORT, "gmtest", "HA6zkS", 1, 1, server_key_callback, playerkey_callback, + teamkey_callback, keylist_callback, count_callback, adderror_callback, NULL); + + if(rcode != e_qrnoerror) + return GT2False; +#endif + + // Think. + while(!quit) + { + gt2Think(socket); + +#ifdef REPORT + qr2_think(NULL); +#endif + msleep(10); + } + +#ifdef REPORT + qr2_shutdown(NULL); +#endif + + return GT2True; +} + +GT2Bool StartConnecting +( + const char * server +) +{ + GT2Connection connection; + GT2Socket socket; + GT2Result result; + char address[256]; + unsigned long lastSendTime = 0; + unsigned long now; + + // Clear. + quit = GT2False; + hosting = GT2False; + gotBackupHost = GT2False; + + // Setup the address with the port. + sprintf(address, "%s:%d", server, PORT); + + // create the socket + result = gt2CreateSocket(&socket, NULL, 0, 0, SocketErrorCallback); + if(result != GT2Success) + { + printf("Error creating the socket! (%d)\n", result); + return GT2False; + } + + // Connect to the host. + printf("Connecting to %s (timeout after %d seconds)...\n", address, TIMEOUT / 1000); + result = gt2Connect(socket, &connection, address, NULL, 0, TIMEOUT, &connectionCallbacks, GT2True); + if(result != GT2Success) + { + printf("Error creating the connection! (%d)\n", result); + return GT2False; + } + + // Think. + while(!quit) + { + // Check for sending a new message. + now = current_time(); + if((now - lastSendTime) > SEND_TIME) + { + // Send an echo message. + gt2Send(connection, (const GT2Byte *)("\\echo\\Hello."), -1, GT2False); + + // New last send time. + lastSendTime = now; + } + + // Think. + gt2Think(socket); + + // Yield. + msleep(10); + } + + return GT2True; +} + +int main +( + int argc, + char ** argv +) +{ + // Set the callbacks. + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.connected = ConnectedCallback; + connectionCallbacks.received = ReceivedCallback; + connectionCallbacks.closed = ClosedCallback; + + // Host if no args. + if(argc < 2) + { + if(!StartHosting()) + printf("Failed to start hosting\n"); + } + else + { + // Do the initial connect. + if(!StartConnecting(argv[1])) + { + printf("Failed to connect\n"); + } + else + { + // Do host migration stuff. + GT2Bool done = GT2False; + do + { + // Do we have a backup host? + if(gotBackupHost) + { + // Are we the backup host? + if(!backupHost) + { + printf("Starting up backup host...\n"); + + // Start hosting. + if(!StartHosting()) + { + printf("Failed to start backup host.\n"); + done = GT2True; + } + } + else + { + const char * address = gt2AddressToString(backupHost, 0, NULL); + + printf("Connecting to backup host %s...\n", address); + + // Start connecting to the new host. + if(!StartConnecting(address)) + { + printf("Failed to connect to backup host.\n"); + done = GT2True; + } + } + } + else + { + printf("No backup host, quitting\n"); + done = GT2True; + } + } + while(!done); + } + } + + getchar(); + + return 0; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig.dsp b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig.dsp new file mode 100644 index 00000000000..53593d273f9 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig.dsp @@ -0,0 +1,312 @@ +# Microsoft Developer Studio Project File - Name="gt2hostmig" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gt2hostmig - 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 "gt2hostmig.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 "gt2hostmig.mak" CFG="gt2hostmig - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2hostmig - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2hostmig - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2hostmig", AQOCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2hostmig - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gt2hostmig - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gt2hostmig - Win32 Release" +# Name "gt2hostmig - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2hostmig.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.h +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig_vs2005.vcproj b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig_vs2005.vcproj new file mode 100644 index 00000000000..47f3085c246 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig_vs2005.vcproj @@ -0,0 +1,756 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2hostmig/gt2hostmig_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/gt2/gt2nat/gt2nat.c b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat.c new file mode 100644 index 00000000000..b5473537891 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat.c @@ -0,0 +1,408 @@ +/****** +gt2nat.c +GameSpy Transport 2 SDK + +Copyright 2000 GameSpy Industries, Inc + +****** + + This sample demonstrates sharing a UDP socket with the Query & Reporting 2 SDK + to enable developers to create games that can be hosted behind a NAT. + + Please see the GameSpy Query & Reporting 2 SDK documentation for more + information + +******/ + + +/******** +INCLUDES +********/ +#include "../gt2.h" +#include "../../qr2/qr2.h" + +#include +#include +#include + +#if defined(_WIN32) && !defined(UNDER_CE) +#include +#endif + +/******** +DEFINES +********/ +#define QR2_GAME_VERSION "2.00" +#define QR2_GAME_NAME "gmtest" +#define QR2_MAX_PLAYERS 32 +#define QR2_BASE_PORT 26900 +#define QR2_RANKINGSON_KEY 100 + +#ifdef _WIN32_WCE +void RetailOutputA(CHAR *tszErr, ...); +#define printf RetailOutputA +#endif + +/******** +TYPDEFS +********/ +//representative of a game player structure +typedef struct +{ + char pname[80]; + int pfrags; + int pdeaths; + int pskill; + int pping; + char pteam[80]; +} player_t; + +//representative of a game data structure +typedef struct +{ + player_t players[QR2_MAX_PLAYERS]; + char mapname[20]; + char hostname[120]; + char gamemode[200]; + char gametype[30]; + int locationid; + int numplayers; + int maxplayers; + int fraglimit; + int timelimit; + int teamplay; + int rankingson; + int hostport; +} gamedata_t; + +/******** +GLOBAL VARS +********/ + +//just to give us bogus data +char *constnames[QR2_MAX_PLAYERS]={"Joe Player","L33t 0n3","Raptor","Gr81","Flubber","Sarge","Void","runaway","Ph3ar","wh00t","gr1nder","Mace","stacy","lamby","Thrush"}; +gamedata_t gamedata; + +// Called when a server key needs to be reported +void serverkey_callback(int keyid, qr2_buffer_t outbuf, void *userdata) +{ + switch (keyid) + { + case HOSTNAME_KEY: + qr2_buffer_add(outbuf, gamedata.hostname); + break; + case GAMEVER_KEY: + qr2_buffer_add(outbuf, QR2_GAME_VERSION); + break; + case HOSTPORT_KEY: + qr2_buffer_add_int(outbuf, gamedata.hostport); + break; + case MAPNAME_KEY: + qr2_buffer_add(outbuf, gamedata.mapname); + break; + case GAMETYPE_KEY: + qr2_buffer_add(outbuf, gamedata.gametype); + break; + case NUMPLAYERS_KEY: + qr2_buffer_add_int(outbuf, gamedata.numplayers); + break; + case MAXPLAYERS_KEY: + qr2_buffer_add_int(outbuf, gamedata.maxplayers); + break; + case GAMEMODE_KEY: + qr2_buffer_add(outbuf, gamedata.gamemode); + break; + case TEAMPLAY_KEY: + qr2_buffer_add_int(outbuf, gamedata.teamplay); + break; + case FRAGLIMIT_KEY: + qr2_buffer_add_int(outbuf, gamedata.fraglimit); + break; + case TIMELIMIT_KEY: + qr2_buffer_add_int(outbuf, gamedata.timelimit); + break; + case QR2_RANKINGSON_KEY: + qr2_buffer_add_int(outbuf, gamedata.rankingson); + break; + default: + qr2_buffer_add(outbuf, _T("")); + } + + GSI_UNUSED(userdata); +} + +// Called when a player key needs to be reported +void playerkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + //check for valid index + if (index >= gamedata.numplayers) + { + qr2_buffer_add(outbuf, _T("")); + return; + } + switch (keyid) + { + case PLAYER__KEY: + qr2_buffer_add(outbuf, gamedata.players[index].pname); + break; + case SKILL__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pskill); + break; + case SCORE__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pfrags); + break; + case DEATHS__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pdeaths); + break; + case PING__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pping); + break; + case TEAM__KEY: + qr2_buffer_add(outbuf, gamedata.players[index].pteam); + break; + default: + qr2_buffer_add(outbuf, _T("")); + break; + } + + GSI_UNUSED(userdata); +} + +// Called when a team key needs to be reported +void teamkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + qr2_buffer_add(outbuf, _T("")); + + GSI_UNUSED(userdata); + GSI_UNUSED(index); + GSI_UNUSED(keyid); +} + +// Called when we need to report the list of keys we report values for +void keylist_callback(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata) +{ + //need to add all the keys we support + switch (keytype) + { + case key_server: + qr2_keybuffer_add(keybuffer, HOSTNAME_KEY); + qr2_keybuffer_add(keybuffer, GAMEVER_KEY); + qr2_keybuffer_add(keybuffer, HOSTPORT_KEY); + qr2_keybuffer_add(keybuffer, MAPNAME_KEY); + qr2_keybuffer_add(keybuffer, GAMETYPE_KEY); + qr2_keybuffer_add(keybuffer, NUMPLAYERS_KEY); + qr2_keybuffer_add(keybuffer, NUMTEAMS_KEY); + qr2_keybuffer_add(keybuffer, MAXPLAYERS_KEY); + qr2_keybuffer_add(keybuffer, GAMEMODE_KEY); + qr2_keybuffer_add(keybuffer, TEAMPLAY_KEY); + qr2_keybuffer_add(keybuffer, FRAGLIMIT_KEY); + qr2_keybuffer_add(keybuffer, TIMELIMIT_KEY); + break; + case key_player: + qr2_keybuffer_add(keybuffer, PLAYER__KEY); + qr2_keybuffer_add(keybuffer, SCORE__KEY); + qr2_keybuffer_add(keybuffer, SKILL__KEY); + qr2_keybuffer_add(keybuffer, DEATHS__KEY); + qr2_keybuffer_add(keybuffer, PING__KEY); + qr2_keybuffer_add(keybuffer, TEAM__KEY); + break; + case key_team: + break; + } + + GSI_UNUSED(userdata); +} + +// Called when we need to report the number of players and teams +int count_callback(qr2_key_type keytype, void *userdata) +{ + if (keytype == key_player) + return gamedata.numplayers; + else if (keytype == key_team) + return 0; + else + return 0; + + GSI_UNUSED(userdata); +} + +// Called if our registration with the GameSpy master server failed +void adderror_callback(qr2_error_t error, gsi_char *errmsg, void *userdata) +{ + _tprintf(_T("Error adding server: %d, %s\n"), error, errmsg); + + GSI_UNUSED(userdata); +} + +/*********** +init_game +Initialize the sample data structures with bogus data +************/ +static void init_game(void) +{ + int i; + int team; + + srand((unsigned int) current_time() ); + gamedata.numplayers = rand() % 15; + gamedata.maxplayers = QR2_MAX_PLAYERS; + for (i = 0 ; i < gamedata.numplayers ; i++) + { + strcpy(gamedata.players[i].pname, constnames[i]); + gamedata.players[i].pfrags = rand() % 32; + gamedata.players[i].pdeaths = rand() % 32; + gamedata.players[i].pskill = rand() % 1000; + gamedata.players[i].pping = rand() % 500; + team = rand() % 3; + if (team == 0) + strcpy(gamedata.players[i].pteam,"Red"); + else if (team == 1) + strcpy(gamedata.players[i].pteam,"Blue"); + else if (team == 2) + strcpy(gamedata.players[i].pteam,""); + } + strcpy(gamedata.mapname,"gmtmap1"); + strcpy(gamedata.gametype,"arena"); + strcpy(gamedata.hostname,"GameMaster Arena Server"); + strcpy(gamedata.gamemode,"openplaying"); + gamedata.fraglimit = 0; + gamedata.timelimit = 40; + gamedata.teamplay = 1; + gamedata.locationid = 1; + gamedata.rankingson = 1; + gamedata.hostport = 25000; +} + +/******* + DoGameStuff +Simulate whatever else a game server does +********/ +void DoGameStuff(void) +{ + msleep(10); +} + +GT2Bool UnrecognizedMessageCallback(GT2Socket socket, unsigned int ip, unsigned short port, GT2Byte * message, int len) +{ + static char buffer[8 * 1024]; + struct sockaddr_in saddr; + + if(!len || !message || ((message[0] != QR_MAGIC_1) && (message[1] != QR_MAGIC_2) && (message[0] != '\\'))) + return GT2False; + + // we want to make sure it is NUL-terminated + len = min(len, (sizeof(buffer) - 1)); + memcpy(buffer, message, len); + buffer[len] = '\0'; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = ip; + saddr.sin_port = htons(port); + //qr_parse_query(NULL, buffer, len, (struct sockaddr *)&saddr); + qr2_parse_query(NULL, buffer, len, (struct sockaddr *)&saddr); + return GT2True; + + GSI_UNUSED(socket); +} + +void ConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + printf("Connection attempt from %s (%d ping)\n", gt2AddressToString(ip, port, NULL), latency); + + gt2Reject(connection, NULL, 0); + + GSI_UNUSED(len); + GSI_UNUSED(message); + GSI_UNUSED(socket); +} + +/******************* + main +Simulates a main program loop +First, initializes the Q&R items, then enters a main loop +*****************/ +#if defined(_PS2) +int test_main(int argc, char **argp) +#else +int main(int argc, char **argp) +#endif +{ + char secret_key[9]; + GT2Socket socket; + GT2Result result; + int natNegotiate = 1; + result = gt2CreateSocket(&socket, gt2AddressToString(0, QR2_BASE_PORT, NULL), 0, 0, NULL); + if(result != GT2Success) + return -1; + + gt2Listen(socket, ConnectAttemptCallback); + + //set the secret key, in a semi-obfuscated manner + secret_key[0] = 'H'; + secret_key[1] = 'A'; + secret_key[2] = '6'; + secret_key[3] = 'z'; + secret_key[4] = 'k'; + secret_key[5] = 'S'; + secret_key[6] = '\0'; + + qr2_register_key(QR2_RANKINGSON_KEY, _T("rankingson")); + /* + //call qr_init_socket with the socket and gamename + if (qr_init_socket(NULL,gt2GetSocketSOCKET(socket), QR2_GAME_NAME, secret_key, basic_callback, + info_callback, rules_callback, players_callback, NULL) != 0) + { + printf("Error starting Q&R SDK\n"); + return -1; + } + */ + + // call the qr2_init_socket with the socket and gamename + if (qr2_init_socket(NULL, gt2GetSocketSOCKET(socket), QR2_BASE_PORT, QR2_GAME_NAME, secret_key, 1, natNegotiate, + serverkey_callback, playerkey_callback, teamkey_callback, keylist_callback, count_callback, + adderror_callback, NULL) != e_qrnoerror) + + { + printf("Error starting QR2 SDK\n"); + return -1; + } + // set the unrecognized message callback + gt2SetUnrecognizedMessageCallback(socket, UnrecognizedMessageCallback); + + init_game(); + + printf("Press any key to quit\n"); +#if defined(_WIN32) && !defined(UNDER_CE) + while (!_kbhit()) +#else + while (1) +#endif + { + DoGameStuff(); + //process our game networking + gt2Think(socket); + //check for / process incoming queries + //qr_process_queries(NULL); + qr2_think(NULL); + } + //let gamemaster know we are shutting down + strcpy(gamedata.gamemode,"exiting"); + //qr_send_exiting(NULL); + //qr_shutdown(NULL); + qr2_shutdown(NULL); + gt2CloseSocket(socket); + return 0; + + GSI_UNUSED(argp); + GSI_UNUSED(argc); +} diff --git a/xrGameSpy/gamespy/gt2/gt2nat/gt2nat.dsp b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat.dsp new file mode 100644 index 00000000000..99ad8a8a5a9 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat.dsp @@ -0,0 +1,320 @@ +# Microsoft Developer Studio Project File - Name="gt2nat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gt2nat - 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 "gt2nat.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 "gt2nat.mak" CFG="gt2nat - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2nat - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2nat - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2nat", TTOCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2nat - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gt2nat - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gt2nat - Win32 Release" +# Name "gt2nat - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2nat.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.h +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2nat/gt2nat_vs2005.vcproj b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat_vs2005.vcproj new file mode 100644 index 00000000000..7be11229e6b --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat_vs2005.vcproj @@ -0,0 +1,765 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2nat/gt2nat_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2nat/gt2nat_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy.c b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy.c new file mode 100644 index 00000000000..85903e4a176 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy.c @@ -0,0 +1,534 @@ + +#include "../gt2.h" +#include "../../darray.h" +#include + + +#define STATS 1 + +GT2Socket Socket; +char RemoteAddress[256]; +char LocalAddress[256]; +GT2Bool Quit; +DArray ServerSockets; + +#if STATS +time_t startTime; +int numConnectAttempts; +int connectResults[8]; +int clientReliableMessagesSent; +int serverReliableMessagesSent; +int clientUnreliableMessagesSent; +int serverUnreliableMessagesSent; +int clientReliableBytesSent; +int serverReliableBytesSent; +int clientUnreliableBytesSent; +int serverUnreliableBytesSent; +int clientCloses; +int serverCloses; +#endif + +void FreeServerSocket(void * elem) +{ + GT2Socket socket = *(GT2Socket *)elem; + + gt2CloseSocket(socket); +} + +int ServerSocketCompare(const void * elem1, const void * elem2) +{ + GT2Socket socket1 = *(GT2Socket *)elem1; + GT2Socket socket2 = *(GT2Socket *)elem2; + + if(socket1 == socket2) + return 0; + return 1; +} + +void RemoveServerSocket(GT2Socket socket) +{ + int index; + + // find it first + index = ArraySearch(ServerSockets, &socket, ServerSocketCompare, 0, 0); + if(index != NOT_FOUND) + ArrayDeleteAt(ServerSockets, index); +} + +/* CLIENT CONNECTIONS */ + +void ClientReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + GT2Connection serverConnection; + + // The server connection for this client connection. + //////////////////////////////////////////////////// + serverConnection = (GT2Connection)gt2GetConnectionData(connection); + + // Pass the data along. + /////////////////////// + gt2Send(serverConnection, message, len, reliable); + +#if STATS + // Update stats. + //////////////// + if(reliable) + { + clientReliableMessagesSent++; + clientReliableBytesSent += len; + } + else + { + clientUnreliableMessagesSent++; + clientUnreliableBytesSent += len; + } +#endif +} + +void ClientClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + GT2Connection serverConnection; + + // The server connection for this client connection. + //////////////////////////////////////////////////// + serverConnection = (GT2Connection)gt2GetConnectionData(connection); + if(serverConnection) + { + // We don't want them to try closing us.... + /////////////////////////////////////////// + gt2SetConnectionData(serverConnection, NULL); + + // Close the connection to the server. + ////////////////////////////////////// + gt2CloseConnection(serverConnection); + } + +#if STATS + // Update stats. + //////////////// + if(reason == GT2LocalClose) + clientCloses++; +#endif +} + +GT2ConnectionCallbacks ClientConnectionCallbacks = +{ + NULL, + ClientReceivedCallback, + ClientClosedCallback +}; + +/* SERVER CONNECTIONS */ + +void ServerSocketErrorCallback +( + GT2Socket socket +) +{ + printf("Server socket error\n"); + Quit = GT2True; + + GSI_UNUSED(socket); +} + +void ServerConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + GT2Connection clientConnection; + + // The client connection for this server connection. + //////////////////////////////////////////////////// + clientConnection = (GT2Connection)gt2GetConnectionData(connection); + + // Check the result. + //////////////////// + if(result == GT2Success) + { + // Accept it. + ///////////// + if(!gt2Accept(clientConnection, &ClientConnectionCallbacks)) + gt2CloseConnection(connection); + } + else + { + if(result == GT2Rejected) + gt2Reject(clientConnection, message, len); + else + gt2Reject(clientConnection, (const GT2Byte *)("Proxy failed to connect to server."), -1); + + // Close the socket. + //////////////////// + RemoveServerSocket(gt2GetConnectionSocket(connection)); + } + +#if STATS + // Update stats. + //////////////// + connectResults[result]++; +#endif +} + +void ServerReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + GT2Connection clientConnection; + + // The client connection for this server connection. + //////////////////////////////////////////////////// + clientConnection = (GT2Connection)gt2GetConnectionData(connection); + + // Send it the data. + //////////////////// + gt2Send(clientConnection, message, len, reliable); + +#if STATS + // Update stats. + //////////////// + if(reliable) + { + serverReliableMessagesSent++; + serverReliableBytesSent += len; + } + else + { + serverUnreliableMessagesSent++; + serverUnreliableBytesSent += len; + } +#endif +} + +void ServerClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + GT2Connection clientConnection; + + // The client connection for this server connection. + //////////////////////////////////////////////////// + clientConnection = (GT2Connection)gt2GetConnectionData(connection); + if(clientConnection) + { + // We don't want them to try closing us.... + /////////////////////////////////////////// + gt2SetConnectionData(clientConnection, NULL); + + // Close the connection. + //////////////////////// + gt2CloseConnection(clientConnection); + } + + // Close the socket. + //////////////////// + RemoveServerSocket(gt2GetConnectionSocket(connection)); + +#if STATS + // Update stats. + //////////////// + if(reason == GT2LocalClose) + serverCloses++; +#endif +} + +GT2ConnectionCallbacks ServerConnectionCallbacks = +{ + ServerConnectedCallback, + ServerReceivedCallback, + ServerClosedCallback +}; + +/* LISTENER */ + +void SocketErrorCallback +( + GT2Socket socket +) +{ + printf("Socket error (incoming connections socket)\n"); + Quit = GT2True; + + GSI_UNUSED(socket); +} + +void ConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + GT2Socket serverSocket; + GT2Connection serverConnection; + GT2Result result; + + // Create a socket for this connection. + /////////////////////////////////////// + result = gt2CreateSocket(&serverSocket, NULL, 0, 0, NULL); + if(result != GT2Success) + { + gt2Reject(connection, (const GT2Byte *)("Proxy failed to create a new socket."), -1); + return; + } + + // Connect to the real server. + ////////////////////////////// + result = gt2Connect(serverSocket, &serverConnection, RemoteAddress, message, len, 0, &ServerConnectionCallbacks, GT2False); + if(result != GT2Success) + { + gt2Reject(connection, (const GT2Byte *)("Proxy failed to connect to server."), -1); + gt2CloseSocket(serverSocket); + return; + } + + // Add the socket to the array. + /////////////////////////////// + ArrayAppend(ServerSockets, &serverSocket); + + // The user data for each connection is the other. + ////////////////////////////////////////////////// + gt2SetConnectionData(serverConnection, connection); + gt2SetConnectionData(connection, serverConnection); + +#if STATS + // Update stats. + //////////////// + numConnectAttempts++; +#endif + + GSI_UNUSED(latency); + GSI_UNUSED(port); + GSI_UNUSED(ip); + GSI_UNUSED(socket); +} + +#ifdef WIN32 +BOOL WINAPI CtrlHandler +( + DWORD type +) +{ + // Quit. + //////// + Quit = GT2True; + + // We handled it. + ///////////////// + return TRUE; + + GSI_UNUSED(type); +} +#endif + +#if STATS +void DisplayStats(void) +{ + time_t runTime; + time_t days; + time_t hours; + time_t minutes; + time_t seconds; + time_t ctimeTime; + int numAccepted; + int numRejected; + int total; + + // Do the time stuff. + ///////////////////// + ctimeTime = startTime; + runTime = (time(NULL) - startTime); + seconds = (runTime % 60); + runTime /= 60; + minutes = (runTime % 60); + runTime /= 60; + hours = (runTime % 24); + runTime /= 24; + days = runTime; + + // Do some other stuff. + /////////////////////// + numAccepted = connectResults[GT2Success]; + numRejected = connectResults[GT2Rejected]; + + // Print stats. + /////////////// + printf("Proxying since %s", gsiSecondsToString(&ctimeTime)); + printf("(%d days, %d hours, %d minutes, %d seconds)\n", + days, + hours, + minutes, + seconds); + printf("%d connect attempts, %d (%d%%) accepted, %d (%d%%) rejected\n", + numConnectAttempts, + numAccepted, + (numConnectAttempts)?(numAccepted * 100) / numConnectAttempts:0, + numRejected, + (numConnectAttempts)?(numRejected * 100) / numConnectAttempts:0); + total = (clientReliableMessagesSent + clientUnreliableMessagesSent); + printf("client: %d messages, %d (%d%%) reliable, %d (%d%%) unreliable\n", + total, + clientReliableMessagesSent, + (total)?(clientReliableMessagesSent * 100) / total:0, + clientUnreliableMessagesSent, + (total)?(clientUnreliableMessagesSent * 100) / total:0); + total = (serverReliableMessagesSent + serverUnreliableMessagesSent); + printf("server: %d messages, %d (%d%%) reliable, %d (%d%%) unreliable\n", + total, + serverReliableMessagesSent, + (total)?(serverReliableMessagesSent * 100) / total:0, + serverUnreliableMessagesSent, + (total)?(serverUnreliableMessagesSent * 100) / total:0); + total = (clientReliableBytesSent + clientUnreliableBytesSent); + printf("client: %d bytes, %d (%d%%) reliable, %d (%d%%) unreliable\n", + total, + clientReliableBytesSent, + (total)?(clientReliableBytesSent * 100) / total:0, + clientUnreliableBytesSent, + (total)?(clientUnreliableBytesSent * 100) / total:0); + total = (serverReliableBytesSent + serverUnreliableBytesSent); + printf("server: %d bytes, %d (%d%%) reliable, %d (%d%%) unreliable\n", + total, + serverReliableBytesSent, + (total)?(serverReliableBytesSent * 100) / total:0, + serverUnreliableBytesSent, + (total)?(serverUnreliableBytesSent * 100) / total:0); + total = (clientCloses + serverCloses); + printf("%d closes, %d (%d%%) client, %d (%d%%) server\n", + total, + clientCloses, + (total)?(clientCloses * 100) / total:0, + serverCloses, + (total)?(serverCloses * 100) / total:0); +} +#endif + +int main +( + int argc, + char ** argv +) +{ + GT2Result result; + int num; + int i; +#if STATS + unsigned int lastStatsTime = 0; + unsigned int now; +#endif + + // Check args. + ////////////// + if((argc < 2) || (argc > 3)) + { + printf("%s [localhost][:port]\n", argv[0]); + return 1; + } + + // First is the remote address. + /////////////////////////////// + strcpy(RemoteAddress, argv[1]); + + // Second is the local address. + /////////////////////////////// + if(argc >= 3) + strcpy(LocalAddress, argv[2]); + + // Create the array of server sockets. + ////////////////////////////////////// + ServerSockets = ArrayNew(sizeof(GT2Socket), 10, FreeServerSocket); + if(!ServerSockets) + { + printf("Failed to create the array of server sockets\n"); + return 1; + } + + // Create the socket. + ///////////////////// + result = gt2CreateSocket(&Socket, LocalAddress, 0, 0, SocketErrorCallback); + if(result != GT2Success) + { + printf("Error creating the socket (%d)\n", result); + return 1; + } + + // Start listening. + /////////////////// + gt2Listen(Socket, ConnectAttemptCallback); + + // Show the port. + ///////////////// + printf("Listening on port %d\n", gt2GetLocalPort(Socket)); + + // For win32, setup a ctrl-c handler. + ///////////////////////////////////// + SetConsoleCtrlHandler(CtrlHandler, TRUE); + + // We're starting. + ////////////////// + startTime = time(NULL); + + // Loop until we quit. + ////////////////////// + while(!Quit) + { +#if STATS + // Get the current time. + //////////////////////// + now = current_time(); + + // Display stats? + ///////////////// + if((now - lastStatsTime) >= 30000) + { + DisplayStats(); + lastStatsTime = now; + } +#endif + + // Yield. + ///////// + msleep(1); + + // Think. + ///////// + gt2Think(Socket); + + // Let the server sockets think. + //////////////////////////////// + num = ArrayLength(ServerSockets); + for(i = (num - 1) ; i >= 0 ; i--) + gt2Think(*(GT2Socket *)ArrayNth(ServerSockets, i)); + } + +#if STATS + // Display some final stats. + //////////////////////////// + DisplayStats(); +#endif + + return 0; +} diff --git a/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy.dsp b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy.dsp new file mode 100644 index 00000000000..2ce83d01d62 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy.dsp @@ -0,0 +1,268 @@ +# Microsoft Developer Studio Project File - Name="gt2proxy" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gt2proxy - 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 "gt2proxy.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 "gt2proxy.mak" CFG="gt2proxy - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2proxy - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2proxy - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2proxy", RSOCAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2proxy - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gt2proxy - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gt2proxy - Win32 Release" +# Name "gt2proxy - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2proxy.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy_vs2005.vcproj b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy_vs2005.vcproj new file mode 100644 index 00000000000..a487a7aa484 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy_vs2005.vcproj @@ -0,0 +1,651 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2proxy/gt2proxy_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/gt2/gt2test/StdAfx.cpp b/xrGameSpy/gamespy/gt2/gt2test/StdAfx.cpp new file mode 100644 index 00000000000..18d56e2bf69 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// gt2test.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/gt2/gt2test/StdAfx.h b/xrGameSpy/gamespy/gt2/gt2test/StdAfx.h new file mode 100644 index 00000000000..7c8da714f4d --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/StdAfx.h @@ -0,0 +1,29 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__7F1931C4_E9E9_49E1_A6DC_8ACC78E87145__INCLUDED_) +#define AFX_STDAFX_H__7F1931C4_E9E9_49E1_A6DC_8ACC78E87145__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "../gt2.h" +#include "../../darray.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__7F1931C4_E9E9_49E1_A6DC_8ACC78E87145__INCLUDED_) diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2test.cpp b/xrGameSpy/gamespy/gt2/gt2test/gt2test.cpp new file mode 100644 index 00000000000..926f0ef6ea5 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2test.cpp @@ -0,0 +1,74 @@ +// gt2test.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "gt2test.h" +#include "gt2testDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CGt2testApp + +BEGIN_MESSAGE_MAP(CGt2testApp, CWinApp) + //{{AFX_MSG_MAP(CGt2testApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGt2testApp construction + +CGt2testApp::CGt2testApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CGt2testApp object + +CGt2testApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CGt2testApp initialization + +BOOL CGt2testApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CGt2testDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } + else if (nResponse == IDCANCEL) + { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2test.dsp b/xrGameSpy/gamespy/gt2/gt2test/gt2test.dsp new file mode 100644 index 00000000000..9e63ff1ae1a --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2test.dsp @@ -0,0 +1,336 @@ +# Microsoft Developer Studio Project File - Name="gt2test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=gt2test - 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 "gt2test.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 "gt2test.mak" CFG="gt2test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2test - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "gt2test - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2test", IBOCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2test - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "gt2test - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gt2test - Win32 Release" +# Name "gt2test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2test.cpp +# End Source File +# Begin Source File + +SOURCE=.\gt2test.rc +# End Source File +# Begin Source File + +SOURCE=.\gt2testDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\gt2test.h +# End Source File +# Begin Source File + +SOURCE=.\gt2testDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\gt2test.ico +# End Source File +# Begin Source File + +SOURCE=.\res\gt2test.rc2 +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2test.h b/xrGameSpy/gamespy/gt2/gt2test/gt2test.h new file mode 100644 index 00000000000..5da28ae5110 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2test.h @@ -0,0 +1,49 @@ +// gt2test.h : main header file for the GT2TEST application +// + +#if !defined(AFX_GT2TEST_H__BDC522B0_AA93_4D1B_8271_A3CFD716E950__INCLUDED_) +#define AFX_GT2TEST_H__BDC522B0_AA93_4D1B_8271_A3CFD716E950__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CGt2testApp: +// See gt2test.cpp for the implementation of this class +// + +class CGt2testApp : public CWinApp +{ +public: + CGt2testApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGt2testApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CGt2testApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GT2TEST_H__BDC522B0_AA93_4D1B_8271_A3CFD716E950__INCLUDED_) diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2test.rc b/xrGameSpy/gamespy/gt2/gt2test/gt2test.rc new file mode 100644 index 00000000000..88a765df29c --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2test.rc @@ -0,0 +1,283 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\gt2test.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\gt2test.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_GT2TEST_DIALOG DIALOGEX 0, 0, 347, 331 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "GameSpy Transport SDK 2 MFC Test" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Create",IDC_CREATE_SOCKET,15,20,35,14 + PUSHBUTTON "Close",IDC_CLOSE_SOCKET,15,35,35,14 + EDITTEXT IDC_LOCAL_ADDRESS,109,18,86,12,ES_AUTOHSCROLL + EDITTEXT IDC_IN_BUFFER_SIZE,109,29,86,12,ES_AUTOHSCROLL + EDITTEXT IDC_OUT_BUFFER_SIZE,109,40,86,12,ES_AUTOHSCROLL + PUSHBUTTON "Connect",IDC_CONNECT,15,60,35,14 + EDITTEXT IDC_REMOTE_ADDRESS,55,60,95,13,ES_AUTOHSCROLL + CONTROL "Blocking",IDC_BLOCKING,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,154,62,41,10 + PUSHBUTTON "Close All Connections",IDC_CLOSE_ALL_CONNECTIONS,155,89, + 77,14 + PUSHBUTTON "Close All Connections Hard", + IDC_CLOSE_ALL_CONNECTIONS_HARD,235,89,97,14 + PUSHBUTTON "Think",IDC_THINK,213,18,35,14 + CONTROL "Always Think",IDC_ALWAYS_THINK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,260,20,58,10 + CONTROL "Listen",IDC_LISTEN,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,213,37,35,14 + CONTROL "Accept All",IDC_ACCEPT_ALL,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,259,37,48,10 + CONTROL "Reject All",IDC_REJECT_ALL,"Button",BS_AUTORADIOBUTTON, + 259,50,46,10 + CONTROL "Prompt",IDC_PROMPT,"Button",BS_AUTORADIOBUTTON,259,62, + 38,10 + EDITTEXT IDC_REJECT_REASON,259,73,73,13,ES_AUTOHSCROLL | WS_GROUP + COMBOBOX IDC_CONNECTIONS,15,123,127,97,CBS_DROPDOWNLIST | + CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + CONTROL "Connecting",IDC_CONNECTING,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,149,125,52,10 + CONTROL "Connected",IDC_CONNECTED,"Button",BS_AUTORADIOBUTTON, + 204,125,51,10 + CONTROL "Closing",IDC_CLOSING,"Button",BS_AUTORADIOBUTTON,258, + 125,39,10 + CONTROL "Closed",IDC_CLOSED,"Button",BS_AUTORADIOBUTTON,300,125, + 37,10 + PUSHBUTTON "Send",IDC_SEND,15,151,35,14,WS_GROUP + EDITTEXT IDC_MESSAGE,55,151,95,13,ES_AUTOHSCROLL + CONTROL "Reliable",IDC_RELIABLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,155,153,41,10 + PUSHBUTTON "Ping",IDC_PING,201,151,35,14 + PUSHBUTTON "Close",IDC_CLOSE_CONNECTION,240,151,35,14 + PUSHBUTTON "Close Hard",IDC_CLOSE_CONNECTION_HARD,279,151,45,14 + EDITTEXT IDC_MESSAGES,15,167,180,81,ES_MULTILINE | ES_READONLY | + WS_VSCROLL | WS_HSCROLL + EDITTEXT IDC_SEND_DROP_VALUE,220,221,25,12,ES_AUTOHSCROLL + EDITTEXT IDC_SEND_DELAY_VALUE,220,235,25,12,ES_AUTOHSCROLL + EDITTEXT IDC_RECEIVE_DROP_VALUE,290,221,25,12,ES_AUTOHSCROLL + EDITTEXT IDC_RECEIVE_DELAY_VALUE,290,235,25,12,ES_AUTOHSCROLL + CONTROL "IPAddress1",IDC_ADDRESS_IP,"SysIPAddress32",WS_TABSTOP, + 15,269,100,12 + EDITTEXT IDC_ADDRESS_PORT,117,269,40,12,ES_AUTOHSCROLL + PUSHBUTTON "--->",IDC_ADDRESS_TO,164,269,20,12 + PUSHBUTTON "<---",IDC_ADDRESS_FROM,187,269,20,12 + EDITTEXT IDC_ADDRESS_STRING,213,269,119,12,ES_AUTOHSCROLL + PUSHBUTTON "Get IP Host Info",IDC_GET_IP_HOST_INFO,15,286,38,29, + BS_MULTILINE + EDITTEXT IDC_ADDRESS_HOSTNAME,95,283,194,12,ES_AUTOHSCROLL | + ES_READONLY + EDITTEXT IDC_ADDRESS_ALIASES,95,294,194,12,ES_AUTOHSCROLL | + ES_READONLY + EDITTEXT IDC_ADDRESS_IPS,95,305,194,12,ES_AUTOHSCROLL | + ES_READONLY + PUSHBUTTON "Get String Host Info",IDC_GET_STRING_HOST_INFO,294,286, + 38,29,BS_MULTILINE + GROUPBOX "Socket",IDC_STATIC,7,7,333,102 + GROUPBOX "Connection",IDC_STATIC,7,112,333,141 + GROUPBOX "Address",IDC_STATIC,7,256,333,68 + LTEXT "Hostname:",IDC_STATIC,58,286,35,8 + LTEXT "Aliases:",IDC_STATIC,58,296,25,8 + LTEXT "IPs:",IDC_STATIC,58,307,13,8 + LTEXT "Local Address:",IDC_STATIC,55,20,48,8 + LTEXT "In Buffer Size:",IDC_STATIC,55,31,45,8 + LTEXT "Out Buffer Size:",IDC_STATIC,55,42,50,8 + LTEXT "Reject Reason:",IDC_STATIC,206,75,50,8 + LTEXT "Send Filters:",IDC_STATIC,200,168,40,8 + LTEXT "Receive Filters:",IDC_STATIC,270,168,50,8 + LTEXT "drop",IDC_STATIC,200,224,15,8 + LTEXT "delay",IDC_STATIC,200,238,18,8 + LTEXT "%",IDC_STATIC,247,222,8,8 + LTEXT "ms",IDC_STATIC,247,238,10,8 + LTEXT "drop",IDC_STATIC,270,224,15,8 + LTEXT "delay",IDC_STATIC,270,238,18,8 + LTEXT "%",IDC_STATIC,317,222,8,8 + LTEXT "ms",IDC_STATIC,317,238,10,8 + CONTROL "ROT13",IDC_SEND_ROT13,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,182,39,10 + CONTROL "Drop",IDC_SEND_DROP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,193,31,10 + CONTROL "Delay",IDC_SEND_DELAY,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,206,34,10 + CONTROL "ROT13",IDC_RECEIVE_ROT13,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,270,182,39,10 + CONTROL "Drop",IDC_RECEIVE_DROP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,270,193,31,10 + CONTROL "Delay",IDC_RECEIVE_DELAY,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,270,206,34,10 + EDITTEXT IDC_CONNECT_MESSAGE,55,80,95,12,ES_AUTOHSCROLL + EDITTEXT IDC_TIMEOUT,55,91,95,12,ES_AUTOHSCROLL + LTEXT "Message:",IDC_STATIC,15,82,32,8 + LTEXT "Timeout:",IDC_STATIC,15,93,28,8 + LTEXT "Incoming:",IDC_STATIC,97,139,32,8 + CONTROL "Progress1",IDC_INCOMING_BUFFER_PROGRESS, + "msctls_progress32",PBS_SMOOTH | WS_BORDER,129,140,50,7 + LTEXT "Space Used in Buffers:",IDC_STATIC,15,139,74,8 + LTEXT "55555555",IDC_INCOMING_BUFFER_SIZE,179,139,33,8 + LTEXT "Outgoing:",IDC_STATIC,217,139,32,8 + CONTROL "Progress1",IDC_OUTGOING_BUFFER_PROGRESS, + "msctls_progress32",PBS_SMOOTH | WS_BORDER,249,140,50,7 + LTEXT "55555555",IDC_OUTGOING_BUFFER_SIZE,299,139,33,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "gt2test MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "gt2test\0" + VALUE "LegalCopyright", "Copyright (C) 2002\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "gt2test.EXE\0" + VALUE "ProductName", "gt2test Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_GT2TEST_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 340 + VERTGUIDE, 15 + VERTGUIDE, 332 + TOPMARGIN, 7 + BOTTOMMARGIN, 324 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\gt2test.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2testDlg.cpp b/xrGameSpy/gamespy/gt2/gt2test/gt2testDlg.cpp new file mode 100644 index 00000000000..3106f6b4114 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2testDlg.cpp @@ -0,0 +1,1430 @@ +// gt2testDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "gt2test.h" +#include "gt2testDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CGt2testDlg * dlg; + +///////////////////////////////////////////////////////////////////////////// +// CGt2testDlg dialog + +CGt2testDlg::CGt2testDlg(CWnd* pParent /*=NULL*/) + : CDialog(CGt2testDlg::IDD, pParent) +{ + m_delayedSends = NULL; + m_delayedReceives = NULL; + + //{{AFX_DATA_INIT(CGt2testDlg) + m_addressAliases = _T(""); + m_addressHostname = _T(""); + m_addressIPs = _T(""); + m_addressPort = _T(""); + m_addressString = _T(""); + m_outBufferSize = _T(""); + m_rejectReason = _T(""); + m_acceptMode = 0; + m_alwaysThink = TRUE; + m_blocking = FALSE; + m_localAddress = _T(""); + m_remoteAddress = _T(""); + m_inBufferSize = _T(""); + m_listen = FALSE; + m_connectionState = -1; + m_reliable = FALSE; + m_message = _T(""); + m_messages = _T(""); + m_receiveDelay = FALSE; + m_receiveDelayValue = _T("0"); + m_receiveDrop = FALSE; + m_receiveDropValue = _T("0"); + m_receiveROT13 = FALSE; + m_sendDelay = FALSE; + m_sendDelayValue = _T("0"); + m_sendDrop = FALSE; + m_sendDropValue = _T("0"); + m_sendROT13 = FALSE; + m_connectMessage = _T(""); + m_timeout = _T("5000"); + //}}AFX_DATA_INIT + + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CGt2testDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CGt2testDlg) + DDX_Control(pDX, IDC_OUTGOING_BUFFER_SIZE, m_outgoingBufferSize); + DDX_Control(pDX, IDC_OUTGOING_BUFFER_PROGRESS, m_outgoingBufferProgress); + DDX_Control(pDX, IDC_INCOMING_BUFFER_SIZE, m_incomingBufferSize); + DDX_Control(pDX, IDC_INCOMING_BUFFER_PROGRESS, m_incomingBufferProgress); + DDX_Control(pDX, IDC_CONNECTIONS, m_connections); + DDX_Control(pDX, IDC_ADDRESS_IP, m_addressIP); + DDX_Text(pDX, IDC_ADDRESS_ALIASES, m_addressAliases); + DDX_Text(pDX, IDC_ADDRESS_HOSTNAME, m_addressHostname); + DDX_Text(pDX, IDC_ADDRESS_IPS, m_addressIPs); + DDX_Text(pDX, IDC_ADDRESS_PORT, m_addressPort); + DDX_Text(pDX, IDC_ADDRESS_STRING, m_addressString); + DDX_Text(pDX, IDC_OUT_BUFFER_SIZE, m_outBufferSize); + DDX_Text(pDX, IDC_REJECT_REASON, m_rejectReason); + DDX_Radio(pDX, IDC_ACCEPT_ALL, m_acceptMode); + DDX_Check(pDX, IDC_ALWAYS_THINK, m_alwaysThink); + DDX_Check(pDX, IDC_BLOCKING, m_blocking); + DDX_Text(pDX, IDC_LOCAL_ADDRESS, m_localAddress); + DDX_Text(pDX, IDC_REMOTE_ADDRESS, m_remoteAddress); + DDX_Text(pDX, IDC_IN_BUFFER_SIZE, m_inBufferSize); + DDX_Check(pDX, IDC_LISTEN, m_listen); + DDX_Radio(pDX, IDC_CONNECTING, m_connectionState); + DDX_Check(pDX, IDC_RELIABLE, m_reliable); + DDX_Text(pDX, IDC_MESSAGE, m_message); + DDX_Text(pDX, IDC_MESSAGES, m_messages); + DDX_Check(pDX, IDC_RECEIVE_DELAY, m_receiveDelay); + DDX_Text(pDX, IDC_RECEIVE_DELAY_VALUE, m_receiveDelayValue); + DDX_Check(pDX, IDC_RECEIVE_DROP, m_receiveDrop); + DDX_Text(pDX, IDC_RECEIVE_DROP_VALUE, m_receiveDropValue); + DDX_Check(pDX, IDC_RECEIVE_ROT13, m_receiveROT13); + DDX_Check(pDX, IDC_SEND_DELAY, m_sendDelay); + DDX_Text(pDX, IDC_SEND_DELAY_VALUE, m_sendDelayValue); + DDX_Check(pDX, IDC_SEND_DROP, m_sendDrop); + DDX_Text(pDX, IDC_SEND_DROP_VALUE, m_sendDropValue); + DDX_Check(pDX, IDC_SEND_ROT13, m_sendROT13); + DDX_Text(pDX, IDC_CONNECT_MESSAGE, m_connectMessage); + DDX_Text(pDX, IDC_TIMEOUT, m_timeout); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CGt2testDlg, CDialog) + //{{AFX_MSG_MAP(CGt2testDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_ADDRESS_TO, OnAddressTo) + ON_BN_CLICKED(IDC_ADDRESS_FROM, OnAddressFrom) + ON_BN_CLICKED(IDC_GET_IP_HOST_INFO, OnGetIpHostInfo) + ON_BN_CLICKED(IDC_GET_STRING_HOST_INFO, OnGetStringHostInfo) + ON_BN_CLICKED(IDC_CLOSE_SOCKET, OnCloseSocket) + ON_BN_CLICKED(IDC_CREATE_SOCKET, OnCreateSocket) + ON_BN_CLICKED(IDC_CONNECT, OnConnect) + ON_BN_CLICKED(IDC_THINK, OnThink) + ON_BN_CLICKED(IDC_LISTEN, OnListen) + ON_BN_CLICKED(IDC_CLOSE_ALL_CONNECTIONS, OnCloseAllConnections) + ON_BN_CLICKED(IDC_CLOSE_ALL_CONNECTIONS_HARD, OnCloseAllConnectionsHard) + ON_WM_TIMER() + ON_BN_CLICKED(IDC_SEND, OnSend) + ON_BN_CLICKED(IDC_PING, OnPing) + ON_BN_CLICKED(IDC_CLOSE_CONNECTION, OnCloseConnection) + ON_BN_CLICKED(IDC_CLOSE_CONNECTION_HARD, OnCloseConnectionHard) + ON_CBN_SELCHANGE(IDC_CONNECTIONS, OnSelchangeConnections) + ON_BN_CLICKED(IDC_SEND_ROT13, OnSendRot13) + ON_BN_CLICKED(IDC_RECEIVE_ROT13, OnReceiveRot13) + ON_BN_CLICKED(IDC_SEND_DROP, OnSendDrop) + ON_BN_CLICKED(IDC_RECEIVE_DROP, OnReceiveDrop) + ON_BN_CLICKED(IDC_SEND_DELAY, OnSendDelay) + ON_BN_CLICKED(IDC_RECEIVE_DELAY, OnReceiveDelay) + ON_WM_DESTROY() + ON_EN_CHANGE(IDC_SEND_DROP_VALUE, OnChangeSendDropValue) + ON_EN_CHANGE(IDC_SEND_DELAY_VALUE, OnChangeSendDelayValue) + ON_EN_CHANGE(IDC_RECEIVE_DROP_VALUE, OnChangeReceiveDropValue) + ON_EN_CHANGE(IDC_RECEIVE_DELAY_VALUE, OnChangeReceiveDelayValue) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CGt2testDlg message handlers + +static void DelayedMessageFree(void * elem) +{ + DelayedMessage * message = (DelayedMessage *)elem; + + free(message->message); +} + +BOOL CGt2testDlg::OnInitDialog() +{ + // MFC stuff + CDialog::OnInitDialog(); + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIcon, FALSE); + + // so we can reference members from callbacks + dlg = this; + + // disable the socket controls + EnableSocketControls(FALSE); + + // we initialize sockets ourself because it might be needed for the address functions + // this function is declared in nonport.h + SocketStartUp(); + + // setup the think timer + SetTimer(100, 20, NULL); + + // not thinking yet + m_thinking = GT2False; + + // create the delay arrays + m_delayedSends = ArrayNew(sizeof(DelayedMessage), 10, DelayedMessageFree); + m_delayedReceives = ArrayNew(sizeof(DelayedMessage), 10, DelayedMessageFree); + + return TRUE; +} + +void CGt2testDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + // free our arrays of delayed messages + if(m_delayedSends) + { + ArrayFree(m_delayedSends); + m_delayedSends = NULL; + } + if(m_delayedReceives) + { + ArrayFree(m_delayedReceives); + m_delayedReceives = NULL; + } +} + +// MFC stuff +void CGt2testDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +// MFC stuff +HCURSOR CGt2testDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +/************ +** GENERAL ** +************/ + +// enable or disable a control based on it's control ID +#define ENABLE(control, enable) GetDlgItem(control)->EnableWindow(enable) + +// check if a delayed message should be passed on to it's filter function +static void DelayCheck(DArray delayedMessages, unsigned long now, BOOL send) +{ + DelayedMessage * message; + int num; + int i; + + num = ArrayLength(delayedMessages); + + // loop through the list backwards to allow for safe removals + for(i = (num - 1) ; i >= 0 ; i--) + { + message = (DelayedMessage *)ArrayNth(delayedMessages, i); + + // check if the time passed since the start time is greater than the delay time + if((now - message->startTime) > message->delayTime) + { + if(send) + gt2FilteredSend(message->connection, message->filterID, message->message, message->len, message->reliable); + else + gt2FilteredReceive(message->connection, message->filterID, message->message, message->len, message->reliable); + ArrayDeleteAt(delayedMessages, i); + } + } +} + +static void RemoveDelayedMessages(DArray delayedMessages, GT2Connection connection) +{ + DelayedMessage * message; + int num; + int i; + + num = ArrayLength(delayedMessages); + + // loop through the list backwards to allow for safe removals + for(i = (num - 1) ; i >= 0 ; i--) + { + message = (DelayedMessage *)ArrayNth(delayedMessages, i); + + // remove it if the connection matches + if(message->connection == connection) + ArrayDeleteAt(delayedMessages, i); + } +} + +void CGt2testDlg::OnTimer(UINT nIDEvent) +{ + // check for our timer + if(nIDEvent == 100) + { + // we have a socket, "always think" is checked, and we're not already thinking, think + // the check for already thinking is because this can get called from inside a dialog box brought up + // inside a callback - this would be bad (recursive thinking). + m_alwaysThink = (((CButton *)GetDlgItem(IDC_ALWAYS_THINK))->GetCheck() == BST_CHECKED); + if(m_socket && m_alwaysThink && !m_thinking) + { + m_thinking = GT2True; + gt2Think(m_socket); + m_thinking = GT2False; + } + + // find the active connection, and check what the connection's state should be + GT2Connection connection = GetActiveConnection(); + int newState; + if(connection) + newState = gt2GetConnectionState(connection); + else + newState = -1; + + // if this differs from the previous connection state, make the change + if(newState != m_connectionState) + { + // if there's a state, check it + if(newState != -1) + ((CButton *)GetDlgItem(IDC_CONNECTING + newState))->SetCheck(BST_CHECKED); + + // if there's a previous state, uncheck it + if(m_connectionState != -1) + ((CButton *)GetDlgItem(IDC_CONNECTING + m_connectionState))->SetCheck(BST_UNCHECKED); + + // save the new state + m_connectionState = newState; + } + + // update the buffer display + if(connection) + { + int freeSpace; + int size; + CString text; + + freeSpace = gt2GetIncomingBufferFreeSpace(connection); + size = gt2GetIncomingBufferSize(connection); + text.Format("%d", size); + m_incomingBufferSize.SetWindowText(text); + m_incomingBufferProgress.SetRange32(0, size); + m_incomingBufferProgress.SetPos(size - freeSpace); + + freeSpace = gt2GetOutgoingBufferFreeSpace(connection); + size = gt2GetOutgoingBufferSize(connection); + text.Format("%d", size); + m_outgoingBufferSize.SetWindowText(text); + m_outgoingBufferProgress.SetRange32(0, size); + m_outgoingBufferProgress.SetPos(size - freeSpace); + } + else + { + m_incomingBufferSize.SetWindowText(""); + m_incomingBufferProgress.SetPos(0); + m_outgoingBufferSize.SetWindowText(""); + m_outgoingBufferProgress.SetPos(0); + } + + // check for delayed messages + unsigned long now = current_time(); + DelayCheck(m_delayedSends, now, TRUE); + DelayCheck(m_delayedReceives, now, FALSE); + } + + // MFC stuff + CDialog::OnTimer(nIDEvent); +} + +BOOL CGt2testDlg::PreTranslateMessage(MSG* pMsg) +{ + // Redirect enter. + ////////////////// + if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == 0x0D)) + { + CWnd * pWnd = GetFocus(); + if(pWnd) + { + int id = pWnd->GetDlgCtrlID(); + + if(id == IDC_LOCAL_ADDRESS) + { + OnCreateSocket(); + return TRUE; + } + if(id == IDC_REMOTE_ADDRESS) + { + OnConnect(); + return TRUE; + } + if(id == IDC_CONNECT_MESSAGE) + { + OnConnect(); + return TRUE; + } + if(id == IDC_MESSAGE) + { + OnSend(); + return TRUE; + } + if(id == IDC_ADDRESS_IP) + { + OnAddressTo(); + return TRUE; + } + if(id == IDC_ADDRESS_PORT) + { + OnAddressTo(); + return TRUE; + } + if(id == IDC_ADDRESS_STRING) + { + OnAddressFrom(); + return TRUE; + } + } + } + + // MFC stuff + return CDialog::PreTranslateMessage(pMsg); +} + +static const char * ResultToString(GT2Result result) +{ + switch(result) + { + case GT2Success: + return "GT2Success"; + case GT2OutOfMemory: + return "GT2OutOfMemory"; + case GT2Rejected: + return "GT2Rejected"; + case GT2NetworkError: + return "GT2NetworkError"; + case GT2AddressError: + return "GT2AddressError"; + case GT2DuplicateAddress: + return "GT2DuplicateAddress"; + case GT2TimedOut: + return "GT2TimedOut"; + case GT2NegotiationError: + return "GT2NegotiationError"; + } + + return "Unknown result"; +} + +// used to enable or disable socket controls when a socket is created or destroyed +void CGt2testDlg::EnableSocketControls(BOOL enable) +{ + if(!enable) + m_socket = NULL; + + ENABLE(IDC_CREATE_SOCKET, !enable); + ENABLE(IDC_CLOSE_SOCKET, enable); + ENABLE(IDC_LOCAL_ADDRESS, !enable); + ENABLE(IDC_IN_BUFFER_SIZE, !enable); + ENABLE(IDC_OUT_BUFFER_SIZE, !enable); + ENABLE(IDC_CONNECT, enable); + ENABLE(IDC_REMOTE_ADDRESS, enable); + ENABLE(IDC_BLOCKING, enable); + ENABLE(IDC_CLOSE_ALL_CONNECTIONS, enable); + ENABLE(IDC_CLOSE_ALL_CONNECTIONS_HARD, enable); + ENABLE(IDC_THINK, enable); + ENABLE(IDC_ALWAYS_THINK, enable); + ENABLE(IDC_LISTEN, enable); + ENABLE(IDC_CONNECT_MESSAGE, enable); + ENABLE(IDC_TIMEOUT, enable); + + EnableListenControls(FALSE); + EnableConnectionControls(FALSE); +} + +// used to enable or disable the listen controls, depending on if the socket is listening or not +void CGt2testDlg::EnableListenControls(BOOL enable) +{ + ENABLE(IDC_ACCEPT_ALL, enable); + ENABLE(IDC_REJECT_ALL, enable); + ENABLE(IDC_PROMPT, enable); + ENABLE(IDC_REJECT_REASON, enable); +} + +// used to enable or disable the connection controls, depending on if there's a connection or not +void CGt2testDlg::EnableConnectionControls(BOOL enable) +{ + ENABLE(IDC_CONNECTIONS, enable); + ENABLE(IDC_CONNECTING, enable); + ENABLE(IDC_CONNECTED, enable); + ENABLE(IDC_CLOSING, enable); + ENABLE(IDC_CLOSED, enable); + ENABLE(IDC_SEND, enable); + ENABLE(IDC_MESSAGE, enable); + ENABLE(IDC_RELIABLE, enable); + ENABLE(IDC_PING, enable); + ENABLE(IDC_CLOSE_CONNECTION, enable); + ENABLE(IDC_CLOSE_CONNECTION_HARD, enable); + ENABLE(IDC_SEND_ROT13, enable); + ENABLE(IDC_RECEIVE_ROT13, enable); + ENABLE(IDC_SEND_DROP, enable); + ENABLE(IDC_RECEIVE_DROP, enable); + ENABLE(IDC_SEND_DROP_VALUE, enable); + ENABLE(IDC_RECEIVE_DROP_VALUE, enable); + ENABLE(IDC_SEND_DELAY, enable); + ENABLE(IDC_RECEIVE_DELAY, enable); + ENABLE(IDC_SEND_DELAY_VALUE, enable); + ENABLE(IDC_RECEIVE_DELAY_VALUE, enable); +} + +// get's the list index for a connection object +int CGt2testDlg::GetConnectionIndex(GT2Connection connection) +{ + int nIndex; + int num = m_connections.GetCount(); + + for(nIndex = 0 ; nIndex < num ; nIndex++) + { + if(((ConnectionInfo *)m_connections.GetItemDataPtr(nIndex))->connection == connection) + return nIndex; + } + + return -1; +} + +// get's the connection for a given list index +GT2Connection CGt2testDlg::GetConnection(int nIndex) +{ + if(nIndex == -1) + return NULL; + + ConnectionInfo * info = (ConnectionInfo *)m_connections.GetItemDataPtr(nIndex); + if(!info) + return NULL; + + return info->connection; +} + +// get's the connection info for a given list index +ConnectionInfo * CGt2testDlg::GetConnectionInfo(int nIndex) +{ + if(nIndex == -1) + return NULL; + + return (ConnectionInfo *)m_connections.GetItemDataPtr(nIndex); +} + +ConnectionInfo * CGt2testDlg::GetConnectionInfo(GT2Connection connection) +{ + return GetConnectionInfo(GetConnectionIndex(connection)); +} + +// adds a connection to the connection list +void CGt2testDlg::AddConnection(GT2Connection connection) +{ + // the string to show in the list is it's IP and port + CString address = gt2AddressToString(gt2GetRemoteIP(connection), gt2GetRemotePort(connection), NULL); + + // add the string to the list + int nIndex = m_connections.AddString(address); + if(nIndex == -1) + { + MessageBox("Error adding address to list!"); + return; + } + + // allocation the connection's info + ConnectionInfo * info = new ConnectionInfo; + info->connection = connection; + info->messages.Empty(); + info->sendROT13 = FALSE; + info->receiveROT13 = FALSE; + info->sendDrop = FALSE; + info->receiveDrop = FALSE; + info->sendDelay = FALSE; + info->receiveDelay = FALSE; + + // set the string's data pointer to point to it's info + m_connections.SetItemDataPtr(nIndex, info); + + // we have a connection, so enable the controls + EnableConnectionControls(); + + // set this connection as the active connection + SetActiveConnection(connection); +} + +// sets a connection as active (or, if connection is NULL and nIndex is -1, sets the list to no active connectoin) +void CGt2testDlg::SetActiveConnection(GT2Connection connection, int nIndex) +{ + // make sure this connection is selected + m_connections.SetCurSel(nIndex); + + // enable the connection controls depending on if this is a connection or not + EnableConnectionControls(connection != NULL); + + // make sure the controls reflect the proper connection (or lack thereof) + if(connection) + { + // update the connection values with the saved values for this connection + ConnectionInfo * info = GetConnectionInfo(connection); + m_messages = info->messages; + m_sendROT13 = info->sendROT13; + m_receiveROT13 = info->receiveROT13; + m_sendDrop = info->sendDrop; + m_receiveDrop = info->receiveDrop; + m_sendDropValue = info->sendDropValue; + m_receiveDropValue = info->receiveDropValue; + m_sendDelay = info->sendDelay; + m_receiveDelay = info->receiveDelay; + m_sendDelayValue = info->sendDelayValue; + m_receiveDelayValue = info->receiveDelayValue; + } + else + { + // blank out all the connection values + m_messages = ""; + m_sendROT13 = FALSE; + m_receiveROT13 = FALSE; + m_sendDrop = FALSE; + m_receiveDrop = FALSE; + m_sendDropValue = ""; + m_receiveDropValue = ""; + m_sendDelay = FALSE; + m_receiveDelay = FALSE; + m_sendDelayValue = ""; + m_receiveDelayValue = ""; + } +} + +// set the active connection using a connection object +void CGt2testDlg::SetActiveConnection(GT2Connection connection) +{ + int nIndex = GetConnectionIndex(connection); + ASSERT(nIndex != -1); // tried to activate a bad connection + if(nIndex == -1) + return; + + SetActiveConnection(connection, nIndex); +} + +// set the active connection using a list index +void CGt2testDlg::SetActiveConnection(int nIndex) +{ + if(nIndex != -1) + SetActiveConnection(GetConnection(nIndex), nIndex); + else + SetActiveConnection(NULL, nIndex); +} + +// get the selected connection, or NULL if there is none +GT2Connection CGt2testDlg::GetActiveConnection() +{ + if(!m_connections.IsWindowEnabled()) + return NULL; + + int nIndex = m_connections.GetCurSel(); + if(nIndex == -1) + return NULL; + + return GetConnection(nIndex); +} + +// remove a connection from the list +void CGt2testDlg::RemoveConnection(GT2Connection connection) +{ + // check for any delayed messages that are supposed to use this connection + RemoveDelayedMessages(m_delayedSends, connection); + RemoveDelayedMessages(m_delayedReceives, connection); + + // get this connection's index + int nIndex = GetConnectionIndex(connection); + if(nIndex == -1) + return; + + // check if this is the current selection + BOOL selected = (m_connections.GetCurSel() == nIndex); + + // free it's info + delete GetConnectionInfo(nIndex); + + // delete it + m_connections.DeleteString(nIndex); + + UpdateData(); + + // if it was selected, select something else + if(selected) + { + int count = m_connections.GetCount(); + if(count) + { + // if it was last, select the previous, otherwise select the next + if(nIndex == count) + SetActiveConnection(nIndex - 1); + else + SetActiveConnection(nIndex); + } + else + { + // it was the only one, set to no selection + SetActiveConnection(-1); + } + } + + UpdateData(FALSE); +} + +// adds a string to a connection's message list, and updates the displayed messages list if this is +// the active connection +void CGt2testDlg::AddMessageString(GT2Connection connection, const char *string) +{ + // add this to the connection's info + ConnectionInfo * info = GetConnectionInfo(connection); + if(info) + info->messages += string; + + // is this the active connection? + if(GetActiveConnection() == connection) + { + // update the messages list + UpdateData(); + m_messages += string; + UpdateData(FALSE); + + // scroll the messages to the bottom + CEdit * messagesCtrl = (CEdit *)GetDlgItem(IDC_MESSAGES); + messagesCtrl->SetSel(m_messages.GetLength(), m_messages.GetLength()); + } +} + +/*********** +** SOCKET ** +***********/ + +static void SocketErrorCallback(GT2Socket socket) +{ + dlg->EnableSocketControls(FALSE); + + dlg->MessageBox("Socket error"); + + GSI_UNUSED(socket); +} + +static void SendDumpCallback(GT2Socket socket, GT2Connection connection, unsigned int ip, unsigned short port, GT2Bool reset, const GT2Byte * message, int len) +{ + CString str; + str.Format("SEND %p %p %s %d\n", socket, connection, gt2AddressToString(ip, port, NULL), len); + OutputDebugString(str); + + GSI_UNUSED(message); + GSI_UNUSED(reset); +} + +static void ReceiveDumpCallback(GT2Socket socket, GT2Connection connection, unsigned int ip, unsigned short port, GT2Bool reset, const GT2Byte * message, int len) +{ + CString str; + if(reset) + str.Format("RECV %p %p %s RESET\n", socket, connection, gt2AddressToString(ip, port, NULL)); + else + str.Format("RECV %p %p %s %d\n", socket, connection, gt2AddressToString(ip, port, NULL), len); + OutputDebugString(str); + + GSI_UNUSED(message); +} + +void CGt2testDlg::OnCreateSocket() +{ + UpdateData(); + + // create the socket, using the info provided + GT2Result result = gt2CreateSocket(&m_socket, m_localAddress, atoi(m_outBufferSize), atoi(m_inBufferSize), SocketErrorCallback); + if(result != GT2Success) + { + CString str; + str.Format("gt2CreateSocket failed: %s", ResultToString(result)); + MessageBox(str); + return; + } + + // set the dump callbacks + gt2SetSendDump(m_socket, SendDumpCallback); + gt2SetReceiveDump(m_socket, ReceiveDumpCallback); + + // set the config settings to their actual values + m_localAddress = gt2AddressToString(gt2GetLocalIP(m_socket), gt2GetLocalPort(m_socket), NULL); + m_outBufferSize.Format("%d", atoi(m_outBufferSize)); + m_inBufferSize.Format("%d", atoi(m_inBufferSize)); + + // enable the socket controls + EnableSocketControls(); + + UpdateData(FALSE); +} + +void CGt2testDlg::OnCloseSocket() +{ + // close the socket + gt2CloseSocket(m_socket); + + // disable the socket controls + EnableSocketControls(FALSE); +} + +void CGt2testDlg::OnThink() +{ + // let the socket think, if it's not already thinking + if(m_thinking) + return; + m_thinking = GT2True; + gt2Think(m_socket); + m_thinking = GT2False; +} + +static void ConnectAttemptCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + GT2Bool accept; + + dlg->UpdateData(); + + // check for an empty message + if(!message) + message = (GT2Byte *)""; + + // get a string address for the connector + CString address = gt2AddressToString(ip, port, NULL); + + // check if we should accept, reject, or prompt + if(dlg->m_acceptMode == 0) + accept = GT2True; + else if(dlg->m_acceptMode == 1) + accept = GT2False; + else + { + // ask the user, and set accept/reject based on their answer + CString str; + str.Format("Accept a connection from %s (latency: %dms)?\n%s", (LPCSTR)address, latency, message); + accept = (dlg->MessageBox(str, "Accept/Reject", MB_YESNO) == IDYES); + } + + // accept the connection? + if(accept) + { + // setup the connection callbacks + GT2ConnectionCallbacks callbacks; + dlg->SetupConnectionCallbacks(callbacks); + + // do the accept + if(gt2Accept(connection, &callbacks)) + { + // add the connection to our list + dlg->AddConnection(connection); + } + else + { + // the other side has terminated the connection attempt before we accepted + // only warn about this if they specifically accepted it + if(dlg->m_acceptMode == 2) + dlg->MessageBox("Connection already closed"); + } + } + else + { + // reject them + gt2Reject(connection, (GT2Byte *)(LPCSTR)dlg->m_rejectReason, -1); + } + + dlg->UpdateData(FALSE); + + GSI_UNUSED(len); + GSI_UNUSED(socket); +} + +void CGt2testDlg::OnListen() +{ + UpdateData(); + + // check if we're supposed to start or stop listening + if(m_listen) + { + // start listening + gt2Listen(m_socket, ConnectAttemptCallback); + + // enable the listening controls + EnableListenControls(); + } + else + { + // stop listening + gt2Listen(m_socket, NULL); + + // disable the listening controls + EnableListenControls(FALSE); + } +} + +void CGt2testDlg::OnConnect() +{ + UpdateData(); + + // check the timout, and show what value we're actually using + int timeout = atoi(m_timeout); + if(timeout < 0) + timeout = 0; + m_timeout.Format("%d", timeout); + + // setup the connection callbacks + GT2ConnectionCallbacks callbacks; + dlg->SetupConnectionCallbacks(callbacks); + + // start the connection attempt, using the provided values + GT2Connection connection; + GT2Result result = gt2Connect(m_socket, &connection, m_remoteAddress, (GT2Byte *)(LPCSTR)m_connectMessage, -1, timeout, &callbacks, m_blocking); + if(result != GT2Success) + { + CString str; + str.Format("gt2Connect failed: %s", ResultToString(result)); + MessageBox(str); + return; + } + + // add the connection to our list + AddConnection(connection); + + UpdateData(FALSE); +} + +void CGt2testDlg::OnCloseAllConnections() +{ + // close all the connections + gt2CloseAllConnections(m_socket); +} + +void CGt2testDlg::OnCloseAllConnectionsHard() +{ + // close all the connections without waiting for a response + gt2CloseAllConnectionsHard(m_socket); +} + +/*************** +** CONNECTION ** +***************/ + +void ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + // check if the attempt failed + if(result != GT2Success) + { + // let the user know + CString str; + str.Format("Failed to connect to server: %s", ResultToString(result)); + if(message && len) + { + str += "\n"; + str += (char *)message; + } + dlg->MessageBox(str); + + // remove the connection from our list + dlg->RemoveConnection(connection); + } +} + +void ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + // empty messages are NULL + if(!message) + message = (GT2Byte *)""; + + // add the message to the messages list + CString str; + str.Format("IN(%c): %s\xD\xA", reliable?'r':'u', (char *)message); + dlg->AddMessageString(connection, str); + + GSI_UNUSED(len); +} + +void ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + // show a message if it's an error + if(reason == GT2CommunicationError) + dlg->MessageBox("Connection closed: Communication Error"); + else if(reason == GT2SocketError) + dlg->MessageBox("Connection closed: Socket Error"); + else if(reason == GT2NotEnoughMemory) + dlg->MessageBox("Connection closed: Not Enough Memory"); + + // the connection is closed, so remove it from the list + dlg->RemoveConnection(connection); +} + +void PingCallback +( + GT2Connection connection, + int latency +) +{ + // add the ping to the messages list + CString str; + str.Format("PING: %d\xD\xA", latency); + dlg->AddMessageString(connection, str); +} + +void CGt2testDlg::SetupConnectionCallbacks(GT2ConnectionCallbacks &callbacks) +{ + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.connected = ConnectedCallback; + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + callbacks.ping = PingCallback; +} + +void CGt2testDlg::OnSend() +{ + GT2Connection connection = GetActiveConnection(); + + UpdateData(); + + // print this out before the send because filtering could change it + CString str; + str.Format("OUT(%c): %s\xD\xA", m_reliable?'r':'u', (LPCSTR)m_message); + AddMessageString(connection, str); + + // do the send + gt2Send(connection, (const GT2Byte *)(LPCSTR)m_message, -1, m_reliable); +} + +void CGt2testDlg::OnPing() +{ + // send the ping + gt2Ping(GetActiveConnection()); +} + +void CGt2testDlg::OnCloseConnection() +{ + // start closing the connection + gt2CloseConnection(GetActiveConnection()); +} + +void CGt2testDlg::OnCloseConnectionHard() +{ + // close the ocnnection without waiting for a response + gt2CloseConnectionHard(GetActiveConnection()); +} + +void CGt2testDlg::OnSelchangeConnections() +{ + // make sure the newly selected connection is activated + UpdateData(); + SetActiveConnection(m_connections.GetCurSel()); + UpdateData(FALSE); +} + +// does a ROT13 transformation on a string +// ROT13 changes every letter to it's "opposite" in the alphabet by adding 13 to it. +// a->m, b->n, c->o, d->p, m->a, n->b, o->c, p->d, etc. +// performing ROT13 twice results in the original string, allowing the same filter to be applied to both +// sending and receiving to end up with the original string. cheap encryption. +static void ROT13(char * buffer, int len) +{ + int i; + int c; + int c2; + + for(i = 0 ; i < len ; i++) + { + c = buffer[i]; + + // only change letters + if(isalpha(c)) + { + // shift it by 13 + c2 = c + 13; + + // if it went past the end of the alphabet, mod it. + if((c2 - (isupper(c)?'A':'a')) >= 26) + c2 -= 26; + + // put it back in the string + buffer[i] = (char)c2; + } + } +} + +static void SendFilterCallbackROT13(GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable) +{ + char * msg; + + // we can override the const because we know we're the only filter, + // it's our data we're sending, and we're not changing the length + msg = (char *)message; + + // ROT13 the string + ROT13(msg, len); + + // pass it back to GT2 + gt2FilteredSend(connection, filterID, (GT2Byte *)msg, len, reliable); +} + +static void ReceiveFilterCallbackROT13(GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable) +{ + // ROT13 the string + ROT13((char *)message, len); + + // pass it back to GT2 + gt2FilteredReceive(connection, filterID, message, len, reliable); +} + +// returns true if a message should be dropped, based on the drop value +static BOOL CheckDrop(int dropValue) +{ + return ((rand() % 100) < dropValue); +} + +static void SendFilterCallbackDrop(GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable) +{ + // if it's unreliable, check if it should be dropped + if(!reliable && CheckDrop(atoi(dlg->m_sendDropValue))) + return; + + // pass it back to GT2 + gt2FilteredSend(connection, filterID, message, len, reliable); +} + +static void ReceiveFilterCallbackDrop(GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable) +{ + // if it's unreliable, check if it should be dropped + if(!reliable && CheckDrop(atoi(dlg->m_receiveDropValue))) + return; + + // pass it back to GT2 + gt2FilteredReceive(connection, filterID, message, len, reliable); +} + +static void AddDelayedMessage(DArray array, int delayValue, GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable) +{ + // don't allow negative delays! + if(delayValue < 0) + delayValue = 0; + + // save off everything we need to remember about the message + DelayedMessage msg; + memset(&msg, 0, sizeof(msg)); + msg.connection = connection; + msg.filterID = filterID; + msg.message = (GT2Byte *)malloc(len); + ASSERT(msg.message); + memcpy(msg.message, message, len); + msg.len = len; + msg.reliable = reliable; + msg.startTime = current_time(); + msg.delayTime = delayValue; + + // add it to the delay list + ArrayInsertAt(array, &msg, 0); +} + +static void SendFilterCallbackDelay(GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable) +{ + // add it to the delayed sends list + AddDelayedMessage(dlg->m_delayedSends, atoi(dlg->m_sendDelayValue), connection, filterID, message, len, reliable); +} + +static void ReceiveFilterCallbackDelay(GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable) +{ + // add it to the delayed receives list + AddDelayedMessage(dlg->m_delayedReceives, atoi(dlg->m_receiveDelayValue), connection, filterID, message, len, reliable); +} + +void CGt2testDlg::OnSendRot13() +{ + UpdateData(); + + GT2Connection connection = GetActiveConnection(); + + // add or remove the filter based on the check box + if(m_sendROT13) + gt2AddSendFilter(connection, SendFilterCallbackROT13); + else + gt2RemoveSendFilter(connection, SendFilterCallbackROT13); + + // save the setting with the connection's info + GetConnectionInfo(connection)->sendROT13 = m_sendROT13; +} + +void CGt2testDlg::OnReceiveRot13() +{ + UpdateData(); + + GT2Connection connection = GetActiveConnection(); + + // add or remove the filter based on the check box + if(m_receiveROT13) + gt2AddReceiveFilter(connection, ReceiveFilterCallbackROT13); + else + gt2RemoveReceiveFilter(connection, ReceiveFilterCallbackROT13); + + // save the setting with the connection's info + GetConnectionInfo(connection)->receiveROT13 = m_receiveROT13; +} + +void CGt2testDlg::OnSendDrop() +{ + UpdateData(); + + GT2Connection connection = GetActiveConnection(); + + // add or remove the filter based on the check box + if(m_sendDrop) + gt2AddSendFilter(connection, SendFilterCallbackDrop); + else + gt2RemoveSendFilter(connection, SendFilterCallbackDrop); + + // save the setting with the connection's info + GetConnectionInfo(connection)->sendDrop = m_sendDrop; +} + +void CGt2testDlg::OnReceiveDrop() +{ + UpdateData(); + + GT2Connection connection = GetActiveConnection(); + + // add or remove the filter based on the check box + if(m_receiveDrop) + gt2AddReceiveFilter(connection, ReceiveFilterCallbackDrop); + else + gt2RemoveReceiveFilter(connection, ReceiveFilterCallbackDrop); + + // save the setting with the connection's info + GetConnectionInfo(connection)->receiveDrop = m_receiveDrop; +} + +void CGt2testDlg::OnSendDelay() +{ + UpdateData(); + + GT2Connection connection = GetActiveConnection(); + + // add or remove the filter based on the check box + if(m_sendDelay) + gt2AddSendFilter(connection, SendFilterCallbackDelay); + else + gt2RemoveSendFilter(connection, SendFilterCallbackDelay); + + // save the setting with the connection's info + GetConnectionInfo(connection)->sendDelay = m_sendDelay; +} + +void CGt2testDlg::OnReceiveDelay() +{ + UpdateData(); + + GT2Connection connection = GetActiveConnection(); + + // add or remove the filter based on the check box + if(m_receiveDelay) + gt2AddReceiveFilter(connection, ReceiveFilterCallbackDelay); + else + gt2RemoveReceiveFilter(connection, ReceiveFilterCallbackDelay); + + // save the setting with the connection's info + GetConnectionInfo(connection)->receiveDelay = m_receiveDelay; +} + +void CGt2testDlg::OnChangeSendDropValue() +{ + UpdateData(); + + // save the setting with the connection's info + GetConnectionInfo(GetActiveConnection())->sendDropValue = m_sendDropValue; +} + +void CGt2testDlg::OnChangeReceiveDropValue() +{ + UpdateData(); + + // save the setting with the connection's info + GetConnectionInfo(GetActiveConnection())->receiveDropValue = m_receiveDropValue; +} + +void CGt2testDlg::OnChangeSendDelayValue() +{ + UpdateData(); + + // save the setting with the connection's info + GetConnectionInfo(GetActiveConnection())->sendDelayValue = m_sendDelayValue; +} + +void CGt2testDlg::OnChangeReceiveDelayValue() +{ + UpdateData(); + + // save the setting with the connection's info + GetConnectionInfo(GetActiveConnection())->receiveDelayValue = m_receiveDelayValue; +} + +/************ +** ADDRESS ** +************/ + +void CGt2testDlg::OnAddressTo() +{ + UpdateData(); + + // get the IP and port + DWORD IP; + unsigned int port; + if(m_addressIP.GetAddress(IP) != 4) + { + MessageBox("No IP address"); + return; + } + IP = gt2HostToNetworkInt(IP); + port = atoi(m_addressPort); + + // convert the ip and port to a string + m_addressString = gt2AddressToString(IP, (unsigned short)port, NULL); + + UpdateData(FALSE); +} + +void CGt2testDlg::OnAddressFrom() +{ + UpdateData(); + + // convert the string to an ip and port + unsigned int IP; + unsigned short port; + if(!gt2StringToAddress(m_addressString, &IP, &port)) + { + MessageBox("Unable to convert the string to an address"); + return; + } + + // set the ip and port + m_addressIP.SetAddress((DWORD)gt2NetworkToHostInt(IP)); + m_addressPort.Format("%d", port); + + UpdateData(FALSE); +} + +// updates dialog based on returned host info +void CGt2testDlg::HandleHostInfo(const char * hostname, char ** aliases, unsigned int ** ips) +{ + int count; + + // set the hostname + m_addressHostname = hostname; + + // fill in the aliases + m_addressAliases.Empty(); + for(count = 0 ; aliases[count] ; count++) + { + m_addressAliases += aliases[count]; + m_addressAliases += " "; + } + + // fill in the ips + m_addressIPs.Empty(); + for(count = 0 ; ips[count] ; count++) + { + m_addressIPs += gt2AddressToString(*(ips[count]), 0, NULL); + m_addressIPs += " "; + } +} + +void CGt2testDlg::OnGetIpHostInfo() +{ + UpdateData(); + + // get the ip + DWORD IP; + if(m_addressIP.GetAddress(IP) != 4) + { + MessageBox("No IP address"); + return; + } + IP = gt2HostToNetworkInt(IP); + + // get the info for the ip + const char * hostname; + char ** aliases; + unsigned int ** ips; + hostname = gt2IPToHostInfo(IP, &aliases, &ips); + if(!hostname) + { + MessageBox("Unable to convert the IP to host info"); + return; + } + + // handle the info + HandleHostInfo(hostname, aliases, ips); + + UpdateData(FALSE); +} + +void CGt2testDlg::OnGetStringHostInfo() +{ + UpdateData(); + + // get the info for the string + const char * hostname; + char ** aliases; + unsigned int ** ips; + hostname = gt2StringToHostInfo(m_addressString, &aliases, &ips); + if(!hostname) + { + CString str = "Unable to convert the string to host info"; + if(strchr(m_addressString, ':')) + str += "\n(Remove the port number)"; + MessageBox(str); + return; + } + + // handle the info + HandleHostInfo(hostname, aliases, ips); + + UpdateData(FALSE); +} diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2testDlg.h b/xrGameSpy/gamespy/gt2/gt2test/gt2testDlg.h new file mode 100644 index 00000000000..628a3f7ca6f --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2testDlg.h @@ -0,0 +1,162 @@ +// gt2testDlg.h : header file +// + +#if !defined(AFX_GT2TESTDLG_H__0E64F324_FFA4_4A94_A87D_75652134DC2D__INCLUDED_) +#define AFX_GT2TESTDLG_H__0E64F324_FFA4_4A94_A87D_75652134DC2D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CGt2testDlg dialog + +struct ConnectionInfo +{ + GT2Connection connection; + CString messages; + BOOL sendROT13; + BOOL receiveROT13; + BOOL sendDrop; + BOOL receiveDrop; + CString sendDropValue; + CString receiveDropValue; + BOOL sendDelay; + BOOL receiveDelay; + CString sendDelayValue; + CString receiveDelayValue; +}; + +struct DelayedMessage +{ + GT2Connection connection; + int filterID; + GT2Byte * message; + int len; + GT2Bool reliable; + unsigned long startTime; + unsigned long delayTime; +}; + +class CGt2testDlg : public CDialog +{ +// Construction +public: + void AddMessageString(GT2Connection connection, const char * string); + void RemoveConnection(GT2Connection connection); + GT2Connection GetActiveConnection(); + int GetConnectionIndex(GT2Connection connection); + GT2Connection GetConnection(int nIndex); + ConnectionInfo * GetConnectionInfo(int nIndex); + ConnectionInfo * GetConnectionInfo(GT2Connection connection); + void SetActiveConnection(GT2Connection connection, int nIndex); + void SetActiveConnection(GT2Connection connection); + void SetActiveConnection(int nIndex); + void SetupConnectionCallbacks(GT2ConnectionCallbacks & callbacks); + void AddConnection(GT2Connection connection); + void EnableSocketControls(BOOL enable = TRUE); + void EnableListenControls(BOOL enable = TRUE); + void EnableConnectionControls(BOOL enable = TRUE); + CGt2testDlg(CWnd* pParent = NULL); // standard constructor + + DArray m_delayedSends; + DArray m_delayedReceives; + +// Dialog Data + //{{AFX_DATA(CGt2testDlg) + enum { IDD = IDD_GT2TEST_DIALOG }; + CStatic m_outgoingBufferSize; + CProgressCtrl m_outgoingBufferProgress; + CStatic m_incomingBufferSize; + CProgressCtrl m_incomingBufferProgress; + CComboBox m_connections; + CIPAddressCtrl m_addressIP; + CString m_addressAliases; + CString m_addressHostname; + CString m_addressIPs; + CString m_addressPort; + CString m_addressString; + CString m_outBufferSize; + CString m_rejectReason; + int m_acceptMode; + BOOL m_alwaysThink; + BOOL m_blocking; + CString m_localAddress; + CString m_remoteAddress; + CString m_inBufferSize; + BOOL m_listen; + int m_connectionState; + BOOL m_reliable; + CString m_message; + CString m_messages; + BOOL m_receiveDelay; + CString m_receiveDelayValue; + BOOL m_receiveDrop; + CString m_receiveDropValue; + BOOL m_receiveROT13; + BOOL m_sendDelay; + CString m_sendDelayValue; + BOOL m_sendDrop; + CString m_sendDropValue; + BOOL m_sendROT13; + CString m_connectMessage; + CString m_timeout; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CGt2testDlg) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + void HandleHostInfo(const char * hostname, char ** aliases, unsigned int ** ips); + HICON m_hIcon; + + GT2Socket m_socket; + BOOL m_thinking; + + // Generated message map functions + //{{AFX_MSG(CGt2testDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnAddressTo(); + afx_msg void OnAddressFrom(); + afx_msg void OnGetIpHostInfo(); + afx_msg void OnGetStringHostInfo(); + afx_msg void OnCloseSocket(); + afx_msg void OnCreateSocket(); + afx_msg void OnConnect(); + afx_msg void OnThink(); + afx_msg void OnListen(); + afx_msg void OnCloseAllConnections(); + afx_msg void OnCloseAllConnectionsHard(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnSend(); + afx_msg void OnPing(); + afx_msg void OnCloseConnection(); + afx_msg void OnCloseConnectionHard(); + afx_msg void OnSelchangeConnections(); + afx_msg void OnSendRot13(); + afx_msg void OnReceiveRot13(); + afx_msg void OnSendDrop(); + afx_msg void OnReceiveDrop(); + afx_msg void OnSendDelay(); + afx_msg void OnReceiveDelay(); + afx_msg void OnDestroy(); + afx_msg void OnChangeSendDropValue(); + afx_msg void OnChangeSendDelayValue(); + afx_msg void OnChangeReceiveDropValue(); + afx_msg void OnChangeReceiveDelayValue(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_GT2TESTDLG_H__0E64F324_FFA4_4A94_A87D_75652134DC2D__INCLUDED_) diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2test_vs2005.vcproj b/xrGameSpy/gamespy/gt2/gt2test/gt2test_vs2005.vcproj new file mode 100644 index 00000000000..6e308e85884 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2test_vs2005.vcproj @@ -0,0 +1,767 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2test/gt2test_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/gt2/gt2test/gt2test_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/gt2test_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/gt2/gt2test/res/gt2test.ico b/xrGameSpy/gamespy/gt2/gt2test/res/gt2test.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2test/res/gt2test.ico differ diff --git a/xrGameSpy/gamespy/gt2/gt2test/res/gt2test.rc2 b/xrGameSpy/gamespy/gt2/gt2test/res/gt2test.rc2 new file mode 100644 index 00000000000..e79bcfd7233 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/res/gt2test.rc2 @@ -0,0 +1,13 @@ +// +// GT2TEST.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/gt2/gt2test/resource.h b/xrGameSpy/gamespy/gt2/gt2test/resource.h new file mode 100644 index 00000000000..69de22af997 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2test/resource.h @@ -0,0 +1,73 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gt2test.rc +// +#define IDD_GT2TEST_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_ADDRESS_IP 1000 +#define IDC_ADDRESS_PORT 1001 +#define IDC_ADDRESS_TO 1002 +#define IDC_ADDRESS_FROM 1003 +#define IDC_ADDRESS_STRING 1004 +#define IDC_GET_IP_HOST_INFO 1005 +#define IDC_GET_STRING_HOST_INFO 1006 +#define IDC_ADDRESS_HOSTNAME 1007 +#define IDC_CREATE_SOCKET 1008 +#define IDC_LOCAL_ADDRESS 1009 +#define IDC_ADDRESS_ALIASES 1010 +#define IDC_ADDRESS_IPS 1011 +#define IDC_IN_BUFFER_SIZE 1012 +#define IDC_OUT_BUFFER_SIZE 1013 +#define IDC_CLOSE_SOCKET 1014 +#define IDC_THINK 1015 +#define IDC_ALWAYS_THINK 1016 +#define IDC_CONNECT 1017 +#define IDC_REMOTE_ADDRESS 1018 +#define IDC_BLOCKING 1019 +#define IDC_CLOSE_ALL_CONNECTIONS 1020 +#define IDC_CLOSE_ALL_CONNECTIONS_HARD 1021 +#define IDC_LISTEN 1022 +#define IDC_ACCEPT_ALL 1023 +#define IDC_REJECT_ALL 1024 +#define IDC_PROMPT 1025 +#define IDC_REJECT_REASON 1026 +#define IDC_CONNECTIONS 1027 +#define IDC_CONNECTING 1028 +#define IDC_CONNECTED 1029 +#define IDC_CLOSING 1030 +#define IDC_CLOSED 1031 +#define IDC_MESSAGES 1032 +#define IDC_RELIABLE 1033 +#define IDC_SEND 1034 +#define IDC_MESSAGE 1035 +#define IDC_PING 1036 +#define IDC_CLOSE_CONNECTION_HARD 1037 +#define IDC_CONNECT_MESSAGE 1038 +#define IDC_SEND_DROP_VALUE 1039 +#define IDC_CLOSE_CONNECTION 1040 +#define IDC_SEND_ROT13 1041 +#define IDC_SEND_DELAY_VALUE 1042 +#define IDC_RECEIVE_DROP_VALUE 1043 +#define IDC_RECEIVE_DELAY_VALUE 1044 +#define IDC_SEND_DROP 1045 +#define IDC_SEND_DELAY 1046 +#define IDC_RECEIVE_ROT13 1047 +#define IDC_RECEIVE_DROP 1048 +#define IDC_RECEIVE_DELAY 1049 +#define IDC_TIMEOUT 1050 +#define IDC_LIST1 1051 +#define IDC_INCOMING_BUFFER_PROGRESS 1054 +#define IDC_INCOMING_BUFFER_SIZE 1055 +#define IDC_OUTGOING_BUFFER_PROGRESS 1056 +#define IDC_OUTGOING_BUFFER_SIZE 1057 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1058 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2linux/Makefile b/xrGameSpy/gamespy/gt2/gt2testc/gt2linux/Makefile new file mode 100644 index 00000000000..9efd38b2d80 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2linux/Makefile @@ -0,0 +1,55 @@ +# GameSpy Transport 2 SDK Makefile +# Copyright 2004 GameSpy Industries + +TARGET=gt2testc + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../gt2Auth.o\ + ../../gt2Buffer.o\ + ../../gt2Callback.o\ + ../../gt2Connection.o\ + ../../gt2Filter.o\ + ../../gt2Main.o\ + ../../gt2Message.o\ + ../../gt2Socket.o\ + ../../gt2Encode.o\ + ../../gt2Utility.o\ + ../$(TARGET).o + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(TARGET): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2macosx/Makefile b/xrGameSpy/gamespy/gt2/gt2testc/gt2macosx/Makefile new file mode 100644 index 00000000000..ae863a65505 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2macosx/Makefile @@ -0,0 +1,33 @@ +# GameSpy Transport 2 SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=gt2testc + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../gt2Auth.o\ + ../../gt2Buffer.o\ + ../../gt2Callback.o\ + ../../gt2Connection.o\ + ../../gt2Filter.o\ + ../../gt2Main.o\ + ../../gt2Message.o\ + ../../gt2Socket.o\ + ../../gt2Encode.o\ + ../../gt2Utility.o\ + ../gt2testc.o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/Nitro.lcf b/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/gt2nitrocw.mcp b/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/gt2nitrocw.mcp new file mode 100644 index 00000000000..bdf4d77eb42 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2testc/gt2nitrocw/gt2nitrocw.mcp differ diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2/Makefile b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2/Makefile new file mode 100644 index 00000000000..01cef12f38b --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2/Makefile @@ -0,0 +1,34 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = gt2testc + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../stringutil.o \ + ../../gt2Auth.o\ + ../../gt2Buffer.o\ + ../../gt2Callback.o\ + ../../gt2Connection.o\ + ../../gt2Encode.o\ + ../../gt2Filter.o\ + ../../gt2Main.o\ + ../../gt2Message.o\ + ../../gt2Socket.o\ + ../../gt2Utility.o\ + crt0.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2cw/gt2ps2cw.mcp b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2cw/gt2ps2cw.mcp new file mode 100644 index 00000000000..05a238ea443 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2cw/gt2ps2cw.mcp differ diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.dsp b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.dsp new file mode 100644 index 00000000000..198bb33065c --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.dsp @@ -0,0 +1,400 @@ +# Microsoft Developer Studio Project File - Name="gt2ps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gt2ps2prodg - Win32 Debug_Insock +!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 "gt2ps2prodg.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 "gt2ps2prodg.mak" CFG="gt2ps2prodg - Win32 Debug_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2ps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2ps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2ps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2ps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2ps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2ps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2testc/gt2ps2prodg", XREDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2ps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gt2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gt2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gt2ps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gt2ps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "gt2ps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "INSOCK" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\gt2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\gt2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gt2ps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\gt2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\gt2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gt2ps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gt2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\gt2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gt2ps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gt2ps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "gt2ps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\gt2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\gt2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "gt2ps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\gt2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\gt2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "gt2ps2prodg - Win32 Debug_EENet" +# Name "gt2ps2prodg - Win32 Debug_Insock" +# Name "gt2ps2prodg - Win32 Debug_SNSystems" +# Name "gt2ps2prodg - Win32 Release_EENet" +# Name "gt2ps2prodg - Win32 Release_Insock" +# Name "gt2ps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\gt2testc.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2Utility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.dsw b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.dsw new file mode 100644 index 00000000000..86bed9ad8dc --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gt2ps2prodg"=.\gt2ps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/gt2/gt2testc/gt2ps2prodg", XREDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/gamespy/goa/gt2/gt2testc/gt2ps2prodg", XREDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.sln b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.sln new file mode 100644 index 00000000000..3cac2d268fe --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2ps2prodg", "gt2ps2prodg.vcproj", "{CC62E025-D4AD-43F7-BE17-F7021434FE2C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 1 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = gt2ps2prodg.vcproj + SccProjectName0 = . + SccAuxPath0 = http://tfsapp1:8080 + SccLocalPath0 = . + SccProvider0 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {CC62E025-D4AD-43F7-BE17-F7021434FE2C}.PS2 SN Systems Release|Win32.Build.0 = PS2 EENET Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.vcproj b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.vcproj new file mode 100644 index 00000000000..1cfdedd2905 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps2prodg/gt2ps2prodg.vcproj @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3/Makefile b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3/Makefile new file mode 100644 index 00000000000..5fac27a9a91 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3/Makefile @@ -0,0 +1,39 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = gt2testc + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsAvailable.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../gt2Auth.o\ + ../../gt2Buffer.o\ + ../../gt2Callback.o\ + ../../gt2Connection.o\ + ../../gt2Encode.o\ + ../../gt2Filter.o\ + ../../gt2Main.o\ + ../../gt2Message.o\ + ../../gt2Socket.o\ + ../../gt2Utility.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3prodg/gt2ps3prodg.sln b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3prodg/gt2ps3prodg.sln new file mode 100644 index 00000000000..4869c9d367f --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3prodg/gt2ps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2ps3prodg", "gt2ps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gt2ps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3prodg/gt2ps3prodg.vcproj b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3prodg/gt2ps3prodg.vcproj new file mode 100644 index 00000000000..7df1c42a776 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2ps3prodg/gt2ps3prodg.vcproj @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2pspprodg/gt2pspprodg.sln b/xrGameSpy/gamespy/gt2/gt2testc/gt2pspprodg/gt2pspprodg.sln new file mode 100644 index 00000000000..5cfc8a66752 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2pspprodg/gt2pspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2pspprodg", "gt2pspprodg.vcproj", "{1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = gt2pspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {1B0F9B5E-A560-4194-9C31-2A70CD3BABB1}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2pspprodg/gt2pspprodg.vcproj b/xrGameSpy/gamespy/gt2/gt2testc/gt2pspprodg/gt2pspprodg.vcproj new file mode 100644 index 00000000000..b6ea2988bb7 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2pspprodg/gt2pspprodg.vcproj @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2revolutioncw/gt2revolutioncw.mcp b/xrGameSpy/gamespy/gt2/gt2testc/gt2revolutioncw/gt2revolutioncw.mcp new file mode 100644 index 00000000000..e82890dfd63 Binary files /dev/null and b/xrGameSpy/gamespy/gt2/gt2testc/gt2revolutioncw/gt2revolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2testc.c b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc.c new file mode 100644 index 00000000000..0efe8b08efc --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc.c @@ -0,0 +1,513 @@ +#include +#include +#include +#include "../gt2.h" +#include "../gt2Encode.h" + +#define TEST_ENCODE_DECODE + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define FILL_IN "fill me in" + +typedef struct Message +{ + GT2Bool valid; + char * data; + int len; + GT2Bool reliable; +} Message; + +GT2ConnectionCallbacks connectionCallbacks; +GT2Bool server; +GT2Bool quit; +GT2Bool hardcore; +int messageCount; +unsigned long sendTime; +GT2Connection Connection; + +Message initialMessage = { GT2True, "123456789012345", -1 }; + +Message messageList[] = +{ + { GT2True, NULL, 0, GT2True }, // empty + { GT2True, "1", 1, GT2True }, // 1 byte XXX + { GT2True, "1234567", 7, GT2True }, // 7 bytes XXX + { GT2True, "12345678901234567890123456789012345678901234567890", 50, GT2True }, // 50 bytes + { GT2True, FILL_IN, 128, GT2True }, + { GT2True, FILL_IN, 256, GT2True }, + { GT2True, FILL_IN, 512, GT2True }, + { GT2True, FILL_IN, 768, GT2True }, + { GT2True, FILL_IN, 1024, GT2True }, + { GT2True, FILL_IN, 1400, GT2True }, +#if !defined(_NITRO) + { GT2True, FILL_IN, 2047, GT2True }, + { GT2True, FILL_IN, (3 * 1024) - 1, GT2True }, +#if !defined(_REVOLUTION) + { GT2True, FILL_IN, (5 * 1024) - 1, GT2True }, + { GT2True, FILL_IN, (7 * 1024) - 1, GT2True }, +#if !defined(_PS2) && !defined(_PSP) + { GT2True, FILL_IN, (8 * 1024) + 1017, GT2True }, +#if !defined(_MACOSX) && !defined(_PS3) // Maximum send size for PS3 is 9216 + { GT2True, FILL_IN, (9 * 1024) - 1, GT2True }, + { GT2True, FILL_IN, (32 * 1024) - 1, GT2True }, +#endif +#endif +#endif +#endif +#if !defined(_NITRO) && !defined(_REVOLUTION) + { GT2True, NULL, 0, GT2False }, // empty +#endif + { GT2True, "1", 1, GT2False }, // 1 byte XXX + { GT2True, "1234567", 7, GT2False }, // 7 bytes XXX + { GT2True, "12345678901234567890123456789012345678901234567890", 50, GT2False }, // 50 bytes + { GT2True, FILL_IN, 128, GT2False }, + { GT2True, FILL_IN, 256, GT2False }, + { GT2True, FILL_IN, 512, GT2False }, + { GT2True, FILL_IN, 768, GT2False }, + { GT2True, FILL_IN, 1024, GT2False }, + { GT2True, FILL_IN, 1400, GT2False }, +#if !defined(_NITRO) + { GT2True, FILL_IN, 2047, GT2False }, +#if !defined(_REVOLUTION) + { GT2True, FILL_IN, (5 * 1024) - 1, GT2False }, + { GT2True, FILL_IN, (7 * 1024) - 1, GT2False }, +#if !defined(_PS2) && !defined(_PSP) + { GT2True, FILL_IN, (9 * 1024), GT2False }, +#if !defined (_MACOSX) && !defined(_PS3) // Maximum send size for PS3 is 9216 + { GT2True, FILL_IN, (9 * 1024) + 1, GT2False }, +#endif +#endif +#endif +#endif + + { GT2False } +}; + +Message hardcoreMessage = { GT2True, "12345678901234567890123456789012345678901234567890", 50, GT2True }; + +static void ConnectedCallback(GT2Connection connection, GT2Result result, GT2Byte * message, int len) +{ + if(result != GT2Success) + { + if (!message) + message = (GT2Byte *)""; + printf("Connect failed (%d): %s\n", result, message); + quit = GT2True; + return; + } + + printf("Connected\n"); + + GSI_UNUSED(connection); + GSI_UNUSED(len); +} + +static void ReceivedCallback( GT2Connection connection, GT2Byte * message, int len, GT2Bool reliable) +{ + Message * pcurr; + + // Server echo. + if(server) + { + messageCount++; + + if(!hardcore || !(messageCount % 100)) + printf("Got message %d (%d bytes, %s)\n", messageCount, len, reliable ? "reliable" : "unreliable"); + + gt2Send(connection, message, len, reliable); + } + else + { + if(hardcore) + { + pcurr = &hardcoreMessage; + messageCount++; + } + else + { + pcurr = &messageList[messageCount]; + } + + // Check this against the message list. + if((pcurr->reliable != reliable) || (pcurr->len != len) || (memcmp(pcurr->data, message, (size_t)len) != 0)) + { + printf("Message check failed (%d, %d)\n",pcurr->len, len); + } + else + { + if(!hardcore || !(messageCount % 100)) + { + printf("Message %d validated (%d bytes, %s)", messageCount + 1, len, reliable ? "reliable" : "unreliable"); + if(server) + printf("\n"); + else + printf(": %lu ms\n", current_time() - sendTime); + } + } + sendTime = 0; + } +} + +static void ClosedCallback(GT2Connection connection, GT2CloseReason reason) +{ + // Print out the reason. + printf("Connection closed: "); + if(reason == GT2LocalClose) + printf("Local Close\n"); + else if(reason == GT2RemoteClose) + printf("Remote Close\n"); + else if(reason == GT2CommunicationError) + printf("Communication Error\n"); + else if(reason == GT2SocketError) + printf("Socket Error\n"); + else if(reason == GT2NotEnoughMemory) + printf("Not Enough Memory\n"); + + quit = GT2True; + Connection = NULL; + + GSI_UNUSED(connection); +} + +static void PingCallback(GT2Connection connection, int latency) +{ + printf("Ping: %dms\n", latency); + + GSI_UNUSED(connection); +} + +static void SocketErrorCallback(GT2Socket socket) +{ + printf("SOCKET ERROR!!\n"); + + GSI_UNUSED(socket); +} + +static void ConnectAttemptCallback(GT2Socket socket, GT2Connection connection, unsigned int ip, unsigned short port, int latency, GT2Byte * message, int len) +{ + if((len == ((int)strlen(initialMessage.data) + 1)) && (memcmp(message, initialMessage.data, (size_t)len) == 0)) + { + gt2Accept(connection, &connectionCallbacks); + printf("Accepted connection from %s\n",gt2AddressToString(ip,port,NULL)); + } + else + { + gt2Reject(connection, (const GT2Byte *)"Invalid intial message.", -1); + printf("Rejected connection\n"); + } + + GSI_UNUSED(socket); + GSI_UNUSED(latency); +} + +static void SendDumpCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + GT2Bool reset, + const GT2Byte * message, + int len +) +{ + char buffer[128]; + sprintf(buffer, "SEND %p %p %s %d\n", socket, connection, gt2AddressToString(ip, port, NULL), len); +#ifdef WIN32 + OutputDebugString(buffer); +#endif + + GSI_UNUSED(reset); + GSI_UNUSED(message); +} + +static void ReceiveDumpCallback +( + GT2Socket socket, + GT2Connection connection, + unsigned int ip, + unsigned short port, + GT2Bool reset, + const GT2Byte * message, + int len +) +{ + char buffer[128]; + if(reset) + sprintf(buffer, "RECV %p %p %s RESET\n", socket, connection, gt2AddressToString(ip, port, NULL)); + else + sprintf(buffer, "RECV %p %p %s %d\n", socket, connection, gt2AddressToString(ip, port, NULL), len); +#ifdef WIN32 + OutputDebugString(buffer); +#endif + + GSI_UNUSED(message); +} + +#ifdef TEST_ENCODE_DECODE + +static void EncodeTest() +{ + const char encodestr[] = {GT_INT,GT_UINT,GT_SHORT,GT_USHORT,GT_CHAR,GT_UCHAR, + GT_FLOAT,GT_DOUBLE,GT_CSTR,GT_DBSTR,GT_RAW,0}; + const char encodestr2[] = {GT_CSTR_PTR,GT_DBSTR_PTR,GT_RAW_PTR,0}; + const char bitstr[] = {GT_BIT,GT_BIT,GT_BIT,GT_BIT,GT_BIT,GT_BIT,GT_BIT,GT_BIT,GT_BIT,GT_BIT,0}; + int i = -30, i2; + unsigned int uint = 300, uint2; + short sh = 10000, sh2; + unsigned short ush = 23500, ush2; + char ch = 23, ch2; + unsigned char uch = 129, uch2; + float f = 10.0f, f2; + double d = 1.12312312, d2; + char mystr[] = "this is a test string, this is only a test", mystr2[255], *mystr3; + short dbstr[] = {1234,5678,9012,1010,3210,1341,0}, dbstr2[255], *dbstr3; + char rawstr[] = "raw\001\000\001data", rawstr2[255], *rawstr3; + int rawdatalen = 10, rawdatalen2 = 10; + char bits[]={1,0,1,0,1,0,1,1,0,1},bits2[20]; + char outBuff[1024]; + int retlen, retlen2; + int temp; + + //retlen = gtEncode(0,"fs",outBuff,100,10.0f,mystr); + retlen = gtEncode(0,encodestr,outBuff,1024,i,uint,sh,ush,ch,uch,f,d,mystr,dbstr,rawstr,rawdatalen); + retlen2 = gtDecode(encodestr,outBuff, retlen,&i2,&uint2,&sh2,&ush2,&ch2,&uch2,&f2,&d2,mystr2,dbstr2, + rawstr2,&rawdatalen2); + printf("i=%d,i2=%d\nuint=%u,uint2=%u\nsh=%d,sh2=%d\nush=%u,ush2=%u\nch=%d,ch2=%d\nuch=%u,uch2=%u\nf=%f,f2=%f\nd=%f,d2=%f\n", + i,i2,uint,uint2,sh,sh2,ush,ush2,ch,ch2,uch,uch2,f,f2,d,d2); + printf("mystr =%s\nmystr2=%s\n",mystr,mystr2); + for (temp = 0; dbstr[temp] != 0; temp++) + printf("dbstr[%d]=%d,dbstr2[%d]=%d ",temp,dbstr[temp],temp,dbstr2[temp]); + printf("\nrawdatalen=%d,rawdatalen2=%d\n",rawdatalen,rawdatalen2); + for (temp = 0 ; temp < rawdatalen ; temp++) + printf("rawstr[%d]=%d,rawstr2[%d]=%d ",temp,rawstr[temp],temp,rawstr2[temp]); + printf("\nretlen=%d,retlen2=%d\n",retlen,retlen2); + retlen = gtEncode(0,bitstr,outBuff,1024,bits[0],bits[1],bits[2],bits[3],bits[4],bits[5],bits[6], + bits[7],bits[8],bits[9]); + retlen2 = gtDecode(bitstr,outBuff,retlen,bits2,bits2+1,bits2+2,bits2+3,bits2+4,bits2+5,bits2+6,bits2+7, + bits2+8,bits2+9); + for (temp = 0 ; temp < 10 ; temp++) + printf("bits[%d]=%d,bits2[%d]=%d ",temp,bits[temp],temp,bits2[temp]); + printf("\nretlen=%d,retlen2=%d\n",retlen,retlen2); + retlen = gtEncode(0,encodestr2,outBuff,1024,mystr,dbstr,rawstr,rawdatalen); + retlen2 = gtDecode(encodestr2,outBuff,retlen,&mystr3,&dbstr3,&rawstr3,&rawdatalen2); + printf("mystr =%s\nmystr3=%s\n",mystr,mystr3); + #ifdef ALIGNED_COPY + for (temp = 0; dbstr[temp] != 0; temp++) + { + memcpy(&sh,&dbstr[temp],sizeof(sh)); + memcpy(&sh2,&dbstr3[temp],sizeof(sh2)); + printf("dbstr[%d]=%d,dbstr3[%d]=%d ",temp,sh, temp,sh2); + } + #else + for (temp = 0; dbstr[temp] != 0; temp++) + printf("dbstr[%d]=%d,dbstr3[%d]=%d ",temp,dbstr[temp],temp,dbstr3[temp]); + #endif + printf("\nrawdatalen=%d,rawdatalen2=%d\n",rawdatalen,rawdatalen2); + for (temp = 0 ; temp < rawdatalen ; temp++) + printf("rawstr[%d]=%d,rawstr3[%d]=%d ",temp,rawstr[temp],temp,rawstr3[temp]); + printf("\nretlen=%d,retlen2=%d\n",retlen,retlen2); + + +} +#endif + +#ifdef __MWERKS__ // CodeWarrior will warn if function not prototyped + int test_main(int argc, char **argv); +#endif + +int test_main(int argc, char **argv) +{ + GT2Socket socket = NULL; + char localAddress[128] = ""; + char remoteAddress[128] = ""; + GT2Bool gotIt = GT2False; + Message * message; + int count = 0; + int msgloopcount = 0; + GT2Result result; + int i; + +#ifdef TEST_ENCODE_DECODE + EncodeTest(); +#endif + + // Set the callbacks. + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.connected = ConnectedCallback; + connectionCallbacks.received = ReceivedCallback; + connectionCallbacks.closed = ClosedCallback; + connectionCallbacks.ping = PingCallback; + + // Fill in long messages. + for(message = messageList ; message->valid ; message++) + { + if(message->data && (strcmp(message->data, FILL_IN) == 0)) + { + message->data = (char *)malloc((size_t)message->len); + for(i = 0 ; i < message->len ; i++) + message->data[i] = (char)('0' + (i % 10)); + } + } + + // Check the args. + if(argc > 1) + { + argc = 1; + if(strncmp(argv[argc], "-h", 2) == 0) + { + hardcore = GT2True; + argc++; + } + + // Check for listen. + if(strncmp(argv[argc], "-l", 2) == 0) + { + gotIt = GT2True; + server = GT2True; + argc++; + + if(argv[argc]) + strcpy(localAddress, argv[argc++]); + } + // Check for connect. + else if(strncmp(argv[argc], "-c", 2) == 0) + { + gotIt = GT2True; + server = GT2False; + argc++; + + if(argv[argc]) + strcpy(remoteAddress, argv[argc++]); + if(argv[argc]) + strcpy(localAddress, argv[argc++]); + } + } + + // Check if we haven't decided yet. + if(!gotIt) + { +#if 1 + server = GT2True; + strcpy(localAddress, ":12345"); +#else + server = GT2False; + strcpy(localAddress, ""); + strcpy(remoteAddress, "192.168.0.3:12345"); +#endif + } + + do + { + // create the socket + result = gt2CreateSocket(&socket, localAddress, 0, 0, SocketErrorCallback); + if(result != GT2Success) + { + printf("Failed to create socket! (%d)\n", result); + return 1; + } + + // set the dump callbacks + gt2SetSendDump(socket, SendDumpCallback); + gt2SetReceiveDump(socket, ReceiveDumpCallback); + + // listen if we're the server + if(server) + { + gt2Listen(socket, ConnectAttemptCallback); + + printf("Listening for incoming connections [%s]...\n", localAddress); + while(gsi_true) ///now we just think forever! + { + gt2Think(socket); + if(hardcore) + msleep(5); + else + msleep(20); + } + } + + //the rest is for client only + quit = GT2False; + printf("Attemping to connect to %s (max 10 sec)...\n", remoteAddress); + result = gt2Connect(socket, &Connection, remoteAddress, (GT2Byte *)initialMessage.data, initialMessage.len, 10000, &connectionCallbacks, GT2True); + if(result != GT2Success) + { + printf("gt2Connect failed! (%d)\n", result); + return 1; + } + + gt2Ping(Connection); + + if(quit) + return 1; + + messageCount = 0; + msgloopcount = 0; + quit = GT2False; + while(!quit && msgloopcount < 2) + { + unsigned long maxWait; + if(messageCount == 100000) + { + messageCount = 0; + msgloopcount++; + } + if(hardcore) + { + message = &hardcoreMessage; + } + else + { + message = &messageList[messageCount]; + if(!message->valid) + { + msgloopcount++; + continue; + } + } + + gt2Send(Connection, (GT2Byte *)message->data, message->len, message->reliable); + if(hardcore) + { + do + { + gt2Think(socket); + msleep(5); + } + while(gt2GetOutgoingBufferFreeSpace(Connection) < 100); + } + else + { + sendTime = current_time(); + maxWait = (unsigned long)((message->reliable) ? 120000 : 20000); + while (sendTime != 0 && current_time() - sendTime < maxWait && !quit) //wait a max of 20 sec for the reply + { + gt2Think(socket); + msleep(5); + } + if (sendTime != 0) + { + printf("Sending %d bytes %s failed!!\n",message->len, message->reliable ? "reliable" : "unreliable"); + } + messageCount++; + } + + } + if(Connection) + gt2CloseConnection(Connection); + } + while(!server && (++count < 3)); //if client do the sequence 3 times + + gt2CloseSocket(socket); + + return 0; +} diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2testc.dsp b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc.dsp new file mode 100644 index 00000000000..ed5eb9778b1 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc.dsp @@ -0,0 +1,326 @@ +# Microsoft Developer Studio Project File - Name="gt2testc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gt2testc - Win32 Unicode 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 "gt2testc.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 "gt2testc.mak" CFG="gt2testc - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gt2testc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2testc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2testc - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gt2testc - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/gt2/gt2testc", LPOCAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gt2testc - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gt2testc - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "gt2testc - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gt2testc___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "gt2testc___Win32_Unicode_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "gt2testc - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gt2testc___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "gt2testc___Win32_Unicode_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gt2testc - Win32 Release" +# Name "gt2testc - Win32 Debug" +# Name "gt2testc - Win32 Unicode Release" +# Name "gt2testc - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\gt2testc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\gt2Utility.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2testc_vs2005.vcproj b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc_vs2005.vcproj new file mode 100644 index 00000000000..751d1e11384 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc_vs2005.vcproj @@ -0,0 +1,1086 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2testc_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2testc_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2x360/gt2x360.sln b/xrGameSpy/gamespy/gt2/gt2testc/gt2x360/gt2x360.sln new file mode 100644 index 00000000000..97d5a197d8c --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2x360/gt2x360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gt2x360", "gt2x360.vcproj", "{6B1308C6-305D-4242-8819-DDE653878833}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6B1308C6-305D-4242-8819-DDE653878833}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {6B1308C6-305D-4242-8819-DDE653878833}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/gt2/gt2testc/gt2x360/gt2x360.vcproj b/xrGameSpy/gamespy/gt2/gt2testc/gt2x360/gt2x360.vcproj new file mode 100644 index 00000000000..5c580ace2e8 --- /dev/null +++ b/xrGameSpy/gamespy/gt2/gt2testc/gt2x360/gt2x360.vcproj @@ -0,0 +1,580 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/hashtable.c b/xrGameSpy/gamespy/hashtable.c new file mode 100644 index 00000000000..9313e5031e5 --- /dev/null +++ b/xrGameSpy/gamespy/hashtable.c @@ -0,0 +1,229 @@ +/* + * + * File: hashtable.c + * --------------- + * David Wright + * 10/8/98 + * + * See hashtable.h for function comments + * Implmentation is straight-forward, using a fixed dynamically allocated + * array for the buckets, and a DArray for each individual bucket + */ + +#include +#include +#include "darray.h" +#include "hashtable.h" + +#ifdef _MFC_MEM_DEBUG +#define _CRTDBG_MAP_ALLOC 1 +#include +#endif + + +#ifdef _NO_NOPORT_H_ + #define gsimalloc malloc + #define gsifree free + #define gsirealloc realloc + #include +#else + #include "nonport.h" //for gsimalloc/realloc/free/assert +#endif + + +struct HashImplementation +{ + DArray *buckets; + int nbuckets; + TableElementFreeFn freefn; + TableHashFn hashfn; + TableCompareFn compfn; +}; + +HashTable TableNew(int elemSize, int nBuckets, + TableHashFn hashFn, TableCompareFn compFn, + TableElementFreeFn freeFn) +{ + return TableNew2(elemSize, nBuckets, 4, hashFn, compFn, freeFn); +} +HashTable TableNew2(int elemSize, int nBuckets, int nChains, + TableHashFn hashFn, TableCompareFn compFn, + TableElementFreeFn freeFn) +{ + HashTable table; + int i; + + assert(hashFn); + assert(compFn); + assert(elemSize); + assert(nBuckets); + + table = (HashTable)gsimalloc(sizeof(struct HashImplementation)); + assert(table); + + table->buckets = (DArray *)gsimalloc(nBuckets * sizeof(DArray)); + assert(table->buckets); + for (i = 0; i < nBuckets; i++) //ArrayNew will assert if allocation fails + table->buckets[i] = ArrayNew(elemSize, nChains, freeFn); + table->nbuckets = nBuckets; + table->freefn = freeFn; + table->compfn = compFn; + table->hashfn = hashFn; + + return table; +} + + +void TableFree(HashTable table) +{ + int i; + + assert(table); + + if (NULL == table ) + return; + + for (i = 0 ; i < table->nbuckets ; i++) + ArrayFree(table->buckets[i]); + gsifree(table->buckets); + gsifree(table); +} + + +int TableCount(HashTable table) +{ + int i, count = 0; + + assert(table); + + if (NULL == table ) + return count; + + for (i = 0 ; i < table->nbuckets ; i++) + count += ArrayLength(table->buckets[i]); + + return count; +} + + +void TableEnter(HashTable table, const void *newElem) +{ + int hash, itempos; + + assert(table); + + if (NULL == table ) + return; + + hash = table->hashfn(newElem, table->nbuckets); + itempos = ArraySearch(table->buckets[hash], newElem, table->compfn, 0,0); + if (itempos == NOT_FOUND) + ArrayAppend(table->buckets[hash], newElem); + else + ArrayReplaceAt(table->buckets[hash], newElem, itempos); +} + +int TableRemove(HashTable table, const void *delElem) +{ + int hash, itempos; + + assert(table); + + if (NULL == table ) + return 0; + + hash = table->hashfn(delElem, table->nbuckets); + itempos = ArraySearch(table->buckets[hash], delElem, table->compfn, 0,0); + if (itempos == NOT_FOUND) + return 0; + else + ArrayDeleteAt(table->buckets[hash], itempos); + return 1; +} + +void *TableLookup(HashTable table, const void *elemKey) +{ + int hash, itempos; + + assert(table); + + if (NULL == table ) + return NULL; + + hash = table->hashfn(elemKey, table->nbuckets); + itempos = ArraySearch(table->buckets[hash], elemKey, table->compfn, 0, + 0); + if (itempos == NOT_FOUND) + return NULL; + else + return ArrayNth(table->buckets[hash], itempos); +} + + +void TableMap(HashTable table, TableMapFn fn, void *clientData) +{ + int i; + + assert(table); + assert(fn); + + if (NULL == table || NULL == fn) + return; + + for (i = 0 ; i < table->nbuckets ; i++) + ArrayMap(table->buckets[i], fn, clientData); + +} + +void TableMapSafe(HashTable table, TableMapFn fn, void *clientData) +{ + int i; + + assert(fn); + + for (i = 0 ; i < table->nbuckets ; i++) + ArrayMapBackwards(table->buckets[i], fn, clientData); + +} + +void * TableMap2(HashTable table, TableMapFn2 fn, void *clientData) +{ + int i; + void * pcurr; + + assert(fn); + + for (i = 0 ; i < table->nbuckets ; i++) + { + pcurr = ArrayMap2(table->buckets[i], fn, clientData); + if(pcurr) + return pcurr; + } + + return NULL; +} + +void * TableMapSafe2(HashTable table, TableMapFn2 fn, void *clientData) +{ + int i; + void * pcurr; + + assert(fn); + + for (i = 0 ; i < table->nbuckets ; i++) + { + pcurr = ArrayMapBackwards2(table->buckets[i], fn, clientData); + if(pcurr) + return pcurr; + } + + return NULL; +} + +void TableClear(HashTable table) +{ + int i; + + for (i = 0 ; i < table->nbuckets ; i++) + ArrayClear(table->buckets[i]); +} diff --git a/xrGameSpy/gamespy/hashtable.h b/xrGameSpy/gamespy/hashtable.h new file mode 100644 index 00000000000..d6c8a4a3c2f --- /dev/null +++ b/xrGameSpy/gamespy/hashtable.h @@ -0,0 +1,231 @@ + #ifndef _HASHTABLE_H +#define _HASHTABLE_H + +/* File: hashtable.h + * ------------------ + * Defines the interface for the HashTable ADT. + * The HashTable allows the client to store any number of elements of any + * type in a hash table for fast storage and retrieval. The client specifies + * the size (in bytes) of the elements that will be stored in the table when + * it is created. Thereafter the client and the HashTable refer to elements + * via (void*) ptrs. The HashTable imposes no upper bound on the number of + * elements and deals with all its own memory management. + * + * The client-supplied information (in the form of the number of buckets + * to use and the hashing function to be applied to each element) is employed + * to divide elements in buckets with hopefully only few collisions, resulting + * in Enter & Lookup performance in constant-time. The HashTable also supports + * iterating over all elements by use of mapping function. + */ + +/* Type: HashTable + * ---------------- + * Defines the HashTable type itself. The client can declare variables of type + * HashTable, but these variables must be initialized with the result of + * TableNew. The HashTable is implemented with pointers, so all client + * copies in variables or parameters will be "shallow" -- they will all + * actually point to the same HashTable structure. Only calls to TableNew + * create new tables. The struct declaration below is "incomplete"- the + * implementation details are literally not visible in the client .h file. + */ +typedef struct HashImplementation *HashTable; + + +/* TableHashFn + * ----------- + * TableHashFn is a pointer to a client-supplied function which the + * HashTable uses to hash elements. The hash function takes a (const void*) + * pointer to an element and the number of buckets and returns an int, + * which represents the hash code for this element. The returned hash code + * should be within the range 0 to numBuckets-1 and should be stable (i.e. + * an element's hash code should not change over time). + * For best performance, the hash function should be designed to + * uniformly distribute elements over the available number of buckets. + */ +typedef int (*TableHashFn)(const void *elem, int numBuckets); + + +/* TableCompareFn + * -------------- + * TableCompareFn is a pointer to a client-supplied function which the + * HashTable uses to compare elements. The comparator takes two + * (const void*) pointers (these will point to elements) and returns an int. + * The comparator should indicate the ordering of the two elements + * using the same convention as the strcmp library function: + * If elem1 is "less than" elem2, return a negative number. + * If elem1 is "greater than" elem2, return a positive number. + * If the two elements are "equal", return 0. + */ +#if defined(WIN32) +// explicitly set __cdecl so that Win devs can change default calling convention +typedef int (__cdecl *TableCompareFn)(const void *elem1, const void *elem2); +#else +typedef int (*TableCompareFn)(const void *elem1, const void *elem2); +#endif + + /* TableMapFn + * ---------- + * TableMapFn defines the space of functions that can be used to map over + * the elements in a HashTable. A map function is called with a pointer to + * the element and a client data pointer passed in from the original caller. + */ +typedef void (*TableMapFn)(void *elem, void *clientData); + + /* TableMapFn2 + * ---------- + * Same as TableMapFn, but can return 0 to stop the mapping. + * Used by TableMap2. + */ +typedef int (*TableMapFn2)(void *elem, void *clientData); + + +/* TableElementFreeFn + * ------------------ + * TableElementFreeFn defines the space of functions that can be used as the + * clean-up function for each element as it is deleted from the array + * or when the entire array of elements is freed. The cleanup function is + * called with a pointer to an element about to be deleted. + */ +typedef void (*TableElementFreeFn)(void *elem); + +#ifdef __cplusplus +extern "C" { +#endif + +/* TableNew + * -------- + * Creates a new HashTable with no entries and returns it. The elemSize + * parameter specifies the number of bytes that a single element of the + * table should take up. For example, if you want to store elements of type + * Binky, you would pass sizeof(Binky) as this parameter. An assert is + * raised if this size is not greater than 0. + * + * The nBuckets parameter specifies the number of buckets that the elements + * will be partitioned into. Once a HashTable is created, this number does + * not change. The nBuckets parameter must be in synch with the behavior of + * the hashFn, which must return a hash code between 0 and nBuckets-1. + * The hashFn parameter specifies the function that is called to retrieve the + * hash code for a given element. See the type declaration of TableHashFn + * above for more information. An assert is raised if nBuckets is not + * greater than 0. + * + * The compFn is used for testing equality between elements. See the + * type declaration for TableCompareFn above for more information. + * + * The elemFreeFn is the function that will be called on an element that is + * about to be overwritten (by a new entry in TableEnter) or on each element + * in the table when the entire table is being freed (using TableFree). This + * function is your chance to do any deallocation/cleanup required, + * (such as freeing any pointers contained in the element). The client can pass + * NULL for the cleanupFn if the elements don't require any handling on free. + * An assert is raised if either the hash or compare functions are NULL. + * + * nChains is the number of chains to allocate initially in each bucket + * + */ + +HashTable TableNew(int elemSize, int nBuckets, + TableHashFn hashFn, TableCompareFn compFn, + TableElementFreeFn freeFn); + +HashTable TableNew2(int elemSize, int nBuckets, int nChains, + TableHashFn hashFn, TableCompareFn compFn, + TableElementFreeFn freeFn); + + + /* TableFree + * ---------- + * Frees up all the memory for the table and its elements. It DOES NOT + * automatically free memory owned by pointers embedded in the elements. This + * would require knowledge of the structure of the elements which the HashTable + * does not have. However, it will iterate over the elements calling + * the elementFreeFn earlier supplied to TableNew and therefore, the client, + * who knows what the elements are,can do the appropriate deallocation of any + * embedded pointers through that function. + * After calling this, the value of what table points to is undefined. + */ +void TableFree(HashTable table); + + +/* TableCount + * ---------- + * Returns the number of elements currently in the table. + */ +int TableCount(HashTable table); + + + +/* TableEnter + * ---------- + * Enters a new element into the table. Uses the hash function to determine + * which bucket to place the new element. Its contents are copied from the + * memory pointed to by newElem. If there is already an element in the table + * which is determined to be equal (using the comparison function) this will + * use the contents of the new element to replace the previous element, + * calling the free function on the replaced element. + */ +void TableEnter(HashTable table, const void *newElem); + +/* TableRemove + * ---------- + * Remove a element frin the table. If the element does not exist + * the function returns 0. If it exists, it returns 1 and calls the + * free function on the removed element. + */ +int TableRemove(HashTable table, const void *delElem); + + +/* TableLookup + * ---------- + * Returns a pointer to the table element which matches the elemKey parameter + * (equality is determined by the comparison function). If there is no + * matching element, returns NULL. Calling this function does not + * re-arrange or change contents of the table or modify elemKey in any way. + */ +void *TableLookup(HashTable table, const void *elemKey); + + + +/* TableMap + * ----------- + * Iterates through each element in the table (in any order) and calls the + * function fn for that element. The function is called with the address of + * the table element and the clientData pointer. The clientData value allows + * the client to pass extra state information to the client-supplied function, + * if necessary. If no client data is required, this argument should be NULL. + * An assert is raised if the map function is NULL. + */ +void TableMap(HashTable table, TableMapFn fn, void *clientData); + +/* TableMapSafe + * ----------- + * Same as TableMap, but allows elements to be freed during the mapping. + */ +void TableMapSafe(HashTable table, TableMapFn fn, void *clientData); + +/* TableMap2 + * ----------- + * Same as TableMap, but allows the mapping to be stopped by returning 0 + * from the mapping function. If the mapping was stopped, the element + * it was stopped at will be returned. If it wasn't stopped, then NULL + * will be returned. + */ +void * TableMap2(HashTable table, TableMapFn2 fn, void *clientData); + +/* TableMapSafe2 + * ----------- + * Same as TableMap2, but allows elements to be freed during the mapping. + */ +void * TableMapSafe2(HashTable table, TableMapFn2 fn, void *clientData); + +/* TableClear + * ----------- + * Clears all the elements in the table without freeing it + */ +void TableClear(HashTable table); + +#ifdef __cplusplus +} +#endif + +#endif //_HASHTABLE_H diff --git a/xrGameSpy/gamespy/md5.h b/xrGameSpy/gamespy/md5.h new file mode 100644 index 00000000000..0fccee0c12a --- /dev/null +++ b/xrGameSpy/gamespy/md5.h @@ -0,0 +1,81 @@ +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +/* GLOBAL.H - RSAREF types and constants + */ + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. +The following makes PROTOTYPES default to 0 if it has not already + + been defined with C compiler flags. + */ + +#ifndef _MD5_H_ +#define _MD5_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PROTOTYPES +#define PROTOTYPES 1 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +typedef unsigned int UINT4; + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. +If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); +void MD5Print PROTO_LIST ((unsigned char [16], char[33])); +void MD5Digest PROTO_LIST ((unsigned char *, unsigned int, char[33])); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/md5c.c b/xrGameSpy/gamespy/md5c.c new file mode 100644 index 00000000000..de31fc6afc4 --- /dev/null +++ b/xrGameSpy/gamespy/md5c.c @@ -0,0 +1,354 @@ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +//#include "global.h" +#include "md5.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_NITRO) + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST ((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest operation, + processing another message block, and updating the context. + */ +void MD5Update ( + MD5_CTX *context, /* context */ + unsigned char *input, /* input block */ + unsigned int inputLen /* length of input block */ +) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final ( + unsigned char digest[16], /* message digest */ + MD5_CTX *context /* context */ + ) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (UINT4 state[4], unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG ( d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH ( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ +static void MD5_memcpy (POINTER output, POINTER input, unsigned int len) +{ + memcpy(output, input, len); +/* unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i];*/ +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (POINTER output, int value, unsigned int len) +{ + memset(output, value, len); + /* unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; */ +} + +#endif + +void MD5Print (unsigned char digest[16], char output[33]) +{ + static const char hex_digits[] = "0123456789abcdef"; + unsigned int i; + + for (i = 0; i < 16; i++) + { + output[i*2 ] = hex_digits[digest[i] / 16]; + output[i*2+1] = hex_digits[digest[i] % 16]; + } + output[32] = '\0'; +} + +void MD5Digest (unsigned char *input, unsigned int len, char output[33]) +{ + MD5_CTX ctx; + unsigned char digest[16]; + + MD5Init(&ctx); + MD5Update(&ctx, input, len); + MD5Final(digest, &ctx); + MD5Print(digest, output); + +} +#ifdef __cplusplus +} +#endif diff --git a/xrGameSpy/gamespy/natneg/NATify.c b/xrGameSpy/gamespy/natneg/NATify.c new file mode 100644 index 00000000000..3dbe6120d7b --- /dev/null +++ b/xrGameSpy/gamespy/natneg/NATify.c @@ -0,0 +1,383 @@ +#include +#include "nninternal.h" +#include "NATify.h" + +gsi_bool gotERT1, gotERT2, gotERT3; +gsi_bool gotADDRESS1a, gotADDRESS1b, gotADDRESS2, gotADDRESS3; + +// prototypes for compilers that complain +const char * AddressToString(unsigned int ip, unsigned short port, char string[22]); +unsigned int NameToIp(const char *name); + + +const char * AddressToString(unsigned int ip, unsigned short port, char string[22]) +{ + static char strAddressArray[2][22]; + static int nIndex; + char * strAddress; + + if(string) + strAddress = string; + else + { + nIndex ^= 1; + strAddress = strAddressArray[nIndex]; + } + + if(ip) + { + IN_ADDR inAddr; + + inAddr.s_addr = ip; + + if(port) + sprintf(strAddress, "%s:%d", inet_ntoa(inAddr), port); + else + sprintf(strAddress, "%s", inet_ntoa(inAddr)); + } + else if(port) + sprintf(strAddress, ":%d", port); + else + strAddress[0] = '\0'; + + return strAddress; +} + +static unsigned int GetLocalIP() +{ + int num_local_ips; + struct hostent *phost; + struct in_addr *addr; + unsigned int localip = 0; + phost = getlocalhost(); + if (phost == NULL) + return 0; + for (num_local_ips = 0 ; ; num_local_ips++) + { + if (phost->h_addr_list[num_local_ips] == 0) + break; + addr = (struct in_addr *)phost->h_addr_list[num_local_ips]; + if (addr->s_addr == htonl(0x7F000001)) + continue; + localip = addr->s_addr; + + if(IsPrivateIP(addr)) + return localip; + } + return localip; //else a specific private address wasn't found - return what we've got +} + +static unsigned short GetLocalPort(SOCKET sock) +{ + int ret; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + ret = getsockname(sock,(struct sockaddr *)&saddr, &saddrlen); + if (gsiSocketIsError(ret)) + return 0; + return saddr.sin_port; +} + +unsigned int NameToIp(const char *name) +{ + unsigned int ret; + struct hostent *hent; + + ret = inet_addr(name); + + if (ret == INADDR_NONE) + { + hent = gethostbyname(name); + if (!hent) + return 0; + ret = *(unsigned int *)hent->h_addr_list[0]; + } + return ret; +} + +int DiscoverReachability(SOCKET sock, unsigned int ip, unsigned short port, int portType) +{ + NatNegPacket p; + SOCKADDR_IN addr; + int len = sizeof(SOCKADDR_IN); + int success = 1; + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "(%d) Sending ERT Request to %s\n", portType, AddressToString(ip, port, NULL)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ip; + addr.sin_port = htons(port); + + memset(&p, 0, sizeof(p)); + p.magic[0] = NN_MAGIC_0; + p.magic[1] = NN_MAGIC_1; + p.magic[2] = NN_MAGIC_2; + p.magic[3] = NN_MAGIC_3; + p.magic[4] = NN_MAGIC_4; + p.magic[5] = NN_MAGIC_5; + p.version = NN_PROTVER; + p.packettype = NN_NATIFY_REQUEST; + p.cookie = (int)htonl(NATIFY_COOKIE); + p.Packet.Init.porttype = (unsigned char)portType; + + success = sendto(sock, (const char *)&p, sizeof(p), 0, (SOCKADDR *)&addr, sizeof(addr)); + + GSI_UNUSED(len); + return(success); +} + +int DiscoverMapping(SOCKET sock, unsigned int ip, unsigned short port, int portType, int id) +{ + NatNegPacket p; + SOCKADDR_IN addr; + int len = sizeof(SOCKADDR_IN); + int success; + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "Sending ADDRESS CHECK %d to %s\n", id, AddressToString(ip, port, NULL)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ip; + addr.sin_port = htons(port); + + memset(&p, 0, sizeof(p)); + p.magic[0] = NN_MAGIC_0; + p.magic[1] = NN_MAGIC_1; + p.magic[2] = NN_MAGIC_2; + p.magic[3] = NN_MAGIC_3; + p.magic[4] = NN_MAGIC_4; + p.magic[5] = NN_MAGIC_5; + p.version = NN_PROTVER; + p.packettype = NN_ADDRESS_CHECK; + p.cookie = (int)htonl(id); + p.Packet.Init.porttype = (unsigned char)portType; + + success = sendto(sock, (const char *)&p, sizeof(p), 0, (SOCKADDR *)&addr, sizeof(addr)); + + GSI_UNUSED(len); + return(success); +} + +void OutputMapping(const AddressMapping * theMap) +{ + if(theMap == NULL) + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "ERROR: Port mapping not available."); + } + else + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "Discovered map: [%s] -> [%s]\n", AddressToString(theMap->privateIp, theMap->privatePort, NULL), + AddressToString(theMap->publicIp, theMap->publicPort, NULL)); + } +} + +static int Think(SOCKET sock, NAT * nat) +{ + static char data[NNINBUF_LEN]; + int length; + unsigned char ptype; + NatNegPacket p; + struct sockaddr_in saddr; + int saddrlen = sizeof(struct sockaddr_in); + + // Is natification complete? + if(gotERT1 && gotERT2 && gotERT3 && + gotADDRESS1a && gotADDRESS1b && gotADDRESS2 && gotADDRESS3) + { + // Don't need to wait any longer, got all the stuff. + return(gsi_false); + } + + // Process incoming data if there is any. + if(sock != INVALID_SOCKET) + { + // Check if there is data. + while(CanReceiveOnSocket(sock)) + { + length = recvfrom(sock, data, NNINBUF_LEN, 0, (struct sockaddr *)&saddr, &saddrlen); + + if (gsiSocketIsError(length)) + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "RECV SOCKET ERROR: %d\n", GOAGetLastError(sock)); + break; + } + + if (memcmp(data, NNMagicData, NATNEG_MAGIC_LEN) != 0) + return(gsi_true); + + ptype = *(unsigned char *)(data + offsetof(NatNegPacket, packettype)); + + if (length < INITPACKET_SIZE) + return(gsi_true); + + if(ptype == NN_ERTTEST) + { + memcpy(&p, data, INITPACKET_SIZE); + + switch(p.Packet.Init.porttype) + { + case NN_PT_NN1: + // Got the solicited ERT reply. + gotERT1 = gsi_true; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "(1) Got the solicited ERT from: %s\n", AddressToString(saddr.sin_addr.s_addr, ntohs(saddr.sin_port), NULL)); + break; + case NN_PT_NN2: + // Got the unsolicited IP ERT reply. + nat->ipRestricted = gsi_false; + gotERT2 = gsi_true; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "(2) Got the unsolicited (address) ERT from: %s\n", AddressToString(saddr.sin_addr.s_addr, ntohs(saddr.sin_port), NULL)); + break; + case NN_PT_NN3: + // Got the unsolicited IP&Port ERT reply. + nat->portRestricted = gsi_false; + gotERT3 = gsi_true; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "(3) Got the unsolicited (port) ERT from: %s\n", AddressToString(saddr.sin_addr.s_addr, ntohs(saddr.sin_port), NULL)); + break; + } + + } + else if(ptype == NN_ADDRESS_REPLY) + { + memcpy(&p, data, INITPACKET_SIZE); + + p.cookie = (int)ntohl(p.cookie); + + switch(p.cookie) + { + case packet_map1a: + gotADDRESS1a = gsi_true; break; + case packet_map1b: + gotADDRESS1b = gsi_true; break; + case packet_map2: + gotADDRESS2 = gsi_true; break; + case packet_map3: + gotADDRESS3 = gsi_true; break; + } + + nat->mappings[p.cookie].privateIp = GetLocalIP(); + nat->mappings[p.cookie].privatePort = ntohs(GetLocalPort(sock)); + nat->mappings[p.cookie].publicIp = p.Packet.Init.localip; + nat->mappings[p.cookie].publicPort = ntohs(p.Packet.Init.localport); + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Comment, + "Got ADDRESS REPLY %d from: %s\n", p.cookie, AddressToString(saddr.sin_addr.s_addr, ntohs(saddr.sin_port), NULL)); + OutputMapping(&nat->mappings[p.cookie]); + } + + if (sock == INVALID_SOCKET) + break; + } + } + + return(gsi_true); +} + +int NatifyThink(SOCKET sock, NAT * nat) +{ + return(Think(sock, nat)); +} + +gsi_bool DetermineNatType(NAT * nat) +{ + // Initialize. + nat->natType = unknown; + nat->promiscuity = promiscuity_not_applicable; + nat->qr2Compatible = gsi_true; + + // Some of the address mappings are crucial in determining the NAT type. + // If we don't have them, then we should not proceed. + if(nat->mappings[packet_map1a].publicIp == 0 || + nat->mappings[packet_map2].publicIp == 0 || + nat->mappings[packet_map3].publicIp == 0) + return(gsi_false); + + // Is there a NAT? + if(!nat->portRestricted && + !nat->ipRestricted && + (nat->mappings[packet_map1a].publicIp == nat->mappings[packet_map1a].privateIp)) + { + nat->natType = no_nat; + } + else if(nat->mappings[packet_map1a].publicIp == nat->mappings[packet_map1a].privateIp) + { + nat->natType = firewall_only; + } + else + { + // What type of NAT is it? + if(!nat->ipRestricted && + !nat->portRestricted && + (abs(nat->mappings[packet_map3].publicPort - nat->mappings[packet_map2].publicPort) >= 1)) + { + nat->natType = symmetric; + nat->promiscuity = promiscuous; + } + else if(nat->ipRestricted && + !nat->portRestricted && + (abs(nat->mappings[packet_map3].publicPort - nat->mappings[packet_map2].publicPort) >= 1)) + { + nat->natType = symmetric; + nat->promiscuity = port_promiscuous; + } + else if(!nat->ipRestricted && + nat->portRestricted && + (abs(nat->mappings[packet_map3].publicPort - nat->mappings[packet_map2].publicPort) >= 1)) + { + nat->natType = symmetric; + nat->promiscuity = ip_promiscuous; + } + else if(nat->ipRestricted && + nat->portRestricted && + (abs(nat->mappings[packet_map3].publicPort - nat->mappings[packet_map2].publicPort) >= 1)) + { + nat->natType = symmetric; + nat->promiscuity = not_promiscuous; + } + else if(nat->portRestricted) + nat->natType = port_restricted_cone; + else if(nat->ipRestricted && !nat->portRestricted) + nat->natType = restricted_cone; + else if(!nat->ipRestricted && !nat->portRestricted) + nat->natType = full_cone; + else + nat->natType = unknown; + } + + // What is the port mapping behavior? + if(nat->mappings[packet_map1a].publicPort == nat->mappings[packet_map1a].privatePort && + nat->mappings[packet_map2].publicPort == nat->mappings[packet_map2].privatePort && + nat->mappings[packet_map3].publicPort == nat->mappings[packet_map3].privatePort) + // Using private port as the public port. + nat->mappingScheme = private_as_public; + else if(nat->mappings[packet_map1a].publicPort == nat->mappings[packet_map2].publicPort && + nat->mappings[packet_map2].publicPort == nat->mappings[packet_map3].publicPort) + // Using the same public port for all requests from the same private port. + nat->mappingScheme = consistent_port; + else if(nat->mappings[packet_map1a].publicPort == nat->mappings[packet_map1a].privatePort && + nat->mappings[packet_map3].publicPort - nat->mappings[packet_map2].publicPort == 1) + // Using private port as the public port for the first mapping. + // Using an incremental (+1) port mapping scheme there after. + nat->mappingScheme = mixed; + else if(nat->mappings[packet_map3].publicPort - nat->mappings[packet_map2].publicPort == 1) + // Using an incremental (+1) port mapping scheme. + nat->mappingScheme = incremental; + else + // Unrecognized port mapping scheme. + nat->mappingScheme = unrecognized; + + if(nat->mappings[packet_map1b].publicPort != 0 && nat->mappings[packet_map1a].publicPort != nat->mappings[packet_map1b].publicPort) + { + // NOTE: The NAT maps different ports for the same destination. + // Game servers may not be properly reported to the GameSpy backend. + nat->qr2Compatible = gsi_false; + } + + return(gsi_true); +} diff --git a/xrGameSpy/gamespy/natneg/NATify.h b/xrGameSpy/gamespy/natneg/NATify.h new file mode 100644 index 00000000000..217d9611878 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/NATify.h @@ -0,0 +1,45 @@ +#if !defined(AFX_NATIFY_H__B8FF4369_8789_4674_8569_3D52CE8CA890__INCLUDED_) +#define AFX_NATIFY_H__B8FF4369_8789_4674_8569_3D52CE8CA890__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#define NATIFY_COOKIE 777 +#define NATIFY_TIMEOUT 10000 +#define NATIFY_STATUS_STEPS (NATIFY_TIMEOUT / 1000) + 7 + +typedef enum { packet_map1a, packet_map2, packet_map3, packet_map1b, NUM_PACKETS } NatifyPacket; +typedef enum { no_nat, firewall_only, full_cone, restricted_cone, port_restricted_cone, symmetric, unknown, NUM_NAT_TYPES } NatType; +typedef enum { promiscuous, not_promiscuous, port_promiscuous, ip_promiscuous, promiscuity_not_applicable, NUM_PROMISCUITY_TYPES } NatPromiscuity; +typedef enum { unrecognized, private_as_public, consistent_port, incremental, mixed, NUM_MAPPING_SCHEMES } NatMappingScheme; + +typedef struct _AddressMapping { + unsigned int privateIp; + unsigned short privatePort; + unsigned int publicIp; + unsigned short publicPort; +} AddressMapping; + +typedef struct _NAT { + char brand[32]; + char model[32]; + char firmware[64]; + gsi_bool ipRestricted; + gsi_bool portRestricted; + NatPromiscuity promiscuity; + NatType natType; + NatMappingScheme mappingScheme; + AddressMapping mappings[4]; + gsi_bool qr2Compatible; +} NAT; + +int DiscoverReachability(SOCKET sock, unsigned int ip, unsigned short port, int portType); +int DiscoverMapping(SOCKET sock, unsigned int ip, unsigned short port, int portType, int id); +int NatifyThink(SOCKET sock, NAT * nat); +gsi_bool DetermineNatType(NAT * nat); +void OutputMapping(const AddressMapping * theMap); + + +#endif // !defined(AFX_NATIFY_H__B8FF4369_8789_4674_8569_3D52CE8CA890__INCLUDED_) diff --git a/xrGameSpy/gamespy/natneg/changelog.txt b/xrGameSpy/gamespy/natneg/changelog.txt new file mode 100644 index 00000000000..b7935d81594 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/changelog.txt @@ -0,0 +1,111 @@ +Changelog for: GameSpy NAT Negotiation SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.03.01 DES FEATURE Support for match queuing +12-12-2007 2.03.00 RMV RELEASE Released to Developer Site +08-06-2007 2.02.00 RMV RELEASE Released to Developer Site +07-10-2007 2.01.03 RMV OTHER Raised test Project warning levels (to 4) and fixed compiler warnings +06-13-2007 2.01.02 SAH FIX Fixed a bug where a fast report return could cancel NN prior to completion +05-16-2007 2.01.01 DES FIX Replaced two while(1) statements +12-15-2006 2.01.00 MJW RELEASE Released to Developer Site +12-13-2006 2.00.09 SN FIX Named a union to get rid of a warning +11-13-2006 2.00.08 SAH FIX Fixed a bug where negotiateSock was never closed, even when using a gamesocket +10-05-2006 2.00.07 SAH FIX Updated MacOSX Makefile +09-28-2006 2.00.06 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-24-2006 2.00.05 SAH FIX Fixed VC7 Project file; removed ';' after PRE_ALIGN call in simpletest to get rid of compiler warning +08-18-2006 2.00.04 SN FIX Renamed a parameter of the OutputMapping function due to standard c++ lib conflict +08-02-2006 2.00.03 SAH RELEASE Releasing to developer site +07-31-2006 2.00.03 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution + SAH FIX Fixed Linux makefile +07-25-2006 2.00.02 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file + SAH FIX Fixed some implicit typecasts and unused variables + SAH FIX Changed all instances of BOOL to gsi_bool, FALSE to gsi_false, TRUE to gsi_true + SAH FIX Made some functions static, or included prototypes to get rid of compiler warnings + SAH FIX Fixed PS3, PSP, PS2 projects to include Natify.c,h +07-24-2006 2.00.01 SAH FIX Removed #ifdef _PS3 for socket calls (changed platformSocket.h to typecast calls) +07-21-2006 2.00.00 BMS FEATURE New version 3 of the NN protocol - SDK is now version 2 +07-06-2006 1.00.45 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +06-30-2006 1.00.44 SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) + SAH FIX Fixed Linux makefile +05-31-2006 1.00.43 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-30-2006 1.00.42 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) + Added PRE_ALIGN, POST_ALIGN for mem_managed to simpletest +05-25-2006 1.00.41 SAH FIX Changed PSP project warning levels +05-22-2006 1.00.40 SAH FIX Changed ESTRING to unsigned int to remove warnings +05-19-2006 1.00.39 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-15-2006 1.00.38 SAH FIX Added "PS3 Release" configuration to project +05-09-2006 1.00.37 SN FIX Changed the output statements in simple to be more descriptive +04-25-2006 1.00.36 SAH RELEASE Releasing to developer site +04-24-2006 1.00.36 SAH FIX Fixed Nitro Project files to work on build machine +04-20-2006 1.00.35 SAH FIX Moved GSI_UNUSED call above return statement +04-20-2006 1.00.34 SAH FIX Added _PS3 wrapper typecast for socket calls +02-13-2006 1.00.33 DDW FIX Fixed crash when NN DNS address fails to resolve +01-27-2006 1.00.32 SN RELEASE Releasing to developer site +01-27-2006 1.00.32 SN OTHER Added psp prodg project and solution to sgv +12-22-2005 1.00.32 SN OTHER Cleaned up project and added any missing code common code +11-17-2005 1.00.31 DES FIX Added error check to simpletest. + DES FIX Updated Nitro Makefile. +11-14-2005 1.00.30 DES FIX Updated the OSX Makefile. + DES FEATURE Added GSI_DOMAIN_NAME support. +11-09-2005 1.00.29 BED FEATURE Added PS3 makefile for simpletest. +10-07-2005 1.00.28 DES FEATURE Reduced number of retries, so failures timeout sooner. + DES FEATURE Added packet types for address check feature. +09-25-2005 1.00.27 DES FEATURE Updated DS support + DES FIX Don't send additional ping packets if not needed + DES FEATURE Added game-specific DNS +07-28-2005 1.00.26 SN RELEASE Releasing to developer site. +07-15-2005 1.00.26 SN FIX Fixed included file for availability check +06-03-2005 1.00.25 SN RELEASE Releasing to developer site. +05-04-2005 1.00.25 SN OTHER Created Visual Studio .NET project +04-28-2005 1.00.25 SN RELEASE Releasing to developer site. +04-27-2005 1.00.25 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 1.00.25 DES CLEANUP Replaced old DP() code with debug logging. +04-04-2005 1.00.24 SN RELEASE Releasing to developer site. +03-14-2005 1.00.24 DES FEATURE Nintendo DS support +01-27-2003 1.00.23 DES FIX Fixed custom SN sendto and moved it to nonport +09-16-2004 1.00.22 SN RELEASE Releasing to developer site. +08-27-2004 1.00.22 DES CLEANUP Fixed warnings under OSX + DES CLEANUP Removed #pragma comment for linking with winsock (in nonport now) + DES CLEANUP Updated Win32 project configurations +08-25-2004 1.00.21 DES FEATURE Added OSX makefile +08-05-2004 1.00.20 SN FIX Releasing to developer site. +07-19-2004 1.00.20 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +06-18-2004 1.00.19 BED RELEASE Releasing to developer site. +06-17-2004 1.00.19 BED FEATURE Added PS2 Insock (LibNet) support +11-10-2003 1.00.18 DES RELEASE Releasing to developer site. +11-07-2003 1.00.18 DES FIX Updated the linux and PS2 makefiles. +11-04-2003 1.00.17 DES FEATURE Added availability check code. +10-30-2003 1.00.16 DES FEATURE Pass the gamename to the backend when connecting or searching. +07-24-2003 1.00.15 DES RELEASE Releasing to developer site. +07-18-2003 1.00.15 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 1.00.14 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 1.00.13 BED FIX Added #ifndef to avoid #pragma that PS2 doesn't understand + DES FIX Changed a few __mips64 checks to _PS2 checks. + BED FEATURE Added ProDG sample project files. +05-09-2003 1.00.12 DES CLEANUP Removed Dreamcast support. +04-21-2003 1.00.11 DES FIX Changed WSAGetLastError call in a DP macro to GOAGetLastError. +04-07-2003 1.00.10 DES FIX Fixed byte alignment issues with InitPacket. + RELEASE Releasing to developer site. +03-26-2003 1.00.09 DES RELEASE Releasing to developer site. +03-24-2003 1.00.09 DES OTHER Changed interal IP code to use the common code's IsPrivateIP. +03-21-2003 1.00.08 DDW FEATURE Added support for reporting "internal" address to allow for + negotiation of two users behind the same NAT. + Added NNFreeNegotiateList function to free all memory once done. +03-17-2003 1.00.07 DES FIX Added extern "C" to natneg.h for when compiling with C++. +02-05-2003 1.00.06 DES RELEASE Releasing to developer site. +02-05-2003 1.00.06 DES CLEANUP Switched to use the common code CanReceiveOnSocket and CanSendOnSocket. +12-19-2002 1.00.05 DES RELEASE Releasing to developer site. +12-16-2002 1.00.05 DES CLEANUP Removed calls to GOAClearSocketError. +12-13-2002 1.00.04 DES FEATURE Added PS2 eenet stack support. +12-03-2002 1.00.03 DES RELEASE Releasing to developer site. +12-03-2002 1.00.03 DES FEATURE Added a Linux Makefile. +11-22-2002 1.00.02 DES RELEASE Releasing to developer site. +11-21-2002 1.00.02 DES FIX Hardcoded packet struct sizes to get around PS2/compiler packing bug. +11-20-2002 1.00.01 DES FEATURE Added support for compiling on the PS2. +09-26-2002 1.00.00 DES RELEASE Limited release on developer site +09-25-2002 1.00.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/natneg/natneg.c b/xrGameSpy/gamespy/natneg/natneg.c new file mode 100644 index 00000000000..2f778e751f6 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/natneg.c @@ -0,0 +1,806 @@ +#include "nninternal.h" +#include "../darray.h" +#include "../common/gsAvailable.h" +#include +#include +#include "NATify.h" + +unsigned char NNMagicData[] = {NN_MAGIC_0, NN_MAGIC_1, NN_MAGIC_2, NN_MAGIC_3, NN_MAGIC_4, NN_MAGIC_5}; +struct _NATNegotiator +{ + SOCKET negotiateSock; + SOCKET gameSock; + int cookie; + int clientindex; + NegotiateState state; + int initAckRecv[4]; + int retryCount; + int maxRetryCount; + unsigned long retryTime; + unsigned int guessedIP; + unsigned short guessedPort; + unsigned char gotRemoteData; + unsigned char sendGotRemoteData; + NegotiateProgressFunc progressCallback; + NegotiateCompletedFunc completedCallback; + void *userdata; + NegotiateResult result; + SOCKET connectedSocket; + struct sockaddr_in remoteaddr; +}; + +typedef struct _NATNegotiator *NATNegotiator; + +DArray negotiateList = NULL; + +char *Matchup1Hostname; +char *Matchup2Hostname; +char *Matchup3Hostname; + +unsigned int matchup1ip = 0; +unsigned int matchup2ip = 0; +unsigned int matchup3ip = 0; + +NAT nat; +NatDetectionResultsFunc natifyCallback; +static SOCKET mappingSock = INVALID_SOCKET; +static SOCKET ertSock = INVALID_SOCKET; +static gsi_time natifyStartTime; +static gsi_bool activeNatify = gsi_false; +static NatType natType = unknown; +static NatMappingScheme natMappingScheme = unrecognized; + + +static NATNegotiator FindNegotiatorForCookie(int cookie) +{ + int i; + if (negotiateList == NULL) + return NULL; + for (i = 0 ; i < ArrayLength(negotiateList) ; i++) + { + //we go backwards in case we need to remove one.. + NATNegotiator neg = (NATNegotiator)ArrayNth(negotiateList, i); + if (neg->cookie == cookie) + return neg; + } + return NULL; +} + +static NATNegotiator AddNegotiator() +{ + + struct _NATNegotiator _neg; + + + memset(&_neg, 0, sizeof(_neg)); + + if (negotiateList == NULL) + negotiateList = ArrayNew(sizeof(_neg), 4, NULL); + + ArrayAppend(negotiateList, &_neg); + + return (NATNegotiator)ArrayNth(negotiateList, ArrayLength(negotiateList) - 1); +} + +static void RemoveNegotiator(NATNegotiator neg) +{ + int i; + for (i = 0 ; i < ArrayLength(negotiateList) ; i++) + { + //we go backwards in case we need to remove one.. + if (neg == (NATNegotiator)ArrayNth(negotiateList, i)) + { + ArrayRemoveAt(negotiateList, i); + return; + + } + } +} + +void NNFreeNegotiateList() +{ + if (negotiateList != NULL) + { + ArrayFree(negotiateList); + negotiateList = NULL; + } +} + +static int CheckMagic(char *data) +{ + return (memcmp(data, NNMagicData, NATNEG_MAGIC_LEN) == 0); +} + +static void SendPacket(SOCKET sock, unsigned int toaddr, unsigned short toport, void *data, int len) +{ + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(toport); + saddr.sin_addr.s_addr = toaddr; + sendto(sock, (char *)data, len, 0, (struct sockaddr *)&saddr, sizeof(saddr)); +} + +static unsigned int GetLocalIP() +{ + int num_local_ips; + struct hostent *phost; + struct in_addr *addr; + unsigned int localip = 0; + phost = getlocalhost(); + if (phost == NULL) + return 0; + for (num_local_ips = 0 ; ; num_local_ips++) + { + if (phost->h_addr_list[num_local_ips] == 0) + break; + addr = (struct in_addr *)phost->h_addr_list[num_local_ips]; + if (addr->s_addr == htonl(0x7F000001)) + continue; + localip = addr->s_addr; + + if(IsPrivateIP(addr)) + return localip; + } + return localip; //else a specific private address wasn't found - return what we've got +} + +static unsigned short GetLocalPort(SOCKET sock) +{ + int ret; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + + ret = getsockname(sock,(struct sockaddr *)&saddr, &saddrlen); + + if (gsiSocketIsError(ret)) + return 0; + return saddr.sin_port; +} + +static void SendReportPacket(NATNegotiator neg) +{ + NatNegPacket p; + + memcpy(p.magic, NNMagicData, NATNEG_MAGIC_LEN); + p.version = NN_PROTVER; + p.packettype = NN_REPORT; + p.cookie = (int)htonl(neg->cookie); + p.Packet.Report.clientindex = (unsigned char)neg->clientindex; + p.Packet.Report.negResult = (unsigned char)(neg->result==nr_success?gsi_true:gsi_false); + p.Packet.Report.natType = natType; + p.Packet.Report.natMappingScheme = natMappingScheme; + + if(strlen(__GSIACGamename) > 0) + memcpy(&p.Packet.Report.gamename, __GSIACGamename, sizeof(p.Packet.Report.gamename)); + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending REPORT to %s:%d (result: %d)\n", inet_ntoa(*(struct in_addr *)&matchup1ip), MATCHUP_PORT1, p.Packet.Report.negResult); + + SendPacket(neg->negotiateSock, matchup1ip, MATCHUP_PORT1, &p, REPORTPACKET_SIZE); +} + +static void StartReport(NATNegotiator neg, NegotiateResult result, SOCKET socket, struct sockaddr_in *remoteaddr) +{ + neg->result = result; + neg->connectedSocket = socket; + if(remoteaddr != NULL) + memcpy(&neg->remoteaddr, remoteaddr, sizeof(neg->remoteaddr)); + + if(result == nr_inittimeout || result == nr_deadbeatpartner) + { + neg->state = ns_finished; +// neg->state = ns_reportack; + neg->completedCallback(neg->result, neg->connectedSocket, (struct sockaddr_in *)&neg->remoteaddr, neg->userdata); + + // Close the socket here - no need to keep it open, connected Socket is INVALID + //neg->negotiateSock = INVALID_SOCKET; + NNCancel(neg->cookie); + } + else + { + SendReportPacket(neg); + neg->state = ns_reportsent; + neg->retryTime = current_time() + REPORT_RETRY_TIME; + neg->retryCount = 0; + neg->maxRetryCount = REPORT_RETRY_COUNT; + } +} + +static void SendInitPackets(NATNegotiator neg) +{ + char buffer[INITPACKET_SIZE + sizeof(__GSIACGamename)]; + + NatNegPacket * p = (NatNegPacket *)buffer; + unsigned int localip; + unsigned short localport; + int packetlen; + + memcpy(p->magic, NNMagicData, NATNEG_MAGIC_LEN); + p->version = NN_PROTVER; + p->packettype = NN_INIT; + p->cookie = (int)htonl((unsigned int)neg->cookie); + p->Packet.Init.clientindex = (unsigned char)neg->clientindex; + p->Packet.Init.usegameport = (unsigned char)((neg->gameSock == INVALID_SOCKET) ? 0 : 1); + localip = ntohl(GetLocalIP()); + //ip + buffer[INITPACKET_ADDRESS_OFFSET] = (char)((localip >> 24) & 0xFF); + buffer[INITPACKET_ADDRESS_OFFSET+1] = (char)((localip >> 16) & 0xFF); + buffer[INITPACKET_ADDRESS_OFFSET+2] = (char)((localip >> 8) & 0xFF); + buffer[INITPACKET_ADDRESS_OFFSET+3] = (char)(localip & 0xFF); + //port (this may not be determined until the first packet goes out) + buffer[INITPACKET_ADDRESS_OFFSET+4] = 0; + buffer[INITPACKET_ADDRESS_OFFSET+5] = 0; + // add the gamename to all requests + strcpy(buffer + INITPACKET_SIZE, __GSIACGamename); + packetlen = (INITPACKET_SIZE + (int)strlen(__GSIACGamename) + 1); + if (p->Packet.Init.usegameport && !neg->initAckRecv[NN_PT_GP]) + { + p->Packet.Init.porttype = NN_PT_GP; + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending INIT (GP) to %s:%d...\n", inet_ntoa(*(struct in_addr *)&matchup1ip), MATCHUP_PORT1); + + SendPacket(neg->gameSock, matchup1ip, MATCHUP_PORT1, p, packetlen); + } + + if (!neg->initAckRecv[NN_PT_NN1]) + { + p->Packet.Init.porttype = NN_PT_NN1; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending INIT (NN1) to %s:%d...\n", inet_ntoa(*(struct in_addr *)&matchup1ip), MATCHUP_PORT1); + + SendPacket(neg->negotiateSock, matchup1ip, MATCHUP_PORT1, p, packetlen); + } + + //this should be determined now... + localport = ntohs(GetLocalPort((p->Packet.Init.usegameport) ? neg->gameSock : neg->negotiateSock)); + buffer[INITPACKET_ADDRESS_OFFSET+4] = (char)((localport >> 8) & 0xFF); + buffer[INITPACKET_ADDRESS_OFFSET+5] = (char)(localport & 0xFF); + + if (!neg->initAckRecv[NN_PT_NN2]) + { + p->Packet.Init.porttype = NN_PT_NN2; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending INIT (NN2) to %s:%d...\n", inet_ntoa(*(struct in_addr *)&matchup2ip), MATCHUP_PORT2); + + SendPacket(neg->negotiateSock, matchup2ip, MATCHUP_PORT2, p, packetlen); + } + + if (!neg->initAckRecv[NN_PT_NN3]) + { + p->Packet.Init.porttype = NN_PT_NN3; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending INIT (NN3) to %s:%d...\n", inet_ntoa(*(struct in_addr *)&matchup3ip), MATCHUP_PORT3); + + SendPacket(neg->negotiateSock, matchup3ip, MATCHUP_PORT3, p, packetlen); + } + + neg->retryTime = current_time() + INIT_RETRY_TIME; + neg->maxRetryCount = INIT_RETRY_COUNT; +} + +static void SendPingPacket(NATNegotiator neg) +{ + NatNegPacket p; + + memcpy(p.magic, NNMagicData, NATNEG_MAGIC_LEN); + p.version = NN_PROTVER; + p.packettype = NN_CONNECT_PING; + p.cookie = (int)htonl((unsigned int)neg->cookie); + p.Packet.Connect.remoteIP = neg->guessedIP; + p.Packet.Connect.remotePort = htons(neg->guessedPort); + p.Packet.Connect.gotyourdata = neg->gotRemoteData; + p.Packet.Connect.finished = (unsigned char)((neg->state == ns_connectping) ? 0 : 1); + +////////////// +// playing with a way to re-sync with the NAT's port mappings in the case the guess is off: +//if(neg->retryCount >= 3 && neg->retryCount % 3 == 0) neg->guessedPort++; +////////////// + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending PING to %s:%d (got remote data: %d)\n", inet_ntoa(*(struct in_addr *)&neg->guessedIP), neg->guessedPort, neg->gotRemoteData); + SendPacket((neg->gameSock != INVALID_SOCKET) ? neg->gameSock : neg->negotiateSock, neg->guessedIP, neg->guessedPort, &p, CONNECTPACKET_SIZE); + neg->retryTime = current_time() + PING_RETRY_TIME; + neg->maxRetryCount = PING_RETRY_COUNT; + if(neg->gotRemoteData) + neg->sendGotRemoteData = 1; +} + +static gsi_bool CheckNatifyStatus(SOCKET sock) +{ + gsi_bool active = gsi_true; + gsi_bool success = gsi_false; + + if(sock != INVALID_SOCKET) + { + if(current_time() - natifyStartTime < NATIFY_TIMEOUT) + active = NatifyThink(sock, &nat); + else + active = gsi_false; + + if(!active) + { + success = DetermineNatType(&nat); + natifyCallback(success, nat); + + natType = nat.natType; + natMappingScheme = nat.mappingScheme; + + // Clean up natify's socks. + if (mappingSock != INVALID_SOCKET) + closesocket(mappingSock); + mappingSock = INVALID_SOCKET; + if (ertSock != INVALID_SOCKET) + closesocket(ertSock); + ertSock = INVALID_SOCKET; + } + } + + return(active); +} + +NegotiateError NNBeginNegotiation(int cookie, int clientindex, NegotiateProgressFunc progresscallback, NegotiateCompletedFunc completedcallback, void *userdata) +{ + return NNBeginNegotiationWithSocket(INVALID_SOCKET, cookie, clientindex, progresscallback, completedcallback, userdata); +} + +static unsigned int NameToIp(const char *name) +{ + unsigned int ret; + struct hostent *hent; + + ret = inet_addr(name); + + if (ret == INADDR_NONE) + { + hent = gethostbyname(name); + if (!hent) + return 0; + ret = *(unsigned int *)hent->h_addr_list[0]; + } + return ret; +} + +static unsigned int ResolveServer(const char * overrideHostname, const char * defaultHostname) +{ + const char * hostname; + char hostnameBuffer[64]; + + if(overrideHostname == NULL) + { + snprintf(hostnameBuffer, sizeof(hostnameBuffer), "%s.%s", __GSIACGamename, defaultHostname); + hostname = hostnameBuffer; + } + else + { + hostname = overrideHostname; + } + + return NameToIp(hostname); +} + +static int ResolveServers() +{ + if (matchup1ip == 0) + { + matchup1ip = ResolveServer(Matchup1Hostname, MATCHUP1_HOSTNAME); + } + + if (matchup2ip == 0) + { + matchup2ip = ResolveServer(Matchup2Hostname, MATCHUP2_HOSTNAME); + } + + if (matchup3ip == 0) + { + matchup3ip = ResolveServer(Matchup3Hostname, MATCHUP3_HOSTNAME); + } + + if (matchup1ip == 0 || matchup2ip == 0 || matchup3ip == 0) + return 0; + + return 1; +} + +NegotiateError NNStartNatDetection(NatDetectionResultsFunc resultscallback) +{ + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return ne_socketerror; + if (!ResolveServers()) + return ne_dnserror; + + activeNatify = gsi_true; + natifyCallback = resultscallback; + natifyStartTime = current_time(); + + // Assume this for now. + nat.ipRestricted = gsi_true; + nat.portRestricted = gsi_true; + + // Socket to use for external reach tests. + ertSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + // Socket to use for determining how traffic is mapped. + mappingSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + // Send reachability packets. + DiscoverReachability(ertSock, matchup1ip, MATCHUP_PORT1, NN_PT_NN1); + DiscoverReachability(ertSock, matchup1ip, MATCHUP_PORT1, NN_PT_NN2); + DiscoverReachability(ertSock, matchup2ip, MATCHUP_PORT2, NN_PT_NN3); + + // Send mapping packets. + DiscoverMapping(mappingSock, matchup1ip, MATCHUP_PORT1, NN_PT_NN1, packet_map1a); + DiscoverMapping(mappingSock, matchup1ip, MATCHUP_PORT1, NN_PT_NN1, packet_map1b); + DiscoverMapping(mappingSock, matchup2ip, MATCHUP_PORT2, NN_PT_NN2, packet_map2); + DiscoverMapping(mappingSock, matchup3ip, MATCHUP_PORT3, NN_PT_NN3, packet_map3); + + return ne_noerror; +} + +NegotiateError NNBeginNegotiationWithSocket(SOCKET gamesocket, int cookie, int clientindex, NegotiateProgressFunc progresscallback, NegotiateCompletedFunc completedcallback, void *userdata) +{ + NATNegotiator neg; + + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return ne_socketerror; + if (!ResolveServers()) + return ne_dnserror; + + neg = AddNegotiator(); + if (neg == NULL) + return ne_allocerror; + neg->gameSock = gamesocket; + neg->clientindex = clientindex; + neg->cookie = cookie; + neg->progressCallback = progresscallback; + neg->completedCallback = completedcallback; + neg->userdata = userdata; + neg->negotiateSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + neg->retryCount = 0; + neg->gotRemoteData = 0; + neg->sendGotRemoteData = 0; + neg->guessedIP = 0; + neg->guessedPort = 0; + neg->maxRetryCount = 0; + neg->result = nr_noresult; + if (neg->negotiateSock == INVALID_SOCKET) + { + RemoveNegotiator(neg); + return ne_socketerror; + } + SendInitPackets(neg); + +#if defined(GSI_COMMON_DEBUG) + { + struct sockaddr_in saddr; + int namelen = sizeof(saddr); + + getsockname(neg->negotiateSock, (struct sockaddr *)&saddr, &namelen); + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Negotiate Socket: %d\n", ntohs(saddr.sin_port)); + } +#endif + + return ne_noerror; +} + +void NNCancel(int cookie) +{ + NATNegotiator neg = FindNegotiatorForCookie(cookie); + if (neg == NULL) + return; + if (neg->negotiateSock != INVALID_SOCKET) + closesocket(neg->negotiateSock); + neg->negotiateSock = INVALID_SOCKET; + neg->state = ns_canceled; +} + +static void NegotiateThink(NATNegotiator neg) +{ + //check for any incoming data + static char indata[NNINBUF_LEN]; //256 byte input buffer + struct sockaddr_in saddr; + int saddrlen = sizeof(struct sockaddr_in); + int error; + + if(activeNatify) + { + activeNatify = CheckNatifyStatus(mappingSock); + activeNatify = CheckNatifyStatus(ertSock); + } + + if(neg == NULL) + return; + + if (neg->state == ns_canceled) //we need to remove it + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Memory, GSIDebugLevel_Notice, + "Removing canceled negotiator\n"); + RemoveNegotiator(neg); + return; + } + + if (neg->negotiateSock != INVALID_SOCKET) + { + //first, socket processing + while (CanReceiveOnSocket(neg->negotiateSock)) + { + error = recvfrom(neg->negotiateSock, indata, NNINBUF_LEN, 0, (struct sockaddr *)&saddr, &saddrlen); + + if (gsiSocketIsError(error)) + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "RECV SOCKET ERROR: %d\n", GOAGetLastError(neg->negotiateSock)); + break; + } + + NNProcessData(indata, error, &saddr); + if (neg->state == ns_canceled) + break; + + if (neg->negotiateSock == INVALID_SOCKET) + break; + } + } + + if (neg->state == ns_initsent || neg->state == ns_connectping) //see if we need to resend init packets + { + if (current_time() > neg->retryTime) + { + if (neg->retryCount > neg->maxRetryCount) + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "RETRY FAILED...\n"); + if(neg->state == ns_initsent) + StartReport(neg, nr_inittimeout, INVALID_SOCKET, NULL); + else + StartReport(neg, nr_pingtimeout, INVALID_SOCKET, NULL); + } else + { + + neg->retryCount++; + if (neg->state == ns_initsent) //resend init packets + SendInitPackets(neg); + else + SendPingPacket(neg); //resend ping packet + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "[retry]\n"); + } + + } + } + + if (neg->state == ns_finished && current_time() > neg->retryTime) //check if it is ready to be removed + { + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(neg->guessedPort); + saddr.sin_addr.s_addr = neg->guessedIP; + + // now that we've finished processing, send off the report + if (neg->gameSock == INVALID_SOCKET) + StartReport(neg, nr_success, neg->negotiateSock, (struct sockaddr_in *)&saddr); + else + StartReport(neg, nr_success, neg->gameSock, (struct sockaddr_in *)&saddr); + } + + if (neg->state == ns_initack && current_time() > neg->retryTime) //see if the partner has timed out + { + StartReport(neg, nr_deadbeatpartner, INVALID_SOCKET, NULL); + } + + // Have we timed out sending the result report. + if(neg->state == ns_reportsent && current_time() > neg->retryTime) + { + if(neg->retryCount > neg->maxRetryCount) + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "REPORT retry FAILED...\n"); + + neg->completedCallback(neg->result, neg->connectedSocket, (struct sockaddr_in *)&neg->remoteaddr, neg->userdata); + + if (neg->gameSock == INVALID_SOCKET) + neg->negotiateSock = INVALID_SOCKET; //no gameSock, so don't let NNCancel close this socket + + NNCancel(neg->cookie); //mark to-be-canceled + } + else + { + SendReportPacket(neg); //resend report packet + neg->retryCount++; + neg->retryTime = current_time() + REPORT_RETRY_TIME; + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "[retry]\n"); + } + } +} + +void NNThink() +{ + int i; + + if(negotiateList == NULL || ArrayLength(negotiateList) == 0) + { + NegotiateThink(NULL); + return; + } + + for(i = ArrayLength(negotiateList) - 1 ; i >= 0 ; i--) + { + //we go backwards in case we need to remove one.. + NegotiateThink((NATNegotiator)ArrayNth(negotiateList, i)); + } +} + +static void SendConnectAck(NATNegotiator neg, struct sockaddr_in *toaddr) +{ + NatNegPacket p; + + memcpy(p.magic, NNMagicData, NATNEG_MAGIC_LEN); + p.version = NN_PROTVER; + p.packettype = NN_CONNECT_ACK; + p.cookie = (int)htonl((unsigned int)neg->cookie); + p.Packet.Init.clientindex = (unsigned char)neg->clientindex; + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Sending connect ack...\n"); + SendPacket(neg->negotiateSock, toaddr->sin_addr.s_addr, ntohs(toaddr->sin_port), &p, INITPACKET_SIZE); +} + +static void ProcessConnectPacket(NATNegotiator neg, NatNegPacket *p, struct sockaddr_in *fromaddr) +{ + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Got connect packet (finish code: %d), guess: %s:%d\n", p->Packet.Connect.finished, inet_ntoa(*(struct in_addr *)&p->Packet.Connect.remoteIP), ntohs(p->Packet.Connect.remotePort)); + //send an ack.. + if (p->Packet.Connect.finished == FINISHED_NOERROR) //don't need to ack any errors + SendConnectAck(neg, fromaddr); + + + if (neg->state >= ns_connectping) + return; //don't process it any further + + if (p->Packet.Connect.finished != FINISHED_NOERROR) //call the completed callback with the error code + { + NegotiateResult errcode; + errcode = nr_unknownerror; //default if unknown + if (p->Packet.Connect.finished == FINISHED_ERROR_DEADBEAT_PARTNER) + errcode = nr_deadbeatpartner; + else if (p->Packet.Connect.finished == FINISHED_ERROR_INIT_PACKETS_TIMEDOUT) + errcode = nr_inittimeout; + StartReport(neg, errcode, INVALID_SOCKET, NULL); + return; + } + + neg->guessedIP = p->Packet.Connect.remoteIP; + neg->guessedPort = ntohs(p->Packet.Connect.remotePort); + neg->retryCount = 0; + + neg->state = ns_connectping; + neg->progressCallback(neg->state, neg->userdata); + + SendPingPacket(neg); +} + +static void ProcessPingPacket(NATNegotiator neg, NatNegPacket *p, struct sockaddr_in *fromaddr) +{ + if (neg->state < ns_connectping) + return; + + //update our guessed ip and port + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Got ping from: %s:%d (gotmydata: %d, finished: %d)\n", inet_ntoa(fromaddr->sin_addr), ntohs(fromaddr->sin_port), p->Packet.Connect.gotyourdata, p->Packet.Connect.finished); + + neg->guessedIP = fromaddr->sin_addr.s_addr; + neg->guessedPort = ntohs(fromaddr->sin_port); + neg->gotRemoteData = 1; + + if (!p->Packet.Connect.gotyourdata) //send another packet until they have our data + SendPingPacket(neg); + else //they have our data, and we have their data - it's a connection! + { + if (neg->state == ns_connectping) //advance it + { + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "CONNECT FINISHED\n"); + + if(!neg->sendGotRemoteData) + SendPingPacket(neg); + + //we need to leave it around for a while to process any incoming data. + neg->state = ns_finished; + neg->retryTime = current_time() + FINISHED_IDLE_TIME; + + + } else if (!p->Packet.Connect.finished) + SendPingPacket(neg); + } +} + +static void ProcessInitPacket(NATNegotiator neg, NatNegPacket *p, struct sockaddr_in *fromaddr) +{ + switch (p->packettype) + { + case NN_INITACK: + //mark our init as ack'd + if (p->Packet.Init.porttype > NN_PT_NN3) + return; //invalid port + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Got init ack for port %d\n", p->Packet.Init.porttype); + neg->initAckRecv[p->Packet.Init.porttype] = 1; + if (neg->state == ns_initsent) //see if we can advance to negack + { + if (neg->initAckRecv[NN_PT_NN1] != 0 && neg->initAckRecv[NN_PT_NN2] != 0 && neg->initAckRecv[NN_PT_NN3] != 0 && + (neg->gameSock == INVALID_SOCKET || neg->initAckRecv[NN_PT_GP] != 0)) + { + neg->state = ns_initack; + neg->retryTime = current_time() + PARTNER_WAIT_TIME; + neg->progressCallback(neg->state, neg->userdata); + } + } + break; + + case NN_ERTTEST: + //we just send the packet back where it came from.. + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Got ERT\n"); + p->packettype = NN_ERTACK; + SendPacket(neg->negotiateSock, fromaddr->sin_addr.s_addr, ntohs(fromaddr->sin_port), p, INITPACKET_SIZE); + break; + + case NN_REPORT_ACK: + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Got REPORT ACK\n"); + neg->state = ns_reportack; + + neg->completedCallback(neg->result, neg->connectedSocket, (struct sockaddr_in *)&neg->remoteaddr, neg->userdata); + + if (neg->gameSock == INVALID_SOCKET) + neg->negotiateSock = INVALID_SOCKET; //no gameSock, so don't let NNCancel close this socket + + NNCancel(neg->cookie); + break; + } +} + +void NNProcessData(char *data, int len, struct sockaddr_in *fromaddr) +{ + NatNegPacket p; + NATNegotiator neg; + unsigned char ptype; + + if (!CheckMagic(data)) + return; //invalid packet + + ptype = *(unsigned char *)(data + offsetof(NatNegPacket, packettype)); + + gsDebugFormat(GSIDebugCat_NatNeg, GSIDebugType_Network, GSIDebugLevel_Notice, + "Process data, packet type: %d, %d bytes (%s:%d)\n", ptype, len, inet_ntoa(fromaddr->sin_addr), ntohs(fromaddr->sin_port)); + + if (ptype == NN_CONNECT || ptype == NN_CONNECT_PING) + { //it's a connect packet + if (len < CONNECTPACKET_SIZE) + return; + memcpy(&p, data, CONNECTPACKET_SIZE); + neg = FindNegotiatorForCookie((int)ntohl((unsigned int)p.cookie)); + if (neg) + { + if (ptype == NN_CONNECT) + ProcessConnectPacket(neg, &p, fromaddr); + else + ProcessPingPacket(neg, &p, fromaddr); + } + + + } else //it's an init packet + { + if (len < INITPACKET_SIZE) + return; + memcpy(&p, data, INITPACKET_SIZE); + neg = FindNegotiatorForCookie((int)ntohl((unsigned int)p.cookie)); + if (neg) + ProcessInitPacket(neg, &p, fromaddr); + } +} diff --git a/xrGameSpy/gamespy/natneg/natneg.dsw b/xrGameSpy/gamespy/natneg/natneg.dsw new file mode 100644 index 00000000000..2592c8cb339 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/natneg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "simpletest"=.\simpletest\simpletest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/natneg/simpletest", HFUCAAAA + .\simpletest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/natneg", FFUCAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/natneg/natneg.h b/xrGameSpy/gamespy/natneg/natneg.h new file mode 100644 index 00000000000..753f67b15a4 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/natneg.h @@ -0,0 +1,152 @@ + +/****** +GameSpy NAT Negotiation SDK + +Copyright 2002 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy NAT Negotiation SDK documentation for more + information + +******/ + + +#ifndef _NATNEG_H_ +#define _NATNEG_H_ +#include "../common/gsCommon.h" +#include "NATify.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +NAT Negotiation Packet Magic Bytes +These bytes will start each incoming packet that is part of the NAT Negotiation SDK. +If you are sharing a game socket with the SDK, you can use these bytes to determine when to +pass a packet to NNProcessData +*/ +#define NATNEG_MAGIC_LEN 6 +#define NN_MAGIC_0 0xFD +#define NN_MAGIC_1 0xFC +#define NN_MAGIC_2 0x1E +#define NN_MAGIC_3 0x66 +#define NN_MAGIC_4 0x6A +#define NN_MAGIC_5 0xB2 + +// This external array contains all 6 magic bytes - you can use it with memcmp to quickly check incoming packets for the bytes +extern unsigned char NNMagicData[]; + +/* +Possible states for the SDK. The two you will be notified for are: +ns_initack - when the NAT Negotiation server acknowledges your connection request +ns_connectping - when direct negotiation with the other client has started +*/ +typedef enum {ns_initsent, ns_initack, ns_connectping, ns_finished, ns_canceled, ns_reportsent, ns_reportack } NegotiateState; + +/* +Possible reslts of the negotiation. +nr_success: Successful negotiation, other parameters can be used to continue communications with the client +nr_deadbeatpartner: Partner did not register with the NAT Negotiation Server +nr_inittimeout: Unable to communicate with NAT Negotiation Server +nr_unknownerror: NAT Negotiation server indicated an unknown error condition +*/ +typedef enum {nr_success, nr_deadbeatpartner, nr_inittimeout, nr_pingtimeout, nr_unknownerror, nr_noresult } NegotiateResult; + +/* +Possible errors that can be returned when starting a negotiation +ne_noerror: No error +ne_allocerror: Memory allocation failed +ne_socketerror: Socket allocation failed +ne_dnserror: DNS lookup failed +*/ +typedef enum {ne_noerror, ne_allocerror, ne_socketerror, ne_dnserror} NegotiateError; + + +//Callback prototype for your progress function +typedef void (*NegotiateProgressFunc)(NegotiateState state, void *userdata); + +//Callback prototype for your negotiation completed function +typedef void (*NegotiateCompletedFunc)(NegotiateResult result, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata); + +//Callback prototype for your NAT detection results function +typedef void (*NatDetectionResultsFunc)(gsi_bool success, NAT nat); + + +/* +NNBeginNegotiation +------------------- +Starts the negotiation process. +cookie: Shared cookie value that both players will use so that the NAT Negotiation Server can match them up. +clientindex: One client must use clientindex 0, the other must use clientindex 1. +progresscallback: Callback function that will be called as the state changes +completedcallback: Callback function that will be called when negotiation is complete. +userdata: Pointer for your own use that will be passed into the callback functions. +*/ +NegotiateError NNBeginNegotiation(int cookie, int clientindex, NegotiateProgressFunc progresscallback, NegotiateCompletedFunc completedcallback, void *userdata); + + +/* +NNBeginNegotiationWithSocket +------------------- +Starts the negotiation process using the socket provided, which will be shared with the game. +Incoming traffic is not processed automatically - you will need to read the data off the socket and pass NN packets to NNProcessData +*/ +NegotiateError NNBeginNegotiationWithSocket(SOCKET gamesocket, int cookie, int clientindex, NegotiateProgressFunc progresscallback, NegotiateCompletedFunc completedcallback, void *userdata); + + +/* +NNThink +------------------- +Processes any negotiation requests that are in progress +*/ +void NNThink(); + + +/* +NNProcessData +------------------- +When sharing a socket with the NAT Negotiation SDK, you must read incoming data and pass packets that start the the NN magic bytes +to this function for processing, along with the address they came from. +*/ +void NNProcessData(char *data, int len, struct sockaddr_in *fromaddr); + + +/* +NNCancel +------------------- +Cancels a NAT Negotiation request in progress +*/ +void NNCancel(int cookie); + + +/* +NNFreeNegotiateList +------------------- +De-allocates the memory used by for the negotiate list when you are done with NAT Negotiation. +The list will be re-allocated at a later time if you start additional negotiations. +If any negotiations are outstanding this will cancel them. +*/ +void NNFreeNegotiateList(); + + +/* +NNStartNatDetection +------------------- +Detects if there is network address translation going on between the machine and the Internet. +*/ +NegotiateError NNStartNatDetection(NatDetectionResultsFunc resultscallback); + + +//Used for over-riding the default negotiation hostnames. Should not be used normally. +extern char *Matchup2Hostname; +extern char *Matchup1Hostname; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/natneg/natneg_vs2005.sln b/xrGameSpy/gamespy/natneg/natneg_vs2005.sln new file mode 100644 index 00000000000..dcafd7ff9a4 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/natneg_vs2005.sln @@ -0,0 +1,32 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpletest_vs2005", "simpletest\simpletest_vs2005.vcproj", "{1EBD823F-48A1-4D09-9510-0AE2D2630240}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = simpletest\\simpletest_vs2005.vcproj + SccProjectName1 = simpletest + SccLocalPath1 = simpletest + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1EBD823F-48A1-4D09-9510-0AE2D2630240}.Debug|Win32.ActiveCfg = Debug|Win32 + {1EBD823F-48A1-4D09-9510-0AE2D2630240}.Debug|Win32.Build.0 = Debug|Win32 + {1EBD823F-48A1-4D09-9510-0AE2D2630240}.Release|Win32.ActiveCfg = Release|Win32 + {1EBD823F-48A1-4D09-9510-0AE2D2630240}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/natneg/nninternal.h b/xrGameSpy/gamespy/natneg/nninternal.h new file mode 100644 index 00000000000..34e6ca97097 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/nninternal.h @@ -0,0 +1,109 @@ +#ifndef _NNINTERNAL_H_ +#define _NNINTERNAL_H_ + +#include "natneg.h" +#define MATCHUP1_HOSTNAME "natneg1." GSI_DOMAIN_NAME +#define MATCHUP2_HOSTNAME "natneg2." GSI_DOMAIN_NAME +#define MATCHUP3_HOSTNAME "natneg3." GSI_DOMAIN_NAME +#define MATCHUP_PORT1 27901 +#define MATCHUP_PORT2 27901 +#define MATCHUP_PORT3 27901 + +#define FINISHED_NOERROR 0 +#define FINISHED_ERROR_DEADBEAT_PARTNER 1 +#define FINISHED_ERROR_INIT_PACKETS_TIMEDOUT 2 + +#define INIT_RETRY_TIME 500 +#define INIT_RETRY_COUNT 10 +#define NNINBUF_LEN 512 +#define PING_RETRY_TIME 700 +#define PING_RETRY_COUNT 7 +#define FINISHED_IDLE_TIME 5000 +#define PARTNER_WAIT_TIME 60000 +#define REPORT_RETRY_TIME 1000 +#define REPORT_RETRY_COUNT 5 + +#define NN_PROTVER 3 +//#define NN_PROTVER 2 + +#define NN_PT_GP 0 +#define NN_PT_NN1 1 +#define NN_PT_NN2 2 +#define NN_PT_NN3 3 + +#define NN_INIT 0 +#define NN_INITACK 1 +#define NN_ERTTEST 2 +#define NN_ERTACK 3 +#define NN_STATEUPDATE 4 +#define NN_CONNECT 5 +#define NN_CONNECT_ACK 6 +#define NN_CONNECT_PING 7 +#define NN_BACKUP_TEST 8 +#define NN_BACKUP_ACK 9 +#define NN_ADDRESS_CHECK 10 +#define NN_ADDRESS_REPLY 11 +#define NN_NATIFY_REQUEST 12 +#define NN_REPORT 13 +#define NN_REPORT_ACK 14 + +#if !defined(_PS2) && !defined(_NITRO) +#pragma pack(1) +#endif + + +#define INITPACKET_SIZE BASEPACKET_SIZE + 9 +#define INITPACKET_ADDRESS_OFFSET BASEPACKET_SIZE + 3 +typedef struct _InitPacket +{ + unsigned char porttype; + unsigned char clientindex; + unsigned char usegameport; + unsigned int localip; + unsigned short localport; +} InitPacket; + +#define REPORTPACKET_SIZE BASEPACKET_SIZE + 61 +typedef struct _ReportPacket +{ + unsigned char porttype; + unsigned char clientindex; + unsigned char negResult; + NatType natType; + NatMappingScheme natMappingScheme; + char gamename[50]; +} ReportPacket; + +#define CONNECTPACKET_SIZE BASEPACKET_SIZE + 8 +typedef struct _ConnectPacket +{ + unsigned int remoteIP; + unsigned short remotePort; + unsigned char gotyourdata; + unsigned char finished; +} ConnectPacket; + +#define BASEPACKET_SIZE 12 +#define BASEPACKET_TYPE_OFFSET 7 +typedef struct _NatNegPacket { + // Base members: + unsigned char magic[NATNEG_MAGIC_LEN]; + unsigned char version; + unsigned char packettype; + int cookie; + + union + { + InitPacket Init; + ConnectPacket Connect; + ReportPacket Report; + } Packet; + +} NatNegPacket; + + +#if !defined(_PS2) && !defined(_NITRO) +#pragma pack() +#endif + +#endif diff --git a/xrGameSpy/gamespy/natneg/simpletest/natneglinux/Makefile b/xrGameSpy/gamespy/natneg/simpletest/natneglinux/Makefile new file mode 100644 index 00000000000..dcec2807271 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natneglinux/Makefile @@ -0,0 +1,49 @@ +# NAT Negotiation SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=natneg + +CC=gcc +BASE_CFLAGS=-D_LINUX -D_DEBUG -DGSI_COMMON_DEBUG + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../darray.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../natneg.o\ + ../../NATify.o\ + ../simpletest.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegmacosx/Makefile b/xrGameSpy/gamespy/natneg/simpletest/natnegmacosx/Makefile new file mode 100644 index 00000000000..c8ddce8b67d --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegmacosx/Makefile @@ -0,0 +1,25 @@ +# NAT Negotiation SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=simpletest + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../natneg.o\ + ../../NATify.o\ + ../simpletest.o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/Nitro.lcf b/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/natnegnitrocw.mcp b/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/natnegnitrocw.mcp new file mode 100644 index 00000000000..998ca1aea4a Binary files /dev/null and b/xrGameSpy/gamespy/natneg/simpletest/natnegnitrocw/natnegnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps2/Makefile b/xrGameSpy/gamespy/natneg/simpletest/natnegps2/Makefile new file mode 100644 index 00000000000..bd9f5e5074b --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps2/Makefile @@ -0,0 +1,25 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = simpletest + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o\ + ../../../darray.o\ + ../../../available.o\ + ../../../stringutil.o\ + ../../natneg.o\ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps2cw/natnegps2cw.mcp b/xrGameSpy/gamespy/natneg/simpletest/natnegps2cw/natnegps2cw.mcp new file mode 100644 index 00000000000..846a06383e7 Binary files /dev/null and b/xrGameSpy/gamespy/natneg/simpletest/natnegps2cw/natnegps2cw.mcp differ diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.dsp b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.dsp new file mode 100644 index 00000000000..486a0057f49 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.dsp @@ -0,0 +1,328 @@ +# Microsoft Developer Studio Project File - Name="natnegps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=natnegps2prodg - Win32 Debug_Insock +!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 "natnegps2prodg.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 "natnegps2prodg.mak" CFG="natnegps2prodg - Win32 Debug_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "natnegps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "natnegps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "natnegps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "natnegps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "natnegps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "natnegps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/natneg/simpletest/natnegps2prodg", HTEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "natnegps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /D "GSI_COMMON_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\natnegps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\natnegps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "natnegps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "natnegps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "natnegps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "INSOCK" /D "SN_TARGET_PS2" /D "_DEBUG" /D "GSI_COMMON_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\natnegps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\natnegps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "natnegps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /D "GSI_COMMON_DEBUG" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\natnegps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\natnegps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "natnegps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\natnegps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\natnegps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "natnegps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "natnegps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "natnegps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\natnegps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\natnegps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "natnegps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\natnegps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\natnegps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "natnegps2prodg - Win32 Debug_EENet" +# Name "natnegps2prodg - Win32 Debug_Insock" +# Name "natnegps2prodg - Win32 Debug_SNSystems" +# Name "natnegps2prodg - Win32 Release_EENet" +# Name "natnegps2prodg - Win32 Release_Insock" +# Name "natnegps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# Begin Source File + +SOURCE=..\simpletest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\nninternal.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.dsw b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.dsw new file mode 100644 index 00000000000..9fc56b944c9 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "natnegps2prodg"=.\natnegps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/natneg/simpletest/natnegps2prodg", HTEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/gamespy/goa/natneg/simpletest/natnegps2prodg", HTEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.sln b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.sln new file mode 100644 index 00000000000..79dad182042 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "natnegps2prodg", "natnegps2prodg.vcproj", "{2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 1 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = natnegps2prodg.vcproj + SccProjectName0 = . + SccAuxPath0 = http://tfsapp1:8080 + SccLocalPath0 = . + SccProvider0 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {2F1BE9D3-4A4E-43D6-AEBA-6B9FDABBA933}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.vcproj b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.vcproj new file mode 100644 index 00000000000..2c9b3013b3f --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps2prodg/natnegps2prodg.vcproj @@ -0,0 +1,645 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps3/Makefile b/xrGameSpy/gamespy/natneg/simpletest/natnegps3/Makefile new file mode 100644 index 00000000000..b57103ed9d6 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps3/Makefile @@ -0,0 +1,28 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = simpletest + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o \ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsDebug.o \ + ../../../common/gsAvailable.o \ + ../../../common/gsStringUtil.o \ + ../../../darray.o\ + ../../natneg.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps3prodg/natnegps3prodg.sln b/xrGameSpy/gamespy/natneg/simpletest/natnegps3prodg/natnegps3prodg.sln new file mode 100644 index 00000000000..9d055fca838 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps3prodg/natnegps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "natnegps3prodg", "natnegps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = natnegps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegps3prodg/natnegps3prodg.vcproj b/xrGameSpy/gamespy/natneg/simpletest/natnegps3prodg/natnegps3prodg.vcproj new file mode 100644 index 00000000000..875f37271d2 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegps3prodg/natnegps3prodg.vcproj @@ -0,0 +1,359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegpsp/Makefile b/xrGameSpy/gamespy/natneg/simpletest/natnegpsp/Makefile new file mode 100644 index 00000000000..72467112566 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegpsp/Makefile @@ -0,0 +1,29 @@ +#GameSpy.net PSP Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +#SDK_LIBS = + +#Name of the SDK sample +TARGET = simpletest + +#All the object files needed for this SDK +OBJS = ../../../common/psp/pspcommon.o\ + ../../../common/psp/gsUtilPSP.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsDebug.o\ + ../../../common/gsAvailable.o\ + ../../../darray.o\ + ../../natneg.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/psp/Makefile.common + diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegpspprodg/natnegpspprodg.sln b/xrGameSpy/gamespy/natneg/simpletest/natnegpspprodg/natnegpspprodg.sln new file mode 100644 index 00000000000..776c8271649 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegpspprodg/natnegpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "natnegpspprodg", "natnegpspprodg.vcproj", "{57A7DA8D-5BFF-48FA-811A-80435C611CE3}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = natnegpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {57A7DA8D-5BFF-48FA-811A-80435C611CE3}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {57A7DA8D-5BFF-48FA-811A-80435C611CE3}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {57A7DA8D-5BFF-48FA-811A-80435C611CE3}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {57A7DA8D-5BFF-48FA-811A-80435C611CE3}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {57A7DA8D-5BFF-48FA-811A-80435C611CE3}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {57A7DA8D-5BFF-48FA-811A-80435C611CE3}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegpspprodg/natnegpspprodg.vcproj b/xrGameSpy/gamespy/natneg/simpletest/natnegpspprodg/natnegpspprodg.vcproj new file mode 100644 index 00000000000..c869e4acdb1 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/natnegpspprodg/natnegpspprodg.vcproj @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/natneg/simpletest/natnegrevolutioncw/natnegrevolutioncw.mcp b/xrGameSpy/gamespy/natneg/simpletest/natnegrevolutioncw/natnegrevolutioncw.mcp new file mode 100644 index 00000000000..4f76b3f4438 Binary files /dev/null and b/xrGameSpy/gamespy/natneg/simpletest/natnegrevolutioncw/natnegrevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/natneg/simpletest/simpletest.c b/xrGameSpy/gamespy/natneg/simpletest/simpletest.c new file mode 100644 index 00000000000..cb285fc350d --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/simpletest.c @@ -0,0 +1,308 @@ + + +#include "../natneg.h" +#include "../../common/gsAvailable.h" + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +int connected = 0; +struct sockaddr_in otheraddr; +SOCKET sock = INVALID_SOCKET; +unsigned int ESTRING_SIZE = 128; +char *aString = NULL; +#define USE_OWN_SOCK +#define DETECT_NAT + +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); + } +#endif + +static void tryread(SOCKET s) +{ + char buf[256]; + int len; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + while (CanReceiveOnSocket(s)) + { + len = recvfrom(s, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&saddr, &saddrlen); + + if (len < 0) + { + len = GOAGetLastError(s); + printf("|Got recv error: %d\n", len); + break; + } + buf[len] = 0; + if (memcmp(buf, NNMagicData, NATNEG_MAGIC_LEN) == 0) + { + NNProcessData(buf, len, &saddr); + } else + printf("|Got data (%s:%d): %s\n", inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port), buf); + } +} + +static void pc(NegotiateState state, void *userdata) +{ + if (aString != NULL) + { + // Print any status updates to the console + int charsWritten; + + memset(aString, 0, ESTRING_SIZE); + charsWritten = sprintf(aString, "Got State Update: "); + switch(state) + { + case ns_initack: + sprintf(aString + charsWritten, "ns_initack, Init Packets Acknowledged.\n"); + break; + case ns_connectping: + sprintf(aString + charsWritten, "ns_connectping, Starting connection and pinging other machine.\n"); + break; + default: + break; + } + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + aString); + } + + GSI_UNUSED(userdata); +} + +static void cc(NegotiateResult result, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata) +{ + struct sockaddr_in saddr; + int namelen = sizeof(saddr); + if (gamesocket != INVALID_SOCKET) + { + getsockname(gamesocket, (struct sockaddr *)&saddr, &namelen); + + printf("|Local game socket: %d\n", ntohs(saddr.sin_port)); + } + + if (result != nr_success) + { + if (aString == NULL) + return; + memset(aString, 0, ESTRING_SIZE); + switch(result) + { + case nr_deadbeatpartner: + sprintf(aString, "Result: nr_deadbeatpartner, The other machine isn't responding.\n"); + break; + case nr_inittimeout: + sprintf(aString, "Result: nr_inittimeout, The NAT server could not be contacted.\n"); + break; + case nr_pingtimeout: + sprintf(aString, "Result: nr_pingtimeout, The other machine could not be contacted.\n"); + break; + default: + break; + } + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, aString); + return; + } + + printf("|Got connected, remoteaddr: %s, remoteport: %d\n", (remoteaddr == NULL) ? "" : inet_ntoa(remoteaddr->sin_addr), (remoteaddr == NULL) ? 0 : ntohs(remoteaddr->sin_port)); + if (result == nr_success) + { + connected = 1; + memcpy(&otheraddr, remoteaddr, sizeof(otheraddr)); + sock = gamesocket; + } + + GSI_UNUSED(userdata); +} + +static void nr(gsi_bool success, NAT nat) +{ + int charsWritten; + + if(success == gsi_false) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "Failed to fully detect the NAT. Please try the detection again.\n"); + return; + } + + if(aString == NULL) + return; + + memset(aString, 0, ESTRING_SIZE); + charsWritten = sprintf(aString, "The detected NAT is a "); + switch(nat.natType) + { + case no_nat: + charsWritten = sprintf(aString, "No NAT detected."); + break; + case firewall_only: + charsWritten = sprintf(aString, "No NAT detected, but firewall may be present."); + break; + case full_cone: + charsWritten += sprintf(aString + charsWritten, "full cone "); + break; + case restricted_cone: + charsWritten += sprintf(aString + charsWritten, "restricted cone "); + break; + case port_restricted_cone: + charsWritten += sprintf(aString + charsWritten, "port restricted cone "); + break; + case symmetric: + charsWritten += sprintf(aString + charsWritten, "symmetric "); + break; + case unknown: + default: + charsWritten = sprintf(aString, "Unknown NAT type detected "); + break; + } + + if(nat.natType != no_nat && nat.natType != firewall_only) + switch(nat.mappingScheme) + { + case private_as_public: + charsWritten += sprintf(aString + charsWritten, "and is using the private port as the public port."); + break; + case consistent_port: + charsWritten += sprintf(aString + charsWritten, "and is using the same public port for all requests from the same private port."); + break; + case incremental: + charsWritten += sprintf(aString + charsWritten, "and is using an incremental port mapping scheme."); + break; + case mixed: + charsWritten += sprintf(aString + charsWritten, "and is using a mixed port mapping scheme."); + break; + case unrecognized: + default: + charsWritten += sprintf(aString + charsWritten, "and is using an unrecognized port mapping scheme."); + break; + } + + charsWritten += sprintf(aString + charsWritten, "\n"); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, aString); +} + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped + int test_main(int argc, char **argp); +#endif +int test_main(int argc, char **argp) +{ + unsigned long lastsendtime = 0; + GSIACResult result; + gsi_time startTime; + NegotiateError error; + +#ifdef GSI_COMMON_DEBUG + // Define GSI_COMMON_DEBUG if you want to view the SDK debug output + // Set the SDK debug log file, or set your own handler using gsSetDebugCallback + //gsSetDebugFile(stdout); // output to console + gsSetDebugCallback(DebugCallback); + + // Set debug levels + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); +#endif + +#ifdef GSI_MEM_MANAGED // use gsi mem managed + { + #define MEMPOOL_SIZE (8* 1024*1024) + PRE_ALIGN(16) static char _mempool[MEMPOOL_SIZE] POST_ALIGN(16); + gsMemMgrCreate (gsMemMgrContext_Default, "default", + _mempool, MEMPOOL_SIZE); + } +#endif + + aString = (char *)gsimalloc(ESTRING_SIZE); + // check that the game's backend is available + GSIStartAvailableCheck("gmtest"); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + printf("The backend is not available\n"); + return 1; + } + +#ifdef DETECT_NAT + error = NNStartNatDetection(nr); +#endif + +#ifdef USE_OWN_SOCK + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + error = NNBeginNegotiationWithSocket(sock, 666, (argc == 1) ? 0 : 1, pc, cc, NULL); +#else + error = NNBeginNegotiation(666, (argc == 1) ? 0 : 1, pc, cc, NULL); +#endif + + if(error != ne_noerror) + { + int charsWritten; + memset(aString, 0, ESTRING_SIZE); + charsWritten = sprintf(aString, "Error beginning negotiation: "); + switch(error) + { + case ne_allocerror: + sprintf(aString + charsWritten, "memory allocation failed.\n"); + break; + case ne_dnserror: + sprintf(aString + charsWritten, "DNS lookup failed.\n"); + break; + case ne_socketerror: + sprintf(aString + charsWritten, "socket failed to be created.\n"); + break; + default: + break; + } + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, aString); + gsifree(aString); + return 1; + } + + startTime = current_time(); + while ((current_time() - startTime) < 60000) + { + NNThink(); + if (connected) + { + if (current_time() - lastsendtime > 2000) + { + int ret = sendto(sock, "woohoo!!", 8, 0, (struct sockaddr *)&otheraddr, sizeof(struct sockaddr_in)); + int error = GOAGetLastError(sock); + printf("|Sending (%d:%d), remoteaddr: %s, remoteport: %d\n", ret, error, inet_ntoa(otheraddr.sin_addr), ntohs(otheraddr.sin_port)); + lastsendtime = current_time(); + } + } + if (sock != INVALID_SOCKET) + tryread(sock); + msleep(10); + } + if (sock != INVALID_SOCKET) + closesocket(sock); + + sock = INVALID_SOCKET; + SocketShutDown(); + NNFreeNegotiateList(); + gsifree(aString); + + GSI_UNUSED(argp); + return 0; +} diff --git a/xrGameSpy/gamespy/natneg/simpletest/simpletest.dsp b/xrGameSpy/gamespy/natneg/simpletest/simpletest.dsp new file mode 100644 index 00000000000..ead15019549 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/simpletest.dsp @@ -0,0 +1,211 @@ +# Microsoft Developer Studio Project File - Name="simpletest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=simpletest - 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 "simpletest.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 "simpletest.mak" CFG="simpletest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "simpletest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "simpletest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/natneg/simpletest", HFUCAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "simpletest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "simpletest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "simpletest - Win32 Release" +# Name "simpletest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\simpletest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/natneg/simpletest/simpletest_vs2005.vcproj b/xrGameSpy/gamespy/natneg/simpletest/simpletest_vs2005.vcproj new file mode 100644 index 00000000000..5a18c2b175f --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/simpletest_vs2005.vcproj @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/natneg/simpletest/simpletest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/natneg/simpletest/simpletest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/natneg/simpletest/simpletest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/nonport.c b/xrGameSpy/gamespy/nonport.c new file mode 100644 index 00000000000..54b0a96c6d9 --- /dev/null +++ b/xrGameSpy/gamespy/nonport.c @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Deprecated. Stubbed here for backwards compatability + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "common/gsPlatform.c" +#include "common/gsPlatformSocket.c" +#include "common/gsPlatformThread.c" +#include "common/gsPlatformUtil.c" +#include "common/gsDebug.c" +#include "common/gsAssert.c" +#include "common/gsMemory.c" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/xrGameSpy/gamespy/nonport.h b/xrGameSpy/gamespy/nonport.h new file mode 100644 index 00000000000..36b6fcb37bd --- /dev/null +++ b/xrGameSpy/gamespy/nonport.h @@ -0,0 +1,17 @@ +/****** +nonport.h +GameSpy Common Code + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +******/ + +#ifndef _NONPORT_H_ +#define _NONPORT_H_ + + +#include "common/gsCommon.h" + + +#endif diff --git a/xrGameSpy/gamespy/pinger/pingTest/pingTest.c b/xrGameSpy/gamespy/pinger/pingTest/pingTest.c new file mode 100644 index 00000000000..c457e232570 --- /dev/null +++ b/xrGameSpy/gamespy/pinger/pingTest/pingTest.c @@ -0,0 +1,137 @@ +#include +#include +#include + +#define PINGER_UDP_PING_SIZE 64 +#include "../pinger.h" + +void pinged(unsigned int IP, + unsigned short port, + int ping, + const char * data, + int len, + void * param) +{ + IN_ADDR addr; + addr.S_un.S_addr = IP; + + printf("PINGED!\n" + "%s:%d %dms", inet_ntoa(addr), ntohs(port), ping); + + if(data) + printf(" (%s)\n", data); + else + printf("\n"); +} + +void reply(unsigned int IP, + unsigned short port, + int ping, + const char * data, + int len, + void * param) +{ + IN_ADDR addr; + addr.S_un.S_addr = IP; + + printf("REPLY!\n" + "%s:%d %dms", inet_ntoa(addr), ntohs(port), ping); + + if(data) + printf(" (%s)\n", data); + else + printf("\n"); +} + +void setData(unsigned int IP, unsigned short port, char * data, int len, void * param) +{ + char buffer[32]; + sprintf(buffer, "my pid is %d", _getpid()); + assert((strlen(buffer) + 1) <= (unsigned)len); + strcpy(data, buffer); +} + +int CheckKeyHit(void) +{ + // Check for a key press. + ///////////////////////// + if(_kbhit()) + { + // What char was pressed? + ///////////////////////// + return getch(); + } + + return -1; +} + +int main(int argc, char * argv[]) +{ + int c; + u_short localPort = htons(2222); + u_short remotePort = htons(2222); + unsigned int remoteIP; + char * remoteAddress; + + assert(argc == 2); + remoteAddress = argv[1]; + + if(remoteAddress != NULL) + { + // Check for "a.b.c.d". + /////////////////////// + remoteIP = inet_addr(remoteAddress); + if(remoteIP == INADDR_NONE) + { + HOSTENT * hostent; + + // Check for "machine.host.domain". + /////////////////////////////////// + hostent = gethostbyname(remoteAddress); + if(hostent == NULL) + { + assert(0); + return 0; + } + + // Grab the IP. + /////////////// + assert(remoteIP != 0); + remoteIP = *(unsigned int *)hostent->h_addr_list[0]; + } + } + else + { + // Any IP. + ////////// + remoteIP = INADDR_ANY; + } + + pingerInit(NULL, localPort, pinged, NULL, setData, NULL); + + do + { + c = CheckKeyHit(); + if(c != -1) + { + if(c == 'p') + { + pingerPing(remoteIP, remotePort, reply, NULL, PINGERFalse, 1000); + } + else if(c == 'q') + { + break; + } + } + + pingerThink(); + + Sleep(1); + } + while(c != 'q'); + + pingerShutdown(); + + return 0; +} + diff --git a/xrGameSpy/gamespy/pinger/pingTest/pingTest.dsp b/xrGameSpy/gamespy/pinger/pingTest/pingTest.dsp new file mode 100644 index 00000000000..54ad2af1d00 --- /dev/null +++ b/xrGameSpy/gamespy/pinger/pingTest/pingTest.dsp @@ -0,0 +1,190 @@ +# Microsoft Developer Studio Project File - Name="pingTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pingTest - 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 "pingTest.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 "pingTest.mak" CFG="pingTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pingTest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "pingTest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/pinger/pingTest", VYNAAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "pingTest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 wsock32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "pingTest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "pingTest - Win32 Release" +# Name "pingTest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\pingTest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "pinger" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\pinger.h +# End Source File +# Begin Source File + +SOURCE=..\pingerMain.c +# End Source File +# End Group +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/pinger/pinger.dsp b/xrGameSpy/gamespy/pinger/pinger.dsp new file mode 100644 index 00000000000..48206158583 --- /dev/null +++ b/xrGameSpy/gamespy/pinger/pinger.dsp @@ -0,0 +1,156 @@ +# Microsoft Developer Studio Project File - Name="pinger" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=pinger - 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 "pinger.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 "pinger.mak" CFG="pinger - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pinger - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "pinger - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/Formation/MrPants/pinger", ZXNAAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "pinger - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "pinger - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "pinger - Win32 Release" +# Name "pinger - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\pingerMain.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\pinger.h +# End Source File +# End Group +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/pinger/pinger.dsw b/xrGameSpy/gamespy/pinger/pinger.dsw new file mode 100644 index 00000000000..0555342abbc --- /dev/null +++ b/xrGameSpy/gamespy/pinger/pinger.dsw @@ -0,0 +1,53 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pingTest"=.\pingTest\pingTest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pinger/pingTest", VYNAAAAA + .\pingTest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "pinger"=.\pinger.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pinger", ZXNAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pinger", ZXNAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/pinger/pinger.h b/xrGameSpy/gamespy/pinger/pinger.h new file mode 100644 index 00000000000..a87c44f90e9 --- /dev/null +++ b/xrGameSpy/gamespy/pinger/pinger.h @@ -0,0 +1,117 @@ +/* +GameSpy Ping SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +#ifndef _PINGER_H_ +#define _PINGER_H_ + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************ +** DEFINES ** +************/ +// This controls the size of UDP pings. +// The protocol takes up 8 of these bytes. +// The rest can be used by the app. +////////////////////////////////////////// +#ifndef PINGER_UDP_PING_SIZE +#define PINGER_UDP_PING_SIZE 32 +#endif + +// Value for ping if a ping timed-out. +////////////////////////////////////// +#define PINGER_TIMEOUT -1 + +/********** +** TYPES ** +**********/ +typedef enum { PINGERFalse, PINGERTrue } PINGERBool; + +/************** +** CALLBACKS ** +**************/ +// A function of this type is used as: +// a param to pingerInit, gets called when an uninitiated UDP ping is received +// a param to pingerPing, gets called when the ping is completed, or times out +// if the ping times out, ping is PINGER_TIMEOUT +// IP and port are in network byte order +////////////////////////////////////////////////////////////////////////////// +typedef void (* pingerGotPing)(unsigned int IP, + unsigned short port, + int ping, + const char * data, + int len, + void * param); + +// When a ping is sent, this callback gets called so that +// the application can use the ping bytes not being used +// by the protocol. +// The application can write up to len bytes to data. +// IP and port are in network byte order. +///////////////////////////////////////////////////////// +typedef void (* pingerSetData)(unsigned int IP, + unsigned short port, + char * data, + int len, + void * param); + +/************** +** FUNCTIONS ** +**************/ + +// Called once to initialize the pinger library. +// localPort is in host byte order +// localAddress=NULL : don't specify a local interface +// localPort=0 : not doing UDP pings +////////////////////////////////////////////////////// +PINGERBool pingerInit(const char * localAddress, + unsigned short localPort, + pingerGotPing pinged, + void * pingedParam, + pingerSetData setData, + void * setDataParam); + +// Called to clean-up when done with pinger. +//////////////////////////////////////////// +void pingerShutdown(void); + +// Called to do processing. +// The more frequently this function is called, +// the more accurate the pings will be. +// +// Example: if this func is called once every 20ms, and a ping +// is returned as 100ms, then the ping is in the range 90-110. +////////////////////////////////////////////////////////////// +void pingerThink(void); + +// Does a ping. If blocking, does not return until the ping is completed. +// timeout specifes how long (in milliseconds) to wait for the ping reply. +// A value of 0 means wait forever. Note, this is dangerous because pings +// are not reliable. A blocking ping with a 0 timeout will never return if +// the ping is lost. +// port=0 : ICMP ping (this is NOT currently supported) +// port!=0 : UDP ping +// IP and port are in network byte order +////////////////////////////////////////////////////////////////////////// +void pingerPing(unsigned int IP, + unsigned short port, + pingerGotPing reply, + void * replyParam, + PINGERBool blocking, + gsi_time timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/pinger/pingerMain.c b/xrGameSpy/gamespy/pinger/pingerMain.c new file mode 100644 index 00000000000..d6b8297e35c --- /dev/null +++ b/xrGameSpy/gamespy/pinger/pingerMain.c @@ -0,0 +1,1003 @@ +/* +GameSpy Ping SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com +*/ + +/**************** +** DEFINITIONS ** +***************** + +UPP = UDP Ping Protocol + +*/ + +/************* +** INCLUDES ** +*************/ +#include +#include "pinger.h" +#include "../darray.h" + +/************ +** DEFINES ** +************/ +#define PI_MAGIC 0x91 +#define PI_VERSION 0x01 + +#define PI_TRIP2_TIMEOUT 10000 + +#define PI_DATA_MAX_LEN (PINGER_UDP_PING_SIZE - sizeof(piUDPPing)) + +/********** +** TYPES ** +**********/ +// u_char must be 1 byte unsigned, and unsigned short must be 2 bytes unsigned. +//////////////////////////////////////////////////////////////////////// +typedef unsigned char uint8; +typedef unsigned short uint16; + +// This is the internal data for a UDP ping. +// This is an exact copy of what gets sent over the network, minus filler bytes. +//////////////////////////////////////////////////////////////////////////////// +typedef struct piUDPPing +{ + uint8 magic; // magic number - helps to ignore bad packets + uint8 version; // version - UPP version + uint16 trip; // trip number - will always be 1, 2, or 3 + uint16 ID_A; // this ID is used by A (the source for the first dgram) + uint16 ID_B; // this ID is used by B (the destination for the first dgram) +} piUDPPing; + +// This is a ping on which we're waiting for a reply. +///////////////////////////////////////////////////// +typedef struct piActivePing +{ + PINGERBool originator; // true if we sent the first dgram + uint16 ID; // unique ID for this ping + uint16 expectedTrip; // expected trip # of the reply + gsi_time timestamp; // time we sent the ping + gsi_time timeout; // time this ping expires + unsigned int remoteIP; // IP of the other end of this ping + unsigned short remotePort; // port of the other end of this ping + pingerGotPing reply; // call this callback if we're the originator (otherwise call pingerPinged) + void * replyParam; // the extra param passed to reply +} piActivePing; + +// This is a queued gotPing callback. +///////////////////////////////////// +typedef struct piQueuedCallback +{ + unsigned int IP; + unsigned short port; + int ping; + char * data; + int len; + void * param; + pingerGotPing callback; +} piQueuedCallback; + +/************ +** GLOBALS ** +************/ +static PINGERBool piInitialized = PINGERFalse; +static SOCKET piSocket = INVALID_SOCKET; +static pingerGotPing piPingerPinged; +static void * piPingerPingedParam; +static pingerSetData piPingerSetData; +static void * piPingerSetDataParam; +static PINGERBool piSettingData; +static PINGERBool piUDPEnabled; +static uint16 piNextID; +static DArray piActivePingList; +static gsi_time piLastThinkTime; +static DArray piCallbacks; + +/************** +** FUNCTIONS ** +**************/ +static uint16 piGetNextID(void) +{ + // Store the next ID. + ///////////////////// + uint16 ID = piNextID; + + // Increment the ID. + //////////////////// + if(piNextID == USHRT_MAX) + piNextID = 1; + else + piNextID++; + + return ID; +} + +static PINGERBool piBytesToPing(unsigned char * buffer, piUDPPing * udpPing, char * data) +{ + assert(buffer != NULL); + assert(udpPing != NULL); + assert(data != NULL); + + // Magic. + udpPing->magic = *buffer++; + + // Version. + udpPing->version = *buffer++; + + // Trip. + udpPing->trip = (unsigned short)(*buffer++ << 8); + udpPing->trip |= *buffer++; + + // ID_A. + udpPing->ID_A = (unsigned short)(*buffer++ << 8); + udpPing->ID_A |= *buffer++; + + // ID_B. + udpPing->ID_B = (unsigned short)(*buffer++ << 8); + udpPing->ID_B |= *buffer++; + + // Check for the magic number. + // This asserted on 11/17/00 at aprox. 1:40PM. + // on a ping from 205.251.192.203:13139. + // There were 2 empty bytes at the start of + // the buffer, then the normal message followed. + // Same thing on 12/14/00 at approx. 5PM. + // From 24.156.198.26 + // JED 12/18/00 15:20, again from 24.156.198.26 + // 2001.Jan.15.JED - again from 24.156.198.26 + // 2001.Jan.23.JED - 213.65.117.53 (@11:15am) + // 2001.Mar.26.JED - 24.159.107.0 (@7:30pm) + // PANTS|04.20.00 - commented out per JED's request. + //////////////////////////////////////////////////// + //assert(udpPing->magic == PI_MAGIC); + if(udpPing->magic != PI_MAGIC) + return PINGERFalse; + + // Check the version. + ///////////////////// + assert(udpPing->version == PI_VERSION); + if(udpPing->version != PI_VERSION) + return PINGERFalse; + + // Check the trip. + ////////////////// + assert((udpPing->trip >= 1) && (udpPing->trip <= 3)); + if((udpPing->trip < 1) || (udpPing->trip > 3)) + return PINGERFalse; + + // Fill in the data. + //////////////////// + memcpy(data, buffer, PI_DATA_MAX_LEN); + + return PINGERTrue; +} + +static void piPingToBytes(piUDPPing * udpPing, unsigned char * buffer) +{ + assert(udpPing != NULL); + assert(buffer != NULL); + + // Magic. + *buffer++ = udpPing->magic; + + // Version. + *buffer++ = udpPing->version; + + // Trip. + *buffer++ = (unsigned char)((udpPing->trip & 0xFF00) >> 8); + *buffer++ = (unsigned char)(udpPing->trip & 0x00FF); + + // ID_A. + *buffer++ = (unsigned char)((udpPing->ID_A & 0xFF00) >> 8); + *buffer++ = (unsigned char)(udpPing->ID_A & 0x00FF); + + // ID_B. + *buffer++ = (unsigned char)((udpPing->ID_B & 0xFF00) >> 8); + *buffer++ = (unsigned char)(udpPing->ID_B & 0x00FF); +} + +static PINGERBool piSendPing(SOCKADDR_IN * to, uint16 trip, uint16 ID_A, uint16 ID_B, const char * data) +{ + unsigned char buffer[PINGER_UDP_PING_SIZE]; + piUDPPing udpPing; + int rcode; + + assert(to != NULL); + assert((trip >= 1) && (trip <= 3)); + assert(!((trip == 2) && (ID_A == 0))); + + // Construct the outgoing ping. + /////////////////////////////// + udpPing.magic = PI_MAGIC; + udpPing.version = PI_VERSION; + udpPing.trip = trip; + udpPing.ID_A = ID_A; + udpPing.ID_B = ID_B; + piPingToBytes(&udpPing, buffer); + if(data != NULL) + memcpy(buffer + sizeof(piUDPPing), data, PI_DATA_MAX_LEN); + else + memset(buffer + sizeof(piUDPPing), 0, PI_DATA_MAX_LEN); + + // Send the outgoing ping. + ////////////////////////// + rcode = sendto(piSocket, (char *)buffer, PINGER_UDP_PING_SIZE, 0, (SOCKADDR *)to, sizeof(SOCKADDR_IN)); + // Did it send ok? + ////////////////// + if(rcode != PINGER_UDP_PING_SIZE) + return PINGERFalse; + + return PINGERTrue; +} + +static PINGERBool piSocketInit(const char * localAddress, + unsigned short localPort) +{ + int rcode; + SOCKADDR_IN sockaddr; + int bFlag; + //int iLastError; + + assert(localPort != 0); + + // Setup sockets. + ///////////////// + SocketStartUp(); + + // Setup the address. + ///////////////////// + memset(&sockaddr, 0, sizeof(SOCKADDR_IN)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(localPort); + if(localAddress != NULL) + { + unsigned int IP; + + // Check for "a.b.c.d". + /////////////////////// + IP = inet_addr(localAddress); + if(IP == INADDR_NONE) + { + HOSTENT * hostent; + + // Check for "machine.host.domain". + /////////////////////////////////// + hostent = gethostbyname(localAddress); + if(hostent == NULL) + { +// iLastError = WSAGetLastError(); + assert(0); + return PINGERFalse; + } + + // Grab the IP. + /////////////// + assert(IP != 0); + IP = *(unsigned int *)hostent->h_addr_list[0]; + } + + // Got the IP. + ////////////// + sockaddr.sin_addr.s_addr = IP; + } + else + { + // Any local IP. + //////////////// + sockaddr.sin_addr.s_addr = INADDR_ANY; + } + + // Create the socket. + ///////////////////// + piSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(piSocket == INVALID_SOCKET) + { +// iLastError = GOAGetLastError(piSocket); + assert(0); + return PINGERFalse; + } + + // Allow reuse of the socket if not closed properly before. + /////////////////////////////////////////////////////////// + bFlag = 1; +#ifndef INSOCK // PS2 INSOCK network layer does not support reuse addr + rcode = setsockopt(piSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&bFlag, sizeof(bFlag) ); +#endif + /*if(gsiSocketIsError(rcode)) + { + iLastError = WSAGetLastError(); + assert(0); + return PINGERFalse; + }*/ + + // Bind the socket. + /////////////////// + rcode = bind(piSocket, (SOCKADDR *)&sockaddr, sizeof(SOCKADDR_IN)); + if (gsiSocketIsError(rcode)) + { +// iLastError = GOAGetLastError(piSocket); + assert(0); + return PINGERFalse; + } + + return PINGERTrue; +} + +static void piQueueCallback +( + unsigned int IP, + unsigned short port, + int ping, + const char * data, + int len, + void * param, + pingerGotPing callbackFunc +) +{ + piQueuedCallback callback; + + assert(callbackFunc); + if(!callbackFunc) + return; + + // Setup the callback. + ////////////////////// + callback.IP = IP; + callback.port = port; + callback.ping = ping; + callback.len = len; + callback.param = param; + callback.callback = callbackFunc; + + // Copy the data. + ///////////////// + if(data) + { + callback.data = (char *)gsimalloc((unsigned int)len); + if(!callback.data) + return; + memcpy(callback.data, data, (unsigned int)len); + } + else + { + callback.data = NULL; + } + + // Add it. + ////////// + ArrayAppend(piCallbacks, &callback); +} + +static void piCallCallbacks(void) +{ + piQueuedCallback * callback; + piQueuedCallback callbackCopy; + + while(ArrayLength(piCallbacks) > 0) + { + // Get the info. + //////////////// + callback = (piQueuedCallback *)ArrayNth(piCallbacks, 0); + assert(callback); + if(!callback) + return; + + // Copy the info. + ///////////////// + memcpy(&callbackCopy, callback, sizeof(piQueuedCallback)); + callback = &callbackCopy; + + // Remove it from the list. + /////////////////////////// + ArrayDeleteAt(piCallbacks, 0); + + // Call it. + /////////// + callback->callback(callback->IP, callback->port, callback->ping, callback->data, callback->len, callback->param); + + // gsifree it. + /////////// + gsifree(callback->data); + } +} + +PINGERBool pingerInit(const char * localAddress, + unsigned short localPort, + pingerGotPing pinged, + void * pingedParam, + pingerSetData setData, + void * setDataParam) +{ + // Check if we're already initialized. + ////////////////////////////////////// + assert(!piInitialized); + + // Make sure the UDP ping size is at least as large as the protocol struct. + /////////////////////////////////////////////////////////////////////////// +#if !defined(_NITRO) + assert(PINGER_UDP_PING_SIZE >= sizeof(piUDPPing)); +#endif + + // Check if we're already intialized. + ///////////////////////////////////// + if(piInitialized) + return PINGERFalse; + + // An empty localAddress is them same as a NULL. + //////////////////////////////////////////////// + if((localAddress != NULL) && (localAddress[0] == '\0')) + localAddress = NULL; + + // Initialize data. + /////////////////// + piPingerPinged = pinged; + piPingerPingedParam = pingedParam; + piPingerSetData = setData; + piPingerSetDataParam = setDataParam; + piSettingData = PINGERFalse; + piUDPEnabled = (PINGERBool)(localPort != 0); + piNextID = 1; + piLastThinkTime = 0; + + // Initialize the active ping list. + /////////////////////////////////// + piActivePingList = ArrayNew(sizeof(piActivePing), 0, NULL); + if(piActivePingList == NULL) + return PINGERFalse; + + // Initialize the callbacks list. + ///////////////////////////////// + piCallbacks = ArrayNew(sizeof(piQueuedCallback), 0, NULL); + if(!piCallbacks) + { + ArrayFree(piActivePingList); + return PINGERFalse; + } + + // Setup the UDP socket. + //////////////////////// + if(piUDPEnabled) + { + if(!piSocketInit(localAddress, localPort)) + { + assert(0); + + // Check for partial intialization. + /////////////////////////////////// + if(piSocket != INVALID_SOCKET) + { + closesocket(piSocket); + piSocket = INVALID_SOCKET; + } + + // Shut down sockets. + ///////////////////// + SocketShutDown(); + + // gsifree the lists. + ////////////////// + ArrayFree(piActivePingList); + ArrayFree(piCallbacks); + + return PINGERFalse; + } + } + + // We're initialized! + ///////////////////// + piInitialized = PINGERTrue; + + return PINGERTrue; +} + +void pingerShutdown(void) +{ + if(!piInitialized) + return; + + // Check for setting data. + ////////////////////////// + if(piSettingData) + return; + + // Shut down the socket. + //////////////////////// + if(piSocket != INVALID_SOCKET) + { + closesocket(piSocket); + piSocket = INVALID_SOCKET; + } + + // Shut down sockets. + ///////////////////// + SocketShutDown(); + + // gsifree the active ping list. + ///////////////////////////// + ArrayFree(piActivePingList); + + // gsifree the callbacks list. + /////////////////////////// + ArrayFree(piCallbacks); + + // Not initialized anymore. + /////////////////////////// + piInitialized = PINGERFalse; +} + +static int GS_STATIC_CALLBACK piFindActivePingCompareFn(const void *elem1, const void *elem2) +{ + piActivePing * activePing1 = (piActivePing *)elem1; + piActivePing * activePing2 = (piActivePing *)elem2; + assert(activePing1 != NULL); + assert(activePing2 != NULL); + assert(activePing1->ID != 0); + assert(activePing2->ID != 0); + + return (activePing1->ID - activePing2->ID); +} + +static piActivePing * piFindActivePing(uint16 ID, int * index) +{ + piActivePing key; + int n; + + // Search for a matching ID. + //////////////////////////// + key.ID = ID; + n = ArraySearch(piActivePingList, &key, piFindActivePingCompareFn, 0, 0); + if(index != NULL) + *index = n; + + // Find it? + /////////// + if(n == NOT_FOUND) + return NULL; + + // Found it! + //////////// + return (piActivePing *)ArrayNth(piActivePingList, n); +} + +static int piCalculatePing(gsi_time sendTime, gsi_time recvTime) +{ + int ping; + + // Simple ping calculation. + /////////////////////////// + ping = (int)(recvTime - sendTime); + + // Take off some time based on the last time we called + // the think function. + ////////////////////////////////////////////////////// + if(piLastThinkTime != 0) + { +#if 0 + ping -= ((int)(recvTime - piLastThinkTime) / 2); + if(ping < 0) + ping = 0; +#endif + } + + return ping; +} + +static void piProcessTrip1(piUDPPing * udpPing, const char * data, SOCKADDR_IN * from, gsi_time recvTime) +{ + char dataOut[PI_DATA_MAX_LEN]; + uint16 ID; + + // Validity check. + // udpPing->ID_A != 0 was triggered by a ping + // from 213.105.94.117 sometime during 7/3-7/02 + /////////////////////////////////////////////// + assert(udpPing->trip == 1); + //assert(udpPing->ID_A != 0); + if(udpPing->ID_A == 0) + return; + assert(udpPing->ID_B == 0); + if(udpPing->ID_B != 0) + return; + + // Do we want a reply? + ////////////////////// + if(piPingerPinged != NULL) + { + // Get an ID. + ///////////// + ID = piGetNextID(); + } + else + { + // No reply wanted. + /////////////////// + ID = 0; + } + + // Setup the data. + ////////////////// + memset(dataOut, 0, PI_DATA_MAX_LEN); + if(piPingerSetData != NULL) + { + piSettingData = PINGERTrue; + piPingerSetData(from->sin_addr.s_addr, from->sin_port, dataOut, PI_DATA_MAX_LEN, piPingerSetDataParam); + piSettingData = PINGERFalse; + } + + // Send the return ping (trip 2). + ///////////////////////////////// + piSendPing(from, 2, udpPing->ID_A, ID, dataOut); + + // Do we need to add an active ping? + //////////////////////////////////// + if(piPingerPinged != NULL) + { + piActivePing activePing; + + // Setup the active ping object. + //////////////////////////////// + activePing.originator = PINGERFalse; + activePing.ID = ID; + activePing.expectedTrip = 3; + activePing.timestamp = current_time(); + activePing.timeout = (activePing.timestamp + PI_TRIP2_TIMEOUT); + activePing.remoteIP = from->sin_addr.s_addr; + activePing.remotePort = from->sin_port; + activePing.reply = NULL; + activePing.replyParam = NULL; + + // Add it to the list. + ////////////////////// + ArrayAppend(piActivePingList, &activePing); + } + + GSI_UNUSED(data); + GSI_UNUSED(recvTime); +} + +static void piProcessTrip2(piUDPPing * udpPing, const char * data, SOCKADDR_IN * from, gsi_time recvTime) +{ + char dataOut[PI_DATA_MAX_LEN]; + int index; + piActivePing * activePing; + + // Validity check. + // ID_A != 0 was triggered by a ping from 205.251.192.203. + // 12/4/00 at approx. 5pm + // This is the same IP as the shifted ping assert above. + ////////////////////////////////////////////////////////// + assert(udpPing->trip == 2); + assert(udpPing->ID_A != 0); + if(udpPing->ID_A == 0) + return; + + // Were we waiting for this? + //////////////////////////// + activePing = piFindActivePing(udpPing->ID_A, &index); + if(activePing == NULL) + return; + + // Setup the data. + ////////////////// + memset(dataOut, 0, PI_DATA_MAX_LEN); + if(piPingerSetData != NULL) + { + piSettingData = PINGERTrue; + piPingerSetData(from->sin_addr.s_addr, from->sin_port, dataOut, PI_DATA_MAX_LEN, piPingerSetDataParam); + piSettingData = PINGERFalse; + } + + // Do we send a reply? + ////////////////////// + if(udpPing->ID_B != 0) + { + // Send the return ping. + //////////////////////// + piSendPing(from, 3, 0, udpPing->ID_B, dataOut); + } + + // Call the callback? + ///////////////////// + if(activePing->reply != NULL) + { + // Calculate the ping. + ////////////////////// + int ping = piCalculatePing(activePing->timestamp, recvTime); + + // Add the callback. + //////////////////// + piQueueCallback(from->sin_addr.s_addr, from->sin_port, ping, data, PI_DATA_MAX_LEN, activePing->replyParam, activePing->reply); + } + + // gsifree the active ping. + //////////////////////// + ArrayDeleteAt(piActivePingList, index); +} + +static void piProcessTrip3(piUDPPing * udpPing, const char * data, SOCKADDR_IN * from, gsi_time recvTime) +{ + int index; + piActivePing * activePing; + + // Validity check. + ////////////////// + assert(udpPing->trip == 3); + assert(udpPing->ID_A == 0); + if(udpPing->ID_A != 0) + return; + assert(udpPing->ID_B != 0); + if(udpPing->ID_B == 0) + return; + + // Were we waiting for this? + //////////////////////////// + activePing = piFindActivePing(udpPing->ID_B, &index); + if(activePing == NULL) + return; + + // Call the callback. + ///////////////////// + assert(piPingerPinged != NULL); + if(piPingerPinged != NULL) + { + // Calculate the ping. + ////////////////////// + int ping = piCalculatePing(activePing->timestamp, recvTime); + + // Call it. + /////////// + piPingerPinged(from->sin_addr.s_addr, from->sin_port, ping, data, PI_DATA_MAX_LEN, piPingerPingedParam); + } + + // gsifree the active ping. + //////////////////////// + ArrayDeleteAt(piActivePingList, index); +} + +static void piProcessPing(piUDPPing * udpPing, const char * data, SOCKADDR_IN * from, gsi_time recvTime) +{ + assert(udpPing != NULL); + assert(data != NULL); + assert(from != NULL); + + // Process based on trip num. + ///////////////////////////// + if(udpPing->trip == 1) + piProcessTrip1(udpPing, data, from, recvTime); + else if(udpPing->trip == 2) + piProcessTrip2(udpPing, data, from, recvTime); + else if(udpPing->trip == 3) + piProcessTrip3(udpPing, data, from, recvTime); +} + +static void piProcessIncoming(void) +{ + int rcode; + unsigned char buffer[PINGER_UDP_PING_SIZE]; + SOCKADDR_IN from; + int len; + gsi_time recvTime; + piUDPPing udpPing; + char data[PI_DATA_MAX_LEN]; + + // Check for incoming dgrams. + ///////////////////////////// + while(piInitialized && CanReceiveOnSocket(piSocket)) + { + // Read the dgram. + ////////////////// + len = sizeof(SOCKADDR_IN); + + rcode = recvfrom(piSocket, (char *)buffer, PINGER_UDP_PING_SIZE, 0, (SOCKADDR *)&from, &len); + + // Check for an error. + ////////////////////// + if (gsiSocketIsError(rcode)) + { + if(GOAGetLastError(piSocket) == WSAEMSGSIZE) + { + // Ignore "too big" errors. + /////////////////////////// + rcode = PINGER_UDP_PING_SIZE; + } + else + { + // Something's wrong, get the hell out of here! + /////////////////////////////////////////////// + return; //ERRCON + } + } + else if(rcode < PINGER_UDP_PING_SIZE) + { + // The ping was too small. + ////////////////////////// + return; //ERRCON + } + + // What time did we receive it? + /////////////////////////////// + recvTime = current_time(); + + // Convert the buffer into a ping. + ////////////////////////////////// + if(piBytesToPing(buffer, &udpPing, data)) + { + // Process the dgram. + ///////////////////// + piProcessPing(&udpPing, data, &from, recvTime); + } + } + + // Last time we checked for incoming data. + ////////////////////////////////////////// + piLastThinkTime = current_time(); +} + +static void piCheckTimeouts(void) +{ + gsi_time now; + piActivePing * activePing; + int len; + int n; + + // Get the number of active pings. + ////////////////////////////////// + len = ArrayLength(piActivePingList); + + // Get out if no active pings. + ////////////////////////////// + if(len == 0) + return; + + // Get the current time. + //////////////////////// + now = current_time(); + + // Go through the list backwards. + ///////////////////////////////// + for(n = (len - 1) ; n >= 0 ; n--) + { + // Get the nth element of the list. + /////////////////////////////////// + activePing = (piActivePing *)ArrayNth(piActivePingList, n); + assert(activePing != NULL); + if(activePing != NULL) + { + // Does it have a timeout? + ////////////////////////// + if(activePing->timeout != 0) + { + // Has it timed out? + //////////////////// + if(activePing->timeout <= now) + { + // Do we need to do a failed callback? + ////////////////////////////////////// + if((activePing->originator) && (activePing->reply != NULL)) + { + // Queue the callback. + ////////////////////// + piQueueCallback(activePing->remoteIP, activePing->remotePort, PINGER_TIMEOUT, NULL, 0, activePing->replyParam, activePing->reply); + } + + // Kill it! + /////////// + ArrayDeleteAt(piActivePingList, n); + } + } + } + } +} + +void pingerThink(void) +{ + // If not initialized, don't do anything. + ///////////////////////////////////////// + if(!piInitialized) + return; + + // Check for setting data. + ////////////////////////// + if(piSettingData) + return; + + // Process incoming data. + ///////////////////////// + piProcessIncoming(); + + // Check for timeouts. + ////////////////////// + piCheckTimeouts(); + + // Call queued callbacks. + ///////////////////////// + piCallCallbacks(); +} + +void pingerPing(unsigned int IP, + unsigned short port, + pingerGotPing reply, + void * replyParam, + PINGERBool blocking, + gsi_time timeout) +{ + SOCKADDR_IN to; + uint16 ID; + + assert(piInitialized); + assert(IP != 0); + + // ICMP not supported yet! + ////////////////////////// + assert(port != 0); + assert(piUDPEnabled); + assert(piSocket != INVALID_SOCKET); + + // Check for setting data. + ////////////////////////// + if(piSettingData) + return; + + // Construct the outgoing address. + ////////////////////////////////// + memset(&to, 0, sizeof(SOCKADDR_IN)); + to.sin_family = AF_INET; + to.sin_port = htons(port); + to.sin_addr.s_addr = IP; + + // Get an ID for this ping. + /////////////////////////// + ID = piGetNextID(); + + // Send the outgoing ping. + ////////////////////////// + if(piSendPing(&to, 1, ID, 0, NULL)) + { + piActivePing activePing; + + // Setup the active ping object. + //////////////////////////////// + activePing.originator = PINGERTrue; + activePing.ID = ID; + activePing.expectedTrip = 2; + activePing.timestamp = current_time(); + if(timeout == 0) + activePing.timeout = 0; + else + activePing.timeout = (activePing.timestamp + timeout); + activePing.remoteIP = IP; + activePing.remotePort = port; + activePing.reply = reply; + activePing.replyParam = replyParam; + + // Add it to the list. + ////////////////////// + ArrayAppend(piActivePingList, &activePing); + } + + // Is this blocking? + //////////////////// + if(blocking) + { + // Keep going until this ping has been de-listed. + ///////////////////////////////////////////////// + while(piFindActivePing(ID, NULL) != NULL) + { + // Think. + ///////// + pingerThink(); + + // Yield. + ///////// + msleep(1); + } + + // Call callbacks. + ////////////////// + piCallCallbacks(); + } +} diff --git a/xrGameSpy/gamespy/pt/changelog.txt b/xrGameSpy/gamespy/pt/changelog.txt new file mode 100644 index 00000000000..5f7aeccf38a --- /dev/null +++ b/xrGameSpy/gamespy/pt/changelog.txt @@ -0,0 +1,95 @@ +Changelog for: GameSpy Patching & Tracking SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.04.00 RMV RELEASE Released to Developer Site +08-06-2007 1.03.00 RMV RELEASE Released to Developer Site +07-16-2007 1.02.01 RMV FIX Removed gsTestMain from Mac Makefile + 1.02.01 RMV OTHER Removed FilePlanetInfo calls from pttestc.c +07-11-2007 1.02.01 RMV FIX Fixed pttestc Project file to get rid of Unicode warnings +12-15-2006 1.02.00 MJW RELEASE Released to Developer Site +10-30-2006 1.01.44 SN FIX Modified the ptCreateCheckPatchTrackUsageReqW to use correct corresponding ascii function + Also modified ptCreateCheckPatchTrackUsageReqA to conform with the rest of the SDK where + the request is being saved in a variable +10-30-2006 1.01.43 SAH OTHER Changed PTA_MAX_STRING_SIZE to 2048 +10-05-2006 1.01.42 SAH FIX Updated MacOSX Makefile +09-28-2006 1.01.41 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-02-2006 1.01.40 SAH RELEASE Releasing to developer site +07-31-2006 1.01.40 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 1.01.39 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-06-2006 1.01.38 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +07-06-2006 1.01.37 SAH FIX Fixed Linux makefile to work with pthreads (for http asynch DNS lookup) + SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) +05-31-2006 1.01.36 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-30-2006 1.01.35 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) +05-25-2006 1.01.34 SAH FIX Changed PSP project warning levels +05-19-2006 1.01.33 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-15-2006 1.01.32 SAH FIX Added "PS3 Release" configuration to project +04-25-2006 1.01.31 SAH RELEASE Releasing to developer site +04-24-2006 1.01.31 SAH FIX Moved definition ptCheckForPatchAndTrackUsageA so it was defined before used +04-24-2006 1.01.30 SAH FIX Fixed Nitro project files to work on build machine +04-20-2006 1.01.30 SAH FIX Added necessary files to VC6 project, set to warning level 4 +04-14-2006 1.01.29 SAH FIX Added gsXML and other files to the project to compile for release +01-30-2006 1.01.28 SN FEATURE Added a function similar to ptCheckForPatchAndTrackUsage with a return of a handle + to pass to ghttpRequestThink. +01-27-2006 1.01.27 SN RELEASE Releasing to developer site +01-27-2006 1.01.27 SN FIX Added PSP to test_main define in pttestc + SN OTHER Added psp prodg project and solution to sgv +12-22-2005 1.01.26 SN OTHER Cleaned up project file and added latest common code if needed +11-17-2005 1.01.25 DES FIX Updated Nitro makefile. +11-14-2005 1.01.24 DES FIX Updated the OSX Makefile. + DES FEATURE Added GSI_DOMAIN_NAME support. +09-21-2005 1.01.25 DES FEATURE Updated DS support +07-28-2005 1.01.24 SN RELEASE Releasing to developer site. +07-28-2005 1.01.24 SN FIX Added new common code in pt ps2 project +06-03-2005 1.01.23 SN RELEASE Releasing to developer site. +05-09-2005 1.01.23 SN FIX Fixed common code includes in source files + Fixed project to use new common code +05-04-2005 1.01.22 SN OTHER Created Visual Studio .NET project +04-28-2005 1.01.22 SN RELEASE Releasing to developer site. +04-27-2005 1.01.22 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 1.01.22 DES FEATURE Added common debug support to pttestc +04-04-2005 1.01.21 SN RELEASE Releasing to developer site. +03-14-2005 1.01.21 DES FEATURE Nintendo DS support +11-24-2004 1.01.20 SN FIX Fixed download URL with 100 char limit to be 256. + Made URL character string local to functions that use it. + added a 256 char size constant +09-16-2004 1.01.19 SN RELEASE Releasing to developer site. +08-27-2004 1.01.19 DES CLEANUP Fixed warnings under OSX + DES CLEANUP General Unicode cleanup + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Updated OSX Makefile +08-04-2004 1.01.18 SN RELEASE Releasing to developer site. +07-19-2004 1.01.18 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +06-18-2004 1.01.18 BED RELEASE Releasing to developer site. + BED FEATURE Added PS2 Insock support +11-10-2003 1.01.17 DES RELEASE Releasing to developer site. +11-07-2003 1.01.17 BED FIX Updated CodeWarrior project file. +11-07-2003 1.01.16 DES FIX Updated linux and PS2 makefiles. +11-04-2003 1.01.15 DES FEATURE Added availability check code. +10-29-2003 1.01.14 BED FIX Fixed bug with incorrect data types in callback. + DES FEATURE Now passes the gamename along with the request. +10-22-2003 1.01.13 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-22-2003 1.01.13 BED FIX Removed script compiler warnings in preparation for release. + BED FEATURE Added Unicode support to the sample. +10-09-2003 1.01.12 BED FIX Added ghttpCleanup call to pttestc.c to prevent memory leak. +09-08-2003 1.01.11 BED FEATURE Added UTF-8 wrapper for UNICODE support +07-24-2003 1.01.10 DES RELEASE Releasing to developer site. +07-23-2003 1.01.10 BED FEATURE Added Linux sample Makefile. +07-18-2003 1.01.09 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 1.01.08 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 1.01.07 DES FIX Changed a __mips64 check to a _PS2 check. + BED FEATURE Added ProDG sample project files. +07-11-2003 1.01.06 BED FIX Added a success message in the pttest sample for PS2. +07-10-2003 1.01.05 BED CLEANUP Switch from local UNUSED_PARAM to standard GSI_UNUSED macro. +05-09-2003 1.01.04 DES CLEANUP Removed Dreamcast support. +04-15-2003 1.01.03 JED CLEANUP Removed a few DevStudio Level4 warnings +12-19-2002 1.01.02 DES RELEASE Releasing to developer site. +12-19-2002 1.01.02 DES CLEANUP Removed assert.h include. +12-13-2002 1.01.01 DES FEATURE Added PS2 eenet stack support. + CLEANUP Cleaned up code to remove PS2 compiler warnings. +09-25-2002 1.01.00 DDW OTHER Changelog started diff --git a/xrGameSpy/gamespy/pt/fpupdate/fpupdate.exe b/xrGameSpy/gamespy/pt/fpupdate/fpupdate.exe new file mode 100644 index 00000000000..d0a3dfe39ed Binary files /dev/null and b/xrGameSpy/gamespy/pt/fpupdate/fpupdate.exe differ diff --git a/xrGameSpy/gamespy/pt/pt.dsp b/xrGameSpy/gamespy/pt/pt.dsp new file mode 100644 index 00000000000..398cf6eff01 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pt.dsp @@ -0,0 +1,300 @@ +# Microsoft Developer Studio Project File - Name="pt" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=pt - 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 "pt.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 "pt.mak" CFG="pt - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pt - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "pt - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/pt", FCGBAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "pt - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "pt - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=snLib.exe +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "pt - Win32 Release" +# Name "pt - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ptMain.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\pt.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\md5c.c +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/pt/pt.dsw b/xrGameSpy/gamespy/pt/pt.dsw new file mode 100644 index 00000000000..f2154516969 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pt.dsw @@ -0,0 +1,53 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pt"=.\pt.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pt", FCGBAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "pttestc"=.\pttestc\pttestc.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pt/pttestc", KCGBAAAA + .\pttestc + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pt", FCGBAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/pt/pt.h b/xrGameSpy/gamespy/pt/pt.h new file mode 100644 index 00000000000..1c11fc7fbcd --- /dev/null +++ b/xrGameSpy/gamespy/pt/pt.h @@ -0,0 +1,156 @@ +/* +GameSpy PT SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +/************************************** +** GameSpy Patching and Tracking SDK ** +**************************************/ + +#ifndef _PT_H_ +#define _PT_H_ + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/********** +** TYPES ** +**********/ + +// Boolean. +/////////// +typedef int PTBool; +#define PTFalse 0 +#define PTTrue 1 + +/************** +** FUNCTIONS ** +**************/ +#ifndef GSI_UNICODE +#define ptCheckForPatch ptCheckForPatchA +#define ptTrackUsage ptTrackUsageA +#define ptCheckForPatchAndTrackUsage ptCheckForPatchAndTrackUsageA +#define ptCreateCheckPatchTrackUsageReq ptCreateCheckPatchTrackUsageReqA +#else +#define ptCheckForPatch ptCheckForPatchW +#define ptTrackUsage ptTrackUsageW +#define ptCheckForPatchAndTrackUsage ptCheckForPatchAndTrackUsageW +#define ptCreateCheckPatchTrackUsageReq ptCreateCheckPatchTrackUsageReqW +#endif + +// This callback gets called when a patch is being checked for +// with either ptCheckForPatch or ptCheckForPatchAndTrackUsage. +// If a patch is available, and the fileID is not 0, then +// ptLookupFilePlanetInfo can be used to find download sites. +/////////////////////////////////////////////////////////////// +typedef void (* ptPatchCallback) +( + PTBool available, // If PTTrue, a patch is available. + PTBool mandatory, // If PTTrue, this patch is flagged as being mandatory. + const gsi_char * versionName, // The display name for the new version. + int fileID, // The FilePlanet fileID for the patch, or 0. + const gsi_char * downloadURL, // A URL to download the patch from, or NULL. + void * param // User-data passed originally passed to the function. +); + +// Check for a patch for the current version and particular +// distribution of the product. If this function does not return +// PTFalse, then the callback will be called with info on a +// possible patch to a newer version. +/////////////////////////////////////////////////////////////// +PTBool ptCheckForPatch +( + int productID, // The ID of this product. + const gsi_char * versionUniqueID, // A string uniquely identifying this version. + int distributionID, // The distribution ID for this version. Can be 0. + ptPatchCallback callback, // The callback to call with the patch info. + PTBool blocking, // If PTTrue, don't return until after the callback is called. + void * param // User-data to pass to the callback. +); + +// Used to track usage of a product, based on version and distribution. +// If PTFalse is returned, there was an error tracking usage. +/////////////////////////////////////////////////////////////////////// +PTBool ptTrackUsage +( + int userID, // The GP userID of the user who is using the product. Can be 0. + int productID, // The ID of this product. + const gsi_char * versionUniqueID, // A string uniquely identifying this version. + int distributionID, // The distribution ID for this version. Can be 0. + PTBool blocking +); + +// This does the same thing as both ptCheckForPatch and +// ptTrackUsage in one call. +/////////////////////////////////////////////////////// +PTBool ptCheckForPatchAndTrackUsage +( + int userID, // The GP userID of the user who is using the product. Can be 0. + int productID, // The ID of this product. + const gsi_char * versionUniqueID, // A string uniquely identifying this version. + int distributionID, // The distribution ID for this version. Can be 0. + ptPatchCallback callback, // The callback to call with the patch info. + PTBool blocking, // If PTTrue, don't return until after the callback is called. + void * param // User-data to pass to the callback. +); + +// This function is similar to the function ptCheckForPatchAndTrackUsage +// except that it returns a handle that can be used to call ghttpRequestThink +// or a failure of -1 +////////////////////////////////////////////////////// +PTBool ptCreateCheckPatchTrackUsageReq +( + int userID, // The GP userID of the user who is using the product. Can be 0. + int productID, // The ID of this product. + const gsi_char * versionUniqueID, // A string uniquely identifying this version. + int distributionID, // The distribution ID for this version. Can be 0. + ptPatchCallback callback, // The callback to call with the patch info. + PTBool blocking, // If PTTrue, don't return until after the callback is called. + int *request, // The request that can be used for ghttpRequestThink + void * param // User-data to pass to the callback. + ); + +// This callback gets called when looking up info on a +// FilePlanet file. If the file is found, it provides a +// text description, size, and a list of download sites. +//////////////////////////////////////////////////////// +typedef void (* ptFilePlanetInfoCallback) +( + int fileID, // The ID of the file for which info was looked up. + PTBool found, // PTTrue if the file was found. + const gsi_char * description, // A user-readable description of the file. + const gsi_char * size, // A user-readable size of the file. + int numMirrors, // The number of mirrors found for this file. + const gsi_char ** mirrorNames, // The names of the mirrors. + const gsi_char ** mirrorURLs, // The URLS for downloading the files. + void * param // User-data passed originally passed to the function. +); + +// 9/7/2004 (xgd) ptLookupFilePlanetInfo() deprecated; per case 2724. +// +// Use this function to lookup info on a fileplanet file, by ID. +// This can be used to find a list of download sites for a patch +// based on the fileID passed to ptPatchCallback. If PTFalse is +// returned, then there was an error and the callback will not +// be called. +//////////////////////////////////////////////////////////////// +PTBool ptLookupFilePlanetInfo +( + int fileID, // The ID of the file to find info on. + ptFilePlanetInfoCallback callback, // The callback to call with the patch info. + PTBool blocking, // If PTTrue, don't return until after the callback is called. + void * param // User-data to pass to the callback. +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/pt/ptMain.c b/xrGameSpy/gamespy/pt/ptMain.c new file mode 100644 index 00000000000..dbe0524c7fb --- /dev/null +++ b/xrGameSpy/gamespy/pt/ptMain.c @@ -0,0 +1,686 @@ +/* +GameSpy PT SDK +Dan "Mr. Pants" Schoenblum +dan@gamespy.com + +Copyright 2000 GameSpy Industries, Inc + +*/ + +#ifdef XRAY_DISABLE_GAMESPY_WARNINGS +#pragma warning(disable: 4244) //lines: 606 +#endif //#ifdef XRAY_DISABLE_GAMESPY_WARNINGS + + +#include +#include "pt.h" +#include "../ghttp/ghttp.h" +#include "../common/gsStringUtil.h" +#include "../common/gsAvailable.h" + +/************ +** DEFINES ** +************/ +#define PTA_DEFAULT_VERCHECK_URL "http://motd." GSI_DOMAIN_NAME "/motd/vercheck.asp" +#define PTA_DEFAULT_MOTD_URL "http://motd." GSI_DOMAIN_NAME "/motd/motd.asp" +#define PTA_DEFAULT_FILEPLANET_URL "http://www.fileplanet.com/dlfileraw.asp" +#define MAX_MIRRORS 32 +#define PTA_MAX_STRING_SIZE 2048 + +char gPTAVercheckURL[PTA_MAX_STRING_SIZE]; +char gPTAMOTDURL[PTA_MAX_STRING_SIZE]; +char gPTAFilePlanetURL[PTA_MAX_STRING_SIZE]; + +/********** +** TYPES ** +**********/ +typedef struct ptaPatchData +{ + ptPatchCallback callback; + void * param; +} ptaPatchData; + +typedef struct ptaFilePlanetInfoData +{ + int fileID; + ptFilePlanetInfoCallback callback; + void * param; +} ptaFilePlanetInfoData; + +/************ +** GLOBALS ** +************/ +//static char URL[PTA_MAX_STRING_SIZE]; + +/************** +** FUNCTIONS ** +**************/ +static const char * ptaGetKeyValue +( + const char * buffer, + const char * key +) +{ + static char value[PTA_MAX_STRING_SIZE]; + const char * str; + int len; + + str = strstr(buffer, key); + if(!str) + return NULL; + str += strlen(key); + len = (int)strcspn(str, "\\"); + len = min(len, (int)sizeof(value) - 1); + memcpy(value, str, (unsigned int)len); + value[len] = '\0'; + + return value; +} + +static char Line[PTA_MAX_STRING_SIZE]; +static int ptaFillLine +( + const char * buffer +) +{ + char * str = Line; + int i; + + // Skip white space. + //////////////////// + for(i = 0 ; isspace(*buffer) ; i++) + buffer++; + + // Check for EOF. + ///////////////// + if(*buffer == '\0') + return EOF; + + // Copy off the line. + ///////////////////// + for( ; *buffer && ((*buffer != 0x0A) && (*buffer != 0x0D)) ; i++) + { + if(i == sizeof(Line) - 1) + { + // This line is too big for our buffer. + /////////////////////////////////////// + assert(0); + return EOF; + } + *str++ = *buffer++; + } + *str = '\0'; + + return i; +} + +static void ptaCallPatchCallback +( + ptaPatchData * data, + PTBool available, + PTBool mandatory, + const char * versionName, + int fileID, + const char * downloadURL +) +{ + if(data->callback) + { +#ifndef GSI_UNICODE + data->callback(available, mandatory, versionName, fileID, downloadURL, data->param); +#else + unsigned short versionName_W[255]; + unsigned short downloadURL_W[PTA_MAX_STRING_SIZE*2]; + UTF8ToUCS2String(versionName, versionName_W); + AsciiToUCS2String(downloadURL, downloadURL_W); + data->callback(available, mandatory, versionName_W, fileID, downloadURL_W, data->param); +#endif + } + + gsifree(data); +} + +// already returns ghttptrue +static GHTTPBool ptaPatchFailed +( + ptaPatchData * data +) +{ + ptaCallPatchCallback(data, PTFalse, PTFalse, "", 0, ""); + + return GHTTPTrue; +} + +static void ptaCallFilePlanetInfoCallback +( + ptaFilePlanetInfoData * data, + PTBool found, + const char * description, + const char * size, + int numMirrors, + char ** mirrorNames, + char ** mirrorURLs +) +{ + int i; + + if(data->callback) + { + if (!found) + data->callback(data->fileID, PTFalse, NULL, NULL, 0, NULL, NULL, data->param); + else + { +#ifndef GSI_UNICODE + data->callback(data->fileID, found, description, size, numMirrors, (const char**)mirrorNames, (const char**)mirrorURLs, data->param); +#else + unsigned short description_W[255]; + unsigned short size_W[1024]; + unsigned short** mirrorNames_W; + unsigned short** mirrorURLs_W; + int i; + + UTF8ToUCS2String(description, description_W); + AsciiToUCS2String(size, size_W); + mirrorNames_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)mirrorNames, numMirrors); + mirrorURLs_W = UTF8ToUCS2StringArrayAlloc((const UTF8String *)mirrorURLs, numMirrors); + data->callback(data->fileID, found, description_W, size_W, numMirrors, (const unsigned short**)mirrorNames_W, (const unsigned short**)mirrorURLs_W, data->param); + + for (i=0; i < numMirrors; i++) + { + gsifree(mirrorNames[i]); + gsifree(mirrorURLs[i]); + } + gsifree(mirrorNames); + gsifree(mirrorURLs); +#endif + } + } + + for(i = 0 ; i < numMirrors ; i++) + { + gsifree(mirrorNames[i]); + gsifree(mirrorURLs[i]); + } + + gsifree(data); +} + +// already returns ghttptrue +static GHTTPBool ptaFilePlanetInfoFailed +( + ptaFilePlanetInfoData * data +) +{ + ptaCallFilePlanetInfoCallback(data, PTFalse, NULL, NULL, 0, NULL, NULL); + + return GHTTPTrue; +} + +static GHTTPBool ptaPatchCompletedCallback +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + ptaPatchData * data = (ptaPatchData *)param; + const char * value; + PTBool mandatory; + int fileID; + char versionName[PTA_MAX_STRING_SIZE]; + char downloadURL[PTA_MAX_STRING_SIZE]; + + GSI_UNUSED(bufferLen); + GSI_UNUSED(request); + + // Check for success. + ///////////////////// + if(result != GHTTPSuccess) + return ptaPatchFailed(data); + + // Check for a patch. + ///////////////////// + value = ptaGetKeyValue(buffer, "\\newver\\"); + if(!value || !atoi(value)) + return ptaPatchFailed(data); + + // Check the mandatory flag. + //////////////////////////// + value = ptaGetKeyValue(buffer, "\\lockout\\"); + mandatory = (value && atoi(value)); + + // Get the file id. + /////////////////// + value = ptaGetKeyValue(buffer, "\\fpfileid\\"); + if(value) + fileID = atoi(value); + else + fileID = 0; + + // Get the name. + //////////////// + value = ptaGetKeyValue(buffer, "\\newvername\\"); + if(value) + { + strncpy(versionName, value, sizeof(versionName)); + versionName[sizeof(versionName) - 1] = '\0'; + } + else + versionName[0] = '\0'; + + // Get the URL. + /////////////// + value = ptaGetKeyValue(buffer, "\\dlurl\\"); + if(value) + { + strncpy(downloadURL, value, sizeof(downloadURL)); + downloadURL[sizeof(downloadURL) - 1] = '\0'; + } + else + downloadURL[0] = '\0'; + + // Call the callback. + ///////////////////// + ptaCallPatchCallback(data, PTTrue, mandatory, versionName, fileID, downloadURL); + + return GHTTPTrue; +} + +PTBool ptCheckForPatchA +( + int productID, + const char * versionUniqueID, + int distributionID, + ptPatchCallback callback, + PTBool blocking, + void * param +) +{ + int charsWritten; + char aURL[PTA_MAX_STRING_SIZE]; + ptaPatchData * data; + + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return PTFalse; + + // Check the arguments. + /////////////////////// + assert(versionUniqueID); + if(!versionUniqueID) + return PTFalse; + assert(callback); + if(!callback) + return PTFalse; + + // override hostname? + if (gPTAVercheckURL[0] == '\0') + sprintf(gPTAVercheckURL, PTA_DEFAULT_VERCHECK_URL); + + // Store some data. + /////////////////// + data = (ptaPatchData *)gsimalloc(sizeof(ptaPatchData)); + if(!data) + return PTFalse; + memset(data, 0, sizeof(ptaPatchData)); + data->callback = callback; + data->param = param; + + // Build the URL. + ///////////////// + charsWritten = + snprintf(aURL, PTA_MAX_STRING_SIZE, + "%s?productid=%d&versionuniqueid=%s&distid=%d&gamename=%s", + gPTAVercheckURL, productID, versionUniqueID, distributionID, + __GSIACGamename); + + assert(charsWritten >= 0); + if (charsWritten < 0) + return PTFalse; + + // Send the request. + //////////////////// + if((ghttpGetFileA(aURL, (GHTTPBool)blocking, ptaPatchCompletedCallback, data) == (unsigned char)(-1)) && !blocking) + return PTFalse; + + return PTTrue; +} +#ifdef GSI_UNICODE +PTBool ptCheckForPatchW +( + int productID, + const unsigned short* versionUniqueID, + int distributionID, + ptPatchCallback callback, + PTBool blocking, + void * param +) +{ + char versionUniqueID_A[255]; + UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); + return ptCheckForPatchA(productID, versionUniqueID_A, distributionID, callback, blocking, param); +} +#endif + +PTBool ptTrackUsageA +( + int userID, + int productID, + const char * versionUniqueID, + int distributionID, + PTBool blocking +) +{ + int charsWritten; + char aURL[PTA_MAX_STRING_SIZE]; + + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return PTFalse; + + // Check the arguments. + /////////////////////// + assert(versionUniqueID); + if(!versionUniqueID) + return PTFalse; + + // override hostname? + if (gPTAMOTDURL[0] == '\0') + sprintf(gPTAMOTDURL, PTA_DEFAULT_MOTD_URL); + + // Build the URL. + ///////////////// + charsWritten = snprintf(aURL, PTA_MAX_STRING_SIZE, + "%s?userid=%d&productid=%d&versionuniqueid=%s&distid=%d&uniqueid=%s&gamename=%s", + gPTAMOTDURL, userID, productID, versionUniqueID, distributionID, GOAGetUniqueID(), + __GSIACGamename); + assert(charsWritten >= 0); + if (charsWritten < 0) + return PTFalse; + // Send the info. + ///////////////// + if(ghttpGetFileA(aURL, (GHTTPBool)blocking, NULL, NULL) == -1) + return PTFalse; + + return PTTrue; +} +#ifdef GSI_UNICODE +PTBool ptTrackUsageW +( + int userID, + int productID, + const unsigned short* versionUniqueID, + int distributionID, + PTBool blocking +) +{ + char versionUniqueID_A[255]; + UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); + return ptTrackUsageA(userID, productID, versionUniqueID_A, distributionID, blocking); +} +#endif + +PTBool ptCreateCheckPatchTrackUsageReqA +( + int userID, + int productID, + const char * versionUniqueID, + int distributionID, + ptPatchCallback callback, + PTBool blocking, + int *request, + void * param +) +{ + int charsWritten; + char aURL[PTA_MAX_STRING_SIZE]; + ptaPatchData * data; + + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return PTFalse; + + // Check the arguments. + /////////////////////// + assert(versionUniqueID); + if(!versionUniqueID) + return PTFalse; + assert(callback); + if(!callback) + return PTFalse; + + // Store some data. + /////////////////// + data = (ptaPatchData *)gsimalloc(sizeof(ptaPatchData)); + if(!data) + return PTFalse; + memset(data, 0, sizeof(ptaPatchData)); + data->callback = callback; + data->param = param; + + // override hostname? + if (gPTAVercheckURL[0] == '\0') + sprintf(gPTAVercheckURL, PTA_DEFAULT_VERCHECK_URL); + + // Build the URL. + ///////////////// + charsWritten = snprintf(aURL, PTA_MAX_STRING_SIZE, + "%s?userid=%d&productid=%d&versionuniqueid=%s&distid=%d&uniqueid=%s&gamename=%s", + gPTAVercheckURL, userID, productID, versionUniqueID, distributionID, GOAGetUniqueID(), + __GSIACGamename); + + assert(charsWritten >= 0); + if (charsWritten < 0) + return PTFalse; + + // Send the request. + //////////////////// + *request = ghttpGetFileA(aURL, (GHTTPBool)blocking, ptaPatchCompletedCallback, data); + if (*request == -1) + return PTFalse; + return PTTrue; +} + +#ifdef GSI_UNICODE +PTBool ptCreateCheckPatchTrackUsageReqW +( + int userID, + int productID, + const unsigned short * versionUniqueID, + int distributionID, + ptPatchCallback callback, + PTBool blocking, + int *request, + void * param + ) +{ + char versionUniqueID_A[255]; + UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); + return ptCreateCheckPatchTrackUsageReqA(userID, productID, versionUniqueID_A, distributionID, callback, blocking, request, param); +} +#endif + +PTBool ptCheckForPatchAndTrackUsageA +( + int userID, + int productID, + const char * versionUniqueID, + int distributionID, + ptPatchCallback callback, + PTBool blocking, + void * param +) +{ + GHTTPRequest aRequest; + + // create the request and send it. + /////////////////////////////////// + return ptCreateCheckPatchTrackUsageReqA(userID, productID, versionUniqueID, distributionID, callback, blocking, &aRequest, param); + +} + +#ifdef GSI_UNICODE +PTBool ptCheckForPatchAndTrackUsageW +( + int userID, + int productID, + const unsigned short * versionUniqueID, + int distributionID, + ptPatchCallback callback, + PTBool blocking, + void * param +) +{ + char versionUniqueID_A[255]; + UCS2ToUTF8String(versionUniqueID, versionUniqueID_A); + return ptCheckForPatchAndTrackUsageA(userID, productID, versionUniqueID_A, distributionID, callback, blocking, param); +} +#endif + +static GHTTPBool ptaFilePlanetCompletedCallback +( + GHTTPRequest request, + GHTTPResult result, + char * buffer, + GHTTPByteCount bufferLen, + void * param +) +{ + ptaFilePlanetInfoData * data = (ptaFilePlanetInfoData *)param; + int len; + char description[256]; + char size[64]; + char * mirrorNames[MAX_MIRRORS]; + char * mirrorURLs[MAX_MIRRORS]; + int i; + char * str; + + // check if the backend is available + if(__GSIACResult != GSIACAvailable) + return GHTTPFalse; + + GSI_UNUSED(request); + GSI_UNUSED(bufferLen); + + // Check for success. + ///////////////////// + if(result != GHTTPSuccess) + return ptaFilePlanetInfoFailed(data); + + // Get the description. + /////////////////////// + len = ptaFillLine(buffer); + if(len == EOF) + return ptaFilePlanetInfoFailed(data); + buffer += len; + strncpy(description, Line, sizeof(description)); + description[sizeof(description) - 1] = '\0'; + + // Get the size. + //////////////// + len = ptaFillLine(buffer); + if(len == EOF) + return ptaFilePlanetInfoFailed(data); + buffer += len; + strncpy(size, Line, sizeof(size)); + size[sizeof(size) - 1] = '\0'; + + // Get the mirrors. + /////////////////// + for(i = 0 ; (i < MAX_MIRRORS) && ((len = ptaFillLine(buffer)) != EOF) ; ) + { + // Adjust the buffer. + ///////////////////// + buffer += len; + + // Find the tab. + //////////////// + str = strchr(Line, '\t'); + if(!str) + continue; + + // Copy off the name. + ///////////////////// + len = (str - Line); + mirrorNames[i] = (char *)gsimalloc((unsigned int)len + 1); + if(!mirrorNames[i]) + break; + memcpy(mirrorNames[i], Line, (unsigned int)len); + mirrorNames[i][len] = '\0'; + + // Copy off the URL. + //////////////////// + str++; + len = (int)strlen(str); + mirrorURLs[i] = (char *)gsimalloc((unsigned int)len + 1); + if(!mirrorURLs[i]) + { + gsifree(mirrorNames[i]); + break; + } + strcpy(mirrorURLs[i], str); + + // One more mirror. + /////////////////// + i++; + } + + // Call the callback. + ///////////////////// + ptaCallFilePlanetInfoCallback(data, PTTrue, description, size, i, mirrorNames, mirrorURLs); + + return GHTTPTrue; +} + +// 9/7/2004 (xgd) ptLookupFilePlanetInfo() deprecated; per case 2724. +// +PTBool ptLookupFilePlanetInfo +( + int fileID, + ptFilePlanetInfoCallback callback, + PTBool blocking, + void * param +) +{ + char aURL[PTA_MAX_STRING_SIZE]; + ptaFilePlanetInfoData * data; + + // Check the arguments. + /////////////////////// + assert(callback); + if(!callback) + return PTFalse; + + // override hostname? + if (gPTAFilePlanetURL[0] == '\0') + sprintf(gPTAFilePlanetURL, PTA_DEFAULT_FILEPLANET_URL); + + // Store some data. + /////////////////// + data = (ptaFilePlanetInfoData *)gsimalloc(sizeof(ptaFilePlanetInfoData)); + if(!data) + return PTFalse; + memset(data, 0, sizeof(ptaFilePlanetInfoData)); + data->callback = callback; + data->param = param; + data->fileID = fileID; + + // Build the URL. + ///////////////// + // 11/24/2004 - Added By Saad Nader + // Now using string size as limit for printing + // also null terminate string automatically + /////////////////////////////////////////////// + snprintf(aURL, PTA_MAX_STRING_SIZE, + "%s?file=%d&gamename=%s", gPTAFilePlanetURL, fileID, __GSIACGamename); + + + // Send the request. + //////////////////// + if((ghttpGetFileA(aURL, (GHTTPBool)blocking, ptaFilePlanetCompletedCallback, data) == -1) && !blocking) + return PTFalse; + + return PTTrue; +} diff --git a/xrGameSpy/gamespy/pt/pt_vs2005.sln b/xrGameSpy/gamespy/pt/pt_vs2005.sln new file mode 100644 index 00000000000..e60fbdae0d7 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pt_vs2005.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pttestc_vs2005", "pttestc\pttestc_vs2005.vcproj", "{37C8B4F7-D833-482A-8C64-B46B8D0449F4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Debug|Win32.ActiveCfg = Debug|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Debug|Win32.Build.0 = Debug|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Release|Win32.ActiveCfg = Release|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Release|Win32.Build.0 = Release|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {37C8B4F7-D833-482A-8C64-B46B8D0449F4}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/pt/pttestc/ptlinux/Makefile b/xrGameSpy/gamespy/pt/pttestc/ptlinux/Makefile new file mode 100644 index 00000000000..b1c0e440bb5 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptlinux/Makefile @@ -0,0 +1,62 @@ +# Patching & Tracking SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=pt + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../pttestc.o\ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsXML.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsSSL.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../ptMain.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpPost.o\ + ../../../ghttp/ghttpProcess.o\ + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/pt/pttestc/ptmacosx/Makefile b/xrGameSpy/gamespy/pt/pttestc/ptmacosx/Makefile new file mode 100644 index 00000000000..7b8e2204a1c --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptmacosx/Makefile @@ -0,0 +1,38 @@ +# P&T SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=pttestc + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsXML.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsSSL.o\ + ../../../common/gsMemory.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../ptMain.o\ + ../$(PROJECT).o + + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/Nitro.lcf b/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/ptnitrocw.mcp b/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/ptnitrocw.mcp new file mode 100644 index 00000000000..7d6a954460a Binary files /dev/null and b/xrGameSpy/gamespy/pt/pttestc/ptnitrocw/ptnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps2/Makefile b/xrGameSpy/gamespy/pt/pttestc/ptps2/Makefile new file mode 100644 index 00000000000..6d96831393a --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps2/Makefile @@ -0,0 +1,32 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = pttestc + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o\ + ../../../stringutil.o \ + ../../../available.o \ + ../../ptMain.o \ + ../../../ghttp/ghttpBuffer.o \ + ../../../ghttp/ghttpCallbacks.o \ + ../../../ghttp/ghttpConnection.o \ + ../../../ghttp/ghttpMain.o \ + ../../../ghttp/ghttpProcess.o \ + ../../../ghttp/ghttpCommon.o \ + ../../../ghttp/ghttpPost.o \ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps2cw/ptps2cw.mcp b/xrGameSpy/gamespy/pt/pttestc/ptps2cw/ptps2cw.mcp new file mode 100644 index 00000000000..ce3f7dde200 Binary files /dev/null and b/xrGameSpy/gamespy/pt/pttestc/ptps2cw/ptps2cw.mcp differ diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.dsp b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.dsp new file mode 100644 index 00000000000..0577df54dd5 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.dsp @@ -0,0 +1,452 @@ +# Microsoft Developer Studio Project File - Name="ptps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ptps2prodg - Win32 Release_Insock +!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 "ptps2prodg.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 "ptps2prodg.mak" CFG="ptps2prodg - Win32 Release_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ptps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "ptps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "ptps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "ptps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "ptps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "ptps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/pt/pttestc/ptps2prodg", TTEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ptps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "_DEBUG" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\ptps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\ptps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ptps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ptps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "ptps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "_DEBUG" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "INSOCK" /D "_DEBUG" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\ptps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\ptps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ptps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "UNIQUEID" /D "SN_SYSTEMS" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\ptps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\ptps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ptps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\ptps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a sneetcp.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\ptps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ptps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ptps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "ptps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "INSOCK" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a sneetcp.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\ptps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\ptps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "ptps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /D "UNIQUEID" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\ptps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\ptps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "ptps2prodg - Win32 Debug_EENet" +# Name "ptps2prodg - Win32 Debug_Insock" +# Name "ptps2prodg - Win32 Debug_SNSystems" +# Name "ptps2prodg - Win32 Release_EENet" +# Name "ptps2prodg - Win32 Release_Insock" +# Name "ptps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\pttestc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "PatchingTrackingSDK" + +# PROP Default_Filter "" +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\pt.h +# End Source File +# Begin Source File + +SOURCE=..\..\ptMain.c +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.dsw b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.dsw new file mode 100644 index 00000000000..78b444bb2d5 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ptps2prodg"=.\ptps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/pt/pttestc/ptps2prodg", TTEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/gamespy/goa/pt/pttestc/ptps2prodg", TTEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.sln b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.sln new file mode 100644 index 00000000000..ece44988ac9 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.sln @@ -0,0 +1,43 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ptps2prodg", "ptps2prodg.vcproj", "{35D0D282-DA51-49E2-94B7-33B101ABE5F4}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = ptps2prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EE Debug|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 EENET Debug|Win32.Build.0 = PS2 EE Debug|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 EENET Release|Win32.ActiveCfg = PS2 EE Release|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 EENET Release|Win32.Build.0 = PS2 EE Release|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {35D0D282-DA51-49E2-94B7-33B101ABE5F4}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.vcproj b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.vcproj new file mode 100644 index 00000000000..5b0d1d005aa --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps2prodg/ptps2prodg.vcproj @@ -0,0 +1,764 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps3prodg/ptps3prodg.sln b/xrGameSpy/gamespy/pt/pttestc/ptps3prodg/ptps3prodg.sln new file mode 100644 index 00000000000..3f051f43f4f --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps3prodg/ptps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ptps3prodg", "ptps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = ptps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/pt/pttestc/ptps3prodg/ptps3prodg.vcproj b/xrGameSpy/gamespy/pt/pttestc/ptps3prodg/ptps3prodg.vcproj new file mode 100644 index 00000000000..55cb0686041 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptps3prodg/ptps3prodg.vcproj @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/pt/pttestc/ptpspprodg/ptpspprodg.sln b/xrGameSpy/gamespy/pt/pttestc/ptpspprodg/ptpspprodg.sln new file mode 100644 index 00000000000..f201118f7ab --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptpspprodg/ptpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ptpspprodg", "ptpspprodg.vcproj", "{C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = ptpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {C9B5E9BD-B1E1-4C68-AF23-2FE87BDB94CF}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/pt/pttestc/ptpspprodg/ptpspprodg.vcproj b/xrGameSpy/gamespy/pt/pttestc/ptpspprodg/ptpspprodg.vcproj new file mode 100644 index 00000000000..41354fbc133 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/ptpspprodg/ptpspprodg.vcproj @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/pt/pttestc/ptrevolutioncw/ptrevolutioncw.mcp b/xrGameSpy/gamespy/pt/pttestc/ptrevolutioncw/ptrevolutioncw.mcp new file mode 100644 index 00000000000..f028d94c668 Binary files /dev/null and b/xrGameSpy/gamespy/pt/pttestc/ptrevolutioncw/ptrevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/pt/pttestc/pttestc.c b/xrGameSpy/gamespy/pt/pttestc/pttestc.c new file mode 100644 index 00000000000..d14c678e677 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/pttestc.c @@ -0,0 +1,129 @@ +#include "../pt.h" +#include "../../ghttp/ghttp.h" +#include "../../common/gsAvailable.h" +#include "../../common/gsStringUtil.h" + +#include +#include + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define MRPANTS_UID 100001 + +#define GMTEST_GAMENAME _T("gmtest") +#define GMTEST_PID 21 +#define GMTEST_VID_0 _T("gmtest Alpha 0.01") +#define GMTEST_VID_1 _T("gmtest Alpha 0.02") +#define GMTEST_VID_2 _T("gmtest Beta 1") +#define GMTEST_VID_3 _T("gmtest Beta 2") +#define GMTEST_VID_4 _T("gmtest 1.0") +#define GMTEST_VID_5 _T("gmtest 1.1") +#define GMTEST_VID_6 _T("gmtest 2.0") + +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); + } +#endif + +static const gsi_char * BoolToString +( + PTBool b +) +{ + if(b) + return _T("Yes"); + return _T("No"); +} + +static void PatchCallback +( + PTBool available, + PTBool mandatory, + const gsi_char * versionName, + int fileID, + const gsi_char * downloadURL, + void * param +) +{ + _tprintf(_T("available = %s\n"), BoolToString(available)); + if(!available) + return; + _tprintf(_T("mandatory = %s\n"), BoolToString(mandatory)); + _tprintf(_T("versionName = %s\n"), versionName); + _tprintf(_T("fileID = %d\n"), fileID); + _tprintf(_T("downloadURL = %s\n"), downloadURL); + + GSI_UNUSED(param); +} + +#ifdef __MWERKS__ // CodeWarrior will warn if not prototyped + int test_main(int argc, char **argv); +#endif + +int test_main(int argc, char **argv) +{ + unsigned long start_time; + GSIACResult result; + +#ifdef GSI_COMMON_DEBUG + // Define GSI_COMMON_DEBUG if you want to view the SDK debug output + // Set the SDK debug log file, or set your own handler using gsSetDebugCallback + //gsSetDebugFile(stdout); // output to console + gsSetDebugCallback(DebugCallback); + + // Set some debug levels + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); + //gsSetDebugLevel(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Verbose); // Show Detailed data on network traffic + //gsSetDebugLevel(GSIDebugCat_App, GSIDebugType_All, GSIDebugLevel_Hardcore); // Show All app comment +#endif + + // check that the game's backend is available + GSIStartAvailableCheck(GMTEST_GAMENAME); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + printf("The backend is not available\n"); + return 1; + } + + if(!ptTrackUsage(MRPANTS_UID, GMTEST_PID, GMTEST_VID_0, 0, PTFalse)) + _tprintf(_T("Failed to track usage\n")); + else + _tprintf(_T("ptTrackUsage successful\n")); + + if(!ptCheckForPatch(GMTEST_PID, GMTEST_VID_1, 0, PatchCallback, PTFalse, NULL)) + _tprintf(_T("Failed to check for patch\n")); + + start_time = current_time(); + while((current_time() - start_time) < 20000) + { + ghttpThink(); + msleep(1); + } + + // Must call this to free internal memory + ghttpCleanup(); + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + return 0; +} diff --git a/xrGameSpy/gamespy/pt/pttestc/pttestc.dsp b/xrGameSpy/gamespy/pt/pttestc/pttestc.dsp new file mode 100644 index 00000000000..418523a6cd1 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/pttestc.dsp @@ -0,0 +1,392 @@ +# Microsoft Developer Studio Project File - Name="pttestc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pttestc - Win32 Unicode 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 "pttestc.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 "pttestc.mak" CFG="pttestc - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pttestc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "pttestc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "pttestc - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "pttestc - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/pt/pttestc", KCGBAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "pttestc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 wsock32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "pttestc - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_CONSOLE" /D "WIN32" /D "_DEBUG" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "pttestc - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "pttestc___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "pttestc___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "GSI_UNICODE" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 wsock32.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:console /machine:I386 +# ADD LINK32 wsock32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "pttestc - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "pttestc___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "pttestc___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_CONSOLE" /D "WIN32" /D "_DEBUG" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "pttestc - Win32 Release" +# Name "pttestc - Win32 Debug" +# Name "pttestc - Win32 Unicode Release" +# Name "pttestc - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\pttestc.c +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "PatchingTrackingSDK" + +# PROP Default_Filter "" +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\pt.h +# End Source File +# Begin Source File + +SOURCE=..\ptMain.c +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/pt/pttestc/pttestc_vs2005.vcproj b/xrGameSpy/gamespy/pt/pttestc/pttestc_vs2005.vcproj new file mode 100644 index 00000000000..25ac387c936 --- /dev/null +++ b/xrGameSpy/gamespy/pt/pttestc/pttestc_vs2005.vcproj @@ -0,0 +1,1013 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/qr2/changelog.txt b/xrGameSpy/gamespy/qr2/changelog.txt new file mode 100644 index 00000000000..42149dc2c5c --- /dev/null +++ b/xrGameSpy/gamespy/qr2/changelog.txt @@ -0,0 +1,155 @@ +Changelog for: GameSpy Query & Reporting 2 SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 3.04.00 RMV RELEASE Released to Developer Site +12-12-2007 3.03.07 DES FIX No longer overwrites the availability check if not needed. +12-10-2007 3.03.06 SAH OTHER Updated Nitro project, fixed up compilation errors in sample +12-07-2007 3.03.05 SN FIX Modified sample to use AppDebug +12-07-2007 3.03.05 SAH OTHER Added NatNeg to VC6 project to remove compiler error +11-19-2007 3.03.04 SAH FIX Changed qr2_shutdown, it now frees the negotiate list for ACE +11-05-2007 3.03.03 DES FEATURE Added clientconnected callback (ACE functionality) +08-28-2007 3.03.02 SAH FIX Removed qr2_parse_queryW, it was incorrectly trying to convert to UTF8 +08-22-2007 3.03.01 RMV OTHER Added Unicode configurations to qr2csample projects + Modified qr2csample.c to make it more thorough and developer friendly (and added ReadMe) +08-06-2007 3.03.00 RMV RELEASE Released to Developer Site +07-10-2007 3.02.03 RMV OTHER Raised qr2csample Project warning levels (to 4) and fixed compiler warnings +01-25-2007 3.02.02 SAH FIX Added COUNTRY_KEY and REGION_KEY to reserved keys list + 3.02.02 SAH FIX Added internal function for SB to check if a key is a Query-Master-Only key +01-16-2007 3.02.01 DES FEATURE Added X360 support +12-15-2006 3.02.00 MJW RELEASE Released to Developer Site +11-10-2006 3.01.34 JR RELEASE Limited release +10-23-2006 3.01.34 DES RELEASE Limited release +10-10-2006 3.01.34 DES FEATURE Added ability to call qr2_register_keyA/W directly +10-05-2006 3.01.33 SAH FIX Updated MacOSX Makefile +10-05-2006 3.01.32 DES FIX Changed method of incrementing progress->mCurKeyType to work with VS2K5 +09-28-2006 3.01.31 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-22-2006 3.01.30 SAH FIX Removed static caching of local ips - fixes bug where DCHP allocates a new ip between games +08-02-2006 3.01.29 SAH RELEASE Releasing to developer site +07-31-2006 3.01.29 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 3.01.28 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-24-2006 3.01.27 SAH FIX Removed #ifdef _PS3 for socket calls (changed platformSocket.h to typecast calls) +07-06-2006 3.01.26 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +07-06-2006 3.01.25 SAH FIX Fixed Linux makefile to work with pthreads (http asynch DNS lookups) + SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) +06-09-2006 3.01.24 MJ FEATURE Added NN_GROUP_ID_KEY for new nat negotiation SDK +06-06-2006 3.01.23 SAH FIX moved the (len<4) check for ip-verify queries into the IF block +05-31-2006 3.01.22 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-30-2006 3.01.20 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) +05-25-2006 3.01.19 SAH FIX Moved GSI_UNUSED in qr2csample + SAH FIX Changed PSP project warning levels +05-24-2006 3.01.18 SAH FIX redid previous change, added necessary #ifdefs +05-23-2006 3.01.17 SAH FIX Added gsSetDebug for PS3, and GSI_UNUSED statements to qr2csample.c +05-19-2006 3.01.16 SAH FIX Added gsTestMain.c to nitro CodeWarrior project +05-15-2006 3.01.15 SAH FIX Added "PS3 Release" configuration to project +04-25-2006 3.01.14 SAH RELEASE Releasing to developer site +04-24-2006 3.01.14 SAH FIX Fixed Nitro project files to work on build machine +04-20-2006 3.01.13 SAH FIX Commented out unnecessary variables +04-20-2006 3.01.12 SAH FIX Added _PS3 wrapper typecast for recvfrom calls +04-18-2006 3.01.11 SAH FIX Added || defined(_PS3) to qr2csample.c for PS3 support +01-27-2006 3.01.10 SN RELEASE Releasing to developer site +12-28-2005 3.01.10 SN FIX Modified test application to use new memory manager code +12-22-2005 3.01.09 SN OTHER Cleaned up project file and added missing common code files +11-15-2005 3.01.08 DES FIX Updated DS support. +11-14-2005 3.01.07 DES FIX Updated OSX support. + DES FEATURE Added GSI_DOMAIN_NAME support. +10-24-2005 3.01.06 SN FIX Fixed timer on keep alives causing them to be sent after every heartbeat +10-12-2005 3.01.06 BED RELEASE Releasing to developer site. +10-11-2005 3.01.05 BED FEATURE Added query challege/response to prevent ip spoofing. +09-21-2005 3.01.04 DES FEATURE Updated DS support +08-18-2005 3.01.03 BED CLEANUP Updated LINUX makefile for new common code and Fedora-Redhat +07-28-2005 3.01.02 SN RELEASE Releasing to developer site. +07-28-2005 3.01.02 SN FIX fixed code causing warning in qr2csample +06-03-2005 3.01.01 SN RELEASE Releasing to developer site. +05-05-2005 3.01.01 BED FIX Updated file pathes to use new common folder +05-04-2005 3.01.00 SN OTHER Created Visual Studio .NET project +04-29-2005 3.01.00 BED FEATURE Added support for multi-packet qr2 responses. (Full keys direct only) + BED FIX Individual response packets are limited to 1400 bytes (reasonable udp size) + BED FIX Heartbeats now truncated to server keys only when larger than 1400 bytes. +04-28-2005 3.00.45 SN RELEASE Releasing to developer site. +04-27-2005 3.00.45 DES RELEASE Limited release to Nintendo DS developers. +04-25-2005 3.00.45 DES CLEANUP Minor debug logging cleanup. +04-04-2005 3.00.44 SN RELEASE Releasing to developer site. +03-14-2005 3.00.44 DES FEATURE Nintendo DS support +01-27-2005 3.00.43 DES FIX Fixed custom SN sendto and moved it to nonport +09-28-2004 3.00.42 DES FIX Cleaned up an unused var warning when GSI_MEM_MANAGED was off. +09-23-2004 3.00.41 DES FIX Fixed source control issues with qr2.dsw and qr2csample.dsp. +09-16-2004 3.00.40 SN RELEASE Releasing to developer site. +09-03-2003 3.00.40 BED FEATURE Added support for GSI_COMMON_DEBUG and GSI_MEM_MANAGED modes. +08-27-2004 3.00.39 DES CLEANUP Removed MacOS style includes + DES CLEANUP Fixed warnings under OSX + DES CLEANUP Updated Win32 project configurations + DES CLEANUP General Unicode cleanup + DES FEATURE Added OSX Makefile +08-25-2004 3.00.38 DES FEATURE Added OSX makefile +08-05-2004 3.00.37 SN RELEASE Releasing to developer site. +07-19-2004 3.00.37 SN FIX Updated code with explicit casts to remove implicit cast error + when compiling at highest level and warnings treated as errors. +07-15-2004 3.00.36 BED FIX Now must manually call qr2_internal_key_list_free when using GSI_UNICODE +06-18-2004 3.00.35 BED FIX Removed confusing key name from sample. + BED FIX Added some comments to sample, cleaned up Unicode support in sample. +06-18-2004 3.00.34 BED RELEASE Releasing to developer site. + BED FIX Fixed bug with handling of "No Challenge" error + BED FEATURE Added #defines to simulate hard and soft firewalls +11-10-2003 3.00.33 DES RELEASE Releasing to developer site. +11-07-2003 3.00.33 DES FIX Updated the linux makefile. +10-27-2003 3.00.32 BED FEATURE Added CodeWarrior Unicode switch for PS2. +10-24-2003 3.00.31 BED FEATURE SendStateChanged() will now be queued instead of dropped when sent too soon. +10-24-2003 3.00.30 BED FIX Sample file updated, missing from last release due to directory mismatch + BED FIX Removed misc warnings +10-22-2003 3.00.29 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-22-2003 3.00.28 BED FIX Removed some compiler warnings on strict setting. +09-09-2003 3.00.27 BED FEATURE Added UTF-8 wrapper -- define GSI_UNICODE + OTHER Added stringutil.c and stringutil.h to sample project files +08-25-2003 3.00.26 DES FIX Updated to be compatible with new public IP and port encoding. +08-18-2003 3.00.25 DES FEATURE Added a callback for getting your public reporting address. +07-24-2003 3.00.24 DES RELEASE Releasing to developer site. +07-21-2003 3.00.24 BED FIX Moved VisualStudio workspace into appropriate directory. +07-18-2003 3.00.23 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 3.00.22 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 3.00.21 DES FIX Changed a __mips64 check to a _PS2 check. + BED FEATURE Added ProDG sample project files. +06-11-2003 3.00.20 DES RELEASE Releasing to developer site. +05-09-2003 3.00.20 DES CLEANUP Removed Dreamcast support. + FIX Metrowerks for Win32 is no longer falsely identified as MacOS. +05-07-2003 3.00.19 DES RELEASE Releasing to developer site. +05-06-2003 3.00.19 DES FIX Old style replies were not correctly handling callbacks that didn't add a value. +04-07-2003 3.00.18 DES FIX Fixed the PID__KEY define (changed to 27 from 26). +03-11-2003 3.00.17 DES OTHER Split socket creation into a seperate internal function, needed for Peer. +02-28-2003 3.00.16 DES RELEASE Releasing to developer site. +02-27-2003 3.00.16 DES FIX If not using NULL as the qr2_t parameter, qr2_shutdown() would access + the structure after it was freed. +02-05-2003 3.00.15 DES RELEASE Releasing to developer site. +02-05-2003 3.00.15 DES CLEANUP Switched to use CanReceiveOnSocket instead of select. +02-04-2003 3.00.14 DES RELEASE Relasing to developer site. +02-04-2003 3.00.14 DDW FIX Added an extra \ to the "final" key in the GOA-style reply to fix illegal format +01-31-2003 3.00.13 DES FEATURE Added a check which adds an empty string to the buffer if nothing was added in + a call to the server_key_callback, player_key_callback, or team_key_callback. + Apps no longer need to handle the case of an unrecognized key. +01-20-2003 3.00.12 DES OTHER Changed to use new .master.gamespy.com master server naming convention. +01-16-2003 3.00.11 JED OTHER renamed a static var in qr2.c that was causing linker name conflicts in GS Arcade +01-06-2003 3.00.10 DES OTHER Moved a few things from qr2.c to qr2.h for CDKey SDK integration. +12-19-2002 3.00.09 DES RELEASE Releasing to developer site. +12-19-2002 3.00.09 DES CLEANUP Removed assert.h include. +12-16-2002 3.00.08 DES FEATURE Added a check to prevent statechanges from being sent too frequently. + This is to help alleviate the problem of servers that flood our master server. +12-13-2002 3.00.07 DES FEATURE Added PS2 eenet stack support. +12-11-2002 3.00.06 DES CLEANUP Changed from using gethostname to getlocalhost for getting local IPs. +12-06-2002 3.00.05 DES RELEASE Releasing to developer site. +12-06-2002 3.00.05 DDW FIX Added new heartbeat type so that if restarting a crashed server + the nochallenge error will not be triggered. +12-03-2002 3.00.04 DES RELEASE Releasing to developer site. +12-03-2002 3.00.04 DES FEATURE Added a Linux Makefile. +11-22-2002 3.00.03 DES RELEASE Releasing to developer site. +11-20-2002 3.00.03 DES FIX Only call SocketShutDown if we called SocketStartup. +11-20-2002 3.00.02 DES FEATURE Added support for compiling on the PS2. +09-26-2002 3.00.01 DES RELEASE Limited release on developer site +09-25-2002 3.00.01 DDW OTHER Changelog started +09-23-2002 3.00.01 DDW RELEASE Release to EAPAC for Generals (Peer) +09-18-2002 3.00.01 DDW RELEASE Release to EAPAC for Generals +09-18-2002 3.00.01 DDW FEATURE Added 20-sec keep-alive packets +09-06-2002 3.00.00 DDW RELEASE Release to EAPAC for Generals + diff --git a/xrGameSpy/gamespy/qr2/qr2.c b/xrGameSpy/gamespy/qr2/qr2.c new file mode 100644 index 00000000000..4918dc98d81 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2.c @@ -0,0 +1,1753 @@ +/******** +INCLUDES +********/ +#include "../common/gsCommon.h" +#include "../common/gsAvailable.h" +#include "qr2.h" +#include "qr2regkeys.h" +#include "../natneg/natneg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __MWERKS__ // Codewarrior requires function prototypes +qr2_error_t qr2_initW(/*[out]*/qr2_t *qrec, const unsigned short *ip, int baseport, const unsigned short *gamename, + const unsigned short *secret_key, int ispublic, int natnegotiate, qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, qr2_playerteamkeycallback_t team_key_callback, qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, qr2_adderrorcallback_t adderror_callback, void *userdata); +qr2_error_t qr2_init_socketW(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const unsigned short *gamename, + const unsigned short *secret_key, int ispublic, int natnegotiate, qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, qr2_playerteamkeycallback_t team_key_callback, qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, qr2_adderrorcallback_t adderror_callback, void *userdata); +qr2_error_t qr2_init_socketA(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const char *gamename, const char *secret_key, + int ispublic, int natnegotiate, qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, void *userdata); +qr2_error_t qr2_initA(/*[out]*/qr2_t *qrec, const char *ip, int baseport, const char *gamename, const char *secret_key, + int ispublic, int natnegotiate, qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, void *userdata); +#endif + +/******** +DEFINES +********/ +#define MASTER_PORT 27900 +#define MASTER_ADDR "master." GSI_DOMAIN_NAME + //#define MASTER_ADDR "207.199.80.230" +#define FIRST_HB_TIME 10000 /* 10 sec */ +#define HB_TIME 60000 /* 1 minute */ +#define KA_TIME 20000 /* 20 sec */ +#define MIN_STATECHANGED_HB_TIME 10000 /* 10 sec */ +#define MAX_FIRST_COUNT 4 /* 4 tries */ +#define MAX_DATA_SIZE 1400 +#define INBUF_LEN 256 +#define PUBLIC_ADDR_LEN 12 +#define QR2_OPTION_USE_QUERY_CHALLENGE 128 + +#define PACKET_QUERY 0x00 +#define PACKET_CHALLENGE 0x01 +#define PACKET_ECHO 0x02 +#define PACKET_ECHO_RESPONSE 0x05 // 0x05, not 0x03 (order) +#define PACKET_HEARTBEAT 0x03 +#define PACKET_ADDERROR 0x04 +#define PACKET_CLIENT_MESSAGE 0x06 +#define PACKET_CLIENT_MESSAGE_ACK 0x07 +#define PACKET_KEEPALIVE 0x08 +#define PACKET_PREQUERY_IP_VERIFY 0x09 + + +#define MAX_LOCAL_IP 5 + +//magic bytes for nat negotiation message +#define NATNEG_MAGIC_LEN 6 +#define NN_MAGIC_0 0xFD +#define NN_MAGIC_1 0xFC +#define NN_MAGIC_2 0x1E +#define NN_MAGIC_3 0x66 +#define NN_MAGIC_4 0x6A +#define NN_MAGIC_5 0xB2 + +// ex flags are the 11th byte in the query packet +// Old queries will end at 10 bytes. +#define QR2_EXFLAG_SPLIT (1<<0) + +// Some other settings for split packet responses +#define QR2_SPLITNUM_MAX 7 +#define QR2_SPLITNUM_FINALFLAG (1<<7) + + +/******** +TYPEDEFS +********/ +typedef unsigned char uchar; + +struct qr2_keybuffer_s +{ + uchar keys[MAX_REGISTERED_KEYS]; + int numkeys; +}; + +struct qr2_buffer_s +{ + char buffer[MAX_DATA_SIZE]; + int len; +}; + +#define AVAILABLE_BUFFER_LEN(a) (MAX_DATA_SIZE - (a)->len) + +/******** +VARS +********/ +struct qr2_implementation_s static_qr2_rec = {INVALID_SOCKET}; +static qr2_t current_rec = &static_qr2_rec; +char qr2_hostname[64]; + +static int num_local_ips = 0; +static struct in_addr local_ip_list[MAX_LOCAL_IP]; + + +/******** +PROTOTYPES +********/ +static void send_heartbeat(qr2_t qrec, int statechanged); +static void send_keepalive(qr2_t qrec); +static int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent); +static void qr2_check_queries(qr2_t qrec); +static void qr2_check_send_heartbeat(qr2_t qrec); +static void enum_local_ips(); +static void qr2_expire_ip_verify(qr2_t qrec); +qr2_error_t qr2_create_socket(/*[out]*/SOCKET *sock, const char *ip, /*[in/out]*/int * port); + +/****************************************************************************/ +/* PUBLIC FUNCTIONS */ +/****************************************************************************/ + +/* qr2_init: Initializes the sockets, etc. Returns an error value +if an error occured, or 0 otherwise */ +qr2_error_t qr2_init_socketA(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const char *gamename, const char *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata) +{ + char hostname[64]; + int ret; + int i; + qr2_t cr; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_init_socket()\r\n"); + + if (qrec == NULL) + { + cr = &static_qr2_rec; + } + else + { + *qrec = (qr2_t)gsimalloc(sizeof(struct qr2_implementation_s)); + cr = *qrec; + } + srand((unsigned int)current_time()); + strcpy(cr->gamename,gamename); + strcpy(cr->secret_key,secret_key); + cr->qport = boundport; + cr->lastheartbeat = 0; + cr->lastka = 0; + cr->hbsock = s; + cr->listed_state = 1; + cr->udata = userdata; + cr->server_key_callback = server_key_callback; + cr->player_key_callback = player_key_callback; + cr->team_key_callback = team_key_callback; + cr->key_list_callback = key_list_callback; + cr->playerteam_count_callback = playerteam_count_callback; + cr->adderror_callback = adderror_callback; + cr->nn_callback = NULL; + cr->cm_callback = NULL; + cr->cdkeyprocess = NULL; + cr->ispublic = ispublic; + cr->read_socket = 0; + cr->nat_negotiate = natnegotiate; + cr->publicip = 0; + cr->publicport = 0; + cr->pa_callback = NULL; + cr->cc_callback = NULL; + cr->userstatechangerequested = 0; + cr->backendoptions = 0; + + for (i = 0 ; i < REQUEST_KEY_LEN ; i++) + cr->instance_key[i] = (char)(rand() % 0xFF); + for (i = 0 ; i < RECENT_CLIENT_MESSAGES_TO_TRACK ; i++) + cr->client_message_keys[i] = -1; + cr->cur_message_key = 0; + + memset(cr->ipverify, 0, sizeof(cr->ipverify)); + + //if (num_local_ips == 0) - caching IPs can result in problems if DHCP has allocated a new one + enum_local_ips(); + + if (ispublic) + { + int override = qr2_hostname[0]; + if(!override) + sprintf(hostname, "%s.master." GSI_DOMAIN_NAME, gamename); + ret = get_sockaddrin(override?qr2_hostname:hostname, MASTER_PORT, &(cr->hbaddr), NULL); + + if (ret == 1) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "%s resolved to %s\r\n", override?qr2_hostname:hostname, inet_ntoa(cr->hbaddr.sin_addr)); + } + else + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_HotError, + "Failed on DNS lookup for %s \r\n", override?qr2_hostname:hostname); + } + } + else //don't need to look up + ret = 1; + if (!ret) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_HotError, + "qr2_init_socket() returned failed (DNS error)\r\n"); + return e_qrdnserror; + } + else + { + return e_qrnoerror; + } + + +} + +qr2_error_t qr2_init_socketW(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const unsigned short *gamename, const unsigned short *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata) +{ + char gamename_A[255]; + char secretkey_A[255]; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_init_socketW()\r\n"); + + UCS2ToAsciiString(gamename, gamename_A); + UCS2ToAsciiString(secret_key, secretkey_A); + + return qr2_init_socketA(qrec, s, boundport, gamename_A, secretkey_A, ispublic, natnegotiate, + server_key_callback, player_key_callback, team_key_callback, + key_list_callback, playerteam_count_callback, adderror_callback, userdata); +} + +qr2_error_t qr2_create_socket(/*[out]*/SOCKET *sock, const char *ip, /*[in/out]*/int * port) +{ + struct sockaddr_in saddr; + SOCKET hbsock; + int maxport; + int lasterror = 0; + int baseport = *port; + +#if defined(_LINUX) + unsigned int saddrlen; +#else + int saddrlen; +#endif + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_create_socket()\r\n"); + + SocketStartUp(); + + hbsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (INVALID_SOCKET == hbsock) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_HotError, + "Failed to create heartbeat socket\r\n"); + return e_qrwsockerror; + } + + maxport = baseport + NUM_PORTS_TO_TRY; + while (baseport < maxport) + { + get_sockaddrin(ip,baseport,&saddr,NULL); + if (saddr.sin_addr.s_addr == htonl(0x7F000001)) //localhost -- we don't want that! + saddr.sin_addr.s_addr = INADDR_ANY; + + lasterror = bind(hbsock, (struct sockaddr *)&saddr, sizeof(saddr)); + if (lasterror == 0) + break; //we found a port + baseport++; + } + + if (lasterror != 0) //we weren't able to find a port + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_HotError, + "Failed to bind() query socket\r\n"); + return e_qrbinderror; + } + + if (baseport == 0) //we bound it dynamically + { + saddrlen = sizeof(saddr); + + lasterror = getsockname(hbsock,(struct sockaddr *)&saddr, &saddrlen); + + if (lasterror) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_HotError, + "Query socket bind() success, but getsockname() failed\r\n"); + return e_qrbinderror; + } + baseport = ntohs(saddr.sin_port); + } + + *sock = hbsock; + *port = baseport; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Query socket created and bound to port %d\r\n", *port); + + return e_qrnoerror; +} + +qr2_error_t qr2_initA(/*[out]*/qr2_t *qrec, const char *ip, int baseport, const char *gamename, const char *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata) +{ + SOCKET hbsock; + qr2_error_t ret; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_init()\r\n"); + + ret = qr2_create_socket(&hbsock, ip, &baseport); + if(ret != e_qrnoerror) + { + SocketShutDown(); + return ret; + } + + ret = qr2_init_socketA(qrec, hbsock, baseport, gamename, secret_key, ispublic, natnegotiate, server_key_callback, player_key_callback, team_key_callback, key_list_callback, playerteam_count_callback, adderror_callback, userdata); + if (qrec == NULL) + qrec = ¤t_rec; + (*qrec)->read_socket = 1; + + return ret; +} + +qr2_error_t qr2_initW(/*[out]*/qr2_t *qrec, const unsigned short *ip, int baseport, const unsigned short *gamename, const unsigned short *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata) +{ + char ip_A[255]; + char gamename_A[255]; + char secretkey_A[255]; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_initW()\r\n"); + + if (ip != NULL) // NULL value is valid for IP + UCS2ToAsciiString(ip, ip_A); + UCS2ToAsciiString(gamename, gamename_A); + UCS2ToAsciiString(secret_key, secretkey_A); + + return qr2_initA(qrec, (ip!=NULL)?ip_A:NULL, baseport, gamename_A, secretkey_A, ispublic, natnegotiate, server_key_callback, player_key_callback, team_key_callback, key_list_callback, playerteam_count_callback, adderror_callback, userdata); +} + +void qr2_register_natneg_callback(qr2_t qrec, qr2_natnegcallback_t nncallback) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_natneg_callback()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + qrec->nn_callback = nncallback; + +} +void qr2_register_clientmessage_callback(qr2_t qrec, qr2_clientmessagecallback_t cmcallback) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_clientmessage_callback()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + qrec->cm_callback = cmcallback; +} +void qr2_register_publicaddress_callback(qr2_t qrec, qr2_publicaddresscallback_t pacallback) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_publicaddress_callback()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + qrec->pa_callback = pacallback; +} +void qr2_register_clientconnected_callback(qr2_t qrec, qr2_clientconnectedcallback_t cccallback) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_clientconnected_callback()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + qrec->cc_callback = cccallback; +} + +void qr2_register_denyresponsetoip_callback(qr2_t qrec, qr2_denyqr2responsetoipcallback_t dertoipcallback) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_denyresponsetoip_callback()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + qrec->denyresp2_ip_callback = dertoipcallback; +} + + +/* qr2_think: Processes any waiting queries, and sends a +heartbeat if needed */ +void qr2_think(qr2_t qrec) +{ + if (qrec == NULL) + qrec = current_rec; + if (qrec->ispublic) + qr2_check_send_heartbeat(qrec); + qr2_check_queries(qrec); + qr2_expire_ip_verify(qrec); + NNThink(); +} + +/* qr2_check_queries: Processes any waiting queries */ +void qr2_check_queries(qr2_t qrec) +{ + static char indata[INBUF_LEN]; //256 byte input buffer + struct sockaddr_in saddr; + int error; + +#if defined(_LINUX) + unsigned int saddrlen = sizeof(struct sockaddr_in); +#else + int saddrlen = sizeof(struct sockaddr_in); +#endif + + if (!qrec->read_socket) + return; //not our job + + while(CanReceiveOnSocket(qrec->hbsock)) + { + //else we have data + error = (int)recvfrom(qrec->hbsock, indata, (INBUF_LEN - 1), 0, (struct sockaddr *)&saddr, &saddrlen); + + if (gsiSocketIsNotError(error)) + { + indata[error] = '\0'; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Received %d bytes on query socket\r\n", error); + gsDebugBinary(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_RawDump, + indata, error); + + qr2_parse_queryA(qrec, indata, error, (struct sockaddr *)&saddr); + } + else if (error == 0) + { + // socket closed? + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "CanReceiveOnSocket() returned true, but recvfrom return 0!\r\n", error); + } + else + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "CanReceiveOnSocket() returned true, but recvfrom failed!\r\n", error); + } + } +} + +/* check_send_heartbeat: Perform any scheduled outgoing +heartbeats */ +void qr2_check_send_heartbeat(qr2_t qrec) +{ + gsi_time tc = current_time(); + + if (INVALID_SOCKET == qrec->hbsock) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "HBSock is invalid\r\n"); + return; //no sockets to work with! + } + + //check if we need to send a heartbet + if (qrec->listed_state > 0 && tc - qrec->lastheartbeat > FIRST_HB_TIME) + { //check to see if we haven't gotten a query yet + if (qrec->listed_state >= MAX_FIRST_COUNT) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_HotError, + "No response from master, generating NoChallengeResponse error\r\n"); + + qrec->listed_state = 0; //we failed to get a challenge! let them know +#ifndef GSI_UNICODE + qrec->adderror_callback(e_qrnochallengeerror, "No challenge value was received from the master server.", qrec->udata); +#else + qrec->adderror_callback(e_qrnochallengeerror, L"No challenge value was received from the master server.", qrec->udata); +#endif + return; + } else + { + send_heartbeat(qrec, 3); + qrec->listed_state++; + } + } + else if (qrec->userstatechangerequested && (tc - qrec->lastheartbeat > MIN_STATECHANGED_HB_TIME)) + send_heartbeat(qrec,1); // Send out pending statechange request + else if (tc - qrec->lastheartbeat > HB_TIME || qrec->lastheartbeat == 0 || tc < qrec->lastheartbeat) + send_heartbeat(qrec,0); // Send out a normal hearbeat + + if (current_time() - qrec->lastka > KA_TIME) //send a keep alive (to keep NAT port mappings the same if possible) + send_keepalive(qrec); +} + +/* qr2_send_statechanged: Sends a statechanged heartbeat, call when +your gamemode changes */ +void qr2_send_statechanged(qr2_t qrec) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_send_statechanged()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + if (!qrec->ispublic) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_Warning, + "Requested send statechange for LAN game, discarding\r\n"); + return; + } + if (current_time() - qrec->lastheartbeat < MIN_STATECHANGED_HB_TIME) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_Notice, + "Queing statechange for later send (too soon)\r\n"); + + // Queue up the statechange and send later + qrec->userstatechangerequested = 1; + return; // don't allow the server to spam statechanges + } + + send_heartbeat(qrec, 1); + qrec->userstatechangerequested = 0; // clear the flag in case a queued statechange was still pending +} + + +/* qr2_shutdown: Cleans up the sockets and shuts down */ +void qr2_shutdown(qr2_t qrec) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_StackTrace, + "qr2_shutdown()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + if (qrec->ispublic) + send_heartbeat(qrec, 2); + if (INVALID_SOCKET != qrec->hbsock && qrec->read_socket) //if we own the socket + { + closesocket(qrec->hbsock); + } + qrec->hbsock = INVALID_SOCKET; + qrec->lastheartbeat = 0; + if(qrec->read_socket) //if we own the socket + { + SocketShutDown(); + } + if (qrec != &static_qr2_rec) //need to gsifree it, it was dynamically allocated + { + gsifree(qrec); + } + + // free ACE negotiate list + NNFreeNegotiateList(); //comment out if ACE is not being used + + // BD: Removed - Peer SDK repeatedly calls qr2_shutdown, but + // keys should only be deallocated once. + + // Developers should call this manually (when in GSI_UNICODE mode) + // qr2_internal_key_list_free(); +} + + +gsi_bool qr2_keybuffer_add(qr2_keybuffer_t keybuffer, int keyid) +{ + // mj these are codetime not runtime errors, changing to assert + if (keybuffer->numkeys >= MAX_REGISTERED_KEYS) + return gsi_false; + if (keyid < 1 || keyid > MAX_REGISTERED_KEYS) + return gsi_false; + + keybuffer->keys[keybuffer->numkeys++] = (uchar)keyid; + return gsi_true; +} + +gsi_bool qr2_buffer_add_int(qr2_buffer_t outbuf, int value) +{ + char temp[20]; + sprintf(temp, "%d", value); + return qr2_buffer_addA(outbuf, temp); +} + +gsi_bool qr2_buffer_addA(qr2_buffer_t outbuf, const char *value) +{ + GS_ASSERT(outbuf) + GS_ASSERT(value) + { + int copylen; + copylen = (int)strlen(value) + 1; + if (copylen > AVAILABLE_BUFFER_LEN(outbuf)) + copylen = AVAILABLE_BUFFER_LEN(outbuf); //max length we can fit in the buffer + if (copylen <= 0) + return gsi_false; //no space + memcpy(outbuf->buffer + outbuf->len, value, (unsigned int)copylen); + outbuf->len += copylen; + outbuf->buffer[outbuf->len - 1] = 0; //make sure it's null terminated + return gsi_true; + } +} +#if defined(GSI_UNICODE) +gsi_bool qr2_buffer_addW(qr2_buffer_t outbuf, const unsigned short *value) +{ + char value_A[4096]; + UCS2ToUTF8String(value, value_A); + return qr2_buffer_addA(outbuf, value_A); +} +#endif + + +static void enum_local_ips() +{ + struct hostent *phost; + phost = getlocalhost(); + if (phost == NULL) + return; + for (num_local_ips = 0 ; num_local_ips < MAX_LOCAL_IP ; num_local_ips++) + { + if (phost->h_addr_list[num_local_ips] == 0) + break; + memcpy(&local_ip_list[num_local_ips], phost->h_addr_list[num_local_ips], sizeof(struct in_addr)); + } +} + +/****************************************************************************/ + + +/* Return a sockaddrin for the given host (numeric or DNS) and port) +Returns the hostent in savehent if it is not NULL */ +static int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent) +{ + struct hostent *hent = NULL; + + saddr->sin_family = AF_INET; + saddr->sin_port = htons((unsigned short)port); + if (host == NULL) + saddr->sin_addr.s_addr = INADDR_ANY; + else + saddr->sin_addr.s_addr = inet_addr(host); + + if (saddr->sin_addr.s_addr == INADDR_NONE && strcmp(host,"255.255.255.255") != 0) + { + hent = gethostbyname(host); + if (!hent) + return 0; + saddr->sin_addr.s_addr = *(unsigned int *)hent->h_addr_list[0]; + } + if (savehent != NULL) + *savehent = hent; + return 1; + +} + + + +/*****************************************************************************/ +/* Various encryption / encoding routines */ + +static void swap_byte ( uchar *a, uchar *b ) +{ + uchar swapByte; + + swapByte = *a; + *a = *b; + *b = swapByte; +} + +static uchar encode_ct ( uchar c ) +{ + if (c < 26) return (uchar)('A'+c); + if (c < 52) return (uchar)('a'+c-26); + if (c < 62) return (uchar)('0'+c-52); + if (c == 62) return (uchar)('+'); + if (c == 63) return (uchar)('/'); + + return 0; +} + +static void gs_encode ( uchar *ins, int size, uchar *result ) +{ + int i,pos; + uchar trip[3]; + uchar kwart[4]; + + i=0; + while (i < size) + { + for (pos=0 ; pos <= 2 ; pos++, i++) + if (i < size) trip[pos] = *ins++; + else trip[pos] = '\0'; + kwart[0] = (unsigned char)( (trip[0]) >> 2); + kwart[1] = (unsigned char)((((trip[0]) & 3) << 4) + ((trip[1]) >> 4)); + kwart[2] = (unsigned char)((((trip[1]) & 15) << 2) + ((trip[2]) >> 6)); + kwart[3] = (unsigned char)( (trip[2]) & 63); + for (pos=0; pos <= 3; pos++) *result++ = encode_ct(kwart[pos]); + } + *result='\0'; +} + +static void gs_encrypt ( uchar *key, int key_len, uchar *buffer_ptr, int buffer_len ) +{ + short counter; + uchar x, y, xorIndex; + uchar state[256]; + + for ( counter = 0; counter < 256; counter++) state[counter] = (uchar) counter; + + x = 0; y = 0; + for ( counter = 0; counter < 256; counter++) + { + y = (uchar)((key[x] + state[counter] + y) % 256); + x = (uchar)((x + 1) % key_len); + swap_byte ( &state[counter], &state[y] ); + } + + x = 0; y = 0; + for ( counter = 0; counter < buffer_len; counter ++) + { + x = (uchar)((x + buffer_ptr[counter] + 1) % 256); + y = (uchar)((state[x] + y) % 256); + swap_byte ( &state[x], &state[y] ); + xorIndex = (uchar)((state[x] + state[y]) % 256); + buffer_ptr[counter] ^= state[xorIndex]; + } +} + +/*****************************************************************************/ +/* NAT Negotiation support */ + +static void NatNegProgressCallback(NegotiateState state, void *userdata) +{ + // we don't do anything here + GSI_UNUSED(state); + GSI_UNUSED(userdata); +} + +static void NatNegCompletedCallback(NegotiateResult result, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata) +{ + qr2_t qrec = (qr2_t)userdata; + + if(qrec->cc_callback) + { + if(result == nr_success) + { + qrec->cc_callback(gamesocket, remoteaddr, qrec->udata); + } + } +} + +/*****************************************************************************/ + + +static void qr_add_packet_header(qr2_buffer_t buf, char ptype, char *reqkey) +{ + buf->buffer[0] = ptype; + memcpy(buf->buffer + 1, reqkey, REQUEST_KEY_LEN); + buf->len = REQUEST_KEY_LEN + 1; +} + +#define MAX_CHALLENGE 64 +static void compute_challenge_response(qr2_t qrec, qr2_buffer_t buf, char *challenge, int challengelen) +{ + char encrypted_val[MAX_CHALLENGE + 1]; //don't need to null terminate + + if(challengelen < 1) + return; // invalid, need room for the NUL + if (challengelen > (MAX_CHALLENGE + 1)) + return; //invalid + if (challenge[challengelen - 1] != 0) + return; //invalid - must be NTS + + strcpy(encrypted_val, challenge); + gs_encrypt((uchar *)qrec->secret_key, (int)strlen(qrec->secret_key), (uchar *)encrypted_val, challengelen - 1); + gs_encode((uchar *)encrypted_val,challengelen - 1, (uchar *)(buf->buffer + buf->len)); + buf->len += (int)strlen(buf->buffer + buf->len) + 1; + +} + +static void handle_public_address(qr2_t qrec, char * buffer) +{ + unsigned int ip; + unsigned int portTemp; + unsigned short port; + + // get the public ip and port as the master server sees it + sscanf(buffer, "%08X%04X", &ip, &portTemp); + port = (unsigned short)portTemp; + ip = htonl(ip); + + // sanity check + if((ip == 0) || (port == 0)) + return; + +#ifdef GSI_COMMON_DEBUG + { + IN_ADDR addr; + addr.s_addr = ip; + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Received public address (%s:%d)\r\n", inet_ntoa(addr), port); + } +#endif + + // has anything changed? + if((qrec->publicip != ip) || (qrec->publicport != port)) + { + qrec->publicip = ip; + qrec->publicport = port; + qrec->pa_callback(ip, port, qrec->udata); + } +} + +static void qr_build_partial_query_reply(qr2_t qrec, qr2_buffer_t buf, qr2_key_type keytype, int keycount, uchar *keys) +{ + struct qr2_keybuffer_s kb; + int playerteamcount; + unsigned short cttemp; + int i; + int pindex; + const char *k; + int len; + + kb.numkeys = 0; + if (keycount == 0) + return; //no keys wanted + + if (keytype == key_player || keytype == key_team) //need to add the player/team counts + { + if (AVAILABLE_BUFFER_LEN(buf) < sizeof(cttemp)) + return; //no more space + playerteamcount = qrec->playerteam_count_callback(keytype, qrec->udata); + cttemp = htons((unsigned short)playerteamcount); + memcpy(buf->buffer + buf->len, &cttemp, sizeof(cttemp)); + buf->len += sizeof(cttemp); + } else + playerteamcount = 1; + + if (keycount == 0xFF) //need to get the list of keys + { + qrec->key_list_callback(keytype, &kb, qrec->udata); + //add all the keys + for (i = 0 ; i < kb.numkeys ; i++) + { + k = qr2_registered_key_list[kb.keys[i]]; + if (k == NULL) + k = "unknown"; + qr2_buffer_addA(buf, k); + if (keytype == key_server) //add the server values + { + len = buf->len; + qrec->server_key_callback(kb.keys[i], buf, qrec->udata); + if(len == buf->len) + qr2_buffer_addA(buf, ""); + } + } + //add an extra null + if (AVAILABLE_BUFFER_LEN(buf) < 1) + return; //no space + buf->buffer[buf->len++] = 0; + keycount = kb.numkeys; + keys = kb.keys; + if (keytype == key_server) + return; //already added the keys + } + for (pindex = 0 ; pindex < playerteamcount ; pindex++) + { + for (i = 0 ; i < keycount ; i++) + { + len = buf->len; + if (keytype == key_server) //add the server keys + qrec->server_key_callback(keys[i], buf, qrec->udata); + else if (keytype == key_player) + qrec->player_key_callback(keys[i], pindex, buf, qrec->udata); + else if (keytype == key_team) + qrec->team_key_callback(keys[i], pindex, buf, qrec->udata); + if(len == buf->len) + qr2_buffer_addA(buf, ""); + } + } +} + +static void qr_build_query_reply(qr2_t qrec, qr2_buffer_t buf, int serverkeycount, uchar *serverkeys, int playerkeycount, uchar *playerkeys, int teamkeycount, uchar *teamkeys) +{ + qr_build_partial_query_reply(qrec, buf, key_server, serverkeycount, serverkeys); + qr_build_partial_query_reply(qrec, buf, key_player, playerkeycount, playerkeys); + qr_build_partial_query_reply(qrec, buf, key_team, teamkeycount, teamkeys); +} + + +struct QRSplitQueryProgress +{ + qr2_key_type mCurKeyType; + int mCurPacketNum; + int mCurKeyIndex; // serverkey index, playerkey index, teamkey index + int mCurSubCount; // number of players or number of teams + int mCurSubIndex; // current player num or current team num + struct qr2_keybuffer_s mKeyBuffer; // keybuffer, for key name indexing +}; + + +// return values: +// gsi_true = send buffer, then call this function again +// gsi_false = don't send buffer, don't call this function again +static gsi_bool qr_build_split_query_reply(qr2_t qrec, qr2_buffer_t buf, struct QRSplitQueryProgress* progress) +{ + unsigned char* packetNumPos = NULL; // Used to store the byte position of the packet number + + // Make sure the key type is valid + // (The key type is set to invalid when all keys have been processed.) + //if (progress->mCurKeyType < 0 ||progress->mCurKeyType >= key_type_count) + if (progress->mCurKeyType >= key_type_count) + return gsi_false; // stop processing + + // check buffer space + // (buffer should only contain header at this point) + if (AVAILABLE_BUFFER_LEN(buf) < 32) + return gsi_false; // no space? + + // Dump the split packet "header" + qr2_buffer_addA(buf, "splitnum"); + packetNumPos = (unsigned char*)&buf->buffer[buf->len++]; + *packetNumPos = (gsi_u8)progress->mCurPacketNum++; + + // Resume dumping at key_type level + while (progress->mCurKeyType < key_type_count) + { + // Get the list of keys if we don't have it already + if (progress->mKeyBuffer.numkeys == 0) + qrec->key_list_callback(progress->mCurKeyType, &progress->mKeyBuffer, qrec->udata); + + // Get the list of players/teams if we don't have it already + if (progress->mCurSubCount == 0 && progress->mCurKeyType != key_server) + progress->mCurSubCount = qrec->playerteam_count_callback(progress->mCurKeyType, qrec->udata); + + // check buffer space + if (AVAILABLE_BUFFER_LEN(buf) < 100) + return gsi_true; //no space + + // Write the key type + buf->buffer[buf->len++] = (char)progress->mCurKeyType; + + // For each key + while(progress->mCurKeyIndex < progress->mKeyBuffer.numkeys) + { + // check buffer space + int aRegisteredKeyIndex = progress->mKeyBuffer.keys[progress->mCurKeyIndex]; + const char* aKeyName = qr2_registered_key_list[aRegisteredKeyIndex]; + + // Write the key name + if (gsi_is_false( qr2_buffer_addA(buf,aKeyName) )) + return gsi_true; // send, then try again + + if (progress->mCurKeyType == key_server) + { + // write the key value + qrec->server_key_callback(aRegisteredKeyIndex, buf, qrec->udata); + + // make sure the key was written + if (AVAILABLE_BUFFER_LEN(buf) < 1) + return gsi_true; //ran out of space! retry this key/value next packet + } + else + { + if (AVAILABLE_BUFFER_LEN(buf) < 1) + return gsi_true; //ran out of space, retry this key/value next packet + + // Non-split packets implicitly being with player/team number zero, + // split packet explicitly specify the starting number + buf->buffer[buf->len++] = (char)progress->mCurSubIndex; + + // For each player/team + while(progress->mCurSubIndex < progress->mCurSubCount) + { + // dump the value into the buffer + if (progress->mCurKeyType == key_player) + qrec->player_key_callback(aRegisteredKeyIndex, progress->mCurSubIndex, buf, qrec->udata); + else if (progress->mCurKeyType == key_team) + qrec->team_key_callback(aRegisteredKeyIndex, progress->mCurSubIndex, buf, qrec->udata); + + // make sure the key was written + if (AVAILABLE_BUFFER_LEN(buf) < 1) + return gsi_true; //ran out of space, try again next packet + + // move onto the next player/team value + progress->mCurSubIndex++; + } + // append a null to signify end of this team/player key + if (AVAILABLE_BUFFER_LEN(buf) > 0) + buf->buffer[buf->len++] = '\0'; + } + // move onto next key + progress->mCurKeyIndex++; + progress->mCurSubIndex = 0; + } + + // append a null to signify end of this key_type section + if (AVAILABLE_BUFFER_LEN(buf) > 0) + buf->buffer[buf->len++] = '\0'; + + // Move onto next key type + progress->mCurKeyType = (qr2_key_type)(progress->mCurKeyType + 1); + progress->mCurKeyIndex = 0; + progress->mCurSubCount = 0; + progress->mCurSubIndex = 0; + progress->mKeyBuffer.numkeys = 0; + } + + // Add the "final" flag to the packet number + *packetNumPos |= QR2_SPLITNUM_FINALFLAG; + return gsi_true; // function will bail without sending next iteration +} + +static void qr_process_query(qr2_t qrec, qr2_buffer_t buf, uchar *qdata, int len, struct sockaddr* sender) +{ + uchar serverkeycount; + uchar playerkeycount; + uchar teamkeycount; + uchar exflags = 0; + + uchar *serverkeys = NULL; + uchar *playerkeys = NULL; + uchar *teamkeys = NULL; + if (len < 3) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Discarding invalid query (too short#1: %d bytes total)\r\n", len); + return; //invalid + } + serverkeycount = qdata[0]; + qdata++; + len--; + if (serverkeycount != 0 && serverkeycount != 0xFF) + { + serverkeys = qdata; + qdata += serverkeycount; + len -= serverkeycount; + } + if (len < 2) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Discarding invalid query (too short#2: %d bytes remain)\r\n", len); + return; //invalid + } + playerkeycount = qdata[0]; + qdata++; + len--; + if (playerkeycount != 0 && playerkeycount != 0xFF) + { + playerkeys = qdata; + qdata += playerkeycount; + len -= playerkeycount; + } + if (len < 1) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Discarding invalid query (too short#3: %d bytes remain)\r\n", len); + return; //invalid + } + teamkeycount = qdata[0]; + qdata++; + len--; + if (teamkeycount != 0 && teamkeycount != 0xFF) + { + teamkeys = qdata; + qdata += teamkeycount; + len -= teamkeycount; + } + if (len < 0) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Discarding invalid query (too short#4: %d bytes remain)\r\n", len); + return; //invalid + } + + // check the exflags + if (len > 0) + { + exflags = qdata[0]; + len--; + } + + // Support split queries? + if ((exflags & QR2_EXFLAG_SPLIT)==QR2_EXFLAG_SPLIT) + { + struct QRSplitQueryProgress progress; + progress.mCurPacketNum = 0; + progress.mCurKeyType = key_server; + progress.mCurKeyIndex = 0; + progress.mCurSubCount = 0; + progress.mCurSubIndex = 0; + progress.mKeyBuffer.numkeys = 0; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Building query reply (split packet supported)\r\n"); + + // Send packets as long as we need to + while (gsi_true == qr_build_split_query_reply(qrec, buf, &progress)) + { + sendto(qrec->hbsock, buf->buffer, buf->len, 0, sender, sizeof(struct sockaddr_in)); + buf->len = 5; // reset buffer but preserve 5-byte qr2 header + if (progress.mCurPacketNum > QR2_SPLITNUM_MAX) + return; // more than 7 isn't supported (likely a bug if you hit it) + } + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Finished split query reply (%d packets)\r\n", progress.mCurPacketNum); + } + else + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Building query reply (single packet)\r\n"); + qr_build_query_reply(qrec, buf, serverkeycount, serverkeys, playerkeycount, playerkeys, teamkeycount, teamkeys); + sendto(qrec->hbsock, buf->buffer, buf->len, 0, sender, sizeof(struct sockaddr_in)); + } + + GSI_UNUSED(sender); +} + +/* +static void qr_build_partial_old_query_reply(qr2_t qrec, qr2_buffer_t buf, qr2_key_type keytype) +{ + char tempkeyname[128]; + struct qr2_keybuffer_s kb; + int playerteamcount; + int i; + int pindex; + const char *k; + int len; + + kb.numkeys = 0; + + if (keytype == key_player || keytype == key_team) //need to add the player/team counts + { + playerteamcount = qrec->playerteam_count_callback(keytype, qrec->udata); + } else + playerteamcount = 1; + + qrec->key_list_callback(keytype, &kb, qrec->udata); + //add all the keys + for (i = 0 ; i < kb.numkeys ; i++) + { + k = qr2_registered_key_list[kb.keys[i]]; + if (k == NULL) + k = "unknown"; + if (keytype == key_server) //add the server values + { + qr2_buffer_addA(buf, k); + buf->buffer[buf->len - 1] = '\\'; + len = buf->len; + qrec->server_key_callback(kb.keys[i], buf, qrec->udata); + if(len == buf->len) + qr2_buffer_addA(buf, ""); + buf->buffer[buf->len - 1] = '\\'; + } else //need to look it up for each player/team + { + + for (pindex = 0 ; pindex < playerteamcount ; pindex++) + { + sprintf(tempkeyname, "%s%d", k, pindex); + qr2_buffer_addA(buf, tempkeyname); + buf->buffer[buf->len - 1] = '\\'; + len = buf->len; + if (keytype == key_player) + qrec->player_key_callback(kb.keys[i], pindex, buf, qrec->udata); + else if (keytype == key_team) + qrec->team_key_callback(kb.keys[i], pindex, buf, qrec->udata); + if(len == buf->len) + qr2_buffer_addA(buf, ""); + buf->buffer[buf->len - 1] = '\\'; + } + } + } +} +*/ + +//we just build a status reply, since we don't have equivalent callbacks +/*static void qr_process_old_query(qr2_t qrec, qr2_buffer_t buf) +{ + buf->len = 1; + buf->buffer[0] = '\\'; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_Comment, + "Processing QR1 style query\r\n"); + + qr_build_partial_old_query_reply(qrec, buf, key_server); + qr_build_partial_old_query_reply(qrec, buf, key_player); + qr_build_partial_old_query_reply(qrec, buf, key_team); + qr2_buffer_addA(buf, "final\\\\queryid\\1.1"); + buf->len--; //remove the final null; +}*/ + +static void qr_process_client_message(qr2_t qrec, char *buf, int len) +{ + unsigned char natNegBytes[NATNEG_MAGIC_LEN] = {NN_MAGIC_0,NN_MAGIC_1,NN_MAGIC_2,NN_MAGIC_3,NN_MAGIC_4,NN_MAGIC_5}; + int i; + int isnatneg = 1; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_Notice, + "Processing client message\r\n"); + + //see if it's a natneg request.. + if (len >= NATNEG_MAGIC_LEN + 4) + { + for (i = 0 ; i < NATNEG_MAGIC_LEN ; i++) + if ((unsigned char)buf[i] != natNegBytes[i]) + { + isnatneg = 0; + break; + } + } else + isnatneg = 0; + if (isnatneg) + { + int cookie; + memcpy(&cookie, buf + NATNEG_MAGIC_LEN, 4); + cookie = (int)ntohl((unsigned int)cookie); + + // check if we should do natneg + if(qrec->cc_callback) + { + NegotiateError error; + + if(__GSIACResult != GSIACAvailable) + { + // fake that we passed the availability check + __GSIACResult = GSIACAvailable; + strcpy(__GSIACGamename, qrec->gamename); + } + + // do the negotiation + error = NNBeginNegotiationWithSocket(qrec->hbsock, cookie, 1, NatNegProgressCallback, NatNegCompletedCallback, qrec); + if(error != ne_noerror) + { + // we can ignore errors + } + } + else if (qrec->nn_callback) + { + qrec->nn_callback(cookie, qrec->udata); + } + } else + if (qrec->cm_callback) + { +#ifndef GSI_UNICODE + qrec->cm_callback(buf, len, qrec->udata); +#else + unsigned short* buf_W; + buf_W = UTF8ToUCS2StringAlloc(buf); + qrec->cm_callback(buf_W, wcslen(buf_W), qrec->udata); +#endif + } +} + +static int qr_got_recent_message(qr2_t qrec, int msgkey) +{ + int i; + for (i = 0 ; i < RECENT_CLIENT_MESSAGES_TO_TRACK ; i++) + { + if (qrec->client_message_keys[i] == msgkey) + return 1; + } + //else, add it to the list + qrec->cur_message_key = (qrec->cur_message_key + 1) % RECENT_CLIENT_MESSAGES_TO_TRACK; + qrec->client_message_keys[qrec->cur_message_key] = msgkey; + return 0; +} + +// Send a random value to the user, to verify IP address +static gsi_bool qr2_process_ip_verify(qr2_t qrec, struct qr2_buffer_s* buf, struct sockaddr_in* sender) +{ + int i=0; + gsi_time now = current_time(); + int firstFreeIndex = -1; + int numDuplicates = 0; + + // if the query challenge is disabled, return 0 as the challenge + if ((qrec->backendoptions & QR2_OPTION_USE_QUERY_CHALLENGE) == 0) + { + qr2_buffer_add_int(buf, 0); + return gsi_true; + } + + // check if this ip/port combo is already in the list + for (; i < QR2_IPVERIFY_ARRAY_SIZE; i++) + { + // Mark the first free index when/if found + if (firstFreeIndex == -1 && qrec->ipverify[i].addr.sin_addr.s_addr == 0) + firstFreeIndex = i; + // Count any indexes that match this IP/port + if (qrec->ipverify[i].addr.sin_addr.s_addr == sender->sin_addr.s_addr && + qrec->ipverify[i].addr.sin_port == sender->sin_port) + { + numDuplicates++; + } + } + + // discard if too many duplicates or no index found + if (numDuplicates > QR2_IPVERIFY_MAXDUPLICATES) + return gsi_false; + if (firstFreeIndex == -1) + return gsi_false; // no free indexes + + + // create a random challenge for this ip/port combo + qrec->ipverify[firstFreeIndex].addr = *sender; + qrec->ipverify[firstFreeIndex].challenge = htonl( (rand() << 16) | rand() ); + qrec->ipverify[firstFreeIndex].createtime = now; + + qr2_buffer_add_int(buf, (int)qrec->ipverify[firstFreeIndex].challenge); + return gsi_true; // buffer ready to be sent +} + +// Check if the returned ipverify value matches the random we sent earlier +// If it matches, remove it +static gsi_bool qr2_check_ip_verify(qr2_t qrec, struct sockaddr_in* sender, gsi_u32 ipverify) +{ + int i=0; + for (; i < QR2_IPVERIFY_ARRAY_SIZE; i++) + { + if (qrec->ipverify[i].addr.sin_addr.s_addr == sender->sin_addr.s_addr && + qrec->ipverify[i].addr.sin_port == sender->sin_port) + { + if (qrec->ipverify[i].challenge == ipverify) + { + // reset structure + qrec->ipverify[i].addr.sin_addr.s_addr = 0; + qrec->ipverify[i].addr.sin_port = 0; + return gsi_true; + } + //else + // keep searching...a single IP may have multiple outstanding challenges. + } + } + return gsi_false; +} + +// Expire old verify attempts +static void qr2_expire_ip_verify(qr2_t qrec) +{ + int i=0; + gsi_time now = current_time(); + + for (; i < QR2_IPVERIFY_ARRAY_SIZE; i++) + { + if (qrec->ipverify[i].addr.sin_addr.s_addr != 0 && (now - qrec->ipverify[i].createtime > QR2_IPVERIFY_TIMEOUT)) + qrec->ipverify[i].addr.sin_addr.s_addr = 0; + } +} + +/* parse_query: parse an incoming query and reply to each query */ +void qr2_parse_queryA(qr2_t qrec, char *query, int len, struct sockaddr *sender) +{ + struct qr2_buffer_s buf; + char ptype; + char *reqkey; + char *pos; + gsi_u32 ipverify = 0; + int i; + + buf.len = 0; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_StackTrace, + "qr2_parse_queryA()\r\n"); + + if (qrec == NULL) + qrec = current_rec; + if (query[0] == 0x3B) /* a cdkey query */ + { + if (qrec->cdkeyprocess != NULL) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Forwarding cdkey query onto cdkey sdk\r\n"); + qrec->cdkeyprocess(query, len, sender); + } + else + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Received cdkey query but not using qr2-cdkey integration!\r\n"); + } + return; + } + /*if (query[0] == '\\') //it's a QR1-style query + { + qr_process_old_query(qrec, &buf); + sendto(qrec->hbsock, buf.buffer, buf.len, 0, sender, sizeof(struct sockaddr_in)); + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Sent %d bytes as QR1 query response\r\n", buf.len); + gsDebugBinary(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_RawDump, + buf.buffer, buf.len); + + return; + }*/ + if((len >= 6) && (memcmp(query, NNMagicData, NATNEG_MAGIC_LEN) == 0)) /* a natneg query */ + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Forwarding natneg query onto natneg sdk\r\n"); + NNProcessData(query, len, (struct sockaddr_in*)sender); + return; + } + + if (len < 7) + return; //too small to be valid + //check the magic... + if ((uchar)query[0] != QR_MAGIC_1 || (uchar)query[1] != QR_MAGIC_2) + return; + +//#define SIMULATE_HARD_FIREWALL +#if defined(SIMULATE_HARD_FIREWALL) + // ignore all QR2 packets on this port + // generates "no challenge" error + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Warning, + "SIMULATE_HARD_FIREWALL defined, ignoring QR2 packet\r\n"); + return; +#endif + +//#define SIMULATE_FIREWALL +#if defined(SIMULATE_FIREWALL) + // ignore messages that are not from the gamespy master + { + unsigned int aMasterAddr = (cr->hbaddr.sin_addr); + if (((SOCKADDR_IN*)sender)->sin_addr.s_addr != aMasterAddr) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Warning, + "SIMULATE_FIREWALL defined, ignoring non-master QR2 packet\r\n"); + return; + } + } +#endif +//#if defined(QR2_IP_FILTER) + if (qrec->denyresp2_ip_callback) + { + unsigned int aMasterAddr = (qrec->hbaddr.sin_addr.s_addr); + unsigned int senderAddr = ((SOCKADDR_IN*)sender)->sin_addr.s_addr; //in hbo + if ((aMasterAddr & 0xffff) != (senderAddr & 0xffff)) //if sender ip is not in gamespy subnet /16 (fake) + { + int deny_result = 0; + qrec->denyresp2_ip_callback(qrec->udata, senderAddr, &deny_result); + if (deny_result) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Warning, + "QR2_IP_FILTER defined, ignoring QR2 packet from denied ip\r\n"); + return; + } + } + } +//#endif //#if defined(QR2_IP_FILTER) + + if (qrec->listed_state > 0) + qrec->listed_state = 0; + + ptype = query[2]; + reqkey = &query[3]; + pos = query + 7; + len -= 7; + + qr_add_packet_header(&buf, ptype, reqkey); + switch (ptype) + { + case PACKET_PREQUERY_IP_VERIFY: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Received IP verify challenge request\r\n"); + if (gsi_is_true(qr2_process_ip_verify(qrec, &buf, (struct sockaddr_in*)sender))) + break; // break so that we send below + else + return; // otherwise return and discard buf + + + case PACKET_QUERY: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Processing query packet\r\n"); + + // When using query challenge option, verify that the client sent a PREQUERY_IP_VERIFY + if ((qrec->backendoptions & QR2_OPTION_USE_QUERY_CHALLENGE) == QR2_OPTION_USE_QUERY_CHALLENGE) + { + if (len < 4) + return; // too small for an ip-verify query + + ipverify = ntohl(*(gsi_u32*)pos); + pos += 4; + len -= 4; + + // Has this client verified their IP? (prevent IP spoofing) + if (gsi_is_false(qr2_check_ip_verify(qrec, (struct sockaddr_in*)sender, ipverify))) + { + // Don't send an error. As nice as the debug info would be, + // the incompatible SBs will interpret it as a server response. + return; + } + } + + // qr_process_query now sends packets + qr_process_query(qrec, &buf, (uchar *)pos, len, sender); + return; + case PACKET_CHALLENGE: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Processing challenge packet\r\n"); + + // Check the instance key (to prove this packet came from the master + for (i = 0 ; i < REQUEST_KEY_LEN ; i++) + { + if (reqkey[i] != qrec->instance_key[i]) + return; //not a valid instance key + } + + //calculate the challenge + if (len >= (PUBLIC_ADDR_LEN + 3)) + { + unsigned int backendoptions; + + // read options, then public address + sscanf(pos + len - (PUBLIC_ADDR_LEN + 3), "%02x", &backendoptions); + qrec->backendoptions = (gsi_u8)backendoptions; + + #ifdef QR2_DEBUG_FORCE_USE_QUERY_CHALLENGE + qrec->backendoptions = QR2_OPTION_USE_QUERY_CHALLENGE; + #endif + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_Notice, + "Received setting options: %d\r\n", qrec->backendoptions); + + if(qrec->pa_callback) + handle_public_address(qrec, pos + len - (PUBLIC_ADDR_LEN + 1)); + else + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Discarding public address (no callback set)\r\n"); + } + } + compute_challenge_response(qrec, &buf, pos, len); + break; + case PACKET_ECHO: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Processing echo packet\r\n"); + + //now add the echo data + if (len > 32) + len = 32; //max 32 bytes + buf.buffer[0] = PACKET_ECHO_RESPONSE; + memcpy(buf.buffer + buf.len, pos, (size_t)len); + buf.len += len; + break; + + case PACKET_ADDERROR: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Processing adderror packet\r\n"); + + if (qrec->listed_state == -1) + return; //we already got an error message + //verify the instance code + for (i = 0 ; i < REQUEST_KEY_LEN ; i++) + { + if (reqkey[i] != qrec->instance_key[i]) + return; //not a valid instance key + } + if (len < 2) + return; //not a valid message + qrec->listed_state = -1; +#ifndef GSI_UNICODE + qrec->adderror_callback((qr2_error_t)*pos, pos + 1, qrec->udata); +#else + { + unsigned short* message_W; + message_W = UTF8ToUCS2StringAlloc(pos+1); + qrec->adderror_callback((qr2_error_t)*pos, message_W, qrec->udata); + gsifree(message_W); + } +#endif + return; //we don't need to send anything back for this type of message + case PACKET_CLIENT_MESSAGE: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Notice, + "Processing clientmessage packet\r\n"); + + //verify the instance code + for (i = 0 ; i < REQUEST_KEY_LEN ; i++) + { + if (reqkey[i] != qrec->instance_key[i]) + return; //not a valid instance key + } + if (len < 4) //no message key? + return; + buf.buffer[0] = PACKET_CLIENT_MESSAGE_ACK; + //add the msg key + memcpy(buf.buffer + buf.len, pos, (size_t)4); + buf.len += 4; + //see if we've recently gotten this same message, to help avoid dupes + memcpy(&i, pos, (size_t)4); + if (!qr_got_recent_message(qrec, i)) + qr_process_client_message(qrec, pos + 4, len - 4); + //send an ack response + break; + case PACKET_KEEPALIVE: + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Processing keepalive packet\r\n"); + return; //if we get a keep alive, ignore it and return (just used to tell us the server knows about us) + default: + return; //not valid type + + } + //send the reply + sendto(qrec->hbsock, buf.buffer, buf.len, 0, sender, sizeof(struct sockaddr_in)); + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Sent %d bytes as QR2 query response\r\n", buf.len); + gsDebugBinary(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_RawDump, + buf.buffer, buf.len); +} + +/* NOT necessary since qr2_parse_query uses char not unsigned short +#if defined(GSI_UNICODE) +void qr2_parse_queryW(qr2_t qrec, unsigned short *query, int len, struct sockaddr *sender) +{ + char query_A[4096]; + UCS2ToUTF8String(query, query_A); + qr2_parse_queryA(qrec, query_A, len, sender); +} +#endif*/ + + +/* send_keepalive: Send a keepalive packet to the hbmaster3 */ +static void send_keepalive(qr2_t qrec) +{ + struct qr2_buffer_s buf; + buf.len = 0; + qr_add_packet_header(&buf, PACKET_KEEPALIVE, qrec->instance_key); + sendto(qrec->hbsock, buf.buffer, buf.len, 0, (struct sockaddr *)&(qrec->hbaddr), sizeof(struct sockaddr_in)); + + //set the ka time to now + qrec->lastka = current_time(); + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Sent keepalive to master\r\n", buf); +} + +/* send_heartbeat: Sends a heartbeat to the gamemaster, +adds \statechanged\ if statechanged != 0 */ +static void send_heartbeat(qr2_t qrec, int statechanged) +{ + struct qr2_buffer_s buf; + //int ret; + int i; + char ipkey[20]; + + buf.len = 0; + qr_add_packet_header(&buf, PACKET_HEARTBEAT, qrec->instance_key); + //now we add our special keys + for (i = 0 ; i < num_local_ips ; i++) + { + sprintf(ipkey, "localip%d", i); + qr2_buffer_addA(&buf, ipkey); + qr2_buffer_addA(&buf, inet_ntoa(local_ip_list[i])); + } + qr2_buffer_addA(&buf, "localport"); + qr2_buffer_add_int(&buf, qrec->qport); + qr2_buffer_addA(&buf, "natneg"); + qr2_buffer_addA(&buf, qrec->nat_negotiate ? "1" : "0"); + if(statechanged) + { + qr2_buffer_addA(&buf, "statechanged"); + qr2_buffer_add_int(&buf, statechanged); + } + qr2_buffer_addA(&buf, "gamename"); + qr2_buffer_addA(&buf, qrec->gamename); + if(qrec->pa_callback) + { + qr2_buffer_addA(&buf, "publicip"); + qr2_buffer_add_int(&buf, (int)qrec->publicip); + qr2_buffer_addA(&buf, "publicport"); + qr2_buffer_add_int(&buf, qrec->publicport); + } + + //add the rest of our keys + if (statechanged != 2) //don't need if we are exiting + { + // The hbmaster will crap out if the packet is malformed + // which might happen if the buffer isn't large enough + // So first copy dump the keys into a temporary buffer + struct qr2_buffer_s temp; + memcpy(temp.buffer, buf.buffer, (size_t)buf.len); + temp.len = buf.len; + qr_build_query_reply(qrec, &temp, 0xFF, NULL, 0xFF, NULL, 0xFF, NULL); + + // If we maxxed out the packet, try again using only the server keys + if(AVAILABLE_BUFFER_LEN(&temp) < 1) + { + temp.len = buf.len; + qr_build_query_reply(qrec, &temp, 0xFF, NULL, 0, NULL, 0, NULL); + } + // copy temp back into buffer + memcpy(buf.buffer, temp.buffer, (size_t)temp.len); + buf.len = temp.len; + } + else + { + // PANTS - 2002.6.28 + // add an extra NUL to end the server keys + if (AVAILABLE_BUFFER_LEN(&buf) >= 1) + buf.buffer[buf.len++] = 0; + } + + //ret = (int)sendto(qrec->hbsock, buf.buffer, buf.len, 0, (struct sockaddr *)&(qrec->hbaddr), sizeof(struct sockaddr_in)); + sendto(qrec->hbsock, buf.buffer, buf.len, 0, (struct sockaddr *)&(qrec->hbaddr), sizeof(struct sockaddr_in)); + + //set the ka time and hb time to now + qrec->lastka = qrec->lastheartbeat = current_time(); + + // clear the pending heartbeat request flag + if (statechanged != 0) + qrec->userstatechangerequested = 0; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_Comment, + "Sent heartbeat to master (size %d)\r\n", buf.len); + gsDebugBinary(GSIDebugCat_QR2, GSIDebugType_Network, GSIDebugLevel_RawDump, + buf.buffer, buf.len); +} + +#ifdef __cplusplus +} +#endif + + diff --git a/xrGameSpy/gamespy/qr2/qr2.dsw b/xrGameSpy/gamespy/qr2/qr2.dsw new file mode 100644 index 00000000000..efb6e1ba680 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qr2csample"=.\qr2csample\qr2csample.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/qr2/qr2csample + .\qr2csample + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/qr2 + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/qr2/qr2.h b/xrGameSpy/gamespy/qr2/qr2.h new file mode 100644 index 00000000000..47b08812c59 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2.h @@ -0,0 +1,453 @@ +#ifndef _QR2_H_ +#define _QR2_H_ + +#include "../common/gsCommon.h" + + +/********** +qr2regkeys.h contains defines for all of the reserved keys currently available. +***********/ +#include "qr2regkeys.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef GSI_UNICODE +#define qr2_init qr2_initA +#define qr2_init_socket qr2_init_socketA +#define qr2_parse_query qr2_parse_queryA +#define qr2_buffer_add qr2_buffer_addA +#else +#define qr2_init qr2_initW +#define qr2_init_socket qr2_init_socketW +#define qr2_parse_query qr2_parse_queryW +#define qr2_buffer_add qr2_buffer_addW +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + +//no need to escape strings, more flexible querying, less bandwidth, no need to space check buffers + + +/******** +ERROR CONSTANTS +--------------- +These constants are returned from qr2_init and the error callback to signal an error condition +***************/ +typedef enum +{e_qrnoerror, //no error occured +e_qrwsockerror, //a standard socket call failed (exhausted resources?) +e_qrbinderror, //the SDK was unable to find an available port to bind on +e_qrdnserror, //a DNS lookup (for the master server) failed +e_qrconnerror, //the server is behind a nat and does not support negotiation +e_qrnochallengeerror, //no challenge was received from the master - either the master is down, or a firewall is blocking UDP +qr2_error_t_count +} qr2_error_t; + + +/******** +KEY TYPES +--------------- +Server information is reported in key/value pairs. There are three key types: +key_server - General information about the game in progress +key_player - Information about a specific player +key_team - Information about a specific team +***************/ +typedef enum {key_server, key_player, key_team, key_type_count} qr2_key_type; + +/********* +NUM_PORTS_TO_TRY +---------------- +This value is the maximum number of ports that will be scanned to +find an open query port, starting from the value passed to qr2_init +as the base port. Generally there is no reason to modify this value. +***********/ +#define NUM_PORTS_TO_TRY 100 + + +/********* +MAGIC VALUES +---------------- +These values will be used at the start of all QR2 query packets. If you are processing query +data on your game socket, you can use these bytes to determine if a packet should be forwarded +to the QR2 SDK for processing. +***********/ +#define QR_MAGIC_1 0xFE +#define QR_MAGIC_2 0xFD + +/* The app can resolve the master server hostname for this +game itself and store the IP here before calling qr2_init. +For more information, contact devsupport@gamespy.com. */ +extern char qr2_hostname[64]; + +/*********** +qr2_t +---- +This abstract type is used to instantiate multiple instances of the +Query & Reporting SDK (for example, if you are running multiple servers +in the same process). +For most games, you can ignore this value and pass NULL in to all functions +that require it. A single global instance will be used in this case. +************/ +typedef struct qr2_implementation_s *qr2_t; + +/*********** +qr2_keybuffer_t +--------------- +This structure is used to store a list of keys when enumerating available keys. +Use the qr2_keybuffer_add function to add keys to the list. +************/ +typedef struct qr2_keybuffer_s *qr2_keybuffer_t; + + +/*********** +qr2_buffer_t +------------ +This structure stores data that will be sent back to a client in response to +a query. Use the qr2_buffer_add functions to add data to the buffer in your callbacks. +************/ +typedef struct qr2_buffer_s *qr2_buffer_t; + +typedef struct qr2_ipverify_node_s *qr2_ipverify_node_t; + + +/******** +qr2_serverkeycallback_t +------------------- +This is the prototype for one of the callback functions you will need to provide. +The serverkey callback is called when a client requests information about a specific +server key. +[keyid] is the key being requested. +[outbuf] is the destination buffer for the value information. Use qr2_buffer_add to report the value. +[userdata] is the pointer that was passed into qr2_init. You can use this for an + object or structure pointer if needed. +If you don't have a value for the provided keyid, you should add a empty ("") string to the buffer. +********/ +typedef void (*qr2_serverkeycallback_t)(int keyid, qr2_buffer_t outbuf, void *userdata); + +/******** +qr2_playerteamkeycallback_t +------------------- +This is the prototype for two of the callback functions you will need to provide. +The player key callback is called when a client requests information about a specific key +for a specific player. +The team key callback is called when a client requests the value for a team key. +[keyid] is the key being requested. +[index] is the 0-based index of the player or team being requested. +[outbuf] is the destination buffer for the value information. Use qr2_buffer_add to report the value. +[userdata] is the pointer that was passed into qr2_init. You can use this for an + object or structure pointer if needed. +If you don't have a value for the provided keyid, you should add a empty ("") string to the buffer. +********/ +typedef void (*qr2_playerteamkeycallback_t)(int keyid, int index, qr2_buffer_t outbuf, void *userdata); + + +/******** +qr2_keylistcallback_t +------------------- +This is the prototype for one of the callback functions you will need to provide. +The key list callback is called when the SDK needs to determine all of the keys you game has +values for. +[keytype] is the type of keys being requested (server, player, team). You should only add keys + of this type to the keybuffer. +[keybuffer] is the structure that holds the list of keys. Use qr2_keybuffer_add to add a key + to the buffer. +[userdata] is the pointer that was passed into qr2_init. You can use this for an + object or structure pointer if needed. +********/ +typedef void (*qr2_keylistcallback_t)(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata); + + +/******** +qr2_countcallback_t +------------------- +This is the prototype for one of the callback functions you will need to provide. +The count callback is used by the SDK to get a count of player or teams on the server. +[keytype] should be used to determine whether the player or team count is being requested (key_player or key_team will be passed) +[userdata] is the pointer that was passed into qr2_init. You can use this for an + object or structure pointer if needed. +If your game does not support teams, you can return 0 for the count of teams. +********/ +typedef int (*qr2_countcallback_t)(qr2_key_type keytype, void *userdata); + +/******** +qr2_adderrorcallback_t +------------------- +This is the prototype for one of the callback functions you will need to provide. +The add error callback is called in response to a message from the master server indicating a problem listing the server. +[error] is a code that can be used to determine the specific listing error. +[errmsg] is a human-readable error string returned from the master server. +[userdata] is the pointer that was passed into qr2_init. You can use this for an + object or structure pointer if needed. +The most common error that will be returned is if the master is unable to list the server due to a firewall or proxy +that would block incoming game packets. +********/ +typedef void (*qr2_adderrorcallback_t)(qr2_error_t error, gsi_char *errmsg, void *userdata); + + +//todo - document +typedef void (*qr2_natnegcallback_t)(int cookie, void *userdata); +typedef void (*qr2_clientmessagecallback_t)(gsi_char *data, int len, void *userdata); +typedef void (*qr2_publicaddresscallback_t)(unsigned int ip, unsigned short port, void *userdata); +typedef void (*qr2_clientconnectedcallback_t)(SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata); + +//#if defined(QR2_IP_FILTER) +typedef void (*qr2_denyqr2responsetoipcallback_t)(void *userdata, unsigned int sender_ip, int * result); +//#endif //#if defined(QR2_IP_FILTER) + +void qr2_register_natneg_callback(qr2_t qrec, qr2_natnegcallback_t nncallback); +void qr2_register_clientmessage_callback(qr2_t qrec, qr2_clientmessagecallback_t cmcallback); +void qr2_register_publicaddress_callback(qr2_t qrec, qr2_publicaddresscallback_t pacallback); +void qr2_register_clientconnected_callback(qr2_t qrec, qr2_clientconnectedcallback_t cccallback); + +//#if defined(QR2_IP_FILTER) +void qr2_register_denyresponsetoip_callback(qr2_t qrec, qr2_denyqr2responsetoipcallback_t dertoipcallback); +//#endif //#if defined(QR2_IP_FILTER) + + +/***************** +QR2_REGISTER_KEY +-------------------- +Use this function to register custom server, player, and team keys that your server reports. +[keyid] is the ID number you have chosen for this key. The first NUM_RESERVED_KEYS (50) keys are reserved, all other + keyid values up to MAX_REGISTERED_KEYS (254) are available for your use. +[key] is the string name of the key. Player keys should end in "_" (such as "score_") and team keys should end in "_t". +All custom keys should be registered prior to calling qr2_init. Reserved keys are already registered and should not be +passed to this function. +*******************/ +void qr2_register_key(int keyid, const gsi_char *key); + + +/************ +QR2_INIT +-------- +This function initializes the Query and Reporting SDK and prepares the SDK to accept incoming +queries and send heartbeats to the master server. +[qrec] if not null, will be filled with the qr2_t instance for this server. + If you are not using more than one instance of the Query & Reporting SDK you + can pass in NULL for this value. +[ip] is an optional parameter that determines which dotted IP address to bind to on + a multi-homed machine. You can pass NULL to bind to all IP addresses. + If your game networking supports binding to user-specified IPs, you should make sure the same IP + is bound by the Query and Reporting SDK. +[baseport] is the port to accept queries on. If baseport is not available, the + Query and Reporting SDK will scan for an available port in the range of + baseport -> baseport + NUM_PORTS_TO_TRY + Optionally, you can pass in 0 to have a port chosen automatically + (makes it harder for debugging/testing). +[gamename] is the unique gamename that you were given +[secretkey] is your unique secret key +[ispublic] is 1 if the server should send heartbeats to the GameSpy master server and be publicly listed, + If 0, the server will only be available for LAN browsing +[natnegotiate] is 1 if the server supports GameSpy's NAT-negotiation technology (or another similar technology) + which allows hosting behind a NAT. If you do not support NAT-negotiation (i.e. a 3rd party handshake server), + pass 0 to prevent the server from being listed if it is behind a NAT that cannot be traversed by outside clients. +[qr2_*_callback] are your callback functions, these cannot be NULL +[userdata] is an optional, implementation specific parameter that will be + passed to all callback functions. Use it to store an object or structure + pointer if needed. + +Returns +e_qrnoerror is successful, otherwise one of the qr2_error_t constants above. +************/ +qr2_error_t qr2_init(/*[out]*/qr2_t *qrec, const gsi_char *ip, int baseport, const gsi_char *gamename, const gsi_char *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata); + +/************ +QR2_INIT_SOCKET +-------- +This version of qr2_init allows the game to specify the UDP socket to use for +sending heartbeats and query replies. This enables the game and the QR2 SDK to +share a single UDP socket for all networking, which can make hosting games +behind a NAT proxy possible (see the documentation for more information). +You must also use qr2_parse_query to pass in any data received for the QR SDK +on the socket, since the SDK will not try to read any data off the socket directly. +[s] is the UDP socket to use for heartbeats and query replies. It must be a valid + socket and should be bound to a port before calling qr_init_socket. It can be + blocking or non-blocking. +[boundport] is the local port that the socket is bound to. +All other parameters are the same as described in qr2_init. +************/ +qr2_error_t qr2_init_socket(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const gsi_char *gamename, const gsi_char *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata); + +/******************* +QR2_THINK +------------------- +This function should be called somewhere in your main program loop to +process any pending server queries and send a heartbeat if needed. + +Query replies are very latency sensative, so you should make sure this +function is called at least every 100ms while your game is in progress. +The function has very low overhead and should not cause any performance +problems. +Unless you are using multiple instances of the SDK, you should pass NULL +for qrec. +********************/ +void qr2_think(qr2_t qrec); + +/******************* +QR2_PARSE_QUERY +------------------- +Use only with qr2_init_socket to pass in data that is destined for the Q&R SDK +from your game socket. +You still need to call qr2_think in your main loop, and just call this +function whenever data is received. +Unless you are using multiple instances of the SDK, you should pass NULL +for qrec. +[query] is the packet of query data received from the client. +[len] is the length of the data +[sender] is the address that the query is received from. The QR SDK will reply +directly to that address using the socket provided in qr2_init_socket. +*******************/ +void qr2_parse_query(qr2_t qrec, gsi_char *query, int len, struct sockaddr *sender); + +/***************** +QR2_SEND_STATECHANGED +-------------------- +This function forces a "statechanged" heartbeat to be sent immediately. +Use it any time you have changed the gamestate of your game to signal the +master to update your status. +Unless you are using multiple instances of the SDK, you should pass NULL +for qrec. +*******************/ +void qr2_send_statechanged(qr2_t qrec); + +/***************** +QR2_SHUTDOWN +------------ +This function closes the sockets created in qr_init and takes care of +any misc. cleanup. You should try to call it when before exiting the server process. +An "exiting" statechanged heartbeat will automatically be sent to assist in quickly +de-listing the server. +If you pass in a qrec that was returned from qr_init, all resources associated +with that qrec will be freed. If you passed NULL into qr_int, you can pass +NULL in here as well. +******************/ +void qr2_shutdown(qr2_t qrec); + + + +/***************** +QR2_KEYBUFFER_ADD +------------ +Use this function to add a registered key to the key buffer when asked to provide +a list of supported keys. +******************/ +gsi_bool qr2_keybuffer_add(qr2_keybuffer_t keybuffer, int keyid); + +/***************** +QR2_BUFFER_ADD / ADD_INT +------------ +These functions are used to add a key's value to the outgoing buffer when +requested in a callback function. +******************/ +gsi_bool qr2_buffer_add(qr2_buffer_t outbuf, const gsi_char *value); +gsi_bool qr2_buffer_add_int(qr2_buffer_t outbuf, int value); + + +/* for CDKey SDK integration */ +#define REQUEST_KEY_LEN 4 +#define RECENT_CLIENT_MESSAGES_TO_TRACK 10 +typedef void (*cdkey_process_t)(char *buf, int len, struct sockaddr *fromaddr); + +/* ip verification / spoof prevention */ +#define QR2_IPVERIFY_TIMEOUT 4000 // timeout after 4 seconds round trip time +#define QR2_IPVERIFY_ARRAY_SIZE 200 // allowed outstanding queryies in those 4 seconds +#define QR2_IPVERIFY_MAXDUPLICATES 5 // allow maximum of 5 requests per IP/PORT +struct qr2_ipverify_info_s +{ + struct sockaddr_in addr; // addr = 0 when not in use + gsi_u32 challenge; + gsi_time createtime; +}; + +struct qr2_implementation_s +{ + SOCKET hbsock; + char gamename[64]; + char secret_key[64]; + char instance_key[REQUEST_KEY_LEN]; + qr2_serverkeycallback_t server_key_callback; + qr2_playerteamkeycallback_t player_key_callback; + qr2_playerteamkeycallback_t team_key_callback; + qr2_keylistcallback_t key_list_callback; + qr2_countcallback_t playerteam_count_callback; + qr2_adderrorcallback_t adderror_callback; + qr2_natnegcallback_t nn_callback; + qr2_clientmessagecallback_t cm_callback; + qr2_publicaddresscallback_t pa_callback; + qr2_clientconnectedcallback_t cc_callback; +//#if defined(QR2_IP_FILTER) + qr2_denyqr2responsetoipcallback_t denyresp2_ip_callback; +//#endif //#if defined(QR2_IP_FILTER) + + + gsi_time lastheartbeat; + gsi_time lastka; + int userstatechangerequested; + int listed_state; + int ispublic; + int qport; + int read_socket; + int nat_negotiate; + struct sockaddr_in hbaddr; + cdkey_process_t cdkeyprocess; + int client_message_keys[RECENT_CLIENT_MESSAGES_TO_TRACK]; + int cur_message_key; + unsigned int publicip; + unsigned short publicport; + void *udata; + + gsi_u8 backendoptions; // received from server inside challenge packet + struct qr2_ipverify_info_s ipverify[QR2_IPVERIFY_ARRAY_SIZE]; +}; + +// These need to be defined, even in GSI_UNICODE MODE +void qr2_parse_queryA(qr2_t qrec, char *query, int len, struct sockaddr *sender); +gsi_bool qr2_buffer_addA(qr2_buffer_t outbuf, const char *value); +qr2_error_t qr2_initA(/*[out]*/qr2_t *qrec, const char *ip, int baseport, const char *gamename, const char *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata); +qr2_error_t qr2_init_socketA(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const char *gamename, const char *secret_key, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/xrGameSpy/gamespy/qr2/qr2_vs2005.sln b/xrGameSpy/gamespy/qr2/qr2_vs2005.sln new file mode 100644 index 00000000000..cd4f50a67ac --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2_vs2005.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qr2csample_vs2005", "qr2csample\qr2csample_vs2005.vcproj", "{31E706BC-104B-4045-BD0A-A0FC552CDCEF}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = qr2csample\\qr2csample_vs2005.vcproj + SccProjectName1 = qr2csample + SccLocalPath1 = qr2csample + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {31E706BC-104B-4045-BD0A-A0FC552CDCEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {31E706BC-104B-4045-BD0A-A0FC552CDCEF}.Debug|Win32.Build.0 = Debug|Win32 + {31E706BC-104B-4045-BD0A-A0FC552CDCEF}.Release|Win32.ActiveCfg = Release|Win32 + {31E706BC-104B-4045-BD0A-A0FC552CDCEF}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/qr2/qr2csample/ReadMe.txt b/xrGameSpy/gamespy/qr2/qr2csample/ReadMe.txt new file mode 100644 index 00000000000..44ee06ca903 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/ReadMe.txt @@ -0,0 +1,29 @@ +**qr2csample** + +Command line inputs: Optional + - ip (x.x.x.x:port) => specify only if you want to override your IP (otherwise qr2 will set for you) + +Summary: This cross-platform test app reports a sample server to the backend. Once reporting, the server info +(including player/team info) can be retrieved using the ServerBrowsing SDK. After 30 seconds, the +mapname is updated and qr2_send_statechanged is called so that the master retrieves it. The sample +shuts down after 60 seconds, removing the server from the master list. To ensure that the server is +reporting correctly, you can check the master server list here (look for hostname "Gamespy QR2 Sample"): +http://net.gamespy.com/masterserver/?gamename=gmtest&fields=%5Chostname%5Chostport%5Cgamever%5Cmapname%5Cgametype%5Cgamemode%5Cnumplayers%5Cmaxplayers%5Cgravity%5Crankingon%5Cnumteams&overridemaster=&filter= + +Dependencies: use master server list site for verification, or you can run concurrently with sbctest to +have all the reported keys queried and displayed (wait 6-10 seconds after starting qr2csample to ensure +it is listed on the Master Server before running sbctest) + +For debug output, add GSI_COMMON_DEBUG to the preprocessor definitions. + +For Unicode, add GSI_UNICODE to the preprocessor definitions (or use the Visual Studio Project's Unicode +configuration). + +Internal functions used: + _tprintf - Unicode compatible version of printf + _tcscpy - Unicode compatible version of strcpy + _tcscmp - Unicode compatible version of strcmp + _T - used on all string literals for Unicode compatibility + msleep - Cross-platform compatible version of sleep + GSI_UNUSED - used to avoid unreferenced variable compiler warnings + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2csample.c b/xrGameSpy/gamespy/qr2/qr2csample/qr2csample.c new file mode 100644 index 00000000000..5e8fe30683c --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2csample.c @@ -0,0 +1,536 @@ +/*********************** +qrcsample.c +GameSpy Query & Reporting SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + See the ReadMe file for qrcsample info, and consult the GameSpy Query & Reporting 2 + SDK documentation for more information on implementing the qr2 SDK. + +************************/ + +/******** +INCLUDES +********/ +#include "../qr2.h" + +/******** +DEFINES +********/ +// set some of the fixed server keys +#define GAME_VERSION _T("2.00") +#define GAME_NAME _T("gmtest") +#define MAX_PLAYERS 32 +#define MAX_TEAMS 2 +#define BASE_PORT 11111 + +// ensure cross-platform compatibility for printf +#ifdef _WIN32_WCE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +// define our additional keys, making sure not to overwrite the reserved standard key ids +// standard keys use 0-NUM_RESERVED_KEYS (defined in qr2regkeys.h) +#define GRAVITY_KEY 100 +#define RANKINGON_KEY 101 +#define TIME__KEY 102 +#define AVGPING_T_KEY 103 + +/******** +TYPDEFS +********/ +//representative of a game player structure +typedef struct +{ + gsi_char pname[80]; + int pfrags; + int pdeaths; + int ptime; + int pping; + int pteam; +} player_t; + +//representative of a team structure +typedef struct +{ + gsi_char tname[80]; + int tscore; + int avgping; + +} team_t; + +//representative of a game data structure +typedef struct +{ + player_t players[MAX_PLAYERS]; + team_t teams[MAX_TEAMS]; + gsi_char mapname[20]; + gsi_char hostname[120]; + gsi_char gamemode[200]; + gsi_char gametype[30]; + int numteams; + int numplayers; + int maxplayers; + int fraglimit; + int timelimit; + int teamplay; + int rankingson; + int gravity; + int hostport; +} gamedata_t; + +/******** +GLOBAL VARS +********/ +// just to give us bogus data +gsi_char *constnames[MAX_PLAYERS]= +{ + _T("Joe Player"), _T("L33t 0n3"), _T("Raptor"), _T("Gr81"), + _T("Flubber"), _T("Sarge"), _T("Void"), _T("runaway"), + _T("Ph3ar"), _T("wh00t"), _T("gr1nder"),_T("Mace"), + _T("stacy"), _T("lamby"), _T("Thrush"), _T("Leeroy") +}; +gamedata_t gamedata; // to store all the server/player/teamkeys + +/******** +DEBUG OUTPUT +********/ +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); + } + + #ifdef GSI_UNICODE + static void AppDebug(const unsigned short* format, ...) + { + // Construct text, then pass in as ASCII + unsigned short buf[1024]; + char tmp[2056]; + va_list aList; + va_start(aList, format); + vswprintf(buf, 1024, format, aList); + + UCS2ToAsciiString(buf, tmp); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "%s", tmp); + } + #else + static void AppDebug(const char* format, ...) + { + va_list aList; + va_start(aList, format); + gsDebugVaList(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + format, aList); + } + #endif +#else + #define AppDebug _tprintf +#endif + +/******** +PROTOTYPES - To prevent warnings on codewarrior strict compile +********/ +void serverkey_callback(int keyid, qr2_buffer_t outbuf, void *userdata); +void playerkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata); +void teamkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata); +void keylist_callback(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata); +int count_callback(qr2_key_type keytype, void *userdata); +void adderror_callback(qr2_error_t error, gsi_char *errmsg, void *userdata); +void nn_callback(int cookie, void *userdata); +void cm_callback(gsi_char *data, int len, void *userdata); +void cc_callback(SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata); +void DoGameStuff(gsi_time totalTime); +int test_main(int argc, char **argp); + +// called when a server key needs to be reported +void serverkey_callback(int keyid, qr2_buffer_t outbuf, void *userdata) +{ + AppDebug("Reporting server keys\n"); + + switch (keyid) + { + case HOSTNAME_KEY: + qr2_buffer_add(outbuf, gamedata.hostname); + break; + case GAMEVER_KEY: + qr2_buffer_add(outbuf, GAME_VERSION); + break; + case HOSTPORT_KEY: + qr2_buffer_add_int(outbuf, gamedata.hostport); + break; + case MAPNAME_KEY: + qr2_buffer_add(outbuf, gamedata.mapname); + break; + case GAMETYPE_KEY: + qr2_buffer_add(outbuf, gamedata.gametype); + break; + case NUMPLAYERS_KEY: + qr2_buffer_add_int(outbuf, gamedata.numplayers); + break; + case NUMTEAMS_KEY: + qr2_buffer_add_int(outbuf, gamedata.numteams); + break; + case MAXPLAYERS_KEY: + qr2_buffer_add_int(outbuf, gamedata.maxplayers); + break; + case GAMEMODE_KEY: + qr2_buffer_add(outbuf, gamedata.gamemode); + break; + case TEAMPLAY_KEY: + qr2_buffer_add_int(outbuf, gamedata.teamplay); + break; + case FRAGLIMIT_KEY: + qr2_buffer_add_int(outbuf, gamedata.fraglimit); + break; + case TIMELIMIT_KEY: + qr2_buffer_add_int(outbuf, gamedata.timelimit); + break; + case GRAVITY_KEY: + qr2_buffer_add_int(outbuf, gamedata.gravity); + break; + case RANKINGON_KEY: + qr2_buffer_add_int(outbuf, gamedata.rankingson); + break; + default: + qr2_buffer_add(outbuf, _T("")); + } + + GSI_UNUSED(userdata); +} + +// called when a player key needs to be reported +void playerkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + AppDebug("Reporting player keys\n"); + + //check for valid index + if (index >= gamedata.numplayers) + { + qr2_buffer_add(outbuf, _T("")); + return; + } + switch (keyid) + { + case PLAYER__KEY: + qr2_buffer_add(outbuf, gamedata.players[index].pname); + break; + case SCORE__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pfrags); + break; + case DEATHS__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pdeaths); + break; + case PING__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pping); + break; + case TEAM__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].pteam); + break; + case TIME__KEY: + qr2_buffer_add_int(outbuf, gamedata.players[index].ptime); + break; + default: + qr2_buffer_add(outbuf, _T("")); + break; + } + + GSI_UNUSED(userdata); +} + +// called when a team key needs to be reported +void teamkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata) +{ + AppDebug("Reporting team keys\n"); + + //check for valid index + if (index >= gamedata.numteams) + { + qr2_buffer_add(outbuf, _T("")); + return; + } + switch (keyid) + { + case TEAM_T_KEY: + qr2_buffer_add(outbuf, gamedata.teams[index].tname); + break; + case SCORE_T_KEY: + qr2_buffer_add_int(outbuf, gamedata.teams[index].tscore); + break; + case AVGPING_T_KEY: + qr2_buffer_add_int(outbuf, gamedata.teams[index].avgping); + break; + default: + qr2_buffer_add(outbuf, _T("")); + break; + } + + GSI_UNUSED(userdata); +} + +// called when we need to report the list of keys we report values for +void keylist_callback(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata) +{ + AppDebug("Reporting keylist\n"); + + //need to add all the keys we support + switch (keytype) + { + case key_server: + qr2_keybuffer_add(keybuffer, HOSTNAME_KEY); + qr2_keybuffer_add(keybuffer, GAMEVER_KEY); + qr2_keybuffer_add(keybuffer, HOSTPORT_KEY); + qr2_keybuffer_add(keybuffer, MAPNAME_KEY); + qr2_keybuffer_add(keybuffer, GAMETYPE_KEY); + qr2_keybuffer_add(keybuffer, NUMPLAYERS_KEY); + qr2_keybuffer_add(keybuffer, NUMTEAMS_KEY); + qr2_keybuffer_add(keybuffer, MAXPLAYERS_KEY); + qr2_keybuffer_add(keybuffer, GAMEMODE_KEY); + qr2_keybuffer_add(keybuffer, TEAMPLAY_KEY); + qr2_keybuffer_add(keybuffer, FRAGLIMIT_KEY); + qr2_keybuffer_add(keybuffer, TIMELIMIT_KEY); + qr2_keybuffer_add(keybuffer, GRAVITY_KEY); //a custom key + qr2_keybuffer_add(keybuffer, RANKINGON_KEY); //a custom key + break; + case key_player: + qr2_keybuffer_add(keybuffer, PLAYER__KEY); + qr2_keybuffer_add(keybuffer, SCORE__KEY); + qr2_keybuffer_add(keybuffer, DEATHS__KEY); + qr2_keybuffer_add(keybuffer, PING__KEY); + qr2_keybuffer_add(keybuffer, TEAM__KEY); + qr2_keybuffer_add(keybuffer, TIME__KEY); //a custom key + break; + case key_team: + qr2_keybuffer_add(keybuffer, TEAM_T_KEY); + qr2_keybuffer_add(keybuffer, SCORE_T_KEY); + qr2_keybuffer_add(keybuffer, AVGPING_T_KEY); //a custom key + break; + default: break; + } + + GSI_UNUSED(userdata); +} + +// called when we need to report the number of players and teams +int count_callback(qr2_key_type keytype, void *userdata) +{ + AppDebug("Reporting number of players/teams\n"); + + if (keytype == key_player) + return gamedata.numplayers; + else if (keytype == key_team) + return gamedata.numteams; + else + return 0; + + GSI_UNUSED(userdata); +} + +// called if our registration with the GameSpy master server failed +void adderror_callback(qr2_error_t error, gsi_char *errmsg, void *userdata) +{ + GS_ASSERT(errmsg) + AppDebug("Error adding server: %d, %s\n", error, errmsg); + GSI_UNUSED(userdata); +} + +// called when a client wants to connect using nat negotiation +// (Nat Negotiation must be enabled in qr2_init) +void nn_callback(int cookie, void *userdata) +{ + AppDebug("Got natneg cookie: %d\n", cookie); + GSI_UNUSED(userdata); +} + +// called when a client sends a message to the server through qr2 (not commonly used) +void cm_callback(gsi_char *data, int len, void *userdata) +{ + AppDebug("Got %d bytes from client\n", len); + GSI_UNUSED(data); + GSI_UNUSED(userdata); +} + +// called when a client has connected +void cc_callback(SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata) +{ + AppDebug("Client connected from %s:%d\n", inet_ntoa(remoteaddr->sin_addr), ntohs(remoteaddr->sin_port)); + GSI_UNUSED(gamesocket); + GSI_UNUSED(userdata); +} + +// initialize the gamedata structure with bogus data +static void init_game(void) +{ + int i; + AppDebug("Generating game data\n"); + srand((unsigned int) current_time() ); + gamedata.numplayers = rand() % 15 + 1; + gamedata.maxplayers = MAX_PLAYERS; + for (i = 0 ; i < gamedata.numplayers ; i++) + { + _tcscpy(gamedata.players[i].pname, constnames[i]); + gamedata.players[i].pfrags = rand() % 32; + gamedata.players[i].pdeaths = rand() % 32; + gamedata.players[i].ptime = rand() % 1000; + gamedata.players[i].pping = rand() % 500; + gamedata.players[i].pteam = rand() % 2; + } + gamedata.numteams = 2; + for (i = 0 ; i < gamedata.numteams ; i++) + { + gamedata.teams[i].tscore = rand() % 500; + gamedata.teams[i].avgping = rand() % 500; + } + + _tcscpy(gamedata.teams[0].tname,_T("Red")); + _tcscpy(gamedata.teams[1].tname,_T("Blue")); + _tcscpy(gamedata.mapname,_T("gmtmap1")); + _tcscpy(gamedata.gametype,_T("arena")); + _tcscpy(gamedata.hostname,_T("GameSpy QR2 Sample")); + _tcscpy(gamedata.gamemode,_T("openplaying")); + + gamedata.fraglimit = 0; + gamedata.timelimit = 40; + gamedata.teamplay = 1; + gamedata.rankingson = 1; + gamedata.gravity = 800; + gamedata.hostport = 25000; +} + +// simulate whatever else a game server does +void DoGameStuff(gsi_time totalTime) +{ + // After 30 seconds, we will change the game map and call qr2_send_statechanged + // This should only be called after major changes such as mapname or gametype, and + // cannot be applied more than once every 10 seconds (subsequent calls will be delayed + // when necessary) + static int stateChanged = 0; + if (!stateChanged && totalTime > 30000) { + AppDebug("Mapname changed, calling qr2_send_statechanged\n"); + _tcscpy(gamedata.mapname,_T("gmtmap2")); + qr2_send_statechanged(NULL); + stateChanged = 1; + } + + msleep(10); +} + + +int test_main(int argc, char **argp) +{ + /* qr2_init parameters */ + gsi_char secret_key[9]; // your title's assigned secret key + gsi_char ip[255]; // to manually set local IP + const int isPublic = 1; // set to '0' for a LAN game + const int isNatNegSupported = 1; // set to '0' if you don't support Nat Negotiation + gsi_time aStartTime = 0; // for sample, so we don't run forever + void * userData = NULL; // optional data that will be passed to the callback functions + + // for debug output on these platforms +#if defined (_PS3) || defined (_PS2) || defined (_PSP) || defined(_NITRO) + #ifdef GSI_COMMON_DEBUG + // Define GSI_COMMON_DEBUG if you want to view the SDK debug output + // Set the SDK debug log file, or set your own handler using gsSetDebugCallback + //gsSetDebugFile(stdout); // output to console + gsSetDebugCallback(DebugCallback); + + // Set debug levels + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); + #endif +#endif + + //set the secret key, in a semi-obfuscated manner + secret_key[0] = 'H'; + secret_key[1] = 'A'; + secret_key[2] = '6'; + secret_key[3] = 'z'; + secret_key[4] = 'k'; + secret_key[5] = 'S'; + secret_key[6] = '\0'; + + // register our custom keys (you do not have to register the reserved standard keys) + AppDebug("Registering custom keys\n"); + qr2_register_key(GRAVITY_KEY, _T("gravity") ); + qr2_register_key(RANKINGON_KEY, _T("rankingon")); + qr2_register_key(TIME__KEY, _T("time_") ); // player keys always end with '_' + qr2_register_key(AVGPING_T_KEY, _T("avgping_t")); // team keys always end with '_t' + + // create some random game data + init_game(); + + // Check if we want to override our IP (otherwise qr2 will set for us) +#ifndef GSI_UNICODE + if (argc>1) + strcpy(ip, argp[1]); +#else + if (argc>1) + AsciiToUCS2String(argp[1], ip); +#endif + + AppDebug("Initializing SDK; server should show up on the master list within 6-10 sec.\n"); + //Call qr_init with the query port number and gamename, default IP address, and no user data + //Pass NULL for the qrec parameter (first parameter) as long as you're running a single game + //server instance per process + //Reference gt2nat sample for qr2_init_socket implementation + if (qr2_init(NULL,argc>1?ip:NULL,BASE_PORT,GAME_NAME, secret_key, isPublic, isNatNegSupported, + serverkey_callback, playerkey_callback, teamkey_callback, + keylist_callback, count_callback, adderror_callback, userData) != e_qrnoerror) + { + printf("Error starting query sockets\n"); + return -1; + } + + // Set a function to be called when we receive a game specific message + qr2_register_clientmessage_callback(NULL, cm_callback); + + // Set a function to be called when we receive a nat negotiation request + qr2_register_natneg_callback(NULL, nn_callback); + + // Set a function to be called when a client has connected + qr2_register_clientconnected_callback(NULL, cc_callback); + + // Enter the main loop + AppDebug("Sample will quit after 60 seconds\n"); + aStartTime = current_time(); + while ((current_time() - aStartTime) < 60000) + { + gsi_time totalTime = current_time() - aStartTime; // used to change the game state after 30 seconds + + // An actual game would do something between "thinks" + DoGameStuff(totalTime); + + //check for / process incoming queries + //should be called every 10-100 ms; quicker calls produce more accurate ping measurements + qr2_think(NULL); + } + + AppDebug("Shutting down - server will be removed from the master server list\n"); + //let gamemaster know we are shutting down (removes dead server entry from the list) + qr2_shutdown(NULL); + + +#ifdef GSI_UNICODE + // In Unicode mode we must perform additional cleanup + qr2_internal_key_list_free(); +#endif + + // Finished + return 0; +} + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2csample.dsp b/xrGameSpy/gamespy/qr2/qr2csample/qr2csample.dsp new file mode 100644 index 00000000000..4b4c37290b4 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2csample.dsp @@ -0,0 +1,292 @@ +# Microsoft Developer Studio Project File - Name="qr2csample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qr2csample - Win32 Unicode Release +!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 "qr2csample.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 "qr2csample.mak" CFG="qr2csample - Win32 Unicode Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qr2csample - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2csample - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2csample - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2csample - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/qr2/qr2csample" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qr2csample - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I ".." /I "../.." /I "../../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "qr2csample - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "../.." /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "qr2csample - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qr2csample___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "qr2csample___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "../.." /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "../.." /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "qr2csample - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qr2csample___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "qr2csample___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "../.." /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /I "../.." /I "../../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "qr2csample - Win32 Release" +# Name "qr2csample - Win32 Debug" +# Name "qr2csample - Win32 Unicode Debug" +# Name "qr2csample - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\qr2csample.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\qr2regkeys.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2csample_vs2005.vcproj b/xrGameSpy/gamespy/qr2/qr2csample/qr2csample_vs2005.vcproj new file mode 100644 index 00000000000..3f0def0edd9 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2csample_vs2005.vcproj @@ -0,0 +1,918 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2linux/Makefile b/xrGameSpy/gamespy/qr2/qr2csample/qr2linux/Makefile new file mode 100644 index 00000000000..a97d01624ad --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2linux/Makefile @@ -0,0 +1,52 @@ +# Query & Reporting 2 SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=qr2csample + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../../../common/gsPlatform.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsDebug.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../qr2.o\ + ../../qr2regkeys.o\ + ../../../natneg/natneg.o\ + ../../../natneg/NATify.o\ + ../qr2csample.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2macosx/Makefile b/xrGameSpy/gamespy/qr2/qr2csample/qr2macosx/Makefile new file mode 100644 index 00000000000..4505aacd37b --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2macosx/Makefile @@ -0,0 +1,26 @@ +# Query & Reporting 2 SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=qr2csample + +PROG_OBJS = \ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../natneg/natneg.o\ + ../../../natneg/NATify.o\ + ../../qr2.o\ + ../../qr2regkeys.o\ + ../qr2csample.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/Nitro.lcf b/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/qr2nitrocw.mcp b/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/qr2nitrocw.mcp new file mode 100644 index 00000000000..3c59c7bbb72 Binary files /dev/null and b/xrGameSpy/gamespy/qr2/qr2csample/qr2nitrocw/qr2nitrocw.mcp differ diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2/Makefile b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2/Makefile new file mode 100644 index 00000000000..17d41069f2d --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2/Makefile @@ -0,0 +1,24 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = qr2csample + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o\ + ../../../stringutil.o \ + ../../qr2.o\ + ../../qr2regkeys.o\ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2cw/qr2ps2cw.mcp b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2cw/qr2ps2cw.mcp new file mode 100644 index 00000000000..08d145a1232 Binary files /dev/null and b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2cw/qr2ps2cw.mcp differ diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.dsp b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.dsp new file mode 100644 index 00000000000..21c28a0b8a5 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.dsp @@ -0,0 +1,327 @@ +# Microsoft Developer Studio Project File - Name="qr2ps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qr2ps2prodg - Win32 Release_Insock +!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 "qr2ps2prodg.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 "qr2ps2prodg.mak" CFG="qr2ps2prodg - Win32 Release_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qr2ps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2ps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2ps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2ps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2ps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "qr2ps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/qr2/qr2csample/qr2ps2prodg", ZTEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qr2ps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug -fshort-wchar /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_EENet\qr2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "qr2ps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qr2ps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "qr2ps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /D "_DEBUG" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "INSOCK" /FD /debug -fshort-wchar /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_EENet\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_Insock\qr2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "qr2ps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /FD /debug -fshort-wchar /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_SNSystems\qr2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "qr2ps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "qr2ps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qr2ps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "qr2ps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "EENET" /D "SN_TARGET_PS2" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "c:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# SUBTRACT BASE LINK32 /nodefaultlib +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "qr2ps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_SYSTEMS" /D "SN_TARGET_PS2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\qr2ps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\qr2ps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "qr2ps2prodg - Win32 Debug_EENet" +# Name "qr2ps2prodg - Win32 Debug_Insock" +# Name "qr2ps2prodg - Win32 Debug_SNSystems" +# Name "qr2ps2prodg - Win32 Release_EENet" +# Name "qr2ps2prodg - Win32 Release_Insock" +# Name "qr2ps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\qr2csample.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2.h +# End Source File +# Begin Source File + +SOURCE=..\..\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2regkeys.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.dsw b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.dsw new file mode 100644 index 00000000000..b838df483f0 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qr2ps2prodg"=.\qr2ps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/qr2/qr2csample/qr2ps2prodg", ZTEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/qr2/qr2csample/qr2ps2prodg", ZTEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.sln b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.sln new file mode 100644 index 00000000000..f855e6b37b9 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.sln @@ -0,0 +1,43 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qr2ps2prodg", "qr2ps2prodg.vcproj", "{0C6CBA96-9BE6-4597-8662-C621D69E47AC}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = qr2ps2prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {0C6CBA96-9BE6-4597-8662-C621D69E47AC}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.vcproj b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.vcproj new file mode 100644 index 00000000000..dffd0357888 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps2prodg/qr2ps2prodg.vcproj @@ -0,0 +1,650 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3/Makefile b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3/Makefile new file mode 100644 index 00000000000..2b4b1ce94d0 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3/Makefile @@ -0,0 +1,29 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = qr2csample + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../qr2.o\ + ../../qr2regkeys.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3prodg/qr2ps3prodg.sln b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3prodg/qr2ps3prodg.sln new file mode 100644 index 00000000000..480d13d2be7 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3prodg/qr2ps3prodg.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qr2ps3prodg", "qr2ps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccProjectUniqueName0 = qr2ps3prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3prodg/qr2ps3prodg.vcproj b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3prodg/qr2ps3prodg.vcproj new file mode 100644 index 00000000000..4ebda54a4a4 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2ps3prodg/qr2ps3prodg.vcproj @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2psp/Makefile b/xrGameSpy/gamespy/qr2/qr2csample/qr2psp/Makefile new file mode 100644 index 00000000000..2ac21c7a35e --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2psp/Makefile @@ -0,0 +1,26 @@ +#GameSpy.net PSP Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +#SDK_LIBS = + +#Name of the SDK sample +TARGET = qr2csample + +#All the object files needed for this SDK +OBJS = ../../../common/psp/pspcommon.o\ + ../../../common/psp/gsUtilPSP.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../qr2.o\ + ../../qr2regkeys.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/psp/Makefile.common + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2pspprodg/qr2pspprodg.sln b/xrGameSpy/gamespy/qr2/qr2csample/qr2pspprodg/qr2pspprodg.sln new file mode 100644 index 00000000000..d0a4cd146c9 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2pspprodg/qr2pspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qr2pspprodg", "qr2pspprodg.vcproj", "{1963F851-A8FF-4063-8573-3889C78F1BD9}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = qr2pspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1963F851-A8FF-4063-8573-3889C78F1BD9}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {1963F851-A8FF-4063-8573-3889C78F1BD9}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {1963F851-A8FF-4063-8573-3889C78F1BD9}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {1963F851-A8FF-4063-8573-3889C78F1BD9}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {1963F851-A8FF-4063-8573-3889C78F1BD9}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {1963F851-A8FF-4063-8573-3889C78F1BD9}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2pspprodg/qr2pspprodg.vcproj b/xrGameSpy/gamespy/qr2/qr2csample/qr2pspprodg/qr2pspprodg.vcproj new file mode 100644 index 00000000000..5a28d08ddc7 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2pspprodg/qr2pspprodg.vcproj @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2revolutioncw/qr2revolutioncw.mcp b/xrGameSpy/gamespy/qr2/qr2csample/qr2revolutioncw/qr2revolutioncw.mcp new file mode 100644 index 00000000000..189c061f3ca Binary files /dev/null and b/xrGameSpy/gamespy/qr2/qr2csample/qr2revolutioncw/qr2revolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2x360/qr2x360.sln b/xrGameSpy/gamespy/qr2/qr2csample/qr2x360/qr2x360.sln new file mode 100644 index 00000000000..05831a2e3d0 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2x360/qr2x360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qr2x360", "qr2x360.vcproj", "{87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {87AD5C21-8F1F-4039-AE0F-CAFD56B88AC9}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/qr2/qr2csample/qr2x360/qr2x360.vcproj b/xrGameSpy/gamespy/qr2/qr2csample/qr2x360/qr2x360.vcproj new file mode 100644 index 00000000000..afa616f8912 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2csample/qr2x360/qr2x360.vcproj @@ -0,0 +1,623 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/qr2/qr2regkeys.c b/xrGameSpy/gamespy/qr2/qr2regkeys.c new file mode 100644 index 00000000000..ff4cf29076c --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2regkeys.c @@ -0,0 +1,157 @@ + +#include "qr2regkeys.h" + +#include "../common/gsStringUtil.h" +#include "../common/gsDebug.h" + +#ifdef __MWERKS__ // CodeWarrior requires prototypes +void qr2_register_keyW(int keyid, const unsigned short *key); +void qr2_register_keyA(int keyid, const char *key); +#endif + +const char *qr2_registered_key_list[MAX_REGISTERED_KEYS] = +{ + "", //0 is reserved + "hostname", //1 + "gamename", //2 + "gamever", //3 + "hostport", //4 + "mapname", //5 + "gametype", //6 + "gamevariant", //7 + "numplayers", //8 + "numteams", //9 + "maxplayers", //10 + "gamemode", //11 + "teamplay", //12 + "fraglimit", //13 + "teamfraglimit",//14 + "timeelapsed", //15 + "timelimit", //16 + "roundtime", //17 + "roundelapsed", //18 + "password", //19 + "groupid", //20 + "player_", //21 + "score_", //22 + "skill_", //23 + "ping_", //24 + "team_", //25 + "deaths_", //26 + "pid_", //27 + "team_t", //28 + "score_t", //29 + "nn_groupid", //30 + + // Query From Master Only keys + "country", //31 + "region" //32 +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Keep a list of the unicode keys we've allocated internally so that we can free +// them when qr2 is shutdown +typedef struct QR2KeyListNodeS +{ + char* mKeyData; + struct QR2KeyListNodeS* mNextKey; +} QR2KeyListNode; + +typedef struct QR2KeyListS +{ + struct QR2KeyListNodeS* mHead; +} QR2KeyList; + +static QR2KeyList qr2_internal_key_list = { NULL }; + +void qr2_internal_key_list_append(char* theKey) +{ + QR2KeyListNode* aNewNode; + + assert(theKey != NULL); + + // Init the new node + aNewNode = (QR2KeyListNode*)gsimalloc(sizeof(QR2KeyListNode)); + aNewNode->mKeyData = theKey; + aNewNode->mNextKey = NULL; + + // Check for a NULL head + if (qr2_internal_key_list.mHead == NULL) + qr2_internal_key_list.mHead = aNewNode; + else + { + // Find the end of the list and append this node + QR2KeyListNode* aInsertPlace = qr2_internal_key_list.mHead; + while(aInsertPlace->mNextKey != NULL) + aInsertPlace = aInsertPlace->mNextKey; + + aInsertPlace->mNextKey = aNewNode; + } +} + +void qr2_internal_key_list_free() +{ + QR2KeyListNode* aNodeToFree; + QR2KeyListNode* aNextNode; + + // Free the nodes + aNodeToFree = qr2_internal_key_list.mHead; + while (aNodeToFree != NULL) + { + aNextNode = aNodeToFree->mNextKey; // Get a ptr to the next node (or will be lost) + gsifree(aNodeToFree->mKeyData); // free the string we allocated in qr2_register_keyW + gsifree(aNodeToFree); // free the current node + aNodeToFree = aNextNode; // set the current node to the next node + } + + // Initialize the list back to NULL + qr2_internal_key_list.mHead = NULL; +} + +gsi_bool qr2_internal_is_master_only_key(const char * keyname) +{ + if (strcmp(keyname,qr2_registered_key_list[COUNTRY_KEY]) == 0 || + strcmp(keyname,qr2_registered_key_list[REGION_KEY]) == 0) + return gsi_true; + + return gsi_false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void qr2_register_keyA(int keyid, const char *key) +{ + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_keyA()\r\n"); + + // Verify the key range + if (keyid < NUM_RESERVED_KEYS || keyid > MAX_REGISTERED_KEYS) + { + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_WarmError, + "Attempted to register invalid key %d - %s\r\n", keyid, key); + return; + } + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_Comment, + "Registered key %d - %s\r\n", keyid, key); + + qr2_registered_key_list[keyid] = key; +} +void qr2_register_keyW(int keyid, const unsigned short *key) +{ + char* key_A = NULL; + + gsDebugFormat(GSIDebugCat_QR2, GSIDebugType_Misc, GSIDebugLevel_StackTrace, + "qr2_register_keyW()\r\n"); + + // Create UTF8 copy + key_A = UCS2ToUTF8StringAlloc(key); + + // Register the ascii version + qr2_register_keyA(keyid, key_A); + + // Keep track of the unicode version so we can delete it later + qr2_internal_key_list_append(key_A); +} diff --git a/xrGameSpy/gamespy/qr2/qr2regkeys.h b/xrGameSpy/gamespy/qr2/qr2regkeys.h new file mode 100644 index 00000000000..b312fa15214 --- /dev/null +++ b/xrGameSpy/gamespy/qr2/qr2regkeys.h @@ -0,0 +1,84 @@ + + +#ifndef _QR2REGKEYS_H_ +#define _QR2REGKEYS_H_ + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MAX_REGISTERED_KEYS 254 +#define NUM_RESERVED_KEYS 50 + + +#define HOSTNAME_KEY 1 +#define GAMENAME_KEY 2 +#define GAMEVER_KEY 3 +#define HOSTPORT_KEY 4 +#define MAPNAME_KEY 5 +#define GAMETYPE_KEY 6 +#define GAMEVARIANT_KEY 7 +#define NUMPLAYERS_KEY 8 +#define NUMTEAMS_KEY 9 +#define MAXPLAYERS_KEY 10 +#define GAMEMODE_KEY 11 +#define TEAMPLAY_KEY 12 +#define FRAGLIMIT_KEY 13 +#define TEAMFRAGLIMIT_KEY 14 +#define TIMEELAPSED_KEY 15 +#define TIMELIMIT_KEY 16 +#define ROUNDTIME_KEY 17 +#define ROUNDELAPSED_KEY 18 +#define PASSWORD_KEY 19 +#define GROUPID_KEY 20 +#define PLAYER__KEY 21 +#define SCORE__KEY 22 +#define SKILL__KEY 23 +#define PING__KEY 24 +#define TEAM__KEY 25 +#define DEATHS__KEY 26 +#define PID__KEY 27 +#define TEAM_T_KEY 28 +#define SCORE_T_KEY 29 +#define NN_GROUP_ID_KEY 30 + +// Query-From-Master-Only keys +// - these two values are retrieved only from the master server so we need to make +// sure not to overwrite them when querying servers directly +#define COUNTRY_KEY 31 +#define REGION_KEY 32 + + +#ifndef GSI_UNICODE + #define qr2_register_key qr2_register_keyA +#else + #define qr2_register_key qr2_register_keyW +#endif + +extern const char *qr2_registered_key_list[]; +void qr2_register_key(int keyid, const gsi_char *key); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Necessary for unicode support. Must store a copy of the UTF8 keys +// generated from qr2_register_keyW +void qr2_internal_key_list_append(char* theKey); +void qr2_internal_key_list_free(); // call this at qr2 shutdown + +// internal function used by ServerBrowser to check if a key is Query-Master-Only +gsi_bool qr2_internal_is_master_only_key(const char * keyname); + + +// Always define for direct access +void qr2_register_keyA(int keyid, const char *key); +void qr2_register_keyW(int keyid, const unsigned short *key); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/xrGameSpy/gamespy/qr2/querytest.exe b/xrGameSpy/gamespy/qr2/querytest.exe new file mode 100644 index 00000000000..6d108625a49 Binary files /dev/null and b/xrGameSpy/gamespy/qr2/querytest.exe differ diff --git a/xrGameSpy/gamespy/sake/changelog.txt b/xrGameSpy/gamespy/sake/changelog.txt new file mode 100644 index 00000000000..cc0be7b4a68 --- /dev/null +++ b/xrGameSpy/gamespy/sake/changelog.txt @@ -0,0 +1,57 @@ +Changelog for: GameSpy SAKE SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.04.00 RMV RELEASE Released to Developer Site +12-11-2007 1.03.03 SN FIX Removed a check due to compiler warning +11-16-2007 1.03.02 SAH FIX Fixed mem leak in saketest.c from invalid gsCore shutdown, added memleak check +10-09-2007 1.03.01 SAH FIX Fixed mFilter and mTargetFilter to support unicode strings + SAH OTHER Added Win32 Unicode Debug & Unicode Release projects to VS2005 solution +08-06-2007 1.03.00 RMV RELEASE Released to Developer Site +08-03-2007 1.02.08 SAH FEATURE Added mCacheFlag for searchForRecords and getRowCount +07-19-2007 1.02.07 SAH FIX Fixed projects to work with new GP changes +07-03-2007 1.02.06 SAH FIX Fixed memory leak in GetRandomRecord +06-29-2007 1.02.05 SAH OTHER Added SAKEFileResult_SERVER_ERROR to error code list +06-20-2007 1.02.04 SAH FEATURE Added sakeGetRecordCount + SAH FEATURE Added new input data for sakeSearchForRecords for initial leaderboard support +06-13-2007 1.02.03 SAH FIX Fixed memory leak from not freeing BinaryData fields or UnicodeStrings +05-29-2007 1.02.02 DES FEATURE Updated saketest to include GetRandomRecord test +03-22-2007 1.02.01 DES FIX Allow NULL for mFilter and mSort with SearchForRecords + DES FEATURE Added GetRandomRecord + DES FEATURE Added special field "my_rating" + DES FEATURE Added special filter tags "@rated" and "@unrated" +03-05-2007 1.02.00 SAH RELEASE Released to Developer Site +01-22-2007 1.01.02 SAH FIX Fixed unicode for upload/download URLs and setGameName, added unicode config +01-17-2007 1.01.01 DES RELEASE Limited Release +01-16-2007 1.01.01 DES FEATURE Added X360 support +12-15-2006 1.01.00 MJW RELEASE Released to Developer Site +12-14-2006 1.00.20 MJW FIX Removed tabs from Makefile for linux (was causing it to break) +11-10-2006 1.00.19 JR RELEASE Limited Release +11-02-2006 1.00.19 SAH FIX Fixed bug where all booleans values returned "false", even when true +10-23-2006 1.00.18 DES RELEASE Limited release +10-12-2006 1.00.18 DES FIX Added explicit cast for gsimalloc +10-11-2006 1.00.17 DES FIX Fixed Unicode issue with upload/download URLs +10-05-2006 1.00.16 SAH FIX Updated Mac OSX Makefile + SAH FIX Fixed saketest to get rid of compiler warning errors for Mac +09-29-2006 1.00.15 SAH FIX Updated all sake projects to compile with GP (for saketest change) +09-28-2006 1.00.14 SAH FIX Updated saketest application to login to GP and retrieve a loginticket to authenticate sake. +09-28-2006 1.00.13 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +09-27-2006 1.00.13 SN OTHER Removed function below until development backend is available +09-20-2006 1.00.12 SN FEATURE Added an interface function allow usage of the development environment +08-04-2006 1.00.11 SN FIX Fixed Sake Read requestion function for date and time to use time_t +08-04-2006 1.00.10 SAH FIX Changed DateTime read call to gsXmlReadChildAsDateTimeElement to parse correctly +08-02-2006 1.00.09 SAH RELEASE Releasing to developer site +08-01-2006 1.00.09 SAH FIX Fixed saketest.c so that it won't crash when a specific record does not exist + SAH OTHER Added sakelinux makefile - *NOTE: unsupported in current version due to pthreads +07-31-2006 1.00.08 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 1.00.07 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-06-2006 1.00.06 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +07-06-2006 1.00.05 SAH FIX Fixed NITRO project & linker command file (to work with CW 2.0/NitroSDK 3.1) +07-05-2006 1.00.04 SAH OTHER Updated saketest.c to have a larger size upload test (5K by default) +06-21-2006 1.00.03 DES FEATURE sakeSetGame now requires the game's secret key +05-31-2006 1.00.02 SAH RELEASE Releasing to developer site +05-30-2006 1.00.01 SAH FIX #ifdef PS2 Unicode hack to get rid of PS2 Unicode warnings + SAH FIX Added GSI_UNUSED calls, newline at end of files +05-18-2006 1.00.00 DES RELEASE Initial limited release + diff --git a/xrGameSpy/gamespy/sake/sake.dsp b/xrGameSpy/gamespy/sake/sake.dsp new file mode 100644 index 00000000000..aa51e24009e --- /dev/null +++ b/xrGameSpy/gamespy/sake/sake.dsp @@ -0,0 +1,128 @@ +# Microsoft Developer Studio Project File - Name="sake" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=sake - 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 "sake.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 "sake.mak" CFG="sake - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sake - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "sake - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/sake" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sake - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /I "../gsoap" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "sake - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /I "../gsoap" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "sake - Win32 Release" +# Name "sake - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sakeMain.c +# End Source File +# Begin Source File + +SOURCE=.\sakeRequest.c +# End Source File +# Begin Source File + +SOURCE=.\sakeRequestMisc.c +# End Source File +# Begin Source File + +SOURCE=.\sakeRequestModify.c +# End Source File +# Begin Source File + +SOURCE=.\sakeRequestRead.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\sake.h +# End Source File +# Begin Source File + +SOURCE=.\sakeMain.h +# End Source File +# Begin Source File + +SOURCE=.\sakeRequest.h +# End Source File +# Begin Source File + +SOURCE=.\sakeRequestInternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/sake/sake.dsw b/xrGameSpy/gamespy/sake/sake.dsw new file mode 100644 index 00000000000..715f2342e0c --- /dev/null +++ b/xrGameSpy/gamespy/sake/sake.dsw @@ -0,0 +1,53 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "sake"=.\sake.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/sake + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "saketest"=.\saketest\saketest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/sake/saketest + .\saketest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + $/Gamespy/GOA/sake + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/sake/sake.h b/xrGameSpy/gamespy/sake/sake.h new file mode 100644 index 00000000000..8a4d0a3d478 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sake.h @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SAKE_H__ +#define __SAKE_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../common/gsCommon.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef SAKE_CALL + #define SAKE_CALL +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// URL for sake webservice +#define SAKE_MAX_URL_LENGTH 128 +extern char sakeiSoapUrl[SAKE_MAX_URL_LENGTH]; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// General +typedef struct SAKEInternal *SAKE; + +typedef enum +{ + SAKEStartupResult_SUCCESS, + SAKEStartupResult_NOT_AVAILABLE, + SAKEStartupResult_CORE_SHUTDOWN, + SAKEStartupResult_OUT_OF_MEMORY +} SAKEStartupResult; + +SAKEStartupResult SAKE_CALL sakeStartup(SAKE *sakePtr); +void SAKE_CALL sakeShutdown(SAKE sake); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Authentication +void SAKE_CALL sakeSetGame(SAKE sake, const gsi_char *gameName, int gameId, const gsi_char *secretKey); +void SAKE_CALL sakeSetProfile(SAKE sake, int profileId, const char *loginTicket); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Fields +typedef enum +{ + SAKEFieldType_BYTE, + SAKEFieldType_SHORT, + SAKEFieldType_INT, + SAKEFieldType_FLOAT, + SAKEFieldType_ASCII_STRING, + SAKEFieldType_UNICODE_STRING, + SAKEFieldType_BOOLEAN, + SAKEFieldType_DATE_AND_TIME, + SAKEFieldType_BINARY_DATA, + SAKEFieldType_INT64, + SAKEFieldType_NUM_FIELD_TYPES +} SAKEFieldType; + +typedef struct +{ + gsi_u8 *mValue; + int mLength; +} SAKEBinaryData; + +typedef union +{ + gsi_u8 mByte; + gsi_i16 mShort; + gsi_i32 mInt; + float mFloat; + char *mAsciiString; + gsi_u16 *mUnicodeString; + gsi_bool mBoolean; + time_t mDateAndTime; + SAKEBinaryData mBinaryData; + gsi_i64 mInt64; +} SAKEValue; + +typedef struct +{ + char *mName; + SAKEFieldType mType; + SAKEValue mValue; +} SAKEField; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Requests +typedef struct SAKERequestInternal *SAKERequest; + +typedef enum +{ + SAKEStartRequestResult_SUCCESS, + SAKEStartRequestResult_NOT_AUTHENTICATED, + SAKEStartRequestResult_OUT_OF_MEMORY, + SAKEStartRequestResult_BAD_INPUT, + SAKEStartRequestResult_BAD_TABLEID, + SAKEStartRequestResult_BAD_FIELDS, + SAKEStartRequestResult_BAD_NUM_FIELDS, + SAKEStartRequestResult_BAD_FIELD_NAME, + SAKEStartRequestResult_BAD_FIELD_TYPE, + SAKEStartRequestResult_BAD_FIELD_VALUE, + SAKEStartRequestResult_BAD_OFFSET, + SAKEStartRequestResult_BAD_MAX, + SAKEStartRequestResult_BAD_RECORDIDS, + SAKEStartRequestResult_BAD_NUM_RECORDIDS, + SAKEStartRequestResult_UNKNOWN_ERROR +} SAKEStartRequestResult; + +typedef enum +{ + SAKERequestResult_SUCCESS, + SAKERequestResult_SECRET_KEY_INVALID, + SAKERequestResult_SERVICE_DISABLED, + SAKERequestResult_CONNECTION_TIMEOUT, + SAKERequestResult_CONNECTION_ERROR, + SAKERequestResult_MALFORMED_RESPONSE, + SAKERequestResult_OUT_OF_MEMORY, + SAKERequestResult_DATABASE_UNAVAILABLE, + SAKERequestResult_LOGIN_TICKET_INVALID, + SAKERequestResult_LOGIN_TICKET_EXPIRED, + SAKERequestResult_TABLE_NOT_FOUND, + SAKERequestResult_RECORD_NOT_FOUND, + SAKERequestResult_FIELD_NOT_FOUND, + SAKERequestResult_FIELD_TYPE_INVALID, + SAKERequestResult_NO_PERMISSION, + SAKERequestResult_RECORD_LIMIT_REACHED, + SAKERequestResult_ALREADY_RATED, + SAKERequestResult_NOT_RATEABLE, + SAKERequestResult_NOT_OWNED, + SAKERequestResult_FILTER_INVALID, + SAKERequestResult_SORT_INVALID, + SAKERequestResult_TARGET_FILTER_INVALID, + SAKERequestResult_UNKNOWN_ERROR +} SAKERequestResult; + +typedef void (*SAKERequestCallback)(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// get start request result +SAKEStartRequestResult SAKE_CALL sakeGetStartRequestResult(SAKE sake); + +/////////////////////////////////////////////////////////////////////////////// +// create record +typedef struct +{ + char *mTableId; + SAKEField *mFields; + int mNumFields; +} SAKECreateRecordInput; +typedef struct +{ + int mRecordId; +} SAKECreateRecordOutput; +SAKERequest SAKE_CALL sakeCreateRecord(SAKE sake, SAKECreateRecordInput *input, SAKERequestCallback callback, void *userData); + +//////////////////////////// /////////////////////////////////////////////////// +// update record +typedef struct +{ + char *mTableId; + int mRecordId; + SAKEField *mFields; + int mNumFields; +} SAKEUpdateRecordInput; +SAKERequest SAKE_CALL sakeUpdateRecord(SAKE sake, SAKEUpdateRecordInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// delete record +typedef struct +{ + char *mTableId; + int mRecordId; +} SAKEDeleteRecordInput; +SAKERequest SAKE_CALL sakeDeleteRecord(SAKE sake, SAKEDeleteRecordInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// search for records +typedef struct +{ + char *mTableId; + char **mFieldNames; + int mNumFields; + gsi_char *mFilter; + char *mSort; + int mOffset; + int mMaxRecords; + gsi_char *mTargetRecordFilter; + int mSurroundingRecordsCount; + int *mOwnerIds; + int mNumOwnerIds; + gsi_bool mCacheFlag; +} SAKESearchForRecordsInput; +typedef struct +{ + int mNumRecords; + SAKEField **mRecords; +} SAKESearchForRecordsOutput; +SAKERequest SAKE_CALL sakeSearchForRecords(SAKE sake, SAKESearchForRecordsInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// get my records +typedef struct +{ + char *mTableId; + char **mFieldNames; + int mNumFields; +} SAKEGetMyRecordsInput; +typedef struct +{ + int mNumRecords; + SAKEField **mRecords; +} SAKEGetMyRecordsOutput; +SAKERequest SAKE_CALL sakeGetMyRecords(SAKE sake, SAKEGetMyRecordsInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// get specific records +typedef struct +{ + char *mTableId; + int *mRecordIds; + int mNumRecordIds; + char **mFieldNames; + int mNumFields; +} SAKEGetSpecificRecordsInput; +typedef struct +{ + int mNumRecords; + SAKEField **mRecords; +} SAKEGetSpecificRecordsOutput; +SAKERequest SAKE_CALL sakeGetSpecificRecords(SAKE sake, SAKEGetSpecificRecordsInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// get random record +typedef struct +{ + char *mTableId; + char **mFieldNames; + int mNumFields; + gsi_char *mFilter; +} SAKEGetRandomRecordInput; +typedef struct +{ + SAKEField *mRecord; +} SAKEGetRandomRecordOutput; +SAKERequest SAKE_CALL sakeGetRandomRecord(SAKE sake, SAKEGetRandomRecordInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// rate record +typedef struct +{ + char *mTableId; + int mRecordId; + gsi_u8 mRating; +} SAKERateRecordInput; +typedef struct +{ + int mNumRatings; + float mAverageRating; +} SAKERateRecordOutput; +SAKERequest SAKE_CALL sakeRateRecord(SAKE sake, SAKERateRecordInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// get record limit +typedef struct +{ + char *mTableId; +} SAKEGetRecordLimitInput; +typedef struct +{ + int mLimitPerOwner; + int mNumOwned; +} SAKEGetRecordLimitOutput; +SAKERequest SAKE_CALL sakeGetRecordLimit(SAKE sake, SAKEGetRecordLimitInput *input, SAKERequestCallback callback, void *userData); + +/////////////////////////////////////////////////////////////////////////////// +// get record count +typedef struct +{ + char *mTableId; + gsi_char *mFilter; + gsi_bool mCacheFlag; +} SAKEGetRecordCountInput; +typedef struct +{ + int mCount; +} SAKEGetRecordCountOutput; +SAKERequest SAKE_CALL sakeGetRecordCount(SAKE sake, SAKEGetRecordCountInput *input, SAKERequestCallback callback, void *userData); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// read request utility +SAKEField * SAKE_CALL sakeGetFieldByName(const char *name, SAKEField *fields, int numFields); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Files + +#define SAKE_FILE_RESULT_HEADER "Sake-File-Result:" +#define SAKE_FILE_ID_HEADER "Sake-File-Id:" + +// Sake-File-Result from the HTTP response header +typedef enum +{ + SAKEFileResult_SUCCESS = 0, + SAKEFileResult_BAD_HTTP_METHOD = 1, + SAKEFileResult_BAD_FILE_COUNT = 2, + SAKEFileResult_MISSING_PARAMETER = 3, + SAKEFileResult_FILE_NOT_FOUND = 4, + SAKEFileResult_FILE_TOO_LARGE = 5, + SAKEFileResult_SERVER_ERROR = 6, + SAKEFileResult_UNKNOWN_ERROR +} SAKEFileResult; + +gsi_bool SAKE_CALL sakeSetFileDownloadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH]); +gsi_bool SAKE_CALL sakeSetFileUploadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH]); + +gsi_bool SAKE_CALL sakeGetFileDownloadURL(SAKE sake, int fileId, gsi_char url[SAKE_MAX_URL_LENGTH]); +gsi_bool SAKE_CALL sakeGetFileUploadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH]); + +gsi_bool SAKE_CALL sakeGetFileResultFromHeaders(const char *headers, SAKEFileResult *result); +gsi_bool SAKE_CALL sakeGetFileIdFromHeaders(const char *headers, int *fileId); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SAKE_H__ diff --git a/xrGameSpy/gamespy/sake/sakeMain.c b/xrGameSpy/gamespy/sake/sakeMain.c new file mode 100644 index 00000000000..b59e2b09827 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeMain.c @@ -0,0 +1,428 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeMain.h" +#include "sakeRequest.h" +#include "../common/gsAvailable.h" +#include "../common/gsCore.h" + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// General + +gsi_char gSakeUploadUrlOverride[SAKE_MAX_URL_LENGTH]; +gsi_char gSakeDownloadUrlOverride[SAKE_MAX_URL_LENGTH]; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKEStartupResult SAKE_CALL sakeStartup(SAKE * sakePtr) +{ + SAKE sake; + + GS_ASSERT(sakePtr); + + // check for availability + if(__GSIACResult != GSIACAvailable) + return SAKEStartupResult_NOT_AVAILABLE; + + // check that the core is initialized + if(gsCoreIsShutdown()) + return SAKEStartupResult_CORE_SHUTDOWN; + + // allocate the sake object + sake = (SAKE)gsimalloc(sizeof(SAKEInternal)); + if(sake == NULL) + return SAKEStartupResult_OUT_OF_MEMORY; + + // init the sake object + memset(sake, 0, sizeof(SAKEInternal)); + + // store the object in the user pointer + *sakePtr = sake; + + return SAKEStartupResult_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void SAKE_CALL sakeShutdown(SAKE sake) +{ + GS_ASSERT(sake); + + //TODO: ensure that there are no pending operations + // that might reference this object + + // free the struct + gsifree(sake); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Authentication + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void SAKE_CALL sakeSetGame(SAKE sake, const gsi_char * gameName, int gameId, const gsi_char *secretKey) +{ + GS_ASSERT(sake); + GS_ASSERT(gameName && (_tcslen(gameName) <= SAKEI_GAME_NAME_LENGTH)); + GS_ASSERT(gameId >= 0); + GS_ASSERT(secretKey && (_tcslen(secretKey) <= SAKEI_SECRET_KEY_LENGTH)); + +#ifdef GSI_UNICODE + // convert gamename and secretkey to ascii for executing requests + UCS2ToAsciiString(gameName, sake->mGameName); + UCS2ToAsciiString(secretKey, sake->mSecretKey); +#else + strcpy(sake->mGameName, gameName); + strcpy(sake->mSecretKey, secretKey); +#endif + + sake->mGameId = gameId; + sake->mIsGameAuthenticated = gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void SAKE_CALL sakeSetProfile(SAKE sake, int profileId, const char *loginTicket) +{ + GS_ASSERT(sake); + GS_ASSERT(loginTicket); + GS_ASSERT(strlen(loginTicket) == SAKEI_LOGIN_TICKET_LENGTH); + + sake->mProfileId = profileId; + memcpy(sake->mLoginTicket, loginTicket, SAKEI_LOGIN_TICKET_LENGTH + 1); + sake->mIsProfileAuthenticated = gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Requests + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKEStartRequestResult SAKE_CALL sakeGetStartRequestResult(SAKE sake) +{ + GS_ASSERT(sake); + + return sake->mStartRequestResult; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKERequest SAKE_CALL sakeiRunRequest(SAKE sake, void *input, + SAKERequestCallback callback, void *userData, + SAKEIRequestType type, + SAKEStartRequestResult (*startRequestFunc)(SAKERequest request)) +{ + SAKERequest request; + + GS_ASSERT(sake); + + request = sakeiInitRequest(sake, type, input, callback, userData); + if(!request) + return NULL; + + sake->mStartRequestResult = startRequestFunc(request); + if(sake->mStartRequestResult != SAKEStartRequestResult_SUCCESS) + { + sakeiFreeRequest(request); + return NULL; + } + + return request; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeCreateRecord(SAKE sake, SAKECreateRecordInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_CREATE_RECORD, sakeiStartCreateRecordRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeUpdateRecord(SAKE sake, SAKEUpdateRecordInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_UPDATE_RECORD, sakeiStartUpdateRecordRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeDeleteRecord(SAKE sake, SAKEDeleteRecordInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_DELETE_RECORD, sakeiStartDeleteRecordRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeSearchForRecords(SAKE sake, SAKESearchForRecordsInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_SEARCH_FOR_RECORDS, sakeiStartSearchForRecordsRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeGetMyRecords(SAKE sake, SAKEGetMyRecordsInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_MY_RECORDS, sakeiStartGetMyRecordsRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeGetSpecificRecords(SAKE sake, SAKEGetSpecificRecordsInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_SPECIFIC_RECORDS, sakeiStartGetSpecificRecordsRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeGetRandomRecord(SAKE sake, SAKEGetRandomRecordInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_RANDOM_RECORD, sakeiStartGetRandomRecordRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeRateRecord(SAKE sake, SAKERateRecordInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_RATE_RECORD, sakeiStartRateRecordRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeGetRecordLimit(SAKE sake, SAKEGetRecordLimitInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_RECORD_LIMIT, sakeiStartGetRecordLimitRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeGetRecordCount(SAKE sake, SAKEGetRecordCountInput *input, SAKERequestCallback callback, void *userData) +{ + return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_RECORD_COUNT, sakeiStartGetRecordCountRequest); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// read request utility +SAKEField * SAKE_CALL sakeGetFieldByName(const char *name, SAKEField *fields, int numFields) +{ + int i; + + GS_ASSERT(name); + GS_ASSERT(fields); + GS_ASSERT(numFields >= 0); + + for(i = 0 ; i < numFields ; i++) + { + if(strcmp(fields[i].mName, name) == 0) + return &fields[i]; + } + + return NULL; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Files + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Set the URL format to be used by sakeGetFileDownloadUrl +gsi_bool SAKE_CALL sakeSetFileDownloadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH]) +{ + GS_ASSERT(sake); + GS_ASSERT(url); + + if(!sake || !url) + return gsi_false; + + _tcscpy(gSakeDownloadUrlOverride, url); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool SAKE_CALL sakeGetFileDownloadURL(SAKE sake, int fileId, gsi_char url[SAKE_MAX_URL_LENGTH]) +{ + int rcode; + + GS_ASSERT(sake); + GS_ASSERT(fileId != 0); + GS_ASSERT(url); + GS_ASSERT(sake->mIsGameAuthenticated); + GS_ASSERT(sake->mIsProfileAuthenticated); + + if(!sake || !url || !sake->mIsGameAuthenticated || !sake->mIsProfileAuthenticated) + return gsi_false; + + if (gSakeDownloadUrlOverride[0] != '\0') + { + rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("%s?gameid=%d&pid=%d"), + gSakeDownloadUrlOverride, sake->mGameId, sake->mProfileId); + } + else + { + #ifdef GSI_UNICODE + { + // use capital %S to convert the gamename to a wide string + rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%S.sake.%S/SakeFileServer/download.aspx?fileid=%d&gameid=%d&pid=%d"), + sake->mGameName, GSI_DOMAIN_NAME, fileId, sake->mGameId, sake->mProfileId); + } + #else + { + rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%s.sake.%s/SakeFileServer/download.aspx?fileid=%d&gameid=%d&pid=%d"), + sake->mGameName, GSI_DOMAIN_NAME, fileId, sake->mGameId, sake->mProfileId); + } + #endif + } + + if(rcode < 0) + return gsi_false; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool SAKE_CALL sakeSetFileUploadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH]) +{ + GS_ASSERT(sake); + GS_ASSERT(url); + + if(!sake || !url) + return gsi_false; + + _tcscpy(gSakeUploadUrlOverride, url); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool SAKE_CALL sakeGetFileUploadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH]) +{ + int rcode; + + GS_ASSERT(sake); + GS_ASSERT(url); + GS_ASSERT(sake->mIsGameAuthenticated); + GS_ASSERT(sake->mIsProfileAuthenticated); + + if(!sake || !url || !sake->mIsGameAuthenticated || !sake->mIsProfileAuthenticated) + return gsi_false; + + if (gSakeUploadUrlOverride[0] != '\0') + { + rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("%s?gameid=%d&pid=%d"), + gSakeUploadUrlOverride, sake->mGameId, sake->mProfileId); + } + else + { + #ifdef GSI_UNICODE + { + // use capital %S to convert the gamename to a wide string + rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%S.sake.%S/SakeFileServer/upload.aspx?gameid=%d&pid=%d"), + sake->mGameName, GSI_DOMAIN_NAME, sake->mGameId, sake->mProfileId); + } + #else + { + rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%s.sake.%s/SakeFileServer/upload.aspx?gameid=%d&pid=%d"), + sake->mGameName, GSI_DOMAIN_NAME, sake->mGameId, sake->mProfileId); + } + #endif + } + + if(rcode < 0) + return gsi_false; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKEFileResult SAKE_CALL sakeiParseFileResult(int resultCode) +{ + if(resultCode >= SAKEFileResult_UNKNOWN_ERROR) + return SAKEFileResult_UNKNOWN_ERROR; + return (SAKEFileResult)resultCode; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool SAKE_CALL sakeiGetHeaderValueInt(const char *headers, const char *headerName, int *value) +{ + const char * header; + int rcode; + + GS_ASSERT(headers); + GS_ASSERT(headerName); + GS_ASSERT(value); +#ifdef _DEBUG + // headerName must include the trailing colon + GS_ASSERT(headerName[strlen(headerName) - 1] == ':'); +#endif + + // find this header in the list of headers + header = strstr(headers, headerName); + if(header) + { + // skip the header name + header += strlen(headerName); + + // scan in the result + rcode = sscanf(header, " %d", value); + if(rcode == 1) + return gsi_true; + } + + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool SAKE_CALL sakeGetFileResultFromHeaders(const char *headers, SAKEFileResult *result) +{ + int resultCode; + gsi_bool foundResultCode; + + foundResultCode = sakeiGetHeaderValueInt(headers, SAKE_FILE_RESULT_HEADER, &resultCode); + + if(gsi_is_false(foundResultCode)) + return gsi_false; + + *result = sakeiParseFileResult(resultCode); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool SAKE_CALL sakeGetFileIdFromHeaders(const char *headers, int *fileId) +{ + return sakeiGetHeaderValueInt(headers, SAKE_FILE_ID_HEADER, fileId); +} diff --git a/xrGameSpy/gamespy/sake/sakeMain.h b/xrGameSpy/gamespy/sake/sakeMain.h new file mode 100644 index 00000000000..a0fa250d240 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeMain.h @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SAKEMAIN_H__ +#define __SAKEMAIN_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sake.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define SAKEI_GAME_NAME_LENGTH 15 +#define SAKEI_SECRET_KEY_LENGTH 8 +#define SAKEI_LOGIN_TICKET_LENGTH 24 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct SAKEInternal +{ + gsi_bool mIsGameAuthenticated; + char mGameName[SAKEI_GAME_NAME_LENGTH + 1]; + int mGameId; + char mSecretKey[SAKEI_SECRET_KEY_LENGTH + 1]; + + gsi_bool mIsProfileAuthenticated; + int mProfileId; + char mLoginTicket[SAKEI_LOGIN_TICKET_LENGTH + 1]; + + SAKEStartRequestResult mStartRequestResult; +} SAKEInternal; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SAKEMAIN_H__ diff --git a/xrGameSpy/gamespy/sake/sakeRequest.c b/xrGameSpy/gamespy/sake/sakeRequest.c new file mode 100644 index 00000000000..9e30820a32c --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeRequest.c @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeRequest.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +const char * GSI_SAKE_SERVICE_NAMESPACES[GSI_SAKE_SERVICE_NAMESPACE_COUNT] = +{ + "ns1=\"http://gamespy.net/sake\"" +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define SAKEI_SOAP_URL_FORMAT "http://%s.sake." GSI_DOMAIN_NAME "/SakeStorageServer/StorageServer.asmx" +char sakeiSoapUrl[SAKE_MAX_URL_LENGTH] = ""; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeiInitRequest(SAKE sake, SAKEIRequestType type, void *input, SAKERequestCallback callback, void *userData) +{ + SAKERequest request; + + GS_ASSERT(sake); + + // init the request init result to success + sake->mStartRequestResult = SAKEStartRequestResult_SUCCESS; + + // check for input + if(!input) + { + sake->mStartRequestResult = SAKEStartRequestResult_BAD_INPUT; + return NULL; + } + + // check for authentication + if(gsi_is_false(sake->mIsGameAuthenticated) || gsi_is_false(sake->mIsProfileAuthenticated)) + { + sake->mStartRequestResult = SAKEStartRequestResult_NOT_AUTHENTICATED; + return NULL; + } + + // allocate memory for the request object + request = (SAKERequest)gsimalloc(sizeof(SAKERequestInternal)); + if(!request) + { + sake->mStartRequestResult = SAKEStartRequestResult_OUT_OF_MEMORY; + return NULL; + } + + // init the request object + memset(request, 0, sizeof(SAKERequestInternal)); + request->mSake = sake; + request->mType = type; + request->mInput = input; + request->mCallback = callback; + request->mUserData = userData; + + return request; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void SAKE_CALL sakeiFreeRequest(SAKERequest request) +{ + GS_ASSERT(request); + + // this should already be freed by the time we get here + GS_ASSERT(request->mOutput == NULL); + + // free the request + gsifree(request); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKERequestResult SAKE_CALL sakeiCheckHttpResult(GHTTPResult httpResult) +{ + switch(httpResult) + { + case GHTTPSuccess: + return SAKERequestResult_SUCCESS; + case GHTTPOutOfMemory: + return SAKERequestResult_OUT_OF_MEMORY; + default: + return SAKERequestResult_CONNECTION_ERROR; + } +} + +static SAKERequestResult SAKE_CALL sakeiCheckSakeResult(const char * sakeResult) +{ + if(strcmp(sakeResult, "Success") == 0) + return SAKERequestResult_SUCCESS; + else if(strcmp(sakeResult, "SecretKeyInvalid") == 0) + return SAKERequestResult_SECRET_KEY_INVALID; + else if(strcmp(sakeResult, "ServiceDisabled") == 0) + return SAKERequestResult_SERVICE_DISABLED; + else if(strcmp(sakeResult, "DatabaseUnavailable") == 0) + return SAKERequestResult_DATABASE_UNAVAILABLE; + else if(strcmp(sakeResult, "LoginTicketInvalid") == 0) + return SAKERequestResult_LOGIN_TICKET_INVALID; + else if(strcmp(sakeResult, "LoginTicketExpired") == 0) + return SAKERequestResult_LOGIN_TICKET_EXPIRED; + else if(strcmp(sakeResult, "TableNotFound") == 0) + return SAKERequestResult_TABLE_NOT_FOUND; + else if(strcmp(sakeResult, "RecordNotFound") == 0) + return SAKERequestResult_RECORD_NOT_FOUND; + else if(strcmp(sakeResult, "FieldNotFound") == 0) + return SAKERequestResult_FIELD_NOT_FOUND; + else if(strcmp(sakeResult, "FieldTypeInvalid") == 0) + return SAKERequestResult_FIELD_TYPE_INVALID; + else if(strcmp(sakeResult, "NoPermission") == 0) + return SAKERequestResult_NO_PERMISSION; + else if(strcmp(sakeResult, "RecordLimitReached") == 0) + return SAKERequestResult_RECORD_LIMIT_REACHED; + else if(strcmp(sakeResult, "AlreadyRated") == 0) + return SAKERequestResult_ALREADY_RATED; + else if(strcmp(sakeResult, "NotRateable") == 0) + return SAKERequestResult_NOT_RATEABLE; + else if(strcmp(sakeResult, "NotOwned") == 0) + return SAKERequestResult_NOT_OWNED; + else if(strcmp(sakeResult, "FilterInvalid") == 0) + return SAKERequestResult_FILTER_INVALID; + else if(strcmp(sakeResult, "SortInvalid") == 0) + return SAKERequestResult_SORT_INVALID; + else if(strcmp(sakeResult, "TargetFilterInvalid") == 0) + return SAKERequestResult_TARGET_FILTER_INVALID; + else + return SAKERequestResult_UNKNOWN_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiSoapCallback(GHTTPResult httpResult, GSXmlStreamWriter requestData, GSXmlStreamReader responseData, void *userData) +{ + SAKERequest request = (SAKERequest)userData; + void *output = NULL; + SAKERequestResult result; + char resultString[32]; + + // sanity check + GS_ASSERT(request); + GS_ASSERT(request->mSake); + GS_ASSERT(request->mInfo); + if(!request || !request->mSake || !request->mInfo) + return; + + result = sakeiCheckHttpResult(httpResult); + if(result == SAKERequestResult_SUCCESS) + { + if(gsi_is_false(gsXmlMoveToStart(responseData)) || + gsi_is_false(gsXmlMoveToNext(responseData, request->mInfo->mResponseTag)) || + gsi_is_false(gsXmlReadChildAsStringNT(responseData, request->mInfo->mResultTag, resultString, sizeof(resultString)))) + { + result = SAKERequestResult_MALFORMED_RESPONSE; + } + else + { + result = sakeiCheckSakeResult(resultString); + + // fill in the output + if(result == SAKERequestResult_SUCCESS) + { + if(request->mInfo->mSakeOutputSize != 0) + { + request->mOutput = gsimalloc(request->mInfo->mSakeOutputSize); + if(request->mOutput) + { + request->mSoapResponse = responseData; + result = request->mInfo->mProcessSoapResponseFunc(request); + if(result == SAKERequestResult_SUCCESS) + output = request->mOutput; + } + else + { + result = SAKERequestResult_OUT_OF_MEMORY; + } + } + } + } + } + + // call the callback + if(request->mCallback) + request->mCallback(request->mSake, request, result, request->mInput, output, request->mUserData); + + // free data + if(request->mInfo->mFreeDataFunc) + request->mInfo->mFreeDataFunc(request); + + // free the output data + gsifree(request->mOutput); + request->mOutput = NULL; + + // free the sake request + sakeiFreeRequest(request); + + GSI_UNUSED(requestData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKEStartRequestResult SAKE_CALL sakeiSetupRequest(SAKERequest request) +{ + SAKEStartRequestResult result; + SAKEIRequestInfo * info; + + GS_ASSERT(request); + GS_ASSERT(request->mSake); + GS_ASSERT(request->mInfo); + + // store a utility pointer to the info + info = request->mInfo; + + // check the input + result = info->mValidateInputFunc(request); + if(result != SAKEStartRequestResult_SUCCESS) + return result; + + // create the xml request stream + request->mSoapRequest = gsXmlCreateStreamWriter(GSI_SAKE_SERVICE_NAMESPACES, GSI_SAKE_SERVICE_NAMESPACE_COUNT); + if(request->mSoapRequest == NULL) + return SAKEStartRequestResult_OUT_OF_MEMORY; + + // open the stream + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, request->mInfo->mFuncName); + + // this info is included with every request + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "gameid", (gsi_u32)request->mSake->mGameId); + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "secretKey", request->mSake->mSecretKey); + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "loginTicket", request->mSake->mLoginTicket); + + // fill in the request data + result = info->mFillSoapRequestFunc(request); + if(result != SAKEStartRequestResult_SUCCESS) + { + gsXmlFreeWriter(request->mSoapRequest); + request->mSoapRequest = NULL; + if(info->mFreeDataFunc) + info->mFreeDataFunc(request); + return result; + } + + // close the stream and writer + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, request->mInfo->mFuncName); + gsXmlCloseWriter(request->mSoapRequest); + + return SAKEStartRequestResult_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiExecuteRequest(SAKERequest request) +{ + if(sakeiSoapUrl[0] == '\0') + { + int rcode; + rcode = snprintf(sakeiSoapUrl, SAKE_MAX_URL_LENGTH, SAKEI_SOAP_URL_FORMAT, request->mSake->mGameName); + GS_ASSERT(rcode >= 0); + GSI_UNUSED(rcode); + } + gsiExecuteSoap(sakeiSoapUrl, request->mInfo->mSoapAction, request->mSoapRequest, sakeiSoapCallback, request); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKEStartRequestResult SAKE_CALL sakeiStartRequest(SAKERequest request, SAKEIRequestInfo * info) +{ + SAKEStartRequestResult result; + + request->mInfo = info; + + result = sakeiSetupRequest(request); + if(result != SAKEStartRequestResult_SUCCESS) + return result; + + sakeiExecuteRequest(request); + + return SAKEStartRequestResult_SUCCESS; +} diff --git a/xrGameSpy/gamespy/sake/sakeRequest.h b/xrGameSpy/gamespy/sake/sakeRequest.h new file mode 100644 index 00000000000..d2016e26632 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeRequest.h @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SAKEREQUEST_H__ +#define __SAKEREQUEST_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeMain.h" +#include "sakeRequestInternal.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define GSI_SAKE_SERVICE_NAMESPACE_COUNT 1 +#define GSI_SAKE_SERVICE_NAMESPACE "ns1" +#define GSI_SAKE_SERVICE_NAMESPACE_URL "http://gamespy.net/sake" +extern const char * GSI_SAKE_SERVICE_NAMESPACES[GSI_SAKE_SERVICE_NAMESPACE_COUNT]; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef enum +{ + SAKEIRequestType_CREATE_RECORD, + SAKEIRequestType_UPDATE_RECORD, + SAKEIRequestType_DELETE_RECORD, + SAKEIRequestType_SEARCH_FOR_RECORDS, + SAKEIRequestType_GET_MY_RECORDS, + SAKEIRequestType_GET_SPECIFIC_RECORDS, + SAKEIRequestType_GET_RANDOM_RECORD, + SAKEIRequestType_RATE_RECORD, + SAKEIRequestType_GET_RECORD_LIMIT, + SAKEIRequestType_GET_RECORD_COUNT +} SAKEIRequestType; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct SAKERequestInternal +{ + SAKE mSake; + SAKEIRequestType mType; + void *mInput; + void *mOutput; + SAKERequestCallback mCallback; + void *mUserData; + GSXmlStreamWriter mSoapRequest; + GSXmlStreamWriter mSoapResponse; + SAKEIRequestInfo *mInfo; +} SAKERequestInternal; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKERequest SAKE_CALL sakeiInitRequest(SAKE sake, SAKEIRequestType type, void *input, SAKERequestCallback callback, void *userData); +void SAKE_CALL sakeiFreeRequest(SAKERequest request); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKEStartRequestResult SAKE_CALL sakeiStartCreateRecordRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartUpdateRecordRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartDeleteRecordRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartSearchForRecordsRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartGetMyRecordsRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartGetSpecificRecordsRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartGetRandomRecordRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartRateRecordRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartGetRecordLimitRequest(SAKERequest request); +SAKEStartRequestResult SAKE_CALL sakeiStartGetRecordCountRequest(SAKERequest request); + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SAKEREQUEST_H__ diff --git a/xrGameSpy/gamespy/sake/sakeRequestInternal.h b/xrGameSpy/gamespy/sake/sakeRequestInternal.h new file mode 100644 index 00000000000..bd797bdebb3 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeRequestInternal.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SAKEREQUESTINTERNAL_H__ +#define __SAKEREQUESTINTERNAL_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeMain.h" +#include "../common/gsSoap.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +extern "C" { +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define SAKEI_REQUEST_SAFE_MALLOC(dest, type) SAKEI_REQUEST_SAFE_MALLOC_ARRAY(dest, type, 1) +#define SAKEI_REQUEST_SAFE_MALLOC_ARRAY(dest, type, num) {\ + dest = (type*)gsimalloc(sizeof(type)*num); /*malloc*/ \ + if(!dest) goto out_of_mem_cleanup; /*check*/ \ + memset(dest, 0, sizeof(type)*num); } /*zero*/ + +#define SAKEI_FUNC_NAME_STRINGS(func) func,\ + "SOAPAction: \"http://gamespy.net/sake/" func "\"",\ + func "Response",\ + func "Result" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct +{ + size_t mSakeOutputSize; + const char *mFuncName; + const char *mSoapAction; + const char *mResponseTag; + const char *mResultTag; + + SAKEStartRequestResult (*mValidateInputFunc)(SAKERequest request); + SAKEStartRequestResult (*mFillSoapRequestFunc)(SAKERequest request); + SAKERequestResult (*mProcessSoapResponseFunc)(SAKERequest request); + void (*mFreeDataFunc)(SAKERequest request); +} SAKEIRequestInfo; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SAKEStartRequestResult SAKE_CALL sakeiStartRequest(SAKERequest request, SAKEIRequestInfo * info); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SAKEREQUESTINTERNAL_H__ diff --git a/xrGameSpy/gamespy/sake/sakeRequestMisc.c b/xrGameSpy/gamespy/sake/sakeRequestMisc.c new file mode 100644 index 00000000000..a264a87193e --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeRequestMisc.c @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeRequestInternal.h" +#include "sakeRequest.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Rate Record + +static SAKEStartRequestResult SAKE_CALL sakeiRateRecordValidateInput(SAKERequest request) +{ + SAKERateRecordInput *input = (SAKERateRecordInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKEStartRequestResult SAKE_CALL sakeiRateRecordFillSoapRequest(SAKERequest request) +{ + SAKERateRecordInput *input = (SAKERateRecordInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // write the recordid + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "recordid", (gsi_u32)input->mRecordId); + + // write the rating + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "rating", (gsi_u32)input->mRating); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiRateRecordProcessSoapResponse(SAKERequest request) +{ + SAKERateRecordOutput *output = (SAKERateRecordOutput *)request->mOutput; + + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "numRatings", &output->mNumRatings)) || + gsi_is_false(gsXmlReadChildAsFloat(request->mSoapResponse, "averageRating", &output->mAverageRating))) + { + return SAKERequestResult_MALFORMED_RESPONSE; + } + + return SAKERequestResult_SUCCESS; +} + +SAKEStartRequestResult SAKE_CALL sakeiStartRateRecordRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKERateRecordOutput), + SAKEI_FUNC_NAME_STRINGS("RateRecord"), + sakeiRateRecordValidateInput, + sakeiRateRecordFillSoapRequest, + sakeiRateRecordProcessSoapResponse + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Get Record Limit + +static SAKEStartRequestResult SAKE_CALL sakeiGetRecordLimitValidateInput(SAKERequest request) +{ + SAKEGetRecordLimitInput *input = (SAKEGetRecordLimitInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKEStartRequestResult SAKE_CALL sakeiGetRecordLimitFillSoapRequest(SAKERequest request) +{ + SAKEGetRecordLimitInput *input = (SAKEGetRecordLimitInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiGetRecordLimitProcessSoapResponse(SAKERequest request) +{ + SAKEGetRecordLimitOutput *output = (SAKEGetRecordLimitOutput *)request->mOutput; + + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "limitPerOwner", &output->mLimitPerOwner)) || + gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "numOwned", &output->mNumOwned))) + { + return SAKERequestResult_MALFORMED_RESPONSE; + } + + return SAKERequestResult_SUCCESS; +} + +SAKEStartRequestResult SAKE_CALL sakeiStartGetRecordLimitRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKEGetRecordLimitOutput), + SAKEI_FUNC_NAME_STRINGS("GetRecordLimit"), + sakeiGetRecordLimitValidateInput, + sakeiGetRecordLimitFillSoapRequest, + sakeiGetRecordLimitProcessSoapResponse + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Get Record Count + +static SAKEStartRequestResult SAKE_CALL sakeiGetRecordCountValidateInput(SAKERequest request) +{ + SAKEGetRecordCountInput *input = (SAKEGetRecordCountInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKEStartRequestResult SAKE_CALL sakeiGetRecordCountFillSoapRequest(SAKERequest request) +{ + SAKEGetRecordCountInput *input = (SAKEGetRecordCountInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // write the filter + if(input->mFilter != NULL) + gsXmlWriteTStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "filter", input->mFilter); + + // write the cache flag + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "cacheFlag", (gsi_u32)input->mCacheFlag); + + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiGetRecordCountProcessSoapResponse(SAKERequest request) +{ + SAKEGetRecordCountOutput *output = (SAKEGetRecordCountOutput *)request->mOutput; + + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "count", &output->mCount))) + { + return SAKERequestResult_MALFORMED_RESPONSE; + } + + return SAKERequestResult_SUCCESS; +} + + +SAKEStartRequestResult SAKE_CALL sakeiStartGetRecordCountRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKEGetRandomRecordOutput), + SAKEI_FUNC_NAME_STRINGS("GetRecordCount"), + sakeiGetRecordCountValidateInput, + sakeiGetRecordCountFillSoapRequest, + sakeiGetRecordCountProcessSoapResponse + }; + + return sakeiStartRequest(request, &info); +} diff --git a/xrGameSpy/gamespy/sake/sakeRequestModify.c b/xrGameSpy/gamespy/sake/sakeRequestModify.c new file mode 100644 index 00000000000..839e47b7f3b --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeRequestModify.c @@ -0,0 +1,290 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeRequestInternal.h" +#include "sakeRequest.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKEStartRequestResult SAKE_CALL sakeiValidateRequestFields(SAKEField *fields, int numFields) +{ + int i; + + for(i = 0 ; i < numFields ; i++) + { + if(!fields[i].mName || !fields[i].mName[0]) + return SAKEStartRequestResult_BAD_FIELD_NAME; + if((fields[i].mType >= SAKEFieldType_NUM_FIELD_TYPES)) + return SAKEStartRequestResult_BAD_FIELD_TYPE; + if(fields[i].mType == SAKEFieldType_ASCII_STRING) + { + if(!fields[i].mValue.mAsciiString) + return SAKEStartRequestResult_BAD_FIELD_VALUE; + } + if(fields[i].mType == SAKEFieldType_UNICODE_STRING) + { + if(!fields[i].mValue.mUnicodeString) + return SAKEStartRequestResult_BAD_FIELD_VALUE; + } + if(fields[i].mType == SAKEFieldType_BINARY_DATA) + { + if(fields[i].mValue.mBinaryData.mLength < 0) + return SAKEStartRequestResult_BAD_FIELD_VALUE; + if(!fields[i].mValue.mBinaryData.mValue && (fields[i].mValue.mBinaryData.mLength > 0)) + return SAKEStartRequestResult_BAD_FIELD_VALUE; + } + } + + return SAKEStartRequestResult_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiFillSoapRequestFieldValues(SAKERequest request, SAKEField *fields, int numFields) +{ + int i; + + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "values"); + + for(i = 0 ; i < numFields ; i++) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "RecordField"); + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "name", fields[i].mName); + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value"); + + // fill-in the type-specific value struct based on the type + if(fields[i].mType == SAKEFieldType_BYTE) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "byteValue"); + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mByte); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "byteValue"); + } + else if(fields[i].mType == SAKEFieldType_SHORT) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "shortValue"); + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mShort); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "shortValue"); + } + else if(fields[i].mType == SAKEFieldType_INT) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "intValue"); + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", (gsi_u32)fields[i].mValue.mInt); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "intValue"); + } + else if (fields[i].mType == SAKEFieldType_INT64) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "int64Value"); + gsXmlWriteInt64Element(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mInt64); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "int64Value"); + } + else if(fields[i].mType == SAKEFieldType_FLOAT) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "floatValue"); + gsXmlWriteFloatElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mFloat); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "floatValue"); + } + else if(fields[i].mType == SAKEFieldType_ASCII_STRING) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "asciiStringValue"); + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mAsciiString); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "asciiStringValue"); + } + else if(fields[i].mType == SAKEFieldType_UNICODE_STRING) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "unicodeStringValue"); + gsXmlWriteUnicodeStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mUnicodeString); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "unicodeStringValue"); + } + else if(fields[i].mType == SAKEFieldType_BOOLEAN) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "booleanValue"); + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", (gsi_u32)(gsi_is_false(fields[i].mValue.mBoolean)?0:1)); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "booleanValue"); + } + else if(fields[i].mType == SAKEFieldType_DATE_AND_TIME) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "dateAndTimeValue"); + gsXmlWriteDateTimeElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", fields[i].mValue.mDateAndTime); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "dateAndTimeValue"); + } + else if(fields[i].mType == SAKEFieldType_BINARY_DATA) + { + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "binaryDataValue"); + gsXmlWriteBase64BinaryElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value", + fields[i].mValue.mBinaryData.mValue, fields[i].mValue.mBinaryData.mLength); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "binaryDataValue"); + } + else + { + // a type isn't being handled + GS_FAIL_STR("Unhandled field type"); + } + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "value"); + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "RecordField"); + } + + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "values"); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Create Record + +static SAKEStartRequestResult SAKE_CALL sakeiCreateRecordValidateInput(SAKERequest request) +{ + SAKECreateRecordInput *input = (SAKECreateRecordInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + // check the num fields + if(input->mNumFields < 0) + return SAKEStartRequestResult_BAD_NUM_FIELDS; + + // check for NULL fields + if(!input->mFields && (input->mNumFields > 0)) + return SAKEStartRequestResult_BAD_FIELDS; + + // check the fields + return sakeiValidateRequestFields(input->mFields, input->mNumFields); +} + +static SAKEStartRequestResult SAKE_CALL sakeiCreateRecordFillSoapRequest(SAKERequest request) +{ + SAKECreateRecordInput *input = (SAKECreateRecordInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // fill in the field values + sakeiFillSoapRequestFieldValues(request, input->mFields, input->mNumFields); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiCreateRecordProcessSoapResponse(SAKERequest request) +{ + SAKECreateRecordOutput *output = (SAKECreateRecordOutput *)request->mOutput; + + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "recordid", &output->mRecordId))) + { + return SAKERequestResult_MALFORMED_RESPONSE; + } + + return SAKERequestResult_SUCCESS; +} + +SAKEStartRequestResult SAKE_CALL sakeiStartCreateRecordRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKECreateRecordOutput), + SAKEI_FUNC_NAME_STRINGS("CreateRecord"), + sakeiCreateRecordValidateInput, + sakeiCreateRecordFillSoapRequest, + sakeiCreateRecordProcessSoapResponse + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Update Record + +static SAKEStartRequestResult SAKE_CALL sakeiUpdateRecordValidateInput(SAKERequest request) +{ + SAKEUpdateRecordInput *input = (SAKEUpdateRecordInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + // check the num fields + if(input->mNumFields <= 0) + return SAKEStartRequestResult_BAD_NUM_FIELDS; + + // check for NULL fields + if(!input->mFields) + return SAKEStartRequestResult_BAD_FIELDS; + + // check the fields + return sakeiValidateRequestFields(input->mFields, input->mNumFields); +} + +static SAKEStartRequestResult SAKE_CALL sakeiUpdateRecordFillSoapRequest(SAKERequest request) +{ + SAKEUpdateRecordInput *input = (SAKEUpdateRecordInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // write the recordid + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "recordid", (gsi_u32)input->mRecordId); + + // fill in the field values + sakeiFillSoapRequestFieldValues(request, input->mFields, input->mNumFields); + + return SAKEStartRequestResult_SUCCESS; +} + +SAKEStartRequestResult SAKE_CALL sakeiStartUpdateRecordRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + 0, + SAKEI_FUNC_NAME_STRINGS("UpdateRecord"), + sakeiUpdateRecordValidateInput, + sakeiUpdateRecordFillSoapRequest, + NULL + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Delete Record + +static SAKEStartRequestResult SAKE_CALL sakeiDeleteRecordValidateInput(SAKERequest request) +{ + SAKEDeleteRecordInput *input = (SAKEDeleteRecordInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKEStartRequestResult SAKE_CALL sakeiDeleteRecordFillSoapRequest(SAKERequest request) +{ + SAKEDeleteRecordInput *input = (SAKEDeleteRecordInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // write the recordid + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "recordid", (gsi_u32)input->mRecordId); + + return SAKEStartRequestResult_SUCCESS; +} + +SAKEStartRequestResult SAKE_CALL sakeiStartDeleteRecordRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + 0, + SAKEI_FUNC_NAME_STRINGS("DeleteRecord"), + sakeiDeleteRecordValidateInput, + sakeiDeleteRecordFillSoapRequest, + NULL + }; + + return sakeiStartRequest(request, &info); +} diff --git a/xrGameSpy/gamespy/sake/sakeRequestRead.c b/xrGameSpy/gamespy/sake/sakeRequestRead.c new file mode 100644 index 00000000000..15772be3016 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sakeRequestRead.c @@ -0,0 +1,674 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sakeRequestInternal.h" +#include "sakeRequest.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKEStartRequestResult SAKE_CALL sakeiValidateRequestFieldNames(char **fields, int numFields) +{ + int i; + + for(i = 0 ; i < numFields ; i++) + { + if(!fields[i] || !fields[i][0]) + return SAKEStartRequestResult_BAD_FIELD_NAME; + } + + return SAKEStartRequestResult_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiFillSoapRequestFieldNames(SAKERequest request, char **names, int numFields) +{ + int i; + + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "fields"); + + for(i = 0 ; i < numFields ; i++) + { + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "string", names[i]); + } + + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "fields"); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiFillSoapRequestRecordIds(SAKERequest request, int *recordIds, int numRecordIds) +{ + int i; + + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "recordids"); + + for(i = 0 ; i < numRecordIds ; i++) + { + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "int", (gsi_u32)recordIds[i]); + } + + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "recordids"); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiFillSoapRequestOwnerIds(SAKERequest request, int *ownerIds, int numOwnerIds) +{ + int i; + + gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "ownerids"); + + for(i = 0 ; i < numOwnerIds ; i++) + { + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "int", (gsi_u32)ownerIds[i]); + } + + gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "ownerids"); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static SAKERequestResult SAKE_CALL sakeiReadOutputRecords(SAKERequest request, SAKEField ***outputRecordsPtr, int *numRecords, + int numFields, char ** fieldNames) + +{ + SAKEField **outputRecords; + SAKEField *outputRecord; + SAKEField *outputField; + int recordIndex; + int fieldIndex; + size_t size; + + // get to the start of the values + if(gsi_is_false(gsXmlMoveToChild(request->mSoapResponse, "values"))) + return SAKERequestResult_MALFORMED_RESPONSE; + + // count the number of records + *numRecords = gsXmlCountChildren(request->mSoapResponse, "ArrayOfRecordValue"); + + // check for no records + if(*numRecords == 0) + { + *outputRecordsPtr = NULL; + return SAKERequestResult_SUCCESS; + } + + // allocate the array of records + size = (sizeof(SAKEField*) * *numRecords); + outputRecords = (SAKEField**)gsimalloc(size); + if(!outputRecords) + return SAKERequestResult_OUT_OF_MEMORY; + memset(outputRecords, 0, size); + *outputRecordsPtr = outputRecords; + + // loop through the records + for(recordIndex = 0 ; recordIndex < *numRecords ; recordIndex++) + { + // advance to this record + if(gsi_is_false(gsXmlMoveToNext(request->mSoapResponse, "ArrayOfRecordValue"))) + return SAKERequestResult_MALFORMED_RESPONSE; + + // allocate the array of record fields + size = (sizeof(SAKEField) * numFields); + outputRecord = (SAKEField*)gsimalloc(size); + if(!outputRecord) + return SAKERequestResult_OUT_OF_MEMORY; + memset(outputRecord, 0, size); + outputRecords[recordIndex] = outputRecord; + + // check for the wrong number of fields in the response + if(gsXmlCountChildren(request->mSoapResponse, "RecordValue") != numFields) + return SAKERequestResult_MALFORMED_RESPONSE; + + // fill in the array of fields for this record + for(fieldIndex = 0 ; fieldIndex < numFields ; fieldIndex++) + { + // utility pointer + outputField = &outputRecord[fieldIndex]; + + // set the name for this field + outputField->mName = fieldNames[fieldIndex]; + + // move to this field + if(gsi_is_false(gsXmlMoveToNext(request->mSoapResponse, "RecordValue"))) + return SAKERequestResult_MALFORMED_RESPONSE; + + // set the type and value based on the response field + if(gsXmlMoveToChild(request->mSoapResponse, "byteValue")) + { + int value; + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "value", &value))) + return SAKERequestResult_MALFORMED_RESPONSE; + outputField->mType = SAKEFieldType_BYTE; + outputField->mValue.mByte = (gsi_u8)value; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "shortValue")) + { + int value; + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "value", &value))) + return SAKERequestResult_MALFORMED_RESPONSE; + outputField->mType = SAKEFieldType_SHORT; + outputField->mValue.mShort = (gsi_i16)value; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "intValue")) + { + int value; + if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "value", &value))) + return SAKERequestResult_MALFORMED_RESPONSE; + outputField->mType = SAKEFieldType_INT; + outputField->mValue.mInt = (gsi_i32)value; + } + else if (gsXmlMoveToChild(request->mSoapResponse, "int64Value")) + { + gsi_i64 value; + if (gsi_is_false(gsXmlReadChildAsInt64(request->mSoapResponse, "value", &value))) + return SAKERequestResult_MALFORMED_RESPONSE; + outputField->mType = SAKEFieldType_INT64; + outputField->mValue.mInt64 = value; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "floatValue")) + { + float value; + if(gsi_is_false(gsXmlReadChildAsFloat(request->mSoapResponse, "value", &value))) + return SAKERequestResult_MALFORMED_RESPONSE; + outputField->mType = SAKEFieldType_FLOAT; + outputField->mValue.mFloat = value; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "asciiStringValue")) + { + char *value; + int len; + if(gsi_is_false(gsXmlReadChildAsString(request->mSoapResponse, "value", (const char**)&value, &len))) + return SAKERequestResult_MALFORMED_RESPONSE; + if(value) + value[len] = '\0'; + else + value = ""; + outputField->mType = SAKEFieldType_ASCII_STRING; + outputField->mValue.mAsciiString = value; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "unicodeStringValue")) + { + char *value; + gsi_u16 *valueUnicode; + int len; + if(gsi_is_false(gsXmlReadChildAsString(request->mSoapResponse, "value", (const char**)&value, &len))) + return SAKERequestResult_MALFORMED_RESPONSE; + if(value) + value[len] = '\0'; + else + value = ""; + valueUnicode = UTF8ToUCS2StringAlloc(value); + if(!valueUnicode) + return SAKERequestResult_OUT_OF_MEMORY; + outputField->mType = SAKEFieldType_UNICODE_STRING; + outputField->mValue.mUnicodeString = valueUnicode; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "booleanValue")) + { + char *value; + int len; + gsi_bool boolval; + if(gsi_is_false(gsXmlReadChildAsString(request->mSoapResponse, "value", (const char**)&value, &len))) + return SAKERequestResult_MALFORMED_RESPONSE; + if(value) + { + value[len] = '\0'; + boolval = (strcmp(value,"true") == 0)?gsi_true:gsi_false; + } + else + boolval = gsi_false; //if returned a NULL value, set bool to false + outputField->mType = SAKEFieldType_BOOLEAN; + outputField->mValue.mBoolean = boolval; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "dateAndTimeValue")) + { + time_t value; + if(gsi_is_false(gsXmlReadChildAsDateTimeElement(request->mSoapResponse, "value", &value))) + return SAKERequestResult_MALFORMED_RESPONSE; + outputField->mType = SAKEFieldType_DATE_AND_TIME; + outputField->mValue.mDateAndTime = value; + } + else if(gsXmlMoveToChild(request->mSoapResponse, "binaryDataValue")) + { + gsi_u8 *value; + int len; + if(gsi_is_false(gsXmlReadChildAsBase64Binary(request->mSoapResponse, "value", NULL, &len))) + return SAKERequestResult_MALFORMED_RESPONSE; + if(len > 0) + { + value = (gsi_u8*)gsimalloc((size_t)len); + if(!value) + return SAKERequestResult_OUT_OF_MEMORY; + if(gsi_is_false(gsXmlReadChildAsBase64Binary(request->mSoapResponse, "value", value, &len))) + { + gsifree(value); + return SAKERequestResult_MALFORMED_RESPONSE; + } + } + else + { + value = NULL; + len = 0; + } + outputField->mType = SAKEFieldType_BINARY_DATA; + outputField->mValue.mBinaryData.mLength = len; + outputField->mValue.mBinaryData.mValue = value; + } + else + { + GS_FAIL_STR("No recognized field type found in RecordValue"); + return SAKERequestResult_UNKNOWN_ERROR; + } + } + } + + return SAKERequestResult_SUCCESS; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiFreeOutputRecord(int numFields, SAKEField *record) +{ + int i; + + if(!record) + return; + + + //Check for binary data or unicode strings and free it if necessary + for (i = 0; i < numFields; i++) + { + if (record[i].mType == SAKEFieldType_BINARY_DATA && record[i].mValue.mBinaryData.mValue != NULL) + gsifree(record[i].mValue.mBinaryData.mValue); + if (record[i].mType == SAKEFieldType_UNICODE_STRING) + gsifree(record[i].mValue.mUnicodeString); + } + gsifree(record); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void SAKE_CALL sakeiFreeOutputRecords(int numFields, int numRecords, SAKEField **records) +{ + int i,j; + + if(!records) + return; + + for(i = 0 ; i < numRecords ; i++) + { + //Check for binary data or unicode strings and free it if necessary + for (j = 0; j < numFields; j++) + { + if (records[i][j].mType == SAKEFieldType_BINARY_DATA && records[i][j].mValue.mBinaryData.mValue != NULL) + gsifree(records[i][j].mValue.mBinaryData.mValue); + if (records[i][j].mType == SAKEFieldType_UNICODE_STRING) + gsifree(records[i][j].mValue.mUnicodeString); + } + + gsifree(records[i]); + } + gsifree(records); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Search For Records + +static SAKEStartRequestResult SAKE_CALL sakeiSearchForRecordsValidateInput(SAKERequest request) +{ + SAKESearchForRecordsInput *input = (SAKESearchForRecordsInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + // check the num fields + if(input->mNumFields <= 0) + return SAKEStartRequestResult_BAD_NUM_FIELDS; + + // check for NULL field names + if(!input->mFieldNames) + return SAKEStartRequestResult_BAD_FIELDS; + + // check the offset + if(input->mOffset < 0) + return SAKEStartRequestResult_BAD_OFFSET; + + // check the max + if(input->mMaxRecords <= 0) + return SAKEStartRequestResult_BAD_MAX; + + // check the field names + return sakeiValidateRequestFieldNames(input->mFieldNames, input->mNumFields); +} + +static SAKEStartRequestResult SAKE_CALL sakeiSearchForRecordsFillSoapRequest(SAKERequest request) +{ + SAKESearchForRecordsInput *input = (SAKESearchForRecordsInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // write the filter + if(input->mFilter != NULL) + gsXmlWriteTStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "filter", input->mFilter); + + // write the sort + if(input->mSort != NULL) + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "sort", input->mSort); + + // write the offset + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "offset", (gsi_u32)input->mOffset); + + // write the max + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "max", (gsi_u32)input->mMaxRecords); + + // write the target record filter + if(input->mTargetRecordFilter != NULL) + gsXmlWriteTStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "targetfilter", input->mTargetRecordFilter); + + // write the surrounding record count + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "surrounding", (gsi_u32)input->mSurroundingRecordsCount); + + // fill in the ownerids + sakeiFillSoapRequestOwnerIds(request, input->mOwnerIds, input->mNumOwnerIds); + + // write the cache flag + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "cacheFlag", (gsi_u32)input->mCacheFlag); + + + // fill in the field names + sakeiFillSoapRequestFieldNames(request, input->mFieldNames, input->mNumFields); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiSearchForRecordsProcessSoapResponse(SAKERequest request) +{ + SAKESearchForRecordsInput *input = (SAKESearchForRecordsInput *)request->mInput; + SAKESearchForRecordsOutput *output = (SAKESearchForRecordsOutput *)request->mOutput; + + // fill the output records + return sakeiReadOutputRecords(request, &output->mRecords, &output->mNumRecords, input->mNumFields, input->mFieldNames); +} + +static void sakeiSearchForRecordsFreeData(SAKERequest request) +{ + SAKESearchForRecordsInput *input = (SAKESearchForRecordsInput *)request->mInput; + SAKESearchForRecordsOutput *output = (SAKESearchForRecordsOutput *)request->mOutput; + + if(output) + sakeiFreeOutputRecords(input->mNumFields, output->mNumRecords, output->mRecords); +} + +SAKEStartRequestResult SAKE_CALL sakeiStartSearchForRecordsRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKESearchForRecordsOutput), + SAKEI_FUNC_NAME_STRINGS("SearchForRecords"), + sakeiSearchForRecordsValidateInput, + sakeiSearchForRecordsFillSoapRequest, + sakeiSearchForRecordsProcessSoapResponse, + sakeiSearchForRecordsFreeData + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Get My Records + +static SAKEStartRequestResult SAKE_CALL sakeiGetMyRecordsValidateInput(SAKERequest request) +{ + SAKEGetMyRecordsInput *input = (SAKEGetMyRecordsInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + // check the num fields + if(input->mNumFields <= 0) + return SAKEStartRequestResult_BAD_NUM_FIELDS; + + // check for NULL field names + if(!input->mFieldNames) + return SAKEStartRequestResult_BAD_FIELDS; + + // check the field names + return sakeiValidateRequestFieldNames(input->mFieldNames, input->mNumFields); +} + +static SAKEStartRequestResult SAKE_CALL sakeiGetMyRecordsFillSoapRequest(SAKERequest request) +{ + SAKEGetMyRecordsInput *input = (SAKEGetMyRecordsInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // fill in the field names + sakeiFillSoapRequestFieldNames(request, input->mFieldNames, input->mNumFields); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiGetMyRecordsProcessSoapResponse(SAKERequest request) +{ + SAKEGetMyRecordsInput *input = (SAKEGetMyRecordsInput *)request->mInput; + SAKEGetMyRecordsOutput *output = (SAKEGetMyRecordsOutput *)request->mOutput; + + // fill the output records + return sakeiReadOutputRecords(request, &output->mRecords, &output->mNumRecords, input->mNumFields, input->mFieldNames); +} + +static void sakeiGetMyRecordsFreeData(SAKERequest request) +{ + SAKEGetMyRecordsInput *input = (SAKEGetMyRecordsInput *)request->mInput; + SAKEGetMyRecordsOutput *output = (SAKEGetMyRecordsOutput *)request->mOutput; + + if(output) + sakeiFreeOutputRecords(input->mNumFields, output->mNumRecords, output->mRecords); +} + +SAKEStartRequestResult SAKE_CALL sakeiStartGetMyRecordsRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKEGetMyRecordsOutput), + SAKEI_FUNC_NAME_STRINGS("GetMyRecords"), + sakeiGetMyRecordsValidateInput, + sakeiGetMyRecordsFillSoapRequest, + sakeiGetMyRecordsProcessSoapResponse, + sakeiGetMyRecordsFreeData + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Get Specific Records + +static SAKEStartRequestResult SAKE_CALL sakeiGetSpecificRecordsValidateInput(SAKERequest request) +{ + SAKEGetSpecificRecordsInput *input = (SAKEGetSpecificRecordsInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + // check the num recordids + if(input->mNumRecordIds <= 0) + return SAKEStartRequestResult_BAD_NUM_RECORDIDS; + + // check the recordids + if(!input->mRecordIds) + return SAKEStartRequestResult_BAD_RECORDIDS; + + // check the num fields + if(input->mNumFields <= 0) + return SAKEStartRequestResult_BAD_NUM_FIELDS; + + // check for NULL field names + if(!input->mFieldNames) + return SAKEStartRequestResult_BAD_FIELDS; + + // check the field names + return sakeiValidateRequestFieldNames(input->mFieldNames, input->mNumFields); +} + +static SAKEStartRequestResult SAKE_CALL sakeiGetSpecificRecordsFillSoapRequest(SAKERequest request) +{ + SAKEGetSpecificRecordsInput *input = (SAKEGetSpecificRecordsInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // fill in the recordids + sakeiFillSoapRequestRecordIds(request, input->mRecordIds, input->mNumRecordIds); + + // fill in the field names + sakeiFillSoapRequestFieldNames(request, input->mFieldNames, input->mNumFields); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiGetSpecificRecordsProcessSoapResponse(SAKERequest request) +{ + SAKEGetSpecificRecordsInput *input = (SAKEGetSpecificRecordsInput *)request->mInput; + SAKEGetSpecificRecordsOutput *output = (SAKEGetSpecificRecordsOutput *)request->mOutput; + + // fill the output records + return sakeiReadOutputRecords(request, &output->mRecords, &output->mNumRecords, input->mNumFields, input->mFieldNames); +} + +static void sakeiGetSpecificRecordsFreeData(SAKERequest request) +{ + SAKEGetSpecificRecordsInput *input = (SAKEGetSpecificRecordsInput *)request->mInput; + SAKEGetSpecificRecordsOutput *output = (SAKEGetSpecificRecordsOutput *)request->mOutput; + + if(output) + sakeiFreeOutputRecords(input->mNumFields, output->mNumRecords, output->mRecords); +} + +SAKEStartRequestResult SAKE_CALL sakeiStartGetSpecificRecordsRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKEGetSpecificRecordsOutput), + SAKEI_FUNC_NAME_STRINGS("GetSpecificRecords"), + sakeiGetSpecificRecordsValidateInput, + sakeiGetSpecificRecordsFillSoapRequest, + sakeiGetSpecificRecordsProcessSoapResponse, + sakeiGetSpecificRecordsFreeData + }; + + return sakeiStartRequest(request, &info); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Get Random Record + +static SAKEStartRequestResult SAKE_CALL sakeiGetRandomRecordValidateInput(SAKERequest request) +{ + SAKEGetRandomRecordInput *input = (SAKEGetRandomRecordInput *)request->mInput; + + // check the tableid + if(!input->mTableId) + return SAKEStartRequestResult_BAD_TABLEID; + + // check the num fields + if(input->mNumFields <= 0) + return SAKEStartRequestResult_BAD_NUM_FIELDS; + + // check for NULL field names + if(!input->mFieldNames) + return SAKEStartRequestResult_BAD_FIELDS; + + // check the field names + return sakeiValidateRequestFieldNames(input->mFieldNames, input->mNumFields); +} + +static SAKEStartRequestResult SAKE_CALL sakeiGetRandomRecordFillSoapRequest(SAKERequest request) +{ + SAKEGetRandomRecordInput *input = (SAKEGetRandomRecordInput *)request->mInput; + + // write the table id + gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "tableid", input->mTableId); + + // write the filter + if(input->mFilter != NULL) + gsXmlWriteTStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "filter", input->mFilter); + + // write the max + gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "max", 1); + + // fill in the field names + sakeiFillSoapRequestFieldNames(request, input->mFieldNames, input->mNumFields); + + return SAKEStartRequestResult_SUCCESS; +} + +static SAKERequestResult sakeiGetRandomRecordProcessSoapResponse(SAKERequest request) +{ + SAKEGetRandomRecordInput *input = (SAKEGetRandomRecordInput *)request->mInput; + SAKEGetRandomRecordOutput *output = (SAKEGetRandomRecordOutput *)request->mOutput; + SAKEField **records; + int numRecords; + + // fill the output record + SAKERequestResult result = sakeiReadOutputRecords(request, &records, &numRecords, input->mNumFields, input->mFieldNames); + if(result == SAKERequestResult_SUCCESS) + { + if((records != NULL) && (numRecords > 0)) + output->mRecord = records[0]; + else + output->mRecord = NULL; + } + //free up the outer record pointer + gsifree(records); + + return result; +} + +static void sakeiGetRandomRecordFreeData(SAKERequest request) +{ + SAKEGetRandomRecordInput *input = (SAKEGetRandomRecordInput *)request->mInput; + SAKEGetRandomRecordOutput *output = (SAKEGetRandomRecordOutput *)request->mOutput; + + if(output) + sakeiFreeOutputRecord(input->mNumFields, output->mRecord); + +} + +SAKEStartRequestResult SAKE_CALL sakeiStartGetRandomRecordRequest(SAKERequest request) +{ + static SAKEIRequestInfo info = + { + sizeof(SAKEGetRandomRecordOutput), + SAKEI_FUNC_NAME_STRINGS("GetRandomRecords"), + sakeiGetRandomRecordValidateInput, + sakeiGetRandomRecordFillSoapRequest, + sakeiGetRandomRecordProcessSoapResponse, + sakeiGetRandomRecordFreeData + }; + + return sakeiStartRequest(request, &info); +} + + diff --git a/xrGameSpy/gamespy/sake/sake_vs2005.ncb b/xrGameSpy/gamespy/sake/sake_vs2005.ncb new file mode 100644 index 00000000000..74250d0085b Binary files /dev/null and b/xrGameSpy/gamespy/sake/sake_vs2005.ncb differ diff --git a/xrGameSpy/gamespy/sake/sake_vs2005.sln b/xrGameSpy/gamespy/sake/sake_vs2005.sln new file mode 100644 index 00000000000..f6ae0319ebe --- /dev/null +++ b/xrGameSpy/gamespy/sake/sake_vs2005.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "saketest_vs2005", "saketest\saketest_vs2005.vcproj", "{3134EE04-96C9-417C-808D-60D34FC8DE34}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = saketest\\saketest_vs2005.vcproj + SccProjectName1 = saketest + SccLocalPath1 = saketest + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Debug|Win32.ActiveCfg = Debug|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Debug|Win32.Build.0 = Debug|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Release|Win32.ActiveCfg = Release|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Release|Win32.Build.0 = Release|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {3134EE04-96C9-417C-808D-60D34FC8DE34}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sake/sake_vs2005.suo b/xrGameSpy/gamespy/sake/sake_vs2005.suo new file mode 100644 index 00000000000..b3b9e6a88e6 Binary files /dev/null and b/xrGameSpy/gamespy/sake/sake_vs2005.suo differ diff --git a/xrGameSpy/gamespy/sake/sake_vs2005.vssscc b/xrGameSpy/gamespy/sake/sake_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/sake/sake_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/sake/saketest/sakelinux/Makefile b/xrGameSpy/gamespy/sake/saketest/sakelinux/Makefile new file mode 100644 index 00000000000..19f0ee83b3b --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakelinux/Makefile @@ -0,0 +1,99 @@ +# SAKE SDK Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=sakelinux + +CC=gcc +BASE_CFLAGS=-D_LINUX -DGSI_COMMON_DEBUG -D_DEBUG -DGSI_NO_THREADS + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 + +#use these when debugging +DEBUG_CFLAGS=$(BASE_CFLAGS) -g -lpthread -march=i486 -O6 + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/linux/LinuxCommon.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCore.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../../common/gsSoap.o\ + ../../../common/gsUdpEngine.o\ + ../../../gp/gp.o\ + ../../../gp/gpi.o\ + ../../../gp/gpiBuddy.o\ + ../../../gp/gpiBuffer.o\ + ../../../gp/gpiCallback.o\ + ../../../gp/gpiConnect.o\ + ../../../gp/gpiInfo.o\ + ../../../gp/gpiKeys.o\ + ../../../gp/gpiOperation.o\ + ../../../gp/gpiPeer.o\ + ../../../gp/gpiProfile.o\ + ../../../gp/gpiSearch.o\ + ../../../gp/gpiUnique.o\ + ../../../gp/gpiUtility.o\ + ../../../gp/gpiTransfer.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../gt2/gt2Auth.o\ + ../../../gt2/gt2Buffer.o\ + ../../../gt2/gt2Callback.o\ + ../../../gt2/gt2Connection.o\ + ../../../gt2/gt2Filter.o\ + ../../../gt2/gt2Main.o\ + ../../../gt2/gt2Message.o\ + ../../../gt2/gt2Socket.o\ + ../../../gt2/gt2Encode.o\ + ../../../gt2/gt2Utility.o\ + ../../sakeMain.o\ + ../../sakeRequest.o\ + ../../sakeRequestMisc.o\ + ../../sakeRequestModify.o\ + ../../sakeRequestRead.o\ + ../saketest.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# +ghttp_debug: $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/sake/saketest/sakemacosx/Makefile b/xrGameSpy/gamespy/sake/saketest/sakemacosx/Makefile new file mode 100644 index 00000000000..e76b9936dc3 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakemacosx/Makefile @@ -0,0 +1,72 @@ +# Sake SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=saketest + +DEFINES=-D_MACOSX -DGSI_NO_THREADS + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCore.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../../common/gsSoap.o\ + ../../../common/gsUdpEngine.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../gp/gp.o\ + ../../../gp/gpi.o\ + ../../../gp/gpiBuddy.o\ + ../../../gp/gpiBuffer.o\ + ../../../gp/gpiCallback.o\ + ../../../gp/gpiConnect.o\ + ../../../gp/gpiInfo.o\ + ../../../gp/gpiKeys.o\ + ../../../gp/gpiOperation.o\ + ../../../gp/gpiPeer.o\ + ../../../gp/gpiProfile.o\ + ../../../gp/gpiSearch.o\ + ../../../gp/gpiUnique.o\ + ../../../gp/gpiUtility.o\ + ../../../gp/gpiTransfer.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../gt2/gt2Auth.o\ + ../../../gt2/gt2Buffer.o\ + ../../../gt2/gt2Callback.o\ + ../../../gt2/gt2Connection.o\ + ../../../gt2/gt2Filter.o\ + ../../../gt2/gt2Main.o\ + ../../../gt2/gt2Message.o\ + ../../../gt2/gt2Socket.o\ + ../../../gt2/gt2Encode.o\ + ../../../gt2/gt2Utility.o\ + ../../sakeMain.o\ + ../../sakeRequest.o\ + ../../sakeRequestMisc.o\ + ../../sakeRequestModify.o\ + ../../sakeRequestRead.o\ + ../saketest.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/sake/saketest/sakenitrocw/Nitro.lcf b/xrGameSpy/gamespy/sake/saketest/sakenitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakenitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/sake/saketest/sakenitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/sake/saketest/sakenitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakenitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/sake/saketest/sakenitrocw/sakenitrocw.mcp b/xrGameSpy/gamespy/sake/saketest/sakenitrocw/sakenitrocw.mcp new file mode 100644 index 00000000000..3fc748cdcf9 Binary files /dev/null and b/xrGameSpy/gamespy/sake/saketest/sakenitrocw/sakenitrocw.mcp differ diff --git a/xrGameSpy/gamespy/sake/saketest/sakeps2prodg/sakeps2prodg.sln b/xrGameSpy/gamespy/sake/saketest/sakeps2prodg/sakeps2prodg.sln new file mode 100644 index 00000000000..78390efe00f --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakeps2prodg/sakeps2prodg.sln @@ -0,0 +1,43 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sakeps2prodg", "sakeps2prodg.vcproj", "{190F63A1-557A-4CAF-B92F-0C98884B422B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = sakeps2prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EE Debug|Win32 = PS2 EE Debug|Win32 + PS2 EE Release|Win32 = PS2 EE Release|Win32 + PS2_INET_Debug|Win32 = PS2_INET_Debug|Win32 + PS2_INET_Release|Win32 = PS2_INET_Release|Win32 + PS2_SNSystems_Debug|Win32 = PS2_SNSystems_Debug|Win32 + PS2_SNSystems_Release|Win32 = PS2_SNSystems_Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Debug|Win32.ActiveCfg = PS2 EE Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Debug|Win32.Build.0 = PS2 EE Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Release|Win32.ActiveCfg = PS2 EE Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Release|Win32.Build.0 = PS2 EE Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Debug|Win32.ActiveCfg = PS2_INET_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Debug|Win32.Build.0 = PS2_INET_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Release|Win32.ActiveCfg = PS2_INET_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Release|Win32.Build.0 = PS2_INET_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Debug|Win32.ActiveCfg = PS2_SNSystems_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Debug|Win32.Build.0 = PS2_SNSystems_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Release|Win32.ActiveCfg = PS2_SNSystems_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Release|Win32.Build.0 = PS2_SNSystems_Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sake/saketest/sakeps2prodg/sakeps2prodg.vcproj b/xrGameSpy/gamespy/sake/saketest/sakeps2prodg/sakeps2prodg.vcproj new file mode 100644 index 00000000000..7743444be35 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakeps2prodg/sakeps2prodg.vcproj @@ -0,0 +1,1019 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.sln b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.sln new file mode 100644 index 00000000000..f4426418b99 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sakeps3prodg", "sakeps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = sakeps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vcproj b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vcproj new file mode 100644 index 00000000000..bb9c0411d50 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vcproj @@ -0,0 +1,751 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vcproj.vspscc b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vssscc b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakeps3prodg/sakeps3prodg.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/sake/saketest/sakepspprodg/sakepspprodg.sln b/xrGameSpy/gamespy/sake/saketest/sakepspprodg/sakepspprodg.sln new file mode 100644 index 00000000000..ee9e692a8d0 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakepspprodg/sakepspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sakepspprodg", "sakepspprodg.vcproj", "{962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = sakepspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sake/saketest/sakepspprodg/sakepspprodg.vcproj b/xrGameSpy/gamespy/sake/saketest/sakepspprodg/sakepspprodg.vcproj new file mode 100644 index 00000000000..30662206fad --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakepspprodg/sakepspprodg.vcproj @@ -0,0 +1,825 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sake/saketest/sakerevolutioncw/sakerevolutioncw.mcp b/xrGameSpy/gamespy/sake/saketest/sakerevolutioncw/sakerevolutioncw.mcp new file mode 100644 index 00000000000..3b5f93ab704 Binary files /dev/null and b/xrGameSpy/gamespy/sake/saketest/sakerevolutioncw/sakerevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/sake/saketest/saketest.c b/xrGameSpy/gamespy/sake/saketest/saketest.c new file mode 100644 index 00000000000..d082b6a7e7d --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/saketest.c @@ -0,0 +1,1154 @@ +#include "../../common/gsCommon.h" +#include "../../common/gsAvailable.h" +#include "../../common/gsCore.h" +#include "../../common/gsSoap.h" +#include "../sake.h" +#include "../../ghttp/ghttp.h" +#include "../../gp/gp.h" + +#if defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +#define URL NULL + +#define GAMENAME _T("gmtest") +#define SECRET_KEY _T("HA6zkS") +#define GAMEID 0 + +#define PRODUCTID 0 +#define NAMESPACEID 0 +#define NICKNAME _T("gptestc1") +#define EMAIL _T("gptestc@gptestc.com") +#define PASSWORD _T("gptestc") + + +#define CHECK_GP_RESULT(func, errString) if(func != GP_NO_ERROR) { printf("%s\n", errString); exit(0); } + +#define SAKE_UPLOAD_AMOUNT 5028 + + +typedef struct DataStruct +{ + char pData[SAKE_UPLOAD_AMOUNT]; +} DataStruct; + +int NumOperations = 0; +GPConnection * pconn; +GPProfile profileid; + +#ifdef GSI_COMMON_DEBUG + static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) + { + GSI_UNUSED(theLevel); + + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); + } +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static GSIACResult CheckServices(void) +{ + GSIACResult aResult; + GSIStartAvailableCheck(GAMENAME); + + // Continue processing while the check is in progress + do + { + aResult = GSIAvailableCheckThink(); + msleep(10); + } + while(aResult == GSIACWaiting); + + // Check the result + switch(aResult) + { + case GSIACAvailable: + printf("Online Services are available\r\n"); + break; + case GSIACUnavailable: + printf("Online services are unavailable\r\n"); + printf("Please visit www.mygame.com for more information.\r\n"); + break; + case GSIACTemporarilyUnavailable: + printf("Online services are temporarily unavailable.\r\n"); + printf("Please visit www.mygame.com for more information.\r\n"); + break; + default: + break; + }; + + return aResult; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void ConnectResponse(GPConnection * pconnection, GPConnectResponseArg * arg, void * param) +{ + if(arg->result == GP_NO_ERROR) + printf("Connected to GP\n"); + else + printf("GP Connection Attempt Failed\n"); + + profileid = arg->profile; + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +//GP callbacks, everything is a noop except for the error callback +static void Error(GPConnection * pconnection, GPErrorArg * arg, void * param) +{ + gsi_char * errorCodeString; + gsi_char * resultString; + +#define RESULT(x) case x: resultString = _T(#x); break; + switch(arg->result) + { + RESULT(GP_NO_ERROR) + RESULT(GP_MEMORY_ERROR) + RESULT(GP_PARAMETER_ERROR) + RESULT(GP_NETWORK_ERROR) + RESULT(GP_SERVER_ERROR) + default: + resultString = _T("Unknown result!\n"); + } + +#define ERRORCODE(x) case x: errorCodeString = _T(#x); break; + switch(arg->errorCode) + { + ERRORCODE(GP_GENERAL) + ERRORCODE(GP_PARSE) + ERRORCODE(GP_NOT_LOGGED_IN) + ERRORCODE(GP_BAD_SESSKEY) + ERRORCODE(GP_DATABASE) + ERRORCODE(GP_NETWORK) + ERRORCODE(GP_FORCED_DISCONNECT) + ERRORCODE(GP_CONNECTION_CLOSED) + ERRORCODE(GP_LOGIN) + ERRORCODE(GP_LOGIN_TIMEOUT) + ERRORCODE(GP_LOGIN_BAD_NICK) + ERRORCODE(GP_LOGIN_BAD_EMAIL) + ERRORCODE(GP_LOGIN_BAD_PASSWORD) + ERRORCODE(GP_LOGIN_BAD_PROFILE) + ERRORCODE(GP_LOGIN_PROFILE_DELETED) + ERRORCODE(GP_LOGIN_CONNECTION_FAILED) + ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED) + ERRORCODE(GP_NEWUSER) + ERRORCODE(GP_NEWUSER_BAD_NICK) + ERRORCODE(GP_NEWUSER_BAD_PASSWORD) + ERRORCODE(GP_UPDATEUI) + ERRORCODE(GP_UPDATEUI_BAD_EMAIL) + ERRORCODE(GP_NEWPROFILE) + ERRORCODE(GP_NEWPROFILE_BAD_NICK) + ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK) + ERRORCODE(GP_UPDATEPRO) + ERRORCODE(GP_UPDATEPRO_BAD_NICK) + ERRORCODE(GP_ADDBUDDY) + ERRORCODE(GP_ADDBUDDY_BAD_FROM) + ERRORCODE(GP_ADDBUDDY_BAD_NEW) + ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY) + ERRORCODE(GP_AUTHADD) + ERRORCODE(GP_AUTHADD_BAD_FROM) + ERRORCODE(GP_AUTHADD_BAD_SIG) + ERRORCODE(GP_STATUS) + ERRORCODE(GP_BM) + ERRORCODE(GP_BM_NOT_BUDDY) + ERRORCODE(GP_GETPROFILE) + ERRORCODE(GP_GETPROFILE_BAD_PROFILE) + ERRORCODE(GP_DELBUDDY) + ERRORCODE(GP_DELBUDDY_NOT_BUDDY) + ERRORCODE(GP_DELPROFILE) + ERRORCODE(GP_DELPROFILE_LAST_PROFILE) + ERRORCODE(GP_SEARCH) + ERRORCODE(GP_SEARCH_CONNECTION_FAILED) + default: + errorCodeString = _T("Unknown error code!\n"); + } + + if(arg->fatal) + { + printf( "-----------\n"); + printf( "GP FATAL ERROR\n"); + printf( "-----------\n"); + } + else + { + printf( "-----\n"); + printf( "GP ERROR\n"); + printf( "-----\n"); + } + _tprintf( _T("RESULT: %s (%d)\n"), resultString, arg->result); + _tprintf( _T("ERROR CODE: %s (0x%X)\n"), errorCodeString, arg->errorCode); + _tprintf( _T("ERROR STRING: %s\n"), arg->errorString); + + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void RecvBuddyRequest(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + + +static void RecvBuddyStatus(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void RecvBuddyMessage(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void RecvGameInvite(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + + +static void TransferCallback(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void RecvBuddyAuth(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + +static void RecvBuddyRevoke(GPConnection * pconnection, GPRecvBuddyMessageArg * arg, void * param) +{ + GSI_UNUSED(arg); + GSI_UNUSED(pconnection); + GSI_UNUSED(param); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static int UnicodeStringLen(const unsigned short * str) +{ + const unsigned short * end = str; + while(*end++) + {} + return (end - str - 1); +} + +static void PrintSeperator(void) +{ + printf("*******************\n"); +} + +static const char * FieldTypeToString(SAKEField * field) +{ + static char buffer[32]; + SAKEFieldType type = field->mType; + + if(type == SAKEFieldType_BYTE) + return "byte"; + if(type == SAKEFieldType_SHORT) + return "short"; + if(type == SAKEFieldType_INT) + return "int"; + if(type == SAKEFieldType_FLOAT) + return "float"; + if(type == SAKEFieldType_ASCII_STRING) + return "asciiString"; + if(type == SAKEFieldType_UNICODE_STRING) + return "unicodeString"; + if(type == SAKEFieldType_BOOLEAN) + return "boolean"; + if(type == SAKEFieldType_DATE_AND_TIME) + return "dateAndTime"; + if(type == SAKEFieldType_BINARY_DATA) + { + sprintf(buffer, "binaryData-%d", field->mValue.mBinaryData.mLength); + return buffer; + } + if (type == SAKEFieldType_INT64) + { + return "int64"; + } + return "ERROR!! Invalid value type set"; +} + +static const char * FieldValueToString(SAKEField * field) +{ + static char buffer[64]; + SAKEFieldType type = field->mType; + SAKEValue * value = &field->mValue; + + if(type == SAKEFieldType_BYTE) + sprintf(buffer, "%d", (int)value->mByte); + else if(type == SAKEFieldType_SHORT) + sprintf(buffer, "%d", (int)value->mShort); + else if(type == SAKEFieldType_INT) + sprintf(buffer, "%d", value->mInt); + else if(type == SAKEFieldType_FLOAT) + sprintf(buffer, "%0.3f", value->mFloat); + else if(type == SAKEFieldType_ASCII_STRING) + return value->mAsciiString; + else if(type == SAKEFieldType_UNICODE_STRING) + { + // cap the value if it is too long (note, this is destructive) + if(UnicodeStringLen(value->mUnicodeString) > 20) + value->mUnicodeString[20] = 0; + UCS2ToAsciiString(value->mUnicodeString, buffer); + } + else if(type == SAKEFieldType_BOOLEAN) + return (value->mBoolean)?"true":"false"; + else if(type == SAKEFieldType_DATE_AND_TIME) + { + char * str = gsiSecondsToString(&value->mDateAndTime); + str[strlen(str) - 1] = '\0'; + return str; + } + else if(type == SAKEFieldType_BINARY_DATA) + { + int i; + int len = min(value->mBinaryData.mLength, 8); + for(i = 0 ; i < len ; i++) + sprintf(buffer + (len*2), "%0X", value->mBinaryData.mValue[i]); + buffer[len*2] = '\0'; + } + else if(type == SAKEFieldType_INT64) + { + gsiInt64ToString(buffer, value->mInt64); + } + else + return "ERROR!! Invalid value type set"; + + return buffer; +} + +static const char * RequestResultToString(SAKERequestResult requestResult) +{ + switch(requestResult) + { + case SAKERequestResult_SUCCESS: + return "SUCCESS"; + case SAKERequestResult_CONNECTION_TIMEOUT: + return "CONNECTION_TIMEOUT"; + case SAKERequestResult_CONNECTION_ERROR: + return "CONNECTION_ERROR"; + case SAKERequestResult_MALFORMED_RESPONSE: + return "MALFORMED_RESPONSE"; + case SAKERequestResult_OUT_OF_MEMORY: + return "OUT_OF_MEMORY"; + case SAKERequestResult_DATABASE_UNAVAILABLE: + return "DATABASE_UNAVAILABLE"; + case SAKERequestResult_LOGIN_TICKET_INVALID: + return "LOGIN_TICKET_INVALID"; + case SAKERequestResult_LOGIN_TICKET_EXPIRED: + return "LOGIN_TICKET_EXPIRED"; + case SAKERequestResult_TABLE_NOT_FOUND: + return "TABLE_NOT_FOUND"; + case SAKERequestResult_RECORD_NOT_FOUND: + return "RECORD_NOT_FOUND"; + case SAKERequestResult_FIELD_NOT_FOUND: + return "FIELD_NOT_FOUND"; + case SAKERequestResult_FIELD_TYPE_INVALID: + return "FIELD_TYPE_INVALID"; + case SAKERequestResult_NO_PERMISSION: + return "NO_PERMISSION"; + case SAKERequestResult_RECORD_LIMIT_REACHED: + return "RECORD_LIMIT_REACHED"; + case SAKERequestResult_ALREADY_RATED: + return "ALREADY_RATED"; + case SAKERequestResult_NOT_RATEABLE: + return "NOT_RATEABLE"; + case SAKERequestResult_NOT_OWNED: + return "NOT_OWNED"; + case SAKERequestResult_FILTER_INVALID: + return "FILTER_INVALID"; + case SAKERequestResult_SORT_INVALID: + return "SORT_INVALID"; + case SAKERequestResult_UNKNOWN_ERROR: + return "UNKNOWN_ERROR"; + default: + break; + } + + return "Unrecognized error"; +} + +// prints request result, returns gsi_false for errors +static gsi_bool HandleRequestResult(SAKERequestResult requestResult, const char * requestType) +{ + if(requestResult != SAKERequestResult_SUCCESS) + { + printf("%s - Error - %s\n", requestType, RequestResultToString(requestResult)); + return gsi_false; + } + + printf("%s - Success\n", requestType); + return gsi_true; +} + +static void DisplayReadResults(SAKEField ** records, int numRecords, int numFields) +{ + SAKEField * field; + int recordIndex; + int fieldIndex; + + PrintSeperator(); + printf("Num Records: %d\n", numRecords); + PrintSeperator(); + + for(recordIndex = 0 ; recordIndex < numRecords ; recordIndex++) + { + for(fieldIndex = 0 ; fieldIndex < numFields ; fieldIndex++) + { + field = &records[recordIndex][fieldIndex]; + printf("%s[%s]=%s\n", field->mName, FieldTypeToString(field), FieldValueToString(field)); + } + + PrintSeperator(); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void CreateRecordCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKECreateRecordOutput * output = (SAKECreateRecordOutput *)outputData; + + NumOperations--; + + if(HandleRequestResult(result, "CreateRecord") == gsi_false) + return; + + printf("Created recordid %d\n", output->mRecordId); + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(inputData); + GSI_UNUSED(userData); +} + +static void UpdateRecordCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(inputData); + GSI_UNUSED(outputData); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "UpdateRecord") == gsi_false) + return; +} + +static void DeleteRecordCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(inputData); + GSI_UNUSED(outputData); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "DeleteRecord") == gsi_false) + return; +} + +static void SearchForRecordsCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKESearchForRecordsInput * input = (SAKESearchForRecordsInput *)inputData; + SAKESearchForRecordsOutput * output = (SAKESearchForRecordsOutput *)outputData; + + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "SearchForRecords") == gsi_false) + return; + + DisplayReadResults(output->mRecords, output->mNumRecords, input->mNumFields); +} + +static void GetMyRecordsCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKEGetMyRecordsInput * input = (SAKEGetMyRecordsInput *)inputData; + SAKEGetMyRecordsOutput * output = (SAKEGetMyRecordsOutput *)outputData; + + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "GetMyRecords") == gsi_false) + return; + + DisplayReadResults(output->mRecords, output->mNumRecords, input->mNumFields); +} + +static void GetSpecificRecordsCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKEGetSpecificRecordsInput * input = (SAKEGetSpecificRecordsInput *)inputData; + SAKEGetSpecificRecordsOutput * output = (SAKEGetSpecificRecordsOutput *)outputData; + + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "GetSpecificRecords") == gsi_false) + return; + + if(output->mNumRecords > 0) + { + SAKEField * field; + field = sakeGetFieldByName("score", output->mRecords[0], input->mNumFields); + GSI_UNUSED(field); + } + else + { + printf("No record found\n"); + } + + DisplayReadResults(output->mRecords, output->mNumRecords, input->mNumFields); +} + +static void GetRandomRecordCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKEGetRandomRecordInput * input = (SAKEGetRandomRecordInput *)inputData; + SAKEGetRandomRecordOutput * output = (SAKEGetRandomRecordOutput *)outputData; + SAKEField *records[1]; + int numRecords; + + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "GetRandomRecord") == gsi_false) + return; + + records[0] = output->mRecord; + if(records[0] != NULL) + numRecords = 1; + else + numRecords = 0; + + DisplayReadResults(records, numRecords, input->mNumFields); +} + +static void RateRecordCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKERateRecordOutput * output = (SAKERateRecordOutput *)outputData; + + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(inputData); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "RateRecord") == gsi_false) + return; + + printf("NumRatings: %d\n", output->mNumRatings); + printf("AverageRating: %0.3f\n", output->mAverageRating); +} + +static void GetRecordLimitCallback(SAKE sake, SAKERequest request, SAKERequestResult result, void *inputData, void *outputData, void *userData) +{ + SAKEGetRecordLimitOutput * output = (SAKEGetRecordLimitOutput *)outputData; + + NumOperations--; + + GSI_UNUSED(sake); + GSI_UNUSED(request); + GSI_UNUSED(inputData); + GSI_UNUSED(userData); + + if(HandleRequestResult(result, "GetRecordLimit") == gsi_false) + return; + + printf("LimitPerOwner: %d\n", output->mLimitPerOwner); + printf("NumOwned: %d\n", output->mNumOwned); +} + +static gsi_bool gUploadResult; +static int gUploadedFileId; +static GHTTPBool UploadCompletedCallback(GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param) +{ + SAKEFileResult fileResult; + + gUploadResult = gsi_false; + NumOperations--; + + GSI_UNUSED(param); + GSI_UNUSED(bufferLen); + GSI_UNUSED(buffer); + + if(result != GHTTPSuccess) + { + printf("File Upload: GHTTP Error: %d\n", result); + return GHTTPTrue; + } + + if(!sakeGetFileResultFromHeaders(ghttpGetHeaders(request), &fileResult)) + { + printf("File Upload: Failed to find Sake-File-Result header\n"); + return GHTTPTrue; + } + + if(fileResult != SAKEFileResult_SUCCESS) + { + printf("File Upload: SakeFileResult != success: %d\n", fileResult); + return GHTTPTrue; + } + + if(!sakeGetFileIdFromHeaders(ghttpGetHeaders(request), &gUploadedFileId)) + { + printf("File Upload: Unable to parse Sake-File-Id header\n"); + return GHTTPTrue; + } + + printf("File Upload: Uploaded fileId: %d\n", gUploadedFileId); + gUploadResult = gsi_true; + + return GHTTPTrue; +} + +static GHTTPBool DownloadCompletedCallback(GHTTPRequest request, GHTTPResult result, char * buffer, GHTTPByteCount bufferLen, void * param) +{ + SAKEFileResult fileResult; + + NumOperations--; + + GSI_UNUSED(param); + GSI_UNUSED(buffer); + + if(result != GHTTPSuccess) + { + printf("File Download: GHTTP Error: %d\n", result); + return GHTTPTrue; + } + + if(!sakeGetFileResultFromHeaders(ghttpGetHeaders(request), &fileResult)) + { + printf("File Download: Failed to find Sake-File-Result header\n"); + return GHTTPTrue; + } + + if(fileResult != SAKEFileResult_SUCCESS) + { + printf("File Download: SakeFileResult != success: %d\n", fileResult); + return GHTTPTrue; + } + + printf("File Download: Downloaded %d byte file\n", bufferLen); + + return GHTTPTrue; +} + +static void postCallback(GHTTPRequest request, int bytesPosted, int totalBytes, int objectsPosted, int totalObjects, void * param) +{ + printf("==============================\n"); + printf("* bytesPosted: %7d\n", bytesPosted); + printf("* totalBytes: %7d\n", totalBytes); + printf("* objectsPosted: %7d\n", objectsPosted); + printf("* totalObjects: %7d\n", totalObjects); + GSI_UNUSED(request); + GSI_UNUSED(param); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void RunTests(SAKE sake) +{ +#if 1 + { + static SAKECreateRecordInput input; + static SAKEField field; + SAKERequest request; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "test"; + field.mName = "MyAsciiString"; + field.mType = SAKEFieldType_ASCII_STRING; + field.mValue.mAsciiString = "this is a record"; + input.mFields = &field; + input.mNumFields = 1; + + request = sakeCreateRecord(sake, &input, CreateRecordCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKEUpdateRecordInput input; + static SAKEField fields[16]; + static char binaryData[] = "\x12\x34\x56\xAB\xCD"; +#if defined(_PS2) || defined(_MACOSX) + static gsi_u16 unicodeString[] = {'u','n','i','c','o','d','e','\0'}; +#else + static gsi_u16 *unicodeString = L"unicode"; +#endif + int index = 0; + SAKERequest request; + SAKEStartRequestResult startRequestResult; + + + input.mTableId = "test"; + input.mRecordId = 158; + fields[index].mName = "MyByte"; + fields[index].mType = SAKEFieldType_BYTE; + fields[index].mValue.mByte = 123; + index++; + fields[index].mName = "MyShort"; + fields[index].mType = SAKEFieldType_SHORT; + fields[index].mValue.mShort = 12345; + index++; + fields[index].mName = "MyInt"; + fields[index].mType = SAKEFieldType_INT; + fields[index].mValue.mInt = 123456789; + index++; + fields[index].mName = "MyFloat"; + fields[index].mType = SAKEFieldType_FLOAT; + fields[index].mValue.mFloat = 3.14159265f; + index++; + fields[index].mName = "MyAsciiString"; + fields[index].mType = SAKEFieldType_ASCII_STRING; + fields[index].mValue.mAsciiString = "ascii"; + index++; + fields[index].mName = "MyUnicodeString"; + fields[index].mType = SAKEFieldType_UNICODE_STRING; + fields[index].mValue.mUnicodeString = unicodeString; + index++; + fields[index].mName = "MyBoolean"; + fields[index].mType = SAKEFieldType_BOOLEAN; + fields[index].mValue.mBoolean = gsi_true; + index++; + fields[index].mName = "MyDateAndTime"; + fields[index].mType = SAKEFieldType_DATE_AND_TIME; + fields[index].mValue.mDateAndTime = time(NULL); + index++; + fields[index].mName = "MyBinaryData"; + fields[index].mType = SAKEFieldType_BINARY_DATA; + fields[index].mValue.mBinaryData.mValue = (gsi_u8*) binaryData; + fields[index].mValue.mBinaryData.mLength = (int)strlen(binaryData); + index++; + input.mFields = fields; + input.mNumFields = index; + + request = sakeUpdateRecord(sake, &input, UpdateRecordCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKEDeleteRecordInput input; + SAKERequest request; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "test"; + input.mRecordId = 150; + + request = sakeDeleteRecord(sake, &input, DeleteRecordCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKESearchForRecordsInput input; + static SAKERequest request; + static char *fieldNames[] = { "score", "recordid" }; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "scores"; + input.mFieldNames = fieldNames; + input.mNumFields = (sizeof(fieldNames) / sizeof(fieldNames[0])); + input.mFilter = _T("score < 50"); + input.mSort = "score desc"; + input.mOffset = 0; + input.mMaxRecords = 3; + + request = sakeSearchForRecords(sake, &input, SearchForRecordsCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKEGetMyRecordsInput input; + static SAKERequest request; + static char *fieldNames[] = { "recordid", "ownerid", "MyByte", "MyShort", + "MyInt", "MyFloat", "MyAsciiString", + "MyUnicodeString", "MyBoolean", "MyDateAndTime", + "MyBinaryData", "MyFileID", "num_ratings", + "average_rating" }; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "test"; + input.mFieldNames = fieldNames; + input.mNumFields = (sizeof(fieldNames) / sizeof(fieldNames[0])); + + request = sakeGetMyRecords(sake, &input, GetMyRecordsCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKEGetSpecificRecordsInput input; + static SAKERequest request; + static int recordIds[] = { 1, 2, 4, 5 }; + static char *fieldNames[] = { "recordid", "ownerid", "score" }; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "scores"; + input.mRecordIds = recordIds; + input.mNumRecordIds = (sizeof(recordIds) / sizeof(recordIds[0])); + input.mFieldNames = fieldNames; + input.mNumFields = (sizeof(fieldNames) / sizeof(fieldNames[0])); + + request = sakeGetSpecificRecords(sake, &input, GetSpecificRecordsCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKEGetRandomRecordInput input; + static SAKERequest request; + //static char *fieldNames[] = { "recordid", "matchname" }; + static char *fieldNames[] = { "recordid", "score" }; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "levels"; + //input.mTableId = "archive"; + input.mFieldNames = fieldNames; + input.mNumFields = (sizeof(fieldNames) / sizeof(fieldNames[0])); + input.mFilter = NULL; + //input.mFilter = "my_rating > 100"; + request = sakeGetRandomRecord(sake, &input, GetRandomRecordCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKERateRecordInput input; + static SAKERequest request; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "test"; + input.mRecordId = 158; + input.mRating = 200; + + request = sakeRateRecord(sake, &input, RateRecordCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + static SAKEGetRecordLimitInput input; + static SAKERequest request; + SAKEStartRequestResult startRequestResult; + + input.mTableId = "nicks"; + + request = sakeGetRecordLimit(sake, &input, GetRecordLimitCallback, NULL); + if(!request) + { + startRequestResult = sakeGetStartRequestResult(sake); + printf("Failed to start request: %d\n", startRequestResult); + } + else + { + NumOperations++; + } + } +#endif +#if 1 + { + GHTTPPost post; + GHTTPRequest request; + //const char *memFile = "This is a test file"; + gsi_char url[SAKE_MAX_URL_LENGTH]; + + int i; + DataStruct data; + + for (i=0; i +#endif + +int test_main(int argc, char* argv[]); // CW needs this prototyped + +int test_main(int argc, char* argv[]) +{ + SAKEStartupResult startupResult; + SAKE sake; + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + // setup the common debugging +#ifdef GSI_COMMON_DEBUG + gsSetDebugCallback(DebugCallback); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Hardcore); +#endif + + // enable Win32 C Runtime debugging +#if defined(_WIN32) && !defined(_XBOX) && defined(_DEBUG) + { + int tempFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + _CrtSetDbgFlag(tempFlag | _CRTDBG_LEAK_CHECK_DF); + } +#endif + + // availability check + printf("Checking availability\n"); + if(CheckServices() != GSIACAvailable) + return 0; + + // Init the GameSpy SDK Core (required by SOAP SDKs) + printf("Initializing the GameSpy Core\n"); + gsCoreInitialize(); + + // startup sake + printf("Starting up Sake\n"); + startupResult = sakeStartup(&sake); + if(startupResult != SAKEStartupResult_SUCCESS) + { + printf("Startup failed: %d\n", startupResult); + return 0; + } + + // login to GP and use data to authenticate Sake + LoginAndAuthenticate(sake); + + // run the tests + RunTests(sake); + + // keep thinking + printf("Entering think loop\n"); + while(NumOperations > 0) + { + msleep(5); + gsCoreThink(0); + } + + // shutdown sake + printf("Shutting down Sake\n"); + sakeShutdown(sake); + + // shutdown the core + printf("Shutting down the GameSpy Core\n"); + gsCoreShutdown(); + + // Wait for core shutdown + // (should be instantaneous unless you have multiple cores) + while(gsCoreIsShutdown() == GSCore_SHUTDOWN_PENDING) + { + gsCoreThink(0); + msleep(5); + } + + return 0; +} diff --git a/xrGameSpy/gamespy/sake/saketest/saketest.dsp b/xrGameSpy/gamespy/sake/saketest/saketest.dsp new file mode 100644 index 00000000000..84af79c3d94 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/saketest.dsp @@ -0,0 +1,657 @@ +# Microsoft Developer Studio Project File - Name="saketest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=saketest - Win32 Unicode 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 "saketest.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 "saketest.mak" CFG="saketest - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "saketest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "saketest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "saketest - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "saketest - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/sake/saketest" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "saketest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /I "../../" /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "saketest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /I "../../" /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_MEM_MANAGED" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "saketest - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "saketest___Win32_Unicode_Debug1" +# PROP BASE Intermediate_Dir "saketest___Win32_Unicode_Debug1" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "saketest___Win32_Unicode_Debug1" +# PROP Intermediate_Dir "saketest___Win32_Unicode_Debug1" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /I "../../" /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_MEM_MANAGED" /D "GSI_COMMON_DEBUG" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /I "../../" /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_MEM_MANAGED" /D "GSI_COMMON_DEBUG" /D "GSI_UNICODE" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "saketest - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "saketest___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "saketest___Win32_Unicode_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "saketest___Win32_Unicode_Release" +# PROP Intermediate_Dir "saketest___Win32_Unicode_Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /I "../" /I "../../" /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /I "../../" /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ENDIF + +# Begin Target + +# Name "saketest - Win32 Release" +# Name "saketest - Win32 Debug" +# Name "saketest - Win32 Unicode Debug" +# Name "saketest - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\saketest.c +# End Source File +# End Group +# Begin Group "GOA" + +# PROP Default_Filter "" +# Begin Group "sake" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sake.h +# End Source File +# Begin Source File + +SOURCE=..\sakeMain.c +# End Source File +# Begin Source File + +SOURCE=..\sakeMain.h +# End Source File +# Begin Source File + +SOURCE=..\sakeRequest.c +# End Source File +# Begin Source File + +SOURCE=..\sakeRequest.h +# End Source File +# Begin Source File + +SOURCE=..\sakeRequestInternal.h +# End Source File +# Begin Source File + +SOURCE=..\sakeRequestMisc.c +# End Source File +# Begin Source File + +SOURCE=..\sakeRequestModify.c +# End Source File +# Begin Source File + +SOURCE=..\sakeRequestRead.c +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "ghttp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "gp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\GP\gp.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpi.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuddy.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiCallback.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiConnect.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiInfo.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiOperation.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiPeer.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiProfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiSearch.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiTransfer.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUtility.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUtility.h +# End Source File +# End Group +# Begin Group "gt2" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj b/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj new file mode 100644 index 00000000000..3acbb6edf2c --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj @@ -0,0 +1,2669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user b/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user new file mode 100644 index 00000000000..4b72a685c83 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj.LOOPZILLA2.Zaytsev Evgeniy.user @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/saketest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/sake/saketest/sakex360/sakex360.sln b/xrGameSpy/gamespy/sake/saketest/sakex360/sakex360.sln new file mode 100644 index 00000000000..5aa45f55989 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakex360/sakex360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sakex360", "sakex360.vcproj", "{8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {8D6111DA-2950-4B83-BB7D-E3F9FAE9B8DA}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sake/saketest/sakex360/sakex360.vcproj b/xrGameSpy/gamespy/sake/saketest/sakex360/sakex360.vcproj new file mode 100644 index 00000000000..00431ba57c3 --- /dev/null +++ b/xrGameSpy/gamespy/sake/saketest/sakex360/sakex360.vcproj @@ -0,0 +1,812 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/changelog.txt b/xrGameSpy/gamespy/sc/changelog.txt new file mode 100644 index 00000000000..e034643f668 --- /dev/null +++ b/xrGameSpy/gamespy/sc/changelog.txt @@ -0,0 +1,50 @@ +Changelog for: GameSpy Competition SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 1.04.00 RMV RELEASE Released to Developer Site +12-07-2007 1.03.01 SAH OTHER Fixed projects missing dependencies +12-03-2007 1.03.00 SN FEATURE Added Int64 support for reports +08-06-2007 1.02.00 RMV RELEASE Released to Developer Site +07-18-2007 1.01.01 RMV OTHER Created sctestmatchless projects for multiple platforms +07-17-2007 1.01.01 RMV FIX Fixed compiler warnings for PSP test project +06-15-2007 1.01.00 BMS FEATURE Updated for "matchless" ATLAS. +04-17-2007 1.00.02 SAH FEATURE Added scReportAddFloatValue + 1.00.02 SAH OTHER Changed sctest for easier testing of AuthService +03-16-2007 1.00.01 SAH FIX Fixed an issue where team indexes were not properly retrieved based on the team ID. +03-06-2007 1.00.00 SAH RELEASE Released to Developer Site +03-06-2007 0.09.08 SAH FIX Added SCResult_NO_AVAILABILITY_CHECK for unperformed checks made prior to init + 0.09.08 SAH FIX Modified sctest to include availability check. + 0.09.08 SAH FIX Fixed scServiceURL to construct the proper URL based on the __GSIACGamename +03-02-2007 0.09.07 SAH FIX Added Linux, MACOSX makefiles and Nintendo DS project +03-02-2007 0.09.06 SN FIX Fixed some compiler warnings for code warrior + SN FIX Added checks for consoles in sctest.c after testing terminates +03-02-2007 0.09.06 SN FIX Fixed an alignment issue for sctest.c on the ps2 +03-02-2007 0.09.05 SN FIX Fixed compiler warnings for sctest.c +02-28-2007 0.09.04 SAH FIX Fixed an assert, added ghttpPost.h for extern function call + 0.09.04 SAH FIX Added ScRaceSample to VS2005 project, updated sample to use AdminSite header +02-27-2007 0.09.03 SAH FEATURE Created ScRaceSample application and added it to the project +02-22-2007 0.09.02 SN FEATURE Added code to calculate an MD5 hash on the binary report before sending it + 0.09.02 SN FIX Fixed the report version number + 0.09.02 SN FIX Modified sctest to have each player submit its own snapsnot +02-21-2007 0.09.01 SAH FEATURE Added SCGameStatus enum, gamestatus is now set when calling scReportEnd + 0.09.01 SAH FIX Removed all references to isFinal, no longer used +01-31-2007 0.09.00 SAH FEATURE Added scReportAddShortValue / scReportAddByteValue + 0.09.00 SAH FIX Fixed protocol header length define for rosterSection +01-31-2007 0.08.00 SAH FEATURE TeamIndex now takes in an arena teamID (or a local index for games that don't plan to use arena) + 0.08.00 SAH FEATURE Fixed a bug where the result enum was improperly casted, causing win/loss mismatch +01-22-2007 0.07.00 SAH FIX Increasing version number to remove confusion + 0.07.00 SAH FIX Fixed Unicode issues as well as the addString function + 0.07.00 SAH FIX Added Unicode configuration in Project + 0.07.00 SAH FIX Added String tests in scTest.c +01-16-2007 0.04.03 DES FEATURE Added X360 support +01-04-2007 0.04.02 SN FIX Changed URLs to release backend +12-18-2006 0.04.01 SN FIX Added PS2, PS3, PSP projects +12-18-2006 0.04.01 SN FEATURE Added scDestroyReport for freeing reports + SN FIX Fixed sdk shutdown code, and any warnings and errors that came up when compiling as C++ code + SN FIX Updated sctest to use latest sdk interface and fixed some issues with building the report +12-15-2006 0.04.00 MJW RELEASE Released to Developer Site +12-05-2006 0.03.01 SN FIX Fixed errors and warnings on all platforms slated for release +10-20-2006 0.03.00 BED RELEASE Aplha update + FEATURE Added User data for callbacks diff --git a/xrGameSpy/gamespy/sc/sc.dsw b/xrGameSpy/gamespy/sc/sc.dsw new file mode 100644 index 00000000000..a146f4fc69a --- /dev/null +++ b/xrGameSpy/gamespy/sc/sc.dsw @@ -0,0 +1,53 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ScRaceSample"=.\scRaceSample\scRaceSample.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "sctest"=.\sctest\sctest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "sctestmatchless"=.\sctestmatchless\sctestmatchless.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/sc/sc.h b/xrGameSpy/gamespy/sc/sc.h new file mode 100644 index 00000000000..145f580dbf7 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sc.h @@ -0,0 +1,314 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SC_H__ +#define __SC_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../common/gsCommon.h" +#include "../common/gsRC4.h" +#include "../common/gsAvailable.h" +#include "../ghttp/ghttp.h" +#include "../webservices/AuthService.h" + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// optional to explicitly use __stdcall, __cdecl, __fastcall +#define SC_CALL + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Set this to define memory settings for the SDK +#define SC_STATIC_MEM + +// The initial (or fixed, for static memory) report buffer size +#define SC_REPORT_BUFFER_BYTES 65536 + +// URL for sc services. +#define SC_SERVICE_MAX_URL_LEN 128 +extern char scServiceURL[SC_SERVICE_MAX_URL_LEN]; + +// Session GUID size - must match backend +//#define SC_SESSION_GUID_SIZE 16 +#define SC_AUTHDATA_SIZE 16 +#define SC_SESSION_GUID_SIZE 40 +#define SC_CONNECTION_GUID_SIZE 40 + +#define SC_GUID_BINARY_SIZE 16 // convert the 40 byte string guid into an int, 2 shorts and 8 bytes + +// Limit to the number of teams +#define SC_MAX_NUM_TEAMS 64 + +// OPTIONS flags - first two bits reserved for authoritative / final flags +#define SC_OPTIONS_NONE 0 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Result codes +typedef enum +{ + SCResult_NO_ERROR = 0, + SCResult_NO_AVAILABILITY_CHECK, + SCResult_INVALID_PARAMETERS, + SCResult_NOT_INITIALIZED, + SCResult_CORE_NOT_INITIALIZED, + SCResult_OUT_OF_MEMORY, + SCResult_CALLBACK_PENDING, + + SCResult_HTTP_ERROR, + SCResult_UNKNOWN_RESPONSE, // server reported an error which is unknown to us + SCResult_RESPONSE_INVALID, + + SCResult_REPORT_INCOMPLETE, + SCResult_REPORT_INVALID, + SCResult_SUBMISSION_FAILED, + + SCResult_UNKNOWN_ERROR, + + SCResultMax +} SCResult; + + +// Game Results +typedef enum +{ + SCGameResult_WIN, + SCGameResult_LOSS, + SCGameResult_DRAW, + SCGameResult_DISCONNECT, + SCGameResult_DESYNC, + SCGameResult_NONE, + + SCGameResultMax +} SCGameResult; + + +// Game Status +typedef enum +{ + SCGameStatus_COMPLETE, + SCGameStatus_PARTIAL, + SCGameStatus_BROKEN, + + SCGameStatusMax +} SCGameStatus; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Data types +typedef void* SCInterfacePtr; +typedef void* SCReportPtr; + + +//typedef gsi_u32 SCTeamCount; +//typedef gsi_u32 SCTeamIndex; + +//typedef gsi_u32 SCPlayerCount; +//typedef gsi_u32 SCPlayerIndex; + +//typedef gsi_u16 SCKey; + +typedef char SCHiddenData[64]; + +//typedef enum +//{ +// SCReportKeyType_SERVER, +// SCReportKeyType_TEAM, +// SCReportKeyType_PLAYER +//} SCReportKeyType; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Callbacks +typedef void (*SCCreateSessionCallback)(const SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData); +typedef void (*SCSetReportIntentionCallback)(const SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData); +typedef void (*SCSubmitReportCallback)(const SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData); + +/* +typedef void (*SCKeyCallback) (SCReportPtr theReport, + SCReportKeyType theKeyType, + gsi_u32 theIndex, // how many times this has been called + void* theUserParam); +*/ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Main interface functions +SCResult SC_CALL scInitialize(int theGameId, + SCInterfacePtr * theInterfaceOut); +SCResult SC_CALL scShutdown (SCInterfacePtr theInterface); +SCResult SC_CALL scThink (SCInterfacePtr theInterface); + +SCResult SC_CALL scCreateSession(SCInterfacePtr theInterface, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +// This is a variation of scCreateSession that creates a "matchless" session. +// "matchless" means incoming data will be scrutinized less, and applied to stats immediately instead of when the match is over. +SCResult SC_CALL scCreateMatchlessSession(SCInterfacePtr theInterface, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +SCResult SC_CALL scSetReportIntention(const SCInterfacePtr theInterface, + const gsi_u8 theConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +SCResult SC_CALL scSubmitReport (const SCInterfacePtr theInterface, + const SCReportPtr theReport, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSubmitReportCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +//SCResult SC_CALL sc +SCResult SC_CALL scSetSessionId(const SCInterfacePtr theInterface, const gsi_u8 theSessionId[SC_SESSION_GUID_SIZE]); + +const char * scGetSessionId (const SCInterfacePtr theInterface); +const char * scGetConnectionId(const SCInterfacePtr theInterface); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Report generation functions + +// Create a new (empty) report +// - Specify player and team count so we can allocate memory +// and later sanity check against reported data +SCResult SC_CALL scCreateReport(const SCInterfacePtr theInterface, + gsi_u32 theHeaderVersion, + gsi_u32 thePlayerCount, + gsi_u32 theTeamCount, + SCReportPtr * theReportOut); + +// - Write global data key/values +SCResult SC_CALL scReportBeginGlobalData(SCReportPtr theReportData); +SCResult SC_CALL scReportBeginPlayerData(SCReportPtr theReportData); +SCResult SC_CALL scReportBeginTeamData (SCReportPtr theReportData); + + +// - Write player auth info and key/values +SCResult SC_CALL scReportBeginNewPlayer(SCReportPtr theReportData); +SCResult SC_CALL scReportSetPlayerData (SCReportPtr theReport, + gsi_u32 thePlayerIndex, + const gsi_u8 thePlayerConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_u32 thePlayerTeamId, + SCGameResult theResult, + gsi_u32 theProfileId, + const GSLoginCertificate * theCertificate, + const gsi_u8 theAuthData[16]); + +// - Write team info and key/values +SCResult SC_CALL scReportBeginNewTeam(SCReportPtr theReportData); +SCResult SC_CALL scReportSetTeamData (SCReportPtr theReport, + gsi_u32 theTeamId, + SCGameResult theResult); + +// - Call this when you're finished writing the report +SCResult SC_CALL scReportEnd(SCReportPtr theReport, + gsi_bool isAuth, + SCGameStatus theStatus); + +// Call this to set the report as "matchless". +// This is needed if the report is being submitted to a "matchless" game session. +SCResult SC_CALL scReportSetAsMatchless(SCReportPtr theReport); + + +// Utility to record key value pairs +SCResult SC_CALL scReportAddIntValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + gsi_i32 theValue); +SCResult SC_CALL scReportAddInt64Value(SCReportPtr theReportData, + gsi_u16 theKeyId, + gsi_i64 theValue); +SCResult SC_CALL scReportAddShortValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + gsi_i16 theValue); +SCResult SC_CALL scReportAddByteValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + gsi_i8 theValue); +SCResult SC_CALL scReportAddFloatValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + float theValue); +SCResult SC_CALL scReportAddStringValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + const gsi_char * theValue); +SCResult SC_CALL scDestroyReport(SCReportPtr theReport); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Peer to peer encryption utilities (Will probably be moved to common code) + +// A symmetric cipher key for peer-to-peer communication +// Will usually have one key for sending and a second key for receiving +typedef struct SCPeerCipher +{ + RC4Context mRC4; + gsi_u8 mKey[GS_CRYPT_RSA_BYTE_SIZE]; + gsi_u32 mKeyLen; + gsi_bool mInitialized; +} SCPeerCipher; + +typedef char SCPeerKeyExchangeMsg[GS_CRYPT_RSA_BYTE_SIZE]; + +SCResult SC_CALL scPeerCipherInit(const GSLoginCertificate * theLocalCert, SCPeerCipher * theCipher); + +SCResult SC_CALL scPeerCipherCreateKeyExchangeMsg(const GSLoginCertificate * theRemoteCert, + const SCPeerCipher * theCipher, + SCPeerKeyExchangeMsg theMsgOut); + +SCResult SC_CALL scPeerCipherParseKeyExchangeMsg (const GSLoginCertificate * theLocalCert, + const GSLoginPrivateData * theCertPrivateData, + const SCPeerKeyExchangeMsg theMsg, + SCPeerCipher * theCipherOut); + +// Encrypt/Decrypt in place, also the RC4 context is modified everytime encryption/decryption take place +SCResult SC_CALL scPeerCipherEncryptBuffer(SCPeerCipher * theCipher, gsi_u8 * theData, gsi_u32 theLen); +SCResult SC_CALL scPeerCipherDecryptBuffer(SCPeerCipher * theCipher, gsi_u8 * theData, gsi_u32 theLen); + +// When using UDP (non-ordered) you must supply a message num +// - This is less efficient then ecrypting an ordered stream +SCResult SC_CALL scPeerCipherEncryptBufferIV(SCPeerCipher * theCipher, gsi_u32 theMessageNum, gsi_u8 * theData, gsi_u32 theLen); +SCResult SC_CALL scPeerCipherDecryptBufferIV(SCPeerCipher * theCipher, gsi_u32 theMessageNum, gsi_u8 * theData, gsi_u32 theLen); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SC_H__ diff --git a/xrGameSpy/gamespy/sc/scRaceSample/HostOrJoinDlg.cpp b/xrGameSpy/gamespy/sc/scRaceSample/HostOrJoinDlg.cpp new file mode 100644 index 00000000000..1bd41f5bc88 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/HostOrJoinDlg.cpp @@ -0,0 +1,69 @@ +// HostOrJoinDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ScRaceSample.h" +#include "HostOrJoinDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg dialog + + +CHostOrJoinDlg::CHostOrJoinDlg(CWnd* pParent /*=NULL*/) + : CDialog(CHostOrJoinDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CHostOrJoinDlg) + m_joinAddress = _T(""); + m_hostOrJoin = 0; + //}}AFX_DATA_INIT +} + + +void CHostOrJoinDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CHostOrJoinDlg) + DDX_Text(pDX, IDC_JOIN_ADDRESS, m_joinAddress); + DDX_Radio(pDX, IDC_HOST, m_hostOrJoin); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CHostOrJoinDlg, CDialog) + //{{AFX_MSG_MAP(CHostOrJoinDlg) + ON_EN_SETFOCUS(IDC_JOIN_ADDRESS, OnSetfocusJoinAddress) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg message handlers + +void CHostOrJoinDlg::OnOK() +{ + UpdateData(); + + // Check for no join address. + ///////////////////////////// + if((m_hostOrJoin == HOSTORJOIN_JOIN) && m_joinAddress.IsEmpty()) + { + MessageBox("Please enter the address of the host to connect to"); + return; + } + + CDialog::OnOK(); +} + +void CHostOrJoinDlg::OnSetfocusJoinAddress() +{ + // Make sure its on join. + ///////////////////////// + UpdateData(); + m_hostOrJoin = HOSTORJOIN_JOIN; + UpdateData(FALSE); +} diff --git a/xrGameSpy/gamespy/sc/scRaceSample/HostOrJoinDlg.h b/xrGameSpy/gamespy/sc/scRaceSample/HostOrJoinDlg.h new file mode 100644 index 00000000000..98fbc34eab6 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/HostOrJoinDlg.h @@ -0,0 +1,51 @@ +#if !defined(AFX_HOSTORJOINDLG_H__7A7BDB42_5AA8_45CD_9DD1_0EA7FC3A723F__INCLUDED_) +#define AFX_HOSTORJOINDLG_H__7A7BDB42_5AA8_45CD_9DD1_0EA7FC3A723F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// HostOrJoinDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CHostOrJoinDlg dialog + +#define HOSTORJOIN_HOST 0 +#define HOSTORJOIN_JOIN 1 + +class CHostOrJoinDlg : public CDialog +{ +// Construction +public: + CHostOrJoinDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CHostOrJoinDlg) + enum { IDD = IDD_HOST_OR_JOIN }; + CString m_joinAddress; + int m_hostOrJoin; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CHostOrJoinDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CHostOrJoinDlg) + virtual void OnOK(); + afx_msg void OnSetfocusJoinAddress(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_HOSTORJOINDLG_H__7A7BDB42_5AA8_45CD_9DD1_0EA7FC3A723F__INCLUDED_) diff --git a/xrGameSpy/gamespy/sc/scRaceSample/LoginDlg.cpp b/xrGameSpy/gamespy/sc/scRaceSample/LoginDlg.cpp new file mode 100644 index 00000000000..7d4cf438408 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/LoginDlg.cpp @@ -0,0 +1,245 @@ +// LoginDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ScRaceSample.h" +#include "LoginDlg.h" +#include "../../common/gsAvailable.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + + +CLoginDlg::CLoginDlg(CWnd* pParent /*=NULL*/) + : CDialog(CLoginDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoginDlg) + m_email = _T(""); + m_nick = _T(""); + m_password = _T(""); + //}}AFX_DATA_INIT +} + + +void CLoginDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoginDlg) + DDX_Text(pDX, IDC_EMAIL, m_email); + DDX_Text(pDX, IDC_NICK, m_nick); + DDX_Text(pDX, IDC_PASSWORD, m_password); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoginDlg, CDialog) + //{{AFX_MSG_MAP(CLoginDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg message handlers + +GPResult checkResult; +int checkProfile; +gsi_char loginResponse[1024]; +gsi_bool loginSuccess; +gsi_bool waitForLogin; + + +void CheckUserCallback(GPConnection * connection, void * _arg, void * param) +{ + GPCheckResponseArg * arg = (GPCheckResponseArg *)_arg; + + checkResult = arg->result; + checkProfile = arg->profile; +} + +void LoginCallback(GHTTPResult httpResult, WSLoginResponse * theResponse, void * theUserData) +{ + CString debugStr; + + if (httpResult != GHTTPSuccess) + { + loginSuccess = gsi_false; + + debugStr.Format("[LoginCallback] HTTPError: %d", httpResult); + OutputDebugString(debugStr); + + sprintf(loginResponse, "HTTP Error: Player Login Failed."); + } + else if (theResponse->mLoginResult != WSLogin_Success) + { + loginSuccess = gsi_false; + + debugStr.Format("[LoginCallback] Login Result Error: %d", theResponse->mLoginResult); + OutputDebugString(debugStr); + + sprintf(loginResponse, "Server Error: Player Login Failed."); + } + else + { + SamplePlayerData * newPlayer = &gPlayerData; + + loginSuccess = gsi_true; + + + // Store the profile ID for the player + ////////////////////////////////////// + newPlayer->mProfileId = theResponse->mCertificate.mProfileId; + + // Store the Login Certificate & Private Data for later use w/ Competition + ////////////////////////////////////////////////////////////////////////// + memcpy(&newPlayer->mCertificate, &theResponse->mCertificate, sizeof(GSLoginCertificate)); + memcpy(&newPlayer->mPrivateData, &theResponse->mPrivateData, sizeof(GSLoginPrivateData)); + } + waitForLogin = gsi_true; +} + + +void CLoginDlg::OnOK() +{ + GPConnection connection; + HCURSOR hourglass; + HCURSOR lastCursor; + GPResult result; + int loginResult; + + + UpdateData(); + + // Check for no account info + //////////////////////////// + if(m_email.IsEmpty() || m_nick.IsEmpty() || m_password.IsEmpty()) + { + MessageBox("Please fill in all the account information."); + return; + } + + // Initialize GP + //////////////// + if(gpInitialize(&connection, SCRACE_PRODUCTID, WSLogin_NAMESPACE_SHARED_NONUNIQUE, GP_PARTNERID_GAMESPY) != GP_NO_ERROR) + { + MessageBox("Error initializing the login system."); + return; + } + + // Wait cursor on + ///////////////// + hourglass = LoadCursor(NULL, IDC_WAIT); + if(hourglass) + lastCursor = SetCursor(hourglass); + + // Check for the account specified + ////////////////////////////////// + result = gpCheckUser(&connection, m_nick, m_email, m_password, GP_BLOCKING, CheckUserCallback, NULL); + + // Wait cursor off + ////////////////// + if(hourglass) + SetCursor(lastCursor); + + // Destroy the GP Object + //////////////////////// + gpDestroy(&connection); + + // Check for an error + ///////////////////// + if(result != GP_NO_ERROR) + { + MessageBox("Error verifying the account."); + return; + } + + // Check the result + /////////////////// + if(checkResult != GP_NO_ERROR) + { + if(checkResult == GP_CHECK_BAD_EMAIL) + MessageBox("Invalid e-mail."); + else if(checkResult == GP_CHECK_BAD_NICK) + MessageBox("Invalid nick."); + else if(checkResult == GP_CHECK_BAD_PASSWORD) + MessageBox("Invalid password."); + else + MessageBox("Error verifying the account."); + return; + } + + // Save the login info for next time + //////////////////////////////////// + FILE * file; + file = fopen("login.txt", "wt"); + if(file) + { + fprintf(file, "%s\n%s\n%s", m_email, m_nick, m_password); + fclose(file); + } + + // Login to the Authentication Service + ////////////////////////////////////// + loginResult = wsLoginProfile(WSLogin_NAMESPACE_SHARED_NONUNIQUE, WSLogin_PARTNERCODE_GAMESPY, m_nick, m_email, m_password, "", LoginCallback, NULL); + if (loginResult != WSLogin_Success) + { + if (loginResult == WSLogin_InvalidParameters) + MessageBox("Login Failed - Invalid Parameters."); // this should not be reached + else if (loginResult == WSLogin_OutOfMemory) + MessageBox("Login Failed - Out of Memory Exception."); + else if (loginResult == WSLogin_NoAvailabilityCheck) + MessageBox("Login Failed - Availability Check Not Performed"); + else + MessageBox("Login Failed - Unknown Error."); + return; + } + + while (!waitForLogin) + { + gsCoreThink(5); //process the login and wait for callback to complete + } + + if (!loginSuccess) + { + MessageBox(loginResponse); + return; + } + + CDialog::OnOK(); +} + +BOOL CLoginDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // load login info + ////////////////// + FILE * file; + file = fopen("login.txt", "rt"); + if(file) + { + char buffer[512]; + + if(fgets(buffer, sizeof(buffer), file)) + m_email = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_nick = buffer; + if(fgets(buffer, sizeof(buffer), file)) + m_password = buffer; + + fclose(file); + + m_email.Remove('\n'); + m_nick.Remove('\n'); + m_password.Remove('\n'); + } + + UpdateData(FALSE); + + return TRUE; +} \ No newline at end of file diff --git a/xrGameSpy/gamespy/sc/scRaceSample/LoginDlg.h b/xrGameSpy/gamespy/sc/scRaceSample/LoginDlg.h new file mode 100644 index 00000000000..a4fce342a62 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/LoginDlg.h @@ -0,0 +1,52 @@ +#if !defined(AFX_LOGINDLG_H__58A8C6B5_2AD3_4C62_882E_DC1F8D104CC5__INCLUDED_) +#define AFX_LOGINDLG_H__58A8C6B5_2AD3_4C62_882E_DC1F8D104CC5__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// LoginDlg.h : header file +// + + +///////////////////////////////////////////////////////////////////////////// +// CLoginDlg dialog + +class CLoginDlg : public CDialog +{ +// Construction +public: + CLoginDlg(CWnd* pParent = NULL); // standard constructor + SamplePlayerData m_playerData; // global player data + + +// Dialog Data + //{{AFX_DATA(CLoginDlg) + enum { IDD = IDD_LOGIN }; + CString m_email; + CString m_nick; + CString m_password; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoginDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoginDlg) + virtual void OnOK(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOGINDLG_H__58A8C6B5_2AD3_4C62_882E_DC1F8D104CC5__INCLUDED_) diff --git a/xrGameSpy/gamespy/sc/scRaceSample/ReadMe.txt b/xrGameSpy/gamespy/sc/scRaceSample/ReadMe.txt new file mode 100644 index 00000000000..b1744165d73 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/ReadMe.txt @@ -0,0 +1,42 @@ +=========================================================== +================ ScRaceSample Overview ==================== +=========================================================== + +The ScRaceSample program is intended to give developers an +example for how the Competition SDK is used in practice. The +sample game is a simple 1v1 racing game using a +challenge-response mechanism. + +========== +HOW TO USE +========== +1. Login with a GameSpy account + +When starting the sample, you will first see a Dialog Box +prompting you to login. Using your GameSpy account, login with +your e-mail, profile nickname and password. If you do not have +an account, you can create a free account at www.gamespyid.com. + +2. Choose to Host or Join a game + +After the login is complete, another Dialog Box will ask if you +plan to Host or Join the game. Once another player has a game +being hosted, you can enter that IP in order to join into his/her +game. This sample is very basic and does not do any NAT +Negotiation for Hosts behind NATs, so make sure ports are open for +connections that drop unsolicited packets. + +The Sample uses a default port of 38466 for the Host, which can be +modified at the top of ScRaceSampleDlg.cpp by changing the value +of HOST_PORT_STRING. The CLIENT_PORT_STRING is set to 38467 to +allow for local joining of a session. + +3. Start the Game + +Once the two players are connected. The Host can start the game +by clicking on "Start Game". The game will countdown from 5 and +say "GO!" when the game begins. To race, players must alternate +between pressing 'Z' and 'X' on the keyboard as quickly as +possible. The progress bar will display how far you and your +opponent are from the finish. The game will wait until both +players have finished before displaying the results. \ No newline at end of file diff --git a/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.cpp b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.cpp new file mode 100644 index 00000000000..e0971a256b0 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.cpp @@ -0,0 +1,68 @@ +// ScRaceSample.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "ScRaceSample.h" +#include "ScRaceSampleDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp + +BEGIN_MESSAGE_MAP(CLadderTrackApp, CWinApp) + //{{AFX_MSG_MAP(CLadderTrackApp) + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +SamplePlayerData gPlayerData; //global player data + + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp construction + +CLadderTrackApp::CLadderTrackApp() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CLadderTrackApp object + +CLadderTrackApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp initialization + +BOOL CLadderTrackApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + + CScRaceSampleDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + } + else if (nResponse == IDCANCEL) + { + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.h b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.h new file mode 100644 index 00000000000..a0b9ea90016 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.h @@ -0,0 +1,95 @@ +// ladderTrack.h : main header file for the LADDERTRACK application +// + +#if !defined(AFX_LADDERTRACK_H__E9856F44_580A_48C0_ABFF_6FFA9BA944A3__INCLUDED_) +#define AFX_LADDERTRACK_H__E9856F44_580A_48C0_ABFF_6FFA9BA944A3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// global defines used in the sample + +#define SCRACE_GAMENAME "sc_race" +#define SCRACE_SECRETKEY "Zc0eM6" +#define SCRACE_GAMEID 1649 +#define SCRACE_PRODUCTID 11030 + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This represents the player data structure in your game. +typedef struct SamplePlayerData +{ + // "Normal" game data + gsi_u32 mProfileId; + GSLoginCertificate mCertificate; + GSLoginPrivateData mPrivateData; + SCPeerCipher mPeerSendCipher; // for fast encryption + SCPeerCipher mPeerRecvCipher; // for fast decryption + + SCInterfacePtr mStatsInterface; + + // Stats related data + gsi_u8 mSessionId[SC_SESSION_GUID_SIZE]; + gsi_u8 mConnectionId[SC_CONNECTION_GUID_SIZE]; + gsi_u8 mStatsAuthdata[16]; + + gsi_i32 mFrags; + gsi_i32 mScore; + gsi_i16 mDeaths; + gsi_i16 mShots; + gsi_i32 mTeam; + + // Obfuscated versions + SCHiddenData mHiddenFrags; + SCHiddenData mHiddenDeaths; + SCHiddenData mHiddenShots; + SCHiddenData mHiddenScore; + + // A simple way to block the sample's progress + gsi_u32 mWaitCount; + +} SamplePlayerData; + +extern SamplePlayerData gPlayerData; + +///////////////////////////////////////////////////////////////////////////// +// CLadderTrackApp: +// See ladderTrack.cpp for the implementation of this class +// + +class CLadderTrackApp : public CWinApp +{ +public: + CLadderTrackApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLadderTrackApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CLadderTrackApp) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LADDERTRACK_H__E9856F44_580A_48C0_ABFF_6FFA9BA944A3__INCLUDED_) diff --git a/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.rc b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.rc new file mode 100644 index 00000000000..956b768ba8e --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSample.rc @@ -0,0 +1,239 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\ScRaceSample.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\ScRaceSample.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SCRACESAMPLE_DIALOG DIALOGEX 0, 0, 212, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "ScRaceSample" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Exit",IDOK,155,5,50,14 + PUSHBUTTON "Logout",IDC_LOGOUT,155,21,50,14 + PUSHBUTTON "Start Race",IDC_START_RACE,10,15,50,14 + LTEXT "Info",IDC_INFO,70,15,80,8 + CONTROL "Progress1",IDC_LOCAL_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,7,48,80,14 + CONTROL "Progress1",IDC_REMOTE_PROGRESS,"msctls_progress32", + PBS_SMOOTH | WS_BORDER,113,48,80,14 + LTEXT "You:",IDC_STATIC,7,38,16,8 + LTEXT "Opponent:",IDC_STATIC,113,38,34,8 + LTEXT "Use Z && X to race",IDC_STATIC,70,25,57,8 +END + +IDD_HOST_OR_JOIN DIALOG DISCARDABLE 0, 0, 165, 50 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Host or Join?" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Host",IDC_HOST,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7, + 7,31,10 + CONTROL "Join",IDC_JOIN,"Button",BS_AUTORADIOBUTTON,7,31,29,10 + EDITTEXT IDC_JOIN_ADDRESS,52,28,106,14,ES_AUTOHSCROLL | WS_GROUP + DEFPUSHBUTTON "OK",IDOK,52,7,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,108,7,50,14 +END + +IDD_WAITING DIALOG DISCARDABLE 0, 0, 64, 45 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ScRaceSample" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,7,24,50,14 + LTEXT "Please Wait...",IDC_STATIC,9,7,45,8 +END + +IDD_LOGIN DIALOG DISCARDABLE 0, 0, 147, 76 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "GameSpy Login" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_EMAIL,51,8,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_NICK,51,23,84,12,ES_AUTOHSCROLL + EDITTEXT IDC_PASSWORD,51,38,84,12,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "Login",IDOK,15,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,80,55,50,14 + LTEXT "email:",IDC_STATIC,10,10,19,8 + LTEXT "nick:",IDC_STATIC,10,25,16,8 + LTEXT "password:",IDC_STATIC,10,40,33,8 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "ScRaceSample MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "ScRaceSample\0" + VALUE "LegalCopyright", "Copyright (C) 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "ScRaceSample.EXE\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "ScRaceSample Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_SCRACESAMPLE_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 93 + END + + IDD_HOST_OR_JOIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 158 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_WAITING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 57 + TOPMARGIN, 7 + BOTTOMMARGIN, 38 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\ScRaceSample.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSampleDlg.cpp b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSampleDlg.cpp new file mode 100644 index 00000000000..495a58df02c --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSampleDlg.cpp @@ -0,0 +1,1486 @@ +// ScRaceSampleDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ScRaceSample.h" +#include "ScRaceSampleDlg.h" +#include "waitingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CScRaceSampleDlg dialog + +CScRaceSampleDlg::CScRaceSampleDlg(CWnd* pParent /*=NULL*/) + : CDialog(CScRaceSampleDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CScRaceSampleDlg) + m_info = _T("Ready"); + //}}AFX_DATA_INIT + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CScRaceSampleDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CScRaceSampleDlg) + DDX_Control(pDX, IDC_START_RACE, m_startRace); + DDX_Control(pDX, IDC_REMOTE_PROGRESS, m_remoteProgress); + DDX_Control(pDX, IDC_LOCAL_PROGRESS, m_localProgress); + DDX_Text(pDX, IDC_INFO, m_info); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CScRaceSampleDlg, CDialog) + //{{AFX_MSG_MAP(CScRaceSampleDlg) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_START_RACE, OnStart) + ON_WM_DESTROY() + ON_WM_TIMER() + ON_BN_CLICKED(IDC_LOGOUT, OnLogout) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CScRaceSampleDlg message handlers + +// Pre-game messaging +#define MSG_CONNECT "is" // client-pid, nick +#define MSG_TO_HOST_CERT "ir" // host-pid, certificate +#define MSG_TO_HOST_CERT_TYPE 1 +#define MSG_TO_CLIENT_CERT "ir" // join-pid, certificate +#define MSG_TO_CLIENT_CERT_TYPE 2 +#define MSG_TO_HOST_KEYS "r" // encryption keys +#define MSG_TO_HOST_KEYS_TYPE 3 +#define MSG_TO_CLIENT_KEYS "r" // encrpytion keys +#define MSG_TO_CLIENT_KEYS_TYPE 4 + +// Game messaging +#define MSG_COUNTDOWN "i" // count +#define MSG_COUNTDOWN_TYPE 20 +#define MSG_SESSION_ID "rr" // Host session ID, connID exchange +#define MSG_SESSION_ID_TYPE 21 +#define MSG_CONNECTION_ID "r" // connection ID exhcnage +#define MSG_CONNECTION_ID_TYPE 22 +#define MSG_START_RACE "" // race start +#define MSG_START_RACE_TYPE 23 +#define MSG_PROGRESS "i" // progress +#define MSG_PROGRESS_TYPE 24 +#define MSG_END_RACE "i" // time +#define MSG_END_RACE_TYPE 25 +#define MSG_CHAT "s" // message +#define MSG_CHAT_TYPE 26 + +//#define HOST_PORT 38466 +#define HOST_PORT_STRING ":38466" +#define CLIENT_PORT_STRING ":38467" // so you can run both +#define COUNTDOWN_START 5 + +#define TIMER_THINK 100 +#define TIMER_COUNTDOWN 101 + +// Stats & SDK constants +#define SCRACE_TIMEOUT_MS 0 +#define SCRACE_SLEEP_MS 100 +#define SCRACE_AUTHORITATIVE gsi_true +#define SCRACE_COLLABORATIVE gsi_false +#define SCRACE_NUM_PLAYERS 2 +#define SCRACE_NUM_TEAMS 2 + +#define SCRACE_HOST_TEAM 7564 // fake team ids +#define SCRACE_CLIENT_TEAM 7565 // fake team ids + + +CScRaceSampleDlg * Dlg; +gsi_bool sessionCreated; +gsi_bool connIdSet; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to block until a request completes +// Used to simplify the logic flow of the sample +void waitForScCallbacks(SCInterfacePtr theInterface, int howMany) +{ + // wait for the request to complete + ///////////////////////////////////////////////////////// + gPlayerData.mWaitCount = howMany; + while (gPlayerData.mWaitCount > 0) + { + msleep(SCRACE_SLEEP_MS); + scThink(theInterface); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Competition Callbacks +void createSessionCallback(const SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + CString debugStr; + + if (theHttpResult == GHTTPSuccess && theResult == SCResult_NO_ERROR) + { + // Retrieve the Session/Connection ID to be used later + ///////////////////////////////////////////////////////// + + memcpy(gPlayerData.mSessionId, scGetSessionId(theInterface), SC_SESSION_GUID_SIZE); + memcpy(gPlayerData.mConnectionId, scGetConnectionId(theInterface), SC_CONNECTION_GUID_SIZE); + + sessionCreated = gsi_true; + + debugStr.Format("[createSessionCB] Session ID: %s\n", gPlayerData.mSessionId); + OutputDebugString(debugStr); + debugStr.Format("[createSessionCB] Connection ID: [%s]\n", gPlayerData.mConnectionId); + OutputDebugString(debugStr); + } + else + { + debugStr.Format("[createSessionCB] Error. HTTPResult: %d, SCResult: %d\r\n", + theHttpResult, theResult); + OutputDebugString(debugStr); + + Dlg->MessageBox("Error Creating Stats Session"); + Dlg->Logout(); + } + + gPlayerData.mWaitCount--; + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + +void setReportIntentionCallback(const SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + CString debugStr; + + if (theHttpResult == GHTTPSuccess && theResult == SCResult_NO_ERROR) + { + // Retrieve the connection ID to be used later + ///////////////////////////////////////////////////////// + const char * connectionId = scGetConnectionId(theInterface); + memcpy(gPlayerData.mConnectionId, connectionId, SC_CONNECTION_GUID_SIZE); + connIdSet = gsi_true; + + debugStr.Format("[setIntentionCB] Connection ID: [%s]\n", gPlayerData.mConnectionId); + OutputDebugString(debugStr); + } + else + { + debugStr.Format("[setIntentionCB] Error. HTTPResult: %d, SCResult: %d\r\n", + theHttpResult, theResult); + OutputDebugString(debugStr); + + Dlg->MessageBox("Error Initializing Stats System"); + Dlg->Logout(); + } + + gPlayerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + +void submitReportCallback(const SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + CString debugStr; + + if (theHttpResult != GHTTPSuccess || theResult != SCResult_NO_ERROR) + { + debugStr.Format("[submitReportCB] Error. HTTPResult: %d, SCResult: %d\r\n", + theHttpResult, theResult); + OutputDebugString(debugStr); + + Dlg->MessageBox("Error Submitting Stats Report"); + } + + gPlayerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + +/////////////////////////////////////////////////////////////////////////////// +// GT2 Callbacks +void ConnectedCallback +( + GT2Connection connection, + GT2Result result, + GT2Byte * message, + int len +) +{ + if(result == GT2Success) + Dlg->m_state = JOIN_EXCHANGE_CERT; + else + { + Dlg->m_state = JOIN_ERROR; + Dlg->m_GT2Connection = NULL; + } +} + +void ReceivedCallback +( + GT2Connection connection, + GT2Byte * message, + int len, + GT2Bool reliable +) +{ + if(!message || !len) + return; + + GTMessageType type; + CString debugStr; + + type = gtEncodedMessageType((char*)message); + + if(type == MSG_TO_CLIENT_CERT_TYPE) + { + char remoteCert[512]; + int remoteCertLen = 512; + int pid; + + if(gtDecode(MSG_TO_CLIENT_CERT, (char*)message, len, &pid, remoteCert, &remoteCertLen) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + // Parse the certificate + ///////////////////////////////////////////////////////// + wsLoginCertReadBinary(&Dlg->m_remoteCertificate, remoteCert, remoteCertLen); + + Dlg->m_remoteProfile = pid; + + // Build up and send the certificate response + ///////////////////////////////////////////////////////// + char buffer[520]; + char cert[512]; + int rcode; + gsi_u32 certLen; + + wsLoginCertWriteBinary(&gPlayerData.mCertificate, cert, sizeof(cert), &certLen); + + rcode = gtEncode(MSG_TO_HOST_CERT_TYPE, MSG_TO_HOST_CERT, buffer, sizeof(buffer), gPlayerData.mProfileId, cert, certLen); + ASSERT(rcode != -1); + gt2Send(connection, (const unsigned char*)buffer, rcode, GT2True); + + Dlg->m_state = JOIN_VERIFY_CERT; + } + else if(type == MSG_TO_HOST_CERT_TYPE) + { + char remoteCert[512]; + int remoteCertLen = 512; + int pid; + + if(gtDecode(MSG_TO_HOST_CERT, (char*)message, len, &pid, remoteCert, &remoteCertLen) == -1) + { + Dlg->m_state = HOST_ERROR; + return; + } + + // Parse the certificate + ///////////////////////////////////////////////////////// + wsLoginCertReadBinary(&Dlg->m_remoteCertificate, remoteCert, remoteCertLen); + + Dlg->m_remoteProfile = pid; + Dlg->m_state = HOST_VERIFY_CERT; + } + else if(type == MSG_TO_CLIENT_KEYS_TYPE) + { + SCPeerKeyExchangeMsg recvMsg; + int recvMsgLen = GS_CRYPT_RSA_BYTE_SIZE; + + if(gtDecode(MSG_TO_CLIENT_KEYS, (char*)message, len, recvMsg, &recvMsgLen) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + // Receiving player should parse the cipher key out of it. + // - decrypting the msg requires the local player's private data + ///////////////////////////////////////////////////////// + scPeerCipherParseKeyExchangeMsg(&gPlayerData.mCertificate, &gPlayerData.mPrivateData, + recvMsg, &gPlayerData.mPeerSendCipher); + + + // Send response to host + ///////////////////////////////////////////////////////// + char buffer[512]; + int rcode; + SCPeerKeyExchangeMsg exchangeMsg; + + scPeerCipherInit(&gPlayerData.mCertificate, &gPlayerData.mPeerRecvCipher); + scPeerCipherCreateKeyExchangeMsg(&Dlg->m_remoteCertificate, &gPlayerData.mPeerRecvCipher, exchangeMsg); + + // Now send the key to the other player + ///////////////////////////////////////////////////////// + rcode = gtEncode(MSG_TO_HOST_KEYS_TYPE, MSG_TO_HOST_KEYS, buffer, sizeof(buffer), exchangeMsg, GS_CRYPT_RSA_BYTE_SIZE); + ASSERT(rcode != -1); + gt2Send(connection, (const unsigned char*)buffer, rcode, GT2True); + + Dlg->m_state = JOIN_CONNECTED; + } + else if(type == MSG_TO_HOST_KEYS_TYPE) + { + SCPeerKeyExchangeMsg exchangeMsg; + int exchangeMsgLen = GS_CRYPT_RSA_BYTE_SIZE; + + if(gtDecode(MSG_TO_HOST_KEYS, (char*)message, len, exchangeMsg, &exchangeMsgLen) == -1) + { + Dlg->m_state = HOST_ERROR; + return; + } + + // Receiving player should parse the cipher key out of it. + // - decrypting the msg requires the local player's private data + ///////////////////////////////////////////////////////// + scPeerCipherParseKeyExchangeMsg(&gPlayerData.mCertificate, &gPlayerData.mPrivateData, + exchangeMsg, &gPlayerData.mPeerSendCipher); + + + Dlg->m_state = HOST_CONNECTED; + } + else if(type == MSG_COUNTDOWN_TYPE) + { + ASSERT(!Dlg->m_hosting); + + if(gtDecode(MSG_COUNTDOWN, (char*)message, len, &Dlg->m_countdown) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + Dlg->Countdown(); + } + else if(type == MSG_SESSION_ID_TYPE) + { + ASSERT(!Dlg->m_hosting); + char sessionCrypt[SC_SESSION_GUID_SIZE]; + char connCrypt[SC_CONNECTION_GUID_SIZE]; + int sidLen = SC_SESSION_GUID_SIZE; + int ccidLen = SC_CONNECTION_GUID_SIZE; + + + // Client decodes sessionID / remote connID + ///////////////////////////////////////////////////////// + if(gtDecode(MSG_SESSION_ID, (char*)message, len, sessionCrypt, &sidLen, connCrypt, &ccidLen) == -1) + { + Dlg->m_state = JOIN_ERROR; + return; + } + + debugStr.Format("[MSG_SESSION_ID_TYPE] sessionCrypt: %.40s\r\n", sessionCrypt); + OutputDebugString(debugStr); + debugStr.Format("[MSG_SESSION_ID_TYPE] connCrypt: %.40s\r\n", connCrypt); + OutputDebugString(debugStr); + + // Decrypt the sessionID / remote connID + ///////////////////////////////////////////////////////// + scPeerCipherDecryptBufferIV(&gPlayerData.mPeerRecvCipher, 1, (gsi_u8*)sessionCrypt, SC_SESSION_GUID_SIZE); + memcpy(gPlayerData.mSessionId, sessionCrypt, SC_SESSION_GUID_SIZE); + + scPeerCipherDecryptBufferIV(&gPlayerData.mPeerRecvCipher, 2, (gsi_u8*)connCrypt, SC_CONNECTION_GUID_SIZE); + memcpy(Dlg->m_remoteConnId, connCrypt, SC_CONNECTION_GUID_SIZE); + + + debugStr.Format("[MSG_SESSION_ID_TYPE] mSessionId: %s\r\n", gPlayerData.mSessionId); + OutputDebugString(debugStr); + debugStr.Format("[MSG_SESSION_ID_TYPE] m_remoteConnId: %s\r\n", Dlg->m_remoteConnId); + OutputDebugString(debugStr); + + + // Joining player sets the session ID and the report intention + ///////////////////////////////////////////////////////// + scSetSessionId(gPlayerData.mStatsInterface, gPlayerData.mSessionId); + scSetReportIntention(gPlayerData.mStatsInterface, gPlayerData.mConnectionId, SCRACE_AUTHORITATIVE, &gPlayerData.mCertificate, &gPlayerData.mPrivateData, + setReportIntentionCallback, SCRACE_TIMEOUT_MS, NULL); + + Dlg->m_state = JOIN_SEND_CONNID; + } + else if(type == MSG_CONNECTION_ID_TYPE) + { + ASSERT(Dlg->m_hosting); + char connCrypt[SC_CONNECTION_GUID_SIZE]; + int ccidLen = SC_CONNECTION_GUID_SIZE; + + // Hosting player decodes the remote conn ID for use in reporting + ///////////////////////////////////////////////////////// + if(gtDecode(MSG_CONNECTION_ID, (char*)message, len, connCrypt, &ccidLen) == -1) + { + Dlg->m_state = HOST_ERROR; + return; + } + + debugStr.Format("[MSG_CONNECTION_ID_TYPE] connCrypt: %.40s\r\n", connCrypt); + OutputDebugString(debugStr); + + + // Decrypt the remote conn ID + ///////////////////////////////////////////////////////// + scPeerCipherDecryptBufferIV(&gPlayerData.mPeerRecvCipher, 1, (gsi_u8*)connCrypt, SC_CONNECTION_GUID_SIZE); + memcpy(Dlg->m_remoteConnId, connCrypt, SC_CONNECTION_GUID_SIZE); + + + debugStr.Format("[MSG_CONNECTION_ID_TYPE] m_remoteConnId: %s\r\n", Dlg->m_remoteConnId); + OutputDebugString(debugStr); + + // at this point all of our exchanges are complete - ready for game start + ///////////////////////////////////////////////////////// + } + else if(type == MSG_START_RACE_TYPE) + { + ASSERT(!Dlg->m_hosting); + + Dlg->StartRace(); + } + else if(type == MSG_PROGRESS_TYPE) + { + if(Dlg->m_racing) + { + int progress; + + if(gtDecode(MSG_PROGRESS, (char*)message, len, &progress) != -1) + { + Dlg->m_remoteProgress.SetPos(progress); + } + } + } + else if(type == MSG_END_RACE_TYPE) + { + if(Dlg->m_racing) + { + gtDecode(MSG_END_RACE, (char*)message, len, &Dlg->m_remoteTime); + } + } +} + +void ClosedCallback +( + GT2Connection connection, + GT2CloseReason reason +) +{ + // Logout triggers this function when it's a local close + // so we need to make sure we don't loop + ///////////////////////////////////////////////////////// + if (reason != GT2LocalClose) + { + if (Dlg->m_racing && !Dlg->m_reportSent) + { + // If the connection was closed remotely, or connection errors occured + // we should report stats anyways + ////////////////////////////////////////////////////////////////////// + Dlg->MessageBox("Connection closed - Sending Broken report"); + + Dlg->m_disconnect = gsi_true; + Dlg->ReportStats(); + + // Reset progress bars + ////////////////////// + Dlg->m_localProgress.SetPos(0); + Dlg->m_remoteProgress.SetPos(0); + + // Once stats have been reported, we can logout + /////////////////////////////////////////////// + Dlg->Logout(); + } + else + { + // Reset progress bars + ////////////////////// + Dlg->m_localProgress.SetPos(0); + Dlg->m_remoteProgress.SetPos(0); + + Dlg->MessageBox("Connection closed"); + Dlg->Logout(); + } + } + else + Dlg->m_GT2Connection = NULL; +} + +void ConnectAttemptCallback +( + GT2Socket listener, + GT2Connection connection, + unsigned int ip, + unsigned short port, + int latency, + GT2Byte * message, + int len +) +{ + int pid = 0; + char nick[128]; + + // Only allow one connection. + ///////////////////////////// + if(Dlg->m_GT2Connection) + { + gt2Reject(connection, NULL, 0); + return; + } + + // Decode the pid. + ////////////////// + if(message && len) + { + if(gtDecodeNoType(MSG_CONNECT, (char*)message, len, &pid, nick) == -1) + pid = 0; + } + + // If we didn't/couldn't get the pid, reject the attempt. + ///////////////////////////////////////////////////////// + if(!pid) + { + gt2Reject(connection, NULL, 0); + return; + } + + // Accept the connection. + ///////////////////////// + GT2ConnectionCallbacks callbacks; + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + if(!gt2Accept(connection, &callbacks)) + return; + + // Set some states. + /////////////////// + Dlg->m_remoteProfile = pid; + Dlg->m_GT2Connection = connection; + Dlg->m_state = HOST_EXCHANGE_CERT; //once connected, exchange certifications + Dlg->m_remoteNick = nick; +} + +void SocketErrorCallback +( + GT2Socket socket +) +{ + Dlg->MessageBox("Socket Error!"); + Dlg->Logout(); +} + + +BOOL CScRaceSampleDlg::SetupHosting() +{ + int rcode; + CString str; + + + GT2ConnectionCallbacks connectionCallbacks; + memset(&connectionCallbacks, 0, sizeof(GT2ConnectionCallbacks)); + connectionCallbacks.received = ReceivedCallback; + connectionCallbacks.closed = ClosedCallback; + + GT2Result aResult = gt2CreateSocket(&m_GT2Socket, HOST_PORT_STRING, 0, 0, SocketErrorCallback); + if (GT2Success != aResult) + return FALSE; + + gt2Listen(m_GT2Socket, ConnectAttemptCallback); + m_state = HOST_LISTENING; + + // Bring up the "waiting" dialog. + ///////////////////////////////// + rcode = m_waitingDlg.DoModal(); + + // If it was cancelled, try again. + ////////////////////////////////// + if(rcode != IDOK) + Logout(); + + return TRUE; +} + +BOOL CScRaceSampleDlg::SetupJoining() +{ + int rcode; + + // Setup the address to connect to. + /////////////////////////////////// + CString remoteAddress; + remoteAddress.Format("%s%s", m_hostOrJoinDlg.m_joinAddress, HOST_PORT_STRING); + + // Encode the profile id. + ///////////////////////// + char buffer[64]; + rcode = gtEncodeNoType(MSG_CONNECT, buffer, sizeof(buffer), gPlayerData.mProfileId, m_loginDlg.m_nick); + ASSERT(rcode != -1); + + // Setup the callbacks. + /////////////////////// + GT2ConnectionCallbacks callbacks; + memset(&callbacks, 0, sizeof(GT2ConnectionCallbacks)); + callbacks.connected = ConnectedCallback; + callbacks.received = ReceivedCallback; + callbacks.closed = ClosedCallback; + + // Create the socket + GT2Result aResult = gt2CreateSocket(&m_GT2Socket, CLIENT_PORT_STRING, 0, 0, SocketErrorCallback); + if (aResult != GT2Success) + { + MessageBox("Failed to create socket!"); + return FALSE; + } + + // Connect. + /////////// + m_state = JOIN_CONNECTING; + GT2Result result; + result = gt2Connect(m_GT2Socket, &m_GT2Connection, remoteAddress, (const GT2Byte *)buffer, sizeof(buffer), -1, &callbacks, GT2False); + if(!m_GT2Connection) + return FALSE; + + // Bring up the "waiting" dialog. + ///////////////////////////////// + rcode = m_waitingDlg.DoModal(); + + // If it was cancelled, try again. + ////////////////////////////////// + if(rcode != IDOK) + Logout(); + + return TRUE; +} + +BOOL CScRaceSampleDlg::SetupMatch() +{ + int rcode; + BOOL result; + + m_state = SETTING_UP; + + ASSERT(!m_GT2Connection); + ASSERT(!m_GT2Socket); + + m_state = 0; + m_remoteResponse.Empty(); + m_remoteProfile = 0; + m_GT2Connection = NULL; + m_startRace.EnableWindow(FALSE); + m_start = 0; + m_countdown = 0; + m_racing = FALSE; + m_numSteps = 0; + m_step = NONE; + m_reportSent = gsi_false; + + do + { + // Login the user + ////////////////////////////////////////////////////// + rcode = m_loginDlg.DoModal(); + if(rcode != IDOK) + { + PostQuitMessage(1); + return FALSE; + } + + // See if they want to host or join. + //////////////////////////////////// + rcode = m_hostOrJoinDlg.DoModal(); + } + while(rcode != IDOK); + + m_GT2Connection = NULL; + m_hosting = (m_hostOrJoinDlg.m_hostOrJoin == HOSTORJOIN_HOST); + + CString str; + str.Format("ScRaceSample%s", m_hosting?" (hosting)":""); + SetWindowText(str); + + if(m_hosting) + result = SetupHosting(); + else + result = SetupJoining(); + + if(result && m_hosting) + { + m_startRace.EnableWindow(); + } + + return result; +} + +BOOL CScRaceSampleDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIcon, FALSE); + + // Basic initialization. + //////////////////////// + Dlg = this; + sessionCreated = gsi_false; + connIdSet = gsi_false; + m_GT2Connection = NULL; + m_GT2Socket = NULL; + m_state = LOGGED_OUT; + m_countdown = 0; + m_racing = FALSE; + + + // Do Availability Check - Make sure backend is available + ///////////////////////////////////////////////////////// + GSIACResult aResult = GSIACWaiting; + GSIStartAvailableCheck(SCRACE_GAMENAME); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + msleep(5); + } + + if (aResult == GSIACUnavailable) + { + MessageBox("Online service for ScRaceSample is no longer available."); + return FALSE; + } + + if (aResult == GSIACTemporarilyUnavailable) + { + MessageBox("Online service for ScRaceSample is temporarily down for maintenance."); + return FALSE; + } + + + // Initialize SDK core object - used for both the AuthService and the Competition SDK + ///////////////////////////////// + gsCoreInitialize(); + + + // Initialize the Competition SDK - all users submit a snapshot + ///////////////////////////////// + if (scInitialize(SCRACE_GAMEID, &m_interface) != SCResult_NO_ERROR) + { + MessageBox("Out of memory exception - application failed to initialize."); + return FALSE; + } + gPlayerData.mStatsInterface = m_interface; + + + // Set a think timer. + ///////////////////// + SetTimer(TIMER_THINK, 50, NULL); + + return TRUE; +} + +void CScRaceSampleDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +HCURSOR CScRaceSampleDlg::OnQueryDragIcon() +{ + return (HCURSOR) m_hIcon; +} + +void CScRaceSampleDlg::OnLogout() +{ + if (m_racing && !m_reportSent) + { + // If we close the connection explicitly, we should report our stats + ////////////////////////////////////////////////////////////////////// + MessageBox("Logging out - Sending Broken report"); + + m_disconnect = gsi_true; + ReportStats(); + + // Reset progress bars + ////////////////////// + m_localProgress.SetPos(0); + m_remoteProgress.SetPos(0); + } + + // Clean stuff up. + ////////////////// + if(m_GT2Connection) + { + gt2CloseConnection(m_GT2Connection); + m_GT2Connection = NULL; + } + if(m_GT2Socket) + { + gt2CloseSocket(m_GT2Socket); + m_GT2Socket = NULL; + } + if(m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + { + m_waitingDlg.EndDialog(IDCANCEL); + } + + m_state = LOGGED_OUT; +} + +void CScRaceSampleDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + if (m_racing && !m_reportSent) + { + // If we attempt to kill the app by hard-killing it or exiting while in + // the middle of a game, report it as a disconnect + ////////////////////////////////////////////////////////////////////// + MessageBox("Hard Close - Sending Broken report"); + + m_disconnect = gsi_true; + ReportStats(); + + // Reset progress bars + ////////////////////// + m_localProgress.SetPos(0); + m_remoteProgress.SetPos(0); + } + + scShutdown(m_interface); + m_interface = NULL; + + gsCoreShutdown(); + + // Wait for core shutdown + // (should be instantaneous unless you have multiple cores) + while(gsCoreIsShutdown() == GSCore_SHUTDOWN_PENDING) + { + gsCoreThink(0); + msleep(5); + } + + ghttpCleanup(); + + if (m_GT2Connection) + { + gt2CloseConnection(m_GT2Connection); + m_GT2Connection = NULL; + } + if (m_GT2Socket) + { + gt2CloseSocket(m_GT2Socket); + m_GT2Socket = NULL; + } +} + +void CScRaceSampleDlg::OnTimer(UINT nIDEvent) +{ + CString debugStr; + + if(nIDEvent == TIMER_THINK) + { + static BOOL thinking; + + if(!thinking) + { + thinking = TRUE; + + // Think so SDKs can process + ///////////////////////////////////////////// + if (m_GT2Socket) + gt2Think(m_GT2Socket); + ghttpThink(); + scThink(m_interface); + +// ********************************************************** // +// ************************* HOST LOGIC ********************* // +// ********************************************************** // + + if(m_state == HOST_EXCHANGE_CERT) + { + char buffer[520]; + char cert[512]; + int rcode; + gsi_u32 certLen; + + // Store cert in a binary buffer for easy exchange + ///////////////////////////////////////////// + wsLoginCertWriteBinary(&gPlayerData.mCertificate, cert, sizeof(cert), &certLen); + + // Exchange certificates with the other player to validate (step 1) + ///////////////////////////////////////////// + rcode = gtEncode(MSG_TO_CLIENT_CERT_TYPE, MSG_TO_CLIENT_CERT, buffer, sizeof(buffer), gPlayerData.mProfileId, cert, certLen); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + + // Wait for a reply + ///////////////////////////////////////////// + m_state = HOST_WAITING; + } + else if(m_state == HOST_VERIFY_CERT) + { + // Validate authentication certificates (step 2) + ///////////////////////////////////////////// + Dlg->m_remoteCertificate.mIsValid = wsLoginCertIsValid(&Dlg->m_remoteCertificate); + if (gsi_is_false(Dlg->m_remoteCertificate.mIsValid)) + { + MessageBox("Remote player has an invalid certificate, cancelling game."); + m_waitingDlg.EndDialog(IDCANCEL); + Logout(); + } + else + m_state = HOST_EXCHANGE_KEYS; + } + else if(m_state == HOST_EXCHANGE_KEYS) + { + char buffer[512]; + int rcode; + SCPeerKeyExchangeMsg exchangeMsg; + + // P2P encryption exchange keys (step 3) + ///////////////////////////////////////////// + + // Each player should create a key for receiving data from the remote player + // For extra security, we use a different encryption key for each channel + ///////////////////////////////////////////// + scPeerCipherInit(&gPlayerData.mCertificate, &gPlayerData.mPeerRecvCipher); + + // Create a key exchange message for transmitting the key to the other player + // using the remote player's certificate to encrypt the cipher + ///////////////////////////////////////////// + scPeerCipherCreateKeyExchangeMsg(&m_remoteCertificate, &gPlayerData.mPeerRecvCipher, exchangeMsg); + + // Now send the key to the other player + ///////////////////////////////////////////// + rcode = gtEncode(MSG_TO_CLIENT_KEYS_TYPE, MSG_TO_CLIENT_KEYS, buffer, sizeof(buffer), exchangeMsg, GS_CRYPT_RSA_BYTE_SIZE); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + + // Wait for a reply + ///////////////////////////////////////////// + m_state = HOST_WAITING; + } + else if(m_state == HOST_CONNECTED) + { + if (m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + m_waitingDlg.EndDialog(IDOK); + m_state = RACING; + } + else if(m_state == HOST_SEND_SESSID) + { + if(sessionCreated) + { + int rcode; + char buffer[256]; + char sessionCrypt[SC_SESSION_GUID_SIZE]; + char connCrypt[SC_CONNECTION_GUID_SIZE]; + + // Encrypt the connID/session ID to send using P2P encryption + ///////////////////////////////////////////////////////// + memcpy(sessionCrypt, gPlayerData.mSessionId, SC_SESSION_GUID_SIZE); + scPeerCipherEncryptBufferIV(&gPlayerData.mPeerSendCipher, 1, (gsi_u8*)sessionCrypt, SC_SESSION_GUID_SIZE); + + memcpy(connCrypt, gPlayerData.mConnectionId, SC_CONNECTION_GUID_SIZE); + scPeerCipherEncryptBufferIV(&gPlayerData.mPeerSendCipher, 2, (gsi_u8*)connCrypt, SC_CONNECTION_GUID_SIZE); + + debugStr.Format("[HOST_SEND_SESSID] sessionCrypt: %.40s\r\n", sessionCrypt); + OutputDebugString(debugStr); + debugStr.Format("[HOST_SEND_SESSID] connCrypt: %.40s\r\n", connCrypt); + OutputDebugString(debugStr); + + + // Now the host sends the session ID & his conn ID to the client + ///////////////////////////////////////////// + rcode = gtEncode(MSG_SESSION_ID_TYPE, MSG_SESSION_ID, buffer, sizeof(buffer), + sessionCrypt, SC_SESSION_GUID_SIZE, connCrypt, SC_CONNECTION_GUID_SIZE); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + + + // Once session is created, set the session ID and report intention + ///////////////////////////////////////////// + scSetSessionId(m_interface, gPlayerData.mSessionId); + scSetReportIntention(m_interface, gPlayerData.mConnectionId, SCRACE_AUTHORITATIVE, &gPlayerData.mCertificate, &gPlayerData.mPrivateData, + setReportIntentionCallback, SCRACE_TIMEOUT_MS, NULL); + + sessionCreated = gsi_false; + + // Go back to connected state + ///////////////////////////////////////////// + m_state = HOST_CONNECTED; + } + } + else if(m_state == HOST_ERROR) + { + MessageBox("Error setting up hosting"); + m_waitingDlg.EndDialog(IDCANCEL); + } + +// ********************************************************** // +// **************** JOIN (CLIENT) LOGIC ********************* // +// ********************************************************** // + + else if(m_state == JOIN_EXCHANGE_CERT) + { + // Wait for host to send cert first + ///////////////////////////////////////////// + } + else if(m_state == JOIN_VERIFY_CERT) + { + // Validate authentication certificates (step 2) + ///////////////////////////////////////////// + Dlg->m_remoteCertificate.mIsValid = wsLoginCertIsValid(&Dlg->m_remoteCertificate); + if (gsi_is_false(Dlg->m_remoteCertificate.mIsValid)) + { + MessageBox("Remote player has an invalid certificate, cancelling game."); + m_waitingDlg.EndDialog(IDCANCEL); + Logout(); + } + else + m_state = JOIN_EXCHANGE_KEYS; + } + else if(m_state == JOIN_EXCHANGE_KEYS) + { + // Wait for host to send keys first + ///////////////////////////////////////////// + } + else if(m_state == JOIN_CONNECTED) + { + if(m_waitingDlg.m_hWnd && m_waitingDlg.IsWindowEnabled()) + m_waitingDlg.EndDialog(IDOK); + } + else if(m_state == JOIN_SEND_CONNID) + { + // Once connection ID has been set, relay it to the host + ///////////////////////////////////////////// + if (connIdSet) + { + int rcode; + char buffer[128]; + char connCrypt[SC_CONNECTION_GUID_SIZE]; + + // Encrypt the connection ID to send using P2P encryption + ///////////////////////////////////////////////////////// + memcpy(connCrypt, gPlayerData.mConnectionId, SC_CONNECTION_GUID_SIZE); + scPeerCipherEncryptBufferIV(&gPlayerData.mPeerSendCipher, 1, (gsi_u8*)connCrypt, SC_CONNECTION_GUID_SIZE); + + debugStr.Format("[JOIN_SEND_CONNID] connCrypt: %.40s\r\n", connCrypt); + OutputDebugString(debugStr); + + + // Client needs to send the host his/her connection ID + ///////////////////////////////////////////// + rcode = gtEncode(MSG_CONNECTION_ID_TYPE, MSG_CONNECTION_ID, buffer, sizeof(buffer), connCrypt, SC_CONNECTION_GUID_SIZE); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + + connIdSet = gsi_false; + + // Go back to the connected state + ///////////////////////////////////////////// + m_state = JOIN_CONNECTED; + } + } + else if(m_state == JOIN_ERROR) + { + MessageBox("Error joining a game"); + m_waitingDlg.EndDialog(IDCANCEL); + } + + thinking = FALSE; + } + + if(m_state == LOGGED_OUT) + { + if(!Dlg->SetupMatch()) + { + MessageBox("Error setting up the match"); + Logout(); + } + } + + // Are we racing? + ///////////////// + if(m_racing) + { + // Did we finish? + ///////////////// + if(m_localTime) + { + // Did we both finish? + ////////////////////// + if(m_remoteTime) + { + // Done racing. + /////////////// + m_racing = FALSE; + + m_info = "Race Complete"; + UpdateData(FALSE); + + // Show the times. + ////////////////// + CString message; + if(m_localTime < m_remoteTime) + { + message.Format("You won!\n%0.3fs to %0.3fs", m_localTime / 1000.0, m_remoteTime / 1000.0); + m_win = gsi_true; + } + else if(m_remoteTime < m_localTime) + { + message.Format("You lost!\n%0.3fs to %0.3fs", m_localTime / 1000.0, m_remoteTime / 1000.0); + } + else + { + message.Format("You tied!\n%0.3fs", m_localTime / 1000.0); + m_tie = gsi_true; + } + MessageBox(message); + + + // Report the stats. + //////////////////// + if (!m_reportSent) + { + m_disconnect = gsi_false; + ReportStats(); + } + + m_localProgress.SetPos(0); + m_remoteProgress.SetPos(0); + } + } + else + { + char buffer[64]; + int rcode; + + // Let our opponent know how far we are. + //////////////////////////////////////// + rcode = gtEncode(MSG_PROGRESS_TYPE, MSG_PROGRESS, buffer, sizeof(buffer), m_numSteps); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2False); + } + } + } + else if(nIDEvent == TIMER_COUNTDOWN) + { + m_countdown--; + if(m_countdown <= 0) + KillTimer(TIMER_COUNTDOWN); + + if(m_countdown < 0) + return; + + Countdown(); + if(!m_countdown) + StartRace(); + } + + CDialog::OnTimer(nIDEvent); +} + +void CScRaceSampleDlg::Logout() +{ + OnLogout(); +} + +void CScRaceSampleDlg::Countdown() +{ + // If report was just recently submitted, reset the submission flag + /////////////////////////////////////////////////////////////////// + if (m_reportSent) + m_reportSent = gsi_false; + + if(m_hosting) + { + int rcode; + char message[32]; + + rcode = gtEncode(MSG_COUNTDOWN_TYPE, MSG_COUNTDOWN, message, sizeof(message), m_countdown); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)message, rcode, GT2True); + } + + if(m_countdown) + { + UpdateData(); + + m_info.Format("Race starts in %ds", m_countdown); + + UpdateData(FALSE); + } +} + +void CScRaceSampleDlg::OnStart() +{ + // The countdown here could be thought of as a loading screen. + // During this loading phase - the Host will create the game session and notify + // the other players of the session ID. All players will set their report intentions. + ///////////////////////////////////////////// + if (m_hosting) + { + scCreateSession(m_interface, &gPlayerData.mCertificate, &gPlayerData.mPrivateData, + createSessionCallback, SCRACE_TIMEOUT_MS, NULL); + m_state = HOST_SEND_SESSID; + } + + // Start the countdown. + /////////////////////// + m_countdown = COUNTDOWN_START; + SetTimer(TIMER_COUNTDOWN, 1000, NULL); + Countdown(); +} + +BOOL CScRaceSampleDlg::PreTranslateMessage(MSG* pMsg) +{ + if(pMsg->message == WM_KEYDOWN) + { + int nChar = pMsg->wParam; + if((nChar == 'Z') || (nChar == 'X')) + { + if((pMsg->lParam & 0xFFFF) == 1) + { + CString str; + BOOL stepped = FALSE; + + if((nChar == 'Z') && (m_step != LEFT)) + { + m_step = LEFT; + m_numSteps++; + stepped = TRUE; + } + else if ((nChar == 'X') && (m_step != RIGHT)) + { + m_step = RIGHT; + m_numSteps++; + stepped = TRUE; + } + + if(stepped && m_racing) + { + m_localProgress.SetPos(m_numSteps); + if(m_numSteps == m_totalSteps) + { + m_localTime = (GetTickCount() - m_start); + str.Format("%0.3fs\n", m_localTime / 1000.0); + OutputDebugString(str); + //MessageBox(str); + + if(!m_remoteTime) + { + UpdateData(); + m_info = "Waiting for opponent"; + UpdateData(FALSE); + } + + // Let them know we finished. + ///////////////////////////// + char buffer[32]; + int rcode; + rcode = gtEncode(MSG_END_RACE_TYPE, MSG_END_RACE, buffer, sizeof(buffer), m_localTime); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + } + } + } + + return TRUE; + } + } + + return CDialog::PreTranslateMessage(pMsg); +} + +void CScRaceSampleDlg::StartRace() +{ + if(m_hosting) + { + int rcode; + char buffer[32]; + rcode = gtEncode(MSG_START_RACE_TYPE, MSG_START_RACE, buffer, sizeof(buffer)); + ASSERT(rcode != -1); + gt2Send(m_GT2Connection, (const unsigned char*)buffer, rcode, GT2True); + } + + m_localTime = 0; + m_remoteTime = 0; + m_racing = TRUE; + m_numSteps = 0; + m_step = NONE; + m_racing = TRUE; + m_start = GetTickCount(); + m_totalSteps = RACE_STEPS; + m_localProgress.SetRange(0, m_totalSteps); + m_localProgress.SetPos(0); + m_remoteProgress.SetRange(0, m_totalSteps); + m_remoteProgress.SetPos(0); + + // initialize stats markers + ///////////////////////////////////////////// + m_win = gsi_false; + m_tie = gsi_false; + m_disconnect = gsi_false; + + + UpdateData(); + m_info.Format("GO!"); + UpdateData(FALSE); +} + +void CScRaceSampleDlg::ReportStats() +{ + SCReportPtr aReport = NULL; + SCResult aResult = SCResult_NO_ERROR; + SCGameResult myGameResult, opponentGameResult; + int myTeam, opponentTeam; + char myTeamName[64], opponentTeamName[64]; + int numPlayers = SCRACE_NUM_PLAYERS; + int numTeams = SCRACE_NUM_TEAMS; + + + // Determine winners and losers + ///////////////////////////////////////////// + if (!m_disconnect) + { + if (m_win) + { + myGameResult = SCGameResult_WIN; + opponentGameResult = SCGameResult_LOSS; + } + else if (!m_tie) + { + myGameResult = SCGameResult_LOSS; + opponentGameResult = SCGameResult_WIN; + } + else + { + myGameResult = SCGameResult_DRAW; + opponentGameResult = SCGameResult_DRAW; + } + } + else + { + //report disconnected game - don't report any keys + myGameResult = SCGameResult_DISCONNECT; + opponentGameResult = SCGameResult_DISCONNECT; + } + + + // Determine teams, and who is on which + ///////////////////////////////////////////// + if (m_hosting) + { + myTeam = SCRACE_HOST_TEAM; + opponentTeam = SCRACE_CLIENT_TEAM; + } + else + { + myTeam = SCRACE_CLIENT_TEAM; + opponentTeam = SCRACE_HOST_TEAM; + } + + sprintf(myTeamName, "%s's Team", m_loginDlg.m_nick); + sprintf(opponentTeamName, "%s's Team", m_remoteCertificate.mProfileNick); + + + // Create the report and begin building it + ///////////////////////////////////////////// + aResult = scCreateReport(m_interface, ATLAS_RULE_SET_VERSION, numPlayers, numTeams, &aReport); + if (aResult != SCResult_NO_ERROR) + { + MessageBox("Failed to Create Report - Out of memory"); + return; + } + + // Non-player data + ///////////////////////////////////////////// + scReportBeginGlobalData(aReport); + // no global data reported + + // Player data + ///////////////////////////////////////////// + scReportBeginPlayerData(aReport); + + // Report your data + //////////////////// + scReportBeginNewPlayer(aReport); + scReportSetPlayerData(aReport, 0, gPlayerData.mConnectionId, myTeam, + myGameResult, gPlayerData.mProfileId, &gPlayerData.mCertificate, gPlayerData.mStatsAuthdata); + if (!m_disconnect) + scReportAddIntValue(aReport, RACE_TIME, m_localTime); + + // Report opponent data + //////////////////// + scReportBeginNewPlayer(aReport); + scReportSetPlayerData(aReport, 1, m_remoteConnId, opponentTeam, + opponentGameResult, m_remoteProfile, &m_remoteCertificate, gPlayerData.mStatsAuthdata); + if (!m_disconnect) + scReportAddIntValue(aReport, RACE_TIME, m_remoteTime); + + + // Team data + ///////////////////////////////////////////// + scReportBeginTeamData(aReport); + + // Report your team data + //////////////////////// + scReportBeginNewTeam(aReport); + scReportSetTeamData(aReport, myTeam, myGameResult); + + // Report opponent team data + //////////////////////// + scReportBeginNewTeam(aReport); + scReportSetTeamData(aReport, opponentTeam, opponentGameResult); + + + // End the report and set GameStatus + if (!m_disconnect) + scReportEnd(aReport, SCRACE_AUTHORITATIVE, SCGameStatus_COMPLETE); + else + scReportEnd(aReport, SCRACE_AUTHORITATIVE, SCGameStatus_BROKEN); + + // Submit the Report + ///////////////////////////////////////////// + if (SCResult_NO_ERROR != scSubmitReport(m_interface, aReport, SCRACE_AUTHORITATIVE, &gPlayerData.mCertificate, + &gPlayerData.mPrivateData, submitReportCallback, SCRACE_TIMEOUT_MS, NULL)) + { + MessageBox("Failed to submit Stats Report - Out of memory"); + return; + } + + // To keep the logic clean, wait for submission to finish and then cleanup the report buffer + ///////////////////////////////////////////// + waitForScCallbacks(m_interface, 1); + + m_reportSent = gsi_true; //mark that we've submitted a report for this session + + // Cleanup + ///////////////////////////////////////////// + scDestroyReport(aReport); + aReport = NULL; +} diff --git a/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSampleDlg.h b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSampleDlg.h new file mode 100644 index 00000000000..87a24b5a313 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/ScRaceSampleDlg.h @@ -0,0 +1,135 @@ +// ladderTrackDlg.h : header file +// + +#if !defined(AFX_LADDERTRACKDLG_H__82121F55_1FDB_427A_B616_B59EB16C5E6D__INCLUDED_) +#define AFX_LADDERTRACKDLG_H__82121F55_1FDB_427A_B616_B59EB16C5E6D__INCLUDED_ + +#include "LoginDlg.h" +#include "HostOrJoinDlg.h" +#include "..\..\GT2\gt2.h" // Added by ClassView +#include "..\..\GT2\gt2Encode.h" +#include "WaitingDlg.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CScRaceSampleDlg dialog + +#define LOGGED_OUT 1 +#define SETTING_UP 2 +#define RACING 3 + +#define HOST_LISTENING 11 +#define HOST_CONNECTED 12 +#define HOST_ERROR 13 +#define HOST_EXCHANGE_CERT 14 +#define HOST_VERIFY_CERT 15 +#define HOST_EXCHANGE_KEYS 16 +#define HOST_WAITING 17 +#define HOST_SEND_SESSID 18 + +#define JOIN_CONNECTING 21 +#define JOIN_CONNECTED 22 +#define JOIN_ERROR 23 +#define JOIN_EXCHANGE_CERT 24 +#define JOIN_VERIFY_CERT 25 +#define JOIN_EXCHANGE_KEYS 26 +#define JOIN_WAITING 27 +#define JOIN_SEND_CONNID 28 + + +#define NONE -1 +#define LEFT 0 +#define RIGHT 1 + +#define RACE_STEPS 60 + +extern SamplePlayerData gPlayerData; + +class CScRaceSampleDlg : public CDialog +{ +// Construction +public: + void FakeStats(); + CString m_remoteNick; + DWORD m_remoteTime; + DWORD m_localTime; + int m_totalSteps; + int m_step; + int m_numSteps; + DWORD m_start; + BOOL m_racing; + int m_countdown; + CString m_remoteResponse; + int m_state; + BOOL m_hosting; + CString m_challenge; + + // stats markers + gsi_bool m_win; + gsi_bool m_tie; + gsi_bool m_disconnect; + gsi_bool m_reportSent; + + CLoginDlg m_loginDlg; + CHostOrJoinDlg m_hostOrJoinDlg; + CWaitingDlg m_waitingDlg; + + GT2Socket m_GT2Socket; // raw socket + GT2Connection m_GT2Connection; // established connection + + SCInterfacePtr m_interface; //pointer to the stats interface + int m_remoteProfile; + GSLoginCertificate m_remoteCertificate; + gsi_u8 m_remoteConnId[SC_CONNECTION_GUID_SIZE]; + + + BOOL SetupHosting(); + BOOL SetupJoining(); + BOOL SetupMatch(); + void Countdown(); + void Logout(); + void StartRace(); + void ReportStats(); + CScRaceSampleDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CScRaceSampleDlg) + enum { IDD = IDD_SCRACESAMPLE_DIALOG }; + CButton m_startRace; + CProgressCtrl m_remoteProgress; + CProgressCtrl m_localProgress; + CString m_info; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CScRaceSampleDlg) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + HICON m_hIcon; + + // Generated message map functions + //{{AFX_MSG(CScRaceSampleDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnStart(); + afx_msg void OnDestroy(); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnLogout(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LADDERTRACKDLG_H__82121F55_1FDB_427A_B616_B59EB16C5E6D__INCLUDED_) diff --git a/xrGameSpy/gamespy/sc/scRaceSample/StdAfx.cpp b/xrGameSpy/gamespy/sc/scRaceSample/StdAfx.cpp new file mode 100644 index 00000000000..a891b5d967d --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ScRaceSample.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/sc/scRaceSample/StdAfx.h b/xrGameSpy/gamespy/sc/scRaceSample/StdAfx.h new file mode 100644 index 00000000000..83bff5f8c94 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/StdAfx.h @@ -0,0 +1,32 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__207466EE_5E75_4F57_8FC6_639F9C33B505__INCLUDED_) +#define AFX_STDAFX_H__207466EE_5E75_4F57_8FC6_639F9C33B505__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "../sc.h" +//#include "atlas_Competition_Race_Sample_App_v1.h" // Admin Site generated Header file +#include "atlas_sc_race_v1.h" // Admin Site generated Header file +#include "../../gp/gp.h" + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__207466EE_5E75_4F57_8FC6_639F9C33B505__INCLUDED_) diff --git a/xrGameSpy/gamespy/sc/scRaceSample/WaitingDlg.cpp b/xrGameSpy/gamespy/sc/scRaceSample/WaitingDlg.cpp new file mode 100644 index 00000000000..eb85e08e28a --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/WaitingDlg.cpp @@ -0,0 +1,43 @@ +// WaitingDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "ScRaceSample.h" +#include "WaitingDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg dialog + + +CWaitingDlg::CWaitingDlg(CWnd* pParent /*=NULL*/) + : CDialog(CWaitingDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CWaitingDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CWaitingDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CWaitingDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CWaitingDlg, CDialog) + //{{AFX_MSG_MAP(CWaitingDlg) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg message handlers diff --git a/xrGameSpy/gamespy/sc/scRaceSample/WaitingDlg.h b/xrGameSpy/gamespy/sc/scRaceSample/WaitingDlg.h new file mode 100644 index 00000000000..e5d262bd9cf --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/WaitingDlg.h @@ -0,0 +1,46 @@ +#if !defined(AFX_WAITINGDLG_H__874B6CC6_8058_4BDF_B714_8FE3610A12B4__INCLUDED_) +#define AFX_WAITINGDLG_H__874B6CC6_8058_4BDF_B714_8FE3610A12B4__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// WaitingDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CWaitingDlg dialog + +class CWaitingDlg : public CDialog +{ +// Construction +public: + CWaitingDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CWaitingDlg) + enum { IDD = IDD_WAITING }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CWaitingDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CWaitingDlg) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_WAITINGDLG_H__874B6CC6_8058_4BDF_B714_8FE3610A12B4__INCLUDED_) diff --git a/xrGameSpy/gamespy/sc/scRaceSample/atlas_Competition_Race_Sample_App_v1.h b/xrGameSpy/gamespy/sc/scRaceSample/atlas_Competition_Race_Sample_App_v1.h new file mode 100644 index 00000000000..c15b246afab --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/atlas_Competition_Race_Sample_App_v1.h @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// GameSpy ATLAS Competition System Header File +// +// NOTE: This is an auto-generated file, do not edit this file directly. +/////////////////////////////////////////////////////////////////////////////// + +#define ATLAS_RULE_SET_VERSION 1 + +// KEYS +// Use these key ID's to report match data for your game. + +#define RACE_TIME 1 // Player's race time for the match (milliseconds). + +/////////////////////////////////////////////////////////////////////////////// + +// STATS +// Use these stat ID's to query aggregate statistics for your game. + +#define CAREER_WINS 1 +#define CAREER_LOSSES 2 +#define BEST_RACE_TIME 3 // Player's career best race time (milliseconds). +#define WORST_RACE_TIME 4 // Player's career worst race time (milliseconds). +#define TOTAL_MATCHES 5 +#define AVERAGE_RACE_TIME 6 // Player's average race time per match (milliseconds/match). +#define CURRENT_WIN_STREAK 7 +#define CURRENT_LOSS_STREAK 8 +#define TOTAL_RACE_TIME 9 // Player's total race time for all matches (milliseconds). \ No newline at end of file diff --git a/xrGameSpy/gamespy/sc/scRaceSample/atlas_sc_race_v1.c b/xrGameSpy/gamespy/sc/scRaceSample/atlas_sc_race_v1.c new file mode 100644 index 00000000000..aff4a9e4491 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/atlas_sc_race_v1.c @@ -0,0 +1,130 @@ +/////////////////////////////////////////////////////////////////////////////// +// GameSpy ATLAS Competition System Source File +// +// NOTE: This is an auto-generated file, do not edit this file directly. +/////////////////////////////////////////////////////////////////////////////// + +#include +#include "atlas_sc_race_v1.h" + +int atlas_rule_set_version = 1; + +int ATLAS_GET_KEY(char* keyName) +{ + if(!keyName) + return 0; + + if(!strcmp("RACE_TIME", keyName)) + return RACE_TIME; + + return 0; +} + +char* ATLAS_GET_KEY_NAME(int keyId) +{ + if(keyId <= 0) + return ""; + + if(keyId == RACE_TIME) + return "RACE_TIME"; + + return ""; +} + +int ATLAS_GET_STAT(char* statName) +{ + if(!statName) + return 0; + + if(!strcmp("CAREER_WINS", statName)) + return CAREER_WINS; + else if(!strcmp("CAREER_LOSSES", statName)) + return CAREER_LOSSES; + else if(!strcmp("BEST_RACE_TIME", statName)) + return BEST_RACE_TIME; + else if(!strcmp("WORST_RACE_TIME", statName)) + return WORST_RACE_TIME; + else if(!strcmp("TOTAL_MATCHES", statName)) + return TOTAL_MATCHES; + else if(!strcmp("AVERAGE_RACE_TIME", statName)) + return AVERAGE_RACE_TIME; + else if(!strcmp("CURRENT_WIN_STREAK", statName)) + return CURRENT_WIN_STREAK; + else if(!strcmp("CURRENT_LOSS_STREAK", statName)) + return CURRENT_LOSS_STREAK; + else if(!strcmp("TOTAL_RACE_TIME", statName)) + return TOTAL_RACE_TIME; + else if(!strcmp("CAREER_DISCONNECTS", statName)) + return CAREER_DISCONNECTS; + else if(!strcmp("DISCONNECT_RATE", statName)) + return DISCONNECT_RATE; + else if(!strcmp("CAREER_DRAWS", statName)) + return CAREER_DRAWS; + else if(!strcmp("CURRENT_DRAW_STREAK", statName)) + return CURRENT_DRAW_STREAK; + else if(!strcmp("CAREER_LONGEST_WIN_STREAK", statName)) + return CAREER_LONGEST_WIN_STREAK; + else if(!strcmp("CAREER_LONGEST_LOSS_STREAK", statName)) + return CAREER_LONGEST_LOSS_STREAK; + else if(!strcmp("CAREER_LONGEST_DRAW_STREAK", statName)) + return CAREER_LONGEST_DRAW_STREAK; + else if(!strcmp("TOTAL_COMPLETE_MATCHES", statName)) + return TOTAL_COMPLETE_MATCHES; + else if(!strcmp("RICHARD_TEST1", statName)) + return RICHARD_TEST1; + else if(!strcmp("RICHARD_TEST2", statName)) + return RICHARD_TEST2; + else if(!strcmp("RICHARD_TEST3", statName)) + return RICHARD_TEST3; + + return 0; +} +char* ATLAS_GET_STAT_NAME(int statId) +{ + if(statId <= 0) + return ""; + + if(statId == CAREER_WINS) + return "CAREER_WINS"; + else if(statId == CAREER_LOSSES) + return "CAREER_LOSSES"; + else if(statId == BEST_RACE_TIME) + return "BEST_RACE_TIME"; + else if(statId == WORST_RACE_TIME) + return "WORST_RACE_TIME"; + else if(statId == TOTAL_MATCHES) + return "TOTAL_MATCHES"; + else if(statId == AVERAGE_RACE_TIME) + return "AVERAGE_RACE_TIME"; + else if(statId == CURRENT_WIN_STREAK) + return "CURRENT_WIN_STREAK"; + else if(statId == CURRENT_LOSS_STREAK) + return "CURRENT_LOSS_STREAK"; + else if(statId == TOTAL_RACE_TIME) + return "TOTAL_RACE_TIME"; + else if(statId == CAREER_DISCONNECTS) + return "CAREER_DISCONNECTS"; + else if(statId == DISCONNECT_RATE) + return "DISCONNECT_RATE"; + else if(statId == CAREER_DRAWS) + return "CAREER_DRAWS"; + else if(statId == CURRENT_DRAW_STREAK) + return "CURRENT_DRAW_STREAK"; + else if(statId == CAREER_LONGEST_WIN_STREAK) + return "CAREER_LONGEST_WIN_STREAK"; + else if(statId == CAREER_LONGEST_LOSS_STREAK) + return "CAREER_LONGEST_LOSS_STREAK"; + else if(statId == CAREER_LONGEST_DRAW_STREAK) + return "CAREER_LONGEST_DRAW_STREAK"; + else if(statId == TOTAL_COMPLETE_MATCHES) + return "TOTAL_COMPLETE_MATCHES"; + else if(statId == RICHARD_TEST1) + return "RICHARD_TEST1"; + else if(statId == RICHARD_TEST2) + return "RICHARD_TEST2"; + else if(statId == RICHARD_TEST3) + return "RICHARD_TEST3"; + + return ""; +} + diff --git a/xrGameSpy/gamespy/sc/scRaceSample/atlas_sc_race_v1.h b/xrGameSpy/gamespy/sc/scRaceSample/atlas_sc_race_v1.h new file mode 100644 index 00000000000..03346d1df22 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/atlas_sc_race_v1.h @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////// +// GameSpy ATLAS Competition System Header File +// +// NOTE: This is an auto-generated file, do not edit this file directly. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _ATLAS_SC_RACE_V1_H_ +#define _ATLAS_SC_RACE_V1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ATLAS_GET_KEY(char* keyName); +extern char* ATLAS_GET_KEY_NAME(int keyId); +extern int ATLAS_GET_STAT(char* statName); +extern char* ATLAS_GET_STAT_NAME(int statId); + +#define ATLAS_RULE_SET_VERSION 1 + +// KEYS +// Use these key ID's to report match data for your game. + +#define RACE_TIME 1 // [TYPE: int] [DESC: Player's race time for the match (milliseconds).] + +/////////////////////////////////////////////////////////////////////////////// + +// STATS +// Use these stat ID's to query aggregate statistics for your game. + +#define CAREER_WINS 1 // [TYPE: int] +#define CAREER_LOSSES 2 // [TYPE: int] +#define BEST_RACE_TIME 3 // [TYPE: int] [DESC: Player's career best race time (milliseconds).] +#define WORST_RACE_TIME 4 // [TYPE: int] [DESC: Player's career worst race time (milliseconds).] +#define TOTAL_MATCHES 5 // [TYPE: int] +#define AVERAGE_RACE_TIME 6 // [TYPE: float] [DESC: Player's average race time per match (milliseconds/match).] +#define CURRENT_WIN_STREAK 7 // [TYPE: int] +#define CURRENT_LOSS_STREAK 8 // [TYPE: int] +#define TOTAL_RACE_TIME 9 // [TYPE: int] [DESC: Player's total race time for all matches (milliseconds).] +#define CAREER_DISCONNECTS 11 // [TYPE: int] [DESC: Player's total number of times disconnected.] +#define DISCONNECT_RATE 12 // [TYPE: float] [DESC: Player's disconnect rate (disconnects/matches).] +#define CAREER_DRAWS 13 // [TYPE: int] [DESC: Player's total number of draws (tied matches).] +#define CURRENT_DRAW_STREAK 14 // [TYPE: int] +#define CAREER_LONGEST_WIN_STREAK 15 // [TYPE: int] +#define CAREER_LONGEST_LOSS_STREAK 16 // [TYPE: int] +#define CAREER_LONGEST_DRAW_STREAK 17 // [TYPE: int] +#define TOTAL_COMPLETE_MATCHES 18 // [TYPE: int] [DESC: Total number of matches where the game went to completion (all win/loss/draw results).] +#define RICHARD_TEST1 19 // [TYPE: int] +#define RICHARD_TEST2 20 // [TYPE: int] +#define RICHARD_TEST3 21 // [TYPE: int] + + +#ifdef __cplusplus +} +#endif + +#endif // _ATLAS_SC_RACE_V1_H_ diff --git a/xrGameSpy/gamespy/sc/scRaceSample/res/ScRaceSample.ico b/xrGameSpy/gamespy/sc/scRaceSample/res/ScRaceSample.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/sc/scRaceSample/res/ScRaceSample.ico differ diff --git a/xrGameSpy/gamespy/sc/scRaceSample/res/ScRaceSample.rc2 b/xrGameSpy/gamespy/sc/scRaceSample/res/ScRaceSample.rc2 new file mode 100644 index 00000000000..746d0bdbee0 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/res/ScRaceSample.rc2 @@ -0,0 +1,13 @@ +// +// SCRACESAMPLE.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/sc/scRaceSample/resource.h b/xrGameSpy/gamespy/sc/scRaceSample/resource.h new file mode 100644 index 00000000000..5c15d825728 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/resource.h @@ -0,0 +1,34 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ScRaceSample.rc +// +#define IDD_SCRACESAMPLE_DIALOG 102 +#define IDC_EMAIL 103 +#define IDC_NICK 104 +#define IDC_PASSWORD 105 +#define IDR_MAINFRAME 128 +#define IDD_LOGIN 129 +#define IDD_HOST_OR_JOIN 130 +#define IDD_WAITING 132 +#define IDC_HOST 1000 +#define IDC_LOCAL_POSITION 1000 +#define IDC_JOIN 1001 +#define IDC_REMOTE_POSITION 1001 +#define IDC_JOIN_ADDRESS 1002 +#define IDC_LOGOUT 1004 +#define IDC_START_RACE 1005 +#define IDC_INFO 1006 +#define IDC_LOCAL_PROGRESS 1007 +#define IDC_REMOTE_PROGRESS 1008 +#define IDC_UPDATE_POSITIONS 1009 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample.dsp b/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample.dsp new file mode 100644 index 00000000000..254fd4ca7ec --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample.dsp @@ -0,0 +1,737 @@ +# Microsoft Developer Studio Project File - Name="ScRaceSample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ScRaceSample - Win32 Release +!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 "scRaceSample.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 "scRaceSample.mak" CFG="ScRaceSample - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ScRaceSample - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ScRaceSample - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/sc/ScRaceSample", YNHCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ScRaceSample - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ScRaceSample - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "RECV_LOG" /D "GSI_COMMON_DEBUG" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ScRaceSample - Win32 Release" +# Name "ScRaceSample - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\HostOrJoinDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\LoginDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\ScRaceSample.cpp +# End Source File +# Begin Source File + +SOURCE=.\ScRaceSample.rc +# End Source File +# Begin Source File + +SOURCE=.\ScRaceSampleDlg.cpp + +!IF "$(CFG)" == "ScRaceSample - Win32 Release" + +!ELSEIF "$(CFG)" == "ScRaceSample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\WaitingDlg.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\atlas_Competition_Race_Sample_App_v1.h +# End Source File +# Begin Source File + +SOURCE=.\HostOrJoinDlg.h +# End Source File +# Begin Source File + +SOURCE=.\LoginDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\ScRaceSample.h +# End Source File +# Begin Source File + +SOURCE=.\ScRaceSampleDlg.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\WaitingDlg.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\ScRaceSample.ico +# End Source File +# Begin Source File + +SOURCE=.\res\ScRaceSample.rc2 +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsUdpEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "PresenceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gp\gp.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gp.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpi.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuddy.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiConnect.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiOperation.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiPeer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiProfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiSearch.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiTransfer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\GP\gpiUnique.h +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gp\gpiUtility.h +# End Source File +# End Group +# Begin Group "HttpSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "TransportSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\gt2\gt2.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Auth.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Connection.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Encode.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Main.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Message.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Socket.h +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\gt2\gt2Utility.h +# End Source File +# End Group +# Begin Group "CompetitionSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc.h +# End Source File +# Begin Source File + +SOURCE=..\sci.h +# End Source File +# Begin Source File + +SOURCE=..\sciInterface.c +# End Source File +# Begin Source File + +SOURCE=..\sciInterface.h +# End Source File +# Begin Source File + +SOURCE=..\sciMain.c +# End Source File +# Begin Source File + +SOURCE=..\sciReport.c +# End Source File +# Begin Source File + +SOURCE=..\sciReport.h +# End Source File +# Begin Source File + +SOURCE=..\sciSerialize.c +# End Source File +# Begin Source File + +SOURCE=..\sciSerialize.h +# End Source File +# Begin Source File + +SOURCE=..\sciWebServices.c +# End Source File +# Begin Source File + +SOURCE=..\sciWebServices.h +# End Source File +# End Group +# Begin Group "AuthServiceSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\webservices\AuthService.c +# End Source File +# Begin Source File + +SOURCE=..\..\webservices\AuthService.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample_vs2005.vcproj b/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample_vs2005.vcproj new file mode 100644 index 00000000000..d726460ca45 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample_vs2005.vcproj @@ -0,0 +1,1863 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/sc/scRaceSample/scRaceSample_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/sc/sc_vs2005.sln b/xrGameSpy/gamespy/sc/sc_vs2005.sln new file mode 100644 index 00000000000..d5db9d7e08b --- /dev/null +++ b/xrGameSpy/gamespy/sc/sc_vs2005.sln @@ -0,0 +1,81 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sctest_vs2005", "sctest\sctest_vs2005.vcproj", "{86C8BA16-7AD5-4366-ABFE-0F319E299A04}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScRaceSample_vs2005", "scRaceSample\scRaceSample_vs2005.vcproj", "{CE7A165A-399F-4B16-A590-16FC58166A2D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sctestmatchless_vs2005", "sctestmatchless\sctestmatchless_vs2005.vcproj", "{2039A6BF-58A8-4142-BEC1-D37D44CF3173}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4BB71178-8B8D-4B5F-962C-62C6DD0C9081}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(SolutionItems) = preProject + changelog.txt = changelog.txt + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = sctest\\sctest_vs2005.vcproj + SccProjectName1 = sctest + SccLocalPath1 = sctest + SccProjectUniqueName2 = scRaceSample\\scRaceSample_vs2005.vcproj + SccProjectName2 = scRaceSample + SccLocalPath2 = scRaceSample + SccProjectUniqueName3 = sctestmatchless\\sctestmatchless_vs2005.vcproj + SccProjectName3 = sctestmatchless + SccLocalPath3 = sctestmatchless + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Debug|Win32.ActiveCfg = Debug|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Debug|Win32.Build.0 = Debug|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Release|Win32.ActiveCfg = Release|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Release|Win32.Build.0 = Release|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {86C8BA16-7AD5-4366-ABFE-0F319E299A04}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Debug|Win32.ActiveCfg = Debug|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Debug|Win32.Build.0 = Debug|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Release|Win32.ActiveCfg = Release|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Release|Win32.Build.0 = Release|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {CE7A165A-399F-4B16-A590-16FC58166A2D}.Unicode Release|Win32.Build.0 = Release|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Debug|Win32.ActiveCfg = Debug|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Debug|Win32.Build.0 = Debug|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Release|Win32.ActiveCfg = Release|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Release|Win32.Build.0 = Release|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {2039A6BF-58A8-4142-BEC1-D37D44CF3173}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sc_vs2005.vssscc b/xrGameSpy/gamespy/sc/sc_vs2005.vssscc new file mode 100644 index 00000000000..6cb031bcf51 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sc_vs2005.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/sc/sci.h b/xrGameSpy/gamespy/sc/sci.h new file mode 100644 index 00000000000..db81d9d00f7 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sci.h @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SCI_H__ +#define __SCI_H__ + +/* Internal interface for S&C SDK -- Developers should use sc.h */ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sc.h" + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Data types + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SCI_H__ diff --git a/xrGameSpy/gamespy/sc/sciInterface.c b/xrGameSpy/gamespy/sc/sciInterface.c new file mode 100644 index 00000000000..1bf05252f68 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciInterface.c @@ -0,0 +1,132 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sciInterface.h" + + +/* PRIVATE INTERFACE FUNCTIONS -- SCMAIN.C CONTAINS PUBLIC INTERFACE */ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// This is declared as an extern so it can be overriden when testing +#define SC_SERVICE_URL_FORMAT "http://%s.comp.pubsvs." GSI_DOMAIN_NAME "/CompetitionService/CompetitionService.asmx" +char scServiceURL[SC_SERVICE_MAX_URL_LEN] = ""; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciInterfaceCreate(SCInterface** theInterfaceOut) +{ +#ifdef GSI_SC_STATIC_MEM + static SCInterface gStaticInterface; +#endif + + GS_ASSERT(theInterfaceOut != NULL); + + // Check to see if the availability check has been performed and if it has + // set the service URL prepended with the gamename + if (__GSIACResult == GSIACAvailable) + { + if (scServiceURL[0] == '\0') + snprintf(scServiceURL, SC_SERVICE_MAX_URL_LEN, SC_SERVICE_URL_FORMAT, __GSIACGamename); + } + else + return SCResult_NO_AVAILABILITY_CHECK; + +#ifdef GSI_SC_STATIC_MEM + *theInterfaceOut = &gStaticInterface; +#else + *theInterfaceOut = (SCInterface*)gsimalloc(sizeof(SCInterface)); + if (*theInterfaceOut == NULL) + { + return SCResult_OUT_OF_MEMORY; + } +#endif + + GS_ASSERT(*theInterfaceOut != NULL); + memset(*theInterfaceOut, 0, sizeof(SCInterface)); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciInterfaceInit(SCInterface* theInterface) +{ + SCResult anInitResult = SCResult_NO_ERROR; + + GS_ASSERT(theInterface != NULL); + + anInitResult = sciWsInit(&theInterface->mWebServices, theInterface); + if (anInitResult != SCResult_NO_ERROR) + { + return anInitResult; + } + + memset(theInterface->mSessionId, 0, sizeof(theInterface->mSessionId)); + memset(theInterface->mConnectionId, 0, sizeof(theInterface->mConnectionId)); + + theInterface->mInit = gsi_true; + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciInterfaceDestroy(SCInterface* theInterface) +{ + GS_ASSERT(theInterface != NULL); + GS_ASSERT(theInterface->mInit); + + sciWsDestroy(&theInterface->mWebServices); + + memset(theInterface->mSessionId, 0, sizeof(theInterface->mSessionId)); + memset(theInterface->mConnectionId, 0, sizeof(theInterface->mConnectionId)); + theInterface->mSessionId[0] = 0xde; + theInterface->mSessionId[1] = 0xad; + theInterface->mConnectionId[0] = 0xde; + theInterface->mConnectionId[1] = 0xad; + + theInterface->mInit = gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciInterfaceSetSessionId(SCInterface * theInterface, const char * theSessionId) +{ + GS_ASSERT(theInterface != NULL); + + if (theSessionId == NULL) + theInterface->mSessionId[0] = '\0'; + else + { + GS_ASSERT(strlen(theSessionId) < sizeof(theInterface->mSessionId)); + strcpy((char *)theInterface->mSessionId, theSessionId); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciInterfaceSetConnectionId(SCInterface * theInterface, const char * theConnectionId) +{ + GS_ASSERT(theInterface != NULL); + + if (theConnectionId == NULL) + theInterface->mConnectionId[0] = '\0'; + else + { + GS_ASSERT(strlen(theConnectionId) < sizeof(theInterface->mConnectionId)); + strcpy((char *)theInterface->mConnectionId, theConnectionId); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/sc/sciInterface.h b/xrGameSpy/gamespy/sc/sciInterface.h new file mode 100644 index 00000000000..eb2562e33e8 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciInterface.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SCIINTERFACE_H__ +#define __SCIINTERFACE_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sci.h" +#include "sciWebServices.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// SDK instance +typedef struct +{ + SCWebServices mWebServices; + gsi_u32 mGameId; + //gsi_u32 mOptionsFlags; + gsi_bool mInit; + const char * mServiceURL; + GSCoreMgr * mSdkCore; + gsi_u8 mSessionId[SC_SESSION_GUID_SIZE]; + gsi_u8 mConnectionId[SC_CONNECTION_GUID_SIZE]; +} SCInterface; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciInterfaceCreate (SCInterface** theInterfaceOut); +SCResult sciInterfaceInit (SCInterface* theInterface); +void sciInterfaceDestroy(SCInterface* theInterface); + +void sciInterfaceSetSessionId(SCInterface* theInterface, const char * theSessionId); +void sciInterfaceSetConnectionId(SCInterface* theInterface, const char * theConnectionId); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SCINTERFACE_H__ diff --git a/xrGameSpy/gamespy/sc/sciMain.c b/xrGameSpy/gamespy/sc/sciMain.c new file mode 100644 index 00000000000..19ec53edd4b --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciMain.c @@ -0,0 +1,706 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sci.h" +#include "sciInterface.h" +#include "sciReport.h" + +#include "../md5.h" +#include "../common/gsRC4.h" + +/* PUBLIC INTERFACE FUNCTIONS - SCINTERFACE.C CONTAINS PRIVATE INTERFACE */ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scInitialize(int theGameId, SCInterfacePtr* theInterfaceOut) +{ + SCInterface* anInterface = NULL; + SCResult anInitResult = SCResult_NO_ERROR; + + // Check parameters + if (theInterfaceOut == NULL) + { + return SCResult_INVALID_PARAMETERS; + } + + // Clear out parameter + *theInterfaceOut = NULL; + + // Obtain the internal interface + anInitResult = sciInterfaceCreate(&anInterface); + if (anInitResult != SCResult_NO_ERROR) + { + return anInitResult; + } + + // Init the internal interface + anInitResult = sciInterfaceInit(anInterface); + if (anInitResult != SCResult_NO_ERROR) + { + return anInitResult; + } + + anInterface->mGameId = (gsi_u32)theGameId; + //anInterface->mOptionsFlags = (gsi_u32)theOptionsFlags; + + // Set the out parameter and return + *theInterfaceOut = anInterface; + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scShutdown(SCInterfacePtr theInterface) +{ + SCInterface* anInterface = (SCInterface*)theInterface; + + // Check parameters + if (anInterface == NULL) + { + return SCResult_INVALID_PARAMETERS; + } + + // Destroy interface if necessary + if (anInterface->mInit) + { + sciInterfaceDestroy(anInterface); + gsifree(anInterface); + } + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scThink(SCInterfacePtr theInterface) +{ + SCInterface* anInterface = (SCInterface*)theInterface; + + // Check parameters + if (anInterface == NULL) + { + return SCResult_INVALID_PARAMETERS; + } + if (!anInterface->mInit) + { + return SCResult_NOT_INITIALIZED; + } + + sciWsThink(&anInterface->mWebServices); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +const char * scGetSessionId(const SCInterfacePtr theInterface) +{ + SCInterface * anInterface = (SCInterface*)theInterface; + GS_ASSERT(theInterface != NULL); + GS_ASSERT(gsi_is_true(anInterface->mInit)); + return (char *)anInterface->mSessionId; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +const char * scGetConnectionId(const SCInterfacePtr theInterface) +{ + SCInterface * anInterface = (SCInterface*)theInterface; + GS_ASSERT(theInterface != NULL); + GS_ASSERT(gsi_is_true(anInterface->mInit)); + return (char *)anInterface->mConnectionId; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scSetSessionId(const SCInterfacePtr theInterface, const gsi_u8 theSessionId[SC_SESSION_GUID_SIZE]) +{ + SCInterface * anInterface = (SCInterface*)theInterface; + GS_ASSERT(theInterface != NULL); + GS_ASSERT(gsi_is_true(anInterface->mInit)); + + sciInterfaceSetSessionId(anInterface, (char *)theSessionId); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// The certificate and private data may be NULL if the local client +// is an unauthenticated dedicated server +SCResult SC_CALL scCreateSession(SCInterfacePtr theInterface, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + SCInterface * anInterface = (SCInterface*)theInterface; + GS_ASSERT(theInterface != NULL); + GS_ASSERT(theCertificate != NULL || (theCertificate==NULL && thePrivateData==NULL)); + + if (!wsLoginCertIsValid(theCertificate)) + return SCResult_INVALID_PARAMETERS; + + return sciWsCreateSession(&anInterface->mWebServices, anInterface->mGameId, theCertificate, thePrivateData, theCallback, theTimeoutMs, theUserData); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scCreateMatchlessSession(SCInterfacePtr theInterface, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + SCInterface * anInterface = (SCInterface*)theInterface; + GS_ASSERT(theInterface != NULL); + GS_ASSERT(theCertificate != NULL || (theCertificate==NULL && thePrivateData==NULL)); + + if (!wsLoginCertIsValid(theCertificate)) + return SCResult_INVALID_PARAMETERS; + + return sciWsCreateMatchlessSession(&anInterface->mWebServices, anInterface->mGameId, theCertificate, thePrivateData, theCallback, theTimeoutMs, theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/* +SCResult SC_CALL scJoinSession(SCInterfacePtr theInterface, + GSLoginCertificate * theCertificate, + GSLoginPrivateData * thePrivateData, + gsi_u8 theSessionId[SC_SESSION_GUID_SIZE], + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs) +{ + SCInterface * anInterface = (SCInterface*)theInterface; + GS_ASSERT(theInterface != NULL); + + memcpy(anInterface->mSessionId, theSessionId, SC_SESSION_GUID_SIZE); + return SCResult_NO_ERROR; +}*/ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scSetReportIntention(const SCInterfacePtr theInterface, + const gsi_u8 theConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + SCInterface* anInterface = (SCInterface*)theInterface; + + // Check parameters + if (anInterface == NULL) + { + return SCResult_INVALID_PARAMETERS; + } + if (!theCertificate) + { + return SCResult_INVALID_PARAMETERS; + } + if (!thePrivateData) + { + return SCResult_INVALID_PARAMETERS; + } + if (!anInterface->mInit) + { + return SCResult_NOT_INITIALIZED; + } + + sciInterfaceSetConnectionId(anInterface, (const char *)theConnectionId); + // Call web service + return sciWsSetReportIntention(&anInterface->mWebServices, anInterface->mGameId, + (char *)anInterface->mSessionId, (char *)anInterface->mConnectionId, isAuthoritative, + theCertificate, thePrivateData, theCallback, theTimeoutMs, theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scSubmitReport(const SCInterfacePtr theInterface, + const SCReportPtr theReport, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSubmitReportCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + SCInterface* anInterface = (SCInterface*)theInterface; + SCIReport *aReport = (SCIReport *)theReport; + //SCResult aResult = SCResult_NO_ERROR; + + // Check parameters + if (anInterface == NULL) + { + return SCResult_INVALID_PARAMETERS; + } + if (!anInterface->mInit) + { + return SCResult_NOT_INITIALIZED; + } + + // Generate report from report data + // aResult = sciGenerateReport(theReportData, theProfileID, &aReport); + //if (aResult != SCResult_NO_ERROR) + // return aResult; + + // Prepare the report hash + { + SCIReportHeader * header = (SCIReportHeader*)aReport->mBuffer.mData; + MD5_CTX md5; + // Clear out the checksum portion of the header so that the + // MD5 hash is calculated on the entire report without a checksum + memset(header->mChecksum, 0, sizeof(header->mChecksum)); + + MD5Init(&md5); + MD5Update(&md5, (unsigned char *)aReport->mBuffer.mData, aReport->mBuffer.mPos); + MD5Final(header->mChecksum, &md5); + } + + // Call web service + return sciWsSubmitReport(&anInterface->mWebServices, anInterface->mGameId, + (char *)anInterface->mSessionId, (char *)anInterface->mConnectionId, aReport, isAuthoritative, + theCertificate, thePrivateData, theCallback, theTimeoutMs, theUserData); + +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scCreateReport(const SCInterfacePtr theInterface, + gsi_u32 theHeaderVersion, + gsi_u32 thePlayerCount, + gsi_u32 theTeamCount, + SCReportPtr * theReportDataOut) +{ + SCResult aResult = SCResult_NO_ERROR; + SCIReport * aReport = NULL; + SCInterface * aInterface = (SCInterface*)theInterface; + + GS_ASSERT(theInterface != NULL); + GS_ASSERT(theReportDataOut != NULL); + if (theInterface == NULL) + return SCResult_INVALID_PARAMETERS; + if (theReportDataOut == NULL) + return SCResult_INVALID_PARAMETERS; + + aResult = sciCreateReport(aInterface->mSessionId, theHeaderVersion, + thePlayerCount, theTeamCount, &aReport); + if (aResult == SCResult_NO_ERROR) + *theReportDataOut = (SCReportPtr)aReport; + + return aResult; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportBeginGlobalData(SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + + return sciReportBeginGlobalData(aReport); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportBeginPlayerData(SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + + return sciReportBeginPlayerData(aReport); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportBeginTeamData(SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + + return sciReportBeginTeamData(aReport); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportBeginNewTeam(SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + //return SCResult_NO_ERROR; + return sciReportBeginNewTeam(aReport); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportBeginNewPlayer(SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + //return SCResult_NO_ERROR; + return sciReportBeginNewPlayer(aReport); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportEnd(SCReportPtr theReport, gsi_bool isAuth, SCGameStatus theStatus) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + + return sciReportEnd(aReport, isAuth, theStatus); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportSetPlayerData(SCReportPtr theReport, + gsi_u32 thePlayerIndex, + const gsi_u8 thePlayerConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_u32 thePlayerTeamId, + SCGameResult theResult, + gsi_u32 theProfileId, + const GSLoginCertificate * theCertificate, + const gsi_u8 theAuthHash[16]) +{ + SCIReport * aReport = NULL; + SCResult aResult = SCResult_NO_ERROR; + gsi_u32 i; + gsi_bool isNewTeam = gsi_true; + + GS_ASSERT(theReport != NULL); + GS_ASSERT(theCertificate != NULL); + GSI_UNUSED(theProfileId); + aReport = (SCIReport*)theReport; + + // store the team ID here and use this in order to index the team game results + for (i=0; imNumTeamsReported; i++) + { + // has the team already been reported by another player? + if (aReport->mTeamIds[i] == thePlayerTeamId) + { + isNewTeam = gsi_false; + break; + } + } + + if (isNewTeam) + { + aReport->mNumTeamsReported++; + + // have they gone over the limit of teams? If so, this is an error + GS_ASSERT(aReport->mNumTeamsReported < SC_MAX_NUM_TEAMS); + if (aReport->mNumTeamsReported > SC_MAX_NUM_TEAMS) + return SCResult_OUT_OF_MEMORY; + + // if no problems, store the teamId + aReport->mTeamIds[aReport->mNumTeamsReported-1] = thePlayerTeamId; + } + + + if (aResult == SCResult_NO_ERROR) aResult = sciReportSetPlayerConnectionId(aReport, thePlayerIndex, thePlayerConnectionId); + if (aResult == SCResult_NO_ERROR) aResult = sciReportSetPlayerTeamIndex (aReport, thePlayerIndex, thePlayerTeamId); + if (aResult == SCResult_NO_ERROR) aResult = sciReportSetPlayerGameResult (aReport, thePlayerIndex, theResult); + if (aResult == SCResult_NO_ERROR) aResult = sciReportSetPlayerAuthInfo (aReport, thePlayerIndex, theCertificate, theAuthHash); + + return aResult; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportSetTeamData(const SCReportPtr theReport, + gsi_u32 theTeamId, + SCGameResult theResult) +{ + SCIReport * aReport = NULL; + gsi_u32 i; + gsi_i32 aTeamIndex = -1; + GS_ASSERT(theReport != NULL); + GS_ASSERT(theResult < SCGameResultMax); + + aReport = (SCIReport*)theReport; + + // redundancy check - have they gone over the max limit of teams? + GS_ASSERT(aReport->mNumTeamsReported < SC_MAX_NUM_TEAMS); + + // find the proper team index based on the teamId + for (i=0; imNumTeamsReported; i++) + { + if (aReport->mTeamIds[i] == theTeamId) + { + aTeamIndex = (gsi_i32)i; + break; + } + } + + // if no such team exists in our list, an invalid ID was given + if (aTeamIndex == -1) + return SCResult_INVALID_PARAMETERS; + + // the teamindex reported here needs to be 0 based, which is why we subtract 1 + return sciReportSetTeamGameResult(aReport, (gsi_u32)aTeamIndex, theResult); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportSetAsMatchless(const SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + return(sciReportSetAsMatchless(aReport)); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportAddIntValue(const SCReportPtr theReport, + gsi_u16 theKeyId, + gsi_i32 theValue) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + return sciReportAddIntValue(aReport, theKeyId, theValue); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportAddInt64Value(SCReportPtr theReport, + gsi_u16 theKeyId, + gsi_i64 theValue) +{ + SCIReport *aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport *)theReport; + return sciReportAddInt64Value(aReport, theKeyId, theValue); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportAddShortValue(const SCReportPtr theReport, + gsi_u16 theKeyId, + gsi_i16 theValue) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + return sciReportAddShortValue(aReport, theKeyId, theValue); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportAddByteValue(const SCReportPtr theReport, + gsi_u16 theKeyId, + gsi_i8 theValue) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + return sciReportAddByteValue(aReport, theKeyId, theValue); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportAddFloatValue(const SCReportPtr theReport, + gsi_u16 theKeyId, + float theValue) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + return sciReportAddFloatValue(aReport, theKeyId, theValue); + +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scReportAddStringValue(const SCReportPtr theReport, + gsi_u16 theKeyId, + const gsi_char * theValue) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + GS_ASSERT(theValue != NULL); + aReport = (SCIReport*)theReport; + return sciReportAddStringValue(aReport, theKeyId, theValue); + +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scDestroyReport(SCReportPtr theReport) +{ + SCIReport * aReport = NULL; + GS_ASSERT(theReport != NULL); + aReport = (SCIReport*)theReport; + + return sciDestroyReport(aReport); +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Create a random key for this cipher +SCResult SC_CALL scPeerCipherInit(const GSLoginCertificate * theLocalCert, SCPeerCipher * theCipher) +{ + // hardcoded to a 256-bit key block, although some ciphers will not use the entire block + + // What to use for a random seed? + // 1) 16 bytes from our Util_Rand seeded with current time + // 2) Hashed with 16 bytes from the cert public key (for a little extra randomness) + // 3) Repeat 1-2 for every 16 bytes of key block needed + unsigned char randBytes[32]; + int i=0; + MD5_CTX md5; + + GS_ASSERT(theCipher != NULL); + //CANNOT assert on constant expressions, they are meaningless. + //GS_ASSERT(GS_CRYPT_RSA_BYTE_SIZE >= 32); // crypt lib must support 128-bit keys. + + #if defined (GS_CRYPT_NO_RANDOM) + Util_RandSeed(0x2d2d2d2d); + #else + Util_RandSeed(current_time()); + #endif + + for (i=0; i < 32; i++) + randBytes[i] = (unsigned char)Util_RandInt(0x00, 0xFF); + + // Calc the first half, bytes 0-15 + MD5Init(&md5); + MD5Update(&md5, randBytes, 16); + MD5Update(&md5, (unsigned char*)theLocalCert->mPeerPublicKey.modulus.mData, 16); // first 16 bytes of the key + MD5Final(&theCipher->mKey[0], &md5); + + // Calc the second half, bytes 16-31 + MD5Init(&md5); + MD5Update(&md5, &randBytes[16], 16); + MD5Update(&md5, (unsigned char*)&theLocalCert->mPeerPublicKey.modulus.mData[16], 16); // last 16 bytes of the key + MD5Final(&theCipher->mKey[16], &md5); + + theCipher->mKeyLen = 32; + + RC4Init(&theCipher->mRC4, theCipher->mKey, (int)theCipher->mKeyLen); + theCipher->mInitialized = gsi_true; + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, "Created PeerCipher key block\r\n"); + gsDebugBinary(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, (char *)theCipher->mKey, (gsi_i32)theCipher->mKeyLen); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scPeerCipherCreateKeyExchangeMsg(const GSLoginCertificate * theRemoteCert, const SCPeerCipher * theCipher, SCPeerKeyExchangeMsg theMsgOut) +{ + // Encrypt the key with the recipients public key, this makes it safe to transmit + if (0 == gsCryptRSAEncryptBuffer(&theRemoteCert->mPeerPublicKey, theCipher->mKey, theCipher->mKeyLen, (unsigned char *)theMsgOut)) + return SCResult_NO_ERROR; + else + return SCResult_UNKNOWN_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scPeerCipherParseKeyExchangeMsg (const GSLoginCertificate * theLocalCert, const GSLoginPrivateData * theCertPrivateData, const SCPeerKeyExchangeMsg theMsg, SCPeerCipher * theCipherOut) +{ + GSI_UNUSED(theLocalCert); + // Decrypt the key with the local player's private key + if (0 == gsCryptRSADecryptBuffer(&theCertPrivateData->mPeerPrivateKey, (unsigned char *)theMsg, theCipherOut->mKey, &theCipherOut->mKeyLen)) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, "Decrypted PeerCipher key block\r\n"); + gsDebugBinary(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, (char *)theCipherOut->mKey, (gsi_i32)theCipherOut->mKeyLen); + RC4Init(&theCipherOut->mRC4, theCipherOut->mKey, (int)theCipherOut->mKeyLen); + theCipherOut->mInitialized = gsi_true; + return SCResult_NO_ERROR; + } + else + return SCResult_UNKNOWN_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scPeerCipherEncryptBufferIV(SCPeerCipher * theCipher, gsi_u32 theMessageNum, gsi_u8 * theData, gsi_u32 theLen) +{ + RC4Context rc4; + MD5_CTX md5; + char tempHash[16]; + + GS_ASSERT(gsi_is_true(theCipher->mInitialized)); + + // Construct a new key for this message + // - Using the same key for all messages would be extremely unsafe + MD5Init(&md5); + MD5Update(&md5, theCipher->mKey, theCipher->mKeyLen); + MD5Update(&md5, (unsigned char*)&theMessageNum, sizeof(theMessageNum)); + MD5Final((unsigned char *)tempHash, &md5); + + RC4Init(&rc4, (unsigned char *)tempHash, GS_CRYPT_MD5_HASHSIZE); + RC4Encrypt(&rc4, (const unsigned char*)theData, theData, (int)theLen); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scPeerCipherDecryptBufferIV(SCPeerCipher * theCipher, gsi_u32 theMessageNum, gsi_u8 * theData, gsi_u32 theLen) +{ + return scPeerCipherEncryptBufferIV(theCipher, theMessageNum, theData, theLen); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scPeerCipherEncryptBuffer(SCPeerCipher * theCipher, gsi_u8 * theData, gsi_u32 theLen) +{ + // Encrypt the data using the RC4 context + GS_ASSERT(gsi_is_true(theCipher->mInitialized)); + RC4Encrypt(&theCipher->mRC4, (const unsigned char*)theData, theData, (int)theLen); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL scPeerCipherDecryptBuffer(SCPeerCipher * theCipher, gsi_u8 * theData, gsi_u32 theLen) +{ + return scPeerCipherEncryptBuffer(theCipher, theData, theLen); +} diff --git a/xrGameSpy/gamespy/sc/sciReport.c b/xrGameSpy/gamespy/sc/sciReport.c new file mode 100644 index 00000000000..6c63fca93b2 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciReport.c @@ -0,0 +1,874 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sciReport.h" +#include "sciSerialize.h" +#include "../md5.h" + +#pragma warning(disable: 4267) + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciCreateReport(gsi_u8 theSessionGuid[SC_SESSION_GUID_SIZE], + gsi_u32 theHeaderVersion, + gsi_u32 thePlayerCount, + gsi_u32 theTeamCount, + SCIReport ** theReportOut) +{ + SCIReport * theNewReport; + SCIReportHeader * theReportHeader; + gsi_u8 * theReportData; + + // roster is [CCID (16) + TeamIndex (4)] * numplayers + const gsi_u32 theRosterSize = SC_GUID_BINARY_SIZE * thePlayerCount + + SC_REPORT_TEAMINDEX_LENGTH * thePlayerCount; + + GS_ASSERT(theReportOut != NULL); + + // allocate the report + //GS_ASSERT(0); // todo: memalignment + theNewReport = (SCIReport*)gsimalloc(sizeof(SCIReport)); + if (theNewReport == NULL) + return SCResult_OUT_OF_MEMORY; + memset(theNewReport, 0, sizeof(SCIReport)); + + // allocate the report buffer (holds submission data) + theReportData = (gsi_u8*)gsimalloc(SC_REPORT_BUFFER_BYTES); + if (theReportData == NULL) + { + gsifree(theNewReport); + return SCResult_OUT_OF_MEMORY; + } + memset(theReportData, 0, SC_REPORT_BUFFER_BYTES); + theNewReport->mBuffer.mIsStatic = gsi_false; + theNewReport->mBuffer.mCapacity = SC_REPORT_BUFFER_BYTES; + + // Fill in report header + theReportHeader = (SCIReportHeader*)theReportData; + memset(theReportHeader, 0, sizeof(SCIReportHeader)); + + theReportHeader->mProtocolVersion = htonl(SC_REPORT_PROTOCOL); + theReportHeader->mDeveloperVersion = htonl(theHeaderVersion); + + theReportHeader->mRosterSectionLength = theRosterSize; + theReportHeader->mAuthSectionLength = SC_REPORT_AUTHDATA_LENGTH * thePlayerCount; + theReportHeader->mResultsSectionLength = SC_REPORT_ENTITYRESULT_LENGTH * (thePlayerCount + theTeamCount); + theReportHeader->mPlayerCount = (gsi_u16)thePlayerCount; + theReportHeader->mTeamCount = (gsi_u16)theTeamCount; + //theReportHeader->mFlags = (gsi_u32)theOptionsFlags; + + // Finished, return new report + theNewReport->mReportState = SCIReportState_ROSTER; + theNewReport->mBuffer.mData = (char *)theReportData; + theNewReport->mCurEntityStartPos = -1; + theNewReport->mNumTeamsReported = 0; + + *theReportOut = theNewReport; + GSI_UNUSED(theSessionGuid); + return SCResult_NO_ERROR; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +SCResult sciDestroyReport(SCIReport *theReport) +{ + theReport->mReportState = SCIReportState_NONE; + theReport->mCurEntityKeyCount = 0; + theReport->mCurEntityStartPos = 0; +// theReport->mNumPlayersReported = 0; + theReport->mNumTeamsReported = 0; + theReport->mNumResultsReported = 0; + + gsifree(theReport->mBuffer.mData); + theReport->mBuffer.mData = NULL; + theReport->mBuffer.mCapacity = 0; + theReport->mBuffer.mLen = 0; + theReport->mBuffer.mPos = 0; + gsifree(theReport); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportSetPlayerConnectionId(SCIReport * theReport, gsi_u32 thePlayerIndex, const gsi_u8 theConnectionId[SC_CONNECTION_GUID_SIZE]) +{ + gsi_u32 rosterDataOffset = 0; + + // Roster section is just after the header + rosterDataOffset = sizeof(SCIReportHeader); + rosterDataOffset += SC_REPORT_ROSTERDATA_LENGTH * thePlayerIndex; + + // copy the connection id + GS_ASSERT((rosterDataOffset + SC_GUID_BINARY_SIZE) < theReport->mBuffer.mCapacity); + + sciSerializeGUID((gsi_u8 *)&theReport->mBuffer.mData[rosterDataOffset], theConnectionId); + //memcpy(&theReport->mBuffer.mData[rosterDataOffset], theConnectionId, SC_CONNECTION_GUID_SIZE); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportSetPlayerTeamIndex(SCIReport * theReport, gsi_u32 thePlayerIndex, gsi_u32 theTeamIndex) +{ + //SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + gsi_u32 rosterDataOffset = 0; + + // Roster section is just after the header + rosterDataOffset = sizeof(SCIReportHeader); + rosterDataOffset += SC_REPORT_ROSTERDATA_LENGTH * thePlayerIndex; + + // copy the team index, which must appear just after the connection id + rosterDataOffset += SC_GUID_BINARY_SIZE; + GS_ASSERT((rosterDataOffset + sizeof(gsi_i32)) < theReport->mBuffer.mCapacity); + sciSerializeInt32((gsi_u8 *)&theReport->mBuffer.mData[rosterDataOffset], (gsi_i32)theTeamIndex); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportSetPlayerGameResult(SCIReport * theReport, gsi_u32 thePlayerIndex, SCGameResult theGameResult) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + gsi_u32 resultsDataOffset = 0; + + // Results section is just after the auth section + resultsDataOffset = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength + aHeader->mAuthSectionLength; + resultsDataOffset += sizeof(gsi_u32) * thePlayerIndex; // 4 byte game result per player + + // copy the game result in network byte order + GS_ASSERT((resultsDataOffset + sizeof(gsi_u32)) < theReport->mBuffer.mCapacity); + sciSerializeInt32((gsi_u8 *)&theReport->mBuffer.mData[resultsDataOffset], theGameResult); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportSetPlayerAuthInfo(SCIReport * theReport, gsi_u32 thePlayerIndex, const GSLoginCertificate * theCertificate, const gsi_u8 theAuthHash[16]) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + gsi_u32 authDataOffset = 0; + + // Auth section is just after the roster + authDataOffset = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength; + authDataOffset += SC_REPORT_AUTHDATA_LENGTH * thePlayerIndex; + + // copy auth data into the buffer + // &theReport->mBuffer.mData[authDataOffset] + GSI_UNUSED(theAuthHash); + GSI_UNUSED(theCertificate); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportSetTeamGameResult(SCIReport * theReport, gsi_u32 theTeamIndex, SCGameResult theGameResult) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + gsi_u32 resultsDataOffset = 0; + + // Results section is just after the auth section + // team results are just after player results + resultsDataOffset = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength + aHeader->mAuthSectionLength; + resultsDataOffset += sizeof(gsi_u32) * aHeader->mPlayerCount; // 4 byte game result per player + resultsDataOffset += sizeof(gsi_u32) * theTeamIndex; // 4 byte game result per player + + // copy the game result in network byte order + GS_ASSERT((resultsDataOffset + sizeof(gsi_i32)) < theReport->mBuffer.mCapacity); + sciSerializeInt32((gsi_u8 *)&theReport->mBuffer.mData[resultsDataOffset], theGameResult); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportSetAsMatchless(SCIReport * theReport) +{ + SCIReportHeader * aHeader; + + aHeader = (SCIReportHeader *)theReport->mBuffer.mData; + + aHeader->mFlags |= SC_REPORT_FLAG_MATCHLESS_SESSION; + + return SCResult_NO_ERROR; +} + +/* -----------UNUSED------------ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportPlayerAuth(SCIReport * theReport, + gsi_u32 thePlayerIndex, + gsi_u8 thePlayerConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_u32 thePlayerTeamIndex, + gsi_u32 theProfileId, + GSLoginCertificate * theCertificate, + gsi_u8 theAuthHash[16]) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + //unsigned int len = 0; + + gsi_u32 rosterDataOffset = 0; + gsi_u32 authDataOffset = 0; + + //gsi_u8 * rosterWritePos = NULL; + + // Roster section is just after the header + rosterDataOffset = sizeof(SCIReportHeader); + + // Auth section is just after the roster + authDataOffset = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength; + + // Check size and length + GS_ASSERT((authDataOffset + aHeader->mAuthSectionLength) < SC_REPORT_BUFFER_BYTES); + + // Record player index and team in roster section + // The report contains an array of players, so we offset the write position + // based on the number of players previously reported + rosterDataOffset += aHeader->mPlayerCount * (SC_GUID_BINARY_SIZE + SC_REPORT_ENTITYINDEX_LENGTH); + + // write the connection id GUID + GS_ASSERT(rosterDataOffset < authDataOffset); + sciSerializeGUID((gsi_u8 *)&theReport->mBuffer.mData[rosterDataOffset], thePlayerConnectionId); + rosterDataOffset += SC_GUID_BINARY_SIZE; + + +// GS_ASSERT(rosterDataOffset < authDataOffset); +// memcpy(&theReport->mBuffer.mData[rosterDataOffset], thePlayerConnectionId, SC_GUID_BINARY_SIZE); +// rosterDataOffset += SC_CONNECTION_GUID_SIZE; + + + GS_ASSERT(rosterDataOffset < authDataOffset); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[rosterDataOffset], (gsi_i16)thePlayerTeamIndex); + rosterDataOffset += 2; // we just wrote an Int16, so bump by two. + + GS_ASSERT(rosterDataOffset < authDataOffset); // check overrun + + // Write auth data for this player + // The report contains an array of auth data, so we offset the write position + // based on the number of players previously reported + authDataOffset += aHeader->mPlayerCount * (SC_GUID_BINARY_SIZE + SC_REPORT_ENTITYINDEX_LENGTH); + + GS_ASSERT((authDataOffset + SC_REPORT_AUTHDATA_LENGTH) < theReport->mBuffer.mCapacity); // check buffer space + + // Write auth data + //result = wsLoginCertWriteBinary(theCertificate, &theReport->mBuffer.mData[theReport->mBuffer.mPos], (SC_REPORT_BUFFER_BYTES - theReport->mBuffer.mPos), &len); + //if (gsi_is_false(result)) + // return SCResult_OUT_OF_MEMORY; + //memcpy(&theReport->mBuffer.mData[theReport->mBuffer.mPos], theAuthHash, 16); + //theReport->mBuffer.mPos += 16; + + //theReport->mNumPlayersReported++; // remember how many player's we've written data for + GSI_UNUSED(theAuthHash); + GSI_UNUSED(theCertificate); + GSI_UNUSED(theProfileId); + GSI_UNUSED(thePlayerIndex); + return SCResult_NO_ERROR; +} + +// -----------UNUSED------------ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportPlayerResult(SCIReport * theReport, + gsi_u32 thePlayerIndex, + SCGameResult theResult) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + //unsigned int len = 0; + gsi_u32 resultsOffset = 0; + + resultsOffset = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength + aHeader->mAuthSectionLength; + GS_ASSERT(resultsOffset < SC_REPORT_BUFFER_BYTES); + + resultsOffset += SC_REPORT_ENTITYRESULT_LENGTH * theReport->mNumResultsReported; + sciSerializeInt32((gsi_u8 *)&theReport->mBuffer.mData[resultsOffset], theResult); + + theReport->mNumResultsReported++; + GSI_UNUSED(thePlayerIndex); + return SCResult_NO_ERROR; +} + +// -----------UNUSED------------ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportTeamResult(SCIReport * theReport, + gsi_u32 theTeamIndex, + SCGameResult theResult) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + //unsigned int len = 0; + gsi_u32 resultsOffset = 0; + + resultsOffset = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength + aHeader->mAuthSectionLength; + resultsOffset += SC_REPORT_ENTITYRESULT_LENGTH * theReport->mNumResultsReported; + GS_ASSERT(resultsOffset < SC_REPORT_BUFFER_BYTES); + + resultsOffset += SC_REPORT_ENTITYRESULT_LENGTH * theReport->mNumResultsReported; + sciSerializeInt32((gsi_u8 *)&theReport->mBuffer.mData[resultsOffset], theResult); + + theReport->mNumResultsReported++; + GSI_UNUSED(theTeamIndex); + return SCResult_NO_ERROR; +}*/ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportBeginNewTeam(SCIReport * theReport) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + + //sciReportEndEntity(theReport); + + theReport->mCurEntityKeyCount = 0; + theReport->mCurEntityStartPos = (gsi_i32)theReport->mBuffer.mPos; + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + + aHeader->mTeamSectionLength += sizeof(gsi_u16); + + // Mark the start of the new entity + //theReport->mStatus.mCurEntityStart = &theReport->mBuffer.mData[theReport->mBuffer.mPos]; + //theReport->mStatus.mCurEntityType = SC_REPORT_ENTITY_TEAM; + //theReport->mBuffer.mPos += 4; // skip 4 byte for length, it will be filled in later + //aHeader->mTeamCount++; +// aHeader->mTeamDataLength += 4; // 4 bytes for the new team's length + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportBeginNewPlayer(SCIReport * theReport) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + GS_ASSERT(theReport != NULL); + + //if (theReport->mReportState == SCIReportState_ROSTER) + { + // this is the first player + + } + //GS_ASSERT(theReport->mReportState == SCIReportState_ROSTER); + + theReport->mCurEntityKeyCount = 0; + theReport->mCurEntityStartPos = (gsi_i32)theReport->mBuffer.mPos; + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + + aHeader->mPlayerSectionLength += sizeof(gsi_u16); + + + //sciReportEndEntity(theReport); + + // Mark the start of the new entity + //theReport->mStatus.mCurEntityStart = &theReport->mBuffer.mData[theReport->mBuffer.mPos]; + //theReport->mStatus.mCurEntityType = SC_REPORT_ENTITY_PLAYER; + //theReport->mBuffer.mPos += 4; // skip 4 byte for length, it will be filled in later + //sciSerializeInt32(&theReport->mBuffer.mData[theReport->mBuffer.mPos], thePlayerIndex); + //theReport->mBuffer.mPos += 4; // 4 byte index + //aHeader->mPlayerCount++; +// aHeader->mPlayerDataLength += 4; // 4 bytes for the new player's length + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportBeginGlobalData(SCIReport * theReport) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + + GS_ASSERT(theReport != NULL); + GS_ASSERT(theReport->mReportState == SCIReportState_ROSTER); + + theReport->mReportState = SCIReportState_GLOBALDATA; + //theReport->mCurEntityIndex = 0; + + // set buffer write position to start of global data + theReport->mBuffer.mPos = sizeof(SCIReportHeader) + aHeader->mRosterSectionLength + + aHeader->mAuthSectionLength + aHeader->mResultsSectionLength; + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportBeginPlayerData(SCIReport * theReport) +{ + //SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + + GS_ASSERT(theReport != NULL); + + // Must not have passed into player data state yet. + GS_ASSERT(theReport->mReportState == SCIReportState_ROSTER || + theReport->mReportState == SCIReportState_GLOBALDATA); + + // case where there is no global data + if (theReport->mReportState == SCIReportState_ROSTER) + { + } + + theReport->mReportState = SCIReportState_PLAYERDATA; + //theReport->mCurEntityIndex = 0; + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportBeginTeamData(SCIReport * theReport) +{ + GS_ASSERT(theReport != NULL); + + // Must not have passed into player data state yet. + GS_ASSERT( + theReport->mReportState == SCIReportState_ROSTER || + theReport->mReportState == SCIReportState_GLOBALDATA || + theReport->mReportState == SCIReportState_PLAYERDATA + ); + + theReport->mReportState = SCIReportState_TEAMDATA; + //theReport->mCurEntityIndex = 0; + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportEndEntity(SCIReport * theReport) +{ + //gsi_u8 * anEntityEnd = NULL; + //gsi_u32 anEntityLen = 0; + + // Calculate and update the last entities length + /*if (theReport->mStatus.mCurEntityStart != NULL) + { + anEntityEnd = &theReport->mBuffer.mData[theReport->mBuffer.mPos]; + anEntityLen = anEntityEnd - theReport->mStatus.mCurEntityStart; + sciSerializeDataLength(theReport->mStatus.mCurEntityStart, anEntityLen); + theReport->mStatus.mCurEntityStart = NULL; + }*/ + GSI_UNUSED(theReport); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportEnd(SCIReport * theReport, gsi_bool isAuth, SCGameStatus theStatus) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + + sciReportEndEntity(theReport); + + if (gsi_is_true(isAuth)) + aHeader->mFlags |= SC_REPORT_FLAG_AUTHORITATIVE; + + // Send header in network byte order + aHeader->mGameStatus = htonl(theStatus); + + aHeader->mFlags = htonl(aHeader->mFlags); + aHeader->mPlayerCount = htons(aHeader->mPlayerCount); + aHeader->mTeamCount = htons(aHeader->mTeamCount); + aHeader->mReserved = 0; + + aHeader->mGameKeyCount = htons(aHeader->mGameKeyCount); + aHeader->mPlayerKeyCount = htons(aHeader->mPlayerKeyCount); + aHeader->mTeamKeyCount = htons(aHeader->mTeamKeyCount); + + aHeader->mRosterSectionLength = htonl(aHeader->mRosterSectionLength); + aHeader->mAuthSectionLength = htonl(aHeader->mAuthSectionLength); + aHeader->mResultsSectionLength = htonl(aHeader->mResultsSectionLength); + + aHeader->mGameSectionLength = htonl(aHeader->mGameSectionLength); + aHeader->mPlayerSectionLength = htonl(aHeader->mPlayerSectionLength); + aHeader->mTeamSectionLength = htonl(aHeader->mTeamSectionLength); + + +// aHeader->mSessionDataLength = htonl(aHeader->mSessionDataLength); +// aHeader->mPlayerDataLength = htonl(aHeader->mPlayerDataLength); +// aHeader->mTeamDataLength = htonl(aHeader->mTeamDataLength); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportAddIntValue(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i32 theValue) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + int writtenLen = 0; + gsi_i16 theKeyType = SCIKeyType_INT32; + + // calculate length of data to be written + writtenLen += sizeof(gsi_u16) + sizeof(gsi_u16); // 2 byte key ID, 2 byte key type; + writtenLen += sizeof(gsi_u32); // 4 bytes of data + + // Check room in buffer + GS_ASSERT((theReport->mBuffer.mPos + writtenLen) < theReport->mBuffer.mCapacity); + + // Update count and length markers + if (theReport->mReportState == SCIReportState_GLOBALDATA) + { + aHeader->mGameKeyCount++; + aHeader->mGameSectionLength += writtenLen; + } + else if (theReport->mReportState == SCIReportState_PLAYERDATA) + { + GS_ASSERT(theReport->mCurEntityStartPos != -1); + aHeader->mPlayerKeyCount++; + aHeader->mPlayerSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + else if (theReport->mReportState == SCIReportState_TEAMDATA) + { + aHeader->mTeamKeyCount++; + aHeader->mTeamSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + // Needs real error handling code or an assertion on a non-constant expression + //else + // GS_ASSERT(0); // invalid state for writing key/value pairs! + + // Write the data + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], (gsi_i16)theKeyId); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theKeyType); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt32((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theValue); + theReport->mBuffer.mPos += sizeof(gsi_u32); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportAddInt64Value(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i64 theValue) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + int writtenLen = 0; + gsi_i16 theKeyType = SCIKeyType_INT64; + + // calculate length of data to be written + writtenLen += sizeof(gsi_u16) + sizeof(gsi_u16); // 2 byte key ID, 2 byte key type; + writtenLen += sizeof(gsi_i64); // 4 bytes of data + + // Check room in buffer + GS_ASSERT((theReport->mBuffer.mPos + writtenLen) < theReport->mBuffer.mCapacity); + + // Update count and length markers + if (theReport->mReportState == SCIReportState_GLOBALDATA) + { + aHeader->mGameKeyCount++; + aHeader->mGameSectionLength += writtenLen; + } + else if (theReport->mReportState == SCIReportState_PLAYERDATA) + { + GS_ASSERT(theReport->mCurEntityStartPos != -1); + aHeader->mPlayerKeyCount++; + aHeader->mPlayerSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + else if (theReport->mReportState == SCIReportState_TEAMDATA) + { + aHeader->mTeamKeyCount++; + aHeader->mTeamSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + + // Write the data + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], (gsi_i16)theKeyId); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theKeyType); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt64((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theValue); + theReport->mBuffer.mPos += sizeof(gsi_i64); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportAddShortValue(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i16 theValue) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + int writtenLen = 0; + gsi_i16 theKeyType = SCIKeyType_INT16; + + // calculate length of data to be written + writtenLen += sizeof(gsi_u16) + sizeof(gsi_u16); // 2 byte key ID, 2 byte key type; + writtenLen += sizeof(gsi_u16); // 2 bytes of data + + // Check room in buffer + GS_ASSERT((theReport->mBuffer.mPos + writtenLen) < theReport->mBuffer.mCapacity); + + // Update count and length markers + if (theReport->mReportState == SCIReportState_GLOBALDATA) + { + aHeader->mGameKeyCount++; + aHeader->mGameSectionLength += writtenLen; + } + else if (theReport->mReportState == SCIReportState_PLAYERDATA) + { + GS_ASSERT(theReport->mCurEntityStartPos != -1); + aHeader->mPlayerKeyCount++; + aHeader->mPlayerSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + else if (theReport->mReportState == SCIReportState_TEAMDATA) + { + aHeader->mTeamKeyCount++; + aHeader->mTeamSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + // Needs real error handling code or an assertion on a non-constant expression + //else + // GS_ASSERT(0); // invalid state for writing key/value pairs! + + // Write the data + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], (gsi_i16)theKeyId); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theKeyType); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theValue); + theReport->mBuffer.mPos += sizeof(gsi_u16); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportAddByteValue(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i8 theValue) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + int writtenLen = 0; + gsi_i16 theKeyType = SCIKeyType_BYTE; + + // calculate length of data to be written + writtenLen += sizeof(gsi_u16) + sizeof(gsi_u16); // 2 byte key ID, 2 byte key type; + writtenLen += sizeof(gsi_u8); // 1 bytes of data + + // Check room in buffer + GS_ASSERT((theReport->mBuffer.mPos + writtenLen) < theReport->mBuffer.mCapacity); + + // Update count and length markers + if (theReport->mReportState == SCIReportState_GLOBALDATA) + { + aHeader->mGameKeyCount++; + aHeader->mGameSectionLength += writtenLen; + } + else if (theReport->mReportState == SCIReportState_PLAYERDATA) + { + GS_ASSERT(theReport->mCurEntityStartPos != -1); + aHeader->mPlayerKeyCount++; + aHeader->mPlayerSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + else if (theReport->mReportState == SCIReportState_TEAMDATA) + { + aHeader->mTeamKeyCount++; + aHeader->mTeamSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + // Needs real error handling code or an assertion on a non-constant expression + //else + // GS_ASSERT(0); // invalid state for writing key/value pairs! + + // Write the data + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], (gsi_i16)theKeyId); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theKeyType); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt8((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theValue); + theReport->mBuffer.mPos += sizeof(gsi_u8); + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportAddFloatValue(SCIReport * theReport, + gsi_u16 theKeyId, + float theValue) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + int writtenLen = 0; + gsi_i16 theKeyType = SCIKeyType_FLOAT; + + // calculate length of data to be written + writtenLen += sizeof(gsi_u16) + sizeof(gsi_u16); // 2 byte key ID, 2 byte key type; + writtenLen += sizeof(float); // stored in stream as a 4 byte char array + + // Check room in buffer + GS_ASSERT((theReport->mBuffer.mPos + writtenLen) < theReport->mBuffer.mCapacity); + + // Update count and length markers + if (theReport->mReportState == SCIReportState_GLOBALDATA) + { + aHeader->mGameKeyCount++; + aHeader->mGameSectionLength += writtenLen; + } + else if (theReport->mReportState == SCIReportState_PLAYERDATA) + { + GS_ASSERT(theReport->mCurEntityStartPos != -1); + aHeader->mPlayerKeyCount++; + aHeader->mPlayerSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + else if (theReport->mReportState == SCIReportState_TEAMDATA) + { + aHeader->mTeamKeyCount++; + aHeader->mTeamSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + // Needs real error handling code or an assertion on a non-constant expression + //else + // GS_ASSERT(0); // invalid state for writing key/value pairs! + + // Write the data + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], (gsi_i16)theKeyId); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theKeyType); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeFloat((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theValue); + theReport->mBuffer.mPos += sizeof(float); + + return SCResult_NO_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult SC_CALL sciReportAddStringValue(SCIReport * theReport, + gsi_u16 theKeyId, + const gsi_char * theValue) +{ + SCIReportHeader * aHeader = (SCIReportHeader*)theReport->mBuffer.mData; + int writtenLen = 0, numLenBytes = 0, asciiLen = 0; + gsi_i16 theKeyType = SCIKeyType_STRING; + + // for unicode we need to store the ascii-converted string first in the buffer so as + // not to dynamically allocate space for it. Then once we have the length of it, we can + // write over the buffer + +#if defined(GSI_UNICODE) + // First check room in buffer + GS_ASSERT(((theReport->mBuffer.mPos + (_tcslen(theValue)) + (sizeof(gsi_u16)*2)) + < theReport->mBuffer.mCapacity)); + + // as long as we have enough room - add to the buffer and store length of the Ascii string + // need to remove 1 for the appended null char \0 which we want to remove + asciiLen = UCS2ToAsciiString(theValue, &theReport->mBuffer.mData[theReport->mBuffer.mPos])-1; + + // now determine how many bytes are necessary to represent len + numLenBytes = (asciiLen/127)+1; + +#else + + numLenBytes = (gsi_i32)(strlen(theValue)/127)+1; //finds out number of bytes necessary to represent len + asciiLen = (int)strlen(theValue); +#endif + + + // calculate length of data to be written + writtenLen += sizeof(gsi_u16) + sizeof(gsi_u16); // 2 byte key ID, 2 byte key type; + writtenLen += asciiLen; // 0 for empty string + writtenLen += numLenBytes; // the number of bytes necessary to represent len + + // Check room in buffer + GS_ASSERT((theReport->mBuffer.mPos + writtenLen) < theReport->mBuffer.mCapacity); + + // Update count and length markers + if (theReport->mReportState == SCIReportState_GLOBALDATA) + { + aHeader->mGameKeyCount++; + aHeader->mGameSectionLength += writtenLen; + } + else if (theReport->mReportState == SCIReportState_PLAYERDATA) + { + aHeader->mPlayerKeyCount++; + aHeader->mPlayerSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + else if (theReport->mReportState == SCIReportState_TEAMDATA) + { + aHeader->mTeamKeyCount++; + aHeader->mTeamSectionLength += writtenLen; + + theReport->mCurEntityKeyCount++; + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mCurEntityStartPos], (gsi_i16)theReport->mCurEntityKeyCount); + } + // Needs real error handling code or an assertion on a non-constant expression + //else + // GS_ASSERT(0); // invalid state for writing key/value pairs! + + // Write the data + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], (gsi_i16)theKeyId); + theReport->mBuffer.mPos += sizeof(gsi_u16); + sciSerializeInt16((gsi_u8 *)&theReport->mBuffer.mData[theReport->mBuffer.mPos], theKeyType); + theReport->mBuffer.mPos += sizeof(gsi_u16); + + // now prior to writing the string we need to prepend the length of the string to follow + // the .NET format of (string length)(String) + memset(&theReport->mBuffer.mData[theReport->mBuffer.mPos], asciiLen, (gsi_u32)numLenBytes); + theReport->mBuffer.mPos += numLenBytes; + +#if defined(GSI_UNICODE) + // Now strip to Ascii and write the length - subtract 1 to get rid of appended null character + theReport->mBuffer.mPos += UCS2ToAsciiString(theValue, &theReport->mBuffer.mData[theReport->mBuffer.mPos])-1; +#else + strncpy(&theReport->mBuffer.mData[theReport->mBuffer.mPos], theValue, strlen(theValue)); + theReport->mBuffer.mPos += strlen(theValue); +#endif + + return SCResult_NO_ERROR; +} + +#pragma warning(default: 4267) \ No newline at end of file diff --git a/xrGameSpy/gamespy/sc/sciReport.h b/xrGameSpy/gamespy/sc/sciReport.h new file mode 100644 index 00000000000..6519a307b25 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciReport.h @@ -0,0 +1,185 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SCIREPORT_H__ +#define __SCIREPORT_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sci.h" +#include "../hashtable.h" + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Constants +#define SC_REPORT_PROTOCOL 2 + +// NOTE: broke up entity index in two - for later versions we will want to send the 2 byte +// team index followed by the 4 byte team ID later in the stream + + // Protocol length settings +#define SC_REPORT_ROSTERDATA_LENGTH 20 // V1.0 - 16 byte connection id + 4 byte team index +#define SC_REPORT_PLAYERINDEX_LENGTH 2 // V1.0 - 2 bytes for a player index +#define SC_REPORT_TEAMINDEX_LENGTH 4 // V1.0 - 4 bytes for a team index +#define SC_REPORT_AUTHDATA_LENGTH 16 // V1.0 - length of auth data per player +#define SC_REPORT_ENTITYRESULT_LENGTH 4 // V1.0 - 4 byte enum value + + +#define SC_REPORT_ENTITY_NONE 0 +#define SC_REPORT_ENTITY_PLAYER 1 +#define SC_REPORT_ENTITY_TEAM 2 + +// (must match server) +#define SC_REPORT_FLAG_AUTHORITATIVE (1<<0) +#define SC_REPORT_FLAG_NON_RELATIVE_RESULT (1<<1) +#define SC_REPORT_FLAG_MATCHLESS_SESSION (1<<2) +//#define SC_REPORT_FLAG_DEDICATED_HOST (1<<3) + +typedef enum +{ + SCIReportState_NONE, + SCIReportState_ROSTER, + //SCIReportState_AUTHDATA, + //SCIReportState_RESTULTS, + SCIReportState_GLOBALDATA, + SCIReportState_PLAYERDATA, + SCIReportState_TEAMDATA +} SCIReportState; + +typedef enum +{ + SCIKeyType_INT32, + SCIKeyType_INT16, + SCIKeyType_BYTE, + SCIKeyType_STRING, + SCIKeyType_FLOAT, + SCIKeyType_INT64 +} SCIKeyType; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Structs +typedef struct SCIReportHeader +{ + gsi_u32 mProtocolVersion; // To support future changes + gsi_u32 mDeveloperVersion; + gsi_u8 mChecksum[GS_CRYPT_MD5_HASHSIZE]; // Hash(session, player, team data) + gsi_u32 mGameStatus; + gsi_u32 mFlags; // Flags for authoritative, final, etc. + gsi_u16 mPlayerCount; // Players in session + gsi_u16 mTeamCount; // Teams in session + gsi_u16 mGameKeyCount; + gsi_u16 mPlayerKeyCount; + gsi_u16 mTeamKeyCount; + gsi_u16 mReserved; // pad, for 32-bit alignment + gsi_u32 mRosterSectionLength; // + gsi_u32 mAuthSectionLength; // + gsi_u32 mResultsSectionLength; // + gsi_u32 mGameSectionLength; // + gsi_u32 mPlayerSectionLength; // + gsi_u32 mTeamSectionLength; // +} SCIReportHeader; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct SCIReportBuffer +{ + gsi_bool mIsStatic; + + gsi_u32 mLen; + gsi_u32 mCapacity; + gsi_u32 mPos; + + char * mData; + +} SCIReportBuffer; + +typedef struct SCIReport +{ + SCIReportState mReportState; + + gsi_i32 mCurEntityStartPos; // where this entity's data begins + gsi_u16 mCurEntityKeyCount; // how many keys we've added for this entity + + //gsi_u32 mNumPlayersReported; // to check against expected count - not used + gsi_u32 mNumResultsReported; // to check against expected count + + gsi_u32 mNumTeamsReported; // keeps track of the number of team IDs that have been reported + gsi_u32 mTeamIds[SC_MAX_NUM_TEAMS]; // internal list of team IDs + + SCIReportBuffer mBuffer; +} SCIReport; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciCreateReport(gsi_u8 theSessionGuid[16], + gsi_u32 theHeaderVersion, + gsi_u32 thePlayerCount, + gsi_u32 theTeamCount, + SCIReport ** theReportOut); + +SCResult sciDestroyReport(SCIReport *theReport); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// ReportData functions +SCResult SC_CALL sciReportSetPlayerConnectionId(SCIReport * theReport, gsi_u32 thePlayerIndex, const gsi_u8 theConnectionId[SC_CONNECTION_GUID_SIZE]); +SCResult SC_CALL sciReportSetPlayerTeamIndex (SCIReport * theReport, gsi_u32 thePlayerIndex, gsi_u32 theTeamIndex); +SCResult SC_CALL sciReportSetPlayerGameResult (SCIReport * theReport, gsi_u32 thePlayerIndex, SCGameResult theGameResult); +SCResult SC_CALL sciReportSetPlayerAuthInfo (SCIReport * theReport, gsi_u32 thePlayerIndex, const GSLoginCertificate * theCertificate, const gsi_u8 theAuthHash[16]); +SCResult SC_CALL sciReportSetTeamGameResult (SCIReport * theReport, gsi_u32 theTeamIndex , SCGameResult theGameResult); +SCResult SC_CALL sciReportSetAsMatchless (SCIReport * theReport); + +// Key/Value data +SCResult SC_CALL sciReportBeginGlobalData(SCIReport * theReport); +SCResult SC_CALL sciReportBeginPlayerData(SCIReport * theReport); +SCResult SC_CALL sciReportBeginTeamData (SCIReport * theReport); + +SCResult SC_CALL sciReportAddIntValue(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i32 theValue); +SCResult SC_CALL sciReportAddInt64Value(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i64 theValue); +SCResult SC_CALL sciReportAddShortValue(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i16 theValue); +SCResult SC_CALL sciReportAddByteValue(SCIReport * theReport, + gsi_u16 theKeyId, + gsi_i8 theValue); +SCResult SC_CALL sciReportAddFloatValue(SCIReport * theReport, + gsi_u16 theKeyId, + float theValue); +SCResult SC_CALL sciReportAddStringValue(SCIReport * theReport, + gsi_u16 theKeyId, + const gsi_char * theValue); + +SCResult SC_CALL sciReportBeginNewTeam(SCIReport * theReport); +SCResult SC_CALL sciReportBeginNewPlayer(SCIReport * theReport); +SCResult SC_CALL sciReportEndEntity(SCIReport * theReport); +// Call when finished writing +SCResult SC_CALL sciReportEnd(SCIReport * theReport, gsi_bool isAuth, SCGameStatus theStatus); + + + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SCREPORT_H__ diff --git a/xrGameSpy/gamespy/sc/sciSerialize.c b/xrGameSpy/gamespy/sc/sciSerialize.c new file mode 100644 index 00000000000..9100ea99927 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciSerialize.c @@ -0,0 +1,171 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sciSerialize.h" + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeInt8(gsi_u8* theCursor, gsi_i8 theValue) +{ + // Copy int8 value to possibly misaligned destination + gsi_u8* dst = (gsi_u8*)theCursor; + + *dst++ = (gsi_u8)theValue; + + return (gsi_u8*)dst; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeInt16(gsi_u8* theCursor, gsi_i16 theValue) +{ + // Convert to network byte order + gsi_i16 netValue = (gsi_i16)htons(theValue); + + // Copy int16 value to possibly misaligned destination + gsi_u8* dst = (gsi_u8*)theCursor; + gsi_u8* src = (gsi_u8*)&netValue; + + *dst++ = *src++; + *dst++ = *src++; + + return (gsi_u8*)dst; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeInt32(gsi_u8* theCursor, gsi_i32 theValue) +{ + // Convert to network byte order + gsi_i32 netValue = (gsi_i32)htonl(theValue); + + // Copy int32 value to possibly misaligned destination + gsi_u8* dst = (gsi_u8*)theCursor; + gsi_u8* src = (gsi_u8*)&netValue; + + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + + return (gsi_u8*)dst; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeInt64(gsi_u8* theCursor, gsi_i64 theValue) +{ + // Convert to network byte order + //gsi_i32 netValue = (gsi_i32)htonl(theValue); + + // Copy int32 value to possibly misaligned destination + gsi_u8* dst = (gsi_u8*)theCursor; + gsi_u8* src = (gsi_u8*)&theValue; + +#ifdef GSI_BIG_ENDIAN + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +#else + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; +#endif + + return (gsi_u8*)dst; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeFloat(gsi_u8* theCursor, float theValue) +{ + unsigned char netValue[4]; + gsi_u8 *dst, *src; + +#if defined(GSI_BIG_ENDIAN) + //swap byte ordering for floats to little endian - htonl doesn't work + gsiFloatSwap(netValue, theValue); +#else + memcpy(netValue, &theValue, 4); +#endif + + dst = (gsi_u8*)theCursor; + src = (gsi_u8*)&netValue; + + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + + return (gsi_u8*)dst; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeKey(gsi_u8* theCursor, gsi_u16 theKey) +{ + return sciSerializeInt16(theCursor, (gsi_i16)theKey); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeDataLength(gsi_u8* theCursor, gsi_u32 theDataLength) +{ + return sciSerializeInt32(theCursor, (gsi_i32)theDataLength); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeGUID(gsi_u8* theCursor, const gsi_u8 theGUID[SC_CONNECTION_GUID_SIZE]) +{ + // a GUID is a string comprised of an int, two shorts and eight bytes + // 6B29FC40-CA47-1067-B31D-00DD010662DA + gsi_u32 anInt = 0; + gsi_u32 aShort1 = 0; + gsi_u32 aShort2 = 0; + gsi_u32 aIntArray[8]; + gsi_u8 aByteArray[8]; + int i=0; + + sscanf((char *)theGUID, "%8x", &anInt); + sscanf((char *)theGUID+9, "%4x", &aShort1); + sscanf((char *)theGUID+14, "%4x", &aShort2); + + sscanf((char *)theGUID+19, "%2x", &aIntArray[0]); + sscanf((char *)theGUID+21, "%2x", &aIntArray[1]); + + sscanf((char *)theGUID+24, "%2x%2x%2x%2x%2x%2x", &aIntArray[2], + &aIntArray[3], &aIntArray[4], &aIntArray[5], + &aIntArray[6], &aIntArray[7]); + + for (i=0; i < 8; i++) + aByteArray[i] = (gsi_u8)aIntArray[i]; + + theCursor = sciSerializeInt32(theCursor, (gsi_i32)anInt); + theCursor = sciSerializeInt16(theCursor, (gsi_i16)aShort1); + theCursor = sciSerializeInt16(theCursor, (gsi_i16)aShort2); + memcpy(theCursor, aByteArray, 8); + theCursor += 8; + + return theCursor; +} diff --git a/xrGameSpy/gamespy/sc/sciSerialize.h b/xrGameSpy/gamespy/sc/sciSerialize.h new file mode 100644 index 00000000000..32e65d99a53 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciSerialize.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SCISERIALIZE_H__ +#define __SCISERIALIZE_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "sciReport.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u8* sciSerializeInt8 (gsi_u8* theCursor, gsi_i8 theValue); + +gsi_u8* sciSerializeInt16 (gsi_u8* theCursor, gsi_i16 theValue); + +gsi_u8* sciSerializeInt32 (gsi_u8* theCursor, gsi_i32 theValue); + +gsi_u8* sciSerializeInt64 (gsi_u8* theCursor, gsi_i64 theValue); + +gsi_u8* sciSerializeFloat (gsi_u8* theCursor, float theValue); + +gsi_u8* sciSerializeKey (gsi_u8* theCursor, gsi_u16 theKey); + +gsi_u8* sciSerializeDataLength(gsi_u8* theCursor, gsi_u32 theDataLength); + +gsi_u8* sciSerializeGUID (gsi_u8* theCursor, const gsi_u8 theGUID[SC_CONNECTION_GUID_SIZE]); + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SCSERIALIZE_H__ diff --git a/xrGameSpy/gamespy/sc/sciWebServices.c b/xrGameSpy/gamespy/sc/sciWebServices.c new file mode 100644 index 00000000000..4620f94a576 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciWebServices.c @@ -0,0 +1,600 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../common/gsCore.h" + +#include "sci.h" +#include "sciInterface.h" +#include "sciWebServices.h" +#include "sciReport.h" + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define SC_CREATEMATCHLESSSESSION_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/CreateMatchlessSession\"" +#define SC_CREATESESSION_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/CreateSession\"" +#define SC_SUBMITREPORT_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/SubmitReport\"" +#define SC_SETINTENTION_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/SetReportIntention\"" + +#define SC_SERVICE_NAMESPACE_COUNT 1 +const char * SC_SERVICE_NAMESPACES[SC_SERVICE_NAMESPACE_COUNT] = +{ + "gsc=\"http://gamespy.net/competition/\"" +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsInit(SCWebServices* theWebServices, + SCInterfacePtr theInterface) +{ + + + GS_ASSERT(theWebServices != NULL); + GS_ASSERT(theInterface != NULL); + GS_ASSERT(!theWebServices->mInit); + + // Check gsCore + if (gsCoreIsShutdown()) + { + return SCResult_CORE_NOT_INITIALIZED; + } + + // Initialize SCWebServices struct + theWebServices->mInterface = theInterface; + theWebServices->mCreateSessionCallback = NULL; + theWebServices->mSetReportIntentionCallback = NULL; + theWebServices->mSubmitReportDataCallback = NULL; + theWebServices->mCreateSessionUserData = NULL; + theWebServices->mSetReportIntentionUserData = NULL; + theWebServices->mSubmitReportUserData = NULL; + theWebServices->mCreateSessionPending = gsi_false; + theWebServices->mSetReportIntentionPending = gsi_false; + theWebServices->mSubmitReportPending = gsi_false; + + // Now initialized + theWebServices->mInit = gsi_true; + + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciWsDestroy(SCWebServices* theWebServices) +{ + GS_ASSERT(theWebServices != NULL); + GS_ASSERT(theWebServices->mInit); + + // No longer initialized + theWebServices->mInit = gsi_false; + + // Destroy SCWebServices struct + theWebServices->mCreateSessionCallback = NULL; + theWebServices->mSetReportIntentionCallback = NULL; + theWebServices->mSubmitReportDataCallback = NULL; + theWebServices->mCreateSessionUserData = NULL; + theWebServices->mSetReportIntentionUserData = NULL; + theWebServices->mSubmitReportUserData = NULL; + theWebServices->mCreateSessionPending = gsi_false; + theWebServices->mSetReportIntentionPending = gsi_false; + theWebServices->mSubmitReportPending = gsi_false; + theWebServices->mInterface = NULL; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciWsThink(SCWebServices* theWebServices) +{ + GS_ASSERT(theWebServices != NULL); + GS_ASSERT(theWebServices->mInit); + + gsCoreThink(0); + + GSI_UNUSED(theWebServices); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsCreateSession (SCWebServices * theWebServices, + gsi_u32 theGameId, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + GSXmlStreamWriter aRequest = NULL; + + // Check parameters + GS_ASSERT(theWebServices != NULL); + GS_ASSERT(theWebServices->mInit); + + // Check for pending request + if (theWebServices->mCreateSessionPending) + return SCResult_CALLBACK_PENDING; + + // Create the XML message writer + aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT); + if (aRequest == NULL) + return SCResult_OUT_OF_MEMORY; + + // Fill in the request data + if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "CreateSession")) || + gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) || + gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) || + gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) || + gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "CreateSession")) || + gsi_is_false(gsXmlCloseWriter(aRequest)) + ) + { + gsXmlFreeWriter(aRequest); + return SCResult_HTTP_ERROR; + } + + // Set callback + theWebServices->mCreateSessionCallback = theCallback; + theWebServices->mCreateSessionUserData = theUserData; + theWebServices->mCreateSessionPending = gsi_true; + + // Execute soap call + gsiExecuteSoap(scServiceURL, SC_CREATESESSION_SOAPACTION, + aRequest, sciWsCreateSessionCallback, theWebServices); + GSI_UNUSED(theTimeoutMs); + return SCResult_NO_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsCreateMatchlessSession (SCWebServices * theWebServices, + gsi_u32 theGameId, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + GSXmlStreamWriter aRequest = NULL; + + // Check parameters + GS_ASSERT(theWebServices != NULL); + GS_ASSERT(theWebServices->mInit); + + // Check for pending request + if (theWebServices->mCreateSessionPending) + return SCResult_CALLBACK_PENDING; + + // Create the XML message writer + aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT); + if (aRequest == NULL) + return SCResult_OUT_OF_MEMORY; + + // Fill in the request data + if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "CreateMatchlessSession")) || + gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) || + gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) || + gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) || + gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "CreateMatchlessSession")) || + gsi_is_false(gsXmlCloseWriter(aRequest)) + ) + { + gsXmlFreeWriter(aRequest); + return SCResult_HTTP_ERROR; + } + + // Set callback + theWebServices->mCreateSessionCallback = theCallback; + theWebServices->mCreateSessionUserData = theUserData; + theWebServices->mCreateSessionPending = gsi_true; + + // Execute soap call + gsiExecuteSoap(scServiceURL, SC_CREATEMATCHLESSSESSION_SOAPACTION, + aRequest, sciWsCreateSessionCallback, theWebServices); + GSI_UNUSED(theTimeoutMs); + return SCResult_NO_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciWsCreateSessionCallback(GHTTPResult theHttpResult, + GSXmlStreamWriter theRequestData, + GSXmlStreamReader theResponseData, + void* theUserData) +{ + SCResult aTranslatedResult = SCResult_HTTP_ERROR; + SCWebServices* aWebServices = (SCWebServices*)theUserData; + + char csid[255]; + char ccid[255]; + int csidLen = 255; + int ccidLen = 255; + + GS_ASSERT(aWebServices != NULL); + GS_ASSERT(aWebServices->mCreateSessionPending); + + // Check for shutdown + if (!aWebServices->mInit) + return; + + if (theHttpResult == GHTTPSuccess) + { + int createResult = 0; + + // Parse through in a way that will work for either type of CreateSession response. + if (gsi_is_false(gsXmlMoveToStart(theResponseData))) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + else if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateSessionResponse"))) + { + if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateMatchlessSessionResponse"))) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + } + + if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateSessionResult"))) + { + if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateMatchlessSessionResult"))) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + } + + if(gsi_is_false(gsXmlReadChildAsInt(theResponseData, "result", &createResult))) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + else if(aTranslatedResult != SCResult_RESPONSE_INVALID) + { + // Parse server reported result + if (createResult == SCWsResult_NO_ERROR) + { + // Read session and connection ID + if(gsi_is_false(gsXmlReadChildAsStringNT(theResponseData, "csid", csid, csidLen)) || + gsi_is_false(gsXmlReadChildAsStringNT(theResponseData, "ccid", ccid, ccidLen)) + ) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + else + { + sciInterfaceSetSessionId((SCInterface*)aWebServices->mInterface, csid); + sciInterfaceSetConnectionId((SCInterface*)aWebServices->mInterface, ccid); + aTranslatedResult = SCResult_NO_ERROR; + } + } + else + { + // Server reported an error, handle it? + + // TODO: + // translate result into developer useable form + // report result string as gsDebugFormat message for easier debugging + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + } + } + else + { + aTranslatedResult = SCResult_HTTP_ERROR; + } + + // Client callback + aWebServices->mCreateSessionPending = gsi_false; + if (aWebServices->mCreateSessionCallback != NULL) + { + aWebServices->mCreateSessionCallback(aWebServices->mInterface, theHttpResult, aTranslatedResult, aWebServices->mCreateSessionUserData); + aWebServices->mCreateSessionUserData = NULL; + aWebServices->mCreateSessionCallback = NULL; + } + GSI_UNUSED(theRequestData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsSetReportIntention(SCWebServices* theWebServices, + gsi_u32 theGameId, + const char * theSessionId, + const char * theConnectionId, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + GSXmlStreamWriter aRequest = NULL; + + // Check parameters + GS_ASSERT(theWebServices != NULL); + GS_ASSERT(theWebServices->mInit); + + // Check for pending request + if (theWebServices->mSetReportIntentionPending) + return SCResult_CALLBACK_PENDING; + + // Create the XML message writer + aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT); + if (aRequest == NULL) + return SCResult_OUT_OF_MEMORY; + + // Fill in the request data + if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "SetReportIntention")) || + gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) || + gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) || + gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) || + gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "csid", theSessionId)) || + gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "ccid", theConnectionId)) || + gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) || + gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "authoritative", (gsi_u32)(gsi_is_true(isAuthoritative) ? 1:0))) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "SetReportIntention")) || + gsi_is_false(gsXmlCloseWriter(aRequest)) + ) + { + gsXmlFreeWriter(aRequest); + return SCResult_HTTP_ERROR; + } + + // Set callback + theWebServices->mSetReportIntentionCallback = theCallback; + theWebServices->mSetReportIntentionUserData = theUserData; + theWebServices->mSetReportIntentionPending = gsi_true; + + // Execute soap call + gsiExecuteSoap(scServiceURL, SC_SETINTENTION_SOAPACTION, + aRequest, sciWsSetReportIntentionCallback, theWebServices); + + GSI_UNUSED(theTimeoutMs); + return SCResult_NO_ERROR; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciWsSetReportIntentionCallback(GHTTPResult theHttpResult, + GSXmlStreamWriter theRequestData, + GSXmlStreamReader theResponseData, + void* theUserData) +{ + SCResult aTranslatedResult = SCResult_HTTP_ERROR; + SCWebServices* aWebServices = (SCWebServices*)theUserData; + + char ccid[255]; + int ccidLen = 255; + + + GS_ASSERT(aWebServices != NULL); + GS_ASSERT(aWebServices->mSetReportIntentionPending); + + // Check for shutdown + if (!aWebServices->mInit) + return; + + if (theHttpResult == GHTTPSuccess) + { + int intentionResult = 0; + + if (gsi_is_false(gsXmlMoveToStart(theResponseData)) || + gsi_is_false(gsXmlMoveToNext(theResponseData, "SetReportIntentionResponse")) || + gsi_is_false(gsXmlMoveToNext(theResponseData, "SetReportIntentionResult")) || + gsi_is_false(gsXmlReadChildAsInt(theResponseData, "result", &intentionResult)) || + gsi_is_false(gsXmlReadChildAsStringNT(theResponseData, "ccid", ccid, ccidLen)) + ) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + else + { + if (intentionResult == SCWsResult_NO_ERROR) + { + aTranslatedResult = SCResult_NO_ERROR; + sciInterfaceSetConnectionId((SCInterface*)aWebServices->mInterface, ccid); + } + else + aTranslatedResult = SCResult_UNKNOWN_RESPONSE; + } + } + else + { + aTranslatedResult = SCResult_HTTP_ERROR; + } + + // Client callback + aWebServices->mSetReportIntentionPending = gsi_false; + if (aWebServices->mSetReportIntentionCallback != NULL) + { + aWebServices->mSetReportIntentionCallback(aWebServices->mInterface, + theHttpResult, + aTranslatedResult, + aWebServices->mSetReportIntentionUserData); + aWebServices->mSetReportIntentionUserData = NULL; + aWebServices->mSetReportIntentionCallback = NULL; + } + GSI_UNUSED(theRequestData); +} + + +/////////////////////////////////////////////////////////////////////////////// +// declared here to allow function to get around Unicode calls +extern GHTTPBool ghiPostAddFileFromMemory(GHTTPPost post,const char * name,const char * buffer, + int bufferLen,const char * reportFilename,const char * contentType); +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Private GSSoapCustomFunc used by sciWsSubmitReport +static void sciWsSubmitReportCustom(GHTTPPost thePost, void* theUserData) +{ + SCWebServices* aWebServices = (SCWebServices*)theUserData; + + //Use internal method to get around unicode calls + ghiPostAddFileFromMemory(thePost, "report", (char *)aWebServices->mSubmitReportData, + (gsi_i32)aWebServices->mSubmitReportLength, "report", "application/bin"); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsSubmitReport(SCWebServices* theWebServices, + gsi_u32 theGameId, + const char * theSessionId, + const char * theConnectionId, + const SCIReport * theReport, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSubmitReportCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + GSXmlStreamWriter aRequest = NULL; + //SCIReportHeader * aReportHeader = NULL; + //gsi_u32 aTotalSize = 0; + + //SCReportStatus* aStatus = NULL; + + // Check parameters + GS_ASSERT(theWebServices != NULL); + //GS_ASSERT(theReportData != NULL); + + // Check for pending request + if (theWebServices->mSubmitReportPending) + { + return SCResult_CALLBACK_PENDING; + } + + // Get a pointer to the header + //aReportHeader = (SCIReportHeader*)theReport->mBuffer.mData; + + // Check for complete report + if (theReport->mBuffer.mPos < sizeof(SCIReportHeader)) + return SCResult_REPORT_INVALID; + + // Check size (early check for easier debugging) + //aTotalSize = sizeof(SCIReportHeader); + //aTotalSize += htonl(aReportHeader->mPlayerDataLength); + //aTotalSize += htonl(aReportHeader->mTeamDataLength); + //aTotalSize += htonl(aReportHeader->mSessionDataLength); + // aTotalSize += auth info... + //if (theReport->mBuffer.mPos != aTotalSize) + // return SCResult_REPORT_INVALID; + + // Create the XML message writer + aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT); + if (aRequest == NULL) + return SCResult_OUT_OF_MEMORY; + + // Fill in the request data + if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "SubmitReport")) || + gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) || + gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) || + gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) || + gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "csid", theSessionId)) || + gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "ccid", theConnectionId)) || + gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) || + gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "authoritative", (gsi_u32)(gsi_is_true(isAuthoritative) ? 1:0))) || + gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "SubmitReport")) || + gsi_is_false(gsXmlCloseWriter(aRequest)) + ) + { + gsXmlFreeWriter(aRequest); + return SCResult_OUT_OF_MEMORY; + } + + // Get submission size + theWebServices->mSubmitReportData = (gsi_u8*)theReport->mBuffer.mData; + theWebServices->mSubmitReportLength = theReport->mBuffer.mPos; + + // Set callback + theWebServices->mSubmitReportDataCallback = theCallback; + theWebServices->mSubmitReportUserData = theUserData; + theWebServices->mSubmitReportPending = gsi_true; + + // Execute soap call + gsiExecuteSoapCustom(scServiceURL, SC_SUBMITREPORT_SOAPACTION, + aRequest, sciWsSubmitReportCallback,sciWsSubmitReportCustom, theWebServices); + + GSI_UNUSED(theTimeoutMs); + return SCResult_NO_ERROR; +} + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +void sciWsSubmitReportCallback(GHTTPResult theHttpResult, + GSXmlStreamWriter theRequestData, + GSXmlStreamReader theResponseData, + void* theUserData) +{ + SCResult aTranslatedResult = SCResult_HTTP_ERROR; + SCWebServices* aWebServices = (SCWebServices*)theUserData; + + GS_ASSERT(aWebServices != NULL); + + // Check for shutdown + if (!aWebServices->mInit) + return; + + GS_ASSERT(aWebServices->mSubmitReportPending); + + if (theHttpResult == GHTTPSuccess) + { + int submitResult = 0; + + if (gsi_is_false(gsXmlMoveToStart(theResponseData)) || + gsi_is_false(gsXmlMoveToNext(theResponseData, "SubmitReportResponse")) || + gsi_is_false(gsXmlMoveToNext(theResponseData, "SubmitReportResult")) || + gsi_is_false(gsXmlReadChildAsInt(theResponseData, "result", &submitResult)) + ) + { + aTranslatedResult = SCResult_RESPONSE_INVALID; + } + else + { + switch (submitResult) + { + case SCWsResult_NO_ERROR: + aTranslatedResult = SCResult_NO_ERROR; + break; + case SCWsResult_REPORT_INVALID: + aTranslatedResult = SCResult_REPORT_INVALID; + break; + case SCWsResult_SINGLE_ATTACHMENT_EXPECTED: + aTranslatedResult = SCResult_SUBMISSION_FAILED; + break; + default: + aTranslatedResult = SCResult_UNKNOWN_RESPONSE; + break; + }; + } + } + else + { + aTranslatedResult = SCResult_HTTP_ERROR; + } + + // Client callback + aWebServices->mSubmitReportPending = gsi_false; + if (aWebServices->mSubmitReportDataCallback != NULL) + { + aWebServices->mSubmitReportDataCallback(aWebServices->mInterface, + theHttpResult, + aTranslatedResult, + aWebServices->mSubmitReportUserData); + aWebServices->mSubmitReportUserData = NULL; + aWebServices->mSubmitReportDataCallback = NULL; + } + GSI_UNUSED(theRequestData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/sc/sciWebServices.h b/xrGameSpy/gamespy/sc/sciWebServices.h new file mode 100644 index 00000000000..a6d0fb5caa3 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sciWebServices.h @@ -0,0 +1,126 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __SCWEBSERVICES_H__ +#define __SCWEBSERVICES_H__ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../common/gsSoap.h" +#include "../common/gsXML.h" +#include "../ghttp/ghttpPost.h" + +#include "sci.h" +#include "sciReport.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Web service result codes (must match definitions in StatsReceiver) +typedef enum +{ + SCWsResult_NO_ERROR = 0, + SCWsResult_REPORT_INVALID, + SCWsResult_SINGLE_ATTACHMENT_EXPECTED +} SCWsResult; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +typedef struct +{ + SCInterfacePtr mInterface; + SCCreateSessionCallback mCreateSessionCallback; + SCSetReportIntentionCallback mSetReportIntentionCallback; + SCSubmitReportCallback mSubmitReportDataCallback; + gsi_bool mSetReportIntentionPending; + gsi_bool mCreateSessionPending; + gsi_bool mSubmitReportPending; + void * mSetReportIntentionUserData; + void * mCreateSessionUserData; + void * mSubmitReportUserData; + gsi_u8* mSubmitReportData; + gsi_u32 mSubmitReportLength; + gsi_bool mInit; +} SCWebServices; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsInit (SCWebServices* theWebServices, + SCInterfacePtr theInterface); +void sciWsDestroy(SCWebServices* theWebServices); +void sciWsThink (SCWebServices* theWebServices); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +SCResult sciWsCreateSession (SCWebServices * theWebServices, + gsi_u32 theGameId, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +SCResult sciWsCreateMatchlessSession(SCWebServices * theWebServices, + gsi_u32 theGameId, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +void sciWsCreateSessionCallback(GHTTPResult theHttpResult, + GSXmlStreamWriter theRequestData, + GSXmlStreamReader theResponseData, + void* theUserData); + +SCResult sciWsSetReportIntention (SCWebServices* theWebServices, + gsi_u32 theGameId, + const char * theSessionId, + const char * theConnectionId, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +void sciWsSetReportIntentionCallback(GHTTPResult theHttpResult, + GSXmlStreamWriter theRequestData, + GSXmlStreamReader theResponseData, + void* theUserData); + +SCResult sciWsSubmitReport (SCWebServices* theWebServices, + gsi_u32 theGameId, + const char * theSessionId, + const char * theConnectionId, + const SCIReport* theReport, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSubmitReportCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData); + +void sciWsSubmitReportCallback(GHTTPResult theHttpResult, + GSXmlStreamWriter theRequestData, + GSXmlStreamReader theResponseData, + void* theUserData); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#endif // __SCWEBSERVICES_H__ diff --git a/xrGameSpy/gamespy/sc/sctest/sclinux/Makefile b/xrGameSpy/gamespy/sc/sctest/sclinux/Makefile new file mode 100644 index 00000000000..96e2ef39820 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/sclinux/Makefile @@ -0,0 +1,74 @@ +# Competition SDK Makefile +# Copyright 2007 GameSpy Industries + +PROJECT=sclinux + +CC=gcc +BASE_CFLAGS=-D_LINUX -DGSI_COMMON_DEBUG -D_DEBUG -DGSI_NO_THREADS + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 + +#use these when debugging +DEBUG_CFLAGS=$(BASE_CFLAGS) -g -lpthread -march=i486 -O6 + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCore.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../../common/gsSoap.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../webservices/AuthService.o\ + ../../sciInterface.o\ + ../../sciMain.o\ + ../../sciReport.o\ + ../../sciSerialize.o\ + ../../sciWebServices.o\ + ../sctest.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# +ghttp_debug: $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/sc/sctest/scmacosx/Makefile b/xrGameSpy/gamespy/sc/sctest/scmacosx/Makefile new file mode 100644 index 00000000000..f34c15dcabd --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scmacosx/Makefile @@ -0,0 +1,47 @@ +# Competition SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=sctest + +DEFINES=-D_MACOSX -DGSI_NO_THREADS + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCore.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../../common/gsSoap.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../webservices/AuthService.o\ + ../../sciInterface.o\ + ../../sciMain.o\ + ../../sciReport.o\ + ../../sciSerialize.o\ + ../../sciWebServices.o\ + ../sctest.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/sc/sctest/scnitrocw/Nitro.lcf b/xrGameSpy/gamespy/sc/sctest/scnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/sc/sctest/scnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/sc/sctest/scnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/sc/sctest/scnitrocw/scnitrocw.mcp b/xrGameSpy/gamespy/sc/sctest/scnitrocw/scnitrocw.mcp new file mode 100644 index 00000000000..64b79d06a4d Binary files /dev/null and b/xrGameSpy/gamespy/sc/sctest/scnitrocw/scnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/sc/sctest/scps2prodg/scps2prodg.sln b/xrGameSpy/gamespy/sc/sctest/scps2prodg/scps2prodg.sln new file mode 100644 index 00000000000..7850f8f6b59 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scps2prodg/scps2prodg.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scps2prodg", "scps2prodg.vcproj", "{190F63A1-557A-4CAF-B92F-0C98884B422B}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = scps2prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EE Debug|Win32 = PS2 EE Debug|Win32 + PS2 EE Release|Win32 = PS2 EE Release|Win32 + PS2_INET_Debug|Win32 = PS2_INET_Debug|Win32 + PS2_INET_Release|Win32 = PS2_INET_Release|Win32 + PS2_SNSystems_Debug|Win32 = PS2_SNSystems_Debug|Win32 + PS2_SNSystems_Release|Win32 = PS2_SNSystems_Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Debug|Win32.ActiveCfg = PS2 EE Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Debug|Win32.Build.0 = PS2 EE Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Release|Win32.ActiveCfg = PS2 EE Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Release|Win32.Build.0 = PS2 EE Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Debug|Win32.ActiveCfg = PS2_INET_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Debug|Win32.Build.0 = PS2_INET_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Release|Win32.ActiveCfg = PS2_INET_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Release|Win32.Build.0 = PS2_INET_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Debug|Win32.ActiveCfg = PS2_SNSystems_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Debug|Win32.Build.0 = PS2_SNSystems_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Release|Win32.ActiveCfg = PS2_SNSystems_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Release|Win32.Build.0 = PS2_SNSystems_Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctest/scps2prodg/scps2prodg.vcproj b/xrGameSpy/gamespy/sc/sctest/scps2prodg/scps2prodg.vcproj new file mode 100644 index 00000000000..05633773066 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scps2prodg/scps2prodg.vcproj @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctest/scps3prodg/scps3prodg.sln b/xrGameSpy/gamespy/sc/sctest/scps3prodg/scps3prodg.sln new file mode 100644 index 00000000000..7fef92ee6cf --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scps3prodg/scps3prodg.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scps3prodg", "scps3prodg.vcproj", "{CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = scps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctest/scps3prodg/scps3prodg.vcproj b/xrGameSpy/gamespy/sc/sctest/scps3prodg/scps3prodg.vcproj new file mode 100644 index 00000000000..57b25331b67 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scps3prodg/scps3prodg.vcproj @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctest/scpspprodg/scpspprodg.sln b/xrGameSpy/gamespy/sc/sctest/scpspprodg/scpspprodg.sln new file mode 100644 index 00000000000..4360b4a4317 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scpspprodg/scpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scpspprodg", "scpspprodg.vcproj", "{71304287-4974-4E1B-8FC8-EE987BEBFB8A}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = scpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctest/scpspprodg/scpspprodg.vcproj b/xrGameSpy/gamespy/sc/sctest/scpspprodg/scpspprodg.vcproj new file mode 100644 index 00000000000..2faf80dfb15 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scpspprodg/scpspprodg.vcproj @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctest/screvolutioncw/screvolutioncw.mcp b/xrGameSpy/gamespy/sc/sctest/screvolutioncw/screvolutioncw.mcp new file mode 100644 index 00000000000..ca1dc9e0b34 Binary files /dev/null and b/xrGameSpy/gamespy/sc/sctest/screvolutioncw/screvolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/sc/sctest/sctest.c b/xrGameSpy/gamespy/sc/sctest/sctest.c new file mode 100644 index 00000000000..8d89febb2ab --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/sctest.c @@ -0,0 +1,1022 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../../common/gsCommon.h" +#include "../../common/gsCore.h" +#include "../../common/gsAvailable.h" +#include "../../webservices/AuthService.h" +#include "../sc.h" + +#include + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This sample simulates a stats implementation for a 2v2 game. +// +// For simplicity, all 4 players are run from one machine. +// 4 people use the auth service functions to login and get their certificates +// The SDK is initialized and the game creates a session using one of the +// player's certificate +// +// + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Player account information. (see GP documentation for account creation.) +#define SCTEST_LOGIN_PARTNERCODE 0 // gamespy account space +#define SCTEST_LOGIN_NAMESPACE 1 // shared namespace with unique nicknames + +#define SCTEST_REMOTE_PARTNERCODE 1 +#define SCTEST_REMOTE_NAMESPACEID 0 + +// Hardcoded information for four sample players +#define SCTEST_NICK_1 _T("sctest01") +#define SCTEST_NICK_2 _T("sctest02") +#define SCTEST_NICK_3 _T("sctest03") +#define SCTEST_NICK_4 _T("sctest04") +#define SCTEST_NICK_5 _T("sctest05") +#define SCTEST_NICK_6 _T("sctest06") +#define SCTEST_EMAIL _T("sctest@gamespy.com") +#define SCTEST_PASSWORD _T("gspy") + +#define SCTEST_TOKEN_1 _T("GMTy13lsJmiY7L19ojyN3XTM08ll0C4EWWijwmJyq3ttiZmoDUQJ0OSnar9nQCu5MpOGvi4Z0EcC2uNaS4yKrUA+h+tTDDoJHF7ZjoWKOTj00yNOEdzWyG08cKdVQwFRkF+h8oG/Jd+Ik3sWviXq/+5bhZQ7iXxTbbDwNL6Lagp/pLZ9czLnYPhY7VEcoQlx9oO") +#define SCTEST_CHALLENGE_1 _T("LH8c.DLe") +#define SCTEST_TOKEN_2 _T("GMTSc9Hl0VvG1FjqkCLkanABNB/u9jhNrQnXng6cQva0JtsJgEkwt6znjLDABAm3MmyEHDEcj6yZWwZmvPl1R8uEcJ0RW1OplewifmRhfU3dglMq3OP1VOgX6+lG0SoPwp9BLmka8O4JGiSTSq8jGuDyHnCBLVozMMpeYPJ3wGAuxrx2OlWdUe3PTNhFK/LeNBl") +#define SCTEST_CHALLENGE_2 _T("@WWm5DWI") + +// Use to toggle "matchless" session mode on/off. +//#define MATCHLESS_SESSION + +#define SCTEST_LOGIN_PROFILE 0 +#define SCTEST_LOGIN_UNIQUE 1 +#define SCTEST_LOGIN_REMOTEAUTH 2 + +#define SCTEST_GAMETYPE_CTF 2 +#define SCTEST_GAMETYPE_DEATHMATCH 3 +#define SCTEST_TEAMRANK_HEROES 26 +#define SCTEST_TEAMRANK_VILLAINS 35 + +#define SCTEST_KEY_TEAM_TYPE_HEROES 0 +#define SCTEST_KEY_TEAM_TYPE_VILLAINS 1 + +#define SCTEST_KEY_TEAM_ARENAID_HEROES 7066 +#define SCTEST_KEY_TEAM_ARENAID_VILLAINS 7067 +#define SCTEST_KEY_TEAM_NAME_HEROES _T("Heroes") +#define SCTEST_KEY_TEAM_NAME_VILLAINS _T("Villains") + +// StatsAdmin generated header file +#define SCTEST_KEY_HEADER_VERSION 10001 + +#define SCTEST_KEY_MAPNAME 1035 +#define SCTEST_KEY_GAMETYPE 1036 +#define SCTEST_KEY_GAMEVER 1037 +#define SCTEST_KEY_HOSTNAME 1038 +#define SCTEST_KEY_WINNINGTEAM 1039 +#define SCTEST_KEY_CUSTOM_MAP 1040 +#define SCTEST_KEY_ROUND_TIME 1041 + +#define SCTEST_KEY_PLAYER_FRAGS 1029 +#define SCTEST_KEY_PLAYER_SCORE 1030 +#define SCTEST_KEY_PLAYER_DEATHS 1032 +#define SCTEST_KEY_PLAYER_SHOTS 1031 +#define SCTEST_KEY_PLAYER_TEAM 1033 +#define SCTEST_KEY_PLAYER_NICK 1034 + +#define SCTEST_KEY_TEAM_ID 1042 +#define SCTEST_KEY_TEAM_RANK 1043 +#define SCTEST_KEY_TEAM_NAME 1044 + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Some application settings, #defined for clarity +#define SCTEST_GAMENAME _T("gmtest") +#define SCTEST_GAME_ID 0 // assigned by GameSpy +#define SCTEST_GAME_VERSION _T("v1.0") +#define SLEEP_MS 100 + +#define TIMEOUT_MS 0 // use default + +#define INVALID_PTR ((void*)0xdeadc0de) + +#define SCTEST_NUM_TEAMS 2 +#define SCTEST_NUM_PLAYERS 2 + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Report keys, generated by the admin webpage at http://net.gamespy.com/ +/* +// - server keys +#define SC_KEY_HOSTNAME 0 +#define SC_KEY_MAPNAME 1 +// - player keys (one value for each player) +#define SC_KEY_FRAGS 2 +#define SC_KEY_DEATHS 3 +#define SC_KEY_SHOTS 4 +#define SC_KEY_SCORE 5 +*/ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This represents the player data structure in your game. +typedef struct SamplePlayerData +{ + // "Normal" game data + gsi_u32 mProfileId; + GSLoginCertificate mCertificate; + GSLoginPrivateData mPrivateData; + SCPeerCipher mPeerSendCipher[SCTEST_NUM_PLAYERS]; // for fast encryption + SCPeerCipher mPeerRecvCipher[SCTEST_NUM_PLAYERS]; // for fast decryption + + // Stats interface + SCInterfacePtr mStatsInterface; + + // Stats Report + SCReportPtr mReport; + // Stats related data + gsi_u8 mConnectionId[SC_CONNECTION_GUID_SIZE]; + gsi_u8 mStatsAuthdata[16]; + gsi_i32 mFrags; + gsi_i32 mScore; + gsi_i16 mDeaths; + gsi_i16 mShots; + gsi_u32 mTeam; + + // Obfuscated versions + SCHiddenData mHiddenFrags; + SCHiddenData mHiddenDeaths; + SCHiddenData mHiddenShots; + SCHiddenData mHiddenScore; +} SamplePlayerData; +static SamplePlayerData gPlayerData[SCTEST_NUM_PLAYERS]; + +// This represents the server (session) data in your game. +typedef struct SampleServerData +{ + // "Normal" server data + gsi_u32 mNumPlayers; + SCHiddenData mObfuscationSeed; // Starting value for SCHiddenData + + // Reported session data (You will likely report this to qr2 as well) + const gsi_char * mHostName; + const gsi_char * mMapName; + const gsi_char * mVersion; + int mWinningTeam; + int mGameType; + gsi_i8 mCustomMap; + float mRoundTime; + + // A simple way to block the sample's progress + gsi_u32 mWaitCount; + +} SampleServerData; +static SampleServerData gServerData; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Text equivalent of SCResult values, for debugging +char* SCResultStr[SCResultMax + 1] = +{ + "SCResult_NO_ERROR", + "SCResult_NO_AVAILABILITY_CHECK", + "SCResult_INVALID_PARAMETERS", + "SCResult_NOT_INITIALIZED", + "SCResult_CORE_NOT_INITIALIZED", + "SCResult_OUT_OF_MEMORY", + "SCResult_CALLBACK_PENDING", + "SCResult_HTTP_ERROR", + "SCResult_SERVER_ERROR", + "SCResult_RESPONSE_INVALID", + "SCResult_REPORT_INCOMPLETE", + "SCResult_REPORT_INVALID", + "SCResult_SUBMISSION_FAILED", + (char *)INVALID_PTR +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool isBackendAvailable() +{ + // Do Availability Check - Make sure backend is available + ///////////////////////////////////////////////////////// + GSIACResult aResult = GSIACWaiting; + GSIStartAvailableCheck(SCTEST_GAMENAME); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + msleep(5); + } + + if (aResult == GSIACUnavailable) + { + printf("Online Services for sctest are no longer available\r\n"); + return gsi_false; + } + + if (aResult == GSIACTemporarilyUnavailable) + { + printf("Online Services for sctest are temporarily down for maintenance\r\n"); + return gsi_false; + } + + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void myLoginCallback(GHTTPResult httpResult, WSLoginResponse * theResponse, void * theUserData) +{ + if (httpResult != GHTTPSuccess) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, HTTP error: %d\r\n", httpResult); + getc(stdin); + exit(0); + } + else if (theResponse->mLoginResult != WSLogin_Success) + { + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, Login result: %d\r\n", theResponse->mLoginResult); + getc(stdin); + exit(0); + } + else + { + SamplePlayerData * newPlayer = NULL; + int playerIndex = (int)theUserData; + char playerNick[WS_LOGIN_NICK_LEN]; + + newPlayer = &gPlayerData[playerIndex]; + + // copy certificate and private key + newPlayer->mProfileId = theResponse->mCertificate.mProfileId; + memcpy(&newPlayer->mCertificate, &theResponse->mCertificate, sizeof(GSLoginCertificate)); + memcpy(&newPlayer->mPrivateData, &theResponse->mPrivateData, sizeof(GSLoginPrivateData)); + +#ifdef GSI_UNICODE + UCS2ToAsciiString(theResponse->mCertificate.mUniqueNick, playerNick); + printf("Player '%s' logged in.\r\n", playerNick); +#else + printf("Player '%s' logged in.\r\n", theResponse->mCertificate.mUniqueNick); + GSI_UNUSED(playerNick); +#endif + } + gServerData.mWaitCount--; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/*static void myPs3LoginCallback(GHTTPResult httpResult, WSLoginPs3CertResponse * theResponse, void * theUserData) +{ + if (httpResult != GHTTPSuccess) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, HTTP error: %d\r\n", httpResult); + getc(stdin); + exit(0); + } + else if (theResponse->mLoginResult != WSLogin_Success) + { + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, Login result: %d\r\n", theResponse->mLoginResult); + getc(stdin); + exit(0); + } + else + { + SamplePlayerData * newPlayer = NULL; + int playerIndex = (int)theUserData; + char playerNick[WS_LOGIN_NICK_LEN]; + + newPlayer = &gPlayerData[playerIndex]; + } + gServerData.mWaitCount--; +}*/ + + + +static void myPlayerLogin(gsi_u8 logintype, const gsi_char * nick, const gsi_char * password, int localPlayerNumber) +{ + gsi_u32 result; + + if (logintype == SCTEST_LOGIN_PROFILE) + { + if (0 != wsLoginProfile(SCTEST_LOGIN_PARTNERCODE, SCTEST_LOGIN_NAMESPACE, nick, SCTEST_EMAIL, password, _T(""), myLoginCallback, (void*)localPlayerNumber)) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginProfile\r\n"); + getc(stdin); + exit(0); + } + } + else if (logintype == SCTEST_LOGIN_UNIQUE) + { + result = wsLoginUnique(SCTEST_LOGIN_PARTNERCODE, SCTEST_LOGIN_NAMESPACE, nick, password, _T(""), myLoginCallback, (void*)localPlayerNumber); + if (result != WSLogin_Success) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginUnique. Result: %d\r\n", result); + getc(stdin); + exit(0); + } + } + else if (logintype == SCTEST_LOGIN_REMOTEAUTH) + { + result = wsLoginRemoteAuth(SCTEST_REMOTE_PARTNERCODE, SCTEST_REMOTE_NAMESPACEID, nick, password, myLoginCallback, (void*)localPlayerNumber); + if (result != WSLogin_Success) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginUnique. Result: %d\r\n", result); + getc(stdin); + exit(0); + } + } + + + /*result = wsLoginPs3Cert(0, 19, 28, + "IQAAAAAAAPAwAACkAAgAFJM+TMa5EdVMnN4uVUeVHCBFZWMTAAEABAAAAAEABwAIAAABDNXa36MABwAIAAABDNXtLXAAAgAIMkQh9jjX3f0ABAAgZ3NpLXNuYWRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAEdXMAAQAEAARhMAAAAAgAGFNDRUktWFgtWFRDTTAwMDAzLTAwAAAAAAABAARqAAAAAAAAAAAAAAAwAgBEAAgABFoOxO8ACAA4MDUCGQDoMjq/8ZeDFo0Bdo7FPBmAFoWLEzJHbRgCGGX88UQim5OJqDzp7N048ZBmjZcS7xP0dQA=", + strlen("IQAAAAAAAPAwAACkAAgAFJM+TMa5EdVMnN4uVUeVHCBFZWMTAAEABAAAAAEABwAIAAABDNXa36MABwAIAAABDNXtLXAAAgAIMkQh9jjX3f0ABAAgZ3NpLXNuYWRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAEdXMAAQAEAARhMAAAAAgAGFNDRUktWFgtWFRDTTAwMDAzLTAwAAAAAAABAARqAAAAAAAAAAAAAAAwAgBEAAgABFoOxO8ACAA4MDUCGQDoMjq/8ZeDFo0Bdo7FPBmAFoWLEzJHbRgCGGX88UQim5OJqDzp7N048ZBmjZcS7xP0dQA="), + myPs3LoginCallback, (void*)localPlayerNumber); + + if (result != WSLogin_Success) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginPs3Cert. Result: %d\r\n", result); + getc(stdin); + exit(0); + }*/ + + // wait for it to complete + gServerData.mWaitCount++; + while(gServerData.mWaitCount > 0) + { + msleep(SLEEP_MS); + gsCoreThink(0); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Update obfuscated verification data +static void myUpdateHiddenData(SCHiddenData theDataField, gsi_u32 theAmount) +{ + // TODO: Choice of algorithm for obfuscation + double data; + + memcpy(&data, theDataField, sizeof(double)); + data += (double)theAmount; + memcpy(theDataField, &data, sizeof(double)); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Setup player structure, initial obfuscated verification data +static void myRecordPlayerJoined(gsi_u32 theProfileId, + gsi_u32 theTeamId) +{ + SamplePlayerData* newPlayer = &gPlayerData[gServerData.mNumPlayers]; + newPlayer->mProfileId = theProfileId; + newPlayer->mTeam = theTeamId; + + newPlayer->mFrags = 0; + newPlayer->mDeaths = 0; + newPlayer->mScore = 0; + newPlayer->mShots = 0; + + // Initialize obfuscation data + // TODO: dervice obfuscation seed in a way that prevents copying between variables + memcpy(newPlayer->mHiddenFrags, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + memcpy(newPlayer->mHiddenDeaths, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + memcpy(newPlayer->mHiddenScore, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + memcpy(newPlayer->mHiddenShots, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + + gServerData.mNumPlayers++; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment player kills/deaths and transform obfuscated verification data +// For obfuscation purposes, it's best if this happens as part of +// a larger function which updates game state. +static void myRecordPlayerFrag(gsi_u32 theFraggerId, + gsi_u32 theFraggedId) +{ + unsigned int i=0; + for (i=0; i < gServerData.mNumPlayers; i++) + { + // Score a kill for the fragger + if (gPlayerData[i].mProfileId == theFraggerId) + { + gPlayerData[i].mFrags++; + myUpdateHiddenData(gPlayerData[i].mHiddenFrags, 1); + } + // Scor a death for the fragged + if (gPlayerData[i].mProfileId == theFraggedId) + { + gPlayerData[i].mDeaths++; + myUpdateHiddenData(gPlayerData[i].mHiddenFrags, 1); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment player score and transform obfuscated verification data +// For obfuscation purposes, it's best if this happens as part of +// a larger function which updates game state. +static void myRecordPlayerScored(gsi_u32 thePid, + gsi_u32 theScore) +{ + unsigned int i=0; + for (i=0; i < gServerData.mNumPlayers; i++) + { + // Add to player's score + if (gPlayerData[i].mProfileId == thePid) + { + gPlayerData[i].mScore += theScore; + myUpdateHiddenData(gPlayerData[i].mHiddenScore, theScore); + return; + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment player shots and transform obfuscated verification data +// For obfuscation purposes, it's best if this happens as part of +// a larger function which updates game state. +static void myRecordPlayerFiredGun(gsi_u32 thePid) +{ + unsigned int i=0; + for (i=0; i < gServerData.mNumPlayers; i++) + { + // Add to player's shots + if (gPlayerData[i].mProfileId == thePid) + { + gPlayerData[i].mShots++; + myUpdateHiddenData(gPlayerData[i].mHiddenShots, 1); + return; + } + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to get a random integer +static int myGetRandomInt(int theMax) +{ + return (int)((float)rand()/RAND_MAX*theMax); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to get a random player +// Used by the sample to introduce some variation in results +static gsi_u32 myGetRandomPlayerId(gsi_u32 excludedId) +{ + int aPlayerIndex = 0; + + do + { + float randomNum = (float)rand() / RAND_MAX; + aPlayerIndex = (int)(randomNum*SCTEST_NUM_PLAYERS); + } + while(gPlayerData[aPlayerIndex].mProfileId == excludedId); + + return gPlayerData[aPlayerIndex].mProfileId; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to block until a request completes +// Used to simplify the logic flow of the sample +static void myWaitForCallbacks(SCInterfacePtr theInterface, int howMany) +{ + // wait for the request to complete + gServerData.mWaitCount = (gsi_u32)howMany; + while (gServerData.mWaitCount > 0) + { + msleep(SLEEP_MS); + scThink(theInterface); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This will be triggered when scCreateSession() has completed. +// Expected to occur once per reported game session. +void createSessionCallback(SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "CreateSessionCallback: theHttpResult = %d, theResult = %s\r\n", theHttpResult, SCResultStr[theResult]); + + + if (theHttpResult == GHTTPSuccess && theResult == SCResult_NO_ERROR) + { + const char * sessionId = scGetSessionId(theInterface); + const char * connectionId = scGetConnectionId(theInterface); + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Session ID: %s\r\n", sessionId); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Connection ID: %s\r\n", connectionId); + GSI_UNUSED(sessionId); + GSI_UNUSED(connectionId); + } + + gServerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This will be triggered when scSetReportIntention() has completed. +// Expected to occur once per reported game session. +void setReportIntentionCallback(SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + SamplePlayerData* thePlayer = (SamplePlayerData*)theUserData; + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "SetReportIntentionCallback: theHttpResult = %d, theResult = %s\r\n", theHttpResult, SCResultStr[theResult]); + + if (theHttpResult == GHTTPSuccess && theResult == SCResult_NO_ERROR) + { + const char * connectionId = scGetConnectionId(theInterface); + memcpy(thePlayer->mConnectionId, connectionId, SC_CONNECTION_GUID_SIZE); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Connection ID: %s\r\n", connectionId); + } + + gServerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This will be triggered when scSubmitReport() has completed +// Expected to occur once per call to scSetReportIntention +void submitReportCallback(SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "SubmitReportCallback: theHttpResult = %d, theResult = %s\r\n", theHttpResult, SCResultStr[theResult]); + + gServerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theHttpResult); + GSI_UNUSED(theResult); + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// CreateReportAndSubmit + +static gsi_bool CreateReportAndSubmit() +{ + int i, k; + SCResult aResult; + //////////////////////////////////////// + //////////////////////////////////////// + // Submit report + // This is a little hard to demonstrate since we are simulating four players. + // In a live application you would need to determine which players would + // submit data and when, depending on game specifics. + + // It's not as complicated as it may sound. + // - For late entry games, this will likely occur after each map rotation + // - For coordinated entry, this will likely occur once for each player eliminated + // + // Build the report + // Note that the order for global, player, and team data matters + for (i = 0; i < SCTEST_NUM_PLAYERS; i++) + { + aResult = scCreateReport(gPlayerData[i].mStatsInterface, SCTEST_KEY_HEADER_VERSION, SCTEST_NUM_PLAYERS, SCTEST_NUM_TEAMS, &gPlayerData[i].mReport); + if (aResult != SCResult_NO_ERROR) + { + // NOT GOOD ENOUGH, need to cleanup the SDK after failures + //return gsi_false; // out of memory? + return gsi_false; + } + + // Non-player data + scReportBeginGlobalData(gPlayerData[i].mReport); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_MAPNAME, gServerData.mMapName); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_GAMETYPE, gServerData.mGameType); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_GAMEVER, gServerData.mVersion); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_HOSTNAME, gServerData.mHostName); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_WINNINGTEAM, SCTEST_KEY_TEAM_ARENAID_HEROES); + + // test float and byte values + scReportAddFloatValue(gPlayerData[i].mReport, SCTEST_KEY_ROUND_TIME, gServerData.mRoundTime); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_CUSTOM_MAP, gServerData.mCustomMap); + + // Player data + scReportBeginPlayerData(gPlayerData[i].mReport); + for (k=0; k < SCTEST_NUM_PLAYERS; k++) + { + SCGameResult playersGameResult; + + if (gPlayerData[k].mTeam == SCTEST_KEY_TEAM_ARENAID_HEROES) + playersGameResult = SCGameResult_WIN; // team 0 always wins + else + playersGameResult = SCGameResult_LOSS; // team 1 loses (so sorry!) + scReportBeginNewPlayer(gPlayerData[i].mReport); + scReportSetPlayerData(gPlayerData[i].mReport, (gsi_u32)k, gPlayerData[k].mConnectionId, gPlayerData[k].mTeam, + playersGameResult, gPlayerData[k].mProfileId, &gPlayerData[k].mCertificate, gPlayerData[k].mStatsAuthdata); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_NICK, gPlayerData[k].mCertificate.mUniqueNick); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_FRAGS, gPlayerData[k].mFrags); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_SCORE, gPlayerData[k].mScore); + scReportAddShortValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_SHOTS, gPlayerData[k].mShots); + scReportAddShortValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_DEATHS, gPlayerData[k].mDeaths); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_TEAM, (gsi_i32)gPlayerData[k].mTeam); + } + + // Team data + scReportBeginTeamData(gPlayerData[i].mReport); + + scReportBeginNewTeam(gPlayerData[i].mReport); + scReportSetTeamData(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ARENAID_HEROES, SCGameResult_WIN); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ID, SCTEST_KEY_TEAM_ARENAID_HEROES); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_RANK, SCTEST_TEAMRANK_HEROES); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_NAME, SCTEST_KEY_TEAM_NAME_HEROES); + + + scReportBeginNewTeam(gPlayerData[i].mReport); + scReportSetTeamData(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ARENAID_VILLAINS, SCGameResult_LOSS); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ID, SCTEST_KEY_TEAM_ARENAID_VILLAINS); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_RANK, SCTEST_TEAMRANK_VILLAINS); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_NAME, SCTEST_KEY_TEAM_NAME_VILLAINS); + + scReportEnd(gPlayerData[i].mReport, (i==0)?gsi_true:gsi_false, SCGameStatus_COMPLETE); + + // Submit the report + aResult = scSubmitReport(gPlayerData[i].mStatsInterface, gPlayerData[i].mReport, + (i==0)?gsi_true:gsi_false, &gPlayerData[i].mCertificate, &gPlayerData[i].mPrivateData, + submitReportCallback, TIMEOUT_MS, NULL); + if (SCResult_NO_ERROR != aResult) + { + // error, failed to submit report + return gsi_false; + } + myWaitForCallbacks(gPlayerData[i].mStatsInterface,1); + } + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This runs all the tests +static gsi_bool RunTests(gsi_u8 loginMethod, gsi_bool isLoginOnly) +{ + //SCReportPtr aReport = NULL; + SCResult aResult = SCResult_NO_ERROR; + int i=0, k=0, j=0; + + // Clear sample data + memset(&gServerData, 0, sizeof(gServerData)); + memset(gPlayerData, 0, sizeof(gPlayerData)); + + // Initialize SDK core/common objects for both the auth service and + // the Competition SDK + gsCoreInitialize(); + + + // Override service URLs for debugging? + //strcpy(wsAuthServiceURL, "http://*****/AuthService/AuthService.asmx"); + //strcpy(scServiceURL, "http://*****/CompetitionService/CompetitionService.asmx"); + + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + // Obtain a certificate for each local player. + // - For the sample, all player's are local. + + // Switch up login modes as necessary for testing the authservice + if (loginMethod == SCTEST_LOGIN_REMOTEAUTH) + { + myPlayerLogin(SCTEST_LOGIN_REMOTEAUTH, SCTEST_TOKEN_1, SCTEST_CHALLENGE_1, 0); + myPlayerLogin(SCTEST_LOGIN_REMOTEAUTH, SCTEST_TOKEN_2, SCTEST_CHALLENGE_2, 1); + } + else if (loginMethod == SCTEST_LOGIN_UNIQUE) + { + myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_1, SCTEST_PASSWORD, 0); + myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_2, SCTEST_PASSWORD, 1); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_3, SCTEST_PASSWORD, 2); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_4, SCTEST_PASSWORD, 3); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_5, SCTEST_PASSWORD, 4); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_6, SCTEST_PASSWORD, 5); + } + else if (loginMethod == SCTEST_LOGIN_PROFILE) + { + myPlayerLogin(SCTEST_LOGIN_PROFILE, SCTEST_NICK_1, SCTEST_PASSWORD, 0); + myPlayerLogin(SCTEST_LOGIN_PROFILE, SCTEST_NICK_2, SCTEST_PASSWORD, 1); + } + + + if (!isLoginOnly) + { + // Initialize the SDK + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + aResult = scInitialize(SCTEST_GAME_ID, &gPlayerData[i].mStatsInterface); + if (aResult != SCResult_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "scInitialize returned %s\r\n", SCResultStr[aResult]); + + return gsi_false; + } + } + + + //////////////////////////////////////// + //////////////////////////////////////// + // Simulate peer-to-peer authentication + // You can have the server validate each client. + // You may have each client validate every other. + // Certificates may also be used to exchange keys for encrypting game traffic. + // + // Step1 - Trade certificates using unsecured game socket. (The sample doesn't do this) + // Step2 - Verify certificate is authentic using wsLoginCertIsValid + // Step3 - Verify that the guy who gave you the certificate actually owns it + + // Step1 - skipped. + // - The usual scenario is to have the host verify the client certificate when the player joins. + + // Step2 - validate certificates + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + if (gsi_is_false(wsLoginCertIsValid(&gPlayerData[i].mCertificate))) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Error validating certificate for player %d!\r\n", i); + return gsi_false; + } + } + + // Step3 - exchange keys + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Generating encryption keys\r\n"); + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + for (k=i+1; k < SCTEST_NUM_PLAYERS; k++) + { + SCPeerKeyExchangeMsg exchangeMsg1; + SCPeerKeyExchangeMsg exchangeMsg2; + + const char * plainTextMsg = "Hello Secure!"; + char cipherMsg[32] = {'\0'}; + int msgLen = (int)strlen(plainTextMsg); + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, "Creating session keys for player pair %d <-> %d\r\n", i, k); + + // Each player should create a key for receiving data from the remote player + // For extra security, we use a different encryption key for each channel + scPeerCipherInit(&gPlayerData[i].mCertificate, &gPlayerData[i].mPeerRecvCipher[k]); // 'i' to receive data from 'k' + scPeerCipherInit(&gPlayerData[k].mCertificate, &gPlayerData[k].mPeerRecvCipher[i]); // 'k' to receive data from 'i' + + // Create a key exchange message for transmitting the key to the other player + scPeerCipherCreateKeyExchangeMsg(&gPlayerData[k].mCertificate, &gPlayerData[i].mPeerRecvCipher[k], exchangeMsg1); // from 'i', encrypted with 'k' public key + scPeerCipherCreateKeyExchangeMsg(&gPlayerData[i].mCertificate, &gPlayerData[k].mPeerRecvCipher[i], exchangeMsg2); // from 'k', encrypted with 'i' public key + + // Send it (using game network layer) + // - sample doesn't need to send b/c all player's are local + + // Receiving player should parse the key out of it. + // - decrypting the msg requires the local player's private data + scPeerCipherParseKeyExchangeMsg(&gPlayerData[k].mCertificate, &gPlayerData[k].mPrivateData, + exchangeMsg1, &gPlayerData[k].mPeerSendCipher[i]); // 'k' to send data to 'i' + scPeerCipherParseKeyExchangeMsg(&gPlayerData[i].mCertificate, &gPlayerData[i].mPrivateData, + exchangeMsg2, &gPlayerData[i].mPeerSendCipher[k]); // 'i' to send data to 'k' + + // Now we can send secure data by using the (fast) encryption and decryption functions + // - Encrypts and Decrypts in place + strcpy(cipherMsg, plainTextMsg); + scPeerCipherEncryptBufferIV(&gPlayerData[i].mPeerSendCipher[k], 1, (gsi_u8*)cipherMsg, (gsi_u32)msgLen); // 'i' sending to 'k' + scPeerCipherDecryptBufferIV(&gPlayerData[k].mPeerRecvCipher[i], 1, (gsi_u8*)cipherMsg, (gsi_u32)msgLen); // 'k' receiving from 'i' + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + // Host creates session + // Remember that everyone is on the same machine, so the + // first player's login certificate and private data are + // used to create a session + + scCreateSession(gPlayerData[0].mStatsInterface, &gPlayerData[0].mCertificate, &gPlayerData[0].mPrivateData, createSessionCallback, TIMEOUT_MS, NULL); + + myWaitForCallbacks(gPlayerData[0].mStatsInterface, 1); + + // The host can now set his connection ID + strcpy((char *)gPlayerData[0].mConnectionId, scGetConnectionId(gPlayerData[0].mStatsInterface)); + + // In most cases the host also has the "authoritative" game view + // For this game + scSetReportIntention(gPlayerData[0].mStatsInterface, NULL, gsi_true, &gPlayerData[0].mCertificate, + &gPlayerData[0].mPrivateData, setReportIntentionCallback, TIMEOUT_MS, &gPlayerData[0]); + + myWaitForCallbacks(gPlayerData[0].mStatsInterface, 1); + + for (j=1; j= 10) + myRecordPlayerFrag(aShooterId, aShooteeId); + } + + // some random point values + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + myRecordPlayerScored(gPlayerData[i].mProfileId, (gsi_u32)myGetRandomInt(100)); + + + if (!CreateReportAndSubmit()) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Failed to Create or Submit one of the Reports\r\n"); + } + //////////////////////////////////////// + //////////////////////////////////////// + // Game Over + // exit + // - or - + // clear user data + // goto start (for new map, round etc) + + // Cleanup + //scDestroyReport(aReport); + //aReport = NULL; + + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + if (gPlayerData[i].mReport) + { + scDestroyReport(gPlayerData[i].mReport); + gPlayerData[i].mReport= NULL; + } + if (gPlayerData[i].mStatsInterface) + { + scShutdown(gPlayerData[i].mStatsInterface); + gPlayerData[i].mStatsInterface = NULL; + } + } + } + + gsCoreShutdown(); + + // Wait for core shutdown + // (should be instantaneous unless you have multiple cores) + while(gsCoreIsShutdown() == GSCore_SHUTDOWN_PENDING) + { + gsCoreThink(0); + msleep(5); + } + + GSI_UNUSED(SCResultStr); + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_WIN32) && !defined(_XBOX) && defined(_DEBUG) +#include +#endif + +int test_main(int argc, char *argv[]) +{ + gsi_bool result; + + // Set debug output options + //gsSetDebugFile(stdout); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Debug); + + // enable Win32 C Runtime debugging + #if defined(_WIN32) && !defined(_XBOX) && defined(_DEBUG) + { + int tempFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + _CrtSetDbgFlag(tempFlag | _CRTDBG_LEAK_CHECK_DF); + } + #endif + + if (!isBackendAvailable()) + return -1; + + + result = RunTests(SCTEST_LOGIN_UNIQUE, gsi_false); + + + // For Testing AuthService logins w/o submitting snapshots + ////////////////////////////////////////////////////////// + /*gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_None); + printf("=== Testing wsLoginProfile === \n"); + result = RunTests(SCTEST_LOGIN_PROFILE, gsi_true); + printf("=== Testing wsLoginRemoteAuth === \n"); + result = RunTests(SCTEST_LOGIN_REMOTEAUTH, gsi_true);*/ + + +#if defined(_WIN32) && !defined(_XBOX) && defined (_UNIX) + fflush(stderr); + printf("Done - Press Enter\r\n"); + fflush(stdout); + getc(stdin); +#else + printf("Done.\r\n"); +#endif + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + return gsi_is_true(result)?0:-1; +} diff --git a/xrGameSpy/gamespy/sc/sctest/sctest.dsp b/xrGameSpy/gamespy/sc/sctest/sctest.dsp new file mode 100644 index 00000000000..a09da3169e0 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/sctest.dsp @@ -0,0 +1,488 @@ +# Microsoft Developer Studio Project File - Name="sctest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=sctest - Win32 Unicode 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 "sctest.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 "sctest.mak" CFG="sctest - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sctest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "sctest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "sctest - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "sctest - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sctest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /GX /O2 /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "sctest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HTTP_LOG" /D "GSI_COMMON_DEBUG" /FR /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "sctest - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "sctest___Win32_Unicode_Debug0" +# PROP BASE Intermediate_Dir "sctest___Win32_Unicode_Debug0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "sctest___Win32_Unicode_Debug0" +# PROP Intermediate_Dir "sctest___Win32_Unicode_Debug0" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /Gm /GX /ZI /Od /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HTTP_LOG" /D "GSI_COMMON_DEBUG" /FR /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HTTP_LOG" /D "GSI_COMMON_DEBUG" /D "GSI_UNICODE" /FR /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "sctest - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "sctest___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "sctest___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "sctest___Win32_Unicode_Release" +# PROP Intermediate_Dir "sctest___Win32_Unicode_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /GX /O2 /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /GX /O2 /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ENDIF + +# Begin Target + +# Name "sctest - Win32 Release" +# Name "sctest - Win32 Debug" +# Name "sctest - Win32 Unicode Debug" +# Name "sctest - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sctest.c + +!IF "$(CFG)" == "sctest - Win32 Release" + +!ELSEIF "$(CFG)" == "sctest - Win32 Debug" + +# SUBTRACT CPP /WX + +!ELSEIF "$(CFG)" == "sctest - Win32 Unicode Debug" + +# SUBTRACT BASE CPP /WX +# SUBTRACT CPP /WX + +!ELSEIF "$(CFG)" == "sctest - Win32 Unicode Release" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "GOA" + +# PROP Default_Filter "" +# Begin Group "SC" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc.h +# End Source File +# Begin Source File + +SOURCE=..\sci.h +# End Source File +# Begin Source File + +SOURCE=..\sciInterface.c +# End Source File +# Begin Source File + +SOURCE=..\sciInterface.h +# End Source File +# Begin Source File + +SOURCE=..\sciMain.c +# End Source File +# Begin Source File + +SOURCE=..\sciReport.c +# End Source File +# Begin Source File + +SOURCE=..\sciReport.h +# End Source File +# Begin Source File + +SOURCE=..\sciSerialize.c +# End Source File +# Begin Source File + +SOURCE=..\sciSerialize.h +# End Source File +# Begin Source File + +SOURCE=..\sciWebServices.c +# End Source File +# Begin Source File + +SOURCE=..\sciWebServices.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\nonport.h +# End Source File +# End Group +# Begin Group "ghttp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "webservices" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\webservices\AuthService.c +# End Source File +# Begin Source File + +SOURCE=..\..\webservices\AuthService.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/sc/sctest/sctest_vs2005.vcproj b/xrGameSpy/gamespy/sc/sctest/sctest_vs2005.vcproj new file mode 100644 index 00000000000..95e9a046a72 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/sctest_vs2005.vcproj @@ -0,0 +1,2292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctest/sctest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/sc/sctest/sctest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/sctest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/sc/sctest/scx360/scx360.sln b/xrGameSpy/gamespy/sc/sctest/scx360/scx360.sln new file mode 100644 index 00000000000..65bc4b0d81c --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scx360/scx360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scx360", "scx360.vcproj", "{947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {947A260C-9AD4-4BF7-8DCC-93181DD2F6C7}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctest/scx360/scx360.vcproj b/xrGameSpy/gamespy/sc/sctest/scx360/scx360.vcproj new file mode 100644 index 00000000000..d25aba047fe --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctest/scx360/scx360.vcproj @@ -0,0 +1,716 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/sclinux/Makefile b/xrGameSpy/gamespy/sc/sctestmatchless/sclinux/Makefile new file mode 100644 index 00000000000..722762200c4 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/sclinux/Makefile @@ -0,0 +1,74 @@ +# Competition SDK Makefile +# Copyright 2007 GameSpy Industries + +PROJECT=scmatchlesslinux + +CC=gcc +BASE_CFLAGS=-D_LINUX -DGSI_COMMON_DEBUG -D_DEBUG -DGSI_NO_THREADS + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 + +#use these when debugging +DEBUG_CFLAGS=$(BASE_CFLAGS) -g -lpthread -march=i486 -O6 + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCore.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../../common/gsSoap.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../webservices/AuthService.o\ + ../../sciInterface.o\ + ../../sciMain.o\ + ../../sciReport.o\ + ../../sciSerialize.o\ + ../../sciWebServices.o\ + ../sctestmatchless.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# +ghttp_debug: $(PROG_OBJS) + $(CC) $(DEBUG_CFLAGS) -o $@ $(PROG_OBJS) + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scmacosx/Makefile b/xrGameSpy/gamespy/sc/sctestmatchless/scmacosx/Makefile new file mode 100644 index 00000000000..1e79494b2d9 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scmacosx/Makefile @@ -0,0 +1,47 @@ +# Competition SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=sctestmatchless + +DEFINES=-D_MACOSX -DGSI_NO_THREADS + +PROG_OBJS = \ + ../../../md5c.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAssert.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsCore.o\ + ../../../common/gsDebug.o\ + ../../../common/gsCrypt.o\ + ../../../common/gsLargeInt.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsMemory.o\ + ../../../common/gsXML.o\ + ../../../common/gsSHA1.o\ + ../../../common/gsRC4.o\ + ../../../common/gsSSL.o\ + ../../../common/gsSoap.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../ghttp/ghttpBuffer.o\ + ../../../ghttp/ghttpCallbacks.o\ + ../../../ghttp/ghttpConnection.o\ + ../../../ghttp/ghttpEncryption.o\ + ../../../ghttp/ghttpMain.o\ + ../../../ghttp/ghttpProcess.o\ + ../../../ghttp/ghttpCommon.o\ + ../../../ghttp/ghttpPost.o\ + ../../../webservices/AuthService.o\ + ../../sciInterface.o\ + ../../sciMain.o\ + ../../sciReport.o\ + ../../sciSerialize.o\ + ../../sciWebServices.o\ + ../sctestmatchless.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/Nitro.lcf b/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/scnitrocw.mcp b/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/scnitrocw.mcp new file mode 100644 index 00000000000..02c8cfea4ef Binary files /dev/null and b/xrGameSpy/gamespy/sc/sctestmatchless/scnitrocw/scnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scps2prodg/scps2prodg.sln b/xrGameSpy/gamespy/sc/sctestmatchless/scps2prodg/scps2prodg.sln new file mode 100644 index 00000000000..7850f8f6b59 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scps2prodg/scps2prodg.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scps2prodg", "scps2prodg.vcproj", "{190F63A1-557A-4CAF-B92F-0C98884B422B}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = scps2prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EE Debug|Win32 = PS2 EE Debug|Win32 + PS2 EE Release|Win32 = PS2 EE Release|Win32 + PS2_INET_Debug|Win32 = PS2_INET_Debug|Win32 + PS2_INET_Release|Win32 = PS2_INET_Release|Win32 + PS2_SNSystems_Debug|Win32 = PS2_SNSystems_Debug|Win32 + PS2_SNSystems_Release|Win32 = PS2_SNSystems_Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Debug|Win32.ActiveCfg = PS2 EE Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Debug|Win32.Build.0 = PS2 EE Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Release|Win32.ActiveCfg = PS2 EE Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2 EE Release|Win32.Build.0 = PS2 EE Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Debug|Win32.ActiveCfg = PS2_INET_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Debug|Win32.Build.0 = PS2_INET_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Release|Win32.ActiveCfg = PS2_INET_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_INET_Release|Win32.Build.0 = PS2_INET_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Debug|Win32.ActiveCfg = PS2_SNSystems_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Debug|Win32.Build.0 = PS2_SNSystems_Debug|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Release|Win32.ActiveCfg = PS2_SNSystems_Release|Win32 + {190F63A1-557A-4CAF-B92F-0C98884B422B}.PS2_SNSystems_Release|Win32.Build.0 = PS2_SNSystems_Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scps2prodg/scps2prodg.vcproj b/xrGameSpy/gamespy/sc/sctestmatchless/scps2prodg/scps2prodg.vcproj new file mode 100644 index 00000000000..2c040591a5c --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scps2prodg/scps2prodg.vcproj @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scps3prodg/scps3prodg.sln b/xrGameSpy/gamespy/sc/sctestmatchless/scps3prodg/scps3prodg.sln new file mode 100644 index 00000000000..7fef92ee6cf --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scps3prodg/scps3prodg.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scps3prodg", "scps3prodg.vcproj", "{CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = scps3prodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {CF06BB72-0C4C-4596-B2AB-B00F10A7DA7C}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scps3prodg/scps3prodg.vcproj b/xrGameSpy/gamespy/sc/sctestmatchless/scps3prodg/scps3prodg.vcproj new file mode 100644 index 00000000000..b07b5bb6bf0 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scps3prodg/scps3prodg.vcproj @@ -0,0 +1,558 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scpspprodg/scpspprodg.sln b/xrGameSpy/gamespy/sc/sctestmatchless/scpspprodg/scpspprodg.sln new file mode 100644 index 00000000000..4360b4a4317 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scpspprodg/scpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scpspprodg", "scpspprodg.vcproj", "{71304287-4974-4E1B-8FC8-EE987BEBFB8A}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = scpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {71304287-4974-4E1B-8FC8-EE987BEBFB8A}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/scpspprodg/scpspprodg.vcproj b/xrGameSpy/gamespy/sc/sctestmatchless/scpspprodg/scpspprodg.vcproj new file mode 100644 index 00000000000..a08838b36cc --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/scpspprodg/scpspprodg.vcproj @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless.c b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless.c new file mode 100644 index 00000000000..2a9aec565f4 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless.c @@ -0,0 +1,1147 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "../../common/gsCommon.h" +#include "../../common/gsCore.h" +#include "../../common/gsAvailable.h" +#include "../../webservices/AuthService.h" +#include "../sc.h" + +#include + +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This sample simulates a stats implementation for a 1v1 game. +// +// For simplicity, all 2 players are run from one machine. +// 2 people use the auth service functions to login and get their certificates +// The SDK is initialized and the game creates a session using one of the +// player's certificate +// +// + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Player account information. (see GP documentation for account creation.) +#define SCTEST_LOGIN_PARTNERCODE 0 // gamespy account space +#define SCTEST_LOGIN_NAMESPACE 1 // shared namespace with unique nicknames + +#define SCTEST_REMOTE_PARTNERCODE 1 +#define SCTEST_REMOTE_NAMESPACEID 0 + +// Hardcoded information for four sample players +#define SCTEST_NICK_1 _T("sctest01") +#define SCTEST_NICK_2 _T("sctest02") +#define SCTEST_EMAIL _T("sctest@gamespy.com") +#define SCTEST_PASSWORD _T("gspy") + +#define SCTEST_TOKEN_1 _T("GMTy13lsJmiY7L19ojyN3XTM08ll0C4EWWijwmJyq3ttiZmoDUQJ0OSnar9nQCu5MpOGvi4Z0EcC2uNaS4yKrUA+h+tTDDoJHF7ZjoWKOTj00yNOEdzWyG08cKdVQwFRkF+h8oG/Jd+Ik3sWviXq/+5bhZQ7iXxTbbDwNL6Lagp/pLZ9czLnYPhY7VEcoQlx9oO") +#define SCTEST_CHALLENGE_1 _T("LH8c.DLe") +#define SCTEST_TOKEN_2 _T("GMTSc9Hl0VvG1FjqkCLkanABNB/u9jhNrQnXng6cQva0JtsJgEkwt6znjLDABAm3MmyEHDEcj6yZWwZmvPl1R8uEcJ0RW1OplewifmRhfU3dglMq3OP1VOgX6+lG0SoPwp9BLmka8O4JGiSTSq8jGuDyHnCBLVozMMpeYPJ3wGAuxrx2OlWdUe3PTNhFK/LeNBl") +#define SCTEST_CHALLENGE_2 _T("@WWm5DWI") + +#define SCTEST_LOGIN_PROFILE 0 +#define SCTEST_LOGIN_UNIQUE 1 +#define SCTEST_LOGIN_REMOTEAUTH 2 + +#define SCTEST_GAMETYPE_CTF 2 +#define SCTEST_GAMETYPE_DEATHMATCH 3 +#define SCTEST_TEAMRANK_HEROES 26 +#define SCTEST_TEAMRANK_VILLAINS 35 + +#define SCTEST_KEY_TEAM_TYPE_HEROES 0 +#define SCTEST_KEY_TEAM_TYPE_VILLAINS 1 + +#define SCTEST_KEY_TEAM_ARENAID_HEROES 7066 +#define SCTEST_KEY_TEAM_ARENAID_VILLAINS 7067 +#define SCTEST_KEY_TEAM_NAME_HEROES _T("Heroes") +#define SCTEST_KEY_TEAM_NAME_VILLAINS _T("Villains") + +// StatsAdmin generated header file +// NOTE: not all keys are used +#define SCTEST_KEY_HEADER_VERSION 20001 + +#define FIRAXIS_FFA_PLACE 1 // [TYPE: byte] +#define FIRAXIS_GAMETYPE_1V1 2 // [TYPE: byte] +#define FIRAXIS_GAMETYPE_2V2 3 // [TYPE: byte] +#define FIRAXIS_GAMETYPE_FFA 4 // [TYPE: byte] +#define SCTEST_KEY_CUSTOM_MAP 5 // [TYPE: byte] +#define SCTEST_KEY_GAMETYPE 6 // [TYPE: byte] +#define SCTEST_KEY_GAMEVER 7 // [TYPE: string] +#define SCTEST_KEY_HOSTNAME 8 // [TYPE: string] +#define SCTEST_KEY_MAPNAME 9 // [TYPE: string] +#define SCTEST_KEY_PLAYER_DEATHS 10 // [TYPE: short] +#define SCTEST_KEY_PLAYER_FRAGS 11 // [TYPE: int] +#define SCTEST_KEY_PLAYER_NICK 12 // [TYPE: string] +#define SCTEST_KEY_PLAYER_SCORE 13 // [TYPE: int] +#define SCTEST_KEY_PLAYER_SHOTS 14 // [TYPE: int] +#define SCTEST_KEY_PLAYER_TEAM 15 // [TYPE: int] +#define SCTEST_KEY_PLAYER_TIME 16 // [TYPE: float] +#define SCTEST_KEY_ROUND_TIME 17 // [TYPE: int] [DESC: The amount of time spent in one session] +#define SCTEST_KEY_TEAM_ID 18 // [TYPE: int] +#define SCTEST_KEY_TEAM_NAME 19 // [TYPE: string] +#define SCTEST_KEY_TEAM_RANK 20 // [TYPE: byte] +#define SCTEST_KEY_WINNINGTEAM 21 // [TYPE: int] [DESC: the team that won the round] +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Some application settings, #defined for clarity +#define SCTEST_GAMENAME _T("gmtest") +#define SCTEST_GAME_ID 0 // assigned by GameSpy +#define SCTEST_GAME_VERSION _T("v1.0") +#define SLEEP_MS 100 + +#define TIMEOUT_MS 0 // use default + +#define INVALID_PTR ((void*)0xdeadc0de) + +#define SCTEST_NUM_TEAMS 2 +#define SCTEST_NUM_PLAYERS 2 + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Report keys, generated by the admin webpage at http://net.gamespy.com/ +/* +// - server keys +#define SC_KEY_HOSTNAME 0 +#define SC_KEY_MAPNAME 1 +// - player keys (one value for each player) +#define SC_KEY_FRAGS 2 +#define SC_KEY_DEATHS 3 +#define SC_KEY_SHOTS 4 +#define SC_KEY_SCORE 5 +*/ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This represents the player data structure in your game. +typedef struct SamplePlayerData +{ + // "Normal" game data + gsi_u32 mProfileId; + GSLoginCertificate mCertificate; + GSLoginPrivateData mPrivateData; + SCPeerCipher mPeerSendCipher[SCTEST_NUM_PLAYERS]; // for fast encryption + SCPeerCipher mPeerRecvCipher[SCTEST_NUM_PLAYERS]; // for fast decryption + + // Stats interface + SCInterfacePtr mStatsInterface; + + // Stats Report + SCReportPtr mReport; + // Stats related data + gsi_u8 mConnectionId[SC_CONNECTION_GUID_SIZE]; + gsi_u8 mStatsAuthdata[16]; + gsi_i32 mFrags; + gsi_i32 mScore; + gsi_i16 mDeaths; + gsi_i16 mShots; + gsi_u32 mTeam; + + // Obfuscated versions + SCHiddenData mHiddenFrags; + SCHiddenData mHiddenDeaths; + SCHiddenData mHiddenShots; + SCHiddenData mHiddenScore; +} SamplePlayerData; +static SamplePlayerData gPlayerData[SCTEST_NUM_PLAYERS]; + +// This represents the server (session) data in your game. +typedef struct SampleServerData +{ + // "Normal" server data + gsi_u32 mNumPlayers; + SCHiddenData mObfuscationSeed; // Starting value for SCHiddenData + + // Reported session data (You will likely report this to qr2 as well) + const gsi_char * mHostName; + const gsi_char * mMapName; + const gsi_char * mVersion; + int mWinningTeam; + int mGameType; + gsi_i8 mCustomMap; + float mRoundTime; + + // A simple way to block the sample's progress + gsi_u32 mWaitCount; + +} SampleServerData; +static SampleServerData gServerData; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Text equivalent of SCResult values, for debugging +char* SCResultStr[SCResultMax + 1] = +{ + "SCResult_NO_ERROR", + "SCResult_NO_AVAILABILITY_CHECK", + "SCResult_INVALID_PARAMETERS", + "SCResult_NOT_INITIALIZED", + "SCResult_CORE_NOT_INITIALIZED", + "SCResult_OUT_OF_MEMORY", + "SCResult_CALLBACK_PENDING", + "SCResult_HTTP_ERROR", + "SCResult_SERVER_ERROR", + "SCResult_RESPONSE_INVALID", + "SCResult_REPORT_INCOMPLETE", + "SCResult_REPORT_INVALID", + "SCResult_SUBMISSION_FAILED", + (char *)INVALID_PTR +}; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_bool isBackendAvailable() +{ + // Do Availability Check - Make sure backend is available + ///////////////////////////////////////////////////////// + GSIACResult aResult = GSIACWaiting; + GSIStartAvailableCheck(SCTEST_GAMENAME); + while(aResult == GSIACWaiting) + { + aResult = GSIAvailableCheckThink(); + msleep(5); + } + + if (aResult == GSIACUnavailable) + { + printf("Online Services for sctest are no longer available\r\n"); + return gsi_false; + } + + if (aResult == GSIACTemporarilyUnavailable) + { + printf("Online Services for sctest are temporarily down for maintenance\r\n"); + return gsi_false; + } + + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void myLoginCallback(GHTTPResult httpResult, WSLoginResponse * theResponse, void * theUserData) +{ + if (httpResult != GHTTPSuccess) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, HTTP error: %d\r\n", httpResult); + getc(stdin); + exit(0); + } + else if (theResponse->mLoginResult != WSLogin_Success) + { + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, Login result: %d\r\n", theResponse->mLoginResult); + getc(stdin); + exit(0); + } + else + { + SamplePlayerData * newPlayer = NULL; + int playerIndex = (int)theUserData; + char playerNick[WS_LOGIN_NICK_LEN]; + + newPlayer = &gPlayerData[playerIndex]; + + // copy certificate and private key + newPlayer->mProfileId = theResponse->mCertificate.mProfileId; + memcpy(&newPlayer->mCertificate, &theResponse->mCertificate, sizeof(GSLoginCertificate)); + memcpy(&newPlayer->mPrivateData, &theResponse->mPrivateData, sizeof(GSLoginPrivateData)); + +#ifdef GSI_UNICODE + UCS2ToAsciiString(theResponse->mCertificate.mUniqueNick, playerNick); + printf("Player '%s' logged in.\r\n", playerNick); +#else + printf("Player '%s' logged in.\r\n", theResponse->mCertificate.mUniqueNick); + GSI_UNUSED(playerNick); +#endif + } + gServerData.mWaitCount--; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/*static void myPs3LoginCallback(GHTTPResult httpResult, WSLoginPs3CertResponse * theResponse, void * theUserData) +{ + if (httpResult != GHTTPSuccess) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, HTTP error: %d\r\n", httpResult); + getc(stdin); + exit(0); + } + else if (theResponse->mLoginResult != WSLogin_Success) + { + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on player login, Login result: %d\r\n", theResponse->mLoginResult); + getc(stdin); + exit(0); + } + else + { + SamplePlayerData * newPlayer = NULL; + int playerIndex = (int)theUserData; + char playerNick[WS_LOGIN_NICK_LEN]; + + newPlayer = &gPlayerData[playerIndex]; + } + gServerData.mWaitCount--; +}*/ + + + +static void myPlayerLogin(gsi_u8 logintype, const gsi_char * nick, const gsi_char * password, int localPlayerNumber) +{ + gsi_u32 result; + + if (logintype == SCTEST_LOGIN_PROFILE) + { + if (0 != wsLoginProfile(SCTEST_LOGIN_PARTNERCODE, SCTEST_LOGIN_NAMESPACE, nick, SCTEST_EMAIL, password, _T(""), myLoginCallback, (void*)localPlayerNumber)) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginProfile\r\n"); + getc(stdin); + exit(0); + } + } + else if (logintype == SCTEST_LOGIN_UNIQUE) + { + result = wsLoginUnique(SCTEST_LOGIN_PARTNERCODE, SCTEST_LOGIN_NAMESPACE, nick, password, _T(""), myLoginCallback, (void*)localPlayerNumber); + if (result != WSLogin_Success) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginUnique. Result: %d\r\n", result); + getc(stdin); + exit(0); + } + } + else if (logintype == SCTEST_LOGIN_REMOTEAUTH) + { + result = wsLoginRemoteAuth(SCTEST_REMOTE_PARTNERCODE, SCTEST_REMOTE_NAMESPACEID, nick, password, myLoginCallback, (void*)localPlayerNumber); + if (result != WSLogin_Success) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginUnique. Result: %d\r\n", result); + getc(stdin); + exit(0); + } + } + + + /*result = wsLoginPs3Cert(0, 19, 28, + "IQAAAAAAAPAwAACkAAgAFJM+TMa5EdVMnN4uVUeVHCBFZWMTAAEABAAAAAEABwAIAAABDNXa36MABwAIAAABDNXtLXAAAgAIMkQh9jjX3f0ABAAgZ3NpLXNuYWRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAEdXMAAQAEAARhMAAAAAgAGFNDRUktWFgtWFRDTTAwMDAzLTAwAAAAAAABAARqAAAAAAAAAAAAAAAwAgBEAAgABFoOxO8ACAA4MDUCGQDoMjq/8ZeDFo0Bdo7FPBmAFoWLEzJHbRgCGGX88UQim5OJqDzp7N048ZBmjZcS7xP0dQA=", + strlen("IQAAAAAAAPAwAACkAAgAFJM+TMa5EdVMnN4uVUeVHCBFZWMTAAEABAAAAAEABwAIAAABDNXa36MABwAIAAABDNXtLXAAAgAIMkQh9jjX3f0ABAAgZ3NpLXNuYWRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAEdXMAAQAEAARhMAAAAAgAGFNDRUktWFgtWFRDTTAwMDAzLTAwAAAAAAABAARqAAAAAAAAAAAAAAAwAgBEAAgABFoOxO8ACAA4MDUCGQDoMjq/8ZeDFo0Bdo7FPBmAFoWLEzJHbRgCGGX88UQim5OJqDzp7N048ZBmjZcS7xP0dQA="), + myPs3LoginCallback, (void*)localPlayerNumber); + + if (result != WSLogin_Success) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Failed on wsLoginPs3Cert. Result: %d\r\n", result); + getc(stdin); + exit(0); + }*/ + + // wait for it to complete + gServerData.mWaitCount++; + while(gServerData.mWaitCount > 0) + { + msleep(SLEEP_MS); + gsCoreThink(0); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Update obfuscated verification data +static void myUpdateHiddenData(SCHiddenData theDataField, gsi_u32 theAmount) +{ + // TODO: Choice of algorithm for obfuscation + double data; + + memcpy(&data, theDataField, sizeof(double)); + data += (double)theAmount; + memcpy(theDataField, &data, sizeof(double)); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Setup player structure, initial obfuscated verification data +static void myRecordPlayerJoined(gsi_u32 theProfileId, + gsi_u32 theTeamId) +{ + SamplePlayerData* newPlayer = &gPlayerData[gServerData.mNumPlayers]; + newPlayer->mProfileId = theProfileId; + newPlayer->mTeam = theTeamId; + + newPlayer->mFrags = 0; + newPlayer->mDeaths = 0; + newPlayer->mScore = 0; + newPlayer->mShots = 0; + + // Initialize obfuscation data + // TODO: dervice obfuscation seed in a way that prevents copying between variables + memcpy(newPlayer->mHiddenFrags, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + memcpy(newPlayer->mHiddenDeaths, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + memcpy(newPlayer->mHiddenScore, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + memcpy(newPlayer->mHiddenShots, gServerData.mObfuscationSeed, sizeof(newPlayer->mHiddenDeaths)); + + gServerData.mNumPlayers++; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment player kills/deaths and transform obfuscated verification data +// For obfuscation purposes, it's best if this happens as part of +// a larger function which updates game state. +static void myRecordPlayerFrag(gsi_u32 theFraggerId, + gsi_u32 theFraggedId) +{ + unsigned int i=0; + for (i=0; i < gServerData.mNumPlayers; i++) + { + // Score a kill for the fragger + if (gPlayerData[i].mProfileId == theFraggerId) + { + gPlayerData[i].mFrags++; + myUpdateHiddenData(gPlayerData[i].mHiddenFrags, 1); + } + // Scor a death for the fragged + if (gPlayerData[i].mProfileId == theFraggedId) + { + gPlayerData[i].mDeaths++; + myUpdateHiddenData(gPlayerData[i].mHiddenFrags, 1); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment player score and transform obfuscated verification data +// For obfuscation purposes, it's best if this happens as part of +// a larger function which updates game state. +static void myRecordPlayerScored(gsi_u32 thePid, + gsi_u32 theScore) +{ + unsigned int i=0; + for (i=0; i < gServerData.mNumPlayers; i++) + { + // Add to player's score + if (gPlayerData[i].mProfileId == thePid) + { + gPlayerData[i].mScore += theScore; + myUpdateHiddenData(gPlayerData[i].mHiddenScore, theScore); + return; + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Increment player shots and transform obfuscated verification data +// For obfuscation purposes, it's best if this happens as part of +// a larger function which updates game state. +static void myRecordPlayerFiredGun(gsi_u32 thePid) +{ + unsigned int i=0; + for (i=0; i < gServerData.mNumPlayers; i++) + { + // Add to player's shots + if (gPlayerData[i].mProfileId == thePid) + { + gPlayerData[i].mShots++; + myUpdateHiddenData(gPlayerData[i].mHiddenShots, 1); + return; + } + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to get a random integer +static int myGetRandomInt(int theMax) +{ + return (int)((float)rand()/RAND_MAX*theMax); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to get a random player +// Used by the sample to introduce some variation in results +static gsi_u32 myGetRandomPlayerId(gsi_u32 excludedId) +{ + int aPlayerIndex = 0; + + do + { + float randomNum = (float)rand() / RAND_MAX; + aPlayerIndex = (int)(randomNum*SCTEST_NUM_PLAYERS); + } + while(gPlayerData[aPlayerIndex].mProfileId == excludedId); + + return gPlayerData[aPlayerIndex].mProfileId; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// A utility to block until a request completes +// Used to simplify the logic flow of the sample +static void myWaitForCallbacks(SCInterfacePtr theInterface, int howMany) +{ + // wait for the request to complete + gServerData.mWaitCount = (gsi_u32)howMany; + while (gServerData.mWaitCount > 0) + { + msleep(SLEEP_MS); + scThink(theInterface); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This will be triggered when scCreateSession() has completed. +// Expected to occur once per reported game session. +void createSessionCallback(SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "CreateSessionCallback: theHttpResult = %d, theResult = %s\r\n", theHttpResult, SCResultStr[theResult]); + + + if (theHttpResult == GHTTPSuccess && theResult == SCResult_NO_ERROR) + { + const char * sessionId = scGetSessionId(theInterface); + const char * connectionId = scGetConnectionId(theInterface); + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Session ID: %s\r\n", sessionId); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Connection ID: %s\r\n", connectionId); + GSI_UNUSED(sessionId); + GSI_UNUSED(connectionId); + } + + gServerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This will be triggered when scSetReportIntention() has completed. +// Expected to occur once per reported game session. +void setReportIntentionCallback(SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + SamplePlayerData* thePlayer = (SamplePlayerData*)theUserData; + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "SetReportIntentionCallback: theHttpResult = %d, theResult = %s\r\n", theHttpResult, SCResultStr[theResult]); + + if (theHttpResult == GHTTPSuccess && theResult == SCResult_NO_ERROR) + { + const char * connectionId = scGetConnectionId(theInterface); + memcpy(thePlayer->mConnectionId, connectionId, SC_CONNECTION_GUID_SIZE); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Connection ID: %s\r\n", connectionId); + } + + gServerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This will be triggered when scSubmitReport() has completed +// Expected to occur once per call to scSetReportIntention +void submitReportCallback(SCInterfacePtr theInterface, + GHTTPResult theHttpResult, + SCResult theResult, + void * theUserData) +{ + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "SubmitReportCallback: theHttpResult = %d, theResult = %s\r\n", theHttpResult, SCResultStr[theResult]); + + gServerData.mWaitCount--; // one less request to wait for + + GSI_UNUSED(theHttpResult); + GSI_UNUSED(theResult); + GSI_UNUSED(theInterface); + GSI_UNUSED(theUserData); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// CreateReportAndSubmit + +static gsi_bool CreateReportAndSubmit() +{ + int i; + SCResult aResult; + //////////////////////////////////////// + //////////////////////////////////////// + // Submit report + // This is a little hard to demonstrate since we are simulating four players. + // In a live application you would need to determine which players would + // submit data and when, depending on game specifics. + + // It's not as complicated as it may sound. + // - For late entry games, this will likely occur after each map rotation + // - For coordinated entry, this will likely occur once for each player eliminated + // + // Build the report + // Note that the order for global, player, and team data matters + for (i = 0; i < SCTEST_NUM_PLAYERS; i++) + { + SCGameResult playersGameResult; + // Player reports results only for itself. + aResult = scCreateReport(gPlayerData[i].mStatsInterface, SCTEST_KEY_HEADER_VERSION, 1, 1, &gPlayerData[i].mReport); + if (aResult != SCResult_NO_ERROR) + { + //need to cleanup the SDK after failures + return gsi_false; + } + + // REQUIRED FOR MATCHLESS GAMES + // player joined a matchless game. + scReportSetAsMatchless(gPlayerData[i].mReport); + + // Non-player data + scReportBeginGlobalData(gPlayerData[i].mReport); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_MAPNAME, gServerData.mMapName); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_GAMETYPE, gServerData.mGameType); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_GAMEVER, gServerData.mVersion); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_HOSTNAME, gServerData.mHostName); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_WINNINGTEAM, SCTEST_KEY_TEAM_ARENAID_HEROES); + + // test float and byte values + scReportAddFloatValue(gPlayerData[i].mReport, SCTEST_KEY_ROUND_TIME, gServerData.mRoundTime); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_CUSTOM_MAP, gServerData.mCustomMap); + + // Player data + scReportBeginPlayerData(gPlayerData[i].mReport); + + if (gPlayerData[i].mTeam == SCTEST_KEY_TEAM_ARENAID_HEROES) + playersGameResult = SCGameResult_WIN; // team 0 always wins + else + playersGameResult = SCGameResult_LOSS; // team 1 loses (so sorry!) + scReportBeginNewPlayer(gPlayerData[i].mReport); + + // Remember to report the player's data in the 0th position + // otherwise the Competition System will treat the report as if there + // were no players in the report. + scReportSetPlayerData(gPlayerData[i].mReport, (gsi_u32)0, gPlayerData[i].mConnectionId, gPlayerData[i].mTeam, + playersGameResult, gPlayerData[i].mProfileId, &gPlayerData[i].mCertificate, gPlayerData[i].mStatsAuthdata); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_NICK, gPlayerData[i].mCertificate.mUniqueNick); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_FRAGS, gPlayerData[i].mFrags); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_SCORE, gPlayerData[i].mScore); + scReportAddShortValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_SHOTS, gPlayerData[i].mShots); + scReportAddShortValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_DEATHS, gPlayerData[i].mDeaths); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_TEAM, (gsi_i32)gPlayerData[i].mTeam); + + // Team data + scReportBeginTeamData(gPlayerData[i].mReport); + + // If player is on the winners team, report the winner team + // or report loosing team. + if ((i&1)==0) + { + scReportBeginNewTeam(gPlayerData[i].mReport); + scReportSetTeamData(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ARENAID_HEROES, SCGameResult_WIN); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ID, SCTEST_KEY_TEAM_ARENAID_HEROES); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_RANK, SCTEST_TEAMRANK_HEROES); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_NAME, SCTEST_KEY_TEAM_NAME_HEROES); + } + else + { + scReportBeginNewTeam(gPlayerData[i].mReport); + scReportSetTeamData(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ARENAID_VILLAINS, SCGameResult_LOSS); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ID, SCTEST_KEY_TEAM_ARENAID_VILLAINS); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_RANK, SCTEST_TEAMRANK_VILLAINS); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_NAME, SCTEST_KEY_TEAM_NAME_VILLAINS); + } + + // The setting of an authoritative report in matchless sessions should + // be ignored. It can be set to either gsi_true or gsi_false + scReportEnd(gPlayerData[i].mReport, gsi_false, SCGameStatus_COMPLETE); + + // Submit the report + // The setting of an authoritative report in matchless sessions should + // be ignored. It can be set to either gsi_true or gsi_false + aResult = scSubmitReport(gPlayerData[i].mStatsInterface, gPlayerData[i].mReport, + gsi_false, &gPlayerData[i].mCertificate, &gPlayerData[i].mPrivateData, + submitReportCallback, TIMEOUT_MS, NULL); + if (SCResult_NO_ERROR != aResult) + { + // error, failed to submit report + return gsi_false; + } + myWaitForCallbacks(gPlayerData[i].mStatsInterface,1); + // End of Submitting the report + } + + // The host would then send all other player's the Session ID generated when the session was created + // so that they can set their intentions, and retrieve the connection ID for report submissions + //scSetSessionId(gPlayerData[1].mStatsInterface, (const unsigned char *)scGetSessionId(gPlayerData[0].mStatsInterface)); + + scSetReportIntention(gPlayerData[1].mStatsInterface, (const gsi_u8 *)scGetConnectionId(gPlayerData[1].mStatsInterface), + gsi_false, &gPlayerData[1].mCertificate, &gPlayerData[1].mPrivateData, setReportIntentionCallback, + TIMEOUT_MS, &gPlayerData[1]); + + // store each connection id for the other players + //strcpy((char *)gPlayerData[j].mConnectionId, scGetConnectionId(gPlayerData[j].mStatsInterface)); + + // *NOTE* this is simply meant to show HOW this process works, in truth the connection id + // here is overwritten because it's using the same interface so it will report 4 of the same + // player information. We need to upgrade the sample to communicate with other instances + // in order to report individual player data + + myWaitForCallbacks(gPlayerData[1].mStatsInterface, 1); + + for (i = 1; i < SCTEST_NUM_PLAYERS; i++) + { + SCGameResult playersGameResult; + // Player reports results only for itself. + aResult = scCreateReport(gPlayerData[i].mStatsInterface, SCTEST_KEY_HEADER_VERSION, 1, 1, &gPlayerData[i].mReport); + if (aResult != SCResult_NO_ERROR) + { + //need to cleanup the SDK after failures + return gsi_false; + } + + // REQUIRED FOR MATCHLESS GAMES + // player joined a matchless game. + scReportSetAsMatchless(gPlayerData[i].mReport); + + // Non-player data + scReportBeginGlobalData(gPlayerData[i].mReport); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_MAPNAME, gServerData.mMapName); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_GAMETYPE, gServerData.mGameType); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_GAMEVER, gServerData.mVersion); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_HOSTNAME, gServerData.mHostName); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_WINNINGTEAM, SCTEST_KEY_TEAM_ARENAID_HEROES); + + // test float and byte values + scReportAddFloatValue(gPlayerData[i].mReport, SCTEST_KEY_ROUND_TIME, gServerData.mRoundTime); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_CUSTOM_MAP, gServerData.mCustomMap); + + // Player data + scReportBeginPlayerData(gPlayerData[i].mReport); + + if (gPlayerData[i].mTeam == SCTEST_KEY_TEAM_ARENAID_HEROES) + playersGameResult = SCGameResult_WIN; // team 0 always wins + else + playersGameResult = SCGameResult_LOSS; // team 1 loses (so sorry!) + scReportBeginNewPlayer(gPlayerData[i].mReport); + + // Remember to report the player's data in the 0th position + // otherwise the Competition System will treat the report as if there + // were no players in the report. + scReportSetPlayerData(gPlayerData[i].mReport, (gsi_u32)0, gPlayerData[i].mConnectionId, gPlayerData[i].mTeam, + playersGameResult, gPlayerData[i].mProfileId, &gPlayerData[i].mCertificate, gPlayerData[i].mStatsAuthdata); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_NICK, gPlayerData[i].mCertificate.mUniqueNick); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_FRAGS, gPlayerData[i].mFrags); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_SCORE, gPlayerData[i].mScore); + scReportAddShortValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_SHOTS, gPlayerData[i].mShots); + scReportAddShortValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_DEATHS, gPlayerData[i].mDeaths); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_PLAYER_TEAM, (gsi_i32)gPlayerData[i].mTeam); + + // Team data + scReportBeginTeamData(gPlayerData[i].mReport); + + // If player is on the winners team, report the winner team + // or report loosing team. + if ((i&1)==0) + { + scReportBeginNewTeam(gPlayerData[i].mReport); + scReportSetTeamData(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ARENAID_HEROES, SCGameResult_WIN); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ID, SCTEST_KEY_TEAM_ARENAID_HEROES); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_RANK, SCTEST_TEAMRANK_HEROES); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_NAME, SCTEST_KEY_TEAM_NAME_HEROES); + } + else + { + scReportBeginNewTeam(gPlayerData[i].mReport); + scReportSetTeamData(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ARENAID_VILLAINS, SCGameResult_LOSS); + scReportAddIntValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_ID, SCTEST_KEY_TEAM_ARENAID_VILLAINS); + scReportAddByteValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_RANK, SCTEST_TEAMRANK_VILLAINS); + scReportAddStringValue(gPlayerData[i].mReport, SCTEST_KEY_TEAM_NAME, SCTEST_KEY_TEAM_NAME_VILLAINS); + } + + // The setting of an authoritative report in matchless sessions should + // be ignored. It can be set to either gsi_true or gsi_false + scReportEnd(gPlayerData[i].mReport, gsi_false, SCGameStatus_COMPLETE); + + // Submit the report + // The setting of an authoritative report in matchless sessions should + // be ignored. It can be set to either gsi_true or gsi_false + aResult = scSubmitReport(gPlayerData[i].mStatsInterface, gPlayerData[i].mReport, + gsi_false, &gPlayerData[i].mCertificate, &gPlayerData[i].mPrivateData, + submitReportCallback, TIMEOUT_MS, NULL); + if (SCResult_NO_ERROR != aResult) + { + // error, failed to submit report + return gsi_false; + } + myWaitForCallbacks(gPlayerData[i].mStatsInterface,1); + // End of Submitting the report + } + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// This runs all the tests +static gsi_bool RunTests(gsi_u8 loginMethod, gsi_bool isLoginOnly) +{ + //SCReportPtr aReport = NULL; + SCResult aResult = SCResult_NO_ERROR; + int i=0, k=0, j=0; + + // Clear sample data + memset(&gServerData, 0, sizeof(gServerData)); + memset(gPlayerData, 0, sizeof(gPlayerData)); + + // Initialize SDK core/common objects for both the auth service and + // the Competition SDK + gsCoreInitialize(); + + + // Override service URLs for debugging? + //strcpy(wsAuthServiceURL, "http://mwstage.gamespy.com/AuthService/AuthService.asmx"); + //strcpy(scServiceURL, "http://mwstage.gamespy.com/CompetitionService/CompetitionService.asmx"); + + + //////////////////////////////////////////////// + //////////////////////////////////////////////// + // Obtain a certificate for each local player. + // - For the sample, all player's are local. + + // Switch up login modes as necessary for testing the authservice + if (loginMethod == SCTEST_LOGIN_REMOTEAUTH) + { + myPlayerLogin(SCTEST_LOGIN_REMOTEAUTH, SCTEST_TOKEN_1, SCTEST_CHALLENGE_1, 0); + myPlayerLogin(SCTEST_LOGIN_REMOTEAUTH, SCTEST_TOKEN_2, SCTEST_CHALLENGE_2, 1); + } + else if (loginMethod == SCTEST_LOGIN_UNIQUE) + { + myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_1, SCTEST_PASSWORD, 0); + myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_2, SCTEST_PASSWORD, 1); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_3, SCTEST_PASSWORD, 2); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_4, SCTEST_PASSWORD, 3); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_5, SCTEST_PASSWORD, 4); + //myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_6, SCTEST_PASSWORD, 5); + } + else if (loginMethod == SCTEST_LOGIN_PROFILE) + { + myPlayerLogin(SCTEST_LOGIN_PROFILE, SCTEST_NICK_1, SCTEST_PASSWORD, 0); + myPlayerLogin(SCTEST_LOGIN_PROFILE, SCTEST_NICK_2, SCTEST_PASSWORD, 1); + } + + + if (!isLoginOnly) + { + // Initialize the SDK + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + aResult = scInitialize(SCTEST_GAME_ID, &gPlayerData[i].mStatsInterface); + if (aResult != SCResult_NO_ERROR) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "scInitialize returned %s\r\n", SCResultStr[aResult]); + + return gsi_false; + } + } + + + //////////////////////////////////////// + //////////////////////////////////////// + // Simulate peer-to-peer authentication + // You can have the server validate each client. + // You may have each client validate every other. + // Certificates may also be used to exchange keys for encrypting game traffic. + // + // Step1 - Trade certificates using unsecured game socket. (The sample doesn't do this) + // Step2 - Verify certificate is authentic using wsLoginCertIsValid + // Step3 - Verify that the guy who gave you the certificate actually owns it + + // Step1 - skipped. + // - The usual scenario is to have the host verify the client certificate when the player joins. + + // Step2 - validate certificates + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + if (gsi_is_false(wsLoginCertIsValid(&gPlayerData[i].mCertificate))) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, + "Error validating certificate for player %d!\r\n", i); + return gsi_false; + } + } + + // Step3 - exchange keys + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Generating encryption keys\r\n"); + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + for (k=i+1; k < SCTEST_NUM_PLAYERS; k++) + { + SCPeerKeyExchangeMsg exchangeMsg1; + SCPeerKeyExchangeMsg exchangeMsg2; + + const char * plainTextMsg = "Hello Secure!"; + char cipherMsg[32] = {'\0'}; + int msgLen = (int)strlen(plainTextMsg); + + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, "Creating session keys for player pair %d <-> %d\r\n", i, k); + + // Each player should create a key for receiving data from the remote player + // For extra security, we use a different encryption key for each channel + scPeerCipherInit(&gPlayerData[i].mCertificate, &gPlayerData[i].mPeerRecvCipher[k]); // 'i' to receive data from 'k' + scPeerCipherInit(&gPlayerData[k].mCertificate, &gPlayerData[k].mPeerRecvCipher[i]); // 'k' to receive data from 'i' + + // Create a key exchange message for transmitting the key to the other player + scPeerCipherCreateKeyExchangeMsg(&gPlayerData[k].mCertificate, &gPlayerData[i].mPeerRecvCipher[k], exchangeMsg1); // from 'i', encrypted with 'k' public key + scPeerCipherCreateKeyExchangeMsg(&gPlayerData[i].mCertificate, &gPlayerData[k].mPeerRecvCipher[i], exchangeMsg2); // from 'k', encrypted with 'i' public key + + // Send it (using game network layer) + // - sample doesn't need to send b/c all player's are local + + // Receiving player should parse the key out of it. + // - decrypting the msg requires the local player's private data + scPeerCipherParseKeyExchangeMsg(&gPlayerData[k].mCertificate, &gPlayerData[k].mPrivateData, + exchangeMsg1, &gPlayerData[k].mPeerSendCipher[i]); // 'k' to send data to 'i' + scPeerCipherParseKeyExchangeMsg(&gPlayerData[i].mCertificate, &gPlayerData[i].mPrivateData, + exchangeMsg2, &gPlayerData[i].mPeerSendCipher[k]); // 'i' to send data to 'k' + + // Now we can send secure data by using the (fast) encryption and decryption functions + // - Encrypts and Decrypts in place + strcpy(cipherMsg, plainTextMsg); + scPeerCipherEncryptBufferIV(&gPlayerData[i].mPeerSendCipher[k], 1, (gsi_u8*)cipherMsg, (gsi_u32)msgLen); // 'i' sending to 'k' + scPeerCipherDecryptBufferIV(&gPlayerData[k].mPeerRecvCipher[i], 1, (gsi_u8*)cipherMsg, (gsi_u32)msgLen); // 'k' receiving from 'i' + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + // Host creates session + // Remember that everyone is on the same machine, so the + // first player's login certificate and private data are + // used to create a session + + // REQUIRED FOR MATCHLESS GAMES + // For matchless games this function needs to be called so that the Competition + // System is aware of the type of reports coming in. + scCreateMatchlessSession(gPlayerData[0].mStatsInterface, &gPlayerData[0].mCertificate, &gPlayerData[0].mPrivateData, createSessionCallback, TIMEOUT_MS, NULL); + + myWaitForCallbacks(gPlayerData[0].mStatsInterface, 1); + // End creating the session + + // The host can now set his connection ID + strcpy((char *)gPlayerData[0].mConnectionId, scGetConnectionId(gPlayerData[0].mStatsInterface)); + + // In most cases the host also has the "authoritative" game view + // For this game + // Remember that in matchless sessions, the setting for authoritative should + // not matter as each player's stats get updated soon after they leave. The + // system will not need to wait for all players to submit before processing stats. + scSetReportIntention(gPlayerData[0].mStatsInterface, NULL, gsi_false, &gPlayerData[0].mCertificate, + &gPlayerData[0].mPrivateData, setReportIntentionCallback, TIMEOUT_MS, &gPlayerData[0]); + + myWaitForCallbacks(gPlayerData[0].mStatsInterface, 1); + + for (j=1; j= 10) + myRecordPlayerFrag(aShooterId, aShooteeId); + } + + // some random point values + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + myRecordPlayerScored(gPlayerData[i].mProfileId, (gsi_u32)myGetRandomInt(100)); + + + if (!CreateReportAndSubmit()) + { + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Failed to Create or Submit one of the Reports\r\n"); + } + //////////////////////////////////////// + //////////////////////////////////////// + // Game Over + // exit + // - or - + // clear user data + // goto start (for new map, round etc) + + // Cleanup + //scDestroyReport(aReport); + //aReport = NULL; + + for (i=0; i < SCTEST_NUM_PLAYERS; i++) + { + if (gPlayerData[i].mReport) + { + scDestroyReport(gPlayerData[i].mReport); + gPlayerData[i].mReport= NULL; + } + if (gPlayerData[i].mStatsInterface) + { + scShutdown(gPlayerData[i].mStatsInterface); + gPlayerData[i].mStatsInterface = NULL; + } + } + } + + gsCoreShutdown(); + + // Wait for core shutdown + // (should be instantaneous unless you have multiple cores) + while(gsCoreIsShutdown() == GSCore_SHUTDOWN_PENDING) + { + gsCoreThink(0); + msleep(5); + } + + GSI_UNUSED(SCResultStr); + return gsi_true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(_WIN32) && !defined(_XBOX) && defined(_DEBUG) +#include +#endif + +int test_main(int argc, char *argv[]) +{ + gsi_bool result; + + // Set debug output options + //gsSetDebugFile(stdout); + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Debug); + + // enable Win32 C Runtime debugging + #if defined(_WIN32) && !defined(_XBOX) && defined(_DEBUG) + { + int tempFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + _CrtSetDbgFlag(tempFlag | _CRTDBG_LEAK_CHECK_DF); + } + #endif + + if (!isBackendAvailable()) + return -1; + + + result = RunTests(SCTEST_LOGIN_UNIQUE, gsi_false); + + + // For Testing AuthService logins w/o submitting snapshots + ////////////////////////////////////////////////////////// + /*gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_None); + printf("=== Testing wsLoginProfile === \n"); + result = RunTests(SCTEST_LOGIN_PROFILE, gsi_true); + printf("=== Testing wsLoginRemoteAuth === \n"); + result = RunTests(SCTEST_LOGIN_REMOTEAUTH, gsi_true);*/ + + +#if defined(_WIN32) && !defined(_XBOX) && defined (_UNIX) + fflush(stderr); + printf("Done - Press Enter\r\n"); + fflush(stdout); + getc(stdin); +#else + printf("Done.\r\n"); +#endif + + GSI_UNUSED(argc); + GSI_UNUSED(argv); + + return gsi_is_true(result)?0:-1; +} diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless.dsp b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless.dsp new file mode 100644 index 00000000000..87ce60175fd --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless.dsp @@ -0,0 +1,488 @@ +# Microsoft Developer Studio Project File - Name="sctestmatchless" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=sctestmatchless - Win32 Unicode 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 "sctestmatchless.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 "sctestmatchless.mak" CFG="sctestmatchless - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sctestmatchless - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "sctestmatchless - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "sctestmatchless - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "sctestmatchless - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sctestmatchless - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /GX /O2 /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "sctestmatchless - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HTTP_LOG" /D "GSI_COMMON_DEBUG" /FR /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "sctestmatchless - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "sctestmatchless___Win32_Unicode_Debug0" +# PROP BASE Intermediate_Dir "sctestmatchless___Win32_Unicode_Debug0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "sctestmatchless___Win32_Unicode_Debug0" +# PROP Intermediate_Dir "sctestmatchless___Win32_Unicode_Debug0" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /Gm /GX /ZI /Od /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HTTP_LOG" /D "GSI_COMMON_DEBUG" /FR /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HTTP_LOG" /D "GSI_COMMON_DEBUG" /D "GSI_UNICODE" /FR /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "sctestmatchless - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "sctestmatchless___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "sctestmatchless___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "sctestmatchless___Win32_Unicode_Release" +# PROP Intermediate_Dir "sctestmatchless___Win32_Unicode_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /GX /O2 /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /GX /O2 /I ".." /I "../SCSoap" /I "../.." /I "../../gsoap" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ENDIF + +# Begin Target + +# Name "sctestmatchless - Win32 Release" +# Name "sctestmatchless - Win32 Debug" +# Name "sctestmatchless - Win32 Unicode Debug" +# Name "sctestmatchless - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sctestmatchless.c + +!IF "$(CFG)" == "sctestmatchless - Win32 Release" + +!ELSEIF "$(CFG)" == "sctestmatchless - Win32 Debug" + +# SUBTRACT CPP /WX + +!ELSEIF "$(CFG)" == "sctestmatchless - Win32 Unicode Debug" + +# SUBTRACT BASE CPP /WX +# SUBTRACT CPP /WX + +!ELSEIF "$(CFG)" == "sctestmatchless - Win32 Unicode Release" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "GOA" + +# PROP Default_Filter "" +# Begin Group "SC" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc.h +# End Source File +# Begin Source File + +SOURCE=..\sci.h +# End Source File +# Begin Source File + +SOURCE=..\sciInterface.c +# End Source File +# Begin Source File + +SOURCE=..\sciInterface.h +# End Source File +# Begin Source File + +SOURCE=..\sciMain.c +# End Source File +# Begin Source File + +SOURCE=..\sciReport.c +# End Source File +# Begin Source File + +SOURCE=..\sciReport.h +# End Source File +# Begin Source File + +SOURCE=..\sciSerialize.c +# End Source File +# Begin Source File + +SOURCE=..\sciSerialize.h +# End Source File +# Begin Source File + +SOURCE=..\sciWebServices.c +# End Source File +# Begin Source File + +SOURCE=..\sciWebServices.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCore.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCrypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsLargeInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsRC4.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSHA1.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSoap.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsSSL.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsXML.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\md5c.c +# End Source File +# Begin Source File + +SOURCE=..\..\nonport.h +# End Source File +# End Group +# Begin Group "ghttp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ghttp\ghttp.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpASCII.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCallbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpConnection.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpEncryption.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpMain.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpPost.h +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.c +# End Source File +# Begin Source File + +SOURCE=..\..\ghttp\ghttpProcess.h +# End Source File +# End Group +# Begin Group "webservices" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\webservices\AuthService.c +# End Source File +# Begin Source File + +SOURCE=..\..\webservices\AuthService.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless_vs2005.vcproj b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless_vs2005.vcproj new file mode 100644 index 00000000000..bf563fdcf46 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless_vs2005.vcproj @@ -0,0 +1,2248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/sc/sctestmatchless/sctestmatchless_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/serverbrowsing/changelog.txt b/xrGameSpy/gamespy/serverbrowsing/changelog.txt new file mode 100644 index 00000000000..9877cafbe84 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/changelog.txt @@ -0,0 +1,184 @@ +Changelog for: GameSpy Server Browsing SDK +-------------------------------------------------------- + +DATE VERSION BY TYPE DESCRIPTION +---------- ------- --- ------- --------------------------------------------------------- +12-12-2007 2.07.00 RMV RELEASE Released to Developer Site +12-11-2007 2.06.05 SAH OTHER Added NatNeg files to projects to remove compiler errors +11-27-2007 2.06.03 SAH CLEANUP Moved extern "c" block below includes to prevent linker errors +11-21-2007 2.06.02 SAH FIX Added NNFreeNegotiateList to ServerBrowserFree function +11-05-2007 2.06.01 DES FEATURE Added ServerBrowserConnectToServer (ACE functionality) +08-06-2007 2.06.00 RMV OTHER Modified sbctest, making it more thorough and developer friendly (and added ReadMe) +08-06-2007 2.06.00 RMV RELEASE Released to Developer Site +07-10-2007 2.05.04 RMV FIX Fixed test project files to get rid of Unicode warnings and fixed other compiler warnings +05-16-2007 2.05.03 DES FIX Changed use of u_char to gsi_u8 + DES FEATURE ICMP support is now included by default, define SB_NO_ICMP_SUPPORT to exclude it +01-25-2007 2.05.02 SAH FIX Fixed a bug where the country/region keys would be queried for by individual servers +01-16-2007 2.05.01 DES FEATURE Added X360 support +12-15-2006 2.05.00 MJW RELEASE Released to Developer Site +11-10-2006 2.04.36 JR RELEASE Limited release +10-23-2006 2.04.36 DES RELEASE Limited release +10-11-2006 2.04.36 SN FIX Fixed case where possible disconnection could corrupt input buffer when there + was still data on the buffer. +10-05-2006 2.04.35 SAH FIX Updated MacOSX Makefile +09-28-2006 2.04.34 SAH FIX Fixed PS3 project to work with PS3 095.00x SDK; changed included libaries in linker input. +08-18-2006 2.04.33 SN FIX Fixed ServerBrowserAuxUpdateIP where servers not pending queries were marked + with duplicate query error +08-02-2006 2.04.32 SAH RELEASE Releasing to developer site +07-31-2006 2.04.32 SAH FIX Fixed PS3 project file - added post-build step to create *.SELF for execution +07-25-2006 2.04.31 SAH FIX Fixed NITRO project, include for crt0.o now above others so it add correct file +07-24-2006 2.04.30 SAH FIX Added newline at EOF to sb_serverbrowsing.c to fix compilation warning + SAH FIX Removed #ifdef _PS3 for socket calls (changed platformSocket.h to typecast calls) +07-06-2006 2.04.29 SAH FIX Changed a break; to a return; for challenge received when calling auxUpdateIP synchronously + SAH FIX Made Querytest.c use test_main like our other SDKs, edited project appropriately +07-06-2006 2.04.28 SAH FIX Fixed PSP project file to not explicitly include the PSP linker file +07-06-2006 2.04.27 SAH FIX Fixed linux makefile to work with pthreads (for http asynch DNS lookup) +06-30-2006 2.04.26 SAH FIX Changed natneg = 1 to SBTrue to get rid of warnings + SAH FIX Fixed NITRO project && linker command file (for Codewarrior 2.0/NitroSDK 3.1) +06-30-2006 2.04.25 MJ FEATURE Added SBServerGetConnectionInfo +05-31-2006 2.04.24 SAH RELEASE Releasing to developer site + SAH FIX Fixed Linux makefile +05-30-2006 2.04.24 SAH FIX Fixed PS3 projects to work with PS3(084_001 SDK) +05-25-2006 2.04.24 SAH FIX Changed PSP project warning levels +05-24-2006 2.04.23 SAH FIX added sbe_duplicateupdateerror case to switch statement +05-23-2006 2.04.22 BED FIX AuxUpdate functions will no longer update a server while an update is already pending +05-23-2006 2.04.21 SAH FIX Added win32common.c and gsTestMain.c to sbctest project +05-23-2006 2.04.20 SAH FIX Added GS_STATIC_CALLBACK to compare functions for __fastcall support +05-19-2006 2.04.19 SAH FIX Added gsTestMain.c for nitro CodeWarrior project +05-15-2006 2.04.18 SAH FIX Added "PS3 Release" configuration to project +04-25-2006 2.04.17 SAH RELEASE Releasing to developer site +04-24-2006 2.04.17 SAH FIX Fixed UNICODE compile errors, mainly typecasts +04-24-2006 2.04.16 SAH FIX Fixed SortInfo creation call, fixed Nitro project files to work on build machine +04-20-2006 2.04.15 SAH FIX Removed unnecessary break; statements, added some (char*) typecasts + SAH FIX Moved GSI_UNUSED calls above return statements +04-20-2006 2.04.14 SAH FIX Added _PS3 wrapper typecast for recvfrom calls +04-19-2006 2.04.13 SAH FIX Added || defined(_PS3) to sbctest.c for PS3 Support +04-13-2006 2.04.12 SAH FIX Added parenthesis to remove compiler warnings before Release +04-10-2006 2.04.11 SAH FEATURE Multiple sorts will retain previous sorting arrangement when values are equal +03-28-2006 2.04.10 SN FIX Added extra checks to account for empty keys +03-28-2006 2.04.10 SN FIX Fixed SBServerGetIntValue to return negative numbers +03-20-2006 2.04.09 SN OTHER Added PSP to the defines before the test_main in sbctest + SN OTHER Moved the GSI_UNUSED calls to before the return statement +01-27-2006 2.04.09 SN RELEASE Releasing to developer site +01-27-2006 2.04.09 SN FIX Added psp prodg project and solution to sgv +12-22-2005 2.04.08 SN OTHER Cleaned up project files and added missing common code. +11-17-2005 2.04.07 DES FIX Compatibility fixes. + DES FIX Updated Nitro Makefile. +11-14-2005 2.04.06 DES FIX Updated OSX support. + DES FEATURE Added GSI_DOMAIN_NAME support. +10-12-2005 2.04.05 BED RELEASE Releasing to developer site. +10-11-2005 2.04.04 BED FEATURE Added query challege/response to prevent ip spoofing. +09-23-2005 2.04.03 DES FEATURE Updated DS support + DES FIX Fixed SBServerGetBoolValue() to return the default is the value is empty +07-28-2005 2.04.02 SN RELEASE Releasing to developer site. +06-28-2005 2.04.02 BED FEATURE Added ICMP support for remaining platforms. +06-03-2005 2.04.01 SN RELEASE Releasing to developer site. +05-05-2005 2.04.01 BED FIX Updated projects to use new common folder. +o5-04-2005 2.04.00 SN OTHER Created Visual Studio .NET projects +04-29-2005 2.04.00 BED FEATURE Added support for multi-packet qr2 responses. (Full keys direct only) +04-28-2005 2.03.03 SN RELEASE Releasing to developer site. +04-27-2005 2.03.03 DES RELEASE Limited release to Nintendo DS developers. +04-27-2005 2.03.03 DES FEATURE Modified sbctest to quit when the update is complete. +04-25-2005 2.03.02 DES FIX Fixed a function call in querytest. +04-21-2005 2.03.01 DES FIX Renamed IPHeader and ICMPHeader to avoid Nitro header conflict. +04-18-2005 2.03.00 DDW FEATURE Added initial Win32 support for ICMP pings of firewalled servers + FEATURE Added new SBServerHasValidPing public function +04-04-2005 2.02.21 SN RELEASE Releasing to developer site. +03-14-2005 2.02.21 DES FEATURE Nintendo DS support +02-17-2005 2.02.20 DDW OTHER Extended gamenames in SB structures to 36 bytes from 32 (dynamic gamename support) +01-27-2005 2.02.19 DES FIX Fixed custom SN sendto and moved it to nonport +11-03-2004 2.02.18 SN FIX Fixed and turned off availability check during LAN browsing, + SN FIX Added a check to a server object when obtaining key values + SN FIX Updated SBMFC sample to have new ServerBrowserNew function +09-27-2004 2.02.17 SN RELEASE Releasing qr2 fix to developer site +09-16-2004 2.02.16 SN RELEASE Releasing to developer site. +09-08.2004 2.02.16 BED FIX Fixed cases where same server could appear in FIFO multiple times +08-27-2004 2.02.15 DES CLEANUP Fixed warnings under OSX + DES CLEANUP Updated Win32 project configurations + DES CLEANUP Removed #pragma comment for linking with winsock (in nonport now) + DES CLEANUP General Unicode cleanup + DES CLEANUP Removed MacOS style includes + DES FEATURE Added OSX Makefile +08-25-2004 2.02.14 DES FEATURE Added OSX makefile +08-04-2004 2.02.13 SN RELEASE Releasing to developer site. +07-12-2004 2.02.13 SN FIX Cleared errors when warnings are treated as errors set, and warning level is highest. +06-18-2004 2.02.12 BED RELEASE Releasing to developer site. +06-16-2004 2.02.12 BED FEATURE PS2 Insock configurations added to samples. +05-24-2004 2.02.11 BED FIX ServerBrowserAuxUpdateIP no longer adds a duplicate SBServer to the list +05-22-2004 2.02.10 BED FEATURE Ps2 Insock support added. +05-21-2004 2.02.09 DDW FEATURE VEngine & Peer compatibility fix - now local to each serverlist +05-14-2004 2.02.08 DDW FEATURE VEngine & Peer compatibility fix +05-06-2004 2.02.07 DDW FEATURE Allow external management of the unique string hash +05-06-2004 2.02.06 BED FIX SBServerGetIntValue now returns instead of 0 for a key that is empty-string. +04-02-2004 2.02.05 BED FIX Capped max recvfrom size to 2048 for PS2 INSOCK compatibility. + BED FEATURE Added ability to specify network adapter when LAN browsing. + BED FIX Changed "unsigned long" to "gsi_time" in a couple places for PS2 compatability. +03-30-2004 2.02.04 BED FIX Fixed timing issue where server might appear twice in the FIFO, causing a crash. +03-19-2004 2.02.03 BED FEATURE Added ability to specify network adapter when LAN browsing. +03-09-2004 2.02.02 BED FIX Fixed case where browsing would not complete when all servers were behind a firewall. +01-12-2004 2.02.01 BED FEATURE Added ServerBrowserGetServerByIP for IP lookup into the list. +01-07-2004 2.02.00 DDW FEATURE Added internal support for player searching +01-07-2004 2.01.01 BED FIX Added prototypes for ascii functions in UNICODE mode. +12-16-2003 2.01.00 DDW FEATURE Added internal support for map loop lookup +11-10-2003 2.00.36 DES RELEASE Releasing to developer site. +11-10-2003 2.00.36 BED FIX Fixed case where LAN browsing would never complete. +11-07-2003 2.00.35 BED FIX Update CodeWarrior project file. +11-07-2003 2.00.35 DES FIX Updated linux and PS2 makefiles. +11-06-2003 2.00.34 BED FIX Fixed case where raw buffer was treated as string (unicode conversion doesn't apply) +11-04-2003 2.00.33 BED FIX Added some const-correctness to the SDK. + BED FIX Removed misc warnings for devstudio level 4. +11-04-2003 2.00.32 DES FEATURE Added availability check code. +10-22-2003 2.00.31 BED RELEASE Releasing to developer site. (UNIQUE NICK AND UNICODE SUPPORT) +10-22-2003 2.00.31 BED FIX Removed some compiler warnings on scrict setting. +10-21-2003 2.00.30 DES FIX Added stringutil files to VC++ sample projects. +10-09-2003 2.00.29 BED FIX Switched to gsi_time type instead of unsinged long for PS2 compatibility +09-09-2003 2.00.28 BED FEATURE Added UTF-8 wrapper -- define GSI_UNICODE + OTHER Added stringutil.c and stringutil.h to sample project files +08-06-2003 2.00.27 BED FIX Increased sb_serverlist.c incoming UDP buffer size from 500 to 1500 bytes. +07-29-2003 2.00.26 BED FIX Fixed calls in sb_server.c where integers (#2) were being returned instead of SBBool. +07-24-2003 2.00.25 DES RELEASE Releasing to developer site. +07-18-2003 2.00.25 BED FEATURE Added CodeWarrior (PS2) sample project file. + BED CLEANUP General cleanup to remove CodeWarrior warnings. +07-17-2003 2.00.24 DES CLEANUP Cleaned up the PS2 Makefile, it now uses Makefile.commmon. +07-16-2003 2.00.23 DES FIX Changed a couple of __mips64 checks to _PS2 checks. + BED FEATURE Added ProDG sample project files. +07-09-2003 2.00.22 BED CLEANUP Made MFC sample's server list not continually redraw while sorting. +06-11-2003 2.00.21 DES RELEASE Releasing to developer site. +05-11-2003 2.00.21 DDW CLEANUP Modularized SBServer type handling +05-11-2003 2.00.20 DDW CLEANUP Modularized server parsing and addition +05-09-2003 2.00.19 DES CLEANUP Removed Dreamcast support. +05-09-2003 2.00.18 DDW CLEANUP Modularized refstrings and serverlist functions +05-07-2003 2.00.17 DES RELEASE Releasing to developer site. +04-07-2003 2.00.17 DES FIX Fixed semicolon after if() in SBServerListFindServer. +03-24-2003 2.00.16 DDW FEATURE Added ServerBrowserLimitUpdate function to limit the number of results returned +03-03-2003 2.00.15 DES CLEANUP General cleanup to remove warnings. +02-28-2003 2.00.14 DES RELEASE Releasing to developer site with updated QR2. +02-05-2003 2.00.14 DES RELEASE Releasing to developer site. +02-05-2003 2.00.14 DES FIX Made sure servers in MFC sample show correct info after an sbc_serverupdated. + CLEANUP Switched select calls to CanReceiveOnSocket and CanSendOnSocket. +02-04-2003 2.00.13 DES RELEASE Relasing to developer site. +02-04-2003 2.00.13 DES CLEANUP Removed assert.h include from querytest.c + FIX Use GOA/QR2 checkbox in the MFC sample. + OTHER Show servers in the MFC sample as soon as they are added (sbc_serveradded). +01-23-2003 2.00.12 DES FIX Replaced a call to free with gsifree. +12-19-2002 2.00.11 DES RELEASE Releasing to developer site. +12-19-2002 2.00.11 DES CLEANUP Removed assert.h includes. +12-13-2002 2.00.10 DES FEATURE Added PS2 eenet stack support. +12-06-2002 2.00.09 DES RELEASE Releasing to developer site with updated QR2. +12-03-2002 2.00.09 DES RELEASE Releasing to developer site. +12-03-2002 2.00.09 DES FEATURE Added a Linux Makefile. +11-22-2002 2.00.08 DES RELEASE Releasing to developer site. +11-20-2002 2.00.08 DES FEATURE Added support for compiling on the PS2. +11-15-2002 2.00.07 DDW FEATURE Abstracted the server->next pointer into SBServer.c +11-07-2002 2.00.06 DDW FEATURE Added "deadlist" support so that servers are not freed on the same pass they are removed +11-07-2002 2.00.06 DDW FIX Fixed AV when disconnecting during mainlist with data pending +10-22-2002 2.00.05 DDW FIX Correctly removes server from query engine when removed message arrives +09-26-2002 2.00.04 DES RELEASE Limited release on developer site +09-26-2002 2.00.04 DDW FIX MFC sample checks whether server has full-rules before requerying +09-26-2002 2.00.03 DES FEATURE Added MFC sample (sbmfcsample) +09-26-2002 2.00.02 DDW OTHER Changelog started +09-26-2002 2.00.02 DES FIX Fixed memory leak when cleaning up server list object +09-24-2002 2.00.01 DDW FIX Fixed protocol parsing error on packet boundary +09-23-2002 2.00.00 DDW RELEASE Release to EAPAC for Generals (Peer) +09-06-2002 2.00.00 DDW RELEASE Release to EAPAC for Generals + diff --git a/xrGameSpy/gamespy/serverbrowsing/querytest/querytest.c b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest.c new file mode 100644 index 00000000000..d42a8010ab7 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest.c @@ -0,0 +1,82 @@ +/****** +querytest.c +GameSpy Server Browsing SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + +This program is provided as a diagnostic tool for the Query and Reporting 2 SDK, but is +also provided here as a sample to demonstrate how to query a single server for full rules using +the Server Browisng SDK. + +******/ + +#include "../sb_serverbrowsing.h" +#include "../sb_internal.h" +#include "../../qr2/qr2.h" +#include "../../common/gsAvailable.h" +#include + + + +#define NUM_SIMUL_QUERIES 10 + +void PrintValues(char *key, char *value, void *instance) +{ + printf("%s = %s\n", key, value); + GSI_UNUSED(instance); +} + + +void PrintResultsCallback(ServerBrowser sb, SBCallbackReason reason, SBServer server, void *instance) +{ + if (reason == sbc_serverupdated) + { + printf("Got server data: %s:%d [%d]\nKeys/Values:\n",inet_ntoa(*(struct in_addr *)&server->publicip), ntohs(server->publicport), SBServerGetPing(server)); + SBServerEnumKeys(server, PrintValues, NULL); + + } else if (reason == sbc_serverupdatefailed) + { + printf("Server update timed out\n"); + } + GSI_UNUSED(instance); + GSI_UNUSED(sb); +} + +int test_main(int argc, char **argp) +{ + ServerBrowser sb; + GSIACResult result; + int totalTime = 0; + + // check that the game's backend is available + GSIStartAvailableCheck("gmtest"); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + printf("The backend is not available\n"); + return 1; + } + + if (argc != 3) + { + printf("Invalid parameters!\nQueryTest Usage:\nquerytest.exe [ip] [port]\nExample: querytest.exe 1.2.3.4 28000\n"); + return 1; + } + sb = ServerBrowserNew ("gmtest", "gmtest", "HA6zkS", 0, 10, QVERSION_QR2, SBFalse, PrintResultsCallback, NULL); + // port 11111 for qr2csample + ServerBrowserAuxUpdateIP(sb, argp[1], (unsigned short)atoi(argp[2]), SBFalse, SBTrue, SBTrue); + while (totalTime < 5000) { + ServerBrowserThink(sb); + msleep(50); + totalTime += 50; + } + ServerBrowserFree(sb); + GSI_UNUSED(argp); + GSI_UNUSED(argc); + return 0; +} diff --git a/xrGameSpy/gamespy/serverbrowsing/querytest/querytest.dsp b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest.dsp new file mode 100644 index 00000000000..65562b4f773 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest.dsp @@ -0,0 +1,268 @@ +# Microsoft Developer Studio Project File - Name="querytest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=querytest - 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 "querytest.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 "querytest.mak" CFG="querytest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "querytest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "querytest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/serverbrowsing/querytest", XYTCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "querytest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "querytest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "querytest - Win32 Release" +# Name "querytest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\querytest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=..\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=..\sb_server.c +# End Source File +# Begin Source File + +SOURCE=..\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=..\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\sb_serverlist.c +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/serverbrowsing/querytest/querytest_vs2005.vcproj b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest_vs2005.vcproj new file mode 100644 index 00000000000..7caae63094f --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest_vs2005.vcproj @@ -0,0 +1,747 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/querytest/querytest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/querytest/querytest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_ascii.h b/xrGameSpy/gamespy/serverbrowsing/sb_ascii.h new file mode 100644 index 00000000000..06d74b7ff7f --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_ascii.h @@ -0,0 +1,167 @@ +/****** +GameSpy Server Browsing SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy Server Browsing SDK documentation for more + information + +******/ + +// PROTOTYPES FOR ASCII VERSIONS +// This is required to silence CodeWarrior warnings about functions not having a prototype + + +#ifndef _SB_ASCII_H +#define _SB_ASCII_H + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +ServerBrowserNew +---------------- +Creates and returns a new (empty) ServerBrowser object. +Returns NULL if an allocation error occurs. + +queryForGamename - The gamename you are querying for +queryFromGamename - The gamename you are querying from - generally the same as queryForGamename +queryFromKey - Secret key that corresponds to the queryFromGamename +queryFromVersion - A game-specific version identifier (pass 0 unless told otherwise) +maxConcUpdates - Max number of concurent updates (10-15 for modem users, 20-30 for high-bandwidth) +queryVersion - Query protocol to use. Use QVERSION_GOA for DeveloperSpec/Query&Reporting1 games, and QVERSION_QR2 for games that use Query & Reporting 2 +callback - The function that will be called with list updates +instance - User-defined instance data (e.g. structure or object pointer) */ +ServerBrowser ServerBrowserNewA(const char *queryForGamename, const char *queryFromGamename, const char *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool lanBrowse, ServerBrowserCallback callback, void *instance); + + +/* ServerBrowserUpdate +------------------- +Starts an update by downloading a list of servers from the master server, then querying them. + +sb - The server browser object to update +async - If SBTrue, the update will be initiated, and ServerListThink must be called for processing and querying to occur + If SBFalse, the function will not return until the initial list of servers has been completely updated +disconnectOnComplete - If SBTrue, the connection to the master server will be disconnected immediately after the list is downloaded. + If SBFalse, the connection will be left open for additional data queries, and can be closed via ServerBrowserDisconnect +basicFields - This array of registered QR2 keys is used to determine the fields requested from servers during the initial "basic" update. + Only server keys listed in this array will be returned for servers. +numBasicFields - The number of fields in the basicFields array +serverFilter - SQL Filter string that will be applied on the master server to limit the list of servers returned. + All server keys are available for filtering on the master server, as well as the master-defined "country" and "region" keys. + Standard SQL syntax should be used. + +ServerBrowserLimitUpdate +------------------------ +Identical to ServerBrowserUpdate, except that the number of servers returned can be limited +maxServers - Maximum number of servers to be returned +*/ +SBError ServerBrowserUpdateA(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const char *serverFilter); +SBError ServerBrowserLimitUpdateA(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const char *serverFilter, int maxServers); + + +/* ServerBrowserAuxUpdateIP +------------------- +Manually updates a server given an IP address and query port. Use to manually add servers to the list when you just +have an IP and port for them. + +sb - The server browser object to add the server to +ip - The dotted IP address of the server e.g. "1.2.3.4" +port - The query port of the server +viaMaster - If SBTrue, information about the server will be retrieved from the master server instead of attempting to query the server directly. + If a connection to the master server does not exist, it will be made to kept open afterwards. + If SBFalse, the server will be contacted directly for information. +async - If SBTrue, the update will be initiated, and ServerListThink must be called for processing and querying to occur + If SBFalse, the function will not return until the server has been successfully or unsuccessfully updated +fullUpdate - If SBTrue, all server keys/rules/player/team information will be retrieved + If SBFalse, only the keys specified in the basicFields array of the ServerBrowserUpdate function will be retrieved */ +SBError ServerBrowserAuxUpdateIPA(ServerBrowser sb, const char *ip, unsigned short port, SBBool viaMaster, SBBool async, SBBool fullUpdate); + +/* ServerBrowserRemoveIP +------------------- +Removes a server from the list given an IP and query port */ +void ServerBrowserRemoveIPA(ServerBrowser sb, const char *ip, unsigned short port); + +/* ServerBrowserErrorDesc +------------------- +Returns a human-readable error string for the given error code. */ +const char *ServerBrowserErrorDescA(ServerBrowser sb, SBError error); + +/* ServerBrowserListQueryError +------------------- +When a list query error occurs, as indicated by the sbc_queryerror callback, this function allows you to +obtain the human-readable error string for the error (generally these errors are caused by errors in the +filter string) */ +const char *ServerBrowserListQueryErrorA(ServerBrowser sb); + + +/* ServerBrowserSendNatNegotiateCookieToServer +------------------ +Sends a cookie value to the server for use with NAT Negotiation */ +SBError ServerBrowserSendNatNegotiateCookieToServerA(ServerBrowser sb, const char *ip, unsigned short port, int cookie); + + +/* ServerBrowserSendMessageToServer +------------------ +Sends a game-specific message to a server */ +SBError ServerBrowserSendMessageToServerA(ServerBrowser sb, const char *ip, unsigned short port, const char *data, int len); + + +/* ServerBrowserSort +----------------- +Sort the server list in either ascending or descending order using the +specified comparemode. +sortkey can be a normal server key, or "ping" or "hostaddr" */ +void ServerBrowserSortA(ServerBrowser sb, SBBool ascending, const char *sortkey, SBCompareMode comparemode); + +/******************* +SBServer Object Functions +********************/ + + +/* SBServerGetPublicAddress/SBServerGetPrivateAddress +------------------- +Returns the string, dotted IP address for the specified server +The "private" version is only valid when the server has a private address available */ +char *SBServerGetPublicAddress(SBServer server); +char *SBServerGetPrivateAddress(SBServer server); + + +/* SBServerGet[]Value +------------------ +Returns the value for the specified key. If the key does not exist for the +given server, the default value is returned */ +const char *SBServerGetStringValueA(SBServer server, const char *keyname, const char *def); +int SBServerGetIntValueA(SBServer server, const char *key, int idefault); +double SBServerGetFloatValueA(SBServer server, const char *key, double fdefault); +SBBool SBServerGetBoolValueA(SBServer server, const char *key, SBBool bdefault); + + +/* SBServerGetPlayer[]Value / SBServerGetTeam[]Value +------------------ +Returns the value for the specified key on the specified player or team. If the key does not exist for the +given server, the default value is returned +Player keys take the form keyname_N where N is the player index, and team keys take the form +keyname_tN where N is the team index. You should only specify the keyname for the key in the below functions. +*/ +const char *SBServerGetPlayerStringValueA(SBServer server, int playernum, const char *key, const char *sdefault); +int SBServerGetPlayerIntValueA(SBServer server, int playernum, const char *key, int idefault); +double SBServerGetPlayerFloatValueA(SBServer server, int playernum, const char *key, double fdefault); + +const char *SBServerGetTeamStringValueA(SBServer server, int teamnum, const char *key, const char *sdefault); +int SBServerGetTeamIntValueA(SBServer server, int teamnum, const char *key, int idefault); +double SBServerGetTeamFloatValueA(SBServer server, int teamnum, const char *key, double fdefault); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_crypt.c b/xrGameSpy/gamespy/serverbrowsing/sb_crypt.c new file mode 100644 index 00000000000..85b5fd569d4 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_crypt.c @@ -0,0 +1,212 @@ +#include +#include +#include "sb_crypt.h" + + +static unsigned char keyrand(GOACryptState *state, int limit, + unsigned char *user_key, + unsigned char keysize, + unsigned char *rsum, + unsigned *keypos) +{ + unsigned int u, // Value from 0 to limit to return. + retry_limiter, // No infinite loops allowed. + mask; // Select just enough bits. + + if (!limit) return 0; // Avoid divide by zero error. + retry_limiter = 0; + mask = 1; // Fill mask with enough bits to cover + while (mask < (unsigned)limit) // the desired range. + mask = (mask << 1) + 1; + do + { + *rsum = (unsigned char)(state->cards[*rsum] + user_key[(*keypos)++]); + if (*keypos >= keysize) + { + *keypos = 0; // Recycle the user key. + *rsum = (unsigned char)(*rsum + keysize); // key "aaaa" != key "aaaaaaaa" + } + u = mask & *rsum; + if (++retry_limiter > 11) + u %= (unsigned int)limit; // Prevent very rare long loops. + } + while (u > (unsigned)limit); + return (unsigned char)(u); +} + + +void GOAHashInit(GOACryptState *state) +{ + // This function is used to initialize non-keyed hash + // computation. + + int i, j; + + // Initialize the indices and data dependencies. + + state->rotor = 1; + state->ratchet = 3; + state->avalanche = 5; + state->last_plain = 7; + state->last_cipher = 11; + + // Start with state->cards all in inverse order. + + for (i=0, j=255;i<256;i++,j--) + state->cards[i] = (unsigned char) j; +} + + +void GOACryptInit(GOACryptState *state, unsigned char *key, unsigned char keysize) +{ + // Key size may be up to 256 bytes. + // Pass phrases may be used directly, with longer length + // compensating for the low entropy expected in such keys. + // Alternatively, shorter keys hashed from a pass phrase or + // generated randomly may be used. For random keys, lengths + // of from 4 to 16 bytes are recommended, depending on how + // secure you want this to be. + + int i; + unsigned char toswap, swaptemp, rsum; + unsigned keypos; + + // If we have been given no key, assume the default hash setup. + + if (keysize < 1) + { + GOAHashInit(state); + return; + } + + // Start with state->cards all in order, one of each. + + for (i=0;i<256;i++) + state->cards[i] = (unsigned char)(i); + + // Swap the card at each position with some other card. + + toswap = 0; + keypos = 0; // Start with first byte of user key. + rsum = 0; + for (i=255;i>=0;i--) + { + toswap = keyrand(state, i, key, keysize, &rsum, &keypos); + swaptemp = state->cards[i]; + state->cards[i] = state->cards[toswap]; + state->cards[toswap] = swaptemp; + } + + // Initialize the indices and data dependencies. + // Indices are set to different values instead of all 0 + // to reduce what is known about the state of the state->cards + // when the first byte is emitted. + + state->rotor = state->cards[1]; + state->ratchet = state->cards[3]; + state->avalanche = state->cards[5]; + state->last_plain = state->cards[7]; + state->last_cipher = state->cards[rsum]; + + toswap = swaptemp = rsum = 0; + keypos = 0; +} + + +unsigned char GOAEncryptByte(GOACryptState *state, unsigned char b) +{ + // Picture a single enigma state->rotor with 256 positions, rewired + // on the fly by card-shuffling. + + // This cipher is a variant of one invented and written + // by Michael Paul Johnson in November, 1993. + + unsigned char swaptemp; + + // Shuffle the deck a little more. + + state->ratchet = (unsigned char)(state->ratchet + state->cards[state->rotor++]); + swaptemp = state->cards[state->last_cipher]; + state->cards[state->last_cipher] = state->cards[state->ratchet]; + state->cards[state->ratchet] = state->cards[state->last_plain]; + state->cards[state->last_plain] = state->cards[state->rotor]; + state->cards[state->rotor] = swaptemp; + state->avalanche = (unsigned char)(state->avalanche + state->cards[swaptemp]); + + // Output one byte from the state in such a way as to make it + // very hard to figure out which one you are looking at. + /* + state->last_cipher = b^state->cards[(state->cards[state->ratchet] + state->cards[state->rotor]) & 0xFF] ^ + state->cards[state->cards[(state->cards[state->last_plain] + + state->cards[state->last_cipher] + + state->cards[state->avalanche])&0xFF]]; + */ + state->last_cipher = (unsigned char)(b^state->cards[(state->cards[state->avalanche] + state->cards[state->rotor]) & 0xFF] ^ + state->cards[state->cards[(state->cards[state->last_plain] + + state->cards[state->last_cipher] + + state->cards[state->ratchet])&0xFF]]); + state->last_plain = b; + return state->last_cipher; +} + + +void GOAEncrypt(GOACryptState *state, unsigned char *bp, int len) +{ + int i; + for (i = 0 ; i < len ; i++) + { + bp[i] = GOAEncryptByte(state, bp[i]); + } +} + +unsigned char GOADecryptByte(GOACryptState *state, unsigned char b) +{ + unsigned char swaptemp; + + // Shuffle the deck a little more. + + state->ratchet = (unsigned char)(state->ratchet + state->cards[state->rotor++]); + swaptemp = state->cards[state->last_cipher]; + state->cards[state->last_cipher] = state->cards[state->ratchet]; + state->cards[state->ratchet] = state->cards[state->last_plain]; + state->cards[state->last_plain] = state->cards[state->rotor]; + state->cards[state->rotor] = swaptemp; + state->avalanche = (unsigned char)(state->avalanche + state->cards[swaptemp]); + + // Output one byte from the state in such a way as to make it + // very hard to figure out which one you are looking at. + /* + state->last_plain = b^state->cards[(state->cards[state->ratchet] + state->cards[state->rotor]) & 0xFF] ^ + state->cards[state->cards[(state->cards[state->last_plain] + + state->cards[state->last_cipher] + + state->cards[state->avalanche])&0xFF]]; + */ + //crt - change this around + state->last_plain = (unsigned char)(b^state->cards[(state->cards[state->avalanche] + state->cards[state->rotor]) & 0xFF] ^ + state->cards[state->cards[(state->cards[state->last_plain] + + state->cards[state->last_cipher] + + state->cards[state->ratchet])&0xFF]]); + state->last_cipher = b; + return state->last_plain; +} + +void GOADecrypt(GOACryptState *state, unsigned char *bp, int len) +{ + int i; + for (i = 0 ; i < len ; i++) + { + bp[i] = GOADecryptByte(state, bp[i]); + } +} + +void GOAHashFinal(GOACryptState *state, unsigned char *outputhash, // Destination + unsigned char hashlength) // Size of hash. +{ + int i; + + for (i=255;i>=0;i--) + GOAEncryptByte(state, (unsigned char) i); + for (i=0;istate +#define STATE_BASICKEYS (1 << 0) +#define STATE_FULLKEYS (1 << 1) +#define STATE_PENDINGBASICQUERY (1 << 2) +#define STATE_PENDINGFULLQUERY (1 << 3) +#define STATE_QUERYFAILED (1 << 4) +#define STATE_PENDINGICMPQUERY (1 << 5) +#define STATE_VALIDPING (1 << 6) +#define STATE_PENDINGQUERYCHALLENGE (1 << 7) + +//how long before a server query times out +#define MAX_QUERY_MSEC 2500 + +//game server flags +#define UNSOLICITED_UDP_FLAG 1 +#define PRIVATE_IP_FLAG 2 +#define CONNECT_NEGOTIATE_FLAG 4 +#define ICMP_IP_FLAG 8 +#define NONSTANDARD_PORT_FLAG 16 +#define NONSTANDARD_PRIVATE_PORT_FLAG 32 +#define HAS_KEYS_FLAG 64 +#define HAS_FULL_RULES_FLAG 128 + +//backend query flags (set in hbmaster, don't change) +#define QR2_USE_QUERY_CHALLENGE 128 + +//key types for the key type list +#define KEYTYPE_STRING 0 +#define KEYTYPE_BYTE 1 +#define KEYTYPE_SHORT 2 + +//how long to make the outgoing challenge +#define LIST_CHALLENGE_LEN 8 + +//protocol versions +#define LIST_PROTOCOL_VERSION 1 +#define LIST_ENCODING_VERSION 3 + +//message types for outgoing requests +#define SERVER_LIST_REQUEST 0 +#define SERVER_INFO_REQUEST 1 +#define SEND_MESSAGE_REQUEST 2 +#define KEEPALIVE_REPLY 3 +#define MAPLOOP_REQUEST 4 +#define PLAYERSEARCH_REQUEST 5 + +//message types for incoming requests +#define PUSH_KEYS_MESSAGE 1 +#define PUSH_SERVER_MESSAGE 2 +#define KEEPALIVE_MESSAGE 3 +#define DELETE_SERVER_MESSAGE 4 +#define MAPLOOP_MESSAGE 5 +#define PLAYERSEARCH_MESSAGE 6 + +//server list update options +#define SEND_FIELDS_FOR_ALL 1 +#define NO_SERVER_LIST 2 +#define PUSH_UPDATES 4 +#define SEND_GROUPS 32 +#define NO_LIST_CACHE 64 +#define LIMIT_RESULT_COUNT 128 + +//player search options +#define SEARCH_ALL_GAMES 1 +#define SEARCH_LEFT_SUBSTRING 2 +#define SEARCH_RIGHT_SUBSTRING 4 +#define SEARCH_ANY_SUBSTRING 8 + +//max number of keys for the basic key list +#define MAX_QUERY_KEYS 20 + +//how long to search on the LAN +#define SL_LAN_SEARCH_TIME 2000 + +//MAGIC bytes for the QR2 queries +#define QR2_MAGIC_1 0xFE +#define QR2_MAGIC_2 0xFD + +//magic bytes for nat negotiation message +#define NATNEG_MAGIC_LEN 6 +#define NN_MAGIC_0 0xFD +#define NN_MAGIC_1 0xFC +#define NN_MAGIC_2 0x1E +#define NN_MAGIC_3 0x66 +#define NN_MAGIC_4 0x6A +#define NN_MAGIC_5 0xB2 + + +//query types +#define QTYPE_BASIC 0 +#define QTYPE_FULL 1 +#define QTYPE_ICMP 2 + +//query strings for old-style servers +#define BASIC_GOA_QUERY "\\basic\\\\info\\" +#define BASIC_GOA_QUERY_LEN 13 +#define FULL_GOA_QUERY "\\status\\" +#define FULL_GOA_QUERY_LEN 8 + +//maximum length of a sortkey string +#define SORTKEY_LENGTH 255 + +//include ICMP support by default +#ifndef SB_NO_ICMP_SUPPORT + #undef SB_ICMP_SUPPORT + #define SB_ICMP_SUPPORT +#endif + +//a key/value pair +typedef struct _SBKeyValuePair +{ + const char *key; + const char *value; +} SBKeyValuePair; + + +//a ref-counted string +typedef struct _SBRefString +{ + const char *str; +#ifdef GSI_UNICODE + const unsigned short *str_W; +#endif + int refcount; +} SBRefString; + + +typedef struct _SBServerList *SBServerListPtr; +typedef struct _SBQueryEngine *SBQueryEnginePtr; + +//callback types for server lists +typedef enum {slc_serveradded, slc_serverupdated, slc_serverdeleted, slc_initiallistcomplete, slc_disconnected, slc_queryerror, slc_publicipdetermined, slc_serverchallengereceived} SBListCallbackReason; +//callback types for query engine +typedef enum {qe_updatesuccess, qe_updatefailed, qe_engineidle, qe_challengereceived} SBQueryEngineCallbackReason; + +//callback function prototypes +typedef void (*SBListCallBackFn)(SBServerListPtr serverlist, SBListCallbackReason reason, SBServer server, void *instance); +typedef void (*SBEngineCallbackFn)(SBQueryEnginePtr engine, SBQueryEngineCallbackReason reason, SBServer server, void *instance); +typedef void (*SBMaploopCallbackFn)(SBServerListPtr serverlist, SBServer server, time_t mapChangeTime, int numMaps, char *mapList[], void *instance); +typedef void (*SBPlayerSearchCallbackFn)(SBServerListPtr serverlist, char *nick, goa_uint32 serverIP, unsigned short serverPort, time_t lastSeenTime, char *gamename, void *instance); + +//key information structure +typedef struct _KeyInfo +{ + const char *keyName; + int keyType; +} KeyInfo; + + +typedef struct _SBServerList SBServerList; + +#ifdef VENGINE_SUPPORT + #define FTABLE_TYPES + #include "../../VEngine/ve_gm3ftable.h" +#endif + + +//keeps track of previous and current sorting information +typedef struct _SortInfo +{ + gsi_char sortkey[SORTKEY_LENGTH]; + SBCompareMode comparemode; +} SortInfo; + +struct _SBServerList +{ + SBServerListState state; + DArray servers; + DArray keylist; + char queryforgamename[36]; + char queryfromgamename[36]; + char queryfromkey[32]; + char mychallenge[LIST_CHALLENGE_LEN]; + char *inbuffer; + int inbufferlen; + const char *popularvalues[MAX_POPULAR_VALUES]; + int numpopularvalues; + int expectedelements; + + SBListCallBackFn ListCallback; + SBMaploopCallbackFn MaploopCallback; + SBPlayerSearchCallbackFn PlayerSearchCallback; + void *instance; + + SortInfo currsortinfo; + SortInfo prevsortinfo; + + SBBool sortascending; + goa_uint32 mypublicip; + goa_uint32 srcip; + unsigned short defaultport; + + char *lasterror; +#ifdef GSI_UNICODE + unsigned short *lasterror_W; +#endif + + SOCKET slsocket; + gsi_time lanstarttime; + int fromgamever; + GOACryptState cryptkey; + int queryoptions; + SBListParseState pstate; + gsi_u16 backendgameflags; + + const char* mLanAdapterOverride; + + SBServer deadlist; + +#ifdef VENGINE_SUPPORT + #define FTABLE_IMPLEMENT + #include "../../VEngine/ve_gm3ftable.h" +#endif + +}; + + +//server object + +#ifndef SB_SERVER_DECLARED +#define SB_SERVER_DECLARED + +struct _SBServer +{ + goa_uint32 publicip; + unsigned short publicport; + goa_uint32 privateip; + unsigned short privateport; + goa_uint32 icmpip; + unsigned char state; + unsigned char flags; + HashTable keyvals; + gsi_time updatetime; + gsi_u32 querychallenge; + struct _SBServer *next; + gsi_u8 splitResponseBitmap; +}; + +#endif + +typedef struct _SBServerFIFO +{ + SBServer first; + SBServer last; + int count; +} SBServerFIFO; + +typedef struct _SBQueryEngine +{ + int queryversion; + int maxupdates; + SBServerFIFO querylist; + SBServerFIFO pendinglist; + SOCKET querysock; + #if !defined(SN_SYSTEMS) + SOCKET icmpsock; + #endif + goa_uint32 mypublicip; + unsigned char serverkeys[MAX_QUERY_KEYS]; + int numserverkeys; + SBEngineCallbackFn ListCallback; + void *instance; +} SBQueryEngine; + + +struct _ServerBrowser +{ + SBQueryEngine engine; + SBServerList list; + SBBool disconnectFlag; + SBBool dontUpdate; + goa_uint32 triggerIP; + unsigned short triggerPort; + ServerBrowserCallback BrowserCallback; + SBConnectToServerCallback ConnectCallback; + void *instance; +}; + +#define SB_ICMP_ECHO 8 +#define SB_ICMP_ECHO_REPLY 0 + +typedef struct _IPHeader { + gsi_u8 ip_hl_ver; + gsi_u8 ip_tos; + gsi_i16 ip_len; + gsi_u16 ip_id; + gsi_i16 ip_off; + gsi_u8 ip_ttl; + gsi_u8 ip_p; + gsi_u16 ip_sum; + struct in_addr ip_src,ip_dst; +} SBIPHeader; + + + +typedef struct _ICMPHeader +{ + gsi_u8 type; + gsi_u8 code; + gsi_u16 cksum; + union { + struct { + gsi_u16 id; + gsi_u16 sequence; + } echo; + gsi_u32 idseq; + gsi_u16 gateway; + struct { + gsi_u16 __notused; + gsi_u16 mtu; + } frag; + } un; +} SBICMPHeader; + + +//server list functions +void SBServerListInit(SBServerList *slist, const char *queryForGamename, const char *queryFromGamename, const char *queryFromKey, int queryFromVersion, SBBool lanBrowse, SBListCallBackFn callback, void *instance); +SBError SBServerListConnectAndQuery(SBServerList *slist, const char *fieldList, const char *serverFilter, int options, int maxServers); +SBError SBServerListGetLANList(SBServerList *slist, unsigned short startport, unsigned short endport, int queryversion); +void SBServerListDisconnect(SBServerList *slist); +void SBServerListCleanup(SBServerList *slist); +void SBServerListClear(SBServerList *slist); +SBError SBGetServerRulesFromMaster(SBServerList *slist, goa_uint32 ip, unsigned short port); +SBError SBSendMessageToServer(SBServerList *slist, goa_uint32 ip, unsigned short port, const char *data, int len); +SBError SBSendNatNegotiateCookieToServer(SBServerList *slist, goa_uint32 ip, unsigned short port, int cookie); +SBError SBSendMaploopRequest(SBServerList *slist, SBServer server, SBMaploopCallbackFn callback); +SBError SBSendPlayerSearchRequest(SBServerList *slist, char *searchName, int searchOptions, int maxResults, SBPlayerSearchCallbackFn callback); +int SBServerListFindServerByIP(SBServerList *slist, goa_uint32 ip, unsigned short port); +int SBServerListFindServer(SBServerList *slist, SBServer findserver); +void SBServerListRemoveAt(SBServerList *slist, int index); +void SBServerListAppendServer(SBServerList *slist, SBServer server); +void SBServerListSort(SBServerList *slist, SBBool ascending, SortInfo sortinfo); +int SBServerListCount(SBServerList *slist); +SBServer SBServerListNth(SBServerList *slist, int i); +SBError SBListThink(SBServerList *slist); +const char *SBLastListErrorA(SBServerList *slist); +const unsigned short *SBLastListErrorW(SBServerList *slist); +void SBSetLastListErrorPtr(SBServerList *slist, char* theError); +void SBFreeDeadList(SBServerList *slist); +void SBAllocateServerList(SBServerList *slist); + +//sbserver functions +SBServer SBAllocServer(SBServerList *slist, goa_uint32 publicip, unsigned short publicport); +void SBServerFree(void *elem); +void SBServerAddKeyValue(SBServer server, const char *keyname, const char *value); +void SBServerAddIntKeyValue(SBServer server, const char *keyname, int value); +void SBServerParseKeyVals(SBServer server, char *keyvals); +void SBServerParseQR2FullKeysSingle(SBServer server, char *data, int len); +void SBServerParseQR2FullKeysSplit(SBServer server, char *data, int len); +void SBServerSetFlags(SBServer server, unsigned char flags); +void SBServerSetPublicAddr(SBServer server, goa_uint32 ip, unsigned short port); +void SBServerSetPrivateAddr(SBServer server, goa_uint32 ip, unsigned short port); +void SBServerSetICMPIP(SBServer server, goa_uint32 icmpip); +void SBServerSetState(SBServer server, unsigned char state); +void SBServerSetNext(SBServer server, SBServer next); +SBServer SBServerGetNext(SBServer server); +unsigned char SBServerGetState(SBServer server); +unsigned char SBServerGetFlags(SBServer server); +unsigned short SBServerGetPublicQueryPortNBO(SBServer server); +int SBIsNullServer(SBServer server); +extern SBServer SBNullServer; + + +//ref-str functions +const char *SBRefStr(SBServerList *slist,const char *str); +void SBReleaseStr(SBServerList *slist,const char *str); +HashTable SBRefStrHash(SBServerList *slist); +void SBRefStrHashCleanup(SBServerList *slist); + +extern char *SBOverrideMasterServer; + + +//query engine functions +void SBQueryEngineInit(SBQueryEngine *engine, int maxupdates, int queryversion, SBBool lanBrowse, SBEngineCallbackFn callback, void *instance); +void SBQueryEngineUpdateServer(SBQueryEngine *engine, SBServer server, int addfront, int querytype, SBBool usequerychallenge); +void SBQueryEngineSetPublicIP(SBQueryEngine *engine, goa_uint32 mypublicip); +SBServer SBQueryEngineUpdateServerByIP(SBQueryEngine *engine, const char *ip, unsigned short queryport, int addfront, int querytype, SBBool usequerychallenge); +void SBQueryEngineThink(SBQueryEngine *engine); +void SBQueryEngineAddQueryKey(SBQueryEngine *engine, unsigned char keyid); +void SBEngineCleanup(SBQueryEngine *engine); +void SBQueryEngineRemoveServerFromFIFOs(SBQueryEngine *engine, SBServer server); +int NTSLengthSB(char *buf, int len); +void SBEngineHaltUpdates(SBQueryEngine *engine); + + +//server browser internal function +SBError ServerBrowserBeginUpdate2(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const char *serverFilter, int updateOptions, int maxServers); + + +// Ascii versions of functions that should still be available in GSI_UNICODE mode +#ifdef GSI_UNICODE +const char *SBServerGetStringValueA(SBServer server, const char *keyname, const char *def); // for peer SDK +int SBServerGetIntValueA(SBServer server, const char *key, int idefault); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_queryengine.c b/xrGameSpy/gamespy/serverbrowsing/sb_queryengine.c new file mode 100644 index 00000000000..ae6015c6219 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_queryengine.c @@ -0,0 +1,700 @@ +#include "sb_serverbrowsing.h" +#include "sb_internal.h" + +#ifdef GSI_MANIC_DEBUG +// Make sure the server isn't already in the fifo +void FIFODebugCheckAdd(SBServerFIFO *fifo, SBServer server) +{ + SBServer aServer = fifo->first; + while(aServer != NULL) + { + assert(aServer != server); + aServer = aServer->next; + } +} + + +// Verify the contents of the fifo +void FIFODebugCheck(SBServerFIFO *fifo) +{ + int i=0; + SBServer aServer; + + assert(fifo != NULL); + aServer = fifo->first; + for (i=0; i < fifo->count; i++) + { + assert(aServer != NULL); + aServer = aServer->next; + } +} +#else +#define FIFODebugCheckAdd(a,b) +#define FIFODebugCheck(a) +#endif + +//FIFO Queue management functions +static void FIFOAddRear(SBServerFIFO *fifo, SBServer server) +{ + FIFODebugCheckAdd(fifo, server); + + if (fifo->last != NULL) + fifo->last->next = server; + fifo->last = server; + server->next = NULL; + if (fifo->first == NULL) + fifo->first = server; + fifo->count++; + + FIFODebugCheck(fifo); +} + +static void FIFOAddFront(SBServerFIFO *fifo, SBServer server) +{ + FIFODebugCheckAdd(fifo, server); + + server->next = fifo->first; + fifo->first = server; + if (fifo->last == NULL) + fifo->last = server; + fifo->count++; + + FIFODebugCheck(fifo); +} + +static SBServer FIFOGetFirst(SBServerFIFO *fifo) +{ + SBServer hold; + hold = fifo->first; + if (hold != NULL) + { + fifo->first = hold->next; + if (fifo->first == NULL) + fifo->last = NULL; + fifo->count--; + } + + FIFODebugCheck(fifo); + return hold; +} + +static SBBool FIFORemove(SBServerFIFO *fifo, SBServer server) +{ + SBServer hold, prev; + prev = NULL; + hold = fifo->first; + while (hold != NULL) + { + if (hold == server) //found + { + if (prev != NULL) //there is a previous.. + prev->next = hold->next; + if (fifo->first == hold) + fifo->first = hold->next; + if (fifo->last == hold) + fifo->last = prev; + fifo->count--; + // assert((fifo->count == 0 && fifo->first == NULL && fifo->last == NULL) || fifo->count > 0); + return SBTrue; + } + prev = hold; + hold = hold->next; + } + + FIFODebugCheck(fifo); + return SBFalse; +} + +static void FIFOClear(SBServerFIFO *fifo) +{ + fifo->first = fifo->last = NULL; + fifo->count = 0; + + FIFODebugCheck(fifo); +} + +#ifdef SB_ICMP_SUPPORT +static unsigned short IPChecksum(const unsigned short *buf, int len) +{ + unsigned long cksum = 0; + + //Calculate the checksum + while (len > 1) + { + cksum += *buf++; + len -= sizeof(unsigned short); + } + + //If we have one char left + if (len) { + cksum += *(unsigned char*)buf; + } + + //Complete the calculations + cksum = (cksum >> 16) + (cksum & 0xffff); + cksum += (cksum >> 16); + + //Return the value (inversed) + return (unsigned short)(~cksum); +} +#endif + +static void QEStartQuery(SBQueryEngine *engine, SBServer server) +{ + unsigned char queryBuffer[256]; + int queryLen; + gsi_bool querySuccess = gsi_false; + struct sockaddr_in saddr; + + saddr.sin_family = AF_INET; + server->updatetime = current_time(); + + if (server->state & STATE_PENDINGICMPQUERY) //send an ICMP ping request + { +#ifdef SB_ICMP_SUPPORT + #if !defined(SN_SYSTEMS) + SBICMPHeader *_icmp = (SBICMPHeader *)(queryBuffer); + //todo: alignment issues on PS2 + _icmp->type = SB_ICMP_ECHO; + _icmp->code = 0; + _icmp->un.idseq = server->updatetime; //no need for network byte order since only we read the reply + _icmp->cksum = 0; + queryLen = sizeof(SBICMPHeader) + 6; + memcpy(queryBuffer + sizeof(SBICMPHeader), &server->publicip, 4); //put some data in the echo packet that we can use to verify the reply + memcpy(queryBuffer + sizeof(SBICMPHeader) + 4, &server->publicport, 2); + _icmp->cksum = IPChecksum((unsigned short *)queryBuffer, queryLen); + if (SBServerGetFlags(server) & ICMP_IP_FLAG) //there is a special ICMP address + { + saddr.sin_addr.s_addr = server->icmpip; + } else + { + saddr.sin_addr.s_addr = server->publicip; + } + + sendto(engine->icmpsock, (char *)queryBuffer, queryLen, 0, (struct sockaddr *)&saddr, sizeof(saddr)); + querySuccess = gsi_true; + #else + int result; + sndev_set_ping_ip_type optval; + optval.ip_addr = server->icmpip; + + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Attempting to send ICMP ping to %s\r\n", inet_ntoa(*((struct in_addr*)&server->icmpip))); + + result = sndev_set_options(0, SN_DEV_SET_PING_IP, (void*)&optval, sizeof(optval)); // tell SN to ping this addr + if (result==SN_PING_FAIL) + { + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Network, GSIDebugLevel_WarmError, + "ICMP ping attempt failed on SNSystems (unknown error)\r\n"); + querySuccess = gsi_true; // let the SDK process failures as a timed out ping + } + else if (result==SN_PING_FULL) + { + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Network, GSIDebugLevel_WarmError, + "ICMP ping attempt failed on SNSystems (SN_PING_FULL)\r\n"); + querySuccess = gsi_false; + } + else + querySuccess = gsi_true; + #endif +#endif + } else //send a UDP query + { + if (engine->queryversion == QVERSION_QR2) + { + if (server->state & STATE_PENDINGQUERYCHALLENGE) + { + // send IP verify request now, but send qr2 query later when IP verify returns + int pos = 0; + queryBuffer[pos++] = QR2_MAGIC_1; + queryBuffer[pos++] = QR2_MAGIC_2; + queryBuffer[pos++] = 0x09; // ip verify prequery + //set the request key + memcpy(&queryBuffer[pos], &server->updatetime, 4); + pos += 4; + queryLen = pos; + } + else + { + gsi_u32 challengeNBO = htonl(server->querychallenge); + int pos = 0; + + //set the header + queryBuffer[pos++] = QR2_MAGIC_1; + queryBuffer[pos++] = QR2_MAGIC_2; + queryBuffer[pos++] = 0; + memcpy(&queryBuffer[pos], &server->updatetime, 4); //set the request key + pos += 4; + if (challengeNBO != 0) + { + memcpy(&queryBuffer[pos], &challengeNBO, 4); // set the challenge + pos += 4; + } + if (server->state & STATE_PENDINGBASICQUERY) + { + int i; + queryBuffer[pos++] = (unsigned char)engine->numserverkeys; + for (i = 0 ; i < engine->numserverkeys ; i++) + queryBuffer[pos++] = engine->serverkeys[i]; + + //don't request any player or team keys + queryBuffer[pos++] = 0x00; + queryBuffer[pos++] = 0x00; + queryLen = pos; + + } else //request all keys for everyone + { + queryBuffer[pos++] = 0xFF; + queryBuffer[pos++] = 0xFF; + queryBuffer[pos++] = 0xFF; + + // Tell the server we support split packets + queryBuffer[pos++] = 0x1; + queryLen = pos; // 11 + } + } + } else //GOA + { + if (server->state & STATE_PENDINGBASICQUERY) //original - do a \basic\info\ query + { + memcpy(queryBuffer, BASIC_GOA_QUERY, BASIC_GOA_QUERY_LEN); + queryLen = BASIC_GOA_QUERY_LEN; + } else //original - do a \status\ query + { + memcpy(queryBuffer, FULL_GOA_QUERY, FULL_GOA_QUERY_LEN); + queryLen = FULL_GOA_QUERY_LEN; + } + } + if (server->publicip == engine->mypublicip && (server->flags & PRIVATE_IP_FLAG)) //try querying the private IP + { + saddr.sin_addr.s_addr = server->privateip; + saddr.sin_port = server->privateport; + } else + { + saddr.sin_addr.s_addr = server->publicip; + saddr.sin_port = server->publicport; + } + sendto(engine->querysock, (char *)queryBuffer, queryLen, 0, (struct sockaddr *)&saddr, sizeof(saddr)); + querySuccess = gsi_true; + } + + //add it to the query list + if (gsi_is_true(querySuccess)) + FIFOAddRear(&engine->querylist, server); + else + server->updatetime = 0; +} + + +void SBQueryEngineInit(SBQueryEngine *engine, int maxupdates, int queryversion, SBBool lanBrowse, SBEngineCallbackFn callback, void *instance) +{ + // 11-03-2004 : Added by Saad Nader + // fix for LANs and unnecessary availability check + /////////////////////////////////////////////////// + if(lanBrowse == SBFalse) + { + if(__GSIACResult != GSIACAvailable) + return; + } + SocketStartUp(); + engine->queryversion = queryversion; + engine->maxupdates = maxupdates; + engine->numserverkeys = 0; + engine->ListCallback = callback; + engine->instance = instance; + engine->mypublicip = 0; + engine->querysock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +#if defined(SB_ICMP_SUPPORT) + #if defined(SN_SYSTEMS) + { + // reset SNSystems internal ICMP ping structures + sndev_set_ping_reset_type optval; + optval.timeout_ms = MAX_QUERY_MSEC; // this gets rounded up to 3 sec + optval.reserved = 0; + sndev_set_options(0, SN_DEV_SET_PING_RESET, &optval, sizeof(optval)); + } + #else + engine->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + #endif +#endif + FIFOClear(&engine->pendinglist); + FIFOClear(&engine->querylist); +} + +void SBQueryEngineSetPublicIP(SBQueryEngine *engine, goa_uint32 mypublicip) +{ + engine->mypublicip = mypublicip; +} + +void SBEngineHaltUpdates(SBQueryEngine *engine) +{ + FIFOClear(&engine->pendinglist); + FIFOClear(&engine->querylist); +} + + +void SBEngineCleanup(SBQueryEngine *engine) +{ + closesocket(engine->querysock); +#ifdef SB_ICMP_SUPPORT + #if !defined(SN_SYSTEMS) + closesocket(engine->icmpsock); + #endif +#endif + engine->querysock = INVALID_SOCKET; + FIFOClear(&engine->pendinglist); + FIFOClear(&engine->querylist); +} + + +//NOTE: the server must not be in the pending or update list currently! +void SBQueryEngineUpdateServer(SBQueryEngine *engine, SBServer server, int addfront, int querytype, SBBool usequerychallenge) +{ + // Assert state of FIFOs + FIFODebugCheckAdd(&engine->pendinglist, server); + FIFODebugCheckAdd(&engine->querylist, server); + + server->state &= (unsigned char)~(STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY|STATE_PENDINGQUERYCHALLENGE|STATE_QUERYFAILED); //clear out these flags + server->splitResponseBitmap = 0; + server->querychallenge = 0; + +#ifndef SB_ICMP_SUPPORT + if (querytype == QTYPE_ICMP) + return; // ICMP not supported +#endif + + if (querytype == QTYPE_BASIC) + server->state |= STATE_PENDINGBASICQUERY; + else if (querytype == QTYPE_FULL) + server->state |= STATE_PENDINGFULLQUERY; + else if (querytype == QTYPE_ICMP) + server->state |= STATE_PENDINGICMPQUERY; + else + return; // hoterror: unsupported querytype! + + if (usequerychallenge && (querytype == QTYPE_FULL || querytype == QTYPE_BASIC)) + server->state |= STATE_PENDINGQUERYCHALLENGE; + + if (engine->querylist.count < engine->maxupdates) //add it now.. + { + QEStartQuery(engine, server); + return; + } + //else need to queue it + + if (addfront) + FIFOAddFront(&engine->pendinglist, server); + else + FIFOAddRear(&engine->pendinglist, server); +} + +SBServer SBQueryEngineUpdateServerByIP(SBQueryEngine *engine, const char *ip, unsigned short queryport, int addfront, int querytype, SBBool usequerychallenge) +{ + //need to create a new server + SBServer server; + goa_uint32 ipaddr; + ipaddr = inet_addr(ip); + server = SBAllocServer(NULL, ipaddr, htons(queryport)); + server->flags = UNSOLICITED_UDP_FLAG; //we assume we can talk directly to it + SBQueryEngineUpdateServer(engine, server, addfront, querytype, usequerychallenge); + return server; +} + + +static void ParseSingleQR2Reply(SBQueryEngine *engine, SBServer server, char *data, int len) +{ + int i; + int dlen; + + // 0x00 == qr2 query response, 0x09 == qr2 challenge response + if (data[0] != 0x00 && data[0] != 0x09) + return; + + //we could test the request key here for added security, or skip + data += 5; + len -= 5; + if (server->state & STATE_PENDINGQUERYCHALLENGE) + { + server->state &= (unsigned char)~(STATE_PENDINGQUERYCHALLENGE); + + if (len > 0) + { + server->querychallenge = (gsi_u32)atoi(data); + FIFORemove(&engine->querylist, server); // remove it + QEStartQuery(engine, server); // readd it with a keys query + engine->ListCallback(engine, qe_challengereceived, server, engine->instance); + return; + } + } + else if (server->state & STATE_PENDINGBASICQUERY) + { + //need to pick out the keys they selected + for (i = 0 ; i < engine->numserverkeys ; i++) + { + dlen = NTSLengthSB(data, len); + if (dlen < 0) + break; + //add the value if its not a Query-From-Master-Only key + if (!qr2_internal_is_master_only_key(qr2_registered_key_list[engine->serverkeys[i]])) + { + SBServerAddKeyValue(server, qr2_registered_key_list[engine->serverkeys[i]], data); + } + data += dlen; + len -= dlen; + } + server->state |= STATE_BASICKEYS|STATE_VALIDPING; + } + else //need to parse out all the keys + { + // Is this a split packet format? + if (*data && strncmp("splitnum", data, 8)==0) + { + SBServerParseQR2FullKeysSplit(server, data, len); + if (server->splitResponseBitmap != 0xFF) + return; + server->state |= STATE_FULLKEYS|STATE_BASICKEYS|STATE_VALIDPING; + } + else + { + // single packet + SBServerParseQR2FullKeysSingle(server, data, len); + server->state |= STATE_FULLKEYS|STATE_BASICKEYS|STATE_VALIDPING; + } + } + server->state &= (unsigned char)~(STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY); + server->updatetime = current_time() - server->updatetime; + FIFORemove(&engine->querylist, server); + engine->ListCallback(engine, qe_updatesuccess, server, engine->instance); +} + +static void ParseSingleGOAReply(SBQueryEngine *engine, SBServer server, char *data, int len) +{ + int isfinal; + //need to check before parse as it will modify the string + isfinal = (strstr(data,"\\final\\") != NULL); + SBServerParseKeyVals(server, data); + if (isfinal) + { + if (server->state & STATE_PENDINGBASICQUERY) + server->state |= STATE_BASICKEYS|STATE_VALIDPING; + else + server->state |= STATE_FULLKEYS|STATE_VALIDPING; + server->state &= (unsigned char)~(STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY); + server->updatetime = current_time() - server->updatetime; + FIFORemove(&engine->querylist, server); + engine->ListCallback(engine, qe_updatesuccess, server, engine->instance); + } + + GSI_UNUSED(len); +} + +static SBBool ParseSingleICMPReply(SBQueryEngine *engine, SBServer server, char *data, int len) +{ +#ifdef SB_ICMP_SUPPORT + SBIPHeader *ipheader = (SBIPHeader *)data; + SBICMPHeader *icmpheader; + int ipheaderlen; + goa_uint32 packetpublicip; + unsigned short packetpublicport; + //todo: byte alignment on PS2 + ipheaderlen = (gsi_u8)(ipheader->ip_hl_ver & 15); + ipheaderlen *= 4; + icmpheader = (SBICMPHeader *)(data + ipheaderlen); + if (icmpheader->type != SB_ICMP_ECHO_REPLY) + return SBFalse; + if (icmpheader->un.idseq != server->updatetime) + return SBFalse; + if (len < ipheaderlen + (int)sizeof(SBICMPHeader) + 6) + return SBFalse; //not enough data + //check the server IP and port + memcpy(&packetpublicip, data + ipheaderlen + sizeof(SBICMPHeader), 4); + memcpy(&packetpublicport, data + ipheaderlen + sizeof(SBICMPHeader) + 4, 2); + if (packetpublicport != server->publicport || packetpublicip != server->publicip) + return SBFalse; + //else its a valid echo + server->updatetime = current_time() - server->updatetime; + server->state |= STATE_VALIDPING; + server->state &= (unsigned char)~(STATE_PENDINGICMPQUERY); + FIFORemove(&engine->querylist, server); + engine->ListCallback(engine, qe_updatesuccess, server, engine->instance); +#else + GSI_UNUSED(engine); + GSI_UNUSED(server); + GSI_UNUSED(data); + GSI_UNUSED(len); +#endif + return SBTrue; + +} + +#if defined(SN_SYSTEMS) && defined(SB_ICMP_SUPPORT) +static void ProcessIncomingICMPReplies(SBQueryEngine *engine) +{ + SBServer server; + int result = 0; + int found = 0; + int i = 0; + sndev_stat_ping_times_type optval; + gsi_i32 optsize = sizeof(optval); + + // Get the ICMP replies from the SNSystems stack + result = sndev_get_status(0, SN_DEV_STAT_PING_TIMES, (void*)&optval, &optsize); + if (result != 0) + { + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Failed on sndev_get_status (checking ICMP pings): %d\r\n", result); + return; + } + if (optval.num_entries == 0) + return; // no outstanding pings (according to sn_systems) + + // match servers to ping responses + for (server = engine->querylist.first; server != NULL; server = server->next) + { + if ((server->state & STATE_PENDINGICMPQUERY) == 0 || + (server->flags & ICMP_IP_FLAG) == 0) + continue; // server not flagged for ICMP + + // find this server + for (i=0; iicmpip == optval.times[i].ip_addr) + { + if (optval.times[i].status == SN_PING_TIMES_CODE_GOTREPLY) + { + server->updatetime = optval.times[i].time_ms; + server->state |= STATE_VALIDPING; + server->state &= (unsigned char)~(STATE_PENDINGICMPQUERY); + FIFORemove(&engine->querylist, server); + engine->ListCallback(engine, qe_updatesuccess, server, engine->instance); + } + //else + // let query engine timeout queries on its own (for simplicity) + + found++; + if (found == optval.num_entries) + return; // found them all + } + } + } +} +#endif // SN_SYSTEMS && SB_ICMP_SUPPORT + +static void ProcessIncomingReplies(SBQueryEngine *engine, SBBool icmpSocket) +{ + int i; + char indata[MAX_RECVFROM_SIZE]; + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + SBServer server; + SOCKET recvSock = 0; + + if (icmpSocket) + { + #ifdef SB_ICMP_SUPPORT + #if defined(SN_SYSTEMS) + ProcessIncomingICMPReplies(engine); + return; + #else + recvSock = engine->icmpsock; + #endif + #endif + } + else + { + recvSock = engine->querysock; + } + + // Process all information in the socket buffer + while(CanReceiveOnSocket(recvSock)) + { + i = (int)recvfrom(recvSock, indata, sizeof(indata) - 1, 0, (struct sockaddr *)&saddr, &saddrlen); + + if (gsiSocketIsError(i)) + break; + indata[i] = 0; + //find the server in our query list + for (server = engine->querylist.first ; server != NULL ; server = server->next) + { + if ((icmpSocket && (server->flags & ICMP_IP_FLAG) && server->icmpip == saddr.sin_addr.s_addr) || //if it's an ICMP query and it matches the ICMP address + (server->publicip == saddr.sin_addr.s_addr && (server->publicport == saddr.sin_port || icmpSocket)) || //if it matches public - port doesnt need to match for ICMP + (server->publicip == engine->mypublicip && (server->flags & PRIVATE_IP_FLAG) && server->privateip == saddr.sin_addr.s_addr && server->privateport == saddr.sin_port)) //or has a private, and matches + { + if (icmpSocket) + { + if (ParseSingleICMPReply(engine, server, indata, i)) + break; //only break if it matches exactly, since we may have multiple outstanding pings to the same ICMPIP for different servers! + } else + { + if (engine->queryversion == QVERSION_QR2) + ParseSingleQR2Reply(engine, server, indata, i); + else + ParseSingleGOAReply(engine, server, indata, i); + break; + } + } + } + } + + +} + +static void TimeoutOldQueries(SBQueryEngine *engine) +{ + gsi_time ctime = current_time(); + while (engine->querylist.first != NULL) + { + if (ctime > engine->querylist.first->updatetime + MAX_QUERY_MSEC) + { + engine->querylist.first->flags |= STATE_QUERYFAILED; + engine->querylist.first->updatetime = MAX_QUERY_MSEC; + engine->querylist.first->flags &= (unsigned char)~(STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY); + engine->ListCallback(engine, qe_updatefailed, engine->querylist.first, engine->instance); + FIFOGetFirst(&engine->querylist); + } else + break; //since servers are added in FIFO order, nothing later can have already expired + } +} + +static void QueueNextQueries(SBQueryEngine *engine) +{ + while (engine->querylist.count < engine->maxupdates && engine->pendinglist.count > 0) + { + SBServer server = FIFOGetFirst(&engine->pendinglist); + QEStartQuery(engine, server); + } +} + +void SBQueryEngineThink(SBQueryEngine *engine) +{ + if (engine->querylist.count == 0) //not querying anything - we can go away + return; + ProcessIncomingReplies(engine, SBFalse); +#ifdef SB_ICMP_SUPPORT + ProcessIncomingReplies(engine, SBTrue); +#endif + TimeoutOldQueries(engine); + if (engine->pendinglist.count > 0) + QueueNextQueries(engine); + if (engine->querylist.count == 0) //we are now idle.. + engine->ListCallback(engine, qe_engineidle, NULL, engine->instance); +} + +void SBQueryEngineAddQueryKey(SBQueryEngine *engine, unsigned char keyid) +{ + if (engine->numserverkeys < MAX_QUERY_KEYS) + engine->serverkeys[engine->numserverkeys++] = keyid; +} + + +//remove a server from our update FIFOs +void SBQueryEngineRemoveServerFromFIFOs(SBQueryEngine *engine, SBServer server) +{ + SBBool ret; + + // remove the server from the current query list + ret = FIFORemove(&engine->querylist, server); + if(ret) + return; // -- Caution: assumes that server will not be in pendinglist + FIFORemove(&engine->pendinglist, server); +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_server.c b/xrGameSpy/gamespy/serverbrowsing/sb_server.c new file mode 100644 index 00000000000..477e850d6ee --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_server.c @@ -0,0 +1,892 @@ +#include "sb_internal.h" +#include "sb_ascii.h" + +//for the unique value list +#if defined(_NITRO) + #define LIST_NUMKEYBUCKETS 100 + #define LIST_NUMKEYCHAINS 2 +#else + #define LIST_NUMKEYBUCKETS 500 + #define LIST_NUMKEYCHAINS 4 +#endif + +// for unicode version of key/value pairs +#define UKEY_LENGTH_MAX 255 +#define UVALUE_LENGTH_MAX 255 + +#ifndef EXTERN_REFSTR_HASH +//global, shared unique value list +#if defined(_WIN32) && !defined(_DLL) && !defined (_USRDLL) && !defined(_MANAGED) && defined(GM_2B) +//for gmaster2b +__declspec( thread ) +#endif +HashTable g_SBRefStrList = NULL; +#endif + + +/*********** + * REF COUNTING STRING HASHTABLE FUNCTIONS + **********/ +static int StringHash(const char *s, int numbuckets); +static int RefStringHash(const void *elem, int numbuckets) +{ + return StringHash(((SBRefString *)elem)->str, numbuckets); +} + + + +/* keyval +* Compares two gkeyvaluepair +*/ + +static int GS_STATIC_CALLBACK RefStringCompare(const void *entry1, const void *entry2) +{ + return strcasecmp(((SBRefString *)entry1)->str,((SBRefString *)entry2)->str); +} + + +static void RefStringFree(void *elem) +{ + gsifree((char *)((SBRefString *)elem)->str); +#ifdef GSI_UNICODE + gsifree((unsigned short *)((SBRefString *)elem)->str_W); +#endif +} + + +#ifndef EXTERN_REFSTR_HASH + +HashTable SBRefStrHash(SBServerList *slist) +{ + if (g_SBRefStrList == NULL) + g_SBRefStrList = TableNew2(sizeof(SBRefString),LIST_NUMKEYBUCKETS,LIST_NUMKEYCHAINS,RefStringHash, RefStringCompare, RefStringFree); + + GSI_UNUSED(slist); + return g_SBRefStrList; +} + +void SBRefStrHashCleanup(SBServerList *slist) +{ + if (g_SBRefStrList != NULL && TableCount(g_SBRefStrList) == 0) + { + TableFree(g_SBRefStrList); + g_SBRefStrList = NULL; + } + + GSI_UNUSED(slist); +} + +#endif + + +void SBServerFree(void *elem) +{ + SBServer server = *(SBServer *)elem; + //free all the keys.. + TableFree(server->keyvals); + server->keyvals = NULL; + gsifree(server); +} + +void SBServerAddKeyValue(SBServer server, const char *keyname, const char *value) +{ + SBKeyValuePair kv; + kv.key = SBRefStr(NULL, keyname); + kv.value = SBRefStr(NULL, value); + TableEnter(server->keyvals, &kv); + + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Misc, GSIDebugLevel_Comment, + "SBServerAddKeyValue added %s\\%s\r\n", keyname, value); +} + +void SBServerAddIntKeyValue(SBServer server, const char *keyname, int value) +{ + char stemp[20]; + sprintf(stemp, "%d", value); + SBServerAddKeyValue(server, keyname, stemp); +} + +typedef struct +{ + SBServerKeyEnumFn EnumFn; + void *instance; +} SBServerEnumData; + +/* ServerEnumKeys +----------------- +Enumerates the keys/values for a given server by calling KeyEnumFn with each +key/value. The user-defined instance data will be passed to the KeyFn callback */ + +static void KeyMapF(void *elem, void *clientData) +{ + SBKeyValuePair *kv = (SBKeyValuePair *)elem; + SBServerEnumData *ped = (SBServerEnumData *)clientData; + +#ifndef GSI_UNICODE + ped->EnumFn((char *)kv->key, (char *)kv->value, ped->instance); +#else + unsigned short key_W[UKEY_LENGTH_MAX]; + unsigned short value_W[UVALUE_LENGTH_MAX]; + UTF8ToUCS2String(kv->key, key_W); + UTF8ToUCS2String(kv->value, value_W); + ped->EnumFn(key_W, value_W, ped->instance); +#endif +} +void SBServerEnumKeys(SBServer server, SBServerKeyEnumFn KeyFn, void *instance) +{ + SBServerEnumData ed; + + ed.EnumFn = KeyFn; + ed.instance = instance; + TableMap(server->keyvals, KeyMapF, &ed); +} + + +const char *SBServerGetStringValueA(SBServer server, const char *keyname, const char *def) +{ + SBKeyValuePair kv, *ptr; + + // 11-03-2004 : Saad Nader + // Check if we are getting a valid server + // before doing anything! + /////////////////////////////////////////// + assert(server); + if (!server) + return NULL; + kv.key = keyname; + ptr = (SBKeyValuePair *)TableLookup(server->keyvals, &kv); + if (ptr == NULL) + return def; + return ptr->value; +} +#ifdef GSI_UNICODE +const unsigned short *SBServerGetStringValueW(SBServer server, const unsigned short *keyname, const unsigned short *def) +{ + char* keyname_A = UCS2ToUTF8StringAlloc(keyname); + const char* value = SBServerGetStringValueA(server, keyname_A, NULL); + if (value == NULL) + return def; + else + { + // Since we need the unicode version, we have to dig down to the + // reference counted string structure + SBRefString ref, *val; + ref.str = value; + val = (SBRefString *)TableLookup(SBRefStrHash(NULL), &ref); + if (val == NULL) + return def; // this shouldn't happen + + return val->str_W; + } +} +#endif + +int SBServerGetIntValueA(SBServer server, const char *key, int idefault) +{ + const char *s, *s2; + // check assumtions during development + GS_ASSERT(key != NULL); + GS_ASSERT(server != NULL); + if (server == NULL) + return idefault; + if (strcmp(key,"ping") == 0) //ooh! they want the ping! + return SBServerGetPing(server); + s = SBServerGetStringValueA(server, key, NULL); + if (s == NULL) + return idefault; + s2 = (*s != '-') ? s : s+1; // check for signed values + if (!isdigit((unsigned char)*s2)) // empty-string/non-numeric should return idefault + return idefault; + else + return atoi(s); +} +#ifdef GSI_UNICODE +int SBServerGetIntValueW(SBServer server, const unsigned short *key, int idefault) +{ + char keyname_A[255]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetIntValueA(server, keyname_A, idefault); +} +#endif + +double SBServerGetFloatValueA(SBServer server, const char *key, double fdefault) +{ + const char *s; + s = SBServerGetStringValueA(server, key, NULL); + if (s == NULL) + return fdefault; + else + return atof(s); +} +#ifdef GSI_UNICODE +double SBServerGetFloatValueW(SBServer server, const unsigned short *key, double fdefault) +{ + char keyname_A[255]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetFloatValueA(server, keyname_A, fdefault); +} +#endif + +SBBool SBServerGetBoolValueA(SBServer server, const char *key, SBBool bdefault) +{ + const char *s; + s = SBServerGetStringValueA(server, key, NULL); + if (!s || !s[0]) + return bdefault; + + // check the first char for known "false" values + if('0' == s[0]|| 'F' == s[0] || 'f' == s[0] || 'N' == s[0] || 'n' == s[0]) + return SBFalse; + + // presume that all other non-zero values are "true" + return SBTrue; +} +#ifdef GSI_UNICODE +SBBool SBServerGetBoolValueW(SBServer server, const unsigned short *key, SBBool bdefault) +{ + char keyname_A[255]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetBoolValueA(server, keyname_A, bdefault); +} +#endif + +const char *SBServerGetPlayerStringValueA(SBServer server, int playernum, const char *key, const char *sdefault) +{ + char keyname[128]; + sprintf(keyname, "%s_%d", key, playernum); + return SBServerGetStringValueA(server, keyname, sdefault); +} +#ifdef GSI_UNICODE +const unsigned short *SBServerGetPlayerStringValueW(SBServer server, int playernum, const unsigned short *key, const unsigned short *sdefault) +{ + char keyname_A[UKEY_LENGTH_MAX]; + char default_A[UKEY_LENGTH_MAX]; + const char* value_A = NULL; + UCS2ToUTF8String(key, keyname_A); + UCS2ToUTF8String(sdefault, default_A); + + value_A = SBServerGetPlayerStringValueA(server, playernum, keyname_A, default_A); + if (value_A == NULL) + return sdefault; + else + { + // Since we need the unicode version, we have to dig down to the SBRefString structure + SBRefString ref, *val; + ref.str = value_A; + val = (SBRefString *)TableLookup(SBRefStrHash(NULL), &ref); + if (val == NULL) + return sdefault; + return val->str_W; + } +} +#endif + +int SBServerGetPlayerIntValueA(SBServer server, int playernum, const char *key, int idefault) +{ + char keyname[128]; + sprintf(keyname, "%s_%d", key, playernum); + return SBServerGetIntValueA(server, keyname, idefault); +} +#ifdef GSI_UNICODE +int SBServerGetPlayerIntValueW(SBServer server, int playernum, const unsigned short *key, int idefault) +{ + char keyname_A[UKEY_LENGTH_MAX]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetPlayerIntValueA(server, playernum, keyname_A, idefault); +} +#endif + +double SBServerGetPlayerFloatValueA(SBServer server, int playernum, const char *key, double fdefault) +{ + char keyname[128]; + sprintf(keyname, "%s_%d", key, playernum); + return SBServerGetFloatValueA(server, keyname, fdefault); +} +#ifdef GSI_UNICODE +double SBServerGetPlayerFloatValueW(SBServer server, int playernum, const unsigned short *key, double fdefault) +{ + char keyname_A[UKEY_LENGTH_MAX]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetPlayerFloatValueA(server, playernum, keyname_A, fdefault); +} +#endif + +const char *SBServerGetTeamStringValueA(SBServer server, int teamnum, const char *key, const char *sdefault) +{ + char keyname[128]; + sprintf(keyname, "%s_t%d", key, teamnum); + return SBServerGetStringValueA(server, keyname, sdefault); +} +#ifdef GSI_UNICODE +const unsigned short *SBServerGetTeamStringValueW(SBServer server, int teamnum, const unsigned short *key, const unsigned short *sdefault) +{ + char keyname_A[UKEY_LENGTH_MAX]; + char default_A[UKEY_LENGTH_MAX]; + const char* value_A = NULL; + UCS2ToUTF8String(key, keyname_A); + UCS2ToUTF8String(sdefault, default_A); + value_A = SBServerGetTeamStringValueA(server, teamnum, keyname_A, default_A); + + if (value_A == NULL) + return sdefault; + else + { + // Since we need the unicode version, we have to dig down to the SBRefString structure + SBRefString ref, *val; + ref.str = value_A; + val = (SBRefString *)TableLookup(SBRefStrHash(NULL), &ref); + if (val == NULL) + return sdefault; + return val->str_W; + } +} +#endif + +int SBServerGetTeamIntValueA(SBServer server, int teamnum, const char *key, int idefault) +{ + char keyname[128]; + sprintf(keyname, "%s_t%d", key, teamnum); + return SBServerGetIntValueA(server, keyname, idefault); +} +#ifdef GSI_UNICODE +int SBServerGetTeamIntValueW(SBServer server, int teamnum, const unsigned short *key, int idefault) +{ + char keyname_A[UKEY_LENGTH_MAX]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetTeamIntValueA(server, teamnum, keyname_A, idefault); +} +#endif + +double SBServerGetTeamFloatValueA(SBServer server, int teamnum, const char *key, double fdefault) +{ + char keyname[128]; + sprintf(keyname, "%s_t%d", key, teamnum); + return SBServerGetFloatValueA(server, keyname, fdefault); +} +#ifdef GSI_UNICODE +double SBServerGetTeamFloatValueW(SBServer server, int teamnum, const unsigned short *key, double fdefault) +{ + char keyname_A[UKEY_LENGTH_MAX]; + UCS2ToUTF8String(key, keyname_A); + return SBServerGetTeamFloatValueA(server, teamnum, keyname_A, fdefault); +} +#endif + +SBBool SBServerHasBasicKeys(SBServer server) +{ + return (((server->state & STATE_BASICKEYS) == STATE_BASICKEYS) ? SBTrue : SBFalse); +} + +SBBool SBServerHasFullKeys(SBServer server) +{ + return (((server->state & STATE_FULLKEYS) == STATE_FULLKEYS) ? SBTrue : SBFalse); +} + +SBBool SBServerHasValidPing(SBServer server) +{ + return (((server->state & STATE_VALIDPING) == STATE_VALIDPING) ? SBTrue : SBFalse); +} + + +char *SBServerGetPublicAddress(SBServer server) +{ + return (char *)inet_ntoa(*(struct in_addr *)&server->publicip); +} + +unsigned int SBServerGetPublicInetAddress(SBServer server) +{ + return server->publicip; +} + + +unsigned short SBServerGetPublicQueryPort(SBServer server) +{ + return ntohs(server->publicport); +} + +unsigned short SBServerGetPublicQueryPortNBO(SBServer server) +{ + return server->publicport; +} + +SBBool SBServerHasPrivateAddress(SBServer server) +{ + return (((server->flags & PRIVATE_IP_FLAG) == PRIVATE_IP_FLAG) ? SBTrue : SBFalse); +} + + + +SBBool SBServerDirectConnect(SBServer server) +{ + return (((server->flags & UNSOLICITED_UDP_FLAG) == UNSOLICITED_UDP_FLAG) ? SBTrue : SBFalse); +} + +char *SBServerGetPrivateAddress(SBServer server) +{ + return (char *)inet_ntoa(*(struct in_addr *)&server->privateip); +} + +unsigned int SBServerGetPrivateInetAddress(SBServer server) +{ + return server->privateip; +} + + +unsigned short SBServerGetPrivateQueryPort(SBServer server) +{ + return ntohs(server->privateport); +} + +void SBServerSetNext(SBServer server, SBServer next) +{ + server->next = next; +} + +SBServer SBServerGetNext(SBServer server) +{ + return server->next; +} + +static int CheckValidKey(char *key) +{ + const char *InvalidKeys[]={"queryid","final"}; + int i; + for (i = 0; i < sizeof(InvalidKeys)/sizeof(InvalidKeys[0]); i++) + { + if (strcmp(key,InvalidKeys[i]) == 0) + return 0; + } + return 1; +} + +static char *mytok(char *instr, char delim) +{ + char *result; + static char *thestr; + + if (instr) + thestr = instr; + result=thestr; + while (*thestr && *thestr != delim) + { + thestr++; + } + if (thestr == result) + result = NULL; + if (*thestr) //not the null term + *thestr++ = '\0'; + return result; +} + + +void SBServerParseKeyVals(SBServer server, char *keyvals) +{ + char *k, *v; + + k = mytok(++keyvals,'\\'); //skip over starting backslash + while (k != NULL) + { + v = mytok(NULL,'\\'); + if (v == NULL) + v = ""; + if (CheckValidKey(k)) + { + //add the value if its not a Query-From-Master-Only key + if (!qr2_internal_is_master_only_key(k)) + { + SBServerAddKeyValue(server, k, v); + } + } + k = mytok(NULL,'\\'); + } +} + + +/* +Query Response Format +Packet Type: 1 Byte +Request Key: 4 Bytes (copied from request packet) + +Server Keys (if number of keys requested > 0) +If server key list specified: +Server Values: NTS, one per key specified +If server key list not specified: +Server Keys / Server Values: NTS Pairs, terminated with NUL + +Player Keys (if number of keys requested > 0) +Number of Players: 2 Bytes +If player key list NOT specified + Player Keys: NTS, one per key, terminated with NUL +Player Values: NTS, one per key specified, per player + +Team Keys (if number of keys requested > 0) +Number of Teams: 2 Bytes +If team key list NOT specified + Team Keys: NTS, one per key, terminated with NUL +Team Values: NTS, one per key specified, per team + +*/ +void SBServerParseQR2FullKeysSingle(SBServer server, char *data, int len) +{ + int dlen; + char *k; + char *v; + char *keys; + int nkeys; + unsigned short nunits; + int pflag; + int i,j; + char tempkey[128]; + //first pull out all the server keys/values + while (*data) + { + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; //not a full NTS + k = data; + data += dlen; + len -= dlen; + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; //not a full NTS + v = data; + data += dlen; + len -= dlen; + + //add the value if its not a Query-From-Master-Only key + if (!qr2_internal_is_master_only_key(k)) + { + SBServerAddKeyValue(server, k, v); + } + } + //skip the NUL + data++; + len--; + //now get out the # of players (or teams) .. we do this whole thing 2X, once for players once for teams + for (pflag = 0 ; pflag < 2 ; pflag++) + { + if (len < 2) + return; + memcpy(&nunits, data, 2); + nunits = ntohs(nunits); + data += 2; + len -= 2; + keys = data; + nkeys = 0; + //count up the number of keys.. + while (*data) + { + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; //not all there + if (dlen > 100) //key is too long, may cause buffer overrun + return; + nkeys++; + data += dlen; + len -= dlen; + } + //skip the NUL + data++; + len--; + //now for each player/team + for (i = 0 ; i < nunits ; i++) + { + k = keys; + //for each key.. + for (j = 0 ; j < nkeys ; j++) + { + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; //not all there + sprintf(tempkey, "%s%d", k, i); + SBServerAddKeyValue(server, tempkey, data); + data += dlen; + len -= dlen; + k += strlen(k) + 1; //skip to the next key + } + } + } + +} + + +// FullKeys with split response support +// Goes something like: +// [qr2header]["splitnum"][num (byte)][keytype] +// if keytype is server, read KV's until a NULL +// otherwise read a keyname, then a number of values until NULL +#define QR2_SPLITPACKET_NUMSTRING "splitnum" +#define QR2_SPLITPACKET_MAX 7 // -xxxxxxx +#define QR2_SPLITPACKET_FINAL (1<<7) // x------- +void SBServerParseQR2FullKeysSplit(SBServer server, char *data, int len) +{ + int dlen; + char *k; + char *v; + unsigned int packetNum = 0; + gsi_bool isFinal = gsi_false; + + // make sure it's valid + if (*data == '\0') + return; + + // data should have "splitnum" followed by BINARY key + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; + k = data; + data += dlen; + len -= dlen; + + if (strncasecmp(QR2_SPLITPACKET_NUMSTRING,k,strlen(QR2_SPLITPACKET_NUMSTRING))!=0) + return; + if (len < 1) + return; + + packetNum = (unsigned int)((unsigned char)*data); + data++; + len--; + + // check final flag + if ((packetNum & QR2_SPLITPACKET_FINAL) == QR2_SPLITPACKET_FINAL) + { + isFinal = gsi_true; + packetNum ^= QR2_SPLITPACKET_FINAL; + } + + // sanity check the packet num + if (packetNum > QR2_SPLITPACKET_MAX) + return; + + // update the received flags + if (isFinal == SBTrue) + // mark all bits higher than the final packet + server->splitResponseBitmap |= (char)(0xFF<splitResponseBitmap |= (1< 0) + { + int keyType = 0; + int nindex = 0; + + // Read the key type + keyType = *data; + data++; + len--; + + if (keyType < 0 || keyType > 2) + { + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Split packet parse error, invalid key type! (%d)\r\n", keyType); + return; // invalid key type! + } + + // read keys until section terminator + while(*data) + { + // Read key name + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; + k = data; + data += dlen; + len -= dlen; + + if (keyType == 0) + { + // read the server key value + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; + v = data; + data += dlen; + len -= dlen; + + //add the value if its not a Query-From-Master-Only key + if (!qr2_internal_is_master_only_key(k)) + { + SBServerAddKeyValue(server, k, v); + } + } + else + { + char tempkey[128]; + + // Read first player/team number + if (len < 1) + return; + + nindex = *data; + data++; + len--; + + // read values until + while(*data) + { + // read the value + dlen = NTSLengthSB(data, len); + if (dlen < 0) + return; + v = data; + data += dlen; + len -= dlen; + // append team or player index before adding + sprintf(tempkey, "%s%d", k, nindex); + SBServerAddKeyValue(server, tempkey, v); + nindex++; // index increments from start + } + + // skip the null (key terminator) + if (len > 0) + { + data++; + len--; + } + } + } + + // skip the null (section terminator) + if (len > 0) + { + if (*data != '\0') + { + gsDebugFormat(GSIDebugCat_SB, GSIDebugType_Network, GSIDebugLevel_WarmError, + "Split packet parse error, NULL byte expected!\r\n"); + return; // ERROR! + } + data++; + len--; + } + } +} + +/*********** + * UTILITY FUNCTIONS + **********/ +#define MULTIPLIER -1664117991 +static int StringHash(const char *s, int numbuckets) +{ + goa_uint32 hashcode = 0; + while (*s != 0) + { + hashcode = (goa_uint32)((int)hashcode * MULTIPLIER + tolower(*s)); + s++; + } + return (int)(hashcode % numbuckets); + +} + +static void KeyValFree(void *elem) +{ + SBKeyValuePair *kv = (SBKeyValuePair *)elem; + SBReleaseStr(NULL, kv->key); + SBReleaseStr(NULL, kv->value); +} + +static int KeyValHashKey(const void *elem, int numbuckets) +{ + return StringHash(((SBKeyValuePair *)elem)->key, numbuckets); +} + + +static int GS_STATIC_CALLBACK KeyValCompareKey(const void *entry1, const void *entry2) +{ + GS_ASSERT(entry1) + GS_ASSERT(entry2) + if ( + (((SBKeyValuePair *)entry1)->key == NULL) || + (((SBKeyValuePair *)entry2)->key == NULL) + ) + return 1;// treat NULL as not the same + + return strcasecmp(((SBKeyValuePair *)entry1)->key, ((SBKeyValuePair *)entry2)->key); +} + + +int SBServerGetPing(SBServer server) +{ + return (int) server->updatetime; +} + +#define NUM_BUCKETS 8 +#define NUM_CHAINS 4 + +//todo: benchmark sorted darray vs. hashtable - memory + speed +SBServer SBAllocServer(SBServerList *slist, goa_uint32 publicip, unsigned short publicport) +{ + SBServer server; + server = (SBServer)gsimalloc(sizeof(struct _SBServer)); + if (server == NULL) + return NULL; + server->keyvals = TableNew2(sizeof(SBKeyValuePair),NUM_BUCKETS,NUM_CHAINS, KeyValHashKey, KeyValCompareKey, KeyValFree); + if (server->keyvals == NULL) + { + gsifree(server); + return NULL; + } + server->state = 0; + server->flags = 0; + server->next = NULL; + server->updatetime = 0; + server->icmpip = 0; + server->publicip = publicip; + server->publicport = publicport; + server->privateip = 0; + server->privateport = 0; + + GSI_UNUSED(slist); + return server; +} + + + +void SBServerSetFlags(SBServer server, unsigned char flags) +{ + server->flags = flags; +} +void SBServerSetPublicAddr(SBServer server, goa_uint32 ip, unsigned short port) +{ + server->publicip = ip; + server->publicport = port; + +} +void SBServerSetPrivateAddr(SBServer server, goa_uint32 ip, unsigned short port) +{ + server->privateip = ip; + server->privateport = port; + +} +void SBServerSetICMPIP(SBServer server, goa_uint32 icmpip) +{ + server->icmpip = icmpip; + +} +void SBServerSetState(SBServer server, unsigned char state) +{ + server->state = state; + +} +unsigned char SBServerGetState(SBServer server) +{ + return server->state; + +} +unsigned char SBServerGetFlags(SBServer server) +{ + return server->flags; + +} + +int SBIsNullServer(SBServer server) +{ + return (server == SBNullServer) ? 1 : 0; +} + +SBServer SBNullServer = NULL; diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_serverbrowsing.c b/xrGameSpy/gamespy/serverbrowsing/sb_serverbrowsing.c new file mode 100644 index 00000000000..a8a64f0362d --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_serverbrowsing.c @@ -0,0 +1,681 @@ +#include "sb_internal.h" +#include "sb_ascii.h" +#include "../natneg/natneg.h" + +//Future Versions: +//ICMP Ping support (icmp engine) + + +//internal callback proxy for server list +static void ListCallback(SBServerList *serverlist, SBListCallbackReason reason, SBServer server, void *instance) +{ + ServerBrowser sb = (ServerBrowser)instance; + switch (reason) + { + case slc_serveradded: + sb->BrowserCallback(sb, sbc_serveradded, server, sb->instance); + if ((server->state & (STATE_BASICKEYS|STATE_FULLKEYS)) == 0 || (server->state & STATE_VALIDPING) == 0) //we need to do an update + { + // Don't update if an update is already pending + if (server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY)) + break; + + if (!sb->dontUpdate) //if this flag is set, we don't want to trigger updates + { + int qtype; + if (server->flags & UNSOLICITED_UDP_FLAG) + { + if (sb->list.state == sl_lanbrowse || sb->engine.numserverkeys == 0) + qtype = QTYPE_FULL; + else + qtype = QTYPE_BASIC; + } else + qtype = QTYPE_ICMP; //we can only do an ICMP query + + if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE) + SBQueryEngineUpdateServer(&sb->engine, server, 0, qtype, SBTrue); + else + SBQueryEngineUpdateServer(&sb->engine, server, 0, qtype, SBFalse); + + } + } + break; + case slc_serverupdated: + if ((server->state & (STATE_BASICKEYS|STATE_FULLKEYS|STATE_VALIDPING)) == 0) //if it was updated, but with no data, then the update failed! + sb->BrowserCallback(sb, sbc_serverupdatefailed, server, sb->instance); + else + sb->BrowserCallback(sb, sbc_serverupdated, server, sb->instance); + break; + case slc_serverdeleted: + if ((server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY)) != 0) + SBQueryEngineRemoveServerFromFIFOs(&sb->engine, server); + sb->BrowserCallback(sb, sbc_serverdeleted, server, sb->instance); + break; + case slc_initiallistcomplete: + if (sb->disconnectFlag) + SBServerListDisconnect(serverlist); + // If there aren't any servers to query, call the completed callback + if (ArrayLength(serverlist->servers)==0 || sb->engine.querylist.count==0) + sb->BrowserCallback(sb, sbc_updatecomplete, NULL, sb->instance); + break; + case slc_disconnected: + break; + case slc_queryerror: + sb->BrowserCallback(sb, sbc_queryerror, NULL, sb->instance); + break; + case slc_publicipdetermined: + SBQueryEngineSetPublicIP(&sb->engine, sb->list.mypublicip); + break; + case slc_serverchallengereceived: + break; + } + if (server != NULL && server->publicip == sb->triggerIP && server->publicport == sb->triggerPort) + sb->triggerIP = 0; //clear the trigger +} + +//internal callback proxy for query engine +static void EngineCallback(SBQueryEnginePtr engine, SBQueryEngineCallbackReason reason, SBServer server, void *instance) +{ + ServerBrowser sb = (ServerBrowser)instance; + switch (reason) + { + case qe_updatefailed: + sb->BrowserCallback(sb, sbc_serverupdatefailed, server, sb->instance); + break; + case qe_updatesuccess: + sb->BrowserCallback(sb, sbc_serverupdated, server, sb->instance); + break; + case qe_engineidle: + sb->BrowserCallback(sb, sbc_updatecomplete, server, sb->instance); + break; + case qe_challengereceived: + sb->BrowserCallback(sb, sbc_serverchallengereceived, server, sb->instance); + //challenge received will return instead of break - since the game has not yet been updated + return; + } + if (server != NULL && server->publicip == sb->triggerIP && server->publicport == sb->triggerPort) + sb->triggerIP = 0; //clear the trigger + + GSI_UNUSED(engine); +} + + + +ServerBrowser ServerBrowserNewA(const char *queryForGamename, const char *queryFromGamename, const char *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool lanBrowse, ServerBrowserCallback callback, void *instance) +{ + ServerBrowser sb; + if(lanBrowse == SBFalse) + { + if(__GSIACResult != GSIACAvailable) + return NULL; + } + + sb = (ServerBrowser)gsimalloc(sizeof(struct _ServerBrowser)); + if (sb == NULL) + return NULL; + sb->BrowserCallback = callback; + sb->ConnectCallback = NULL; + sb->instance = instance; + sb->dontUpdate = SBFalse; + SBServerListInit(&sb->list, queryForGamename, queryFromGamename, queryFromKey, queryFromVersion, lanBrowse, ListCallback, sb); + SBQueryEngineInit(&sb->engine, maxConcUpdates, queryVersion, lanBrowse, EngineCallback, sb); + return sb; +} +#ifdef GSI_UNICODE +ServerBrowser ServerBrowserNewW(const unsigned short *queryForGamename, const unsigned short *queryFromGamename, const unsigned short *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool lanBrowse, ServerBrowserCallback callback, void *instance) +{ + char forGameName_A[255]; + char fromGameName_A[255]; + char fromGameKey_A[255]; + + assert(queryForGamename != NULL); + assert(queryFromGamename != NULL); + assert(queryFromKey != NULL); + + UCS2ToAsciiString(queryForGamename, forGameName_A); + UCS2ToAsciiString(queryFromGamename, fromGameName_A); + UCS2ToAsciiString(queryFromKey, fromGameKey_A); + return ServerBrowserNewA(forGameName_A, fromGameName_A, fromGameKey_A, queryFromVersion, maxConcUpdates, queryVersion, lanBrowse, callback, instance); +} +#endif + +void ServerBrowserFree(ServerBrowser sb) +{ + SBServerListCleanup(&sb->list); + SBEngineCleanup(&sb->engine); + NNFreeNegotiateList(); + gsifree(sb); +} + +//internal version that allows passing of additional options +SBError ServerBrowserBeginUpdate2(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const char *serverFilter, int updateOptions, int maxServers) +{ + char keyList[MAX_FIELD_LIST_LEN] = ""; + int listLen = 0; + int i; + int keylen; + SBError err; + + sb->disconnectFlag = disconnectOnComplete; + //clear this out in case it was already set + sb->engine.numserverkeys = 0; + //build the key list... + for (i = 0 ; i < numBasicFields ; i++) + { + keylen = (int)strlen(qr2_registered_key_list[basicFields[i]]); + if (listLen + keylen + 1 >= MAX_FIELD_LIST_LEN) + break; //can't add this field, too long + listLen += sprintf(keyList + listLen, "\\%s", qr2_registered_key_list[basicFields[i]]); + //add to the engine query list + SBQueryEngineAddQueryKey(&sb->engine, basicFields[i]); + } + +#if defined(SN_SYSTEMS) && defined(SB_ICMP_SUPPORT) + { + // reset SNSystems internal ICMP ping structures + sndev_set_ping_reset_type optval; + optval.timeout_ms = MAX_QUERY_MSEC; // this gets rounded up to 3 sec + optval.reserved = 0; + sndev_set_options(0, SN_DEV_SET_PING_RESET, &optval, sizeof(optval)); + } +#endif + + err = SBServerListConnectAndQuery(&sb->list, keyList, serverFilter, updateOptions, maxServers); + if (err != sbe_noerror) + return err; + + if (!async) //loop while we are still getting the main list and the engine is updating... + { + while ((sb->list.state == sl_mainlist) || ((sb->engine.querylist.count > 0) && (err == sbe_noerror))) + { + msleep(10); + err = ServerBrowserThink(sb); + } + } + return err; +} + + +SBError ServerBrowserUpdateA(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const char *serverFilter) +{ + return ServerBrowserBeginUpdate2(sb, async, disconnectOnComplete, basicFields, numBasicFields, serverFilter, 0, 0); +} +#ifdef GSI_UNICODE +SBError ServerBrowserUpdateW(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const unsigned short *serverFilter) +{ + char serverFilter_A[1024]; + if (serverFilter != NULL) + UCS2ToUTF8String(serverFilter, serverFilter_A); + return ServerBrowserUpdateA(sb, async, disconnectOnComplete, basicFields, numBasicFields, (serverFilter != NULL) ? serverFilter_A:NULL); +} +#endif + +SBError ServerBrowserLimitUpdateA(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const char *serverFilter, int maxServers) +{ + return ServerBrowserBeginUpdate2(sb, async, disconnectOnComplete, basicFields, numBasicFields, serverFilter, LIMIT_RESULT_COUNT, maxServers); +} +#ifdef GSI_UNICODE +SBError ServerBrowserLimitUpdateW(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const unsigned short *serverFilter, int maxServers) +{ + char serverFilter_A[1024]; + if (serverFilter != NULL) + UCS2ToUTF8String(serverFilter, serverFilter_A); + return ServerBrowserLimitUpdateA(sb, async, disconnectOnComplete, basicFields, numBasicFields, (serverFilter != NULL) ? serverFilter_A:NULL, maxServers); +} +#endif + +SBError ServerBrowserLANUpdate(ServerBrowser sb, SBBool async, unsigned short startSearchPort, unsigned short endSearchPort) +{ + SBError err = sbe_noerror; + ServerBrowserHalt(sb); + SBServerListGetLANList(&sb->list, startSearchPort, endSearchPort, sb->engine.queryversion); + if (!async) + { + while ((sb->list.state == sl_lanbrowse) || ((sb->engine.querylist.count > 0) && (err == sbe_noerror))) + { + msleep(10); + err = ServerBrowserThink(sb); + } + } + return err; +} + +static SBError WaitForTriggerUpdate(ServerBrowser sb, SBBool viaMaster) +{ + SBError err = sbe_noerror; + //wait until info is received for the triggerIP + while (sb->triggerIP != 0 && err == sbe_noerror) + { + msleep(10); + err = ServerBrowserThink(sb); + if (viaMaster && sb->list.state == sb_disconnected) //we were supposed to get from master, and it's disconnected + break; + } + return err; + +} + + +SBError ServerBrowserSendMessageToServerA(ServerBrowser sb, const char *ip, unsigned short port, const char *data, int len) +{ + return SBSendMessageToServer(&sb->list, inet_addr(ip), htons(port), data, len); +} +#ifdef GSI_UNICODE +SBError ServerBrowserSendMessageToServerW(ServerBrowser sb, const unsigned short *ip, unsigned short port, const char *data, int len) +{ + char ip_A[128]; + UCS2ToAsciiString(ip, ip_A); + return ServerBrowserSendMessageToServerA(sb, ip_A, port, data, len); +} +#endif + +SBError ServerBrowserSendNatNegotiateCookieToServerA(ServerBrowser sb, const char *ip, unsigned short port, int cookie) +{ + return SBSendNatNegotiateCookieToServer(&sb->list, inet_addr(ip), htons(port), cookie); +} +#ifdef GSI_UNICODE +SBError ServerBrowserSendNatNegotiateCookieToServerW(ServerBrowser sb, const unsigned short *ip, unsigned short port, int cookie) +{ + char ip_A[128]; + UCS2ToAsciiString(ip, ip_A); + return ServerBrowserSendNatNegotiateCookieToServerA(sb, ip_A, port, cookie); +} +#endif + +static void NatNegProgressCallback(NegotiateState state, void *userdata) +{ + // we don't do anything here + GSI_UNUSED(state); + GSI_UNUSED(userdata); +} + +static void NatNegCompletedCallback(NegotiateResult result, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata) +{ + ServerBrowser sb = (ServerBrowser)userdata; + + if(result == nr_success) + { + sb->ConnectCallback(sb, sbcs_succeeded, gamesocket, remoteaddr, sb->instance); + } + else + { + sb->ConnectCallback(sb, sbcs_failed, INVALID_SOCKET, NULL, sb->instance); + } + + sb->ConnectCallback = NULL; + + GSI_UNUSED(remoteaddr); +} + +SBError ServerBrowserConnectToServer(ServerBrowser sb, SBServer server, SBConnectToServerCallback callback) +{ + SBError sbError; + NegotiateError nnError; + int cookie; + + if((sb == NULL) || (server == NULL) || (callback == NULL)) + return sbe_paramerror; + + if(sb->ConnectCallback != NULL) + return sbe_connecterror; + + // for now, always do natneg + + // send a cookie to the server + Util_RandSeed((unsigned long)current_time()); + cookie = Util_RandInt(GSI_MIN_I32, GSI_MAX_I32); + sbError = ServerBrowserSendNatNegotiateCookieToServerA(sb, SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server), cookie); + if(sbError != sbe_noerror) + return sbError; + + // start the nn + nnError = NNBeginNegotiation(cookie, 0, NatNegProgressCallback, NatNegCompletedCallback, sb); + if(nnError != ne_noerror) + return sbe_connecterror; + + sb->ConnectCallback = callback; + + return sbe_noerror; +} + +SBError ServerBrowserAuxUpdateIPA(ServerBrowser sb, const char *ip, unsigned short port, SBBool viaMaster, SBBool async, SBBool fullUpdate) +{ + + SBError err = sbe_noerror; + sb->dontUpdate = SBTrue; + + if (!viaMaster) //do an engine query + { + SBServer server; + int i; + SBBool usequerychallenge = (sb->list.backendgameflags & QR2_USE_QUERY_CHALLENGE) > 0 ? SBTrue:SBFalse; + + //need to see if the server exists... + i = SBServerListFindServerByIP(&sb->list, inet_addr(ip), htons(port)); + if (i == -1) + { + server = SBQueryEngineUpdateServerByIP(&sb->engine, ip, port, 1, (fullUpdate) ? QTYPE_FULL : QTYPE_BASIC, usequerychallenge); + SBServerListAppendServer(&sb->list, server); + } + else + server = SBServerListNth(&sb->list, i); + + // Don't overwrite the existing update, otherwise the response for the first update + // will be mistaken as the response for the second update. (Which is bad if they have different update parameters.) + if (server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY)) + return sbe_duplicateupdateerror; + else + SBQueryEngineUpdateServer(&sb->engine, server, 1, (fullUpdate) ? QTYPE_FULL : QTYPE_BASIC, usequerychallenge); + + } else //do a master update + { + err = SBGetServerRulesFromMaster(&sb->list, inet_addr(ip), htons(port)); + //this will add the server itself.. + } + if (!async && err == sbe_noerror) + { + sb->triggerIP = inet_addr(ip); + sb->triggerPort = htons(port); + err = WaitForTriggerUpdate(sb, viaMaster); + } + sb->dontUpdate = SBFalse; + return err; +} +#ifdef GSI_UNICODE +SBError ServerBrowserAuxUpdateIPW(ServerBrowser sb, const unsigned short *ip, unsigned short port, SBBool viaMaster, SBBool async, SBBool fullUpdate) +{ + char ip_A[128]; + UCS2ToAsciiString(ip, ip_A); + return ServerBrowserAuxUpdateIPA(sb, ip_A, port, viaMaster, async, fullUpdate); +} +#endif + +SBError ServerBrowserAuxUpdateServer(ServerBrowser sb, SBServer server, SBBool async, SBBool fullUpdate) +{ + SBBool viaMaster; + SBError err = sbe_noerror; + SBBool usequerychallenge = (sb->list.backendgameflags & QR2_USE_QUERY_CHALLENGE) > 0 ? SBTrue:SBFalse; + + sb->dontUpdate = SBTrue; + + if (server->flags & UNSOLICITED_UDP_FLAG) //do an engine query + { + //remove from the existing update lists if present + SBQueryEngineRemoveServerFromFIFOs(&sb->engine, server); + SBQueryEngineUpdateServer(&sb->engine, server, 1, (fullUpdate) ? QTYPE_FULL : QTYPE_BASIC, usequerychallenge); + viaMaster = SBFalse; + } else //do a master update + { + err = SBGetServerRulesFromMaster(&sb->list, server->publicip, server->publicport); + viaMaster = SBTrue; + } + if (!async && err == sbe_noerror) + { + sb->triggerIP = server->publicip; + sb->triggerPort = server->publicport; + err = WaitForTriggerUpdate(sb, viaMaster); + } + sb->dontUpdate = SBFalse; + return err; +} + +void ServerBrowserRemoveIPA(ServerBrowser sb, const char *ip, unsigned short port) +{ + int i = SBServerListFindServerByIP(&sb->list, inet_addr(ip), htons(port)); + if (i != -1) + SBServerListRemoveAt(&sb->list, i); +} +#ifdef GSI_UNICODE +void ServerBrowserRemoveIPW(ServerBrowser sb, const unsigned short *ip, unsigned short port) +{ + char ip_A[128]; + UCS2ToAsciiString(ip, ip_A); + ServerBrowserRemoveIPA(sb, ip_A, port); +} +#endif + +void ServerBrowserRemoveServer(ServerBrowser sb, SBServer server) +{ + int i = SBServerListFindServer(&sb->list, server); + if (i != -1) + SBServerListRemoveAt(&sb->list, i); +} + +SBError ServerBrowserThink(ServerBrowser sb) +{ + NNThink(); + SBQueryEngineThink(&sb->engine); + return SBListThink(&sb->list); +} + +void ServerBrowserHalt(ServerBrowser sb) +{ + //stop the list + SBServerListDisconnect(&sb->list); + //stop the query engine... + SBEngineHaltUpdates(&sb->engine); + +} + +void ServerBrowserClear(ServerBrowser sb) +{ + ServerBrowserHalt(sb); + SBServerListClear(&sb->list); +} + +const char *ServerBrowserErrorDescA(ServerBrowser sb, SBError error) +{ + switch (error) + { + case sbe_noerror: + return "None"; + //break; + case sbe_socketerror: + return "Socket creation error"; + //break; + case sbe_dnserror: + return "DNS lookup error"; + //break; + case sbe_connecterror: + return "Connection failed"; + //break; + case sbe_dataerror: + return "Data stream error"; + //break; + case sbe_allocerror: + return "Memory allocation error"; + //break; + case sbe_paramerror: + return "Function parameter error"; + //break; + case sbe_duplicateupdateerror: + return "Duplicate update request error"; + //break; + } + + GSI_UNUSED(sb); + return ""; +} +#ifdef GSI_UNICODE +const unsigned short *ServerBrowserErrorDescW(ServerBrowser sb, SBError error) +{ + switch (error) + { + case sbe_noerror: + return L"None"; + break; + case sbe_socketerror: + return L"Socket creation error"; + break; + case sbe_dnserror: + return L"DNS lookup error"; + break; + case sbe_connecterror: + return L"Connection failed"; + break; + case sbe_dataerror: + return L"Data stream error"; + break; + case sbe_allocerror: + return L"Memory allocation error"; + break; + case sbe_paramerror: + return L"Function parameter error"; + break; + case sbe_duplicateupdateerror: + return L"Duplicate update request error"; + break; + } + return L""; + + GSI_UNUSED(sb); +} +#endif + +const char *ServerBrowserListQueryErrorA(ServerBrowser sb) +{ + return SBLastListErrorA(&sb->list); +} +#ifdef GSI_UNICODE +const unsigned short *ServerBrowserListQueryErrorW(ServerBrowser sb) +{ + return SBLastListErrorW(&sb->list); +} +#endif + +SBState ServerBrowserState(ServerBrowser sb) +{ + if (sb->engine.querylist.count > 0) + return sb_querying; + if (sb->list.state == sl_mainlist || sb->list.state == sl_lanbrowse) + return sb_listxfer; + if (sb->list.state == sl_disconnected) + return sb_disconnected; + return sb_connected; +} + +int ServerBrowserPendingQueryCount(ServerBrowser sb) +{ + return sb->engine.querylist.count + sb->engine.pendinglist.count; +} + +SBServer ServerBrowserGetServer(ServerBrowser sb, int index) +{ + return SBServerListNth(&sb->list, index); +} + +SBServer ServerBrowserGetServerByIPA(ServerBrowser sb, const char* ip, unsigned short port) +{ + int anIndex = -1; + goa_uint32 anIP = 0; + unsigned short aPortNBO = htons(port); + + anIP = inet_addr(ip); + anIndex = SBServerListFindServerByIP(&sb->list, anIP, aPortNBO); + if (anIndex != -1) + return SBServerListNth(&sb->list, anIndex); + return NULL; +} +#ifdef GSI_UNICODE +SBServer ServerBrowserGetServerByIPW(ServerBrowser sb, const unsigned short* ip, unsigned short port) +{ + char ip_A[20]; + + if(ip == NULL || wcslen(ip) > 16) + return NULL; + + UCS2ToAsciiString(ip, ip_A); + return ServerBrowserGetServerByIPA(sb, ip_A, port); +} +#endif + +int ServerBrowserCount(ServerBrowser sb) +{ + return SBServerListCount(&sb->list); +} + +void ServerBrowserSortA(ServerBrowser sb, SBBool ascending, const char *sortkey, SBCompareMode comparemode) +{ + SortInfo info; + info.comparemode = comparemode; +#ifdef GSI_UNICODE + GS_ASSERT(sortkey != NULL && _tcslen((const unsigned short *)sortkey) <= SORTKEY_LENGTH); + _tcscpy(info.sortkey, (const unsigned short *)sortkey); +#else + GS_ASSERT(sortkey != NULL && _tcslen(sortkey) <= SORTKEY_LENGTH); + _tcscpy(info.sortkey, sortkey); +#endif + SBServerListSort(&sb->list, ascending, info); +} +#ifdef GSI_UNICODE +void ServerBrowserSortW(ServerBrowser sb, SBBool ascending, const unsigned short *sortkey, SBCompareMode comparemode) +{ + char sortkey_A[255]; + UCS2ToUTF8String(sortkey, sortkey_A); + //struct SortInfo info; + //info.comparemode = comparemode; + //GS_ASSERT(sortkey != NULL && _tcslen((const unsigned short *)sortkey) <= SORTKEY_LENGTH); + //_tcscpy(info.sortkey, (const unsigned short *)sortkey_A); + //SBServerListSort(&sb->list, ascending, info); + ServerBrowserSortA(sb, ascending, sortkey_A, comparemode); +} +#endif + +char *ServerBrowserGetMyPublicIP(ServerBrowser sb) +{ + return (char *)inet_ntoa(*(struct in_addr *)&sb->list.mypublicip); +} + +unsigned int ServerBrowserGetMyPublicIPAddr(ServerBrowser sb) +{ + return sb->list.mypublicip; +} + +void ServerBrowserDisconnect(ServerBrowser sb) +{ + SBServerListDisconnect(&sb->list); +} + +// Allows the user to specify a broadcast address for LAN hosting +void ServerBrowserLANSetLocalAddr(ServerBrowser sb, const char* theAddr) +{ + sb->list.mLanAdapterOverride = theAddr; +} + + +/* SBServerGetConnectionInfo +---------------- +Check if Nat Negotiation is requires, based off whether it is a lan game, public ip present and several other facts. +Returns an IP string to use for NatNeg, or direct connect if possible +Work for subsequent connection to this server, One of three results will occur +i) Lan game, connect using ipstring +2) Internet game, connect using ipstring +3) nat traversal required, perform nat negotiation using Nat SDK and this ipstring before connecting. + +return sb_true if further processing is required... i.e. NAT. sb_false if not. +fills an IP string +*/ +SBBool SBServerGetConnectionInfo(ServerBrowser gSB, SBServer server, gsi_u16 PortToConnectTo, char *ipstring) +{ + SBBool natneg = SBFalse; + if (SBServerHasPrivateAddress(server) == SBTrue && (SBServerGetPublicInetAddress(server) == ServerBrowserGetMyPublicIPAddr(gSB))) + { + + //directly connect to private IP (LAN) + sprintf(ipstring,"%s:%d", SBServerGetPrivateAddress(server),PortToConnectTo ); + + } + else + if ((SBServerDirectConnect(server) == SBTrue )&& (SBServerHasPrivateAddress(server) == SBFalse)) + { + //can directly connect to public IP, no negotiation required + sprintf(ipstring,"%s:%d", SBServerGetPrivateAddress(server), PortToConnectTo ); + } + else + { + //Nat Negotiation required + natneg = SBTrue; + sprintf(ipstring,"%s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort (server) ); + } + return natneg; +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_serverbrowsing.h b/xrGameSpy/gamespy/serverbrowsing/sb_serverbrowsing.h new file mode 100644 index 00000000000..81a65202739 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_serverbrowsing.h @@ -0,0 +1,480 @@ +/****** +GameSpy Server Browsing SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + + Please see the GameSpy Server Browsing SDK documentation for more + information + +******/ + + +#ifndef _SB_SERVERBROWSING_H +#define _SB_SERVERBROWSING_H + +#include "../common/gsCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/******************* +ServerBrowser Typedefs +********************/ +//ServerBrowser is an abstract data type used to represent the server list and query engine objects. +typedef struct _ServerBrowser *ServerBrowser; + +//SBServer is an abstract data type representing a single server. +#ifndef SBServer +typedef struct _SBServer *SBServer; +#endif +//Simple boolean type used for some functions +typedef enum {SBFalse, SBTrue} SBBool; + +//Error codes that can be returned from functions +typedef enum +{ + sbe_noerror, //no error has occured + sbe_socketerror, //a socket function has returned an unexpected error + sbe_dnserror, //DNS lookup of master address failed + sbe_connecterror, //connection to master server failed + sbe_dataerror, //invalid data was returned from master server + sbe_allocerror, //memory allocation failed + sbe_paramerror, //an invalid parameter was passed to a function + sbe_duplicateupdateerror //server update requested on a server that was already being updated +} SBError; + +//States the ServerBrowser object can be in +typedef enum +{ + sb_disconnected, //idle and not connected to the master server + sb_listxfer, //downloading list of servers from the master server + sb_querying, //querying servers + sb_connected //idle but still connected to the master server +} SBState; + +//Callbacks that can occur during server browsing operations +typedef enum +{ + sbc_serveradded, //a server was added to the list, may just have an IP & port at this point + sbc_serverupdated, //server information has been updated - either basic or full information is now available about this server + sbc_serverupdatefailed, //an attempt to retrieve information about this server, either directly or from the master, failed + sbc_serverdeleted, //a server was removed from the list + sbc_updatecomplete, //the server query engine is now idle + sbc_queryerror, //the master returned an error string for the provided query + sbc_serverchallengereceived // received ip verification challenge from server +} SBCallbackReason; + +//Passed to callback to indicate state of attempt to connect to server +typedef enum +{ + sbcs_succeeded, + sbcs_failed +} SBConnectToServerState; + +//Prototype for the callback function you need to provide +typedef void (*ServerBrowserCallback)(ServerBrowser sb, SBCallbackReason reason, SBServer server, void *instance); + +//Prototype for the callback function used when connecting to a server +typedef void (*SBConnectToServerCallback)(ServerBrowser sb, SBConnectToServerState state, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *instance); + +//Maximum length for the SQL filter string +#define MAX_FILTER_LEN 256 + +//Version defines for query protocol +#define QVERSION_GOA 0 +#define QVERSION_QR2 1 + +/******************* +ServerBrowser Object Functions +********************/ + +#ifndef GSI_UNICODE +#define ServerBrowserNew ServerBrowserNewA +#define ServerBrowserUpdate ServerBrowserUpdateA +#define ServerBrowserLimitUpdate ServerBrowserLimitUpdateA +#define ServerBrowserAuxUpdateIP ServerBrowserAuxUpdateIPA +#define ServerBrowserRemoveIP ServerBrowserRemoveIPA +#define ServerBrowserSendNatNegotiateCookieToServer ServerBrowserSendNatNegotiateCookieToServerA +#define ServerBrowserSendMessageToServer ServerBrowserSendMessageToServerA +#define ServerBrowserSort ServerBrowserSortA +#define SBServerGetStringValue SBServerGetStringValueA +#define SBServerGetIntValue SBServerGetIntValueA +#define SBServerGetFloatValue SBServerGetFloatValueA +#define SBServerGetBoolValue SBServerGetBoolValueA +#define SBServerGetPlayerStringValue SBServerGetPlayerStringValueA +#define SBServerGetPlayerIntValue SBServerGetPlayerIntValueA +#define SBServerGetPlayerFloatValue SBServerGetPlayerFloatValueA +#define SBServerGetTeamStringValue SBServerGetTeamStringValueA +#define SBServerGetTeamIntValue SBServerGetTeamIntValueA +#define SBServerGetTeamFloatValue SBServerGetTeamFloatValueA +#define ServerBrowserListQueryError ServerBrowserListQueryErrorA +#define ServerBrowserErrorDesc ServerBrowserErrorDescA +#define ServerBrowserGetServerByIP ServerBrowserGetServerByIPA +#else +#define ServerBrowserNew ServerBrowserNewW +#define ServerBrowserUpdate ServerBrowserUpdateW +#define ServerBrowserLimitUpdate ServerBrowserLimitUpdateW +#define ServerBrowserAuxUpdateIP ServerBrowserAuxUpdateIPW +#define ServerBrowserRemoveIP ServerBrowserRemoveIPW +#define ServerBrowserSendNatNegotiateCookieToServer ServerBrowserSendNatNegotiateCookieToServerW +#define ServerBrowserSendMessageToServer ServerBrowserSendMessageToServerW +#define ServerBrowserSort ServerBrowserSortW +#define SBServerGetStringValue SBServerGetStringValueW +#define SBServerGetIntValue SBServerGetIntValueW +#define SBServerGetFloatValue SBServerGetFloatValueW +#define SBServerGetBoolValue SBServerGetBoolValueW +#define SBServerGetPlayerStringValue SBServerGetPlayerStringValueW +#define SBServerGetPlayerIntValue SBServerGetPlayerIntValueW +#define SBServerGetPlayerFloatValue SBServerGetPlayerFloatValueW +#define SBServerGetTeamStringValue SBServerGetTeamStringValueW +#define SBServerGetTeamIntValue SBServerGetTeamIntValueW +#define SBServerGetTeamFloatValue SBServerGetTeamFloatValueW +#define ServerBrowserListQueryError ServerBrowserListQueryErrorW +#define ServerBrowserErrorDesc ServerBrowserErrorDescW +#define ServerBrowserGetServerByIP ServerBrowserGetServerByIPW +#endif +/* +ServerBrowserNew +---------------- +Creates and returns a new (empty) ServerBrowser object. +Returns NULL if an allocation error occurs. + +queryForGamename - The gamename you are querying for +queryFromGamename - The gamename you are querying from - generally the same as queryForGamename +queryFromKey - Secret key that corresponds to the queryFromGamename +queryFromVersion - A game-specific version identifier (pass 0 unless told otherwise) +maxConcUpdates - Max number of concurent updates (10-15 for modem users, 20-30 for high-bandwidth) +queryVersion - Query protocol to use. Use QVERSION_GOA for DeveloperSpec/Query&Reporting1 games, and QVERSION_QR2 for games that use Query & Reporting 2 +callback - The function that will be called with list updates +instance - User-defined instance data (e.g. structure or object pointer) */ +ServerBrowser ServerBrowserNew(const gsi_char *queryForGamename, const gsi_char *queryFromGamename, const gsi_char *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool lanBrowse, ServerBrowserCallback callback, void *instance); + +/* +ServerBrowserFree +----------------- +Free a ServerBrowser and all internal sturctures and servers */ +void ServerBrowserFree(ServerBrowser sb); + + +/* ServerBrowserUpdate +------------------- +Starts an update by downloading a list of servers from the master server, then querying them. + +sb - The server browser object to update +async - If SBTrue, the update will be initiated, and ServerListThink must be called for processing and querying to occur + If SBFalse, the function will not return until the initial list of servers has been completely updated +disconnectOnComplete - If SBTrue, the connection to the master server will be disconnected immediately after the list is downloaded. + If SBFalse, the connection will be left open for additional data queries, and can be closed via ServerBrowserDisconnect +basicFields - This array of registered QR2 keys is used to determine the fields requested from servers during the initial "basic" update. + Only server keys listed in this array will be returned for servers. +numBasicFields - The number of fields in the basicFields array +serverFilter - SQL Filter string that will be applied on the master server to limit the list of servers returned. + All server keys are available for filtering on the master server, as well as the master-defined "country" and "region" keys. + Standard SQL syntax should be used. + +ServerBrowserLimitUpdate +------------------------ +Identical to ServerBrowserUpdate, except that the number of servers returned can be limited +maxServers - Maximum number of servers to be returned +*/ +SBError ServerBrowserUpdate(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const gsi_char *serverFilter); +SBError ServerBrowserLimitUpdate(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const gsi_char *serverFilter, int maxServers); + + +/* ServerBrowserThink +------------------- +Processes incoming data from the master server and game servers that are being queried. Should be called +as often as possible while a server list update is in progress (~10ms is ideal). */ +SBError ServerBrowserThink(ServerBrowser sb); + +/* ServerBrowserLANUpdate +------------------- +Starts an update by searching for servers on the LAN, then querying them. You can specifiy a range of ports to search +for servers. Generally this should start with your standard query port, and range above it, since the QR and QR2 SDKs will +automatically allocate higher port numbers when running multiple servers on the same machine. You should limit your search +to 100 ports or less in most cases to limit flooding of the LAN with broadcast packets. + +sb - The server browser object to update +async - If SBTrue, the update will be initiated, and ServerListThink must be called for processing and querying to occur + If SBFalse, the function will not return until the initial list of servers has been completely updated +startSearchPort - The initial port to begin searching for servers on +endSearchPort - The final port to search. All ports between start and end will be queried. */ +SBError ServerBrowserLANUpdate(ServerBrowser sb, SBBool async, unsigned short startSearchPort, unsigned short endSearchPort); + +/* ServerBrowserAuxUpdateIP +------------------- +Manually updates a server given an IP address and query port. Use to manually add servers to the list when you just +have an IP and port for them. + +sb - The server browser object to add the server to +ip - The dotted IP address of the server e.g. "1.2.3.4" +port - The query port of the server +viaMaster - If SBTrue, information about the server will be retrieved from the master server instead of attempting to query the server directly. + If a connection to the master server does not exist, it will be made to kept open afterwards. + If SBFalse, the server will be contacted directly for information. +async - If SBTrue, the update will be initiated, and ServerListThink must be called for processing and querying to occur + If SBFalse, the function will not return until the server has been successfully or unsuccessfully updated +fullUpdate - If SBTrue, all server keys/rules/player/team information will be retrieved + If SBFalse, only the keys specified in the basicFields array of the ServerBrowserUpdate function will be retrieved */ +SBError ServerBrowserAuxUpdateIP(ServerBrowser sb, const gsi_char *ip, unsigned short port, SBBool viaMaster, SBBool async, SBBool fullUpdate); + +/* ServerBrowserAuxUpdateServer +------------------- +Manually updates a server object. Generally used to get additional information about a server (for example, to get full rules and +player information from a server that only has basic information so far), but can also be used to "refresh" the information +about a given server. Data will automatically be retrieved from the master server directly or from the game server as appropriate. +When called asynchronously, multiple server update requests can be queued and will be executed by the query engine in turn. + +sb - The server browser object to add the server to +server - Server object to update +async - If SBTrue, the update will be initiated, and ServerListThink must be called for processing and querying to occur + If SBFalse, the function will not return until the server has been successfully or unsuccessfully updated +fullUpdate - If SBTrue, all server keys/rules/player/team information will be retrieved + If SBFalse, only the keys specified in the basicFields array of the ServerBrowserUpdate function will be retrieved */ +SBError ServerBrowserAuxUpdateServer(ServerBrowser sb, SBServer server, SBBool async, SBBool fullUpdate); + + +/* ServerBrowserDisconnects +------------------- +Disconnects an idle connection to the master server when it is no longer needed. Note that if you disconnect +and then request an operation that requires a connection to the master, such as an AuxServerUpdate via the master, +the connection will be automatically re-established. */ +void ServerBrowserDisconnect(ServerBrowser sb); + + +/* ServerBrowserState +------------------- +Returns the current state of the Server Browser object */ +SBState ServerBrowserState(ServerBrowser sb); + +/* ServerBrowserRemoveIP +------------------- +Removes a server from the list given an IP and query port */ +void ServerBrowserRemoveIP(ServerBrowser sb, const gsi_char *ip, unsigned short port); + +/* ServerBrowserRemoveServer +------------------- +Removes a server from the list and releases all resources associated with it */ +void ServerBrowserRemoveServer(ServerBrowser sb, SBServer server); + +/* ServerBrowserHalt +------------------- +Stops a server list update in progress, clears any servers queued to be queried, and disconneects +from the master server. */ +void ServerBrowserHalt(ServerBrowser sb); + +/* ServerBrowserClear +------------------- +Removes all the servers from the list and frees all resources associated with them. */ +void ServerBrowserClear(ServerBrowser sb); + +/* ServerBrowserErrorDesc +------------------- +Returns a human-readable error string for the given error code. */ +const gsi_char *ServerBrowserErrorDesc(ServerBrowser sb, SBError error); + +/* ServerBrowserListQueryError +------------------- +When a list query error occurs, as indicated by the sbc_queryerror callback, this function allows you to +obtain the human-readable error string for the error (generally these errors are caused by errors in the +filter string) */ +const gsi_char *ServerBrowserListQueryError(ServerBrowser sb); + +/* ServerBrowserGetServer +---------------------- +Returns the server at the specified index, or NULL if the index is out of bounds */ +SBServer ServerBrowserGetServer(ServerBrowser sb, int index); + +/* ServerBrowserGetServerByIP +---------------------- +Returns the SBServer with the specified IP, or NULL if the server is not in the list */ +SBServer ServerBrowserGetServerByIP(ServerBrowser sb, const gsi_char* ip, unsigned short port); + +/* ServerBrowserCount +------------------ +Returns the number of servers on the specified list. Indexing is 0 based, so +the actual server indexes are 0 <= valid index < Count */ +int ServerBrowserCount(ServerBrowser sb); + +/* ServerBrowserPendingQueryCount +------------------ +Returns the number of servers currently being queried or queued to be queried. When this number is 0, the query +engine is idle */ +int ServerBrowserPendingQueryCount(ServerBrowser sb); + +/* ServerBrowserGetMyPublicIP +------------------ +Returns the public IP address for this computer, as seen by an outside machine (the master server). Use to determine +if a server you want to connect to is on the same private network or not. Only valid after a call to ServerListUpdate has +connected to the master server */ +char *ServerBrowserGetMyPublicIP(ServerBrowser sb); + +/* ServerBrowserGetMyPublicIPAddr +------------------ +Same as ServerBrowserGetMyPublicIP except that the address is returned in standard network-byte-order form */ +unsigned int ServerBrowserGetMyPublicIPAddr(ServerBrowser sb); + + +/* ServerBrowserSendNatNegotiateCookieToServer +------------------ +Sends a cookie value to the server for use with NAT Negotiation */ +SBError ServerBrowserSendNatNegotiateCookieToServer(ServerBrowser sb, const gsi_char *ip, unsigned short port, int cookie); + + +/* ServerBrowserSendMessageToServer +------------------ +Sends a game-specific message to a server */ +SBError ServerBrowserSendMessageToServer(ServerBrowser sb, const gsi_char *ip, unsigned short port, const char *data, int len); + +/* ServerBrowserConnectToServer +------------------ +Attempts to connect to the server, using natneg if necessary */ +SBError ServerBrowserConnectToServer(ServerBrowser sb, SBServer server, SBConnectToServerCallback callback); + + +/* Comparision types for the ServerBrowserSort function +int - assume the values are int and do an integer compare +float - assume the values are float and do a flot compare +strcase - assume the values are strings and do a case sensitive compare +stricase - assume the values are strings and do a case insensitive compare */ +typedef enum {sbcm_int, sbcm_float, sbcm_strcase, sbcm_stricase} SBCompareMode; + + +/* ServerBrowserSort +----------------- +Sort the server list in either ascending or descending order using the +specified comparemode. +sortkey can be a normal server key, or "ping" or "hostaddr" */ +void ServerBrowserSort(ServerBrowser sb, SBBool ascending, const gsi_char *sortkey, SBCompareMode comparemode); + +/* ServerBrowserLANSetLocalAddr +------------------- +Sets the network adapter to use for LAN broadcasts (optional) */ +void ServerBrowserLANSetLocalAddr(ServerBrowser sb, const char* theAddr); + + +/******************* +SBServer Object Functions +********************/ + + +// Callback function used for enumerating the keys/values for a server +typedef void (*SBServerKeyEnumFn)(gsi_char *key, gsi_char *value, void *instance); + + +/* SBServerGetConnectionInfo +---------------- +Check if Nat Negotiation is requires, based off whether it is a lan game, public ip present and several other facts. +Returns an IP string to use for NatNeg, or direct connect if possible +Work for subsequent connection to this server, One of three results will occur +i) Lan game, connect using ipstring +2) Internet game, connect using ipstring +3) nat traversal required, perform nat negotiation using Nat SDK and this ipstring before connecting. + +return sb_true if further processing is required... i.e. NAT. sb_false if not. +fills an IP string +*/ +SBBool SBServerGetConnectionInfo(ServerBrowser gSB, SBServer server, gsi_u16 PortToConnectTo, char *ipstring_out); + + +/* SBServerHasPrivateAddress +---------------- +Indicates whether the master server has provided a private address for this server */ +SBBool SBServerHasPrivateAddress(SBServer server); + +/* SBServerDirectConnect +---------------- +Indicates whether the server supports direct UDP connections (if false, NAT Negotiation is required) */ +SBBool SBServerDirectConnect(SBServer server); + +/* SBServerGetPing +---------------- +Returns the ping for the specified server. Ping is measured as the latency from the time a +query is sent to the server until the data is returned for that query */ +int SBServerGetPing(SBServer server); + + +/* SBServerGetPublicAddress/SBServerGetPrivateAddress +------------------- +Returns the string, dotted IP address for the specified server +The "private" version is only valid when the server has a private address available */ +char *SBServerGetPublicAddress(SBServer server); +char *SBServerGetPrivateAddress(SBServer server); + +/* SBServerGetPublicInetAddress/SBServerGetPrivateInetAddress +------------------- +Returns the network-ordered IP address for the specified server */ +unsigned int SBServerGetPublicInetAddress(SBServer server); +unsigned int SBServerGetPrivateInetAddress(SBServer server); + +/* SBServerGetPublicQueryPort/SBServerGetPrivateQueryPort +---------------- +Returns the "query" port for the specified server. If the game uses a seperate +"game" port, it can be retrieved via: SBServerGetIntValue(server,"hostport",0) */ +unsigned short SBServerGetPublicQueryPort(SBServer server); +unsigned short SBServerGetPrivateQueryPort(SBServer server); + + +/* SBServerHasBasicKeys +---------------- +Returns SBTrue if a server has at least basic keys available for it. "Basic" keys +are those indicated in the ServerBrowserUpdate function. */ +SBBool SBServerHasBasicKeys(SBServer server); + +/* SBServerHasFullKeys +---------------- +Returns SBTrue if a server has full keys available for it. This includes all server +rules and player/team keys. */ +SBBool SBServerHasFullKeys(SBServer server); + +/* SBServerHasValidPing +---------------- +Returns SBTrue if a server has a valid ping value for it (otherwise the ping will be 0) */ +SBBool SBServerHasValidPing(SBServer server); + + +/* SBServerGet[]Value +------------------ +Returns the value for the specified key. If the key does not exist for the +given server, the default value is returned */ +const gsi_char *SBServerGetStringValue(SBServer server, const gsi_char *keyname, const gsi_char *def); +int SBServerGetIntValue(SBServer server, const gsi_char *key, int idefault); +double SBServerGetFloatValue(SBServer server, const gsi_char *key, double fdefault); +SBBool SBServerGetBoolValue(SBServer server, const gsi_char *key, SBBool bdefault); + + +/* SBServerGetPlayer[]Value / SBServerGetTeam[]Value +------------------ +Returns the value for the specified key on the specified player or team. If the key does not exist for the +given server, the default value is returned +Player keys take the form keyname_N where N is the player index, and team keys take the form +keyname_tN where N is the team index. You should only specify the keyname for the key in the below functions. +*/ +const gsi_char *SBServerGetPlayerStringValue(SBServer server, int playernum, const gsi_char *key, const gsi_char *sdefault); +int SBServerGetPlayerIntValue(SBServer server, int playernum, const gsi_char *key, int idefault); +double SBServerGetPlayerFloatValue(SBServer server, int playernum, const gsi_char *key, double fdefault); + +const gsi_char *SBServerGetTeamStringValue(SBServer server, int teamnum, const gsi_char *key, const gsi_char *sdefault); +int SBServerGetTeamIntValue(SBServer server, int teamnum, const gsi_char *key, int idefault); +double SBServerGetTeamFloatValue(SBServer server, int teamnum, const gsi_char *key, double fdefault); + + +/* SBServerEnumKeys +----------------- +Enumerates the keys/values for a given server by calling KeyEnumFn with each +key/value. The user-defined instance data will be passed to the KeyFn callback */ +void SBServerEnumKeys(SBServer server, SBServerKeyEnumFn KeyFn, void *instance); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/xrGameSpy/gamespy/serverbrowsing/sb_serverlist.c b/xrGameSpy/gamespy/serverbrowsing/sb_serverlist.c new file mode 100644 index 00000000000..40a1465fa1c --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sb_serverlist.c @@ -0,0 +1,1816 @@ +#include "sb_serverbrowsing.h" +#include "sb_internal.h" +#include "sb_ascii.h" + + +#define SERVER_GROWBY 100 + +//for the master server info +#define INCOMING_BUFFER_SIZE 4096 + +#define MAX_OUTGOING_REQUEST_SIZE (MAX_FIELD_LIST_LEN + MAX_FILTER_LEN + 255) + + + + + + +static SBServerList *g_sortserverlist; //global serverlist for sorting info!! + + +//private function used to compare the key values based on a previously defined sortkey +static int prevKeyCompare(SBServer server1, SBServer server2) +{ + const char *prevsortkey = (const char *)g_sortserverlist->prevsortinfo.sortkey; + int diff; + double f; + //test which type of sort + switch(g_sortserverlist->prevsortinfo.comparemode) + { + case sbcm_int: + diff = SBServerGetIntValueA(server1, prevsortkey, 0) - + SBServerGetIntValueA(server2, prevsortkey, 0); + break; + case sbcm_float: + f = SBServerGetFloatValueA(server1, prevsortkey, 0) - + SBServerGetFloatValueA(server2, prevsortkey, 0); + if (!g_sortserverlist->sortascending) + f = -f; + if ((float)f > (float)0.0) + return 1; + else if ((float)f < (float)0.0) + return -1; + else + return 0; + //break; + case sbcm_strcase: + diff = strcmp(SBServerGetStringValueA(server1, prevsortkey, ""), + SBServerGetStringValueA(server2, prevsortkey, "")); + break; + case sbcm_stricase: + diff = strcasecmp(SBServerGetStringValueA(server1, prevsortkey, ""), + SBServerGetStringValueA(server2, prevsortkey, "")); + break; + default: + return 0; + } + if (!g_sortserverlist->sortascending) + diff = -diff; + return diff; +} + + +/**** +Comparision Functions +***/ +static int GS_STATIC_CALLBACK IntKeyCompare(const void *entry1, const void *entry2) +{ + SBServer server1 = *(SBServer *)entry1, server2 = *(SBServer *)entry2; + int diff; + const char *currsortkey = (const char *)g_sortserverlist->currsortinfo.sortkey; + + diff = SBServerGetIntValueA(server1, currsortkey, 0) - + SBServerGetIntValueA(server2, currsortkey, 0); + + if (diff == 0) //if equal, sort by previous sort value to retain earlier sort + return prevKeyCompare(server1, server2); + + if (!g_sortserverlist->sortascending) + diff = -diff; + return diff; + +} + +static int GS_STATIC_CALLBACK FloatKeyCompare(const void *entry1, const void *entry2) +{ + SBServer server1 = *(SBServer *)entry1, server2 = *(SBServer *)entry2; + double f; + const char *currsortkey = (const char *)g_sortserverlist->currsortinfo.sortkey; + + f = SBServerGetFloatValueA(server1, currsortkey, 0) - + SBServerGetFloatValueA(server2, currsortkey, 0); + + //if equal, sort by previous sort value to retain earlier sort + if ( !((float)f > (float)0.0) && !((float)f < (float)0.0) ) + return prevKeyCompare(server1, server2); + + if (!g_sortserverlist->sortascending) + f = -f; + if ((float)f > (float)0.0) + return 1; + else if ((float)f < (float)0.0) + return -1; + else + return 0; +} + +static int GS_STATIC_CALLBACK StrCaseKeyCompare(const void *entry1, const void *entry2) +{ + SBServer server1 = *(SBServer *)entry1, server2 = *(SBServer *)entry2; + int diff; + const char *currsortkey = (const char *)g_sortserverlist->currsortinfo.sortkey; + + diff = strcmp(SBServerGetStringValueA(server1, currsortkey, ""), + SBServerGetStringValueA(server2, currsortkey, "")); + + if (diff == 0) //if equal, sort by previous sort value to retain earlier sort + return prevKeyCompare(server1, server2); + + if (!g_sortserverlist->sortascending) + diff = -diff; + return diff; +} + +static int GS_STATIC_CALLBACK StrNoCaseKeyCompare(const void *entry1, const void *entry2) +{ + SBServer server1 = *(SBServer *)entry1, server2 = *(SBServer *)entry2; + int diff; + const char *currsortkey = (const char *)g_sortserverlist->currsortinfo.sortkey; + + diff = strcasecmp(SBServerGetStringValueA(server1, currsortkey, ""), + SBServerGetStringValueA(server2, currsortkey, "")); + + if (diff == 0) //if equal, sort by previous sort value to retain earlier sort + return prevKeyCompare(server1, server2); + + if (!g_sortserverlist->sortascending) + diff = -diff; + return diff; +} + + +/* ServerListSort +----------------- +Sort the server list in either ascending or descending order using the +specified comparemode. +sortkey can be a normal server key, or "ping" or "hostaddr" */ +void SBServerListSort(SBServerList *slist, SBBool ascending, SortInfo sortinfo) +{ + ArrayCompareFn comparator; + switch (sortinfo.comparemode) + { + case sbcm_int: comparator = IntKeyCompare; + break; + case sbcm_float: comparator = FloatKeyCompare; + break; + case sbcm_strcase: comparator = StrCaseKeyCompare; + break; + case sbcm_stricase: comparator = StrNoCaseKeyCompare; + break; + default: + comparator = StrNoCaseKeyCompare; + } + + //set last used sortkey + if (_tcslen(slist->prevsortinfo.sortkey) == 0) //set prev to current if not initialized + slist->prevsortinfo = sortinfo; + else if (strcmp((const char *)sortinfo.sortkey, (const char *)slist->currsortinfo.sortkey) != 0) + slist->prevsortinfo = slist->currsortinfo; //only set new sort if different than prev + + slist->currsortinfo = sortinfo; + slist->sortascending = ascending; + g_sortserverlist = slist; + ArraySort(slist->servers,comparator); +} + + + + +void SBServerListAppendServer(SBServerList *slist, SBServer server) +{ + ArrayAppend(slist->servers, &server); + slist->ListCallback(slist, slc_serveradded, server, slist->instance); +} + + + +int SBServerListFindServer(SBServerList *slist, SBServer findserver) +{ + int numservers; + int i; + numservers = ArrayLength(slist->servers); + for (i = 0 ; i < numservers ; i++) + { + if (findserver == *(SBServer *)ArrayNth(slist->servers, i)) + { + return i; + } + } + return -1; +} + +int SBServerListFindServerByIP(SBServerList *slist, goa_uint32 ip, unsigned short port) +{ + int numservers; + SBServer server; + int i; + numservers = ArrayLength(slist->servers); + for (i = 0 ; i < numservers ; i++) + { + server = *(SBServer *)ArrayNth(slist->servers, i); + if (SBServerGetPublicInetAddress(server) == ip && SBServerGetPublicQueryPortNBO(server) == port) + { + return i; + } + } + return -1; +} + +//add to the singly linked list of dead servers +static void AddServerToDeadlist(SBServerList *slist, SBServer server) +{ + if (slist->deadlist == NULL) + { + SBServerSetNext(server, NULL); + } else + SBServerSetNext(server, slist->deadlist); + slist->deadlist = server; +} + + +void SBServerListRemoveAt(SBServerList *slist, int index) +{ + SBServer server = *(SBServer *)ArrayNth(slist->servers, index); + slist->ListCallback(slist, slc_serverdeleted, server, slist->instance); + //need to remove it... + ArrayDeleteAt(slist->servers, index); + //now add it to the dead list + AddServerToDeadlist(slist, server); +} + +int SBServerListCount(SBServerList *slist) +{ + return ArrayLength(slist->servers); +} + +SBServer SBServerListNth(SBServerList *slist, int i) +{ + return *(SBServer *)ArrayNth(slist->servers, i); +} + + +void SBFreeDeadList(SBServerList *slist) +{ + SBServer server, next; + if (slist->deadlist == NULL) + return; + server = slist->deadlist; + while (server != NULL) + { + next = SBServerGetNext(server); + SBServerFree(&server); + server = next; + } + slist->deadlist = NULL; +} + + +void SBServerListClear(SBServerList *slist) +{ + //we need to add each server to the dead list so it can be freed after the clear + int i; + int nservers = ArrayLength(slist->servers); + for (i = 0 ; i < nservers ; i++) + { + AddServerToDeadlist(slist, *(SBServer *)ArrayNth(slist->servers, i)); + } + ArrayClear(slist->servers); + //now free the dead list + SBFreeDeadList(slist); +} + +void SBAllocateServerList(SBServerList *slist) +{ + slist->servers = ArrayNew(sizeof(SBServer ), SERVER_GROWBY, NULL); //don't free the server automatically - it goes into the dead list + slist->deadlist = NULL; +} + + + +const char *SBRefStr(SBServerList *slist, const char *str) +{ + SBRefString ref, *val; + ref.str = str; + val = (SBRefString *)TableLookup(SBRefStrHash(slist), &ref); + if (val != NULL) + { + val->refcount++; + return val->str; + } + + //else we need to add. + ref.str = goastrdup(str); + ref.refcount = 1; +#ifdef GSI_UNICODE + ref.str_W = UTF8ToUCS2StringAlloc(str); +#endif + TableEnter(SBRefStrHash(slist), &ref); + return ref.str; + + +} + +void SBReleaseStr(SBServerList *slist, const char *str) +{ + SBRefString ref, *val; + ref.str = str; + val = (SBRefString *)TableLookup(SBRefStrHash(slist), &ref); + assert(val != NULL); + if (val == NULL) + return; //not found! + val->refcount--; + if (val->refcount == 0) + TableRemove(SBRefStrHash(slist), &ref); +} + +#ifdef VENGINE_SUPPORT + #define FTABLE_ASSIGN + #include "../../VEngine/ve_gm3ftable.h" +#endif + + +#ifdef VENGINE_SUPPORT +#define FTABLE_DEFINES +#include "../../VEngine/ve_gm3ftable.h" +#endif + + + +//global pointer to alternate master server name/IP +char *SBOverrideMasterServer = NULL; + + +int NTSLengthSB(char *buf, int len) +{ + int i; + for (i = 0 ; i < len ; i++) + { + if (buf[i] == '\0') //found a full NTS + return i + 1; //return the length including the null + } + return -1; +} + + + +void SBServerListInit(SBServerList *slist, const char *queryForGamename, const char *queryFromGamename, const char *queryFromKey, int queryFromVersion, SBBool lanBrowse, SBListCallBackFn callback, void *instance) +{ + assert(slist != NULL); + // 11-03-2004 : Added by Saad Nader + // fix for LANs and unnecessary availability check + /////////////////////////////////////////////////// + if (lanBrowse == SBFalse) + { + if(__GSIACResult != GSIACAvailable) + return; + } + +#ifdef VENGINE_SUPPORT + SBServerListSetPointers(slist); +#endif + + slist->state = sl_disconnected; + SBAllocateServerList(slist); + SBRefStrHash(slist); //make sure it's initialized + strcpy(slist->queryforgamename, queryForGamename); + strcpy(slist->queryfromgamename, queryFromGamename); + strcpy(slist->queryfromkey, queryFromKey); + slist->ListCallback = callback; + slist->MaploopCallback = NULL; //populate when requested + assert(callback != NULL); + slist->instance = instance; + slist->mypublicip = 0; + slist->slsocket = INVALID_SOCKET; + slist->inbuffer = NULL; + slist->inbufferlen = 0; + slist->keylist = NULL; + slist->expectedelements = -1; + slist->numpopularvalues = 0; + slist->srcip = 0; + slist->fromgamever = queryFromVersion; +#ifdef GSI_UNICODE + slist->lasterror = NULL; + slist->lasterror_W = NULL; + _tcscpy(slist->currsortinfo.sortkey, (const unsigned short *)""); + _tcscpy(slist->prevsortinfo.sortkey, (const unsigned short *)""); +#else + _tcscpy(slist->currsortinfo.sortkey, ""); + _tcscpy(slist->prevsortinfo.sortkey, ""); +#endif + SBSetLastListErrorPtr(slist, ""); + slist->mLanAdapterOverride = NULL; + slist->backendgameflags = QR2_USE_QUERY_CHALLENGE; + + srand((unsigned int)current_time()); + SocketStartUp(); + +} + + +static void ErrorDisconnect(SBServerList *slist) +{ + static char* QUERY_ERROR = "Query Error: "; + + // check to see if there is a Query Error string in the inbuffer + if ((slist->inbufferlen > 0) && ((unsigned int)slist->inbufferlen > strlen(QUERY_ERROR)) && + (0 == strncmp(slist->inbuffer, QUERY_ERROR, strlen(QUERY_ERROR)))) + { + // call the callback with queryerror first + SBSetLastListErrorPtr(slist, slist->inbuffer + strlen(QUERY_ERROR)); + slist->ListCallback(slist, slc_queryerror, SBNullServer, slist->instance); + } + + //call the callback.. + slist->ListCallback(slist, slc_disconnected, SBNullServer, slist->instance); + SBServerListDisconnect(slist); +} + +#define MULTIPLIER -1664117991 +static int StringHash(const char *s, int numbuckets) +{ + goa_uint32 hashcode = 0; + while (*s != 0) + { + hashcode = (goa_uint32)((int)hashcode * MULTIPLIER + tolower(*s)); + s++; + } + return (int)(hashcode % numbuckets); + +} + + + +static SBError ServerListConnect(SBServerList *slist) +{ + struct sockaddr_in saddr; + struct hostent *hent; + char masterHostname[128]; + int masterIndex; + + + masterIndex = StringHash(slist->queryforgamename, NUM_MASTER_SERVERS); + if (SBOverrideMasterServer != NULL) + strcpy(masterHostname, SBOverrideMasterServer); + else //use the default format... + sprintf(masterHostname,"%s.ms%d." GSI_DOMAIN_NAME, slist->queryforgamename, masterIndex); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(MSPORT2); + saddr.sin_addr.s_addr = inet_addr(masterHostname); + if (saddr.sin_addr.s_addr == INADDR_NONE) + { + hent = gethostbyname(masterHostname); + if (!hent) + return sbe_dnserror; + memcpy(&saddr.sin_addr.s_addr,hent->h_addr_list[0], sizeof(saddr.sin_addr.s_addr)); + } + + if (slist->slsocket == INVALID_SOCKET) + { + slist->slsocket = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + if (slist->slsocket == INVALID_SOCKET) + return sbe_socketerror; + } + if (connect ( slist->slsocket, (struct sockaddr *) &saddr, sizeof saddr ) != 0) + { + closesocket(slist->slsocket); + slist->slsocket = INVALID_SOCKET; + return sbe_connecterror; + } + + //else we are connected + return sbe_noerror; + +} + +static void BufferAddNTS(char **buffer, const char *str, int *len) +{ + int slen; + if (str == NULL) + str = ""; + slen = (int)strlen(str) + 1; + memcpy(*buffer, str, (size_t)slen); + (*len) += slen; + (*buffer) += slen; +} + +static void BufferAddByte(char **buffer, unsigned char bval, int *len) +{ + *(*buffer) = (char)bval; + (*len) += 1; + (*buffer) += 1; +} + +static void BufferAddInt(char **buffer, int ival, int *len) +{ + memcpy(*buffer, &ival, 4); + (*len) += 4; + (*buffer) += 4; +} + +// This a utility to write ival as a little-endian (PC) byte order number +static void BufferAddIntLE(char **buffer, int ival, int *len) +{ + unsigned int ivalNBO = htonl(ival); + unsigned int ivalBE = 0; + ivalBE |= ((0x000000FF&ivalNBO)<<24); + ivalBE |= ((0x0000FF00&ivalNBO)<< 8); + ivalBE |= ((0x00FF0000&ivalNBO)>> 8); + ivalBE |= ((0xFF000000&ivalNBO)>>24); + BufferAddInt(buffer, (int)ivalBE, len); +} + + +static void BufferAddData(char **buffer, char *data, int dlen, int *len) +{ + memcpy(*buffer, data, (size_t)dlen); + (*len) += dlen; + (*buffer) += dlen; +} + + + +#define CALCULATEODDMODE(buffer, i, oddmode) ((buffer[i-1] & 1) ^ (i & 1) ^ oddmode ^ (buffer[0] & 1) ^ ((buffer[0] < 79) ? 1 : 0) ^ ((buffer[i-1] < buffer[0]) ? 1 : 0)); +static void SetupListChallenge(SBServerList *slist) +{ + int i; + int oddmode; + + slist->mychallenge[0] = (char)(33 + rand() % 93); //use chars in the range 33 - 125 + oddmode = 0; + for (i = 1; i < LIST_CHALLENGE_LEN ; i++) + { + oddmode = CALCULATEODDMODE(slist->mychallenge,i, oddmode); + slist->mychallenge[i] = (char)(33 + rand() % 93); //use chars in the range 33 - 125 + //if oddmode make sure the char is odd, otherwise make sure it's even + if ((oddmode && (slist->mychallenge[i] & 1) == 0) || (!oddmode && ((slist->mychallenge[i] & 1) == 1))) + slist->mychallenge[i]++; + + } +} + +static SBError SendWithRetry(SBServerList *slist, char *data, int len) +{ + SBError err; + int ret = 0; + + int retryCount = 1; + + while (retryCount >= 0) + { + retryCount--; + ret = send(slist->slsocket, data, len, 0); + if (ret <= 0 && retryCount >= 0) //error! try to reconnect + { + if (slist->inbufferlen > 0) + break; + else + SBServerListDisconnect(slist); + err = SBServerListConnectAndQuery(slist, NULL, NULL, NO_SERVER_LIST, 0); + if (err != sbe_noerror) + { + ErrorDisconnect(slist); + return err; //couldn't reconnect + } + } else + break; //send ok + } + +#ifdef INSOCK + GSI_UNUSED(data); + GSI_UNUSED(len); +#endif + + if (ret <= 0) + return sbe_connecterror; + else + return sbe_noerror; +} + + + +/* +1 bytes - message type (0) +2 bytes - message length +Protocol Version - Byte +Requested Encoding - Byte +Query For Game - NTS +Query From Game - NTS +Server Challenge - 8 bytes +Filter - NTS +Field List - NTS +Options - 4 bytes +Send Fields for non-NAT servers too (TurboQuery!) +No-server-slist-requested (just initiate connection and/or receive push updates) +Push Live-Updates +Log Alternate Source IP +*/ +#define ALTERNATE_SOURCE_IP 8 + +SBError SBServerListConnectAndQuery(SBServerList *slist, const char *fieldList, const char *serverFilter, int options, int maxServers) +{ + SBError err; + int ret; + int requestLen; + unsigned short netLen; + char *requestBuf; + char outgoingRequest[MAX_OUTGOING_REQUEST_SIZE + 1]; + assert(slist->state == sl_disconnected); + + + if (fieldList == NULL) + fieldList = ""; + if (serverFilter == NULL) + serverFilter = ""; + + if (strlen(fieldList) > MAX_FIELD_LIST_LEN) + return sbe_paramerror; + + if (strlen(serverFilter) > MAX_FILTER_LEN) + return sbe_paramerror; + + + err = ServerListConnect(slist); + if (err != sbe_noerror) + return err; + + slist->queryoptions = options; + + //setup our challenge value + SetupListChallenge(slist); + + //skip the length field for now + requestLen = 2; + requestBuf = outgoingRequest + 2; + + BufferAddByte(&requestBuf, SERVER_LIST_REQUEST, &requestLen); + BufferAddByte(&requestBuf, LIST_PROTOCOL_VERSION, &requestLen); + BufferAddByte(&requestBuf, LIST_ENCODING_VERSION, &requestLen); + BufferAddIntLE(&requestBuf, slist->fromgamever, &requestLen); + BufferAddNTS(&requestBuf, slist->queryforgamename, &requestLen); + BufferAddNTS(&requestBuf, slist->queryfromgamename, &requestLen); + BufferAddData(&requestBuf, slist->mychallenge, LIST_CHALLENGE_LEN, &requestLen); + BufferAddNTS(&requestBuf, serverFilter, &requestLen); + BufferAddNTS(&requestBuf, fieldList, &requestLen); + options = (int)htonl((unsigned int)options); + BufferAddInt(&requestBuf, options, &requestLen); + if (slist->queryoptions & ALTERNATE_SOURCE_IP) + { + BufferAddInt(&requestBuf, (int)slist->srcip, &requestLen); + } + if (slist->queryoptions & LIMIT_RESULT_COUNT) + { + BufferAddIntLE(&requestBuf, maxServers, &requestLen); + } + netLen = htons((unsigned short)requestLen); + memcpy(outgoingRequest, &netLen, 2); //set the length... + + //now send! + ret = send(slist->slsocket, outgoingRequest, requestLen, 0); + if (ret <= 0) + { + SBServerListDisconnect(slist); + return sbe_connecterror; + } + slist->state = sl_mainlist; + slist->pstate = pi_cryptheader; + //allocate an incoming buffer + if (slist->inbuffer == NULL) + { + slist->inbuffer = (char *)gsimalloc(INCOMING_BUFFER_SIZE); + if (slist->inbuffer == NULL) + return sbe_allocerror; + slist->inbufferlen = 0; + } + + + return sbe_noerror; +} + +SBError SBServerListGetLANList(SBServerList *slist, unsigned short startport, unsigned short endport, int queryversion) +{ + struct sockaddr_in saddr; + unsigned short i; + unsigned char qr2_echo_request[] = {QR2_MAGIC_1, QR2_MAGIC_2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; + int qr2requestlen = sizeof(qr2_echo_request) / sizeof(qr2_echo_request[0]); + if (slist->state != sl_disconnected) + SBServerListDisconnect(slist); + + slist->slsocket = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if (slist->slsocket == INVALID_SOCKET) + return sbe_socketerror; + +// enable broadcasting where needed +#if !defined(INSOCK) && !defined(_NITRO) && !defined(_REVOLUTION) + { + int optval = 1; + if (setsockopt(slist->slsocket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0) + return sbe_socketerror; + } +#endif + + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = gsiGetBroadcastIP(); //broadcast + + // Added for multihomed machines. Allows the user to specify which adapter to use + if (slist->mLanAdapterOverride != NULL) + { + struct sockaddr_in aClassCAddr; + aClassCAddr.sin_family = AF_INET; + aClassCAddr.sin_addr.s_addr = inet_addr(slist->mLanAdapterOverride); + aClassCAddr.sin_port = 0; // bind to any port + if (0 != bind(slist->slsocket, (struct sockaddr*)&aClassCAddr, sizeof(aClassCAddr))) + return sbe_socketerror; + } + + if (endport - startport > 500) //the max we will search + endport = (unsigned short)(startport + 500); + for (i = startport ; i <= endport ; i += 1) + { + saddr.sin_port = htons(i); + if (queryversion == QVERSION_QR2) //send a QR2 echo request + sendto(slist->slsocket, (char*)qr2_echo_request,qr2requestlen,0,(struct sockaddr *)&saddr,sizeof(saddr)); + else //send a GOA echo request + sendto(slist->slsocket, "\\echo\\test",10,0,(struct sockaddr *)&saddr,sizeof(saddr)); + } + slist->state = sl_lanbrowse; + slist->lanstarttime = current_time(); + return sbe_noerror; +} + +static void FreePopularValues(SBServerList *slist) +{ + int i; + for (i = 0 ; i < slist->numpopularvalues ; i++) + SBReleaseStr(slist, slist->popularvalues[i]); + slist->numpopularvalues = 0; +} + +static void FreeKeyList(SBServerList *slist) +{ + int i; + if (slist->keylist == NULL) + return; + for (i = 0 ; i < ArrayLength(slist->keylist) ; i++) + SBReleaseStr(slist, ((KeyInfo *)ArrayNth(slist->keylist,i))->keyName); + + ArrayFree(slist->keylist); + slist->keylist = NULL; + +} + +void SBServerListDisconnect(SBServerList *slist) +{ + if (slist->inbuffer != NULL) + gsifree(slist->inbuffer); + slist->inbuffer = NULL; + slist->inbufferlen = 0; + if (slist->slsocket != INVALID_SOCKET) + closesocket(slist->slsocket); + slist->slsocket = INVALID_SOCKET; + slist->state = sl_disconnected; + + FreeKeyList(slist); + slist->expectedelements = -1; + FreePopularValues(slist); +} + +void SBServerListCleanup(SBServerList *slist) +{ + SBServerListDisconnect(slist); + SBServerListClear(slist); + SBRefStrHashCleanup(slist); + if(slist->servers) + ArrayFree(slist->servers); + slist->servers = NULL; + +#ifdef GSI_UNICODE + if (slist->lasterror_W != NULL) + { + gsifree(slist->lasterror_W); + slist->lasterror_W = NULL; + } +#endif +} + + + +static void InitCryptKey(SBServerList *slist, char *key, int keylen) +{ + //combine our secret key, our challenge, and the server's challenge into a crypt key + int i; + int seckeylen = (int)strlen(slist->queryfromkey); + char *seckey = slist->queryfromkey; + for (i = 0 ; i < keylen ; i++) + { + slist->mychallenge[(i * seckey[i % seckeylen]) % LIST_CHALLENGE_LEN] ^= (char)((slist->mychallenge[i % LIST_CHALLENGE_LEN] ^ key[i]) & 0xFF); + } + GOACryptInit(&(slist->cryptkey), (unsigned char *)(slist->mychallenge), LIST_CHALLENGE_LEN); + +} + + +static int ServerSizeForFlags(int flags) +{ + int size = 5; //all servers are at least 5 .. + if (flags & PRIVATE_IP_FLAG) + size += 4; + if (flags & ICMP_IP_FLAG) + size += 4; + if (flags & NONSTANDARD_PORT_FLAG) + size += 2; + if (flags & NONSTANDARD_PRIVATE_PORT_FLAG) + size += 2; + return size; + +} + + +static int FullRulesPresent(char *buf, int len) +{ + int i; + while (len > 0 && *buf) + { + i = NTSLengthSB(buf, len); + if (i < 0) + return 0; //no full key + buf += i; + len -= i; + i = NTSLengthSB(buf, len); + if (i < 0) + return 0; //no full value + buf += i; + len -= i; + } + if (len == 0) + return 0; //not even enough space for the null term + if (*buf == 0) + return 1; //all there + return 0; +} + +//checks to see if all the keys for the given servers are there +static int AllKeysPresent(SBServerList *slist, char *buf, int len) +{ + int numkeys; + int i; + int strindex; + numkeys = ArrayLength(slist->keylist); + for (i = 0 ; i < numkeys ; i++) + { + switch (((KeyInfo *)ArrayNth(slist->keylist, i))->keyType) + { + case KEYTYPE_BYTE: + buf++; + len--; + break; + case KEYTYPE_SHORT: + buf += 2; + len -= 2; + break; + case KEYTYPE_STRING: + if (len < 1) + return 0; //not enough + strindex = (unsigned char)(buf[0]); + buf++; + len--; + if (strindex == 0xFF) //a NTS string + { + strindex = NTSLengthSB(buf, len); + if (strindex == -1) //not all there.. + return 0; + buf += strindex; + len -= strindex; + } //else it's a popular string - just the index is present + break; + default: + assert(0); + return 0; //error - unknown key type + } + if (len < 0) + return 0; //not enough.. + } + return 1; +} + +#define LAST_SERVER_MARKER "\xFF\xFF\xFF\xFF" +#define SERVER_MARKER_LEN 4 + +//parse only the IP/port from the server buffer +static void ParseServerIPPort(SBServerList *slist, char *buf, int len, goa_uint32 *ip, unsigned short *port) +{ + unsigned char flags; + if (len < 5) + return; //invalid buffer + flags = (unsigned char)buf[0]; + buf++; + len--; + memcpy(ip, buf, 4); + + buf += 4; + len -= 4; + + if (flags & NONSTANDARD_PORT_FLAG) + { + if (len < 2) + return; //invalid buffer + memcpy(port, buf, 2); + } else + *port = slist->defaultport; +} + + + + +//parse a server buffer +static int ParseServer(SBServerList *slist, SBServer server, char *buf, int len, int usepopularlist) +{ + int numkeys; + int i; + short sval; + int strindex; + int holdlen = len; + goa_uint32 ip; + unsigned short port; + unsigned char flags; + + + flags = (unsigned char)buf[0]; + SBServerSetFlags(server, flags); + buf++; + len--; + + //skip the IP, it's already set + buf += 4; + len -= 4; + + //skip the port, if needed + if (flags & NONSTANDARD_PORT_FLAG) + { + buf += 2; + len -= 2; + } + + if (flags & PRIVATE_IP_FLAG) + { + memcpy(&ip, buf, 4); + buf += 4; + len -= 4; + } else + ip = 0; + if (flags & NONSTANDARD_PRIVATE_PORT_FLAG) + { + memcpy(&port, buf, 2); + buf += 2; + len -= 2; + } else + port = slist->defaultport; + SBServerSetPrivateAddr(server, ip, port); + if (flags & ICMP_IP_FLAG) + { + memcpy(&ip, buf, 4); + buf += 4; + len -= 4; + SBServerSetICMPIP(server, ip); + } + + if (flags & HAS_KEYS_FLAG) //parse the keys + { + numkeys = ArrayLength(slist->keylist); + for (i = 0 ; i < numkeys ; i++) + { + KeyInfo *ki = (KeyInfo *)ArrayNth(slist->keylist, i); + switch (ki->keyType) + { + case KEYTYPE_BYTE: + SBServerAddIntKeyValue(server, ki->keyName, (unsigned char)buf[0]); + buf++; + len--; + break; + case KEYTYPE_SHORT: + memcpy(&sval, buf, 2); + SBServerAddIntKeyValue(server, ki->keyName, ntohs((unsigned short)sval)); + buf += 2; + len -= 2; + break; + case KEYTYPE_STRING: + if (usepopularlist) + { + strindex = (unsigned char)(buf[0]); + buf++; + len--; + } else + strindex = 0xFF; + if (strindex == 0xFF) //a NTS string + { + SBServerAddKeyValue(server, ki->keyName, buf); + strindex = (int)strlen(buf) + 1; + buf += strindex; + len -= strindex; + } else //else it's a popular string - just the index is present + { + SBServerAddKeyValue(server, ki->keyName, slist->popularvalues[strindex]); + } + break; + } + + } + SBServerSetState(server, (unsigned char)(SBServerGetState(server) | STATE_BASICKEYS)); + } + if (flags & HAS_FULL_RULES_FLAG) //got the full rules in there + { + while (*buf && len > 0) + { + char *k = buf; + i = (int)strlen(k) + 1; + buf += i; + len -= i; + SBServerAddKeyValue(server, k, buf); + i = (int)strlen(buf) + 1; + buf += i; + len -= i; + } + buf++; + len--; //get the last null out + SBServerSetState(server, (unsigned char)(SBServerGetState(server) | STATE_FULLKEYS)); + } + + // the server was an empty server message, thus it should be cleared of + // basic key and full key states + { + unsigned char state = SBServerGetState(server); + if ((flags & (HAS_FULL_RULES_FLAG|HAS_KEYS_FLAG)) == 0 && ((state & STATE_BASICKEYS) | (state & STATE_FULLKEYS))) + { + state &= (unsigned char)~(STATE_BASICKEYS|STATE_FULLKEYS); + SBServerSetState(server, state); + } + } + return holdlen - len; +} + + +static int IncomingListParseServer(SBServerList *slist, char *buf, int len) +{ + int i; + goa_uint32 ip; + unsigned short port; + SBServer server; + unsigned char flags; + //fields depends on the flags.. + if (len < 1) + return 0; + flags = (unsigned char)(buf[0]); + i = ServerSizeForFlags(flags); + if (len < i) + return 0; + if (flags & HAS_KEYS_FLAG) + { + if (!AllKeysPresent(slist, buf + i, len - i)) + return 0; + } + if (flags & HAS_FULL_RULES_FLAG) + { + if (!FullRulesPresent(buf + i, len - i)) + return 0; + } + //else we have a whole server! + //see if it's the "last" server (0xffffffff) + if (memcmp(buf + 1, LAST_SERVER_MARKER, SERVER_MARKER_LEN) == 0) + return -1; + ParseServerIPPort(slist, buf, len, &ip, &port); + server = SBAllocServer(slist, ip, port); + if (SBIsNullServer(server)) + return -2; + i = ParseServer(slist, server, buf, len, 1); + SBServerListAppendServer(slist, server); + return i; +} + +const char *SBLastListErrorA(SBServerList *slist) +{ + return slist->lasterror; +} +#ifdef GSI_UNICODE +const unsigned short *SBLastListErrorW(SBServerList *slist) +{ + return slist->lasterror_W; +} +#endif +void SBSetLastListErrorPtr(SBServerList *slist, char* theError) +{ +#ifdef GSI_UNICODE + if (slist->lasterror != theError) + { + // set the ascii error + slist->lasterror = theError; + + // free the current unicode error and allocate a new one + if (slist->lasterror_W != NULL) + gsifree(slist->lasterror_W); + slist->lasterror_W = UTF8ToUCS2StringAlloc(slist->lasterror); + } +#else + slist->lasterror = theError; +#endif +} + +#define FIXED_HEADER_LEN 6 + +/* +--challenge header +1 byte - number of random bytes to follow xor 0xEC +random bytes +1 byte - length xor 0xEA +keylen bytes - server challenge +--fixed header +YOUR public IP - 4 bytes +Standard query port - 2 bytes - or 0xFFFF if the master does not know about this gamename yet +[rest only follows if they requested a server slist] +--key slist +Number of Keys - 1 byte +List of Keys - with key type +Key Type - 1 Byte (0 = string, 1 = byte, 2 = short) +KeyName - NTS +--unique value slist +number of unique string values - 1 byte +Table of Unique String Values (255 most popular string keys) +Key NTS +--servers +Server Table (for each server - terminated with IP of 0xFFFFFFFF, flags 0) +1 byte flags +-Connect negotiate support? +-Has private IP +-Unsolicited UDP support? +-Has ICMP IP +-Nonstandard Public Port +-Nonstandard Private Port +-Has Keys +4 bytes public ip +[optional] +4 bytes port +[optional] +4 bytes private IP +[optional] +4 bytes private port +[optional] +4 bytes ICMP IP +[optional - keys] +String values +1-bytes - value ID +or +FF + valuestring + 00 +Byte Values + 1 byte - value + Short values? + 2 bytes - value +*/ + +static SBError ProcessMainListData(SBServerList *slist) +{ + int reqlen; + int keyoffset; + int keylen; + char *inbuf = slist->inbuffer; + int inlen = slist->inbufferlen; + switch (slist->pstate) + { + case pi_cryptheader: + if (inlen < 1) + break; + reqlen = (((unsigned char)(inbuf[0])) ^ 0xEC) + 2; + if (inlen < reqlen) + break; //not there yet + keyoffset = reqlen; + keylen = ((unsigned char)(inbuf[reqlen - 1])) ^ 0xEA; + reqlen += keylen; + if (inlen < reqlen) + break; //not there yet + //otherwise we have the whole crypt header and can init our crypt key + InitCryptKey(slist, inbuf + keyoffset, keylen); + slist->pstate = pi_fixedheader; + + // the first byte of the "random" data is actually + // the game options flag + memcpy(&slist->backendgameflags, &inbuf[1], 2); + slist->backendgameflags = ntohs(slist->backendgameflags); + + inbuf += reqlen; + inlen -= reqlen; + //decrypt any remaining data! + GOADecrypt(&(slist->cryptkey), (unsigned char *)inbuf, inlen); + //and fall through + case pi_fixedheader: + if (inlen < FIXED_HEADER_LEN) + break; + memcpy(&slist->mypublicip, inbuf, 4); + slist->ListCallback(slist, slc_publicipdetermined, SBNullServer, slist->instance); + memcpy(&slist->defaultport, inbuf + 4, 2); + if (slist->defaultport == 0xFFFF) //there was an error- grab the error string if present.. + { + if (NTSLengthSB(inbuf + FIXED_HEADER_LEN, inlen - FIXED_HEADER_LEN) == -1) //not all there + break; + SBSetLastListErrorPtr(slist, inbuf + FIXED_HEADER_LEN); + //make the error callback + slist->ListCallback(slist, slc_queryerror, SBNullServer, slist->instance); + if (slist->inbuffer == NULL) + break; + } + inbuf += FIXED_HEADER_LEN; + inlen -= FIXED_HEADER_LEN; + if ((slist->queryoptions & NO_SERVER_LIST) || slist->defaultport == 0xFFFF) + { + slist->pstate = pi_finished; + slist->state = sl_connected; + break; //no more data expected (if we didn't request any more, or the server doesn't know about this game) + } + slist->pstate = pi_keylist; + slist->expectedelements = -1; + + //and fall through + case pi_keylist: + if (slist->expectedelements == -1) //we haven't read the initial count of keys yet.. + { + if (inlen < 1) + break; + slist->expectedelements = (unsigned char)(inbuf[0]); + slist->keylist = ArrayNew(sizeof(KeyInfo), slist->expectedelements, NULL); + if (slist->keylist == NULL) //error + return sbe_allocerror; + inbuf++; + inlen--; + } + //try to read elements, up to the expected amount... + while (slist->expectedelements > ArrayLength(slist->keylist)) + { + KeyInfo ki; + int keylen; + if (inlen < 2) + break; //can't possibly be a full key (keytype + string) + keylen = NTSLengthSB(inbuf + 1, inlen - 1); + if (keylen == -1) + break; //no full NTS string there + ki.keyType = (unsigned char)(inbuf[0]); + ki.keyName = SBRefStr(slist, inbuf + 1); + ArrayAppend(slist->keylist, &ki); + inbuf += keylen + 1; + inlen -= keylen + 1; + } + if (slist->expectedelements > ArrayLength(slist->keylist)) + break; //didn't read them all... + //else we have read all the keys, fall through.. + slist->pstate = pi_uniquevaluelist; + slist->expectedelements = -1; + case pi_uniquevaluelist: + if (slist->expectedelements == -1) //we haven't read the # of unique values yet.. + { + if (inlen < 1) + break; + slist->expectedelements = (unsigned char)(inbuf[0]); + slist->numpopularvalues = 0; + inbuf++; + inlen--; + } + while (slist->expectedelements > slist->numpopularvalues) + { + int keylen = NTSLengthSB(inbuf, inlen); + if (keylen == -1) + break; //no full NTS string + slist->popularvalues[slist->numpopularvalues++] = SBRefStr(slist, inbuf); + inbuf += keylen; + inlen -= keylen; + } + if (slist->expectedelements > slist->numpopularvalues) + break; //didn't read all the popular values + //else we've got them all - move on to servers! + slist->pstate = pi_servers; + case pi_servers : + if (inlen < 5) //not enough for a full servers + break; + do + { + reqlen = IncomingListParseServer(slist, inbuf, inlen); + if (reqlen == -2) + return sbe_allocerror; + else if (reqlen == -1) //that was the last server! + { + inlen -= 5; + inbuf += 5; + slist->pstate = pi_finished; + slist->state = sl_connected; + slist->ListCallback(slist, slc_initiallistcomplete, SBNullServer, slist->instance); + break; + } + inbuf += reqlen; + inlen -= reqlen; + if (slist->inbuffer == NULL) + reqlen = 0; //break out - they disconnected + } while (reqlen != 0); + break; + default: + break; + } + assert(inlen >= 0); + if (slist->inbuffer == NULL) + return sbe_noerror; //don't keep processing - they disconnected + if (inlen != 0) //need to shift it over.. + { + memmove(slist->inbuffer, inbuf, (size_t)inlen); + } + slist->inbufferlen = inlen; + //we could clear the key list here if we wanted + + return sbe_noerror; +} + +/* + Number of Keys - Byte + List of Keys - with key type + Key Type - 1 Byte (0 = string, 1 = byte, 2 = short) + KeyName - NTS +*/ +static SBError ProcessPushKeyList(SBServerList *slist, char *buf, int len) +{ + int i; + int numkeys; + //first byte is the # of keys + numkeys = (unsigned char)buf[0]; + buf++; + len--; + //set up our key list... + if (slist->keylist != NULL) //free the existing key list + { + FreeKeyList(slist); + } + slist->keylist = ArrayNew(sizeof(KeyInfo), numkeys, NULL); + if (slist->keylist == NULL) + return sbe_allocerror; + for (i = 0 ; i < numkeys ; i++) + { + int keylen; + KeyInfo ki; + if (len < 2) + return sbe_dataerror; //can't possibly be a full key (keytype + string) + keylen = NTSLengthSB(buf + 1, len - 1); + if (keylen == -1) + return sbe_dataerror; //no full NTS string there + ki.keyType = (unsigned char)(buf[0]); + ki.keyName = SBRefStr(slist, buf + 1); + ArrayAppend(slist->keylist, &ki); + buf += keylen + 1; + len -= keylen + 1; + } + return sbe_noerror; +} + + +/* +Is Final Packet - Byte +Result Count - 1 bytes (up to 255 per packet) +Results + Player Name - NTS + 6 bytes - server addr + 4 bytes - last seen time (UTC Unix time) + gamename - NTS (empty if they are searching for only a single game) +*/ + +static SBError ProcessPlayerSearch(SBServerList *slist, char *buf, int len) +{ + unsigned char isFinal; + unsigned char resultCount; + unsigned int ip; + unsigned short port; + char *nick; + time_t lastSeen; + int i; + + if (len < 2) + return sbe_dataerror; //not a full packet + isFinal = (unsigned char)buf[0]; + resultCount = (unsigned char)buf[1]; + buf += 2; + len -= 2; + for (i = 0 ; i < resultCount ; i++) + { + int slen; + nick = buf; + slen = NTSLengthSB(buf, len); + if (slen == -1) + return sbe_dataerror; + buf += slen; + len -= slen; + if (len < 11) + return sbe_dataerror; //not a full entry + memcpy(&ip, buf, 4); + memcpy(&port, buf + 4, 2); + memcpy(&lastSeen, buf + 6, 4); + lastSeen = (time_t)ntohl((unsigned long)lastSeen); + buf += 10; + len -= 10; + slen = NTSLengthSB(buf, len); + if (slen == -1) + return sbe_dataerror; //not a valid gamename + slist->PlayerSearchCallback(slist, nick, ip, port, lastSeen, buf, slist->instance); + //now skip the gamename + buf += slen; + len -= slen; + } + if (isFinal) //send a final callback + slist->PlayerSearchCallback(slist, NULL, 0, 0, 0, NULL, slist->instance); + + + return sbe_noerror; + +} +/* + Server IP - 4 bytes + Server Port - 2 bytes + Map change time - 4 bytes + Number of maps - 1 byte + Maps + Mapname - NTS +*/ + + +static SBError ProcessMaploop(SBServerList *slist, char *buf, int len) +{ + time_t changeTime; + unsigned int ip; + unsigned short port; + SBServer server; + unsigned char mapCount; + int i; + char *mapList[MAX_MAPLOOP_LENGTH]; + if (len < 11) + return sbe_dataerror; //not a valid packet + memcpy(&ip, buf, 4); + memcpy(&port, buf + 4, 2); + i = SBServerListFindServerByIP(slist, ip, port); + if (i == -1) + return sbe_noerror; //not present any more + server = SBServerListNth(slist, i); + memcpy(&changeTime, buf + 6, 4); + changeTime = (time_t)ntohl((unsigned long)changeTime); + mapCount = (unsigned char)buf[10]; + buf += 11; + len -= 11; + for (i = 0 ; i < mapCount && i < MAX_MAPLOOP_LENGTH; i++) + { + int maplen; + if (len < 1) + break; + maplen = NTSLengthSB(buf, len); + if (maplen == -1) + return sbe_dataerror; //not a full NTS string + mapList[i] = buf; + buf += maplen; + len -= maplen; + } + if (slist->MaploopCallback == NULL) + return sbe_noerror; + slist->MaploopCallback(slist, server, changeTime, i, mapList, slist->instance); + return sbe_noerror; +} + +static SBError ProcessDeleteServer(SBServerList *slist, char *buf, int len) +{ + goa_uint32 ip; + unsigned short port; + int i; + + if (len < 6) + return sbe_dataerror; + //need to grab out the ip & port to find it in our list + memcpy(&ip, buf, 4); + memcpy(&port, buf + 4, 2); + //see if we can find the server in the list - if not, then add it + i = SBServerListFindServerByIP(slist, ip, port); + if (i == -1) + return sbe_noerror; + SBServerListRemoveAt(slist, i); + return sbe_noerror; +} + +/* +same as server list server format, except without using popular value lists +*/ +static SBError ProcessPushServer(SBServerList *slist, char *buf, int len) +{ + + SBServer server; + goa_uint32 ip; + unsigned short port; + int foundexisting; + int i; + + if (len < 5) + return sbe_dataerror; + //need to grab out the ip & port to find it in our list + ParseServerIPPort(slist, buf, len, &ip, &port); + + foundexisting = SBServerListFindServerByIP(slist, ip, port); + if (foundexisting == -1) //need to add it + { + server = SBAllocServer(slist, ip, port); + if (SBIsNullServer(server)) + return sbe_allocerror; + } else + server = SBServerListNth(slist, foundexisting); + i = ParseServer(slist, server, buf, len, 0); + if (i < 0) + return sbe_dataerror; //whole thing wasn't there + if (foundexisting == -1) + SBServerListAppendServer(slist, server); + slist->ListCallback(slist, slc_serverupdated, server, slist->instance); + return sbe_noerror; + +} + + + +static SBError ProcessAdHocData(SBServerList *slist) +{ + unsigned short msglen; + int i; + SBError ret = sbe_noerror; + while (slist->inbufferlen >= 3) //while there is at least 1 message in there.. (2 bytes for the size + 1 for the type) + { + //first two bytes are the length - see if we have the whole message.. + memcpy(&msglen, slist->inbuffer, 2); + msglen = ntohs(msglen); + if (msglen > INCOMING_BUFFER_SIZE) //ack! won't fit.. + { + ret = sbe_dataerror; + break; + } + if (slist->inbufferlen < msglen) + return sbe_noerror; //whole message not yet here + //else process the message + switch (slist->inbuffer[2]) + { + case PUSH_KEYS_MESSAGE: + ret = ProcessPushKeyList(slist, slist->inbuffer + 3, msglen - 3); + break; + case PUSH_SERVER_MESSAGE: + ret = ProcessPushServer(slist, slist->inbuffer + 3, msglen - 3); + break; + case KEEPALIVE_MESSAGE: //just need to send it back.. + i = (int)send(slist->slsocket, slist->inbuffer, msglen, 0); + if (i <= 0) + return sbe_connecterror; + break; + case DELETE_SERVER_MESSAGE: + ret = ProcessDeleteServer(slist, slist->inbuffer + 3, msglen - 3); + break; + case MAPLOOP_MESSAGE: + ret = ProcessMaploop(slist, slist->inbuffer + 3, msglen - 3); + break; + case PLAYERSEARCH_MESSAGE: + ret = ProcessPlayerSearch(slist, slist->inbuffer + 3, msglen - 3); + break; + } + + slist->inbufferlen -= msglen; + assert(slist->inbufferlen >= 0); + if (slist->inbufferlen != 0 && slist->inbuffer != NULL) //if anything is left, shift it over.. + { + memmove(slist->inbuffer, slist->inbuffer + msglen, (size_t)slist->inbufferlen); + } + if (ret != sbe_noerror) + break; + } + if (ret != sbe_noerror) + ErrorDisconnect(slist); + return ret; +} + + +static SBError ProcessIncomingData(SBServerList *slist) +{ + SBError err; + int len; + int oldlen; + + if(!CanReceiveOnSocket(slist->slsocket)) + return sbe_noerror; + + //append to data + oldlen = slist->inbufferlen; + len = recv(slist->slsocket, slist->inbuffer + slist->inbufferlen, INCOMING_BUFFER_SIZE - slist->inbufferlen, 0); + if (gsiSocketIsError(len)|| len == 0) + { + ErrorDisconnect(slist); + return sbe_connecterror; + } + slist->inbufferlen += len; + err = sbe_noerror; + if (slist->state == sl_connected || slist->pstate > pi_cryptheader) //decrypt any new data.. + { + GOADecrypt(&(slist->cryptkey), (unsigned char *)(slist->inbuffer + oldlen), slist->inbufferlen - oldlen); + } + + if (slist->state == sl_mainlist) + err = ProcessMainListData(slist); + if (err != sbe_noerror) + return err; + //always need to check this after mainlistdata, in case some extra data has some in (e.g. key list for push) + if (slist->state == sl_connected && slist->inbufferlen > 0) + return ProcessAdHocData(slist); + return sbe_noerror; + +} + +SBError SBGetServerRulesFromMaster(SBServerList *slist, goa_uint32 ip, unsigned short port) +{ + char requestBuffer[16]; + unsigned short tmp; + unsigned short msgLen = 9; + + if (slist->state == sl_disconnected) //try to connect + SBServerListConnectAndQuery(slist, NULL, NULL, NO_SERVER_LIST, 0); + + if (slist->state == sl_disconnected) + return sbe_connecterror; + + //the length + tmp = htons(msgLen); + memcpy(requestBuffer, &tmp, 2); + //the message type + requestBuffer[2] = SERVER_INFO_REQUEST; + memcpy(requestBuffer + 3, &ip, sizeof(ip)); + memcpy(requestBuffer + 7, &port, sizeof(port)); + return SendWithRetry(slist, requestBuffer, msgLen); +} + +SBError SBSendMessageToServer(SBServerList *slist, goa_uint32 ip, unsigned short port, const char *data, int len) +{ + char requestBuffer[16]; + unsigned short tmp; + unsigned short msgLen = 9; + SBError ret; + int i; + + if (slist->state == sl_disconnected) //try to connect + SBServerListConnectAndQuery(slist, NULL, NULL, NO_SERVER_LIST, 0); + + if (slist->state == sl_disconnected) + return sbe_connecterror; + + //the length + tmp = htons((unsigned short)(msgLen + len)); + memcpy(requestBuffer, &tmp, 2); + //the message type + requestBuffer[2] = SEND_MESSAGE_REQUEST; + memcpy(requestBuffer + 3, &ip, sizeof(ip)); + memcpy(requestBuffer + 7, &port, sizeof(port)); + ret = SendWithRetry(slist, requestBuffer, msgLen); + if (ret != sbe_noerror) + return ret; + i = send(slist->slsocket, data, len, 0); //send the actual push data + if (i < 0) + return sbe_connecterror; + return sbe_noerror; + +} + +SBError SBSendPlayerSearchRequest(SBServerList *slist, char *searchName, int searchOptions, int maxResults, SBPlayerSearchCallbackFn callback) +{ + char requestBuffer[256]; + unsigned short msgLen = 11; + int namelen; + SBError ret; + + if (slist->state == sl_disconnected) //try to connect + SBServerListConnectAndQuery(slist, NULL, NULL, NO_SERVER_LIST, 0); + if (slist->state == sl_disconnected) + return sbe_connecterror; + + slist->PlayerSearchCallback = callback; + + + requestBuffer[2] = PLAYERSEARCH_REQUEST; + searchOptions = (int)htonl((unsigned int)searchOptions); + memcpy(requestBuffer + 3, &searchOptions, 4); + maxResults = (int)htonl((unsigned int)maxResults); + memcpy(requestBuffer + 7, &maxResults, 4); + namelen = (int)strlen(searchName); + msgLen = (unsigned short)(msgLen + (namelen + 1)); + if (msgLen > sizeof(requestBuffer)) + return sbe_paramerror; //search string too long + memcpy(requestBuffer + 11, searchName, (size_t)namelen + 1); + msgLen = htons((unsigned short)(msgLen)); + memcpy(requestBuffer, &msgLen, 2); + ret = SendWithRetry(slist, requestBuffer, ntohs(msgLen)); + if (ret != sbe_noerror) + return ret; + return sbe_noerror; +} + + +SBError SBSendMaploopRequest(SBServerList *slist, SBServer server, SBMaploopCallbackFn callback) +{ + char requestBuffer[16]; + unsigned short tmp; + unsigned short msgLen = 9; + unsigned short port; + unsigned int ip; + SBError ret; + + + if (slist->state == sl_disconnected) //try to connect + SBServerListConnectAndQuery(slist, NULL, NULL, NO_SERVER_LIST, 0); + if (slist->state == sl_disconnected) + return sbe_connecterror; + + slist->MaploopCallback = callback; + //the length + tmp = htons((unsigned short)(msgLen)); + memcpy(requestBuffer, &tmp, 2); + //the message type + requestBuffer[2] = MAPLOOP_REQUEST; + ip = SBServerGetPublicInetAddress(server); + port = SBServerGetPublicQueryPortNBO(server); + memcpy(requestBuffer + 3, &ip, sizeof(ip)); + memcpy(requestBuffer + 7, &port, sizeof(port)); + ret = SendWithRetry(slist, requestBuffer, msgLen); + if (ret != sbe_noerror) + return ret; + return sbe_noerror; + +} + +SBError SBSendNatNegotiateCookieToServer(SBServerList *slist, goa_uint32 ip, unsigned short port, int cookie) +{ + unsigned char negotiateBuffer[NATNEG_MAGIC_LEN + 4]; + negotiateBuffer[0] = NN_MAGIC_0; + negotiateBuffer[1] = NN_MAGIC_1; + negotiateBuffer[2] = NN_MAGIC_2; + negotiateBuffer[3] = NN_MAGIC_3; + negotiateBuffer[4] = NN_MAGIC_4; + negotiateBuffer[5] = NN_MAGIC_5; + cookie = (int)htonl((unsigned int)cookie); + memcpy(negotiateBuffer + NATNEG_MAGIC_LEN, &cookie, 4); + return SBSendMessageToServer(slist, ip, port, (char*)negotiateBuffer, NATNEG_MAGIC_LEN + 4); +} + +static SBError ProcessLanData(SBServerList *slist) +{ + char indata[1500]; // make sure we have enough room for a large UDP packet + struct sockaddr_in saddr; + int saddrlen = sizeof(saddr); + int error; + int foundexisting; + SBServer server; + + while (CanReceiveOnSocket(slist->slsocket)) //we break if the select fails + { +#if defined(_PS3) + error = (int)recvfrom(slist->slsocket, indata, sizeof(indata) - 1, 0, (struct sockaddr *)&saddr, (socklen_t*)&saddrlen ); +#else + error = (int)recvfrom(slist->slsocket, indata, sizeof(indata) - 1, 0, (struct sockaddr *)&saddr, &saddrlen ); +#endif + + if (gsiSocketIsError(error)) + continue; + //if we got data, then add it to the list... + foundexisting = SBServerListFindServerByIP(slist, saddr.sin_addr.s_addr, saddr.sin_port); + if (foundexisting != -1) //already exists + continue; + server = SBAllocServer(slist, saddr.sin_addr.s_addr, saddr.sin_port); + if (SBIsNullServer(server)) + return sbe_allocerror; + SBServerSetFlags(server, UNSOLICITED_UDP_FLAG|NONSTANDARD_PORT_FLAG); + SBServerListAppendServer(slist, server); + } + if (current_time() - slist->lanstarttime > SL_LAN_SEARCH_TIME) //done waiting for replies + { + closesocket(slist->slsocket); + slist->slsocket = INVALID_SOCKET; + slist->state = sl_disconnected; + slist->ListCallback(slist, slc_initiallistcomplete, SBNullServer, slist->instance); + } + return sbe_noerror; +} + +SBError SBListThink(SBServerList *slist) +{ + SBFreeDeadList(slist); //free any pending deleted servers + switch (slist->state) + { + case sl_disconnected: + break; + case sl_connected: + case sl_mainlist: + return ProcessIncomingData(slist); + //break; + case sl_lanbrowse: + return ProcessLanData(slist); + //break; + } + + return sbe_noerror; + //see if any data is available... + +} + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/ReadMe.txt b/xrGameSpy/gamespy/serverbrowsing/sbctest/ReadMe.txt new file mode 100644 index 00000000000..6764b099b76 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/ReadMe.txt @@ -0,0 +1,29 @@ +**sbctest** + +Command line inputs: none + +Summary: This cross-platform test app runs a server browser, which queries the GameSpy Master Server for +all running servers of the specified game ('gmtest' in this case). After retrieving and outputing the +basic server information for all listed servers, the server list is then sorted by ping time and +redisplayed. After this, the server list is refreshed, this time using a server filter to narrow down +the servers retrieved. Then, if the QR2 sample is running, an AuxUpdate is done to get and output all +of its server/player/team keys. + +Dependencies: should be run concurrently with qr2csample (wait 6-10 seconds after starting +qr2csample to ensure it is listed on the Master Server) + +For debug output, add GSI_COMMON_DEBUG to the preprocessor definitions. + +For Unicode, add GSI_UNICODE to the preprocessor definitions (or use the Visual Studio Project's Unicode +configuration). + +Internal functions used: + _tprintf - Unicode compatible version of printf + _tcscpy - Unicode compatible version of strcpy + _tcscmp - Unicode compatible version of strcmp + _T - used on all string literals for Unicode compatibility + msleep - Cross-platform compatible version of sleep + GSI_UNUSED - used to avoid unreferenced variable compiler warnings + + + \ No newline at end of file diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest.c b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest.c new file mode 100644 index 00000000000..9275a4d1c45 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest.c @@ -0,0 +1,355 @@ +/*********************** +sbctest.c +GameSpy Server Browsing SDK + +Copyright 1999-2007 GameSpy Industries, Inc + +devsupport@gamespy.com + +****** + +See the ReadMe file for sbctest info, and consult the GameSpy Server Browsing +SDK documentation for more information on implementing the serverbrowsing SDK. + +************************/ + +/******** +INCLUDES +********/ +#if defined(_WIN32) + #include // used for keyboard input +#endif +#include "../sb_serverbrowsing.h" +#include "../../qr2/qr2.h" +#include "../../common/gsAvailable.h" + +/******** +DEFINES +********/ +#define GAME_NAME _T("gmtest") + +// ensure cross-platform compatibility for printf +#ifdef UNDER_CE + void RetailOutputA(CHAR *tszErr, ...); + #define printf RetailOutputA +#elif defined(_NITRO) + #include "../../common/nitro/screen.h" + #define printf Printf + #define vprintf VPrintf +#endif + +/******** +GLOBAL VARS +********/ +static gsi_bool UpdateFinished = gsi_false; // used to track status of server browser updates + +/******** +DEBUG OUTPUT +********/ +#ifdef GSI_COMMON_DEBUG +static void DebugCallback(GSIDebugCategory theCat, GSIDebugType theType, + GSIDebugLevel theLevel, const char * theTokenStr, + va_list theParamList) +{ + GSI_UNUSED(theLevel); + printf("[%s][%s] ", + gGSIDebugCatStrings[theCat], + gGSIDebugTypeStrings[theType]); + + vprintf(theTokenStr, theParamList); +} +#ifdef GSI_UNICODE +static void AppDebug(const unsigned short* format, ...) +{ + // Construct text, then pass in as ASCII + unsigned short buf[1024]; + char tmp[2056]; + va_list aList; + va_start(aList, format); + vswprintf(buf, 1024, format, aList); + + UCS2ToAsciiString(buf, tmp); + gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + "%s", tmp); +} +#else +static void AppDebug(const char* format, ...) +{ + va_list aList; + va_start(aList, format); + gsDebugVaList(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, + format, aList); +} +#endif +#else + #define AppDebug _tprintf +#endif + +/******** +PROTOTYPES - To prevent warnings on codewarrior strict compile +********/ +int test_main(int argc, char **argp); + +// callback called as server browser updates process +static void SBCallback(ServerBrowser sb, SBCallbackReason reason, SBServer server, void *instance) +{ + int i; // for-loop ctr + gsi_char * defaultString = _T(""); // default string for SBServerGet functions - returns if specified string key is not found + int defaultInt = 0; // default int value for SBServerGet functions - returns if specified int key is not found + gsi_char anAddress[20] = { '\0' }; // to store server IP + + // retrieve the server ip +#ifdef GSI_UNICODE + if (server) + AsciiToUCS2String(SBServerGetPublicAddress(server),anAddress); +#else + if (server) + strcpy(anAddress, SBServerGetPublicAddress(server)); +#endif + + switch (reason) + { + case sbc_serveradded: // new SBServer added to the server browser list + // output the server's IP and port (the rest of the server's basic keys may not yet be available) + AppDebug(_T("Server Added: %s:%d\n"), anAddress, SBServerGetPublicQueryPort(server)); + break; + case sbc_serverchallengereceived: // received ip verification challenge from server + // informational, no action required + break; + case sbc_serverupdated: // either basic or full information is now available for this server + // retrieve and print the basic server fields (specified as a parameter in ServerBrowserUpdate) + AppDebug(_T("ServerUpdated: %s:%d\n"), anAddress, SBServerGetPublicQueryPort(server)); + AppDebug(_T(" Host: %s\n"), SBServerGetStringValue(server, _T("hostname"), defaultString)); + AppDebug(_T(" Gametype: %s\n"), SBServerGetStringValue(server, _T("gametype"), defaultString)); + AppDebug(_T(" Map: %s\n"), SBServerGetStringValue(server, _T("mapname"), defaultString)); + AppDebug(_T(" Players/MaxPlayers: %d/%d\n"), SBServerGetIntValue(server, _T("numplayers"), defaultInt), SBServerGetIntValue(server, _T("maxplayers"), defaultInt)); + AppDebug(_T(" Ping: %dms\n"), SBServerGetPing(server)); + + // if the server has full keys (ServerBrowserAuxUpdate), print them + if (SBServerHasFullKeys(server)) + { + // print some non-basic server info + AppDebug(_T(" Frag limit: %d\n"), SBServerGetIntValue(server, _T("fraglimit"), defaultInt)); + AppDebug(_T(" Time limit: %d minutes\n"), SBServerGetIntValue(server, _T("timelimit"), defaultInt)); + AppDebug(_T(" Gravity: %d\n"), SBServerGetIntValue(server, _T("gravity"), defaultInt)); + + // print player info + AppDebug(_T(" Players:\n")); + for(i = 0; i < SBServerGetIntValue(server, _T("numplayers"), 0); i++) // loop through all players on the server + { + // print player key info for the player at index i + AppDebug(_T(" %s\n"), SBServerGetPlayerStringValue(server, i, _T("player"), defaultString)); + AppDebug(_T(" Score: %d\n"), SBServerGetPlayerIntValue(server, i, _T("score"), defaultInt)); + AppDebug(_T(" Deaths: %d\n"), SBServerGetPlayerIntValue(server, i, _T("deaths"), defaultInt)); + AppDebug(_T(" Team (0=Red/1=Blue): %d\n"), SBServerGetPlayerIntValue(server, i, _T("team"), defaultInt)); + AppDebug(_T(" Ping: %d\n"), SBServerGetPlayerIntValue(server, i, _T("ping"), defaultInt)); + + } + // print team info (team name and team score) + AppDebug(_T(" Teams (Score):\n")); + for(i = 0; i < SBServerGetIntValue(server, _T("numteams"), 0); i++) + { + AppDebug(_T(" %s (%d)\n"), SBServerGetTeamStringValue(server, i, _T("team"), defaultString), + SBServerGetTeamIntValue(server, i, _T("score"), defaultInt)); + } + } + break; + case sbc_serverupdatefailed: + AppDebug(_T("Update Failed: %s:%d\n"), anAddress, SBServerGetPublicQueryPort(server)); + break; + case sbc_updatecomplete: // update is complete; server query engine is now idle (not called upon AuxUpdate completion) + AppDebug(_T("Server Browser Update Complete\r\n")); + UpdateFinished = gsi_true; // this will let us know to stop calling ServerBrowserThink + break; + case sbc_queryerror: // the update returned an error + AppDebug(_T("Query Error: %s\n"), ServerBrowserListQueryError(sb)); + UpdateFinished = gsi_true; // set to true here since we won't get an updatecomplete call + break; + default: + break; + } + + GSI_UNUSED(instance); +} + +int test_main(int argc, char **argp) +{ + ServerBrowser sb; // server browser object initialized with ServerBrowserNew + + /* ServerBrowserNew parameters */ + gsi_char secret_key[9]; // your title's assigned secret key + int version = 0; // ServerBrowserNew parameter; set to 0 unless otherwise directed by GameSpy + int maxConcUpdates = 20; // max number of queries the ServerBrowsing SDK will send out at one time + SBBool lanBrowse = SBFalse; // set true for LAN only browsing + void * userData = NULL; // optional data that will be passed to the SBCallback function after updates + + /* ServerBrowserUpdate parameters */ + SBBool async = SBTrue; // we will run the updates asynchronously + SBBool discOnComplete = SBTrue; // disconnect from the master server after completing update + // (future updates will automatically re-connect) + // these will be the only keys retrieved on server browser updates + unsigned char basicFields[] = {HOSTNAME_KEY, GAMETYPE_KEY, MAPNAME_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY}; + int numFields = sizeof(basicFields) / sizeof(basicFields[0]); + gsi_char serverFilter[100] = {'\0'}; // filter string for server browser updates + + /* ServerBrowserSort parameters */ + SBBool ascending = SBTrue; // sort in ascending order + gsi_char * sortKey = _T("ping"); // sort servers based on ping time + SBCompareMode compareMode = sbcm_int; // we are sorting integers (as opposed to floats or strings) + + /* ServerBrowserAuxUpdateServer parameter */ + SBBool fullUpdate = SBTrue; + + GSIACResult result; // used for backend availability check + int i; // for-loop counter + SBServer server; // used to hold each server when iterating through the server list + int totalServers; // keep track of the total number of servers in our server list + gsi_char * defaultString = _T(""); // default string for SBServerGet functions - returns if specified string key is not found + + // for debug output on these platforms +#if defined (_PS3) || defined (_PS2) || defined (_PSP) || defined (_NITRO) + #ifdef GSI_COMMON_DEBUG + // Define GSI_COMMON_DEBUG if you want to view the SDK debug output + // Set the SDK debug log file, or set your own handler using gsSetDebugCallback + //gsSetDebugFile(stdout); // output to console + gsSetDebugCallback(DebugCallback); + + // Set debug levels + gsSetDebugLevel(GSIDebugCat_All, GSIDebugType_All, GSIDebugLevel_Verbose); + #endif +#endif + + // set the secret key, in a semi-obfuscated manner + secret_key[0] = 'H'; + secret_key[1] = 'A'; + secret_key[2] = '6'; + secret_key[3] = 'z'; + secret_key[4] = 'k'; + secret_key[5] = 'S'; + secret_key[6] = '\0'; + + // check that the game's backend is available + GSIStartAvailableCheck(GAME_NAME); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + AppDebug(_T("The backend is not available\n")); + return 1; + } + + AppDebug(_T("Creating server browser for %s\n\n"), GAME_NAME); + // create a new server browser object + sb = ServerBrowserNew (GAME_NAME, GAME_NAME, secret_key, version, maxConcUpdates, QVERSION_QR2, lanBrowse, SBCallback, userData); + +/** Populate the server browser's server list by doing an Update **/ + AppDebug(_T("Starting server browser update\n")); + // begin the update (async) + ServerBrowserUpdate(sb, async, discOnComplete, basicFields, numFields, serverFilter); + + // think while the update is in progress + while ((ServerBrowserThink(sb) == sbe_noerror) && (UpdateFinished == gsi_false)) + msleep(10); // think should be called every 10-100ms; quicker calls produce more accurate ping measurements +/** End Update **/ + +/** Sort the server list by ping time in ascending order **/ + AppDebug(_T("\nSorting server list by ping\n")); + // sorting is typically done based on user input, such as clicking on the column header of the field to sort + ServerBrowserSort(sb, ascending, sortKey, compareMode); + + totalServers = ServerBrowserCount(sb); // total servers in our server list + if (totalServers == 0) + printf("There are no %s servers running currently\n", GAME_NAME); + else + { + printf("Sorted list:\n"); + // display the server list in the new sorted order + for(i = 0; i < totalServers; i++) + { + server = ServerBrowserGetServer(sb, i); // get the SBServer object at index 'i' in the server list + // print the server host along with its ping + AppDebug(_T(" %s ping: %dms\n"), SBServerGetStringValue(server, _T("hostname"), defaultString), SBServerGetPing(server)); + } + } +/** End server list sorting **/ + +/** Refresh the server list, this time using a server filter **/ + AppDebug(_T("\nRefreshing server list and applying a filter: ")); + ServerBrowserClear(sb); // need to clear first so we don't end up with duplicates + + AppDebug(_T("US servers with more than 5 players, or servers with a hostname containing 'GameSpy'\n\n")); + // filter in US servers that have more than 5 players, or any server containing 'GameSpy' in the hostname + _tcscpy(serverFilter,_T("(country = 'US' and numplayers > 5) or hostname like '%GameSpy%'")); + // note that filtering by "ping" is not possible, since ping is determined by the client - not the master server + + // begin the update (async) + ServerBrowserUpdate(sb, async, discOnComplete, basicFields, numFields, serverFilter); + + UpdateFinished = gsi_false; // this was set to true from the last update, so we set it back until the new update completes + + // think once again while the update is in progress + while ((ServerBrowserThink(sb) == sbe_noerror) && (UpdateFinished == gsi_false)) + msleep(10); +/** End refresh with filter **/ + +/** If the qr2 sample server is running, we will do an AuxUpdate to retrieve its full keys **/ + AppDebug(_T("\nLooking for GameSpy QR2 Sample server\n")); + totalServers = ServerBrowserCount(sb); // total servers in our server list + if (totalServers == 0) + AppDebug(_T("There are no %s servers running currently\n"), GAME_NAME); + else + { + int serverFound = 0; // set to 1 if GameSpy QR2 Sample server is in the list + + // iterate through the server list looking for GameSpy QR2 Sample + for(i = 0; i < totalServers; i++) + { + server = ServerBrowserGetServer(sb, i); // get the SBServer object at index 'i' in the server list + + // check if the hostname server key is "GameSpy QR2 Sample" + if (!(_tcscmp(SBServerGetStringValue(server, _T("hostname"), defaultString), _T("GameSpy QR2 Sample")))) + { + + AppDebug(_T("Found it!\n\nRunning AuxUpdate to get more specific server info:\n\n")); + // update the qr2 sample server object to contain its full keys + ServerBrowserAuxUpdateServer(sb, server, async, fullUpdate); + // Note: Only call this on a server currently in the server list; otherwise call ServerBrowserAuxUpdateIP + + // think once again while the update is in progress; done once the server object has full keys + while ((ServerBrowserThink(sb) == sbe_noerror) && !(SBServerHasFullKeys(server))) + msleep(10); + + serverFound = 1; + break; // already found the qr2 sample server, no need to loop through the rest + } + } + if (serverFound == 0) + AppDebug(_T("Gamespy QR2 Sample server is not running\n")); + } +/** End AuxUpdate **/ + + ServerBrowserFree(sb); // clean up + + // keep program window open until manually exited +#if defined(_WIN32) + AppDebug(_T("\nPress any key to exit")); + i = 1; + while (i) + { + msleep(10); + if (_kbhit()) + break; + } +#else // all non-windows platforms + AppDebug(_T("\nProgram is done and will loop indefinitely until killed")); + i = 1; + while (i) + msleep(10); +#endif + + GSI_UNUSED(argc); + GSI_UNUSED(argp); + + // Finished + return 0; +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest.dsp b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest.dsp new file mode 100644 index 00000000000..6c2ae6641ab --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest.dsp @@ -0,0 +1,326 @@ +# Microsoft Developer Studio Project File - Name="sbctest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=sbctest - Win32 Unicode 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 "sbctest.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 "sbctest.mak" CFG="sbctest - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sbctest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "sbctest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "sbctest - Win32 Unicode Release" (based on "Win32 (x86) Console Application") +!MESSAGE "sbctest - Win32 Unicode Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "$/Gamespy/GOA/serverbrowsing/sbctest" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sbctest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "sbctest - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "sbctest - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "sbctest___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "sbctest___Win32_Unicode_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "UnicodeRelease" +# PROP Intermediate_Dir "UnicodeRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /machine:I386 + +!ELSEIF "$(CFG)" == "sbctest - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "sbctest___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "sbctest___Win32_Unicode_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "UnicodeDebug" +# PROP Intermediate_Dir "UnicodeDebug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GSI_UNICODE" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "sbctest - Win32 Release" +# Name "sbctest - Win32 Debug" +# Name "sbctest - Win32 Unicode Release" +# Name "sbctest - Win32 Unicode Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sbctest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\win32\Win32Common.c +# End Source File +# End Group +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=..\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=..\sb_server.c +# End Source File +# Begin Source File + +SOURCE=..\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=..\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\sb_serverlist.c +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest_vs2005.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest_vs2005.vcproj new file mode 100644 index 00000000000..bbae9b80de7 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest_vs2005.vcproj @@ -0,0 +1,1252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbctest_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sblinux/Makefile b/xrGameSpy/gamespy/serverbrowsing/sbctest/sblinux/Makefile new file mode 100644 index 00000000000..bbe2bbad7b0 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sblinux/Makefile @@ -0,0 +1,54 @@ +# CDKey SDK Server Makefile +# Copyright 2004 GameSpy Industries + +PROJECT=sbctest + +CC=gcc +BASE_CFLAGS=-D_LINUX + +#use these cflags to optimize it +CFLAGS=$(BASE_CFLAGS) -march=i486 -O6 -ffast-math -funroll-loops \ + -fomit-frame-pointer -fexpensive-optimizations -falign-loops=2 \ + -falign-jumps=2 -falign-functions=2 -lpthread +#use these when debugging +#CFLAGS=$(BASE_CFLAGS) -g + +PROG_OBJS = \ + ../sbctest.o\ + ../../../common/gsMemory.o\ + ../../../common/linux/LinuxCommon.o\ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../sb_crypt.o\ + ../../sb_queryengine.o\ + ../../sb_server.o\ + ../../sb_serverbrowsing.o\ + ../../sb_serverlist.o\ + ../../../natneg/natneg.o\ + ../../../natneg/NATify.o\ + ../../../qr2/qr2regkeys.o + + +############################################################################# +# SETUP AND BUILD +############################################################################# + +$(PROJECT): $(PROG_OBJS) + $(CC) $(CFLAGS) -o $@ $(PROG_OBJS) + +############################################################################# +# MISC +############################################################################# + +clean: + rm -f $(PROG_OBJS) + +depend: + gcc -MM $(PROG_OBJS:.o=.c) + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbmacosx/Makefile b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbmacosx/Makefile new file mode 100644 index 00000000000..3034134684c --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbmacosx/Makefile @@ -0,0 +1,30 @@ +# ServerBrowsing SDK Makefile - Mac OSX +# Copyright 2006 GameSpy Industries + +PROJECT=sbctest + +PROG_OBJS = \ + ../sbctest.o\ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../md5c.o\ + ../../../common/gsMemory.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsDebug.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformThread.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/macosx/MacOSXCommon.o\ + ../../../natneg/natneg.o\ + ../../../natneg/NATify.o\ + ../../sb_crypt.o\ + ../../sb_queryengine.o\ + ../../sb_server.o\ + ../../sb_serverbrowsing.o\ + ../../sb_serverlist.o\ + ../../../qr2/qr2regkeys.o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/macosx/Makefile.common diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/Nitro.lcf b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/Nitro.lcf new file mode 100644 index 00000000000..998f6b00259 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/Nitro.lcf @@ -0,0 +1,493 @@ +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools - makelcf +# File: ARM9-TS.lcf.template +# +# Copyright 2003-2006 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ARM9-TS.lcf.template,v $ +# Revision 1.34 04/06/2006 09:02:36 kitase_hirotake +# support for .itcm.bss and .dtcm.bss +# +# Revision 1.33 03/30/2006 23:59:22 AM yasu +# changed creation year +# +# Revision 1.32 03/29/2006 13:14:22 AM yasu +# support for overlays in CWVER 2.x +# +# Revision 1.31 11/24/2005 01:16:47 yada +# change start address of mainEX arena from 0x2400000 to 0x23e0000 +# +# Revision 1.30 09/02/2005 04:14:22 AM yasu +# Old symbols were redefined so they can be used even under SDK2.2 +# +# Revision 1.29 08/31/2005 09:34:57 AM yasu +# Corrected a problem where code would not function normally when using section names such as section_BSS +# +# Revision 1.28 08/26/2005 11:22:16 AM yasu +# overlay support for ITCM/DTCM +# +# Revision 1.27 06/20/2005 12:29:20 AM yasu +# Changed Surffix to Suffix +# +# Revision 1.26 06/14/2005 09:03:42 yada +# fix around minus value of SDK_STACKSIZE +# +# Revision 1.25 04/13/2005 12:51:00 terui +# Change SDK_AUTOLOAD.DTCM.START 0x027c0000 -> 0x027e0000 +# +# Revision 1.24 03/30/2005 00:02:14 yosizaki +# fix copyright header. +# +# Revision 1.23 03/25/2005 12:54:59 AM yasu +# Include .version section +# +# Revision 1.22 10/03/2004 02:00:56 AM yasu +# Output component file list for compstatic tool +# +# Revision 1.21 09/27/2004 05:28:21 AM yasu +# Support .sinit +# +# Revision 1.20 09/09/2004 11:49:20 AM yasu +# Support compstatic in default +# +# Revision 1.19 09/06/2004 06:40:00 AM yasu +# Add labels for digest +# +# Revision 1.18 08/20/2004 06:19:59 AM yasu +# DTCM moves to 0x027c0000 at default +# +# Revision 1.17 08/02/2004 10:38:53 AM yasu +# Add autoload-done callback address in overlaydefs +# +# Revision 1.16 07/26/2004 02:22:32 AM yasu +# Change DTCM address to 0x023c0000 +# +# Revision 1.15 07/26/2004 00:08:27 AM yasu +# Fix label of exception table +# +# Revision 1.14 07/24/2004 05:42:25 AM yasu +# Set default values for SDK_AUTOGEN_xTCM_START +# +# Revision 1.13 07/23/2004 11:32:14 AM yasu +# Define labels for __exception_table_start__ and _end__ +# +# Revision 1.12 07/12/2004 12:21:08 AM yasu +# Check size of ITCM/DTCM +# +# Revision 1.11 07/10/2004 04:10:26 AM yasu +# Support command 'Library' +# +# Revision 1.10 07/02/2004 08:13:02 AM yasu +# Support OBJECT( ) +# +# Revision 1.9 07/01/2004 12:54:38 yasu +# support ITCM/DTCM/WRAM autoload +# +# Revision 1.8 07/01/2004 10:41:46 yasu +# support autoload +# +# Revision 1.7 06/02/2004 07:35:37 yasu +# Set libsyscall.a in FORCE_ACTIVE +# Put NitroMain at the top of ROM image +# +# Revision 1.6 06/02/2004 04:56:28 yasu +# Change to fit to new ROM map of TS +# +# Revision 1.5 2004/06/01 06:12:00 miya +# add padding at top of ROM image. +# +# Revision 1.4 04/26/2004 12:16:48 yasu +# add KEEP_SECTIONS +# +# Revision 1.3 04/20/2004 07:41:32 yasu +# Set STATICINIT instead of .ctor temporarily +# +# Revision 1.2 04/14/2004 07:16:42 yasu +# add ALIGN(32) for convenience to handle cache line +# +# Revision 1.1 04/06/2004 01:59:54 yasu +# newly added +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- +MEMORY +{ + main (RWX) : ORIGIN = 0x02000000, LENGTH = 0x0 > main.sbin + ITCM (RWX) : ORIGIN = 0x01ff8000, LENGTH = 0x0 >> main.sbin + DTCM (RWX) : ORIGIN = 0x027e0000, LENGTH = 0x0 >> main.sbin + binary.AUTOLOAD_INFO (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + binary.STATIC_FOOTER (RWX) : ORIGIN = 0, LENGTH = 0x0 >> main.sbin + + main_defs (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_defs.sbin + main_table (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 > main_table.sbin + dummy.MAIN_EX (RW) : ORIGIN = 0x023e0000, LENGTH = 0x0 + arena.MAIN (RW) : ORIGIN = AFTER(main), LENGTH = 0x0 + arena.MAIN_EX (RW) : ORIGIN = AFTER(dummy.MAIN_EX), LENGTH = 0x0 + arena.ITCM (RW) : ORIGIN = AFTER(ITCM), LENGTH = 0x0 + arena.DTCM (RW) : ORIGIN = AFTER(DTCM), LENGTH = 0x0 + binary.MODULE_FILES (RW) : ORIGIN = 0x0, LENGTH = 0x0 > component.files + check.ITCM (RWX) : ORIGIN = 0x0, LENGTH = 0x08000 > itcm.check + check.DTCM (RW) : ORIGIN = 0x0, LENGTH = 0x04000 > dtcm.check +} + +FORCE_ACTIVE +{ + SVC_SoftReset +} + +KEEP_SECTION +{ + .sinit +} + +SECTIONS +{ + ############################ STATIC ################################# + .main: + { + ALIGNALL(4); . = ALIGN(32); # Fit to cache line + + # + # TEXT BLOCK: READ ONLY + # + SDK_STATIC_START =.; + SDK_STATIC_TEXT_START =.; + #:::::::::: text/rodata + libsyscall.a (.text) + crt0.o (.text) + crt0.o (.rodata) + * (.version) + OBJECT(NitroMain,*) + GROUP(ROOT) (.text) + . = ALIGN(4); + * (.exception) + . = ALIGN(4); + SDK_STATIC_ETABLE_START =.; + EXCEPTION + SDK_STATIC_ETABLE_END =.; + . = ALIGN(4); + GROUP(ROOT) (.init) + . = ALIGN(4); + GROUP(ROOT) (.rodata) + . = ALIGN(4); + + SDK_STATIC_SINIT_START =.; + #:::::::::: ctor + GROUP(ROOT) (.ctor) + GROUP(ROOT) (.sinit) + WRITEW 0; + #:::::::::: ctor + SDK_STATIC_SINIT_END =.; + + #:::::::::: text/rodata + . = ALIGN(32); + SDK_STATIC_TEXT_END =.; + + # + # DATA BLOCK: READ WRITE + # + SDK_STATIC_DATA_START =.; + #:::::::::: data + GROUP(ROOT) (.sdata) + . = ALIGN(4); + GROUP(ROOT) (.data) + . = ALIGN(4); + SDK_OVERLAY_DIGEST =.; + # NO DIGEST + SDK_OVERLAY_DIGEST_END =.; + #:::::::::: data + . = ALIGN(32); + SDK_STATIC_DATA_END =.; + SDK_STATIC_END =.; + + SDK_STATIC_TEXT_SIZE = SDK_STATIC_TEXT_END - SDK_STATIC_TEXT_START; + SDK_STATIC_DATA_SIZE = SDK_STATIC_DATA_END - SDK_STATIC_DATA_START; + SDK_STATIC_SIZE = SDK_STATIC_END - SDK_STATIC_START; + __sinit__ = SDK_STATIC_SINIT_START; # for static initializer + __exception_table_start__ = SDK_STATIC_ETABLE_START; # for exception table + __exception_table_end__ = SDK_STATIC_ETABLE_END; # for exception table + } > main + + .main.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_STATIC_BSS_START =.; + #:::::::::: bss + GROUP(ROOT) (.sbss) + . = ALIGN(4); + GROUP(ROOT) (.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_STATIC_BSS_END = .; + SDK_STATIC_BSS_SIZE = SDK_STATIC_BSS_END - SDK_STATIC_BSS_START; + + } >> main + + + ############################ AUTOLOADS ############################## + SDK_AUTOLOAD.ITCM.START = 0x01ff8000; + SDK_AUTOLOAD.ITCM.END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.BSS_END = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD.ITCM.SIZE = 0; + SDK_AUTOLOAD.ITCM.BSS_SIZE = 0; + SDK_AUTOLOAD.DTCM.START = 0x027e0000; + SDK_AUTOLOAD.DTCM.END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.BSS_END = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD.DTCM.SIZE = 0; + SDK_AUTOLOAD.DTCM.BSS_SIZE = 0; + SDK_AUTOLOAD_START = SDK_STATIC_END; + SDK_AUTOLOAD_SIZE = 0; + SDK_AUTOLOAD_NUMBER = 2; + + .ITCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_ITCM_ID =0; + SDK_AUTOLOAD.ITCM.ID =0; + SDK_AUTOLOAD.ITCM.START =.; + SDK_AUTOLOAD.ITCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + * (.itcm) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.ITCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.ITCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.DATA_END =.; + SDK_AUTOLOAD.ITCM.END =.; + + SDK_AUTOLOAD.ITCM.TEXT_SIZE = SDK_AUTOLOAD.ITCM.TEXT_END - SDK_AUTOLOAD.ITCM.TEXT_START; + SDK_AUTOLOAD.ITCM.DATA_SIZE = SDK_AUTOLOAD.ITCM.DATA_END - SDK_AUTOLOAD.ITCM.DATA_START; + SDK_AUTOLOAD.ITCM.SIZE = SDK_AUTOLOAD.ITCM.END - SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.ITCM.SIZE; + + } > ITCM + + .ITCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.ITCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + * (.itcm.bss) + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.ITCM.BSS_END = .; + + SDK_AUTOLOAD.ITCM.BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_END - SDK_AUTOLOAD.ITCM.BSS_START; + + } >> ITCM + + .DTCM: + { + ALIGNALL(4); . = ALIGN(32); + + # + # TEXT BLOCK: READ ONLY + # + SDK_AUTOLOAD_DTCM_ID =1; + SDK_AUTOLOAD.DTCM.ID =1; + SDK_AUTOLOAD.DTCM.START =.; + SDK_AUTOLOAD.DTCM.TEXT_START =.; + #:::::::::: text/rodata + . = ALIGN(4); + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: text/rodata + SDK_AUTOLOAD.DTCM.TEXT_END =.; + + # + # DATA BLOCK: READ WRITE BLOCK + # + SDK_AUTOLOAD.DTCM.DATA_START =.; + #:::::::::: data + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm) + . = ALIGN(4); + #:::::::::: data + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.DATA_END =.; + SDK_AUTOLOAD.DTCM.END =.; + + SDK_AUTOLOAD.DTCM.TEXT_SIZE = SDK_AUTOLOAD.DTCM.TEXT_END - SDK_AUTOLOAD.DTCM.TEXT_START; + SDK_AUTOLOAD.DTCM.DATA_SIZE = SDK_AUTOLOAD.DTCM.DATA_END - SDK_AUTOLOAD.DTCM.DATA_START; + SDK_AUTOLOAD.DTCM.SIZE = SDK_AUTOLOAD.DTCM.END - SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SDK_AUTOLOAD.DTCM.SIZE; + + } > DTCM + + .DTCM.bss: + { + ALIGNALL(4); . = ALIGN(32); + + # + # BSS BLOCK + # + SDK_AUTOLOAD.DTCM.BSS_START = .; + #:::::::::: bss + . = ALIGN(4); + . = ALIGN(4); + * (.dtcm.bss) + . = ALIGN(4); + . = ALIGN(4); + #:::::::::: bss + . = ALIGN(32); + SDK_AUTOLOAD.DTCM.BSS_END = .; + + SDK_AUTOLOAD.DTCM.BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_END - SDK_AUTOLOAD.DTCM.BSS_START; + + } >> DTCM + + + SDK_AUTOLOAD_ITCM_START = SDK_AUTOLOAD.ITCM.START; + SDK_AUTOLOAD_ITCM_END = SDK_AUTOLOAD.ITCM.END; + SDK_AUTOLOAD_ITCM_BSS_END = SDK_AUTOLOAD.ITCM.BSS_END; + SDK_AUTOLOAD_ITCM_SIZE = SDK_AUTOLOAD.ITCM.SIZE; + SDK_AUTOLOAD_ITCM_BSS_SIZE = SDK_AUTOLOAD.ITCM.BSS_SIZE; + SDK_AUTOLOAD_DTCM_START = SDK_AUTOLOAD.DTCM.START; + SDK_AUTOLOAD_DTCM_END = SDK_AUTOLOAD.DTCM.END; + SDK_AUTOLOAD_DTCM_BSS_END = SDK_AUTOLOAD.DTCM.BSS_END; + SDK_AUTOLOAD_DTCM_SIZE = SDK_AUTOLOAD.DTCM.SIZE; + SDK_AUTOLOAD_DTCM_BSS_SIZE = SDK_AUTOLOAD.DTCM.BSS_SIZE; + + ############################ AUTOLOAD_INFO ########################## + .binary.AUTOLOAD_INFO: + { + WRITEW ADDR(.ITCM); + WRITEW SDK_AUTOLOAD.ITCM.SIZE; + WRITEW SDK_AUTOLOAD.ITCM.BSS_SIZE; + WRITEW ADDR(.DTCM); + WRITEW SDK_AUTOLOAD.DTCM.SIZE; + WRITEW SDK_AUTOLOAD.DTCM.BSS_SIZE; + } > binary.AUTOLOAD_INFO + + SDK_AUTOLOAD_LIST = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE; + SDK_AUTOLOAD_LIST_END = SDK_AUTOLOAD_START + SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + SDK_AUTOLOAD_SIZE = SDK_AUTOLOAD_SIZE + SIZEOF(.binary.AUTOLOAD_INFO); + + ############################ STATIC_FOOTER ########################## + .binary.STATIC_FOOTER: + { + WRITEW 0xdec00621; # LE(0x2106C0DE) = NITRO CODE + WRITEW _start_ModuleParams - ADDR(.main); + WRITEW 0; # NO DIGEST + } > binary.STATIC_FOOTER + + ############################ OVERLAYS ############################### + SDK_OVERLAY_NUMBER = 0; + + + ############################ MAIN EX ################################## + # MAIN EX Area + .dummy.MAIN_EX: + { + . = ALIGN(32); + } > dummy.MAIN_EX + + ############################ ARENA ################################## + .arena.MAIN: + { + . = ALIGN(32); + SDK_SECTION_ARENA_START =.; + } > arena.MAIN + + .arena.MAIN_EX: + { + . = ALIGN(32); + SDK_SECTION_ARENA_EX_START =.; + } > arena.MAIN_EX + + .arena.ITCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_ITCM_START =.; + } > arena.ITCM + + .arena.DTCM: + { + . = ALIGN(32); + SDK_SECTION_ARENA_DTCM_START =.; + } > arena.DTCM + + ############################ OVERLAYDEFS ############################ + .main_defs: + { + ### main module information + WRITEW ADDR(.main); # load address + WRITEW _start; # entry address + WRITEW SDK_STATIC_SIZE + SDK_AUTOLOAD_SIZE; # size of module + WRITEW _start_AutoloadDoneCallback; # callback autoload done + + ### overlay filename + + } > main_defs + + + ############################ OVERLAYTABLE ########################### + .main_table: + { + + } > main_table + + + ############################ OTHERS ################################# + SDK_MAIN_ARENA_LO = SDK_SECTION_ARENA_START; + SDK_IRQ_STACKSIZE = 4096; # allocated in DTCM + SDK_SYS_STACKSIZE = 0; # when 0 means all remains of DTCM + + # Module filelist + .binary.MODULE_FILES: + { + WRITES ("main.sbin"); + WRITES ("main_defs.sbin"); + WRITES ("main_table.sbin"); + } > binary.MODULE_FILES + + # ITCM/DTCM size checker => check AUTOLOAD_ITCM/DTCM + .check.ITCM: + { + . = . + SDK_AUTOLOAD_ITCM_SIZE + SDK_AUTOLOAD_ITCM_BSS_SIZE; + } > check.ITCM + + SDK_SYS_STACKSIZE_SIGN = (SDK_SYS_STACKSIZE < 0x80000000) * 2 - 1; + .check.DTCM: + { + . = . + SDK_AUTOLOAD_DTCM_SIZE + SDK_AUTOLOAD_DTCM_BSS_SIZE; + . = . + SDK_IRQ_STACKSIZE + SDK_SYS_STACKSIZE * SDK_SYS_STACKSIZE_SIGN; + } > check.DTCM + +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/ROM-TS.rsf b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/ROM-TS.rsf new file mode 100644 index 00000000000..cec9e1dbf9a --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/ROM-TS.rsf @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Project: NitroSDK - include +# File: ROM-TS.lsf +# +# Copyright 2003-2005 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: ROM-TS.rsf,v $ +# Revision 1.6 2005/04/05 23:52:58 yosizaki +# fix copyright date. +# +# Revision 1.5 2005/04/05 12:16:10 yosizaki +# support RomSpeedType parameter. +# +# Revision 1.4 2004/09/21 02:18:49 yasu +# Add default banner +# +# Revision 1.3 2004/09/09 11:39:09 yasu +# Unified ROM-TS and ROM-TS-C, also ROM-TEG and ROM-TEG-C +# +# Revision 1.2 2004/05/26 12:03:38 yasu +# add :r option to get basename for supporting IDE with makerom +# +# Revision 1.1 2004/04/06 01:59:59 yasu +# newly added +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- +# +# Nitro ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).nef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7:r).sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7:r)_defs.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7:r)_table.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7:r).nef" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(NITROSDK_ROOT)/include/nitro/specfiles/default.bnr + + ### + ### + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot $(MAKEROM_ROMROOT) + Root / + File $(MAKEROM_ROMFILES) +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/sbnitrocw.mcp b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/sbnitrocw.mcp new file mode 100644 index 00000000000..2cc3dd5e6e6 Binary files /dev/null and b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbnitrocw/sbnitrocw.mcp differ diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2/Makefile b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2/Makefile new file mode 100644 index 00000000000..86bcf5f20b0 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2/Makefile @@ -0,0 +1,31 @@ +#GameSpy.net PS2 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CLFAGS = + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + +#Name of the SDK sample +TARGET = sbctest + +#All the object files needed for this SDK +OBJS = ../../../ps2common/ps2common.o \ + ../../../nonport.o \ + ../../../darray.o\ + ../../../hashtable.o\ + ../../../stringutil.o \ + ../../../available.o \ + ../../sb_crypt.o\ + ../../sb_queryengine.o\ + ../../sb_server.o\ + ../../sb_serverbrowsing.o\ + ../../sb_serverlist.o\ + ../../../qr2/qr2regkeys.o\ + crt0.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../ps2common/Makefile.common diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2cw/sbps2cw.mcp b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2cw/sbps2cw.mcp new file mode 100644 index 00000000000..5a09a552d3b Binary files /dev/null and b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2cw/sbps2cw.mcp differ diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.dsp b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.dsp new file mode 100644 index 00000000000..7ccb0b8075f --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.dsp @@ -0,0 +1,368 @@ +# Microsoft Developer Studio Project File - Name="sbps2prodg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=sbps2prodg - Win32 Release_Insock +!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 "sbps2prodg.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 "sbps2prodg.mak" CFG="sbps2prodg - Win32 Release_Insock" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sbps2prodg - Win32 Debug_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "sbps2prodg - Win32 Debug_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "sbps2prodg - Win32 Debug_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE "sbps2prodg - Win32 Release_EENet" (based on "Win32 (x86) Console Application") +!MESSAGE "sbps2prodg - Win32 Release_Insock" (based on "Win32 (x86) Console Application") +!MESSAGE "sbps2prodg - Win32 Release_SNSystems" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/serverbrowsing/sbctest/sbps2prodg", FUEDAAAA" +# PROP Scc_LocalPath "." +CPP=snCl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sbps2prodg - Win32 Debug_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_EENet" +# PROP BASE Intermediate_Dir "Debug_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_EENet" +# PROP Intermediate_Dir "Debug_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W3 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "EENET" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\sbps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\sbps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "sbps2prodg - Win32 Debug_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "sbps2prodg___Win32_Debug_Insock" +# PROP BASE Intermediate_Dir "sbps2prodg___Win32_Debug_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_Insock" +# PROP Intermediate_Dir "Debug_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "EENET" /FD /debug /c +# ADD CPP /nologo /W4 /WX /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "_DEBUG" /D "INSOCK" /D "UNIQUEID" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libc.a eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_EENet\sbps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /debug /machine:IX86 /out:"Debug_Insock\sbps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "sbps2prodg - Win32 Debug_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_SNSystems" +# PROP BASE Intermediate_Dir "Debug_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_SNSystems" +# PROP Intermediate_Dir "Debug_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Debug/" /FD /debug /c +# ADD CPP /nologo /W3 /Od /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "_DEBUG" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /debug /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /out:"PS2_EE_Debug\sbps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libc.a sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /debug /machine:IX86 /nodefaultlib /out:"Debug_SNSystems\sbps2prodg.elf" /D:SN_TARGET_PS2 -fshort-wchar + +!ELSEIF "$(CFG)" == "sbps2prodg - Win32 Release_EENet" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_EENet" +# PROP BASE Intermediate_Dir "Release_EENet" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_EENet" +# PROP Intermediate_Dir "Release_EENet" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\sbps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\sbps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "sbps2prodg - Win32 Release_Insock" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "sbps2prodg___Win32_Release_Insock" +# PROP BASE Intermediate_Dir "sbps2prodg___Win32_Release_Insock" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_Insock" +# PROP Intermediate_Dir "Release_Insock" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include\libeenet" /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "EENET" /FD /c +# ADD CPP /nologo /W4 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "INSOCK" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 eenetctl.a ent_smap.a ent_eth.a ent_ppp.a libeenet.a libscf.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_EENet\sbps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 libinsck.a libnet.a libmrpc.a libkernl.a libcdvd.a libnetif.a netcnfif.a /nologo /pdb:none /machine:IX86 /out:"Release_Insock\sbps2prodg.elf" /D:SN_TARGET_PS2 + +!ELSEIF "$(CFG)" == "sbps2prodg - Win32 Release_SNSystems" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release_SNSystems" +# PROP BASE Intermediate_Dir "Release_SNSystems" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release_SNSystems" +# PROP Intermediate_Dir "Release_SNSystems" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /w /W0 /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /Fo"PS2_EE_Release/" /FD /c +# ADD CPP /nologo /W3 /WX /O2 /I "C:\usr\local\sce\ee\include" /I "C:\usr\local\sce\common\include" /D "SN_TARGET_PS2" /D "SN_SYSTEMS" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=snBsc.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=snLink.exe +# ADD BASE LINK32 libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"PS2_EE_Release\sbps2prodg.elf" /D:SN_TARGET_PS2 +# ADD LINK32 sneetcp.a libcdvd.a libsn.a libgraph.a libdma.a libdev.a libpad.a libpkt.a libvu0.a /nologo /pdb:none /machine:IX86 /out:"Release_SNSystems\sbps2prodg.elf" /D:SN_TARGET_PS2 + +!ENDIF + +# Begin Target + +# Name "sbps2prodg - Win32 Debug_EENet" +# Name "sbps2prodg - Win32 Debug_Insock" +# Name "sbps2prodg - Win32 Debug_SNSystems" +# Name "sbps2prodg - Win32 Release_EENet" +# Name "sbps2prodg - Win32 Release_Insock" +# Name "sbps2prodg - Win32 Release_SNSystems" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\sbctest.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\ps2\prodg\PS2_in_VC.h +# End Source File +# End Group +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\QR2\qr2regkeys.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=..\..\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\..\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\..\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=..\..\sb_server.c +# End Source File +# Begin Source File + +SOURCE=..\..\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=..\..\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\..\sb_serverlist.c +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\darray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\hashtable.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\ps2\ps2common.c +# End Source File +# End Group +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\app.cmd +# End Source File +# Begin Source File + +SOURCE=c:\usr\local\sce\ee\lib\crt0.s +# End Source File +# Begin Source File + +SOURCE=..\..\..\ps2common\prodg\ps2.lk +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.dsw b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.dsw new file mode 100644 index 00000000000..c5bde86be57 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "sbps2prodg"=.\sbps2prodg.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing/sbctest/sbps2prodg", FUEDAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/gamespy/goa/serverbrowsing/sbctest/sbps2prodg", FUEDAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.sln b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.sln new file mode 100644 index 00000000000..676c53cdd99 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.sln @@ -0,0 +1,43 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbps2prodg", "sbps2prodg.vcproj", "{64DF00B3-ED0A-4E4F-9272-66910FCC56AA}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfsapp1:8080/ + SccProjectUniqueName0 = sbps2prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS2 EENET Debug|Win32 = PS2 EENET Debug|Win32 + PS2 EENET Release|Win32 = PS2 EENET Release|Win32 + PS2 INET Debug|Win32 = PS2 INET Debug|Win32 + PS2 INET Release|Win32 = PS2 INET Release|Win32 + PS2 SN Systems Debug|Win32 = PS2 SN Systems Debug|Win32 + PS2 SN Systems Release|Win32 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 EENET Debug|Win32.ActiveCfg = PS2 EENET Debug|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 EENET Debug|Win32.Build.0 = PS2 EENET Debug|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 EENET Release|Win32.ActiveCfg = PS2 EENET Release|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 EENET Release|Win32.Build.0 = PS2 EENET Release|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 INET Debug|Win32.ActiveCfg = PS2 INET Debug|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 INET Debug|Win32.Build.0 = PS2 INET Debug|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 INET Release|Win32.ActiveCfg = PS2 INET Release|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 INET Release|Win32.Build.0 = PS2 INET Release|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 SN Systems Debug|Win32.ActiveCfg = PS2 SN Systems Debug|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 SN Systems Debug|Win32.Build.0 = PS2 SN Systems Debug|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 SN Systems Release|Win32.ActiveCfg = PS2 SN Systems Release|Win32 + {64DF00B3-ED0A-4E4F-9272-66910FCC56AA}.PS2 SN Systems Release|Win32.Build.0 = PS2 SN Systems Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.vcproj new file mode 100644 index 00000000000..8a74bfcb10e --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps2prodg/sbps2prodg.vcproj @@ -0,0 +1,704 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3/Makefile b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3/Makefile new file mode 100644 index 00000000000..47efc46e00d --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3/Makefile @@ -0,0 +1,36 @@ +#GameSpy.net PS3 Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +SDK_LIBS = + + +#Name of the SDK sample +TARGET = sbctest + +#All the object files needed for this SDK +OBJS = ../../../common/ps3/ps3common.o \ + ../../../common/gsPlatform.o\ + ../../../common/gsPlatformSocket.o \ + ../../../common/gsPlatformThread.o \ + ../../../common/gsPlatformUtil.o \ + ../../../common/gsMemory.o \ + ../../../common/gsDebug.o \ + ../../../common/gsStringUtil.o \ + ../../../common/gsAvailable.o \ + ../../../hashtable.o \ + ../../../darray.o \ + ../../../qr2/qr2regkeys.o \ + ../../sb_crypt.o \ + ../../sb_queryengine.o \ + ../../sb_server.o \ + ../../sb_serverbrowsing.o \ + ../../sb_serverlist.o \ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/ps3/Makefile.common diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.sln b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.sln new file mode 100644 index 00000000000..db7166fb382 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbps3prodg", "sbps3prodg.vcproj", "{A089D0F3-E861-4309-89A4-A47A61401A3D}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccProjectUniqueName0 = sbps3prodg.vcproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PS3 Debug|Win32 = PS3 Debug|Win32 + PS3 Release|Win32 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.ActiveCfg = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Debug|Win32.Build.0 = PS3 Debug|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.ActiveCfg = PS3 Release|Win32 + {A089D0F3-E861-4309-89A4-A47A61401A3D}.PS3 Release|Win32.Build.0 = PS3 Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.vcproj new file mode 100644 index 00000000000..5e66ec7112d --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.vcproj @@ -0,0 +1,415 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.vcproj.vspscc b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbps3prodg/sbps3prodg.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpsp/Makefile b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpsp/Makefile new file mode 100644 index 00000000000..b4bf9f46aee --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpsp/Makefile @@ -0,0 +1,35 @@ +#GameSpy.net PSP Makefile + +#SDK-specific compiler flags +#If the SDK uses Unique IDs, add "-DUNIQUEID" +SDK_CFLAGS = -DUNIQUEID -DGSI_MEM_MANAGED -DGSI_COMMON_DEBUG + +#SDK-specific libraries +#If the SDK needs Logitech audio libraries, add "$(LIBDIR)/liblgaud.a" +#SDK_LIBS = + +#Name of the SDK sample +TARGET = sbctest + +#All the object files needed for this SDK +OBJS = ../../../common/psp/pspcommon.o\ + ../../../common/psp/gsUtilPSP.o\ + ../../../common/gsPlatformSocket.o\ + ../../../common/gsPlatformUtil.o\ + ../../../common/gsStringUtil.o\ + ../../../common/gsAvailable.o\ + ../../../common/gsMemory.o\ + ../../../common/gsDebug.o\ + ../../sb_crypt.o\ + ../../sb_queryengine.o\ + ../../sb_serverbrowsing.o\ + ../../sb_serverlist.o\ + ../../sb_server.o\ + ../../../hashtable.o\ + ../../../darray.o\ + ../../../qr2/qr2regkeys.o\ + ../$(TARGET).o + +#Include the stuff common to the GameSpy.net SDKs +include ../../../common/psp/Makefile.common + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpspprodg/sbpspprodg.sln b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpspprodg/sbpspprodg.sln new file mode 100644 index 00000000000..423e891e73a --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpspprodg/sbpspprodg.sln @@ -0,0 +1,34 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbpspprodg", "sbpspprodg.vcproj", "{962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = sbpspprodg.vcproj + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + PSP Debug Opt|Win32 = PSP Debug Opt|Win32 + PSP Debug|Win32 = PSP Debug|Win32 + PSP Release|Win32 = PSP Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug Opt|Win32.ActiveCfg = PSP Debug Opt|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug Opt|Win32.Build.0 = PSP Debug Opt|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug|Win32.ActiveCfg = PSP Debug|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Debug|Win32.Build.0 = PSP Debug|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Release|Win32.ActiveCfg = PSP Release|Win32 + {962BDE0F-6BDA-4C68-AAB6-9B35F7F9A4E0}.PSP Release|Win32.Build.0 = PSP Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpspprodg/sbpspprodg.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpspprodg/sbpspprodg.vcproj new file mode 100644 index 00000000000..9906f9211d3 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbpspprodg/sbpspprodg.vcproj @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbrevolutioncw/sbrevolutioncw.mcp b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbrevolutioncw/sbrevolutioncw.mcp new file mode 100644 index 00000000000..89a804fcf98 Binary files /dev/null and b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbrevolutioncw/sbrevolutioncw.mcp differ diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbx360/sbx360.sln b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbx360/sbx360.sln new file mode 100644 index 00000000000..f9194437dc2 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbx360/sbx360.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbx360", "sbx360.vcproj", "{5916E6A7-E04A-4AF1-8203-6A1E199E02FA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Xbox 360 = Debug|Xbox 360 + Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360 + Profile|Xbox 360 = Profile|Xbox 360 + Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360 + Release|Xbox 360 = Release|Xbox 360 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Debug|Xbox 360.Build.0 = Debug|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Profile|Xbox 360.Build.0 = Profile|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 + {5916E6A7-E04A-4AF1-8203-6A1E199E02FA}.Release|Xbox 360.Build.0 = Release|Xbox 360 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/serverbrowsing/sbctest/sbx360/sbx360.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbx360/sbx360.vcproj new file mode 100644 index 00000000000..37d3c45a69f --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbctest/sbx360/sbx360.vcproj @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/StdAfx.cpp b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/StdAfx.cpp new file mode 100644 index 00000000000..749a2aaa980 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// sbmfcsample.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/StdAfx.h b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/StdAfx.h new file mode 100644 index 00000000000..3f7783ea131 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/StdAfx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__BFD40F2B_3C12_4712_8A50_65B3BCFA0A5F__INCLUDED_) +#define AFX_STDAFX_H__BFD40F2B_3C12_4712_8A50_65B3BCFA0A5F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__BFD40F2B_3C12_4712_8A50_65B3BCFA0A5F__INCLUDED_) diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/res/sbmfcsample.ico b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/res/sbmfcsample.ico new file mode 100644 index 00000000000..7eef0bcbe65 Binary files /dev/null and b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/res/sbmfcsample.ico differ diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/res/sbmfcsample.rc2 b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/res/sbmfcsample.rc2 new file mode 100644 index 00000000000..8289015ef25 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/res/sbmfcsample.rc2 @@ -0,0 +1,13 @@ +// +// SBMFCSAMPLE.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/resource.h b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/resource.h new file mode 100644 index 00000000000..10c3d57c5bd --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/resource.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by sbmfcsample.rc +// +#define IDD_SBMFCSAMPLE_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_SERVERLIST 1001 +#define IDC_REFRESH 1002 +#define IDC_PLAYERLIST 1003 +#define IDC_GAMENAME 1004 +#define IDC_FILTER 1005 +#define IDC_INTERNET 1006 +#define IDC_LAN 1007 +#define IDC_STARTP 1008 +#define IDC_ENDP 1009 +#define IDC_GOA 1010 +#define IDC_QR2 1011 +#define IDC_PROGRESS 1012 +#define IDC_SERVERS 1013 +#define IDC_PLAYERS 1014 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1016 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.cpp b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.cpp new file mode 100644 index 00000000000..4277c7f8019 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.cpp @@ -0,0 +1,63 @@ +// sbmfcsample.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "sbmfcsample.h" +#include "sbmfcsampleDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleApp + +BEGIN_MESSAGE_MAP(CSbmfcsampleApp, CWinApp) + //{{AFX_MSG_MAP(CSbmfcsampleApp) + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleApp construction + +CSbmfcsampleApp::CSbmfcsampleApp() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CSbmfcsampleApp object + +CSbmfcsampleApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleApp initialization + +BOOL CSbmfcsampleApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization +/* +#ifdef _AFXDLL + Enable3dControls(); // Call this when using MFC in a shared DLL +#else + Enable3dControlsStatic(); // Call this when linking to MFC statically +#endif +*/ + CSbmfcsampleDlg dlg; + m_pMainWnd = &dlg; + int nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + } + else if (nResponse == IDCANCEL) + { + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.dsp b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.dsp new file mode 100644 index 00000000000..215c795657e --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.dsp @@ -0,0 +1,390 @@ +# Microsoft Developer Studio Project File - Name="sbmfcsample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=sbmfcsample - 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 "sbmfcsample.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 "sbmfcsample.mak" CFG="sbmfcsample - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sbmfcsample - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "sbmfcsample - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/serverbrowsing/sbmfcsample", DDVCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +# PROP BASE Use_MFC 5 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# 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 /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# 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 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /machine:I386 /ignore:4089 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# PROP BASE Use_MFC 5 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# 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 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "sbmfcsample - Win32 Release" +# Name "sbmfcsample - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sbmfcsample.cpp +# End Source File +# Begin Source File + +SOURCE=.\sbmfcsample.rc +# End Source File +# Begin Source File + +SOURCE=.\sbmfcsampleDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\sbmfcsample.h +# End Source File +# Begin Source File + +SOURCE=.\sbmfcsampleDlg.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\sbmfcsample.ico +# End Source File +# Begin Source File + +SOURCE=.\res\sbmfcsample.rc2 +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\darray.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\darray.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.c + +!IF "$(CFG)" == "sbmfcsample - Win32 Release" + +!ELSEIF "$(CFG)" == "sbmfcsample - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\common\gsStringUtil.h +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\hashtable.h +# End Source File +# End Group +# Begin Group "ServerBrowsingSDK" + +# PROP Default_Filter "" +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\sb_crypt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=..\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=..\sb_queryengine.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\sb_server.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\sb_serverbrowsing.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\sb_serverbrowsing.h +# End Source File +# Begin Source File + +SOURCE=..\sb_serverlist.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\..\natneg\nninternal.h +# End Source File +# End Group +# End Target +# End Project diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.h b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.h new file mode 100644 index 00000000000..60e34cbe148 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.h @@ -0,0 +1,47 @@ +// sbmfcsample.h : main header file for the SBMFCSAMPLE application +// + +#if !defined(AFX_SBMFCSAMPLE_H__F2EE1BD5_6089_4F00_9E83_2D0A7C9AA592__INCLUDED_) +#define AFX_SBMFCSAMPLE_H__F2EE1BD5_6089_4F00_9E83_2D0A7C9AA592__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleApp: +// See sbmfcsample.cpp for the implementation of this class +// + +class CSbmfcsampleApp : public CWinApp +{ +public: + CSbmfcsampleApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSbmfcsampleApp) + public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + +// Implementation + + //{{AFX_MSG(CSbmfcsampleApp) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SBMFCSAMPLE_H__F2EE1BD5_6089_4F00_9E83_2D0A7C9AA592__INCLUDED_) diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.rc b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.rc new file mode 100644 index 00000000000..f05e98b185e --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.rc @@ -0,0 +1,197 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\sbmfcsample.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON DISCARDABLE "res\\sbmfcsample.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SBMFCSAMPLE_DIALOG DIALOGEX 0, 0, 320, 251 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "sbmfcsample" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Refresh",IDC_REFRESH,7,127,50,14 + PUSHBUTTON "Close",IDOK,60,127,50,14 + EDITTEXT IDC_GAMENAME,49,145,56,12,ES_AUTOHSCROLL + EDITTEXT IDC_FILTER,49,160,56,12,ES_AUTOHSCROLL + CONTROL "Internet",IDC_INTERNET,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,7,176,40,10 + CONTROL "Lan",IDC_LAN,"Button",BS_AUTORADIOBUTTON,60,176,28,10 + CONTROL "GOA",IDC_GOA,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7, + 188,31,10 + CONTROL "QR2",IDC_QR2,"Button",BS_AUTORADIOBUTTON,60,188,31,10 + CONTROL "List2",IDC_SERVERLIST,"SysListView32",LVS_REPORT | + WS_BORDER | WS_GROUP | WS_TABSTOP,7,7,306,117 + CONTROL "List3",IDC_PLAYERLIST,"SysListView32",LVS_REPORT | + WS_BORDER | WS_TABSTOP,112,146,201,98 + LTEXT "Gamename:",IDC_STATIC,7,147,39,8 + LTEXT "Filter:",IDC_STATIC,7,162,18,8 + CONTROL "Progress2",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,112,126,144,10 + LTEXT "Servers:",IDC_STATIC,260,126,27,8 + LTEXT "222222",IDC_SERVERS,288,126,25,8 + EDITTEXT IDC_STARTP,49,214,56,12,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_ENDP,49,229,56,12,ES_AUTOHSCROLL | ES_NUMBER + CTEXT "For LAN Only",IDC_STATIC,16,201,72,11 + LTEXT "Start Port",IDC_STATIC,7,215,35,11 + LTEXT "End Port",IDC_STATIC,8,230,28,11 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "sbmfcsample MFC Application\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "sbmfcsample\0" + VALUE "LegalCopyright", "Copyright (C) 2002\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "sbmfcsample.EXE\0" + VALUE "ProductName", "sbmfcsample Application\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_SBMFCSAMPLE_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 244 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\sbmfcsample.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.vcproj new file mode 100644 index 00000000000..b956286798d --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.vcproj @@ -0,0 +1,639 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.vcproj.vspscc b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.vcproj.vspscc new file mode 100644 index 00000000000..17a7054ce77 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "file:C:\\Gamespy\\GOA\\serverbrowsing\\sbmfcsample\\sbmfcsample.vcproj" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsampleDlg.cpp b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsampleDlg.cpp new file mode 100644 index 00000000000..8d033aeb873 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsampleDlg.cpp @@ -0,0 +1,497 @@ +// sbmfcsampleDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "sbmfcsample.h" +#include "sbmfcsampleDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +//SB - timer ID and frequency +#define TIMER_ID 100 +#define TIMER_FREQUENCY 10 + +//SB - server list columns +#define COL_SERVERNAME 0 +#define COL_PING 1 +#define COL_PLAYERS 2 +#define COL_MAPNAME 3 +#define COL_GAMETYPE 4 + +//SB - player list columns +#define COL_PNAME 0 +#define COL_PPING 1 +#define COL_PSCORE 2 + +// 11-02-2004 : Saad Nader +// replaced with a GUI-based way of doing it. +//SB - starting and ending port for LAN game searches +//#define START_PORT 7778 +//#define END_PORT (START_PORT + 100) + +//SB - maximum number of concurrent updates +#define MAX_UPDATES 30 + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleDlg dialog + +CSbmfcsampleDlg::CSbmfcsampleDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSbmfcsampleDlg::IDD, pParent) +{ + //{{AFX_DATA_INIT(CSbmfcsampleDlg) + m_filter = _T(""); + m_gamename = _T(""); + m_startPort = 0; + m_endPort = 0; + //}}AFX_DATA_INIT + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CSbmfcsampleDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CSbmfcsampleDlg) + DDX_Control(pDX, IDC_SERVERS, m_servers); + DDX_Control(pDX, IDC_PROGRESS, m_progress); + DDX_Control(pDX, IDC_SERVERLIST, m_serverList); + DDX_Control(pDX, IDC_PLAYERLIST, m_playerList); + DDX_Text(pDX, IDC_FILTER, m_filter); + DDX_Text(pDX, IDC_GAMENAME, m_gamename); + DDX_Text(pDX, IDC_STARTP, m_startPort); + DDX_Text(pDX, IDC_ENDP, m_endPort); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CSbmfcsampleDlg, CDialog) + //{{AFX_MSG_MAP(CSbmfcsampleDlg) + ON_BN_CLICKED(IDC_REFRESH, OnRefresh) + ON_NOTIFY(NM_CLICK, IDC_SERVERLIST, OnClickServerlist) + ON_NOTIFY(NM_DBLCLK, IDC_SERVERLIST, OnDblclkServerlist) + ON_WM_TIMER() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_NOTIFY(LVN_COLUMNCLICK, IDC_SERVERLIST, OnColumnclickServerlist) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleDlg message handlers + +BOOL CSbmfcsampleDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + SetIcon(m_hIcon, TRUE); + SetIcon(m_hIcon, FALSE); + + //SB - setup list columns + m_serverList.InsertColumn(COL_SERVERNAME, "Server Name", LVCFMT_LEFT, 150, -1); + m_serverList.InsertColumn(COL_PING, "Ping", LVCFMT_LEFT, 50, 0); + m_serverList.InsertColumn(COL_PLAYERS, "Players", LVCFMT_LEFT, 75, 1); + m_serverList.InsertColumn(COL_MAPNAME, "Map", LVCFMT_LEFT, 75, 2); + m_serverList.InsertColumn(COL_GAMETYPE, "GameType", LVCFMT_LEFT, 100, 3); + m_playerList.InsertColumn(COL_PNAME, "Player Name", LVCFMT_LEFT, 150, -1); + m_playerList.InsertColumn(COL_PPING, "Ping", LVCFMT_LEFT, 50, 0); + m_playerList.InsertColumn(COL_PSCORE, "Score", LVCFMT_LEFT, 50, 1); + ListView_SetExtendedListViewStyle(m_serverList.m_hWnd, LVS_EX_FULLROWSELECT); + ListView_SetExtendedListViewStyle(m_playerList.m_hWnd, LVS_EX_FULLROWSELECT); + + //SB - default to Internet + CheckRadioButton(IDC_INTERNET, IDC_LAN, IDC_INTERNET); + + //SB - default to QR2 + CheckRadioButton(IDC_GOA, IDC_QR2, IDC_QR2); + + //SB - no server browser yet + m_serverBrowser = NULL; + + //SB - no timer yet + m_timerID = 0; + + //SB - no servers yet + m_servers.SetWindowText(""); + + //SB - check that the game's backend is available + GSIACResult result; + GSIStartAvailableCheck("gmtest"); + while((result = GSIAvailableCheckThink()) == GSIACWaiting) + msleep(5); + if(result != GSIACAvailable) + { + MessageBox("The backend is not available\n"); + return TRUE; + } + + return TRUE; +} + +BOOL CSbmfcsampleDlg::DestroyWindow() +{ + // free the browser + if(m_serverBrowser) + { + ServerBrowserFree(m_serverBrowser); + m_serverBrowser = NULL; + } + + return CDialog::DestroyWindow(); +} + +void CSbmfcsampleDlg::OnTimer(UINT nIDEvent) +{ + // think if our timer was called + if(nIDEvent == m_timerID) + { + ServerBrowserThink(m_serverBrowser); + } + + CDialog::OnTimer(nIDEvent); +} + +void CSbmfcsampleDlg::OnRefresh() +{ + UpdateData(); + + // create the server list if we need to + if(!CreateServerList()) + return; + + // if we're doing an update, cancel it + SBState state = ServerBrowserState(m_serverBrowser); + if((state != sb_connected) && (state != sb_disconnected)) + { + ServerBrowserHalt(m_serverBrowser); + return; + } + + // clear the server browser and list + ServerBrowserClear(m_serverBrowser); + m_serverList.DeleteAllItems(); + + // clear the progress bar + m_progress.SetPos(0); + + // clear the server count + m_serverCount = 0; + m_servers.SetWindowText("0"); + + // set a timer + if(!m_timerID) + m_timerID = SetTimer(TIMER_ID, TIMER_FREQUENCY, NULL); + + // fields we're interested in + unsigned char fields[] = { HOSTNAME_KEY, NUMPLAYERS_KEY, MAXPLAYERS_KEY, MAPNAME_KEY, GAMETYPE_KEY }; + int numFields = sizeof(fields) / sizeof(fields[0]); + + // check for internet/lan + bool internet = (IsDlgButtonChecked(IDC_INTERNET) == BST_CHECKED); + + // do an update + SBError error; + if(internet) + error = ServerBrowserUpdate(m_serverBrowser, SBTrue, SBFalse, fields, numFields, (char *)(const char *)m_filter); + else + error = ServerBrowserLANUpdate(m_serverBrowser, SBTrue, (unsigned short)m_startPort, (unsigned short)m_endPort); +} + +void CSbmfcsampleDlg::OnClickServerlist(NMHDR* pNMHDR, LRESULT* pResult) +{ + // clear the player box + m_playerList.DeleteAllItems(); + + // find the selected server + POSITION pos = m_serverList.GetFirstSelectedItemPosition(); + if(pos == NULL) + return; + int index = m_serverList.GetNextSelectedItem(pos); + + // get the server + LVITEM item; + item.mask = LVIF_PARAM; + item.iItem = index; + item.iSubItem = 0; + m_serverList.GetItem(&item); + SBServer server = (SBServer)item.lParam; + + if (!SBServerHasFullKeys(server)) //we need to query for the full rules + { + // turn on the hour glass + HCURSOR cursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); + + // do a server update (this is blocking!) + ServerBrowserAuxUpdateServer(m_serverBrowser, server, SBFalse, SBTrue); + + // turn off the hour glass + SetCursor(cursor); + } + + // get the player count + int count = SBServerGetIntValue(server, "numplayers", 0); + + // add the players to the list + for(int i = 0 ; i < count ; i++) + { + m_playerList.InsertItem(0, SBServerGetPlayerStringValue(server, i, "player", "(NO NAME)")); + m_playerList.SetItem(0, COL_PPING, LVIF_TEXT, SBServerGetPlayerStringValue(server, i, "ping", "0"), -1, 0, 0, 0); + m_playerList.SetItem(0, COL_PSCORE, LVIF_TEXT, SBServerGetPlayerStringValue(server, i, "score", "0"), -1, 0, 0, 0); + } + + // MFC + *pResult = 0; + + GSI_UNUSED(pNMHDR); +} + +void CSbmfcsampleDlg::OnDblclkServerlist(NMHDR* pNMHDR, LRESULT* pResult) +{ + // launch the game here + //MessageBox("If this were a real server browser, you would be launched now!","Go!"); + + // find the selected server + POSITION pos = m_serverList.GetFirstSelectedItemPosition(); + if(pos == NULL) + return; + int index = m_serverList.GetNextSelectedItem(pos); + + // get the server + LVITEM item; + item.mask = LVIF_PARAM; + item.iItem = index; + item.iSubItem = 0; + m_serverList.GetItem(&item); + SBServer server = (SBServer)item.lParam; + SBError error = ServerBrowserConnectToServer(m_serverBrowser, server, SBConnectCallback); + if(error != sbe_noerror) + MessageBox("Error starting connect to server"); + + // MFC + *pResult = 0; + + GSI_UNUSED(pNMHDR); +} + +void CSbmfcsampleDlg::OnColumnclickServerlist(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; + + // track ascending/descending + static bool ascending = false; + ascending = !ascending; + + //figure out which column they clicked + switch(pNMListView->iSubItem) + { + case COL_SERVERNAME: + ServerBrowserSort(m_serverBrowser, (SBBool)ascending, "hostname", sbcm_stricase); + break; + case COL_PING: + ServerBrowserSort(m_serverBrowser, (SBBool)ascending, "ping", sbcm_int); + break; + case COL_PLAYERS: + ServerBrowserSort(m_serverBrowser, (SBBool)ascending, "numplayers", sbcm_int); + break; + case COL_MAPNAME: + ServerBrowserSort(m_serverBrowser, (SBBool)ascending, "mapname", sbcm_stricase); + break; + case COL_GAMETYPE: + ServerBrowserSort(m_serverBrowser, (SBBool)ascending, "gametype", sbcm_stricase); + break; + } + + // we don't want the server list to redraw every time we insert a server! + m_serverList.SetRedraw(false); + + // clear the server list + m_serverList.DeleteAllItems(); + + // clear the server count + m_serverCount = 0; + m_servers.SetWindowText("0"); + + // go through the list of servers + for(int i = 0; i < ServerBrowserCount(m_serverBrowser) ; i++) + { + // if we got basic info for it, put it back in the list + SBServer server = ServerBrowserGetServer(m_serverBrowser, i); + if(SBServerHasBasicKeys(server)) + AddServer(server, FALSE); + } + + // let the server list redraw itself now that we're done updating + m_serverList.SetRedraw(true); + + *pResult = 0; +} + +void CSbmfcsampleDlg::SBCallback(ServerBrowser serverBrowser, SBCallbackReason reason, SBServer server, void *instance) +{ + CString str; + CSbmfcsampleDlg * dlg = (CSbmfcsampleDlg *)instance; + + CString address; + if(server) + address.Format("%s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server)); + + switch(reason) + { + case sbc_serveradded: + dlg->AddServer(server, TRUE); + break; + case sbc_serverupdated: + dlg->AddServer(server, TRUE); + break; + case sbc_serverupdatefailed: + break; + case sbc_serverdeleted: + dlg->RemoveServer(server); + break; + case sbc_updatecomplete: + dlg->m_progress.SetPos(100); + break; + case sbc_queryerror: + str.Format("Query Error: %s\n", ServerBrowserListQueryError(dlg->m_serverBrowser)); + dlg->MessageBox(str); + break; + } + + GSI_UNUSED(serverBrowser); +} + +void CSbmfcsampleDlg::SBConnectCallback(ServerBrowser serverBrowser, SBConnectToServerState state, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *instance) +{ + CSbmfcsampleDlg * dlg = (CSbmfcsampleDlg *)instance; + + switch(state) + { + case sbcs_succeeded: + dlg->MessageBox("Connected to server"); + closesocket(gamesocket); + break; + case sbcs_failed: + dlg->MessageBox("Failed to connect to server"); + break; + } + + GSI_UNUSED(serverBrowser); + GSI_UNUSED(remoteaddr); +} + +BOOL CSbmfcsampleDlg::CreateServerList() +{ + // only create the object once + if(!m_serverBrowser) + { + // check for an empty gamename + if(m_gamename.IsEmpty()) + { + MessageBox("No game specified"); + GetDlgItem(IDC_GAMENAME)->SetFocus(); + return FALSE; + } + SBBool lanBrowsing = (SBBool)(IsDlgButtonChecked(IDC_LAN) == BST_CHECKED); + if (m_startPort == 0 && lanBrowsing == SBTrue) + { + AfxMessageBox("Invalid start port!"); + GetDlgItem(IDC_STARTP)->SetFocus(); + return FALSE; + } + if (m_endPort == 0 && lanBrowsing == SBTrue) + { + AfxMessageBox("Invalid end port!"); + GetDlgItem(IDC_ENDP)->SetFocus(); + return FALSE; + } + + // create it + m_serverBrowser = ServerBrowserNew(m_gamename, "gmtest", "HA6zkS", 0, MAX_UPDATES, (IsDlgButtonChecked(IDC_GOA) == BST_CHECKED)?QVERSION_GOA:QVERSION_QR2, lanBrowsing, SBCallback, this); + if(!m_serverBrowser) + { + MessageBox("Unable to create the server browser object"); + return FALSE; + } + + // don't let them change the gamename + GetDlgItem(IDC_GAMENAME)->EnableWindow(FALSE); + } + + return TRUE; +} + +void CSbmfcsampleDlg::AddServer(SBServer server, BOOL checkForReplace) +{ + // set the progress + if(ServerBrowserCount(m_serverBrowser) > 0) + m_progress.SetPos((ServerBrowserCount(m_serverBrowser) - ServerBrowserPendingQueryCount(m_serverBrowser)) * 100 / ServerBrowserCount(m_serverBrowser)); + + // check for the server in the list + int index = FindServer(server); + bool replace = (index != -1); + + // if we didn't find a server to replace, append + if(!replace) + index = m_serverList.GetItemCount(); + + // set or insert the hostname + const char * hostname = SBServerGetStringValue(server, "hostname","(NO NAME)"); + if(replace) + { + m_serverList.SetItem(index, COL_SERVERNAME, LVIF_TEXT, hostname, -1, 0, 0, NULL); + } + else + { + m_serverList.InsertItem(index, hostname); + m_serverList.SetItem(index, COL_SERVERNAME, LVIF_PARAM, NULL, -1, 0, 0, (LPARAM)server); + } + + // set the rest of the columns + int numplayers = SBServerGetIntValue(server, "numplayers", 0); + CString ping, players; + if (SBServerHasValidPing(server)) + ping.Format("%d%s", SBServerGetPing(server), SBServerDirectConnect(server) ? "" : "i"); + else + ping = "Unknown"; + players.Format("%d/%d", numplayers, SBServerGetIntValue(server, "maxplayers", 0)); + m_serverList.SetItem(index, COL_PING, LVIF_TEXT, ping, -1, 0, 0, 0); + m_serverList.SetItem(index, COL_PLAYERS, LVIF_TEXT, players, -1, 0, 0, 0); + m_serverList.SetItem(index, COL_MAPNAME, LVIF_TEXT, SBServerGetStringValue(server, "mapname", "(NO MAP)"), -1, 0, 0, 0); + m_serverList.SetItem(index, COL_GAMETYPE, LVIF_TEXT, SBServerGetStringValue(server, "gametype", ""), -1, 0, 0, 0); + + // update server count + if(!replace) + { + CString str; + str.Format("%d", ++m_serverCount); + m_servers.SetWindowText(str); + } + + GSI_UNUSED(checkForReplace); +} + +void CSbmfcsampleDlg::RemoveServer(SBServer server) +{ + // find the server + int index = FindServer(server); + ASSERT(index != -1); + if(index == -1) + return; + + // remove it + m_serverList.DeleteItem(index); + + // update server count + CString str; + str.Format("%d", --m_serverCount); + m_servers.SetWindowText(str); +} + +int CSbmfcsampleDlg::FindServer(SBServer server) +{ + LVFINDINFO info; + info.flags = LVFI_PARAM; + info.lParam = (LPARAM)server; + return m_serverList.FindItem(&info); +} diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsampleDlg.h b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsampleDlg.h new file mode 100644 index 00000000000..10498e0cf75 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsampleDlg.h @@ -0,0 +1,74 @@ +// sbmfcsampleDlg.h : header file +// + +#if !defined(AFX_SBMFCSAMPLEDLG_H__8B726D03_AF99_4938_A63C_18525912E55D__INCLUDED_) +#define AFX_SBMFCSAMPLEDLG_H__8B726D03_AF99_4938_A63C_18525912E55D__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CSbmfcsampleDlg dialog + +//SB - header +#include "..\sb_serverbrowsing.h" +#include "..\..\qr2\qr2regkeys.h" +#include "..\..\common\gsAvailable.h" + +class CSbmfcsampleDlg : public CDialog +{ +// Construction +public: + CSbmfcsampleDlg(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CSbmfcsampleDlg) + enum { IDD = IDD_SBMFCSAMPLE_DIALOG }; + CStatic m_servers; + CProgressCtrl m_progress; + CListCtrl m_serverList; + CListCtrl m_playerList; + CString m_filter; + CString m_gamename; + int m_startPort; + int m_endPort; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSbmfcsampleDlg) + public: + virtual BOOL DestroyWindow(); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + static void SBCallback(ServerBrowser serverBrowser, SBCallbackReason reason, SBServer server, void * instance); + static void SBConnectCallback(ServerBrowser serverBrowser, SBConnectToServerState state, SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *instance); + void AddServer(SBServer server, BOOL checkForReplace); + void RemoveServer(SBServer server); + int FindServer(SBServer server); + BOOL CreateServerList(); + HICON m_hIcon; + ServerBrowser m_serverBrowser; + UINT m_timerID; + int m_serverCount; + + // Generated message map functions + //{{AFX_MSG(CSbmfcsampleDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnRefresh(); + afx_msg void OnClickServerlist(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDblclkServerlist(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnColumnclickServerlist(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_SBMFCSAMPLEDLG_H__8B726D03_AF99_4938_A63C_18525912E55D__INCLUDED_) diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample_vs2005.vcproj b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample_vs2005.vcproj new file mode 100644 index 00000000000..6147797b09c --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample_vs2005.vcproj @@ -0,0 +1,860 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample_vs2005.vcproj.vspscc b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample_vs2005.vcproj.vspscc new file mode 100644 index 00000000000..b6d32892fd6 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/sbmfcsample/sbmfcsample_vs2005.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/xrGameSpy/gamespy/serverbrowsing/serverbrowsing.dsp b/xrGameSpy/gamespy/serverbrowsing/serverbrowsing.dsp new file mode 100644 index 00000000000..f762830a43a --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/serverbrowsing.dsp @@ -0,0 +1,244 @@ +# Microsoft Developer Studio Project File - Name="serverbrowsing" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=serverbrowsing - 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 "serverbrowsing.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 "serverbrowsing.mak" CFG="serverbrowsing - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "serverbrowsing - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "serverbrowsing - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Gamespy/GOA/serverbrowsing", HDPCAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "serverbrowsing - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "serverbrowsing - 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 Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "serverbrowsing - Win32 Release" +# Name "serverbrowsing - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\sb_crypt.c +# End Source File +# Begin Source File + +SOURCE=.\sb_queryengine.c +# End Source File +# Begin Source File + +SOURCE=.\sb_server.c +# End Source File +# Begin Source File + +SOURCE=.\sb_serverbrowsing.c +# End Source File +# Begin Source File + +SOURCE=.\sb_serverlist.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\sb_crypt.h +# End Source File +# Begin Source File + +SOURCE=.\sb_internal.h +# End Source File +# Begin Source File + +SOURCE=.\sb_serverbrowsing.h +# End Source File +# End Group +# Begin Group "GsCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\common\gsAssert.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAssert.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsAvailable.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsCommon.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsDebug.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsMemory.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatform.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformSocket.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformThread.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsPlatformUtil.h +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.c +# End Source File +# Begin Source File + +SOURCE=..\common\gsStringUtil.h +# End Source File +# End Group +# Begin Group "QueryReporting2SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\qr2\qr2regkeys.c +# End Source File +# Begin Source File + +SOURCE=..\qr2\qr2regkeys.h +# End Source File +# End Group +# Begin Group "NatNegSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\natneg\NATify.c +# End Source File +# Begin Source File + +SOURCE=..\natneg\NATify.h +# End Source File +# Begin Source File + +SOURCE=..\natneg\natneg.c +# End Source File +# Begin Source File + +SOURCE=..\natneg\natneg.h +# End Source File +# Begin Source File + +SOURCE=..\natneg\nninternal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# End Target +# End Project diff --git a/xrGameSpy/gamespy/serverbrowsing/serverbrowsing.dsw b/xrGameSpy/gamespy/serverbrowsing/serverbrowsing.dsw new file mode 100644 index 00000000000..040e0fe02a7 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/serverbrowsing.dsw @@ -0,0 +1,85 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "querytest"=.\querytest\querytest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing/querytest", XYTCAAAA + .\querytest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "sbctest"=.\sbctest\sbctest.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing/sbctest", IDPCAAAA + .\sbctest + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "sbmfcsample"=.\sbmfcsample\sbmfcsample.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing/sbmfcsample", DDVCAAAA + .\sbmfcsample + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "serverbrowsing"=.\serverbrowsing.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing", HDPCAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/Gamespy/GOA/serverbrowsing", HDPCAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/xrGameSpy/gamespy/serverbrowsing/serverbrowsing_vs2005.sln b/xrGameSpy/gamespy/serverbrowsing/serverbrowsing_vs2005.sln new file mode 100644 index 00000000000..83ed3f78df6 --- /dev/null +++ b/xrGameSpy/gamespy/serverbrowsing/serverbrowsing_vs2005.sln @@ -0,0 +1,60 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "querytest_vs2005", "querytest\querytest_vs2005.vcproj", "{496BCFAD-C259-4B63-B084-59EAEE570802}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbctest_vs2005", "sbctest\sbctest_vs2005.vcproj", "{992EF71C-95A5-4D52-B809-BE79BB6BD953}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbmfcsample_vs2005", "sbmfcsample\sbmfcsample_vs2005.vcproj", "{C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs.ign.com:8080/ + SccLocalPath0 = . + SccProjectUniqueName1 = querytest\\querytest_vs2005.vcproj + SccProjectName1 = querytest + SccLocalPath1 = querytest + SccProjectUniqueName2 = sbctest\\sbctest_vs2005.vcproj + SccProjectName2 = sbctest + SccLocalPath2 = sbctest + SccProjectUniqueName3 = sbmfcsample\\sbmfcsample_vs2005.vcproj + SccProjectName3 = sbmfcsample + SccLocalPath3 = sbmfcsample + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {496BCFAD-C259-4B63-B084-59EAEE570802}.Debug|Win32.ActiveCfg = Debug|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Debug|Win32.Build.0 = Debug|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Release|Win32.ActiveCfg = Release|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Release|Win32.Build.0 = Release|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {496BCFAD-C259-4B63-B084-59EAEE570802}.Unicode Release|Win32.Build.0 = Release|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Debug|Win32.ActiveCfg = Debug|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Debug|Win32.Build.0 = Debug|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Release|Win32.ActiveCfg = Release|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Release|Win32.Build.0 = Release|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {992EF71C-95A5-4D52-B809-BE79BB6BD953}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Debug|Win32.Build.0 = Debug|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Release|Win32.ActiveCfg = Release|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Release|Win32.Build.0 = Release|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Unicode Debug|Win32.ActiveCfg = Debug|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Unicode Debug|Win32.Build.0 = Debug|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Unicode Release|Win32.ActiveCfg = Release|Win32 + {C9FD77D7-9F99-45E1-BAF6-1A30E62313E6}.Unicode Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xrGameSpy/gamespy/webservices/AuthService.c b/xrGameSpy/gamespy/webservices/AuthService.c new file mode 100644 index 00000000000..0ad0ac51d13 --- /dev/null +++ b/xrGameSpy/gamespy/webservices/AuthService.c @@ -0,0 +1,1093 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#include "AuthService.h" +#include "../common/gsXML.h" +#include "../common/gsAvailable.h" +#include "../md5.h" + +#pragma warning(disable: 4267) + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define WS_AUTHSERVICE_LOGINPROFILE "LoginProfile" +#define WS_AUTHSERVICE_LOGINUNIQUE "LoginUniqueNick" +#define WS_AUTHSERVICE_LOGINREMOTEAUTH "LoginRemoteAuth" +#define WS_AUTHSERVICE_LOGINPS3CERT "LoginPs3Cert" +#define WS_AUTHSERVICE_PROTOVERSION 1 + +#define WS_AUTHSERVICE_NAMESPACE "ns1" +#define WS_AUTHSERVICE_LOGINPROFILE_SOAP "SOAPAction: \"http://gamespy.net/AuthService/LoginProfile\"" +#define WS_AUTHSERVICE_LOGINUNIQUE_SOAP "SOAPAction: \"http://gamespy.net/AuthService/LoginUniqueNick\"" +#define WS_AUTHSERVICE_LOGINREMOTEAUTH_SOAP "SOAPAction: \"http://gamespy.net/AuthService/LoginRemoteAuth\"" +#define WS_AUTHSERVICE_LOGINPS3CERT_SOAP "SOAPAction: \"http://gamespy.net/AuthService/LoginPs3Cert\"" + +#define WS_AUTHSERVICE_NAMESPACE_COUNT 1 +const char * WS_AUTHSERVICE_NAMESPACES[WS_AUTHSERVICE_NAMESPACE_COUNT] = +{ + WS_AUTHSERVICE_NAMESPACE "=\"http://gamespy.net/AuthService/\"" +}; + +const char WS_AUTHSERVICE_SIGNATURE_KEY[] = + "BF05D63E93751AD4A59A4A7389CF0BE8" + "A22CCDEEA1E7F12C062D6E194472EFDA" + "5184CCECEB4FBADF5EB1D7ABFE911814" + "53972AA971F624AF9BA8F0F82E2869FB" + "7D44BDE8D56EE50977898F3FEE758696" + "22C4981F07506248BD3D092E8EA05C12" + "B2FA37881176084C8F8B8756C4722CDC" + "57D2AD28ACD3AD85934FB48D6B2D2027"; + +/* "D589F4433FAB2855F85A4EB40E6311F0" + "284C7882A72380938FD0C55CC1D65F7C" + "6EE79EDEF06C1AE5EDE139BDBBAB4219" + "B7D2A3F0AC3D3B23F59F580E0E89B9EC" + "787F2DD5A49788C633D5D3CE79438934" + "861EA68AE545D5BBCAAAD917CE9F5C7C" + "7D1452D9214F989861A7511097C35E60" + "A7273DECEA71CB5F8251653B26ACE781";*/ + + + +const char WS_AUTHSERVICE_SIGNATURE_EXP[] = + "010001"; + +// This is declared as an extern so it can be overriden when testing +#define WS_LOGIN_SERVICE_URL_FORMAT "https://%s.auth.pubsvs." GSI_DOMAIN_NAME "/AuthService/AuthService.asmx" +char wsAuthServiceURL[WS_LOGIN_MAX_URL_LEN] = ""; + +typedef struct WSIRequestData +{ + union + { + WSLoginCallback mLoginCallback; + WSLoginPs3CertCallback mLoginPs3CertCallback; + } mUserCallback; + //void * mUserCallback; + void * mUserData; +} WSIRequestData; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void wsiLoginEncryptPassword(const gsi_char * password, gsi_u8 ciphertext[GS_CRYPT_RSA_BYTE_SIZE]); +static gsi_bool wsiServiceAvailable(); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Checks to make sure the availability check has been performed prior +// to using any AuthService Login, and sets the service URL if it has +static gsi_bool wsiServiceAvailable() +{ + if (__GSIACResult == GSIACAvailable) + { + if (wsAuthServiceURL[0] == '\0') + snprintf(wsAuthServiceURL, WS_LOGIN_MAX_URL_LEN, WS_LOGIN_SERVICE_URL_FORMAT, __GSIACGamename); + return gsi_true; + } + else + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void wsiLoginProfileCallback(GHTTPResult theResult, + GSXmlStreamWriter theRequestXml, + GSXmlStreamReader theResponseXml, + void * theRequestData) +{ + GHTTPResult translatedResult = GHTTPSuccess; + WSIRequestData * requestData = (WSIRequestData*)theRequestData; + + WSLoginResponse response; + GSLoginCertificate * cert = &response.mCertificate; // for convenience + + // initialize local variables + cert->mIsValid = gsi_false; + memset(&response, 0, sizeof(response)); + + if (theResult == GHTTPSuccess) + { + // try to parse the soap + if (gsi_is_false(gsXmlMoveToStart(theResponseXml)) || + gsi_is_false(gsXmlMoveToNext(theResponseXml, "LoginProfileResult"))) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + // prepare response structure + if (gsi_is_false(gsXmlReadChildAsInt(theResponseXml, "responseCode", (int*)&response.mResponseCode))) + { + // could not parse login response code + response.mLoginResult = WSLogin_ParseError; + } + else if (response.mResponseCode != WSLogin_Success) + { + // server reported an error into reponseCode + response.mLoginResult = WSLogin_ServerError; + } + else if (gsi_is_false(gsXmlMoveToChild(theResponseXml, "certificate")) || + gsi_is_false(wsLoginCertReadXML(cert, theResponseXml)) || + gsi_is_false(gsXmlMoveToParent(theResponseXml)) || + gsi_is_false(gsXmlReadChildAsLargeInt(theResponseXml, "peerkeyprivate", + &response.mPrivateData.mPeerPrivateKey.exponent)) + ) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + MD5_CTX md5; + + // peer privatekey modulus is same as peer public key modulus + memcpy(&response.mPrivateData.mPeerPrivateKey.modulus, &cert->mPeerPublicKey.modulus, sizeof(cert->mPeerPublicKey.modulus)); + + // hash the private key + MD5Init(&md5); + //gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.modulus, &md5); + gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.exponent, &md5); + MD5Final((unsigned char*)response.mPrivateData.mKeyHash, &md5); + + // verify certificate + cert->mIsValid = wsLoginCertIsValid(cert); + if (gsi_is_false(cert->mIsValid)) + { + response.mLoginResult = WSLogin_InvalidCertificate; + } + } + } + } + else + { + response.mLoginResult = WSLogin_HttpError; + } + + // trigger the user callback + if (requestData->mUserCallback.mLoginCallback != NULL) + { + WSLoginCallback userCallback = (WSLoginCallback)(requestData->mUserCallback.mLoginCallback); + (userCallback)(translatedResult, &response, requestData->mUserData); + } + gsifree(requestData); + GSI_UNUSED(theRequestXml); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 wsLoginProfile(int partnerCode, + int namespaceId, + const gsi_char * profileNick, + const gsi_char * email, + const gsi_char * password, + const gsi_char * cdkey, + WSLoginCallback callback, + void * userData) +{ + GSXmlStreamWriter writer; + WSIRequestData * requestData = NULL; + gsi_u8 encryptedPassword[GS_CRYPT_RSA_BYTE_SIZE]; + + if (!wsiServiceAvailable()) + return WSLogin_NoAvailabilityCheck; + + GS_ASSERT(partnerCode >= 0); + GS_ASSERT(profileNick != NULL); + GS_ASSERT(email != NULL); + GS_ASSERT(password != NULL); + + if (_tcslen(profileNick) >= WS_LOGIN_NICK_LEN) + return WSLogin_InvalidParameters; + if (_tcslen(email) >= WS_LOGIN_EMAIL_LEN) + return WSLogin_InvalidParameters; + if (_tcslen(password) >= WS_LOGIN_PASSWORD_LEN) + return WSLogin_InvalidParameters; + if (cdkey != NULL && (_tcslen(cdkey) > WS_LOGIN_CDKEY_LEN)) + return WSLogin_InvalidParameters; + + // make a copy of the request callback and user param + requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData)); + if (requestData == NULL) + return WSLogin_OutOfMemory; + requestData->mUserCallback.mLoginCallback = callback; + requestData->mUserData = userData; + + // encrypt the password (includes safety padding and hash) + wsiLoginEncryptPassword(password, encryptedPassword); + + writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT); + if (writer != NULL) + { + GSSoapTask * aTask = NULL; + + if (gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINPROFILE)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) || + gsi_is_false(gsXmlWriteAsciiStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "email", email)) || + gsi_is_false(gsXmlWriteAsciiStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "profilenick", profileNick)) || + gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, "password")) || + gsi_is_false(gsXmlWriteHexBinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", encryptedPassword, GS_CRYPT_RSA_BYTE_SIZE)) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, "password")) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINPROFILE)) || + gsi_is_false(gsXmlCloseWriter (writer)) + ) + { + gsXmlFreeWriter(writer); + return WSLogin_OutOfMemory; + } + + aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINPROFILE_SOAP, + writer, wsiLoginProfileCallback, (void*)requestData); + if (aTask == NULL) + { + gsXmlFreeWriter(writer); + gsifree(requestData); + return WSLogin_OutOfMemory; + } + } + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void wsLoginUniqueCallback(GHTTPResult theResult, + GSXmlStreamWriter theRequestXml, + GSXmlStreamReader theResponseXml, + void * theRequestData) +{ + GHTTPResult translatedResult = theResult; + WSIRequestData * requestData = (WSIRequestData*)theRequestData; + + WSLoginResponse response; + GSLoginCertificate * cert = &response.mCertificate; // for convenience + cert->mIsValid = gsi_false; + + memset(&response, 0, sizeof(response)); + + if (theResult == GHTTPSuccess) + { + // try to parse the soap + if (gsi_is_false(gsXmlMoveToStart(theResponseXml)) || + gsi_is_false(gsXmlMoveToNext(theResponseXml, "LoginUniqueNickResult"))) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + // prepare response structure + if (gsi_is_false(gsXmlReadChildAsInt(theResponseXml, "responseCode", (int*)&response.mResponseCode))) + { + // could not parse login response code + response.mLoginResult = WSLogin_ParseError; + } + else if (response.mResponseCode != WSLogin_Success) + { + // server reported an error into reponseCode + response.mLoginResult = WSLogin_ServerError; + } + else if (gsi_is_false(gsXmlMoveToChild(theResponseXml, "certificate")) || + gsi_is_false(wsLoginCertReadXML(cert, theResponseXml)) || + gsi_is_false(gsXmlMoveToParent(theResponseXml)) || + gsi_is_false(gsXmlReadChildAsLargeInt(theResponseXml, "peerkeyprivate", + &response.mPrivateData.mPeerPrivateKey.exponent)) + ) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + MD5_CTX md5; + + // peer privatekey modulus is same as peer public key modulus + memcpy(&response.mPrivateData.mPeerPrivateKey.modulus, &cert->mPeerPublicKey.modulus, sizeof(cert->mPeerPublicKey.modulus)); + + // hash the private key + // -- we use the has like a password for simple authentication + MD5Init(&md5); + //gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.modulus, &md5); + gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.exponent, &md5); + MD5Final((unsigned char*)response.mPrivateData.mKeyHash, &md5); + + // verify certificate + cert->mIsValid = wsLoginCertIsValid(cert); + if (gsi_is_false(cert->mIsValid)) + { + response.mLoginResult = WSLogin_InvalidCertificate; + } + } + } + } + else if (theResult == GHTTPRequestCancelled) + { + response.mLoginResult = WSLogin_Cancelled; + } + else + { + response.mLoginResult = WSLogin_HttpError; + } + + // trigger the user callback + if (requestData->mUserCallback.mLoginCallback != NULL) + { + WSLoginCallback userCallback = (WSLoginCallback)(requestData->mUserCallback.mLoginCallback); + (userCallback)(translatedResult, &response, requestData->mUserData); + } + gsifree(requestData); + GSI_UNUSED(theRequestXml); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//gsi_u32 wsLoginUnique(WSLoginUniqueRequest * request, WSLoginCallback callback) +gsi_u32 wsLoginUnique(int partnerCode, + int namespaceId, + const gsi_char * uniqueNick, + const gsi_char * password, + const gsi_char * cdkey, + WSLoginCallback userCallback, + void * userData) +{ + GSXmlStreamWriter writer; + WSIRequestData * requestData = NULL; + gsi_u8 encryptedPassword[GS_CRYPT_RSA_BYTE_SIZE]; + + if (!wsiServiceAvailable()) + return WSLogin_NoAvailabilityCheck; + + GS_ASSERT(partnerCode >= 0); + GS_ASSERT(uniqueNick != NULL); + GS_ASSERT(password != NULL); + + if (_tcslen(uniqueNick) >= WS_LOGIN_UNIQUENICK_LEN) + return WSLogin_InvalidParameters; + if (_tcslen(password) >= WS_LOGIN_PASSWORD_LEN) + return WSLogin_InvalidParameters; + if (cdkey != NULL && (_tcslen(cdkey) >= WS_LOGIN_CDKEY_LEN)) + return WSLogin_InvalidParameters; + + // allocate the request values + requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData)); + if (requestData == NULL) + return WSLogin_OutOfMemory; + requestData->mUserCallback.mLoginCallback = userCallback; + requestData->mUserData = userData; + + // encrypt the password (includes safety padding and hash) + wsiLoginEncryptPassword(password, encryptedPassword); + + // create the xml request + writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT); + if (writer != NULL) + { + GSSoapTask * aTask = NULL; + + if (gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINUNIQUE)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) || + gsi_is_false(gsXmlWriteAsciiStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "uniquenick", uniqueNick)) || + gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, "password")) || + gsi_is_false(gsXmlWriteHexBinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", encryptedPassword, GS_CRYPT_RSA_BYTE_SIZE)) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, "password")) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINUNIQUE)) || + gsi_is_false(gsXmlCloseWriter (writer)) + ) + { + gsXmlFreeWriter(writer); + return WSLogin_OutOfMemory; + } + + aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINUNIQUE_SOAP, + writer, wsLoginUniqueCallback, (void*)requestData); + if (aTask == NULL) + { + gsXmlFreeWriter(writer); + gsifree(requestData); + return WSLogin_OutOfMemory; + } + } + return 0; +} + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void wsLoginRemoteAuthCallback(GHTTPResult theResult, + GSXmlStreamWriter theRequestXml, + GSXmlStreamReader theResponseXml, + void * theRequestData) +{ + GHTTPResult translatedResult = theResult; + WSIRequestData * requestData = (WSIRequestData*)theRequestData; + + WSLoginResponse response; + GSLoginCertificate * cert = &response.mCertificate; // for convenience + cert->mIsValid = gsi_false; + + memset(&response, 0, sizeof(response)); + + if (theResult == GHTTPSuccess) + { + // try to parse the soap + if (gsi_is_false(gsXmlMoveToStart(theResponseXml)) || + gsi_is_false(gsXmlMoveToNext(theResponseXml, "LoginRemoteAuthResult"))) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + // prepare response structure + if (gsi_is_false(gsXmlReadChildAsInt(theResponseXml, "responseCode", (int*)&response.mResponseCode))) + { + // could not parse login response code + response.mLoginResult = WSLogin_ParseError; + } + else if (response.mResponseCode != WSLogin_Success) + { + // server reported an error into reponseCode + response.mLoginResult = WSLogin_ServerError; + } + else if (gsi_is_false(gsXmlMoveToChild(theResponseXml, "certificate")) || + gsi_is_false(wsLoginCertReadXML(cert, theResponseXml)) || + gsi_is_false(gsXmlMoveToParent(theResponseXml)) || + gsi_is_false(gsXmlReadChildAsLargeInt(theResponseXml, "peerkeyprivate", + &response.mPrivateData.mPeerPrivateKey.exponent)) + ) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + MD5_CTX md5; + + // peer privatekey modulus is same as peer public key modulus + memcpy(&response.mPrivateData.mPeerPrivateKey.modulus, &cert->mPeerPublicKey.modulus, sizeof(cert->mPeerPublicKey.modulus)); + + // hash the private key + // -- we use the has like a password for simple authentication + MD5Init(&md5); + //gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.modulus, &md5); + gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.exponent, &md5); + MD5Final((unsigned char*)response.mPrivateData.mKeyHash, &md5); + + // verify certificate + cert->mIsValid = wsLoginCertIsValid(cert); + if (gsi_is_false(cert->mIsValid)) + { + response.mLoginResult = WSLogin_InvalidCertificate; + } + } + } + } + else if (theResult == GHTTPRequestCancelled) + { + response.mLoginResult = WSLogin_Cancelled; + } + else + { + response.mLoginResult = WSLogin_HttpError; + } + + // trigger the user callback + if (requestData->mUserCallback.mLoginCallback != NULL) + { + WSLoginCallback userCallback = (WSLoginCallback)(requestData->mUserCallback.mLoginCallback); + (userCallback)(translatedResult, &response, requestData->mUserData); + } + gsifree(requestData); + GSI_UNUSED(theRequestXml); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_u32 wsLoginRemoteAuth(int partnerCode, + int namespaceId, + const gsi_char authtoken[WS_LOGIN_AUTHTOKEN_LEN], + const gsi_char partnerChallenge[WS_LOGIN_PARTNERCHALLENGE_LEN], + WSLoginCallback userCallback, + void * userData) +{ + GSXmlStreamWriter writer; + WSIRequestData * requestData = NULL; + //gsi_u8 encryptedChallenge[GS_CRYPT_RSA_BYTE_SIZE]; + + if (!wsiServiceAvailable()) + return WSLogin_NoAvailabilityCheck; + + GS_ASSERT(partnerCode >= 0); + + // allocate the request values + requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData)); + if (requestData == NULL) + return WSLogin_OutOfMemory; + requestData->mUserCallback.mLoginCallback = userCallback; + requestData->mUserData = userData; + + // encrypt the password (includes safety padding and hash) + //wsiLoginEncryptPassword(partnerChallenge, encryptedChallenge); + + // create the xml request + writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT); + if (writer != NULL) + { + GSSoapTask * aTask = NULL; + + if (gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINREMOTEAUTH)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) || + gsi_is_false(gsXmlWriteTStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "authtoken", authtoken)) || + gsi_is_false(gsXmlWriteTStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "challenge", partnerChallenge)) || + //gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, "challenge")) || + //gsi_is_false(gsXmlWriteHexBinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", encryptedChallenge, GS_CRYPT_RSA_BYTE_SIZE)) || + //gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, "challenge")) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINREMOTEAUTH)) || + gsi_is_false(gsXmlCloseWriter (writer)) + ) + { + gsXmlFreeWriter(writer); + return WSLogin_OutOfMemory; + } + + aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINREMOTEAUTH_SOAP, + writer, wsLoginRemoteAuthCallback, (void*)requestData); + if (aTask == NULL) + { + gsXmlFreeWriter(writer); + gsifree(requestData); + return WSLogin_OutOfMemory; + } + } + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void wsLoginPs3CertCallback(GHTTPResult theResult, + GSXmlStreamWriter theRequestXml, + GSXmlStreamReader theResponseXml, + void * theRequestData) +{ + + GHTTPResult translatedResult = theResult; + WSIRequestData * requestData = (WSIRequestData*)theRequestData; + + WSLoginPs3CertResponse response; + memset(&response, 0, sizeof(response)); + + if (theResult == GHTTPSuccess) + { + // try to parse the soap + if (gsi_is_false(gsXmlMoveToStart(theResponseXml)) || + gsi_is_false(gsXmlMoveToNext(theResponseXml, "LoginPs3CertResult"))) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + // prepare response structure + if (gsi_is_false(gsXmlReadChildAsInt(theResponseXml, "responseCode", (int*)&response.mResponseCode))) + { + // could not parse login response code + response.mLoginResult = WSLogin_ParseError; + } + else if (response.mResponseCode != WSLogin_Success) + { + // server reported an error into reponseCode + response.mLoginResult = WSLogin_ServerError; + } + else + { + const char * tokenStr = NULL; + const char * challengeStr = NULL; + int tokenLen = 0; + int challengeLen = 0; + + // Check length of token+challenge, then read into memory + if ( //gsi_is_false(gsXmlReadChildAsBase64Binary(theResponseXml, "authToken", NULL, &tokenLen)) || + //gsi_is_false(gsXmlReadChildAsBase64Binary(theResponseXml, "partnerChallenge", NULL, &challengeLen)) || + //(tokenLen > WS_LOGIN_AUTHTOKEN_LEN || challengeLen > WS_LOGIN_PARTNERCHALLENGE_LEN) || + gsi_is_false(gsXmlReadChildAsString(theResponseXml, "authToken", &tokenStr, &tokenLen)) || + gsi_is_false(gsXmlReadChildAsString(theResponseXml, "partnerChallenge", &challengeStr, &challengeLen)) || + (tokenLen >= WS_LOGIN_AUTHTOKEN_LEN || challengeLen >= WS_LOGIN_PARTNERCHALLENGE_LEN) ) + { + response.mLoginResult = WSLogin_ParseError; + } + else + { + memcpy(response.mRemoteAuthToken, tokenStr, (gsi_u32)tokenLen); + memcpy(response.mPartnerChallenge, challengeStr, (gsi_u32)challengeLen); + response.mRemoteAuthToken[tokenLen] = '\0'; + response.mPartnerChallenge[challengeLen] = '\0'; + } + } + } + } + else if (theResult == GHTTPRequestCancelled) + { + response.mLoginResult = WSLogin_Cancelled; + } + else + { + response.mLoginResult = WSLogin_HttpError; + } + + // trigger the user callback + if (requestData->mUserCallback.mLoginPs3CertCallback != NULL) + { + WSLoginPs3CertCallback userCallback = (WSLoginPs3CertCallback)(requestData->mUserCallback.mLoginPs3CertCallback); + (userCallback)(translatedResult, &response, requestData->mUserData); + } + gsifree(requestData); + GSI_UNUSED(theRequestXml); +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//gsi_u32 wsLoginUnique(WSLoginUniqueRequest * request, WSLoginCallback callback) +gsi_u32 wsLoginPs3Cert(int gameId, + int partnerCode, + int namespaceId, + const gsi_u8 * ps3cert, + int certLen, + WSLoginPs3CertCallback userCallback, + void * userData) +{ + GSXmlStreamWriter writer; + WSIRequestData * requestData = NULL; + + if (!wsiServiceAvailable()) + return WSLogin_NoAvailabilityCheck; + + GS_ASSERT(partnerCode >= 0); + GS_ASSERT(ps3cert != NULL); + + + // Version check, todo: use something better than length + //if (certLen != 248) + // return WSLogin_InvalidParameters; + + // allocate the request values + requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData)); + if (requestData == NULL) + return WSLogin_OutOfMemory; + + requestData->mUserCallback.mLoginPs3CertCallback = userCallback; + requestData->mUserData = userData; + + // create the xml request + writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT); + if (writer != NULL) + { + GSSoapTask * aTask = NULL; + + if (gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINPS3CERT)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "gameid", (gsi_u32)gameId)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) || + gsi_is_false(gsXmlWriteIntElement (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) || + gsi_is_false(gsXmlWriteOpenTag (writer, WS_AUTHSERVICE_NAMESPACE, "npticket")) || + gsi_is_false(gsXmlWriteBase64BinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", ps3cert, certLen)) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, "npticket")) || + gsi_is_false(gsXmlWriteCloseTag (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINPS3CERT)) || + gsi_is_false(gsXmlCloseWriter (writer)) + ) + { + gsXmlFreeWriter(writer); + return WSLogin_OutOfMemory; + } + + aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINPS3CERT_SOAP, + writer, wsLoginPs3CertCallback, (void*)requestData); + if (aTask == NULL) + { + gsXmlFreeWriter(writer); + gsifree(requestData); + return WSLogin_OutOfMemory; + } + } + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static void wsiLoginEncryptPassword(const gsi_char * password, gsi_u8 ciphertext[GS_CRYPT_RSA_BYTE_SIZE]) +{ + gsCryptRSAKey sigkeypub; + + +#ifdef GSI_UNICODE + char password_A[WS_LOGIN_PASSWORD_LEN]; + // strip password into ascii to encrypt + UCS2ToAsciiString(password, password_A); +#endif + + gsLargeIntSetFromHexString(&sigkeypub.modulus, WS_AUTHSERVICE_SIGNATURE_KEY); + gsLargeIntSetFromHexString(&sigkeypub.exponent, WS_AUTHSERVICE_SIGNATURE_EXP); + +#ifdef GSI_UNICODE + gsCryptRSAEncryptBuffer(&sigkeypub, (const gsi_u8*)password_A, _tcslen(password), ciphertext); +#else + gsCryptRSAEncryptBuffer(&sigkeypub, (const gsi_u8*)password, strlen(password), ciphertext); +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +static gsi_u32 wsiMakeLittleEndian32(gsi_u32 num) +{ +#if defined(GSI_BIG_ENDIAN) + num = gsiByteOrderSwap32(num); +#endif + return num; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool wsLoginCertIsValid(const GSLoginCertificate * cert) +{ + // Verify the signature + gsCryptRSAKey sigkeypub; + MD5_CTX md5; + gsi_u8 hash[16]; + gsi_i32 cryptResult = 0; + gsi_u32 temp; + + // hash certificate data + MD5Init(&md5); + temp = wsiMakeLittleEndian32(cert->mLength); + MD5Update(&md5, (unsigned char*)&temp, 4); + temp = wsiMakeLittleEndian32(cert->mVersion); + MD5Update(&md5, (unsigned char*)&temp, 4); + temp = wsiMakeLittleEndian32(cert->mPartnerCode); + MD5Update(&md5, (unsigned char*)&temp, 4); + temp = wsiMakeLittleEndian32(cert->mNamespaceId); + MD5Update(&md5, (unsigned char*)&temp, 4); + temp = wsiMakeLittleEndian32(cert->mUserId); + MD5Update(&md5, (unsigned char*)&temp, 4); + temp = wsiMakeLittleEndian32(cert->mProfileId); + MD5Update(&md5, (unsigned char*)&temp, 4); + temp = wsiMakeLittleEndian32(cert->mExpireTime); + MD5Update(&md5, (unsigned char*)&temp, 4); + +#if defined(GSI_UNICODE) + { + char profile_A[WS_LOGIN_NICK_LEN]; + char uniquenick_A[WS_LOGIN_UNIQUENICK_LEN]; + char keyhash_A[WS_LOGIN_KEYHASH_LEN]; + + UCS2ToAsciiString(cert->mProfileNick, profile_A); + UCS2ToAsciiString(cert->mUniqueNick, uniquenick_A); + UCS2ToAsciiString(cert->mCdKeyHash, keyhash_A); + + MD5Update(&md5, (unsigned char*)profile_A, strlen(profile_A)); //FIX for unicode + MD5Update(&md5, (unsigned char*)uniquenick_A, strlen(uniquenick_A)); //FIX for unicode + MD5Update(&md5, (unsigned char*)keyhash_A, strlen(keyhash_A)); //FIX for unicode + } +#else + MD5Update(&md5, (unsigned char*)&cert->mProfileNick, strlen(cert->mProfileNick)); + MD5Update(&md5, (unsigned char*)&cert->mUniqueNick, strlen(cert->mUniqueNick)); + MD5Update(&md5, (unsigned char*)&cert->mCdKeyHash, strlen(cert->mCdKeyHash)); +#endif + + // must be hashed in big endian byte order + // skip leading zeroes + gsLargeIntAddToMD5(&cert->mPeerPublicKey.modulus, &md5); + gsLargeIntAddToMD5(&cert->mPeerPublicKey.exponent, &md5); + + MD5Update(&md5, (unsigned char*)&cert->mServerData, WS_LOGIN_SERVERDATA_LEN); + MD5Final(hash, &md5); + + gsLargeIntSetFromHexString(&sigkeypub.modulus, WS_AUTHSERVICE_SIGNATURE_KEY); + gsLargeIntSetFromHexString(&sigkeypub.exponent, WS_AUTHSERVICE_SIGNATURE_EXP); + cryptResult = gsCryptRSAVerifySignedHash(&sigkeypub, hash, 16, cert->mSignature, WS_LOGIN_SIGNATURE_LEN); + if (cryptResult == 0) + return gsi_true; + else + return gsi_false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Utility to write a certificate in binary form, does it really belong in this file? +#define WRITE_NETWORK_INT(a) { \ + intNB = (gsi_i32)htonl(a); \ + if(lenoutSoFar + sizeof(intNB) > maxlen) \ + return gsi_false; \ + memcpy(bufout+lenoutSoFar, &intNB, sizeof(intNB)); \ + lenoutSoFar += sizeof(intNB); } +#define WRITE_NTS(a) { \ + if(lenoutSoFar + _tcslen(a) > maxlen) \ + return gsi_false; \ + strcpy(bufout+lenoutSoFar, a); \ + lenoutSoFar += _tcslen(a) + 1; } + +#define WRITE_BINARY(a,l) { \ + if(lenoutSoFar + l > maxlen) \ + return gsi_false; \ + memcpy(bufout+lenoutSoFar, a, l); \ + lenoutSoFar += l; } + +#define WRITE_REV_BINARY(a,l) { \ + int i=(gsi_i32)l; \ + const char * readPos = ((char*)a)+i-1; \ + if (lenoutSoFar + l > maxlen) \ + return gsi_false; \ + while(i > 0) \ + { \ + *(bufout+lenoutSoFar) = *readPos; \ + readPos--; lenoutSoFar++; i--; \ + }; \ + } + +gsi_bool wsLoginCertWriteBinary(const GSLoginCertificate * cert, char * bufout, unsigned int maxlen, unsigned int * lenout) +{ + gsi_i32 intNB; // network byte order int + gsi_i32 lenoutSoFar = 0; // tracks bytes written to bufout + gsi_i32 lenTemp = 0; // for temp length of large ints + + + WRITE_NETWORK_INT(cert->mLength); + WRITE_NETWORK_INT(cert->mVersion); + WRITE_NETWORK_INT(cert->mPartnerCode); + WRITE_NETWORK_INT(cert->mNamespaceId); + WRITE_NETWORK_INT(cert->mUserId); + WRITE_NETWORK_INT(cert->mProfileId); + WRITE_NETWORK_INT(cert->mExpireTime); + +#ifndef GSI_UNICODE + WRITE_NTS(cert->mProfileNick); + WRITE_NTS(cert->mUniqueNick); + WRITE_NTS(cert->mCdKeyHash); +#else + if((lenoutSoFar + _tcslen(cert->mProfileNick) + _tcslen(cert->mUniqueNick) + _tcslen(cert->mCdKeyHash)) > maxlen) + return gsi_false; + // strip unicode to Ascii before writing this to the buffer + lenoutSoFar += UCS2ToAsciiString(cert->mProfileNick, bufout+lenoutSoFar)+1; + lenoutSoFar += UCS2ToAsciiString(cert->mUniqueNick, bufout+lenoutSoFar)+1; + lenoutSoFar += UCS2ToAsciiString(cert->mCdKeyHash, bufout+lenoutSoFar)+1; +#endif + + lenTemp = (gsi_i32)gsLargeIntGetByteLength(&cert->mPeerPublicKey.modulus); // size in bytes, no leading zeroes + WRITE_NETWORK_INT(lenTemp); + WRITE_REV_BINARY(cert->mPeerPublicKey.modulus.mData, (unsigned int)lenTemp); + + lenTemp = (gsi_i32)gsLargeIntGetByteLength(&cert->mPeerPublicKey.exponent); // size in bytes, no leading zeroes + WRITE_NETWORK_INT(lenTemp); + WRITE_REV_BINARY(cert->mPeerPublicKey.exponent.mData, (unsigned int)lenTemp); + + WRITE_NETWORK_INT(WS_LOGIN_SERVERDATA_LEN); + WRITE_BINARY(cert->mServerData, (unsigned int)WS_LOGIN_SERVERDATA_LEN); + + WRITE_NETWORK_INT(GS_CRYPT_RSA_BYTE_SIZE); + WRITE_BINARY(cert->mSignature, (unsigned int)WS_LOGIN_SERVERDATA_LEN); + + *lenout = (gsi_u32)lenoutSoFar; + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Utility to read the binary certificate + +// each read macro first clears the buffer (a) before writing +#define READ_NTOH_INT(a) { \ + gsi_i32 temp; \ + memset(&a, 0, sizeof(a)); \ + memcpy(&temp, bufin, sizeof(gsi_i32)); \ + intHB = (gsi_u32)ntohl(temp); \ + memcpy(&a, &intHB, sizeof(intHB)); \ + if(lenoutSoFar + sizeof(intHB) > maxlen) \ + return gsi_false; \ + bufin += sizeof(gsi_u32); \ + lenoutSoFar += sizeof(intHB); } +#define READ_NTS(a,l) { \ + memset(&a, 0, sizeof(a)); \ + _tcsncpy(a, bufin, l); \ + if(lenoutSoFar + _tcslen(a)+1 > maxlen) \ + return gsi_false; \ + bufin += _tcslen(a)+1; \ + lenoutSoFar += _tcslen(a)+1; } + +#define READ_ASCII(a,l) { \ + char temp[l]; \ + memset(&a, 0, sizeof(a)); \ + strncpy(temp, bufin, l); \ + AsciiToUCS2String(temp, a); \ + if(lenoutSoFar + _tcslen(a)+1 > maxlen) \ + return gsi_false; \ + bufin += _tcslen(a)+1; \ + lenoutSoFar += _tcslen(a)+1; } + + +#define READ_BINARY(a,l) { \ + int index = 0; \ + memset(&a, 0, sizeof(a)); \ + if(lenoutSoFar + l > maxlen) \ + return gsi_false; \ + memcpy(a+index, bufin, l); \ + lenoutSoFar += l; \ + bufin += l; } + +#define READ_REV_BINARY_TO_INT(a,l) { \ + int i=(gsi_i32)l; \ + int index = 0; \ + char temp[4]; \ + const char * readPos = bufin+i-1; \ + memset(&a, 0, sizeof(a)); \ + if (lenoutSoFar + l > maxlen) \ + return gsi_false; \ + while(i > 0) \ + { \ + temp[index%4] = *readPos; \ + if (index%4 == 3) \ + memcpy(a+(index/4), temp, 4); \ + else if (index == (gsi_i32)l-1) \ + memcpy(a+(index/4), temp, l); \ + readPos--; index++; lenoutSoFar++; i--; \ + }; \ + bufin += l; } + + + + +gsi_bool wsLoginCertReadBinary(GSLoginCertificate * certOut, char * bufin, unsigned int maxlen) +{ + gsi_u32 intHB; // host byte order int + gsi_u32 lenoutSoFar = 0; // tracks bufin index to make sure we dont exceed the maxlen + gsi_u32 lenTemp = 0; // for temp length of large ints + + + READ_NTOH_INT(certOut->mLength); + READ_NTOH_INT(certOut->mVersion); + READ_NTOH_INT(certOut->mPartnerCode); + READ_NTOH_INT(certOut->mNamespaceId); + READ_NTOH_INT(certOut->mUserId); + READ_NTOH_INT(certOut->mProfileId); + READ_NTOH_INT(certOut->mExpireTime); + +#ifndef GSI_UNICODE + + READ_NTS(certOut->mProfileNick, WS_LOGIN_NICK_LEN); + READ_NTS(certOut->mUniqueNick, WS_LOGIN_UNIQUENICK_LEN); + READ_NTS(certOut->mCdKeyHash, WS_LOGIN_CDKEY_LEN); +#else + + // parses ascii to unicode before writing into the buffer + READ_ASCII(certOut->mProfileNick, WS_LOGIN_NICK_LEN); + READ_ASCII(certOut->mUniqueNick, WS_LOGIN_UNIQUENICK_LEN); + READ_ASCII(certOut->mCdKeyHash, WS_LOGIN_CDKEY_LEN); +#endif + + READ_NTOH_INT(lenTemp); //size of the modulus data in bytes + // now calculate the length in int's + certOut->mPeerPublicKey.modulus.mLength = (lenTemp / GS_LARGEINT_DIGIT_SIZE_BYTES); + if (lenTemp % GS_LARGEINT_DIGIT_SIZE_BYTES != 0) + certOut->mPeerPublicKey.modulus.mLength++; + + READ_REV_BINARY_TO_INT(certOut->mPeerPublicKey.modulus.mData, lenTemp); + + READ_NTOH_INT(lenTemp); //size of the exponent data in bytes + // now calculate the length in int's + certOut->mPeerPublicKey.exponent.mLength = (lenTemp / GS_LARGEINT_DIGIT_SIZE_BYTES); + if (lenTemp % GS_LARGEINT_DIGIT_SIZE_BYTES != 0) + certOut->mPeerPublicKey.exponent.mLength++; + + READ_REV_BINARY_TO_INT(certOut->mPeerPublicKey.exponent.mData, lenTemp); + + bufin += sizeof(gsi_u32); //skip the prepended length + READ_BINARY(certOut->mServerData, (unsigned int)WS_LOGIN_SERVERDATA_LEN); + + bufin += sizeof(gsi_u32); //skip the prepended length + READ_BINARY(certOut->mSignature, (unsigned int)WS_LOGIN_SERVERDATA_LEN); + + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool wsLoginCertWriteXML(const GSLoginCertificate * cert, const char * aNamespace, GSXmlStreamWriter writer) +{ + GS_ASSERT(cert != NULL); + GS_ASSERT(writer != NULL); + + if (gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "length", cert->mLength)) || + gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "version", cert->mVersion)) || + gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "partnercode", cert->mPartnerCode)) || + gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "namespaceid", cert->mNamespaceId)) || + gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "userid", cert->mUserId)) || + gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "profileid", cert->mProfileId)) || + gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "expiretime", cert->mExpireTime)) || + gsi_is_false(gsXmlWriteAsciiStringElement(writer, aNamespace, "profilenick", cert->mProfileNick))|| + gsi_is_false(gsXmlWriteAsciiStringElement(writer, aNamespace, "uniquenick", cert->mUniqueNick)) || + gsi_is_false(gsXmlWriteAsciiStringElement(writer, aNamespace, "cdkeyhash", cert->mCdKeyHash)) || + gsi_is_false(gsXmlWriteLargeIntElement(writer, aNamespace, "peerkeymodulus", &cert->mPeerPublicKey.modulus)) || + gsi_is_false(gsXmlWriteLargeIntElement(writer, aNamespace, "peerkeyexponent", &cert->mPeerPublicKey.exponent)) || + gsi_is_false(gsXmlWriteHexBinaryElement(writer, aNamespace, "serverdata", cert->mServerData, WS_LOGIN_SERVERDATA_LEN)) || + gsi_is_false(gsXmlWriteHexBinaryElement(writer, aNamespace, "signature", cert->mSignature, WS_LOGIN_SIGNATURE_LEN)) + ) + { + //gsLargeIntReverseBytes(&cert->mPeerPublicKey.modulus); + //gsLargeIntReverseBytes(&cert->mPeerPublicKey.exponent); + return gsi_false; + } + + //gsLargeIntReverseBytes(&cert->mPeerPublicKey.modulus); + //gsLargeIntReverseBytes(&cert->mPeerPublicKey.exponent); + return gsi_true; +} + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +gsi_bool wsLoginCertReadXML(GSLoginCertificate * cert, GSXmlStreamReader reader) +{ + char hexstr[GS_CRYPT_RSA_BYTE_SIZE*2 +1]; // temp storage for key hex strings + int hexlen; + + GS_ASSERT(cert != NULL); + GS_ASSERT(reader != NULL); + + if (gsi_is_false(gsXmlReadChildAsInt (reader, "length", (int*)&cert->mLength)) || + gsi_is_false(gsXmlReadChildAsInt (reader, "version", (int*)&cert->mVersion)) || + gsi_is_false(gsXmlReadChildAsInt (reader, "partnercode",(int*)&cert->mPartnerCode)) || + gsi_is_false(gsXmlReadChildAsInt (reader, "namespaceid",(int*)&cert->mNamespaceId)) || + gsi_is_false(gsXmlReadChildAsInt (reader, "userid", (int*)&cert->mUserId)) || + gsi_is_false(gsXmlReadChildAsInt (reader, "profileid", (int*)&cert->mProfileId)) || + gsi_is_false(gsXmlReadChildAsInt (reader, "expiretime", (int*)&cert->mExpireTime)) || + gsi_is_false(gsXmlReadChildAsTStringNT (reader, "profilenick", cert->mProfileNick, WS_LOGIN_NICK_LEN)) || + gsi_is_false(gsXmlReadChildAsTStringNT (reader, "uniquenick", cert->mUniqueNick, WS_LOGIN_UNIQUENICK_LEN)) || + gsi_is_false(gsXmlReadChildAsTStringNT (reader, "cdkeyhash", cert->mCdKeyHash, WS_LOGIN_KEYHASH_LEN)) || + + gsi_is_false(gsXmlReadChildAsStringNT (reader, "peerkeymodulus", hexstr, GS_CRYPT_RSA_BYTE_SIZE*2 +1)) || + gsi_is_false(gsLargeIntSetFromHexString(&cert->mPeerPublicKey.modulus, hexstr)) || + + gsi_is_false(gsXmlReadChildAsStringNT (reader, "peerkeyexponent", hexstr, GS_CRYPT_RSA_BYTE_SIZE*2 +1)) || + gsi_is_false(gsLargeIntSetFromHexString(&cert->mPeerPublicKey.exponent, hexstr)) || + + gsi_is_false(gsXmlReadChildAsHexBinary(reader, "serverdata", cert->mServerData, WS_LOGIN_SERVERDATA_LEN, &hexlen)) || + + gsi_is_false(gsXmlReadChildAsHexBinary(reader, "signature", cert->mSignature, WS_LOGIN_SIGNATURE_LEN, &hexlen)) + ) + { + return gsi_false; + } + return gsi_true; +} + +#pragma warning(default: 4267) \ No newline at end of file diff --git a/xrGameSpy/gamespy/webservices/AuthService.h b/xrGameSpy/gamespy/webservices/AuthService.h new file mode 100644 index 00000000000..dc99d619502 --- /dev/null +++ b/xrGameSpy/gamespy/webservices/AuthService.h @@ -0,0 +1,199 @@ +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#ifndef __AUTHSERVICE_H__ +#define __AUTHSERVICE_H__ + + +// ***** Authentication web services. +// +// ***** PUBLIC INTERFACE AT THE BOTTOM OF THE FILE + +#include "../common/gsSoap.h" +#include "../common/gsCrypt.h" +#include "../common/gsLargeInt.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// URL for sc services. +#define WS_LOGIN_MAX_URL_LEN (128) +extern char wsAuthServiceURL[WS_LOGIN_MAX_URL_LEN]; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define WSLogin_PARTNERCODE_GAMESPY 0 +#define WSLogin_NAMESPACE_SHARED_NONUNIQUE 0 +#define WSLogin_NAMESPACE_SHARED_UNIQUE 1 + +typedef enum WSLoginValue +{ + // Login response code (mResponseCode) + // -- GameSpy Devs: Must match server + WSLogin_Success = 0, + WSLogin_ServerInitFailed, + + WSLogin_UserNotFound, + WSLogin_InvalidPassword, + WSLogin_InvalidProfile, + WSLogin_UniqueNickExpired, + + WSLogin_DBError, + WSLogin_ServerError, + WSLogin_FailureMax, // must be the last failure + + // Login result (mLoginResult) + WSLogin_HttpError = 100, // ghttp reported an error, response ignored + WSLogin_ParseError, // couldn't parse http response + WSLogin_InvalidCertificate, // login success but certificate was invalid! + WSLogin_LoginFailed, // failed login or other error condition + WSLogin_OutOfMemory, // could not process due to insufficient memory + WSLogin_InvalidParameters, // check the function arguments + WSLogin_NoAvailabilityCheck,// No availability check was performed + WSLogin_Cancelled, // login request was cancelled + WSLogin_UnknownError // error occured, but detailed information not available + +} WSLoginValue; + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#define WS_LOGIN_SIGKEY_LEN_BITS (GS_CRYPT_RSA_BINARY_SIZE) +#define WS_LOGIN_PEERKEY_LEN_BITS (GS_CRYPT_RSA_BINARY_SIZE) + +#define WS_LOGIN_NICK_LEN (30+1) +#define WS_LOGIN_EMAIL_LEN (50+1) +#define WS_LOGIN_PASSWORD_LEN (30+1) +#define WS_LOGIN_UNIQUENICK_LEN (20+1) +#define WS_LOGIN_CDKEY_LEN (64+1) +#define WS_LOGIN_PEERKEYMOD_LEN (WS_LOGIN_PEERKEY_LEN_BITS/8) +#define WS_LOGIN_PEERKEYEXP_LEN (WS_LOGIN_PEERKEY_LEN_BITS/8) +#define WS_LOGIN_PEERKEYPRV_LEN (WS_LOGIN_PEERKEY_LEN_BITS/8) +#define WS_LOGIN_KEYHASH_LEN (33) // 16 byte hash in hexstr +1 for NULL +#define WS_LOGIN_SIGNATURE_LEN (WS_LOGIN_SIGKEY_LEN_BITS/8) +#define WS_LOGIN_SERVERDATA_LEN (WS_LOGIN_PEERKEY_LEN_BITS/8) +#define WS_LOGIN_AUTHTOKEN_LEN (256) +#define WS_LOGIN_PARTNERCHALLENGE_LEN (256) + +// A user's login certificate, signed by the GameSpy AuthService +// The certificate is public and may be freely passed around +// Avoid use of pointer members so that structure may be easily copied +typedef struct GSLoginCertificate +{ + gsi_bool mIsValid; + + gsi_u32 mLength; + gsi_u32 mVersion; + gsi_u32 mPartnerCode; // aka Account space + gsi_u32 mNamespaceId; + gsi_u32 mUserId; + gsi_u32 mProfileId; + gsi_u32 mExpireTime; + gsi_char mProfileNick[WS_LOGIN_NICK_LEN]; + gsi_char mUniqueNick[WS_LOGIN_UNIQUENICK_LEN]; + gsi_char mCdKeyHash[WS_LOGIN_KEYHASH_LEN]; // hexstr - bigendian + gsCryptRSAKey mPeerPublicKey; + gsi_u8 mSignature[GS_CRYPT_RSA_BYTE_SIZE]; // binary - bigendian + gsi_u8 mServerData[WS_LOGIN_SERVERDATA_LEN]; // binary - bigendian +} GSLoginCertificate; + +// Private information for the owner of the certificate only +// -- careful! private key information must be kept secret -- +typedef struct GSLoginCertificatePrivate +{ + gsCryptRSAKey mPeerPrivateKey; + char mKeyHash[GS_CRYPT_MD5_HASHSIZE]; +} GSLoginPrivateData; + +//typedef char GSLoginCertificateKeyHash[GS_CRYPT_MD5_HASHSIZE]; // Hash of private key, for simple auth + +typedef enum +{ + wsLoginType_INVALID, + wsLoginType_PROFILE, + wsLoginType_UNIQUENICK, + wsLoginType_GPTICKET, + wsLoginType_REMOTEAUTH +} WSLoginType; + +/* +typedef struct WSLoginProfileRequest +{ + int mPartnerCode; + char mProfileName[WS_LOGIN_NICK_LEN]; + char mEmailAddress[WS_LOGIN_EMAIL_LEN]; + char mPassword[WS_LOGIN_PASSWORD_LEN]; + char mCdKeyHash[WS_LOGIN_KEYHASH_LEN]; + void * mUserData; +} WSLoginProfileRequest; + +typedef struct WSLoginUniqueRequest +{ + int mPartnerCode; + char mUniqueNick[WS_LOGIN_NICK_LEN]; + char mPassword[WS_LOGIN_PASSWORD_LEN]; + char mCdKeyHash[WS_LOGIN_KEYHASH_LEN]; + void * mUserData; +} WSLoginUniqueRequest;*/ + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// CERTIFICATE login callback format +typedef struct WSLoginResponse +{ + WSLoginValue mLoginResult; // SDK high level result, e.g. LoginFailed + WSLoginValue mResponseCode; // server's result code, e.g. BadPassword + GSLoginCertificate mCertificate; // Show this to others (prooves: "Bill is a valid user") + GSLoginPrivateData mPrivateData; // Keep this secret! (prooves: "I am Bill") + void * mUserData; +} WSLoginResponse; + +typedef void (*WSLoginCallback)(GHTTPResult httpResult, WSLoginResponse * response, void * userData); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// PS3 login callback format +typedef struct WSLoginPs3CertResponse +{ + WSLoginValue mLoginResult; // SDK high level result, e.g. LoginFailed + WSLoginValue mResponseCode; // server's result code, e.g. BadPassword + char mRemoteAuthToken[WS_LOGIN_AUTHTOKEN_LEN]; // Show this to others + char mPartnerChallenge[WS_LOGIN_PARTNERCHALLENGE_LEN]; // keep this secret! (It's a "password" for the token.) + void * mUserData; +} WSLoginPs3CertResponse; + +typedef void (*WSLoginPs3CertCallback)(GHTTPResult httpResult, WSLoginPs3CertResponse * response, void * userData); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Services to obtain a certificate +gsi_u32 wsLoginProfile(int partnerCode, int namespaceId, const gsi_char * profileNick, const gsi_char * email, const gsi_char * password, const gsi_char * cdkeyhash, WSLoginCallback callback, void * userData); +gsi_u32 wsLoginUnique (int partnerCode, int namespaceId, const gsi_char * uniqueNick, const gsi_char * password, const gsi_char * cdkeyhash, WSLoginCallback callback, void * userData); +gsi_u32 wsLoginRemoteAuth(int partnerCode, int namespaceId, const gsi_char authtoken[WS_LOGIN_AUTHTOKEN_LEN], const gsi_char partnerChallenge[WS_LOGIN_PARTNERCHALLENGE_LEN], WSLoginCallback callback, void * userData); + +// Services to obtain a remote auth token +gsi_u32 wsLoginPs3Cert(int gameId, int partnerCode, int namespaceId, const gsi_u8 * ps3cert, int certLen, WSLoginPs3CertCallback callback, void * userData); + +// Certificate Utilities, for use after obtaining a certificate +gsi_bool wsLoginCertIsValid (const GSLoginCertificate * cert); +gsi_bool wsLoginCertWriteXML (const GSLoginCertificate * cert, const char * anamespace, GSXmlStreamWriter writer); +gsi_bool wsLoginCertWriteBinary(const GSLoginCertificate * cert, char * bufout, unsigned int maxlen, unsigned int * lenout); +gsi_bool wsLoginCertReadBinary (GSLoginCertificate * certOut, char * bufin, unsigned int maxlen); +gsi_bool wsLoginCertReadXML (GSLoginCertificate * cert, GSXmlStreamReader reader); + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif //__AUTHSERVICE_H__ diff --git a/xrGameSpy/stdafx.cpp b/xrGameSpy/stdafx.cpp new file mode 100644 index 00000000000..25e9848a294 --- /dev/null +++ b/xrGameSpy/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// xrGameSpy.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/xrGameSpy/stdafx.h b/xrGameSpy/stdafx.h new file mode 100644 index 00000000000..f45cbcda25d --- /dev/null +++ b/xrGameSpy/stdafx.h @@ -0,0 +1,13 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// TODO: reference additional headers your program requires here diff --git a/xrGameSpy/xrGameSpy.cpp b/xrGameSpy/xrGameSpy.cpp new file mode 100644 index 00000000000..4d34b0594e1 --- /dev/null +++ b/xrGameSpy/xrGameSpy.cpp @@ -0,0 +1,76 @@ +// xrGameSpy.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" +#include "xrGameSpy.h" +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +void FillSecretKey(char* SecretKey) +{ + SecretKey[0] = 'L'; + SecretKey[1] = 'T'; + SecretKey[2] = 'U'; + SecretKey[3] = '2'; + SecretKey[4] = 'z'; + SecretKey[5] = '2'; + SecretKey[6] = '\0'; +} + +const char* GetGameVersion () +{ + /*HKEY KeyCDKey = 0; + long res = RegOpenKeyEx(REGISTRY_BASE, + REGISTRY_PATH, 0, KEY_READ, &KeyCDKey); + +// char KeyValue[1024] = ""; + DWORD KeyValueSize = 128; + DWORD KeyValueType = REG_SZ; + if (res == ERROR_SUCCESS && KeyCDKey != 0) + { + res = RegQueryValueEx(KeyCDKey, REGISTRY_VALUE_VERSION, NULL, &KeyValueType, (LPBYTE)KeyValue, &KeyValueSize); + }; + if (KeyCDKey != 0) RegCloseKey(KeyCDKey); + + if (res == ERROR_PATH_NOT_FOUND || + res == ERROR_FILE_NOT_FOUND || + KeyValueSize == 0) + { + return GAME_VERSION; + };*/ +// return KeyValue; + return GAME_VERSION; +} + +XRGAMESPY_API const char* xrGS_GetGameVersion () +{ + return GetGameVersion(); +} + +XRGAMESPY_API void xrGS_GetGameID (int* GameID, int verID) +{ + *GameID = int(GAMESPY_GAMEID); + +#ifdef DEMO_BUILD + switch (verID) + { + case 1: *GameID = int(1067); break; + case 2: *GameID = int(1576); break; + case 3: *GameID = int(1620); break; + default: *GameID = int(GAMESPY_GAMEID); break; + } +#endif +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy.h b/xrGameSpy/xrGameSpy.h new file mode 100644 index 00000000000..81fc64a8fae --- /dev/null +++ b/xrGameSpy/xrGameSpy.h @@ -0,0 +1,40 @@ +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the XRGAMESPY_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// XRGAMESPY_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#ifdef XRGAMESPY_EXPORTS +#define XRGAMESPY_API __declspec(dllexport) +#else +#define XRGAMESPY_API __declspec(dllimport) +#endif +/* +// This class is exported from the xrGameSpy.dll +class XRGAMESPY_API CxrGameSpy { +public: + CxrGameSpy(void); + // TODO: add your methods here. +}; + +extern XRGAMESPY_API int nxrGameSpy; + +XRGAMESPY_API int fnxrGameSpy(void); +*/ +#pragma once +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_Available.h" +#include "xrGameSpy_ServerBrowser.h" +#include "xrGameSpy_QR2.h" +#include "xrGameSpy_CDKey.h" + + +extern "C" +{ + EXPORT_FN_DECL(const char*, GetGameVersion, ()); + EXPORT_FN_DECL(void, GetGameID, (int* GameID, int verID)); +} + + + diff --git a/xrGameSpy/xrGameSpy.vcproj b/xrGameSpy/xrGameSpy.vcproj new file mode 100644 index 00000000000..3ffaf799257 --- /dev/null +++ b/xrGameSpy/xrGameSpy.vcproj @@ -0,0 +1,2714 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrGameSpy/xrGameSpy_ATLAS.cpp b/xrGameSpy/xrGameSpy_ATLAS.cpp new file mode 100644 index 00000000000..d28223e8257 --- /dev/null +++ b/xrGameSpy/xrGameSpy_ATLAS.cpp @@ -0,0 +1,202 @@ +#include "stdafx.h" +#include "xrGameSpy_MainDefs.h" +#include "xrGameSpy_ATLAS.h" +#include "GameSpy/GP/gp.h" + +XRGAMESPY_API gsi_u32 xrGS_wsLoginProfile(const gsi_char * profileNick, + const gsi_char * email, + const gsi_char * password, + const gsi_char * cdkeyhash, + WSLoginCallback callback, + void * userData) +{ + return wsLoginProfile( + GP_PARTNERID_GAMESPY, + GAMESPY_GP_NAMESPACE_ID, + profileNick, + email, + password, + cdkeyhash, + callback, + userData + ); +} + +XRGAMESPY_API SCResult xrGS_scInitialize(SCInterfacePtr * theInterfaceOut) +{ + return scInitialize(GAMESPY_GAMEID, theInterfaceOut); +} + +XRGAMESPY_API SCResult xrGS_scShutdown(SCInterfacePtr theInterface) +{ + return scShutdown(theInterface); +} + +XRGAMESPY_API SCResult xrGS_scThink(SCInterfacePtr theInterface) +{ + return scThink(theInterface); +} + +XRGAMESPY_API SCResult xrGS_scCreateSession(SCInterfacePtr theInterface, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + return scCreateSession( + theInterface, + theCertificate, + thePrivateData, + theCallback, + theTimeoutMs, + theUserData + ); +} + +XRGAMESPY_API const char * xrGS_scGetSessionId(const SCInterfacePtr theInterface) +{ + return scGetSessionId(theInterface); +} + +XRGAMESPY_API SCResult xrGS_scSetSessionId(const SCInterfacePtr theInterface, + const gsi_u8 theSessionId[SC_SESSION_GUID_SIZE]) +{ + return scSetSessionId( + theInterface, + theSessionId + ); +} + +XRGAMESPY_API SCResult xrGS_scSetReportIntention(const SCInterfacePtr theInterface, + const gsi_u8 theConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + return scSetReportIntention( + theInterface, + theConnectionId, + isAuthoritative, + theCertificate, + thePrivateData, + theCallback, + theTimeoutMs, + theUserData + ); +} + +XRGAMESPY_API const char * xrGS_scGetConnectionId(const SCInterfacePtr theInterface) +{ + return scGetConnectionId(theInterface); +} + +XRGAMESPY_API SCResult xrGS_scCreateReport(const SCInterfacePtr theInterface, + gsi_u32 theHeaderVersion, + gsi_u32 thePlayerCount, + gsi_u32 theTeamCount, + SCReportPtr * theReportOut) +{ + return scCreateReport( + theInterface, + theHeaderVersion, + thePlayerCount, + theTeamCount, + theReportOut + ); +} + +XRGAMESPY_API SCResult xrGS_scReportBeginGlobalData(SCReportPtr theReportData) +{ + return scReportBeginGlobalData(theReportData); +} + +XRGAMESPY_API SCResult xrGS_scReportBeginPlayerData(SCReportPtr theReportData) +{ + return scReportBeginPlayerData(theReportData); +} + +XRGAMESPY_API SCResult xrGS_scReportBeginNewPlayer(SCReportPtr theReportData) +{ + return scReportBeginNewPlayer(theReportData); +} + +XRGAMESPY_API SCResult xrGS_scReportSetPlayerData (SCReportPtr theReport, + gsi_u32 thePlayerIndex, + const gsi_u8 thePlayerConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_u32 thePlayerTeamId, + SCGameResult theResult, + gsi_u32 theProfileId, + const GSLoginCertificate * theCertificate, + const gsi_u8 theAuthHash[16]) +{ + gsi_u8 tmp_auth_data[16]; + ZeroMemory(tmp_auth_data, sizeof(tmp_auth_data)); + return scReportSetPlayerData( + theReport, + thePlayerIndex, + thePlayerConnectionId, + thePlayerTeamId, + theResult, + theProfileId, + theCertificate, + tmp_auth_data //not used + ); +} + +XRGAMESPY_API SCResult xrGS_scReportAddIntValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + gsi_i32 theValue) +{ + return scReportAddIntValue( + theReportData, + theKeyId, + theValue + ); +} + +XRGAMESPY_API SCResult xrGS_scReportAddStringValue(SCReportPtr theReportData, + gsi_u16 theKeyId, + const gsi_char * theValue) +{ + return scReportAddStringValue( + theReportData, + theKeyId, + theValue + ); +} + +XRGAMESPY_API SCResult xrGS_scReportEnd(SCReportPtr theReport, + gsi_bool isAuth, + SCGameStatus theStatus) +{ + return scReportEnd( + theReport, + isAuth, + theStatus + ); +} + +XRGAMESPY_API SCResult xrGS_scSubmitReport(const SCInterfacePtr theInterface, + const SCReportPtr theReport, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSubmitReportCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData) +{ + return scSubmitReport( + theInterface, + theReport, + isAuthoritative, + theCertificate, + thePrivateData, + theCallback, + theTimeoutMs, + theUserData + ); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_ATLAS.h b/xrGameSpy/xrGameSpy_ATLAS.h new file mode 100644 index 00000000000..2c84866ebdf --- /dev/null +++ b/xrGameSpy/xrGameSpy_ATLAS.h @@ -0,0 +1,81 @@ +#ifndef XRGAMESPY_ATLAS_INCLUDED +#define XRGAMESPY_ATLAS_INCLUDED + + +#include "xrGameSpy_MainDefs.h" +#include "GameSpy/sc/sc.h" + +extern "C" +{ + +//export from webservices +EXPORT_FN_DECL(gsi_u32, wsLoginProfile, (const gsi_char * profileNick, + const gsi_char * email, + const gsi_char * password, + const gsi_char * cdkeyhash, + WSLoginCallback callback, + void * userData)); +//export from sc +EXPORT_FN_DECL(SCResult, scInitialize, (SCInterfacePtr * theInterfaceOut)); +EXPORT_FN_DECL(SCResult, scShutdown, (SCInterfacePtr theInterface)); +EXPORT_FN_DECL(SCResult, scThink, (SCInterfacePtr theInterface)); +EXPORT_FN_DECL(SCResult, scCreateSession, (SCInterfacePtr theInterface, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCCreateSessionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData)); +EXPORT_FN_DECL(const char *, scGetSessionId, (const SCInterfacePtr theInterface)); +EXPORT_FN_DECL(SCResult, scSetSessionId, (const SCInterfacePtr theInterface, + const gsi_u8 theSessionId[SC_SESSION_GUID_SIZE])); +EXPORT_FN_DECL(SCResult, scSetReportIntention, (const SCInterfacePtr theInterface, + const gsi_u8 theConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSetReportIntentionCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData)); +EXPORT_FN_DECL(const char *, scGetConnectionId, (const SCInterfacePtr theInterface)); +EXPORT_FN_DECL(SCResult, scCreateReport, (const SCInterfacePtr theInterface, + gsi_u32 theHeaderVersion, + gsi_u32 thePlayerCount, + gsi_u32 theTeamCount, + SCReportPtr * theReportOut)); +EXPORT_FN_DECL(SCResult, scReportBeginGlobalData,(SCReportPtr theReportData)); +EXPORT_FN_DECL(SCResult, scReportBeginPlayerData,(SCReportPtr theReportData)); +EXPORT_FN_DECL(SCResult, scReportBeginNewPlayer, (SCReportPtr theReportData)); + + +EXPORT_FN_DECL(SCResult, scReportSetPlayerData, (SCReportPtr theReport, + gsi_u32 thePlayerIndex, + const gsi_u8 thePlayerConnectionId[SC_CONNECTION_GUID_SIZE], + gsi_u32 thePlayerTeamId, + SCGameResult theResult, + gsi_u32 theProfileId, + const GSLoginCertificate * theCertificate, + const gsi_u8 theAuthHash[16])); + +EXPORT_FN_DECL(SCResult, scReportAddIntValue, (SCReportPtr theReportData, + gsi_u16 theKeyId, + gsi_i32 theValue)); + +EXPORT_FN_DECL(SCResult, scReportAddStringValue, (SCReportPtr theReportData, + gsi_u16 theKeyId, + const gsi_char * theValue)); +EXPORT_FN_DECL(SCResult, scReportEnd, (SCReportPtr theReport, + gsi_bool isAuth, + SCGameStatus theStatus)); + + +EXPORT_FN_DECL(SCResult, scSubmitReport, (const SCInterfacePtr theInterface, + const SCReportPtr theReport, + gsi_bool isAuthoritative, + const GSLoginCertificate * theCertificate, + const GSLoginPrivateData * thePrivateData, + SCSubmitReportCallback theCallback, + gsi_time theTimeoutMs, + void * theUserData)); +}//extern "C" + +#endif //#ifndef XRGAMESPY_ATLAS_INCLUDED \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_Available.cpp b/xrGameSpy/xrGameSpy_Available.cpp new file mode 100644 index 00000000000..572a30f0ead --- /dev/null +++ b/xrGameSpy/xrGameSpy_Available.cpp @@ -0,0 +1,22 @@ +#include "stdafx.h" +#include "windows.h" +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_Available.h" + +//XRGAMESPY_API void xrGS_GSIStartAvailableCheck(const gsi_char * gamename) +XRGAMESPY_API void xrGS_GSIStartAvailableCheckA() +{ +// GSIStartAvailableCheck(gamename); + GSIStartAvailableCheck(GAMESPY_GAMENAME); +}; + +XRGAMESPY_API GSIACResult xrGS_GSIAvailableCheckThink() +{ + return GSIAvailableCheckThink(); +} + +XRGAMESPY_API void xrGS_msleep(gsi_time msec) +{ + msleep(msec); +} diff --git a/xrGameSpy/xrGameSpy_Available.h b/xrGameSpy/xrGameSpy_Available.h new file mode 100644 index 00000000000..8160c1435ba --- /dev/null +++ b/xrGameSpy/xrGameSpy_Available.h @@ -0,0 +1,13 @@ +#pragma once +#include "xrGameSpy_MainDefs.h" + +#include "GameSpy\nonport.h" +#include "GameSpy\common\gsAvailable.h" + +extern "C" +{ +// EXPORT_FN_DECL(void, GSIStartAvailableCheck, (const gsi_char * gamename)); + EXPORT_FN_DECL(void, GSIStartAvailableCheckA, ()); + EXPORT_FN_DECL(GSIACResult, GSIAvailableCheckThink, ()); + EXPORT_FN_DECL(void, msleep, (gsi_time msec)); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_CDKey.cpp b/xrGameSpy/xrGameSpy_CDKey.cpp new file mode 100644 index 00000000000..a643a9eb999 --- /dev/null +++ b/xrGameSpy/xrGameSpy_CDKey.cpp @@ -0,0 +1,49 @@ +#include "stdafx.h" +#include "windows.h" +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_CDKey.h" + +#include "GameSpy/gcdkey/gcdkeyc.h" +#include "GameSpy/gcdkey/gcdkeys.h" + + + + +XRGAMESPY_API void xrGS_gcd_compute_response(char *cdkey, char *challenge,char* response, bool Reauth) +{ + gcd_compute_response(cdkey, challenge,response, Reauth ? CDResponseMethod_REAUTH : CDResponseMethod_NEWAUTH); +}; + +XRGAMESPY_API int xrGS_gcd_init_qr2(qr2_t qrec) +{ + return gcd_init_qr2(qrec, GAMESPY_GAMEID); +}; +XRGAMESPY_API void xrGS_gcd_shutdown(void) +{ + gcd_shutdown(); +} +XRGAMESPY_API void xrGS_gcd_authenticate_user(int localid, unsigned int userip, char *challenge, char *response, + AuthCallBackFn authfn, RefreshAuthCallBackFn refreshfn, void *instance) +{ + gcd_authenticate_user(GAMESPY_GAMEID, localid, userip, challenge, response, authfn, refreshfn, instance); +} + +XRGAMESPY_API void xrGS_gcd_reauthenticate_user(int localid, int hint, const char *response) +{ + gcd_process_reauth(GAMESPY_GAMEID, localid, hint, response); +} + +XRGAMESPY_API void xrGS_gcd_disconnect_user(int localid) +{ + gcd_disconnect_user(GAMESPY_GAMEID, localid); +} +XRGAMESPY_API void xrGS_gcd_think(void) +{ + gcd_think(); +} + +XRGAMESPY_API char* xrGS_gcd_getkeyhash(int localid) +{ + return gcd_getkeyhash(GAMESPY_GAMEID,localid); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_CDKey.h b/xrGameSpy/xrGameSpy_CDKey.h new file mode 100644 index 00000000000..1096f7ef24a --- /dev/null +++ b/xrGameSpy/xrGameSpy_CDKey.h @@ -0,0 +1,17 @@ +#pragma once +#include "xrGameSpy_MainDefs.h" +#include "GameSpy/qr2/qr2.h" +#include "GameSpy/gcdkey/gcdkeys.h" + +extern "C" +{ + EXPORT_FN_DECL(void, gcd_compute_response, (char *cdkey, char *challenge,char* response, bool Reauth)); + EXPORT_FN_DECL(int, gcd_init_qr2, (qr2_t qrec)); + EXPORT_FN_DECL(void, gcd_shutdown, (void)); + EXPORT_FN_DECL(void, gcd_authenticate_user, (int localid, unsigned int userip, char *challenge, char *response, + AuthCallBackFn authfn, RefreshAuthCallBackFn refreshfn, void *instance)); + EXPORT_FN_DECL(void, gcd_reauthenticate_user, (int localid, int hint, const char *response)); + EXPORT_FN_DECL(void, gcd_disconnect_user, (int localid)); + EXPORT_FN_DECL(void, gcd_think, (void)); + EXPORT_FN_DECL(char*, gcd_getkeyhash, (int localid)); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_Core.cpp b/xrGameSpy/xrGameSpy_Core.cpp new file mode 100644 index 00000000000..d7390cc6062 --- /dev/null +++ b/xrGameSpy/xrGameSpy_Core.cpp @@ -0,0 +1,19 @@ +#include "stdafx.h" +#include "xrGameSpy_Core.h" + +void xrGS_gsCoreInitialize() +{ + gsCoreInitialize(); +} + +void xrGS_gsCoreThink(gsi_time theMs) +{ + gsCoreThink(theMs); +} + +void xrGS_gsCoreShutdown() +{ + gsCoreShutdown(); +} + + diff --git a/xrGameSpy/xrGameSpy_Core.h b/xrGameSpy/xrGameSpy_Core.h new file mode 100644 index 00000000000..765ff5f46fb --- /dev/null +++ b/xrGameSpy/xrGameSpy_Core.h @@ -0,0 +1,16 @@ +#ifndef XRGAMESPY_CORE +#define XRGAMESPY_CORE + +#include "xrGameSpy_MainDefs.h" +#include "GameSpy/common/gsCore.h" + +extern "C" +{ + +EXPORT_FN_DECL(void, gsCoreInitialize, ()); +EXPORT_FN_DECL(void, gsCoreThink, (gsi_time theMs)); +EXPORT_FN_DECL(void, gsCoreShutdown, ()); + +} //extern "C" + +#endif \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_GP.cpp b/xrGameSpy/xrGameSpy_GP.cpp new file mode 100644 index 00000000000..bb961b5652c --- /dev/null +++ b/xrGameSpy/xrGameSpy_GP.cpp @@ -0,0 +1,178 @@ +#include "stdafx.h" +#include "xrGameSpy_MainDefs.h" +#include "xrGameSpy_GP.h" + +XRGAMESPY_API GPResult xrGS_gpInitialize(GPConnection * connection) +{ + return gpInitialize( + connection, + GAMESPY_PRODUCTID, + GAMESPY_GP_NAMESPACE_ID, + GP_PARTNERID_GAMESPY + ); +} + +XRGAMESPY_API void xrGS_gpDestroy(GPConnection * connection) +{ + gpDestroy(connection); +} + +XRGAMESPY_API GPResult xrGS_gpProcess(GPConnection * connection) +{ + return gpProcess(connection); +} + +XRGAMESPY_API GPResult xrGS_gpSetCallback(GPConnection * connection, + GPEnum func, + GPCallback callback, + void * param) +{ + return gpSetCallback(connection, func, callback, param); +} + +XRGAMESPY_API GPResult xrGS_gpNewProfileA(GPConnection * connection, + const char nick[GP_NICK_LEN], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpNewProfile(connection, nick, replace, blocking, callback, param); +} + +XRGAMESPY_API GPResult xrGS_gpNewUserA (GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpNewUserA( + connection, + nick, + uniquenick, + email, + password, + cdkey, + blocking, + callback, + param + ); +} + +XRGAMESPY_API GPResult xrGS_gpProfileSearchA(GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char firstname[GP_FIRSTNAME_LEN], + const gsi_char lastname[GP_LASTNAME_LEN], + int icquin, + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpProfileSearchA( + connection, + nick, + uniquenick, + email, + firstname, + lastname, + icquin, + blocking, + callback, + param + ); +} + +XRGAMESPY_API GPResult xrGS_gpGetUserNicksA(GPConnection * connection, + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpGetUserNicksA( + connection, + email, + password, + blocking, + callback, + param + ); +} + + +XRGAMESPY_API GPResult xrGS_gpConnectA(GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpConnectA( + connection, + nick, + email, + password, + firewall, + blocking, + callback, + param + ); +} + +XRGAMESPY_API void xrGS_gpDisconnect(GPConnection * connection) +{ + gpDisconnect(connection); +} + +XRGAMESPY_API GPResult xrGS_gpSuggestUniqueNickA(GPConnection * connection, + const gsi_char desirednick[GP_UNIQUENICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpSuggestUniqueNickA( + connection, + desirednick, + blocking, + callback, + param + ); +} + +XRGAMESPY_API GPResult xrGS_gpDeleteProfile(GPConnection * connection, + GPCallback callback, + void * arg) +{ + return gpDeleteProfile(connection, callback, arg); +} + +XRGAMESPY_API GPResult xrGS_gpGetLoginTicket(GPConnection * connection, + char loginTicket[GP_LOGIN_TICKET_LEN]) +{ + return gpGetLoginTicket(connection, loginTicket); +} + +XRGAMESPY_API GPResult xrGS_gpRegisterUniqueNickA(GPConnection * connection, + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param) +{ + return gpRegisterUniqueNick( + connection, + uniquenick, + cdkey, + blocking, + callback, + param + ); +} diff --git a/xrGameSpy/xrGameSpy_GP.h b/xrGameSpy/xrGameSpy_GP.h new file mode 100644 index 00000000000..d7703785651 --- /dev/null +++ b/xrGameSpy/xrGameSpy_GP.h @@ -0,0 +1,78 @@ +#ifndef XRGAMESPY_GP +#define XRGAMESPY_GP + +#include "xrGameSpy_MainDefs.h" +#include "GameSpy/GP/gp.h" + +extern "C" +{ + +EXPORT_FN_DECL(GPResult, gpInitialize, (GPConnection * connection)); +EXPORT_FN_DECL(void, gpDestroy, (GPConnection * connection)); +EXPORT_FN_DECL(GPResult, gpProcess, (GPConnection * connection)); +EXPORT_FN_DECL(GPResult, gpSetCallback, (GPConnection * connection, + GPEnum func, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(GPResult, gpNewProfileA, (GPConnection * connection, + const char nick[GP_NICK_LEN], + GPEnum replace, + GPEnum blocking, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(GPResult, gpNewUserA, (GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(GPResult, gpProfileSearchA, (GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char firstname[GP_FIRSTNAME_LEN], + const gsi_char lastname[GP_LASTNAME_LEN], + int icquin, + GPEnum blocking, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(GPResult, gpGetUserNicksA, (GPConnection * connection, + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum blocking, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(GPResult, gpConnectA, (GPConnection * connection, + const gsi_char nick[GP_NICK_LEN], + const gsi_char email[GP_EMAIL_LEN], + const gsi_char password[GP_PASSWORD_LEN], + GPEnum firewall, + GPEnum blocking, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(void, gpDisconnect, (GPConnection * connection)); + +EXPORT_FN_DECL(GPResult, gpSuggestUniqueNickA, (GPConnection * connection, + const gsi_char desirednick[GP_UNIQUENICK_LEN], + GPEnum blocking, + GPCallback callback, + void * param)); +EXPORT_FN_DECL(GPResult, gpDeleteProfile, (GPConnection * connection, + GPCallback callback, + void * arg)); + +EXPORT_FN_DECL(GPResult, gpGetLoginTicket, (GPConnection * connection, + char loginTicket[GP_LOGIN_TICKET_LEN])); + +EXPORT_FN_DECL(GPResult, gpRegisterUniqueNickA, (GPConnection * connection, + const gsi_char uniquenick[GP_UNIQUENICK_LEN], + const gsi_char cdkey[GP_CDKEY_LEN], + GPEnum blocking, + GPCallback callback, + void * param)); +}; //extern "C" + +#endif //#ifndef XRGAMESPY_GP \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_HTTP.cpp b/xrGameSpy/xrGameSpy_HTTP.cpp new file mode 100644 index 00000000000..54a27ad6da7 --- /dev/null +++ b/xrGameSpy/xrGameSpy_HTTP.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "windows.h" +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_HTTP.h" + +XRGAMESPY_API void xrGS_ghttpStartup() +{ + ghttpStartup(); +} + +XRGAMESPY_API void xrGS_ghttpCleanup() +{ + ghttpCleanup(); +} + +XRGAMESPY_API void xrGS_ghttpThink() +{ + ghttpThink(); +} + +XRGAMESPY_API GHTTPRequest xrGS_ghttpSaveA ( + const gsi_char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const gsi_char * filename, // The path and name to store the file as locally. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. + ) +{ + return ghttpSaveA( URL, filename, blocking, completedCallback, param); +} + +XRGAMESPY_API GHTTPRequest xrGS_ghttpSaveExA ( + const gsi_char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const gsi_char * filename, // The path and name to store the file as locally. + const gsi_char * headers, // Optional headers to pass with the request. Can be NULL or "". + GHTTPPost post, // Optional data to be posted. + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpProgressCallback progressCallback, // Called periodically with progress updates. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. + ) +{ + return ghttpSaveExA ( URL, filename, headers, post, throttle, blocking, progressCallback, completedCallback, param); +} + +XRGAMESPY_API void xrGS_ghttpCancelRequest ( GHTTPRequest request ) +{ + ghttpCancelRequest ( request ); +}; \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_HTTP.h b/xrGameSpy/xrGameSpy_HTTP.h new file mode 100644 index 00000000000..cda9834359a --- /dev/null +++ b/xrGameSpy/xrGameSpy_HTTP.h @@ -0,0 +1,34 @@ +#pragma once +#include "xrGameSpy_MainDefs.h" +#include "gamespy/ghttp/ghttp.h" +extern "C" +{ + EXPORT_FN_DECL(void, ghttpStartup, ()); + EXPORT_FN_DECL(void, ghttpCleanup, ()); + EXPORT_FN_DECL(void, ghttpThink,()); + EXPORT_FN_DECL(void, ghttpCancelRequest, ( GHTTPRequest request )); + + + + EXPORT_FN_DECL(GHTTPRequest, ghttpSaveA, + ( + const gsi_char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const gsi_char * filename, // The path and name to store the file as locally. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. + )); + + EXPORT_FN_DECL(GHTTPRequest, ghttpSaveExA, + ( + const gsi_char * URL, // The URL for the file ("http://host.domain[:port]/path/filename"). + const gsi_char * filename, // The path and name to store the file as locally. + const gsi_char * headers, // Optional headers to pass with the request. Can be NULL or "". + GHTTPPost post, // Optional data to be posted. + GHTTPBool throttle, // If true, throttle this connection's download speed. + GHTTPBool blocking, // If true, this call doesn't return until the file has been recevied. + ghttpProgressCallback progressCallback, // Called periodically with progress updates. + ghttpCompletedCallback completedCallback, // Called when the file has been received. + void * param // User-data to be passed to the callbacks. + )); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_MainDefs.h b/xrGameSpy/xrGameSpy_MainDefs.h new file mode 100644 index 00000000000..9ad8eafee8d --- /dev/null +++ b/xrGameSpy/xrGameSpy_MainDefs.h @@ -0,0 +1,60 @@ +#pragma once + +#define QRCDKEY_INTEGRATION +#define SB_ICMP_SUPPORT + +#undef DEMO_BUILD + +//#define DEMO_BUILD + +#ifdef DEMO_BUILD + #define GAMESPY_GAMENAME "stalkercoppc" + #define GAMESPY_GAMEID 2760 + #define GAMESPY_PRODUCTID 11994 + #define GAME_VERSION "1.6.02" + #define REGISTRY_PATH "Software\\GSC Game World\\STALKER-COP_DBG\\" +#else + #define GAMESPY_GAMENAME "stalkercoppc" + #define GAMESPY_GAMEID 2760 + #define GAMESPY_PRODUCTID 11994 + #define GAME_VERSION "1.6.02" + #define REGISTRY_PATH "Software\\GSC Game World\\STALKER-COP\\" +#endif + +#define GAMESPY_GP_NAMESPACE_ID 1 /*gamespy global namespace*/ + +#define GAMESPY_QR2_BASEPORT 5445 +#define GAMESPY_BROWSER_MAX_UPDATES 20 + +#define START_PORT 0 +#define END_PORT 65535 +#define START_PORT_LAN GAMESPY_QR2_BASEPORT +#define START_PORT_LAN_SV START_PORT_LAN + 1 +#define START_PORT_LAN_CL START_PORT_LAN + 2 +#define END_PORT_LAN START_PORT_LAN + 250//GameSpy only process 500 ports + +#define REGISTRY_BASE HKEY_LOCAL_MACHINE +#define REGISTRY_VALUE_GSCDKEY "InstallCDKEY" +#define REGISTRY_VALUE_VERSION "InstallVers" +#define REGISTRY_VALUE_USERNAME "InstallUserName" +#define REGISTRY_VALUE_SKU "InstallSource" +#define REGISTRY_VALUE_INSTALL_PATCH_ID "InstallPatchID" +#define REGISTRY_VALUE_LANGUAGE "InstallLang" +#define REGISTRY_VALUE_USEREMAIL "GPUserEmail" +#define REGISTRY_VALUE_USERPASSWORD "GPUserPassword" +#define REGISTRY_VALUE_REMEMBER_PROFILE "GPRememberMe" + +#define GAMESPY_PATCHING_VERSIONUNIQUE_ID "test_version_1" +#define GAMESPY_PATCHING_DISTRIBUTION_ID 0 + + + +#ifndef XRGAMESPY_API + #ifdef XRGAMESPY_EXPORTS + #define XRGAMESPY_API __declspec(dllexport) + #endif +#endif + +#define EXPORT_FN_DECL(r, f, p) XRGAMESPY_API r xrGS_##f p; + +extern void FillSecretKey (char* SecretKey); diff --git a/xrGameSpy/xrGameSpy_Patching.cpp b/xrGameSpy/xrGameSpy_Patching.cpp new file mode 100644 index 00000000000..0790df9ddfc --- /dev/null +++ b/xrGameSpy/xrGameSpy_Patching.cpp @@ -0,0 +1,34 @@ +#include "stdafx.h" +#include "windows.h" +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_Patching.h" + +extern const char* GetGameVersion (); +extern int GetGameDistribution (); + +XRGAMESPY_API bool xrGS_ptCheckForPatchA( + //int productID, const gsi_char * versionUniqueID, int distributionID, + ptPatchCallback callback, + PTBool blocking, + void * instance ) +{ + // return ptCheckForPatch(productID, versionUniqueID, distributionID, callback, blocking, instance )!=PTFalse; + return ptCheckForPatchA(GAMESPY_PRODUCTID, +// GAME_VERSION, + GetGameVersion(), +// GAMESPY_PATCHING_VERSIONUNIQUE_ID, +// GAMESPY_PATCHING_DISTRIBUTION_ID, + GetGameDistribution(), + callback, blocking, instance ) != PTFalse; +}; + +XRGAMESPY_API bool xrGS_ptTrackUsageA(int userID) +{ + return ptTrackUsageA( + userID, + GAMESPY_PRODUCTID, + GetGameVersion(), + GetGameDistribution(), + PTFalse) != PTFalse; +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_Patching.h b/xrGameSpy/xrGameSpy_Patching.h new file mode 100644 index 00000000000..5fc542f8600 --- /dev/null +++ b/xrGameSpy/xrGameSpy_Patching.h @@ -0,0 +1,14 @@ +#pragma once +#include "xrGameSpy_MainDefs.h" +#include "GameSpy/pt/pt.h" + +extern "C" +{ + EXPORT_FN_DECL(bool, ptCheckForPatchA, ( +// int productID, const gsi_char * versionUniqueID, int distributionID, + ptPatchCallback callback, + PTBool blocking, + void * instance )); + + EXPORT_FN_DECL(bool, ptTrackUsageA, (int userID)); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_QR2.cpp b/xrGameSpy/xrGameSpy_QR2.cpp new file mode 100644 index 00000000000..2c8bc9f0146 --- /dev/null +++ b/xrGameSpy/xrGameSpy_QR2.cpp @@ -0,0 +1,95 @@ +#include "stdafx.h" +#include "windows.h" +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_QR2.h" + +XRGAMESPY_API const char* xrGS_RegisteredKey(DWORD KeyID) +{ + return qr2_registered_key_list[KeyID]; +}; + +XRGAMESPY_API void xrGS_qr2_register_keyA(int keyid, const gsi_char *key) +{ + qr2_register_keyA(keyid, key); +} + +XRGAMESPY_API void xrGS_qr2_think(qr2_t qrec) +{ + qr2_think(qrec); +}; + +XRGAMESPY_API void xrGS_qr2_shutdown (qr2_t qrec) +{ + qr2_shutdown(qrec); +}; + +XRGAMESPY_API void xrGS_qr2_buffer_addA(qr2_buffer_t outbuf, const char *value) +{ + qr2_buffer_addA(outbuf, value); +}; + +XRGAMESPY_API void xrGS_qr2_buffer_add_int(qr2_buffer_t outbuf, int value) +{ + qr2_buffer_add_int(outbuf, value); +} + +XRGAMESPY_API void xrGS_qr2_keybuffer_add(qr2_keybuffer_t keybuffer, int keyid) +{ + qr2_keybuffer_add(keybuffer, keyid); +} + +XRGAMESPY_API void xrGS_qr2_register_natneg_callback (qr2_t qrec, qr2_natnegcallback_t nncallback) +{ + qr2_register_natneg_callback (qrec, nncallback); +}; +XRGAMESPY_API void xrGS_qr2_register_clientmessage_callback (qr2_t qrec, qr2_clientmessagecallback_t cmcallback) +{ + qr2_register_clientmessage_callback (qrec, cmcallback); +}; +XRGAMESPY_API void xrGS_qr2_register_publicaddress_callback (qr2_t qrec, qr2_publicaddresscallback_t pacallback) +{ + qr2_register_publicaddress_callback (qrec, pacallback); +}; +XRGAMESPY_API void xrGS_qr2_register_denyresponsetoip_callback(qr2_t qrec, qr2_denyqr2responsetoipcallback_t dertoipcallback) +{ + qr2_register_denyresponsetoip_callback (qrec, dertoipcallback); +}; + + +//XRGAMESPY_API qr2_error_t xrGS_qr2_init(/*[out]*/qr2_t *qrec, const gsi_char *ip, int baseport, const gsi_char *gamename, const gsi_char *secret_key, +XRGAMESPY_API qr2_error_t xrGS_qr2_initA(/*[out]*/qr2_t *qrec, const gsi_char *ip, int baseport, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata) +{ + int BasePort = baseport; + if (BasePort == -1) BasePort = GAMESPY_QR2_BASEPORT; + else + { + if (BasePort < START_PORT) BasePort = START_PORT; + if (BasePort > END_PORT) BasePort = END_PORT; + } + + char SecretKey[16]; + FillSecretKey(SecretKey); + + qr2_error_t res = + qr2_initA(qrec, ip, BasePort, GAMESPY_GAMENAME, SecretKey, + ispublic, + natnegotiate, + server_key_callback, + player_key_callback, + team_key_callback, + key_list_callback, + playerteam_count_callback, + adderror_callback, + userdata); + + return res; +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_QR2.h b/xrGameSpy/xrGameSpy_QR2.h new file mode 100644 index 00000000000..98b35fbab7f --- /dev/null +++ b/xrGameSpy/xrGameSpy_QR2.h @@ -0,0 +1,35 @@ +#pragma once +#include "xrGameSpy_MainDefs.h" + +#include "GameSpy\QR2\qr2regkeys.h" +#include "GameSpy\QR2\qr2.h" + + +extern "C" +{ + EXPORT_FN_DECL(const char*, RegisteredKey, (DWORD KeyID)); + EXPORT_FN_DECL(void, qr2_register_keyA, (int keyid, const gsi_char *key)); + EXPORT_FN_DECL(void, qr2_think, (qr2_t qrec)); + EXPORT_FN_DECL(void, qr2_shutdown, (qr2_t qrec)); + EXPORT_FN_DECL(void, qr2_buffer_addA, (qr2_buffer_t outbuf, const char *value)); + EXPORT_FN_DECL(void, qr2_buffer_add_int, (qr2_buffer_t outbuf, int value)); + EXPORT_FN_DECL(void, qr2_keybuffer_add, (qr2_keybuffer_t keybuffer, int keyid)); + + EXPORT_FN_DECL(void, qr2_register_natneg_callback, (qr2_t qrec, qr2_natnegcallback_t nncallback)); + EXPORT_FN_DECL(void, qr2_register_clientmessage_callback, (qr2_t qrec, qr2_clientmessagecallback_t cmcallback)); + EXPORT_FN_DECL(void, qr2_register_publicaddress_callback, (qr2_t qrec, qr2_publicaddresscallback_t pacallback)); + EXPORT_FN_DECL(void, qr2_register_denyresponsetoip_callback, (qr2_t qrec, qr2_denyqr2responsetoipcallback_t dertoipcallback)); + +// EXPORT_FN_DECL(qr2_error_t, qr2_init, (/*[out]*/qr2_t *qrec, const gsi_char *ip, int baseport, const gsi_char *gamename, const gsi_char *secret_key, + EXPORT_FN_DECL(qr2_error_t, qr2_initA, (/*[out]*/qr2_t *qrec, const gsi_char *ip, int baseport, + int ispublic, int natnegotiate, + qr2_serverkeycallback_t server_key_callback, + qr2_playerteamkeycallback_t player_key_callback, + qr2_playerteamkeycallback_t team_key_callback, + qr2_keylistcallback_t key_list_callback, + qr2_countcallback_t playerteam_count_callback, + qr2_adderrorcallback_t adderror_callback, + void *userdata)); + + +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_SAKE.cpp b/xrGameSpy/xrGameSpy_SAKE.cpp new file mode 100644 index 00000000000..d6b99d6650e --- /dev/null +++ b/xrGameSpy/xrGameSpy_SAKE.cpp @@ -0,0 +1,83 @@ +#include "stdafx.h" +#include "xrGameSpy_MainDefs.h" +#include "xrGameSpy_SAKE.h" + +XRGAMESPY_API SAKEStartupResult xrGS_sakeStartup(SAKE *sakePtr) +{ + SAKEStartupResult tmp_res = sakeStartup(sakePtr); + if (tmp_res == SAKEStartupResult_SUCCESS) + { + char secret_key[32]; + memset(secret_key, 0, sizeof(secret_key)); + FillSecretKey(secret_key); + sakeSetGame(*sakePtr, GAMESPY_GAMENAME, GAMESPY_GAMEID, secret_key); + } + return tmp_res; +} + +XRGAMESPY_API void xrGS_sakeShutdown(SAKE sake) +{ + sakeShutdown(sake); +} + +XRGAMESPY_API void xrGS_sakeSetProfile(SAKE sake,int profileId,const char *loginTicket) +{ + sakeSetProfile(sake, profileId, loginTicket); +} + +XRGAMESPY_API SAKEStartRequestResult xrGS_sakeGetStartRequestResult(SAKE sake) +{ + return sakeGetStartRequestResult(sake); +} + +XRGAMESPY_API SAKERequest xrGS_sakeGetMyRecords(SAKE sake, + SAKEGetMyRecordsInput * input, + SAKERequestCallback callback, + void * userData) +{ + return sakeGetMyRecords( + sake, + input, + callback, + userData + ); +} + +XRGAMESPY_API SAKERequest xrGS_sakeCreateRecord(SAKE sake, + SAKECreateRecordInput * input, + SAKERequestCallback callback, + void * userdata) +{ + return sakeCreateRecord( + sake, + input, + callback, + userdata + ); +} + +XRGAMESPY_API SAKERequest xrGS_sakeUpdateRecord(SAKE sake, + SAKEUpdateRecordInput * input, + SAKERequestCallback callback, + void * userdata) +{ + return sakeUpdateRecord( + sake, + input, + callback, + userdata + ); +} + +XRGAMESPY_API SAKERequest xrGS_sakeSearchForRecords(SAKE sake, + SAKESearchForRecordsInput * input, + SAKERequestCallback callback, + void * userData) +{ + return sakeSearchForRecords( + sake, + input, + callback, + userData + ); +} diff --git a/xrGameSpy/xrGameSpy_SAKE.h b/xrGameSpy/xrGameSpy_SAKE.h new file mode 100644 index 00000000000..49041155b8d --- /dev/null +++ b/xrGameSpy/xrGameSpy_SAKE.h @@ -0,0 +1,36 @@ +#ifndef XRGAMESPY_SAKE +#define XRGAMESPY_SAKE + +#include "xrGameSpy_MainDefs.h" +#include "GameSpy/sake/sake.h" + +extern "C" +{ + +EXPORT_FN_DECL(SAKEStartupResult, sakeStartup, (SAKE *sakePtr)); +EXPORT_FN_DECL(void, sakeShutdown, (SAKE sake)); +EXPORT_FN_DECL(void, sakeSetProfile, (SAKE sake, + int profileId, + const char *loginTicket)); +EXPORT_FN_DECL(SAKEStartRequestResult, sakeGetStartRequestResult, (SAKE sake)); +EXPORT_FN_DECL(SAKERequest, sakeGetMyRecords, (SAKE sake, + SAKEGetMyRecordsInput * input, + SAKERequestCallback callback, + void * userData)); +EXPORT_FN_DECL(SAKERequest, sakeCreateRecord, (SAKE sake, + SAKECreateRecordInput * input, + SAKERequestCallback callback, + void * userdata)); +EXPORT_FN_DECL(SAKERequest, sakeUpdateRecord, (SAKE sake, + SAKEUpdateRecordInput * input, + SAKERequestCallback callback, + void * userdata)); + +EXPORT_FN_DECL(SAKERequest, sakeSearchForRecords, (SAKE sake, + SAKESearchForRecordsInput * input, + SAKERequestCallback callback, + void * userData)); + +} //extern "C" + +#endif //#ifndef XRGAMESPY_SAKE \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_ServerBrowser.cpp b/xrGameSpy/xrGameSpy_ServerBrowser.cpp new file mode 100644 index 00000000000..13d2d858710 --- /dev/null +++ b/xrGameSpy/xrGameSpy_ServerBrowser.cpp @@ -0,0 +1,192 @@ +#include "stdafx.h" +#include "windows.h" +#include "xrGameSpy_MainDefs.h" + +#include "xrGameSpy_ServerBrowser.h" + +#include "gamespy/qr2/qr2regkeys.h" + +#define GAMETYPE_NAME_KEY 100 +#define DEDICATED_KEY 101 +#define G_USER_PASSWORD_KEY 135 + +static unsigned char Fields_Of_Interest[] = +{ + HOSTNAME_KEY, + HOSTPORT_KEY, + NUMPLAYERS_KEY, + MAXPLAYERS_KEY, + MAPNAME_KEY, + GAMETYPE_KEY, + GAMEVER_KEY, + PASSWORD_KEY, + G_USER_PASSWORD_KEY, + DEDICATED_KEY, + GAMETYPE_NAME_KEY +}; + +XRGAMESPY_API int xrGS_GetQueryVersion () +{ + return QVERSION_QR2; +} + +//XRGAMESPY_API ServerBrowser xrGS_ServerBrowserNew(const gsi_char *queryForGamename, const gsi_char *queryFromGamename, const gsi_char *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool bLAN_Only, ServerBrowserCallback callback, void *instance) +XRGAMESPY_API ServerBrowser xrGS_ServerBrowserNewA(SBBool bLAN_Only, ServerBrowserCallback callback, void *instance) +{ +// return ServerBrowserNew(queryForGamename, queryFromGamename, queryFromKey, queryFromVersion, maxConcUpdates, queryVersion, bLAN_Only, callback, instance); + char SecretKey[16]; + FillSecretKey(SecretKey); + return ServerBrowserNewA(GAMESPY_GAMENAME, GAMESPY_GAMENAME, SecretKey, 0, GAMESPY_BROWSER_MAX_UPDATES, xrGS_GetQueryVersion(), bLAN_Only, callback, instance); +} + +XRGAMESPY_API void xrGS_ServerBrowserFree (ServerBrowser sb) +{ + ServerBrowserFree (sb); +}; + +XRGAMESPY_API void xrGS_ServerBrowserClear(ServerBrowser sb) +{ + ServerBrowserClear(sb); +}; + +XRGAMESPY_API SBError xrGS_ServerBrowserThink(ServerBrowser sb) +{ + return ServerBrowserThink(sb); +}; + +XRGAMESPY_API SBState xrGS_ServerBrowserState(ServerBrowser sb) +{ + return ServerBrowserState(sb); +}; + +XRGAMESPY_API void xrGS_ServerBrowserHalt(ServerBrowser sb) +{ + ServerBrowserHalt(sb); +}; + +//XRGAMESPY_API SBError xrGS_ServerBrowserUpdate (ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const gsi_char *serverFilter) +XRGAMESPY_API SBError xrGS_ServerBrowserUpdateA(ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const gsi_char *serverFilter) +{ + + int numBasicFields = sizeof(Fields_Of_Interest)/sizeof(Fields_Of_Interest[0]); + return ServerBrowserUpdateA(sb, async, disconnectOnComplete, Fields_Of_Interest, numBasicFields, serverFilter); +}; + +XRGAMESPY_API void xrGS_ServerBrowserSortA(ServerBrowser sb, SBBool ascending, const char *sortkey, SBCompareMode comparemode) +{ + ServerBrowserSortA(sb, ascending, sortkey, comparemode); +}; + +//XRGAMESPY_API SBError xrGS_ServerBrowserLANUpdate(ServerBrowser sb, SBBool async, unsigned short startSearchPort, unsigned short endSearchPort) +XRGAMESPY_API SBError xrGS_ServerBrowserLANUpdate(ServerBrowser sb, SBBool async) +{ + return ServerBrowserLANUpdate(sb, async, START_PORT_LAN, END_PORT_LAN); +} + +XRGAMESPY_API int xrGS_ServerBrowserCount (ServerBrowser sb) +{ + return ServerBrowserCount (sb); +}; + +XRGAMESPY_API SBServer xrGS_ServerBrowserGetServer (ServerBrowser sb, int index) +{ + return ServerBrowserGetServer(sb, index); +} +XRGAMESPY_API SBServer xrGS_ServerBrowserGetServerByIPA(ServerBrowser sb, const gsi_char* ip, unsigned short port) +{ + return ServerBrowserGetServerByIPA(sb, ip, port); +}; + +XRGAMESPY_API char * xrGS_SBServerGetPublicAddress(SBServer server) +{ + return SBServerGetPublicAddress(server); +}; +XRGAMESPY_API unsigned short xrGS_SBServerGetPublicQueryPort(SBServer server) +{ + return SBServerGetPublicQueryPort(server); +}; +XRGAMESPY_API const gsi_char * xrGS_SBServerGetStringValueA(SBServer server, const gsi_char *keyname, const gsi_char *def) +{ + return SBServerGetStringValueA(server, keyname, def); +}; +XRGAMESPY_API int xrGS_SBServerGetIntValueA(SBServer server, const gsi_char *key, int idefault) +{ + return SBServerGetIntValueA(server, key, idefault); +}; +XRGAMESPY_API double xrGS_SBServerGetFloatValueA(SBServer server, const gsi_char *key, double fdefault) +{ + return SBServerGetFloatValueA(server, key, fdefault); +}; +XRGAMESPY_API SBBool xrGS_SBServerGetBoolValueA(SBServer server, const gsi_char *key, SBBool bdefault) +{ + return SBServerGetBoolValueA(server, key, bdefault); +}; +XRGAMESPY_API int xrGS_SBServerGetPing(SBServer server) +{ + return SBServerGetPing(server); +}; + +XRGAMESPY_API SBError xrGS_ServerBrowserAuxUpdateServer(ServerBrowser sb, SBServer server, SBBool async, SBBool fullUpdate) +{ + return ServerBrowserAuxUpdateServer(sb, server, async, fullUpdate); +} + +XRGAMESPY_API SBError xrGS_ServerBrowserAuxUpdateIPA(ServerBrowser sb, const gsi_char *ip, unsigned short port, SBBool viaMaster, SBBool async, SBBool fullUpdate) +{ + return ServerBrowserAuxUpdateIPA(sb, ip, port, viaMaster, async, fullUpdate); +} + +XRGAMESPY_API const gsi_char * xrGS_SBServerGetPlayerStringValueA(SBServer server, int playernum, const gsi_char *key, const gsi_char *sdefault) +{ + return SBServerGetPlayerStringValueA(server, playernum, key, sdefault); +} +XRGAMESPY_API int xrGS_SBServerGetPlayerIntValueA(SBServer server, int playernum, const gsi_char *key, int idefault) +{ + return SBServerGetPlayerIntValueA(server, playernum, key, idefault); +} +XRGAMESPY_API double xrGS_SBServerGetPlayerFloatValueA(SBServer server, int playernum, const gsi_char *key, double fdefault) +{ + return SBServerGetPlayerFloatValueA(server, playernum, key, fdefault); +} + +XRGAMESPY_API const gsi_char *xrGS_SBServerGetTeamStringValueA(SBServer server, int teamnum, const gsi_char *key, const gsi_char *sdefault) +{ + return SBServerGetTeamStringValueA(server, teamnum, key, sdefault); +} +XRGAMESPY_API int xrGS_SBServerGetTeamIntValueA(SBServer server, int teamnum, const gsi_char *key, int idefault) +{ + return SBServerGetTeamIntValueA(server, teamnum, key, idefault); +} +XRGAMESPY_API double xrGS_SBServerGetTeamFloatValueA(SBServer server, int teamnum, const gsi_char *key, double fdefault) +{ + return SBServerGetTeamFloatValueA(server, teamnum, key, fdefault); +} + +XRGAMESPY_API void xrGS_ServerBrowserRemoveIPA(ServerBrowser sb, const gsi_char *ip, unsigned short port) +{ + ServerBrowserRemoveIPA(sb, ip, port); +} +XRGAMESPY_API void xrGS_ServerBrowserRemoveServer(ServerBrowser sb, SBServer server) +{ + ServerBrowserRemoveServer(sb, server); +} + +XRGAMESPY_API SBBool xrGS_SBServerGetConnectionInfo(ServerBrowser sb, SBServer server, gsi_u16 PortToConnectTo, char *ipstring) +{ + return SBServerGetConnectionInfo( sb, server, PortToConnectTo, ipstring); +}; + +XRGAMESPY_API SBBool xrGS_SBServerDirectConnect (SBServer server) +{ + return SBServerDirectConnect (server); +}; + +XRGAMESPY_API SBBool xrGS_SBServerHasFullKeys (SBServer server) +{ + return SBServerHasFullKeys(server); +} + +XRGAMESPY_API const gsi_char* xrGS_ServerBrowserErrorDescA(ServerBrowser sb, SBError error) +{ + return ServerBrowserErrorDescA(sb, error); +} \ No newline at end of file diff --git a/xrGameSpy/xrGameSpy_ServerBrowser.h b/xrGameSpy/xrGameSpy_ServerBrowser.h new file mode 100644 index 00000000000..7367c0f3af1 --- /dev/null +++ b/xrGameSpy/xrGameSpy_ServerBrowser.h @@ -0,0 +1,56 @@ +#pragma once +#include "xrGameSpy_MainDefs.h" + +#include "GameSpy\ServerBrowsing\sb_serverbrowsing.h" + +extern "C" +{ + EXPORT_FN_DECL(int, GetQueryVersion, ()); +// EXPORT_FN_DECL(ServerBrowser, ServerBrowserNew, (const gsi_char *queryForGamename, const gsi_char *queryFromGamename, const gsi_char *queryFromKey, int queryFromVersion, int maxConcUpdates, int queryVersion, SBBool bLAN_Only, ServerBrowserCallback callback, void *instance)); + EXPORT_FN_DECL(ServerBrowser, ServerBrowserNewA, (SBBool bLAN_Only, ServerBrowserCallback callback, void *instance)); + EXPORT_FN_DECL(void, ServerBrowserFree, (ServerBrowser sb)); + EXPORT_FN_DECL(void, ServerBrowserClear, (ServerBrowser sb)); + + EXPORT_FN_DECL(SBError, ServerBrowserThink, (ServerBrowser sb)); + EXPORT_FN_DECL(SBState, ServerBrowserState, (ServerBrowser sb)); + EXPORT_FN_DECL(void, ServerBrowserHalt, (ServerBrowser sb)); +// EXPORT_FN_DECL(SBError, ServerBrowserUpdate, (ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const unsigned char *basicFields, int numBasicFields, const gsi_char *serverFilter)); + EXPORT_FN_DECL(SBError, ServerBrowserUpdateA, (ServerBrowser sb, SBBool async, SBBool disconnectOnComplete, const gsi_char *serverFilter)); + +// EXPORT_FN_DECL(SBError, ServerBrowserLANUpdate, (ServerBrowser sb, SBBool async, unsigned short startSearchPort, unsigned short endSearchPort)); + EXPORT_FN_DECL(SBError, ServerBrowserLANUpdate, (ServerBrowser sb, SBBool async)); + + EXPORT_FN_DECL(int, ServerBrowserCount, (ServerBrowser sb)); + EXPORT_FN_DECL(SBServer, ServerBrowserGetServer, (ServerBrowser sb, int index)); + EXPORT_FN_DECL(SBServer, ServerBrowserGetServerByIPA, (ServerBrowser sb, const gsi_char* ip, unsigned short port)); + + + EXPORT_FN_DECL(char *, SBServerGetPublicAddress, (SBServer server)); + EXPORT_FN_DECL(unsigned short, SBServerGetPublicQueryPort, (SBServer server)); + EXPORT_FN_DECL(const gsi_char *, SBServerGetStringValueA, (SBServer server, const gsi_char *keyname, const gsi_char *def)); + EXPORT_FN_DECL(int, SBServerGetIntValueA, (SBServer server, const gsi_char *key, int idefault)); + EXPORT_FN_DECL(double, SBServerGetFloatValueA, (SBServer server, const gsi_char *key, double fdefault)); + EXPORT_FN_DECL(SBBool, SBServerGetBoolValueA, (SBServer server, const gsi_char *key, SBBool bdefault)); + EXPORT_FN_DECL(int, SBServerGetPing, (SBServer server)); + + EXPORT_FN_DECL(SBError, ServerBrowserAuxUpdateServer, (ServerBrowser sb, SBServer server, SBBool async, SBBool fullUpdate)); + EXPORT_FN_DECL(SBError, ServerBrowserAuxUpdateIPA, (ServerBrowser sb, const gsi_char *ip, unsigned short port, SBBool viaMaster, SBBool async, SBBool fullUpdate)); + + EXPORT_FN_DECL(const gsi_char *, SBServerGetPlayerStringValueA, (SBServer server, int playernum, const gsi_char *key, const gsi_char *sdefault)); + EXPORT_FN_DECL(int, SBServerGetPlayerIntValueA, (SBServer server, int playernum, const gsi_char *key, int idefault)); + EXPORT_FN_DECL(double, SBServerGetPlayerFloatValueA, (SBServer server, int playernum, const gsi_char *key, double fdefault)); + + EXPORT_FN_DECL(const gsi_char *, SBServerGetTeamStringValueA, (SBServer server, int teamnum, const gsi_char *key, const gsi_char *sdefault)); + EXPORT_FN_DECL(int, SBServerGetTeamIntValueA, (SBServer server, int teamnum, const gsi_char *key, int idefault)); + EXPORT_FN_DECL(double, SBServerGetTeamFloatValueA, (SBServer server, int teamnum, const gsi_char *key, double fdefault)); + + EXPORT_FN_DECL(void, ServerBrowserRemoveIPA, (ServerBrowser sb, const gsi_char *ip, unsigned short port)); + EXPORT_FN_DECL(void, ServerBrowserRemoveServer, (ServerBrowser sb, SBServer server)); + + EXPORT_FN_DECL(SBBool, SBServerGetConnectionInfo, (ServerBrowser sb, SBServer server, gsi_u16 PortToConnectTo, char *ipstring)); + EXPORT_FN_DECL(SBBool, SBServerDirectConnect, (SBServer server)); + EXPORT_FN_DECL(void, ServerBrowserSortA, (ServerBrowser sb, SBBool ascending, const char *sortkey, SBCompareMode comparemode)); + + EXPORT_FN_DECL(SBBool, SBServerHasFullKeys, (SBServer server)); + EXPORT_FN_DECL(const gsi_char*, ServerBrowserErrorDescA, (ServerBrowser sb, SBError error)); +} \ No newline at end of file diff --git a/xrNetServer/NET_AuthCheck.cpp b/xrNetServer/NET_AuthCheck.cpp new file mode 100644 index 00000000000..d42bcd8ab6b --- /dev/null +++ b/xrNetServer/NET_AuthCheck.cpp @@ -0,0 +1,61 @@ +#include "stdafx.h" +#include "NET_AuthCheck.h" + +void XRNETSERVER_API fill_auth_check_params(xr_auth_strings_t & ignore, + xr_auth_strings_t & check) +{ + string_path config; + LPCSTR pth = FS.get_path("$app_data_root$")->m_Path; + ignore.push_back (shared_str(pth)); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "localization.ltx"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "fonts.ltx"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "items.ltx"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "text"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "gameplay"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "ui"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "scripts"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_config$", "misc\\script_sound_pripyat.ltx"))); + ignore.push_back (shared_str(FS.update_path(config, "$game_scripts$", "state_mgr_pri_a15.script"))); + + check.push_back (shared_str(FS.update_path(config, "$game_config$", ""))); + check.push_back (shared_str(FS.update_path(config, "$game_scripts$", ""))); + check.push_back (shared_str(FS.update_path(config, "$game_shaders$", ""))); + //sounds + check.push_back (shared_str(FS.update_path(config, "$game_sounds$", "material"))); + check.push_back (shared_str(FS.update_path(config, "$game_sounds$", "weapons"))); + + // check scopes + check.push_back (shared_str(FS.update_path(config, "$game_textures$", "wpn\\wpn_crosshair.dds"))); + check.push_back (shared_str(FS.update_path(config, "$game_textures$", "wpn\\wpn_crosshair_bino.dds"))); + check.push_back (shared_str(FS.update_path(config, "$game_textures$", "wpn\\wpn_crosshair_g36.dds"))); + check.push_back (shared_str(FS.update_path(config, "$game_textures$", "wpn\\wpn_crosshair_l85.dds"))); + check.push_back (shared_str(FS.update_path(config, "$game_textures$", "wpn\\wpn_crosshair_rpg.dds"))); + + check.push_back (shared_str("xrd3d9-null.dll")); + check.push_back (shared_str("ode.dll")); + check.push_back (shared_str("xrcdb.dll")); + check.push_back (shared_str("xrcore.dll")); +// check.push_back (shared_str("xrcpu_pipe.dll")); +// check.push_back (shared_str("xrgame.dll")); + check.push_back (shared_str("xrgamespy.dll")); + check.push_back (shared_str("xrlua.dll")); + check.push_back (shared_str("xrnetserver.dll")); + check.push_back (shared_str("xrparticles.dll")); + check.push_back (shared_str("xrrender_r1.dll")); + check.push_back (shared_str("xrrender_r2.dll")); + check.push_back (shared_str("xrsound.dll")); + check.push_back (shared_str("xrxmlparser.dll")); +// check.push_back (shared_str("xrEngine.exe")); +} + +bool XRNETSERVER_API allow_to_include_path (xr_auth_strings_t const & ignore, + LPCSTR path) +{ + for (xr_auth_strings_t::const_iterator i = ignore.begin(), + ie = ignore.end(); i != ie; ++i) + { + if (!strncmp(i->c_str(), path, i->size())) + return false; + } + return true; +} \ No newline at end of file diff --git a/xrNetServer/NET_AuthCheck.h b/xrNetServer/NET_AuthCheck.h new file mode 100644 index 00000000000..69f374e269f --- /dev/null +++ b/xrNetServer/NET_AuthCheck.h @@ -0,0 +1,12 @@ +#ifndef NET_AUTH_CHECK_INCLUDED +#define NET_AUTH_CHECK_INCLUDED + +#include "net_shared.h" + +typedef xr_vector xr_auth_strings_t; +void XRNETSERVER_API fill_auth_check_params (xr_auth_strings_t & ignore, + xr_auth_strings_t & check); +bool XRNETSERVER_API allow_to_include_path (xr_auth_strings_t const & ignore, + LPCSTR path); + +#endif//#ifndef NET_AUTH_CHECK_INCLUDED \ No newline at end of file diff --git a/xrNetServer/NET_Client.cpp b/xrNetServer/NET_Client.cpp new file mode 100644 index 00000000000..b8264a622bd --- /dev/null +++ b/xrNetServer/NET_Client.cpp @@ -0,0 +1,1181 @@ +#include "stdafx.h" +#include "NET_Common.h" +#include "net_client.h" +#include "net_server.h" +#include "net_messages.h" +#include "NET_Log.h" + +#include "../xrGameSpy/xrGameSpy_MainDefs.h" + +#pragma warning(push) +#pragma warning(disable:4995) +#include +#include "dxerr.h" + +//#pragma warning(pop) + +// {0218FA8B-515B-4bf2-9A5F-2F079D1759F3} +static const GUID NET_GUID = +{ 0x218fa8b, 0x515b, 0x4bf2, { 0x9a, 0x5f, 0x2f, 0x7, 0x9d, 0x17, 0x59, 0xf3 } }; + +// {8D3F9E5E-A3BD-475b-9E49-B0E77139143C} +static const GUID CLSID_NETWORKSIMULATOR_DP8SP_TCPIP = +{ 0x8d3f9e5e, 0xa3bd, 0x475b, { 0x9e, 0x49, 0xb0, 0xe7, 0x71, 0x39, 0x14, 0x3c } }; + +const GUID CLSID_DirectPlay8Client = +{ 0x743f1dc6, 0x5aba, 0x429f, { 0x8b, 0xdf, 0xc5, 0x4d, 0x03, 0x25, 0x3d, 0xc2 } }; + +// {DA825E1B-6830-43d7-835D-0B5AD82956A2} +const GUID CLSID_DirectPlay8Server = +{ 0xda825e1b, 0x6830, 0x43d7, { 0x83, 0x5d, 0x0b, 0x5a, 0xd8, 0x29, 0x56, 0xa2 } }; + +// {286F484D-375E-4458-A272-B138E2F80A6A} +const GUID CLSID_DirectPlay8Peer = +{ 0x286f484d, 0x375e, 0x4458, { 0xa2, 0x72, 0xb1, 0x38, 0xe2, 0xf8, 0x0a, 0x6a } }; + + +// CLSIDs added for DirectX 9 + +// {FC47060E-6153-4b34-B975-8E4121EB7F3C} +const GUID CLSID_DirectPlay8ThreadPool = +{ 0xfc47060e, 0x6153, 0x4b34, { 0xb9, 0x75, 0x8e, 0x41, 0x21, 0xeb, 0x7f, 0x3c } }; + +// {E4C1D9A2-CBF7-48bd-9A69-34A55E0D8941} +const GUID CLSID_DirectPlay8NATResolver = +{ 0xe4c1d9a2, 0xcbf7, 0x48bd, { 0x9a, 0x69, 0x34, 0xa5, 0x5e, 0x0d, 0x89, 0x41 } }; + +/**************************************************************************** + * + * DirectPlay8 Interface IIDs + * + ****************************************************************************/ + +typedef REFIID DP8REFIID; + + +// {5102DACD-241B-11d3-AEA7-006097B01411} +const GUID IID_IDirectPlay8Client = +{ 0x5102dacd, 0x241b, 0x11d3, { 0xae, 0xa7, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + +// {5102DACE-241B-11d3-AEA7-006097B01411} +const GUID IID_IDirectPlay8Server = +{ 0x5102dace, 0x241b, 0x11d3, { 0xae, 0xa7, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + +// {5102DACF-241B-11d3-AEA7-006097B01411} +const GUID IID_IDirectPlay8Peer = +{ 0x5102dacf, 0x241b, 0x11d3, { 0xae, 0xa7, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + + +// IIDs added for DirectX 9 + +// {0D22EE73-4A46-4a0d-89B2-045B4D666425} +const GUID IID_IDirectPlay8ThreadPool = +{ 0xd22ee73, 0x4a46, 0x4a0d, { 0x89, 0xb2, 0x04, 0x5b, 0x4d, 0x66, 0x64, 0x25 } }; + +// {A9E213F2-9A60-486f-BF3B-53408B6D1CBB} +const GUID IID_IDirectPlay8NATResolver = +{ 0xa9e213f2, 0x9a60, 0x486f, { 0xbf, 0x3b, 0x53, 0x40, 0x8b, 0x6d, 0x1c, 0xbb } }; + +// {53934290-628D-11D2-AE0F-006097B01411} +const GUID CLSID_DP8SP_IPX = +{ 0x53934290, 0x628d, 0x11d2, { 0xae, 0x0f, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + + +// {6D4A3650-628D-11D2-AE0F-006097B01411} +const GUID CLSID_DP8SP_MODEM = +{ 0x6d4a3650, 0x628d, 0x11d2, { 0xae, 0x0f, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + + +// {743B5D60-628D-11D2-AE0F-006097B01411} +const GUID CLSID_DP8SP_SERIAL = +{ 0x743b5d60, 0x628d, 0x11d2, { 0xae, 0x0f, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + + +// {EBFE7BA0-628D-11D2-AE0F-006097B01411} +const GUID CLSID_DP8SP_TCPIP = +{ 0xebfe7ba0, 0x628d, 0x11d2, { 0xae, 0x0f, 0x00, 0x60, 0x97, 0xb0, 0x14, 0x11 } }; + + +// Service providers added for DirectX 9 + + +// {995513AF-3027-4b9a-956E-C772B3F78006} +const GUID CLSID_DP8SP_BLUETOOTH = +{ 0x995513af, 0x3027, 0x4b9a, { 0x95, 0x6e, 0xc7, 0x72, 0xb3, 0xf7, 0x80, 0x06 } }; + +const GUID CLSID_DirectPlay8Address = +{ 0x934a9523, 0xa3ca, 0x4bc5, { 0xad, 0xa0, 0xd6, 0xd9, 0x5d, 0x97, 0x94, 0x21 } }; + +const GUID IID_IDirectPlay8Address = +{ 0x83783300, 0x4063, 0x4c8a, { 0x9d, 0xb3, 0x82, 0x83, 0x0a, 0x7f, 0xeb, 0x31 } }; + +static INetLog* pClNetLog = NULL; + +void dump_URL (LPCSTR p, IDirectPlay8Address* A) +{ + string256 aaaa; + DWORD aaaa_s = sizeof(aaaa); + R_CHK (A->GetURLA(aaaa,&aaaa_s)); + Log (p,aaaa); +} + +// +INetQueue::INetQueue() +#ifdef PROFILE_CRITICAL_SECTIONS + :cs(MUTEX_PROFILE_ID(INetQueue)) +#endif // PROFILE_CRITICAL_SECTIONS +{ + unused.reserve (128); + for (int i=0; i<16; i++) + unused.push_back (xr_new()); +} + +INetQueue::~INetQueue() +{ + cs.Enter (); + u32 it; + for (it=0; it ()); + P = ready.back (); + //--------------------------------------------- + LastTimeCreate = GetTickCount(); + //--------------------------------------------- + } else { + ready.push_back (unused.back()); + unused.pop_back (); + P = ready.back (); + } + //cs.Leave (); + return P; +} +NET_Packet* INetQueue::Create (const NET_Packet& _other) +{ + NET_Packet* P = 0; + cs.Enter (); +//#ifdef _DEBUG +// Msg ("- INetQueue::Create - ready %d, unused %d", ready.size(), unused.size()); +//#endif + if (unused.empty()) + { + ready.push_back (xr_new ()); + P = ready.back (); + //--------------------------------------------- + LastTimeCreate = GetTickCount(); + //--------------------------------------------- + } else { + ready.push_back (unused.back()); + unused.pop_back (); + P = ready.back (); + } + CopyMemory (P,&_other,sizeof(NET_Packet)); + cs.Leave (); + return P; +} +NET_Packet* INetQueue::Retreive () +{ + NET_Packet* P = 0; + //cs.Enter (); +//#ifdef _DEBUG +// Msg ("INetQueue::Retreive - ready %d, unused %d", ready.size(), unused.size()); +//#endif + if (!ready.empty()) P = ready.front(); + //--------------------------------------------- + else + { + u32 tmp_time = GetTickCount()-60000; + u32 size = unused.size(); + if ((LastTimeCreate < tmp_time) && (size > 32)) + { + xr_delete(unused.back()); + unused.pop_back(); + } + } + //--------------------------------------------- + //cs.Leave (); + return P; +} +void INetQueue::Release () +{ + //cs.Enter (); +//#ifdef _DEBUG +// Msg ("INetQueue::Release - ready %d, unused %d", ready.size(), unused.size()); +//#endif + VERIFY (!ready.empty()); + //--------------------------------------------- + u32 tmp_time = GetTickCount()-60000; + u32 size = unused.size(); + ready.front()->B.count = 0; + if ((LastTimeCreate < tmp_time) && (size > 32)) + { + xr_delete(ready.front()); + } + else + unused.push_back(ready.front()); + //--------------------------------------------- + ready.pop_front (); + //cs.Leave (); +} + +// +const u32 syncQueueSize = 512; +const int syncSamples = 256; +class XRNETSERVER_API syncQueue +{ + u32 table [syncQueueSize]; + u32 write; + u32 count; +public: + syncQueue() { clear(); } + + IC void push (u32 value) + { + table[write++] = value; + if (write == syncQueueSize) write = 0; + + if (count <= syncQueueSize) count++; + } + IC u32* begin () { return table; } + IC u32* end () { return table+count; } + IC u32 size () { return count; } + IC void clear () { write=0; count=0; } +} net_DeltaArray; + +//------- +XRNETSERVER_API Flags32 psNET_Flags = {0}; +XRNETSERVER_API int psNET_ClientUpdate = 30; // FPS +XRNETSERVER_API int psNET_ClientPending = 2; +XRNETSERVER_API char psNET_Name[32] = "Player"; +XRNETSERVER_API BOOL psNET_direct_connect = FALSE; + +/**************************************************************************** + * + * DirectPlay8 Service Provider GUIDs + * + ****************************************************************************/ + + + + +static HRESULT WINAPI Handler (PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage) +{ + IPureClient* C = (IPureClient*)pvUserContext; + return C->net_Handler(dwMessageType,pMessage); +} + + + +//------------------------------------------------------------------------------ + +void +IPureClient::_SendTo_LL( const void* data, u32 size, u32 flags, u32 timeout ) +{ + IPureClient::SendTo_LL( const_cast(data), size, flags, timeout ); +} + + +//------------------------------------------------------------------------------ + +void +IPureClient::_Recieve( const void* data, u32 data_size, u32 /*param*/ ) +{ + MSYS_PING* cfg = (MSYS_PING*)data; + net_Statistic.dwBytesReceived += data_size; + + if( (data_size>=2*sizeof(u32)) + && (cfg->sign1==0x12071980) + && (cfg->sign2==0x26111975) + ) + { + // Internal system message + if( (data_size == sizeof(MSYS_PING)) ) + { + // It is reverted(server) ping + u32 time = TimerAsync( device_timer ); + u32 ping = time - (cfg->dwTime_ClientSend); + u32 delta = cfg->dwTime_Server + ping/2 - time; + + net_DeltaArray.push ( delta ); + Sync_Average (); + return; + } + + if ( data_size == sizeof(MSYS_CONFIG) ) + { + net_Connected = EnmConnectionCompleted; + return; + } + Msg( "! Unknown system message" ); + return; + } + else if( net_Connected == EnmConnectionCompleted ) + { + // one of the messages - decompress it + + if( psNET_Flags.test( NETFLAG_LOG_CL_PACKETS ) ) + { + if( !pClNetLog ) + pClNetLog = xr_new("logs\\net_cl_log.log", timeServer()); + + if( pClNetLog ) + pClNetLog->LogData( timeServer(), const_cast(data), data_size, TRUE ); + } + + OnMessage( const_cast(data), data_size ); + } +} + +//============================================================================== + +IPureClient::IPureClient (CTimer* timer): net_Statistic(timer) +#ifdef PROFILE_CRITICAL_SECTIONS + ,net_csEnumeration(MUTEX_PROFILE_ID(IPureClient::net_csEnumeration)) +#endif // PROFILE_CRITICAL_SECTIONS +{ + NET = NULL; + net_Address_server = NULL; + net_Address_device = NULL; + device_timer = timer; + net_TimeDelta_User = 0; + net_Time_LastUpdate = 0; + net_TimeDelta = 0; + net_TimeDelta_Calculated = 0; + + pClNetLog = NULL;//xr_new("logs\\net_cl_log.log", timeServer()); + +} + +IPureClient::~IPureClient () +{ + xr_delete(pClNetLog); pClNetLog = NULL; + psNET_direct_connect = FALSE; +} + +BOOL IPureClient::Connect (LPCSTR options) +{ + R_ASSERT (options); + net_Disconnected = FALSE; + +if(!psNET_direct_connect) +{ + // + string256 server_name = ""; +// xr_strcpy (server_name,options); + if (strchr(options, '/')) + strncpy_s(server_name,options, strchr(options, '/')-options); + if (strchr(server_name,'/')) *strchr(server_name,'/') = 0; + + string64 password_str = ""; + if (strstr(options, "psw=")) + { + const char* PSW = strstr(options, "psw=") + 4; + if (strchr(PSW, '/')) + strncpy_s(password_str, PSW, strchr(PSW, '/') - PSW); + else + xr_strcpy(password_str, PSW); + } + + string64 user_name_str = ""; + if (strstr(options, "name=")) + { + const char* NM = strstr(options, "name=") + 5; + if (strchr(NM, '/')) + strncpy_s(user_name_str, NM, strchr(NM, '/') - NM); + else + xr_strcpy(user_name_str, NM); + } + + string64 user_pass = ""; + if (strstr(options, "pass=")) + { + const char* UP = strstr(options, "pass=") + 5; + if (strchr(UP, '/')) + strncpy_s(user_pass, UP, strchr(UP, '/') - UP); + else + xr_strcpy(user_pass, UP); + } + + int psSV_Port = START_PORT_LAN_SV; + if (strstr(options, "port=")) + { + string64 portstr; + xr_strcpy(portstr, strstr(options, "port=")+5); + if (strchr(portstr,'/')) *strchr(portstr,'/') = 0; + psSV_Port = atol(portstr); + clamp(psSV_Port, int(START_PORT), int(END_PORT)); + }; + + BOOL bPortWasSet = FALSE; + int psCL_Port = START_PORT_LAN_CL; + if (strstr(options, "portcl=")) + { + string64 portstr; + xr_strcpy(portstr, strstr(options, "portcl=")+7); + if (strchr(portstr,'/')) *strchr(portstr,'/') = 0; + psCL_Port = atol(portstr); + clamp(psCL_Port, int(START_PORT), int(END_PORT)); + bPortWasSet = TRUE; + }; +// Msg("* Client connect on port %d\n",psNET_Port); + + // + net_Connected = EnmConnectionWait; + net_Syncronised = FALSE; + net_Disconnected= FALSE; + + //--------------------------- + string1024 tmp=""; +// HRESULT CoInitializeExRes = CoInitializeEx(NULL, 0); +// if (CoInitializeExRes != S_OK && CoInitializeExRes != S_FALSE) +// { +// DXTRACE_ERR(tmp, CoInitializeExRes); +// CHK_DX(CoInitializeExRes); +// }; + //--------------------------- + // Create the IDirectPlay8Client object. + HRESULT CoCreateInstanceRes = CoCreateInstance (CLSID_DirectPlay8Client, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Client, (LPVOID*) &NET); + //--------------------------- + if (CoCreateInstanceRes != S_OK) + { + DXTRACE_ERR(tmp, CoCreateInstanceRes ); + CHK_DX(CoCreateInstanceRes ); + } + //--------------------------- + + // Initialize IDirectPlay8Client object. +#ifdef DEBUG + R_CHK(NET->Initialize (this, Handler, 0)); +#else + R_CHK(NET->Initialize (this, Handler, DPNINITIALIZE_DISABLEPARAMVAL )); +#endif + BOOL bSimulator = FALSE; + if (strstr(Core.Params,"-netsim")) bSimulator = TRUE; + + // Create our IDirectPlay8Address Device Address, --- Set the SP for our Device Address + net_Address_device = NULL; + R_CHK(CoCreateInstance (CLSID_DirectPlay8Address,NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address,(LPVOID*) &net_Address_device )); + R_CHK(net_Address_device->SetSP(bSimulator? &CLSID_NETWORKSIMULATOR_DP8SP_TCPIP : &CLSID_DP8SP_TCPIP )); + + // Create our IDirectPlay8Address Server Address, --- Set the SP for our Server Address + WCHAR ServerNameUNICODE [256]; + R_CHK(MultiByteToWideChar(CP_ACP, 0, server_name, -1, ServerNameUNICODE, 256 )); + + net_Address_server = NULL; + R_CHK(CoCreateInstance (CLSID_DirectPlay8Address,NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address,(LPVOID*) &net_Address_server )); + R_CHK(net_Address_server->SetSP (bSimulator? &CLSID_NETWORKSIMULATOR_DP8SP_TCPIP : &CLSID_DP8SP_TCPIP )); + R_CHK(net_Address_server->AddComponent (DPNA_KEY_HOSTNAME, ServerNameUNICODE, 2*u32(wcslen(ServerNameUNICODE) + 1), DPNA_DATATYPE_STRING )); + R_CHK(net_Address_server->AddComponent (DPNA_KEY_PORT, &psSV_Port, sizeof(psSV_Port), DPNA_DATATYPE_DWORD )); + + + // Debug + // dump_URL ("! cl ", net_Address_device); + // dump_URL ("! en ", net_Address_server); + + // Now set up the Application Description + DPN_APPLICATION_DESC dpAppDesc; + ZeroMemory (&dpAppDesc, sizeof(DPN_APPLICATION_DESC)); + dpAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); + dpAppDesc.guidApplication = NET_GUID; + + // Setup client info + /*xr_strcpy( tmp, server_name ); + xr_strcat( tmp, "/name=" ); + xr_strcat( tmp, user_name_str ); + xr_strcat( tmp, "/" );*/ + + WCHAR ClientNameUNICODE [256]; + R_CHK(MultiByteToWideChar (CP_ACP, 0, user_name_str, -1, ClientNameUNICODE, 256 )); + + { + DPN_PLAYER_INFO Pinfo; + ZeroMemory (&Pinfo,sizeof(Pinfo)); + Pinfo.dwSize = sizeof(Pinfo); + Pinfo.dwInfoFlags = DPNINFO_NAME|DPNINFO_DATA; + Pinfo.pwszName = ClientNameUNICODE; + + SClientConnectData cl_data; + cl_data.process_id = GetCurrentProcessId(); + xr_strcpy( cl_data.name, user_name_str ); + xr_strcpy( cl_data.pass, user_pass ); + + Pinfo.pvData = &cl_data; + Pinfo.dwDataSize = sizeof(cl_data); + + R_CHK(NET->SetClientInfo (&Pinfo,0,0,DPNSETCLIENTINFO_SYNC)); + } + if ( stricmp( server_name, "localhost" ) == 0 ) + { + WCHAR SessionPasswordUNICODE[4096]; + if ( xr_strlen( password_str ) ) + { + CHK_DX(MultiByteToWideChar (CP_ACP, 0, password_str, -1, SessionPasswordUNICODE, 4096 )); + dpAppDesc.dwFlags |= DPNSESSION_REQUIREPASSWORD; + dpAppDesc.pwszPassword = SessionPasswordUNICODE; + }; + + u32 c_port = u32(psCL_Port); + HRESULT res = S_FALSE; + while (res != S_OK) + { + R_CHK(net_Address_device->AddComponent (DPNA_KEY_PORT, &c_port, sizeof(c_port), DPNA_DATATYPE_DWORD )); + res = NET->Connect( + &dpAppDesc, // pdnAppDesc + net_Address_server, // pHostAddr + net_Address_device, // pDeviceInfo + NULL, // pdnSecurity + NULL, // pdnCredentials + NULL, 0, // pvUserConnectData/Size + NULL, // pvAsyncContext + NULL, // pvAsyncHandle + DPNCONNECT_SYNC); // dwFlags + if (res != S_OK) + { + // xr_string res = Debug.error2string(HostSuccess); + + if (bPortWasSet) + { + Msg("! IPureClient : port %d is BUSY!", c_port); + return FALSE; + } + else + { + Msg("! IPureClient : port %d is BUSY!", c_port); + } + + c_port++; + if (c_port > END_PORT_LAN) + { + return FALSE; + } + } + else + { + Msg("- IPureClient : created on port %d!", c_port); + } + }; + +// R_CHK(res); + if (res != S_OK) return FALSE; + + // Create ONE node + HOST_NODE NODE; + ZeroMemory (&NODE, sizeof(HOST_NODE)); + + // Copy the Host Address + R_CHK (net_Address_server->Duplicate(&NODE.pHostAddress ) ); + + // Retreive session name + char desc[4096]; + ZeroMemory (desc,sizeof(desc)); + DPN_APPLICATION_DESC* dpServerDesc=(DPN_APPLICATION_DESC*)desc; + DWORD dpServerDescSize=sizeof(desc); + dpServerDesc->dwSize = sizeof(DPN_APPLICATION_DESC); + R_CHK (NET->GetApplicationDesc(dpServerDesc,&dpServerDescSize,0)); + if (!dpServerDesc->dwApplicationReservedDataSize || !dpServerDesc->pvApplicationReservedData) + { + OnInvalidHost(); + return FALSE; + } + CopyMemory(&m_game_description, dpServerDesc->pvApplicationReservedData, + dpServerDesc->dwApplicationReservedDataSize); + if( dpServerDesc->pwszSessionName) { + string4096 dpSessionName; + R_CHK(WideCharToMultiByte(CP_ACP,0,dpServerDesc->pwszSessionName,-1,dpSessionName,sizeof(dpSessionName),0,0)); + NODE.dpSessionName = (char*)(&dpSessionName[0]); + } + net_Hosts.push_back (NODE); + } else { + string64 EnumData; + EnumData[0] = 0; + xr_strcat (EnumData, "ToConnect"); + DWORD EnumSize = xr_strlen(EnumData) + 1; + // We now have the host address so lets enum + u32 c_port = psCL_Port; + HRESULT res = S_FALSE; + while (res != S_OK && c_port <=END_PORT) + { + R_CHK(net_Address_device->AddComponent (DPNA_KEY_PORT, &c_port, sizeof(c_port), DPNA_DATATYPE_DWORD )); + + res = NET->EnumHosts( + &dpAppDesc, // pApplicationDesc - for unknown reason + net_Address_server, // pdpaddrHost + net_Address_device, // pdpaddrDeviceInfo + EnumData, EnumSize, // pvUserEnumData, size + 10, // dwEnumCount + 1000, // dwRetryInterval + 1000, // dwTimeOut + NULL, // pvUserContext + NULL, // pAsyncHandle + DPNENUMHOSTS_SYNC // dwFlags + ); + if (res != S_OK) + { + // xr_string res = Debug.error2string(HostSuccess); + switch (res) + { + case DPNERR_INVALIDHOSTADDRESS: + { + OnInvalidHost(); + return FALSE; + }break; + case DPNERR_SESSIONFULL: + { + OnSessionFull(); + return FALSE; + }break; + }; + + if (bPortWasSet) + { + Msg("! IPureClient : port %d is BUSY!", c_port); + return FALSE; + } +#ifdef DEBUG + else + Msg("! IPureClient : port %d is BUSY!", c_port); + +// const char* x = DXGetErrorString9(res); + string1024 tmp = ""; + DXTRACE_ERR(tmp, res); +#endif + c_port++; + } + else + { + Msg("- IPureClient : created on port %d!", c_port); + } + }; + + + // ****** Connection + IDirectPlay8Address* pHostAddress = NULL; + if (net_Hosts.empty()) + { + OnInvalidHost(); + return FALSE; + }; + + WCHAR SessionPasswordUNICODE[4096]; + if ( xr_strlen( password_str) ) + { + CHK_DX(MultiByteToWideChar(CP_ACP, 0, password_str, -1, SessionPasswordUNICODE, 4096 )); + dpAppDesc.dwFlags |= DPNSESSION_REQUIREPASSWORD; + dpAppDesc.pwszPassword = SessionPasswordUNICODE; + }; + + net_csEnumeration.Enter (); + // real connect + for (u32 I=0; IDuplicate(&pHostAddress ) ); + // dump_URL ("! c2s ", pHostAddress); + res = NET->Connect( + &dpAppDesc, // pdnAppDesc + pHostAddress, // pHostAddr + net_Address_device, // pDeviceInfo + NULL, // pdnSecurity + NULL, // pdnCredentials + NULL, 0, // pvUserConnectData/Size + NULL, // pvAsyncContext + NULL, // pvAsyncHandle + DPNCONNECT_SYNC); // dwFlags +// R_CHK(res); + net_csEnumeration.Leave (); + _RELEASE (pHostAddress); +#ifdef DEBUG +// const char* x = DXGetErrorString9(res); + string1024 tmp = ""; + DXTRACE_ERR(tmp, res); +#endif + switch (res) + { + case DPNERR_INVALIDPASSWORD: + { + OnInvalidPassword(); + }break; + case DPNERR_SESSIONFULL: + { + OnSessionFull(); + }break; + case DPNERR_CANTCREATEPLAYER: + { + Msg("! Error: Can\'t create player"); + }break; + } + if (res != S_OK) return FALSE; + } + + // Caps + /* + GUID sp_guid; + DPN_SP_CAPS sp_caps; + + net_Address_device->GetSP(&sp_guid); + ZeroMemory (&sp_caps,sizeof(sp_caps)); + sp_caps.dwSize = sizeof(sp_caps); + R_CHK (NET->GetSPCaps(&sp_guid,&sp_caps,0)); + sp_caps.dwSystemBufferSize = 0; + R_CHK (NET->SetSPCaps(&sp_guid,&sp_caps,0)); + R_CHK (NET->GetSPCaps(&sp_guid,&sp_caps,0)); + */ +} //psNET_direct_connect + // Sync + net_TimeDelta = 0; + return TRUE; +} + +void IPureClient::Disconnect() +{ + if( NET ) NET->Close(0); + + // Clean up Host _list_ + net_csEnumeration.Enter (); + for (u32 i=0; ipApplicationDescription; + + if (pDesc->dwApplicationReservedDataSize && pDesc->pvApplicationReservedData) + { + R_ASSERT(pDesc->dwApplicationReservedDataSize == sizeof(m_game_description)); + CopyMemory(&m_game_description, pDesc->pvApplicationReservedData, + pDesc->dwApplicationReservedDataSize); + } + + // Insert each host response if it isn't already present + net_csEnumeration.Enter (); + BOOL bHostRegistered = FALSE; + for (u32 I=0; IguidInstance == N.dpAppDesc.guidInstance) + { + // This host is already in the list + bHostRegistered = TRUE; + break; + } + } + + if (!bHostRegistered) + { + // This host session is not in the list then so insert it. + HOST_NODE NODE; + ZeroMemory (&NODE, sizeof(HOST_NODE)); + + // Copy the Host Address + R_CHK (pEnumHostsResponseMsg->pAddressSender->Duplicate(&NODE.pHostAddress ) ); + CopyMemory(&NODE.dpAppDesc,pDesc,sizeof(DPN_APPLICATION_DESC)); + + // Null out all the pointers we aren't copying + NODE.dpAppDesc.pwszSessionName = NULL; + NODE.dpAppDesc.pwszPassword = NULL; + NODE.dpAppDesc.pvReservedData = NULL; + NODE.dpAppDesc.dwReservedDataSize = 0; + NODE.dpAppDesc.pvApplicationReservedData = NULL; + NODE.dpAppDesc.dwApplicationReservedDataSize = 0; + + if( pDesc->pwszSessionName) { + string4096 dpSessionName; + R_CHK (WideCharToMultiByte(CP_ACP,0,pDesc->pwszSessionName,-1,dpSessionName,sizeof(dpSessionName),0,0)); + NODE.dpSessionName = (char*)(&dpSessionName[0]); + } + + net_Hosts.push_back (NODE); + + } + net_csEnumeration.Leave (); + } + break; + + case DPN_MSGID_RECEIVE: + { + PDPNMSG_RECEIVE pMsg = (PDPNMSG_RECEIVE) pMessage; + + MultipacketReciever::RecievePacket( pMsg->pReceiveData, pMsg->dwReceiveDataSize ); + } + break; + case DPN_MSGID_TERMINATE_SESSION: + { + PDPNMSG_TERMINATE_SESSION pMsg = (PDPNMSG_TERMINATE_SESSION ) pMessage; + char* m_data = (char*)pMsg->pvTerminateData; + u32 m_size = pMsg->dwTerminateDataSize; + HRESULT m_hResultCode = pMsg->hResultCode; + + net_Disconnected = TRUE; + + if (m_size != 0) + { + OnSessionTerminate(m_data); +#ifdef DEBUG + Msg("- Session terminated : %s", m_data); +#endif + } + else + { +#ifdef DEBUG + OnSessionTerminate( (::Debug.error2string(m_hResultCode))); + Msg("- Session terminated : %s", (::Debug.error2string(m_hResultCode))); +#endif + } + }; + break; + default: + { +#if 1 + LPSTR msg = ""; + switch (dwMessageType) + { + case DPN_MSGID_ADD_PLAYER_TO_GROUP: msg = "DPN_MSGID_ADD_PLAYER_TO_GROUP"; break; + case DPN_MSGID_ASYNC_OP_COMPLETE: msg = "DPN_MSGID_ASYNC_OP_COMPLETE"; break; + case DPN_MSGID_CLIENT_INFO: msg = "DPN_MSGID_CLIENT_INFO"; break; + case DPN_MSGID_CONNECT_COMPLETE: + { + PDPNMSG_CONNECT_COMPLETE pMsg = (PDPNMSG_CONNECT_COMPLETE)pMessage; +#ifdef DEBUG +// const char* x = DXGetErrorString9(pMsg->hResultCode); + if (pMsg->hResultCode != S_OK) + { + string1024 tmp=""; + DXTRACE_ERR(tmp, pMsg->hResultCode); + } +#endif + if (pMsg->dwApplicationReplyDataSize) + { + string256 ResStr = ""; + strncpy_s(ResStr, (char*)(pMsg->pvApplicationReplyData), pMsg->dwApplicationReplyDataSize); + Msg("Connection result : %s", ResStr); + } + else + msg = "DPN_MSGID_CONNECT_COMPLETE"; + }break; + case DPN_MSGID_CREATE_GROUP: msg = "DPN_MSGID_CREATE_GROUP"; break; + case DPN_MSGID_CREATE_PLAYER: msg = "DPN_MSGID_CREATE_PLAYER"; break; + case DPN_MSGID_DESTROY_GROUP: msg = "DPN_MSGID_DESTROY_GROUP"; break; + case DPN_MSGID_DESTROY_PLAYER: msg = "DPN_MSGID_DESTROY_PLAYER"; break; + case DPN_MSGID_ENUM_HOSTS_QUERY: msg = "DPN_MSGID_ENUM_HOSTS_QUERY"; break; + case DPN_MSGID_GROUP_INFO: msg = "DPN_MSGID_GROUP_INFO"; break; + case DPN_MSGID_HOST_MIGRATE: msg = "DPN_MSGID_HOST_MIGRATE"; break; + case DPN_MSGID_INDICATE_CONNECT: msg = "DPN_MSGID_INDICATE_CONNECT"; break; + case DPN_MSGID_INDICATED_CONNECT_ABORTED: msg = "DPN_MSGID_INDICATED_CONNECT_ABORTED"; break; + case DPN_MSGID_PEER_INFO: msg = "DPN_MSGID_PEER_INFO"; break; + case DPN_MSGID_REMOVE_PLAYER_FROM_GROUP: msg = "DPN_MSGID_REMOVE_PLAYER_FROM_GROUP"; break; + case DPN_MSGID_RETURN_BUFFER: msg = "DPN_MSGID_RETURN_BUFFER"; break; + case DPN_MSGID_SEND_COMPLETE: msg = "DPN_MSGID_SEND_COMPLETE"; break; + case DPN_MSGID_SERVER_INFO: msg = "DPN_MSGID_SERVER_INFO"; break; + case DPN_MSGID_TERMINATE_SESSION: msg = "DPN_MSGID_TERMINATE_SESSION"; break; + default: msg = "???"; break; + } + //Msg("! ************************************ : %s",msg); +#endif + } + break; + } + + return S_OK; +} + +void IPureClient::OnMessage(void* data, u32 size) +{ + // One of the messages - decompress it + net_Queue.Lock(); + NET_Packet* P = net_Queue.Create(); + + P->construct( data, size ); + P->timeReceive = timeServer_Async();//TimerAsync (device_timer); + + u16 m_type; + P->r_begin (m_type); + net_Queue.Unlock(); +} + +void IPureClient::timeServer_Correct(u32 sv_time, u32 cl_time) +{ + u32 ping = net_Statistic.getPing(); + u32 delta = sv_time + ping/2 - cl_time; + net_DeltaArray.push (delta); + Sync_Average (); +} + +void IPureClient::SendTo_LL(void* data, u32 size, u32 dwFlags, u32 dwTimeout) +{ + if( net_Disconnected ) + return; + + if( psNET_Flags.test(NETFLAG_LOG_CL_PACKETS) ) + { + if( !pClNetLog) + pClNetLog = xr_new( "logs\\net_cl_log.log", timeServer() ); + if( pClNetLog ) + pClNetLog->LogData( timeServer(), data, size ); + } + DPN_BUFFER_DESC desc; + + desc.dwBufferSize = size; + desc.pBufferData = (BYTE*)data; + + net_Statistic.dwBytesSended += size; + + + // verify + VERIFY(desc.dwBufferSize); + VERIFY(desc.pBufferData); + VERIFY(NET); + + DPNHANDLE hAsync = 0; + HRESULT hr = NET->Send( &desc, 1, dwTimeout, 0, &hAsync, dwFlags | DPNSEND_COALESCE ); + +// Msg("- Client::SendTo_LL [%d]", size); + if( FAILED(hr) ) + { + Msg ("! ERROR: Failed to send net-packet, reason: %s",::Debug.error2string(hr)); +// const char* x = DXGetErrorString9(hr); + string1024 tmp=""; + DXTRACE_ERR(tmp, hr); + } + +// UpdateStatistic(); +} + +void IPureClient::Send( NET_Packet& packet, u32 dwFlags, u32 dwTimeout ) +{ + MultipacketSender::SendPacket( packet.B.data, packet.B.count, dwFlags, dwTimeout ); +} + +void IPureClient::Flush_Send_Buffer () +{ + MultipacketSender::FlushSendBuffer( 0 ); +} + +BOOL IPureClient::net_HasBandwidth () +{ + u32 dwTime = TimeGlobal(device_timer); + u32 dwInterval = 0; + if (net_Disconnected) return FALSE; + + if (psNET_ClientUpdate != 0) dwInterval = 1000/psNET_ClientUpdate; + if (psNET_Flags.test(NETFLAG_MINIMIZEUPDATES)) dwInterval = 1000; // approx 3 times per second + + if(psNET_direct_connect) + { + if( 0 != psNET_ClientUpdate && (dwTime-net_Time_LastUpdate)>dwInterval) + { + net_Time_LastUpdate = dwTime; + return TRUE; + }else + return FALSE; + + }else + if (0 != psNET_ClientUpdate && (dwTime-net_Time_LastUpdate)>dwInterval) + { + HRESULT hr; + R_ASSERT (NET); + // check queue for "empty" state + DWORD dwPending=0; + hr = NET->GetSendQueueInfo(&dwPending,0,0); + if (FAILED(hr)) return FALSE; + + if (dwPending > u32(psNET_ClientPending)) + { + net_Statistic.dwTimesBlocked++; + return FALSE; + }; + + UpdateStatistic(); + + // ok + net_Time_LastUpdate = dwTime; + return TRUE; + } + return FALSE; +} + +void IPureClient::UpdateStatistic() +{ + // Query network statistic for this client + DPN_CONNECTION_INFO CI; + ZeroMemory (&CI,sizeof(CI)); + CI.dwSize = sizeof(CI); + HRESULT hr = NET->GetConnectionInfo(&CI,0); + if (FAILED(hr)) return; + + net_Statistic.Update(CI); +} + +void IPureClient::Sync_Thread () +{ + MSYS_PING clPing; + + //***** Ping server + net_DeltaArray.clear(); + R_ASSERT (NET); + for (; NET && !net_Disconnected; ) + { + // Waiting for queue empty state + if (net_Syncronised) break; // Sleep(2000); + else { + DWORD dwPending=0; + do { + R_CHK (NET->GetSendQueueInfo(&dwPending,0,0)); + Sleep (1); + } while (dwPending); + } + + // Construct message + clPing.sign1 = 0x12071980; + clPing.sign2 = 0x26111975; + clPing.dwTime_ClientSend = TimerAsync(device_timer); + + // Send it + __try { + DPN_BUFFER_DESC desc; + DPNHANDLE hAsync=0; + desc.dwBufferSize = sizeof(clPing); + desc.pBufferData = LPBYTE(&clPing); + if (0==NET || net_Disconnected) break; + + if (FAILED(NET->Send(&desc,1,0,0,&hAsync,net_flags(FALSE,FALSE,TRUE)))) { + Msg("* CLIENT: SyncThread: EXIT. (failed to send - disconnected?)"); + break; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + Msg("* CLIENT: SyncThread: EXIT. (failed to send - disconnected?)"); + break; + } + + // Waiting for reply-packet to arrive + if (!net_Syncronised) { + u32 old_size = net_DeltaArray.size(); + u32 timeBegin = TimerAsync(device_timer); + while ((net_DeltaArray.size()==old_size)&&(TimerAsync(device_timer)-timeBegin<5000)) Sleep(1); + + if (net_DeltaArray.size()>=syncSamples) { + net_Syncronised = TRUE; + net_TimeDelta = net_TimeDelta_Calculated; + // Msg ("* CL_TimeSync: DELTA: %d",net_TimeDelta); + } + } + } +} + +void IPureClient::Sync_Average () +{ + //***** Analyze results + s64 summary_delta = 0; + s32 size = net_DeltaArray.size(); + u32* I = net_DeltaArray.begin(); + u32* E = I+size; + for (; I!=E; I++) summary_delta += *((int*)I); + + s64 frac = s64(summary_delta) % s64(size); + if (frac<0) frac=-frac; + summary_delta /= s64(size); + if (frac>s64(size/2)) summary_delta += (summary_delta<0)?-1:1; + net_TimeDelta_Calculated= s32(summary_delta); + net_TimeDelta = (net_TimeDelta*5+net_TimeDelta_Calculated)/6; +// Msg("* CLIENT: d(%d), dc(%d), s(%d)",net_TimeDelta,net_TimeDelta_Calculated,size); +} + +void sync_thread(void* P) +{ + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL); + IPureClient* C = (IPureClient*)P; + C->Sync_Thread (); +} +void IPureClient::net_Syncronize () +{ + net_Syncronised = FALSE; + net_DeltaArray.clear(); + thread_spawn (sync_thread,"network-time-sync",0,this); +} + +void IPureClient::ClearStatistic() +{ + net_Statistic.Clear(); +} + +BOOL IPureClient::net_IsSyncronised() +{ + return net_Syncronised; +} + +#include +#include +bool IPureClient::GetServerAddress (ip_address& pAddress, DWORD* pPort) +{ + *pPort = 0; + if (!net_Address_server) return false; + + WCHAR wstrHostname[ 2048 ] = {0}; + DWORD dwHostNameSize = sizeof(wstrHostname); + DWORD dwHostNameDataType = DPNA_DATATYPE_STRING; + CHK_DX(net_Address_server->GetComponentByName( DPNA_KEY_HOSTNAME, wstrHostname, &dwHostNameSize, &dwHostNameDataType )); + + string2048 HostName; + CHK_DX(WideCharToMultiByte(CP_ACP,0,wstrHostname,-1,HostName,sizeof(HostName),0,0)); + + hostent* pHostEnt = gethostbyname(HostName); + char* localIP; + localIP = inet_ntoa (*(struct in_addr *)*pHostEnt->h_addr_list); + pHostEnt = gethostbyname(pHostEnt->h_name); + localIP = inet_ntoa (*(struct in_addr *)*pHostEnt->h_addr_list); + pAddress.set (localIP); + +//. pAddress[0] = (char)(*(struct in_addr *)*pHostEnt->h_addr_list).s_net; +//. pAddress[1] = (char)(*(struct in_addr *)*pHostEnt->h_addr_list).s_host; +//. pAddress[2] = (char)(*(struct in_addr *)*pHostEnt->h_addr_list).s_lh; +//. pAddress[3] = (char)(*(struct in_addr *)*pHostEnt->h_addr_list).s_impno; + + DWORD dwPort = 0; + DWORD dwPortSize = sizeof(dwPort); + DWORD dwPortDataType = DPNA_DATATYPE_DWORD; + CHK_DX(net_Address_server->GetComponentByName( DPNA_KEY_PORT, &dwPort, &dwPortSize, &dwPortDataType )); + *pPort = dwPort; + + return true; +}; diff --git a/xrNetServer/NET_Client.h b/xrNetServer/NET_Client.h new file mode 100644 index 00000000000..26c9b92dec0 --- /dev/null +++ b/xrNetServer/NET_Client.h @@ -0,0 +1,137 @@ +#pragma once + +#include "net_shared.h" +#include "NET_Common.h" + +struct ip_address; + +class XRNETSERVER_API INetQueue +{ + xrCriticalSection cs; + xr_deque ready; + xr_vector unused; +public: + INetQueue(); + ~INetQueue(); + + NET_Packet* Create (); + NET_Packet* Create (const NET_Packet& _other); + NET_Packet* Retreive(); + void Release (); + inline void Lock () { cs.Enter(); }; + inline void Unlock () { cs.Leave(); }; +}; + + +//============================================================================== + +class XRNETSERVER_API +IPureClient + : private MultipacketReciever, + private MultipacketSender +{ + enum ConnectionState + { + EnmConnectionFails=0, + EnmConnectionWait=-1, + EnmConnectionCompleted=1 + }; + friend void sync_thread(void*); +protected: + struct HOST_NODE //deprecated... + { + DPN_APPLICATION_DESC dpAppDesc; + IDirectPlay8Address* pHostAddress; + shared_str dpSessionName; + }; + GameDescriptionData m_game_description; + CTimer* device_timer; +protected: + IDirectPlay8Client* NET; + IDirectPlay8Address* net_Address_device; + IDirectPlay8Address* net_Address_server; + + xrCriticalSection net_csEnumeration; + xr_vector net_Hosts; + + NET_Compressor net_Compressor; + + ConnectionState net_Connected; + BOOL net_Syncronised; + BOOL net_Disconnected; + + INetQueue net_Queue; + IClientStatistic net_Statistic; + + u32 net_Time_LastUpdate; + s32 net_TimeDelta; + s32 net_TimeDelta_Calculated; + s32 net_TimeDelta_User; + + void Sync_Thread (); + void Sync_Average (); + + void SetClientID (ClientID const & local_client) { net_ClientID = local_client; }; + + + IC virtual void SendTo_LL (void* data, u32 size, u32 dwFlags=DPNSEND_GUARANTEED, u32 dwTimeout=0); + +public: + IPureClient (CTimer* tm); + virtual ~IPureClient (); + HRESULT net_Handler (u32 dwMessageType, PVOID pMessage); + + BOOL Connect (LPCSTR server_name); + void Disconnect (); + + void net_Syncronize (); + BOOL net_isCompleted_Connect () { return net_Connected==EnmConnectionCompleted;} + BOOL net_isFails_Connect () { return net_Connected==EnmConnectionFails;} + BOOL net_isCompleted_Sync () { return net_Syncronised; } + BOOL net_isDisconnected () { return net_Disconnected; } + IC GameDescriptionData const & get_net_DescriptionData() const { return m_game_description; } + LPCSTR net_SessionName () { return *(net_Hosts.front().dpSessionName); } + + // receive + IC void StartProcessQueue () { net_Queue.Lock(); }; // WARNING ! after Start mast be End !!! <- + IC virtual NET_Packet* net_msg_Retreive () { return net_Queue.Retreive(); };// | + IC void net_msg_Release () { net_Queue.Release(); };// | + IC void EndProcessQueue () { net_Queue.Unlock(); };// <- + + // send + virtual void Send (NET_Packet& P, u32 dwFlags=DPNSEND_GUARANTEED, u32 dwTimeout=0); + virtual void Flush_Send_Buffer (); + virtual void OnMessage (void* data, u32 size); + virtual void OnInvalidHost () {}; + virtual void OnInvalidPassword () {}; + virtual void OnSessionFull () {}; + virtual void OnConnectRejected () {}; + BOOL net_HasBandwidth (); + void ClearStatistic (); + IClientStatistic& GetStatistic () {return net_Statistic; } + void UpdateStatistic (); + ClientID const & GetClientID () { return net_ClientID; }; + + bool GetServerAddress (ip_address& pAddress, DWORD* pPort); + + // time management + IC u32 timeServer () { return TimeGlobal(device_timer) + net_TimeDelta + net_TimeDelta_User; } + IC u32 timeServer_Async () { return TimerAsync(device_timer) + net_TimeDelta + net_TimeDelta_User; } + IC u32 timeServer_Delta () { return net_TimeDelta; } + IC void timeServer_UserDelta (s32 d) { net_TimeDelta_User=d; } + IC void timeServer_Correct (u32 sv_time, u32 cl_time); + + virtual BOOL net_IsSyncronised (); + + virtual LPCSTR GetMsgId2Name (u16 ID) { return ""; } + virtual void OnSessionTerminate (LPCSTR reason){}; + + virtual bool TestLoadBEClient () { return false; } + +private: + ClientID net_ClientID; + + virtual void _Recieve( const void* data, u32 data_size, u32 param ); + virtual void _SendTo_LL( const void* data, u32 size, u32 flags, u32 timeout ); +}; + diff --git a/xrNetServer/NET_Common.cpp b/xrNetServer/NET_Common.cpp new file mode 100644 index 00000000000..a6c54a4236c --- /dev/null +++ b/xrNetServer/NET_Common.cpp @@ -0,0 +1,261 @@ + + #include "stdafx.h" + + #include "NET_Common.h" + +/*#ifdef DEBUG +void PrintParsedPacket(const char* message, u16 message_type, const void* packet_data, u32 packet_size) +{ + NET_Packet tNetPacket; + tNetPacket.construct ( packet_data, packet_size ); + u16 msg_type; + tNetPacket.r_begin (msg_type); + if (msg_type == message_type) + { + if (message_type == 1) //M_SPAWN + { + shared_str s_name; + tNetPacket.r_stringZ (s_name ); + + string256 temp; + tNetPacket.r_stringZ (temp); + u8 temp_gt; + tNetPacket.r_u8 (temp_gt ); + u8 s_RP; + tNetPacket.r_u8 (s_RP ); + Fvector o_Position, o_Angle; + tNetPacket.r_vec3 (o_Position ); + tNetPacket.r_vec3 (o_Angle ); + u16 RespawnTime, ID; + tNetPacket.r_u16 (RespawnTime ); + tNetPacket.r_u16 (ID ); + + Msg("%s M_SPAWN for [%s]-[%d]", message, s_name.c_str(), ID); + } else + { + Msg("%s NOT_IMPLEMENTED_PRINT type[%d]", message, message_type); + } + } +} +#endif*/ +//============================================================================== + +#pragma pack( push ) +#pragma pack( 1 ) +struct +MultipacketHeader +{ + u8 tag; + u16 unpacked_size; +}; +#pragma pack( pop ) + + +//============================================================================== + +static NET_Compressor Compressor; +static const unsigned MaxMultipacketSize = 32768; + +XRNETSERVER_API int psNET_GuaranteedPacketMode = NET_GUARANTEEDPACKET_DEFAULT; + + +//------------------------------------------------------------------------------ + +MultipacketSender::MultipacketSender() +{ +} + + +//------------------------------------------------------------------------------ + +void +MultipacketSender::SendPacket( const void* packet_data, u32 packet_sz, u32 flags, u32 timeout ) +{ + _buf_cs.Enter(); + + //PrintParsedPacket("-- LL Sending:", 1, packet_data, packet_sz); + + Buffer* buf = &_buf; + + switch( psNET_GuaranteedPacketMode ) + { + case NET_GUARANTEEDPACKET_IGNORE : + { + flags &= ~DPNSEND_GUARANTEED; + } break; + + case NET_GUARANTEEDPACKET_SEPARATE : + { + if( flags & DPNSEND_GUARANTEED ) + buf = &_gbuf; + } break; + } + + u32 old_flags = (buf->last_flags) & (~DPNSEND_IMMEDIATELLY); + u32 new_flags = flags & (~DPNSEND_IMMEDIATELLY); + + if( (buf->buffer.B.count + packet_sz + sizeof(u16) >= NET_PacketSizeLimit) + || (old_flags != new_flags) + || (flags & DPNSEND_IMMEDIATELLY) + ) + { + _FlushSendBuffer( timeout, buf ); + } + + buf->buffer.w_u16( (u16)packet_sz ); + buf->buffer.w( packet_data, packet_sz ); + + if( flags & DPNSEND_IMMEDIATELLY ) + _FlushSendBuffer( timeout, buf ); + + buf->last_flags = flags; + _buf_cs.Leave(); +} + + +//------------------------------------------------------------------------------ + +void +MultipacketSender::FlushSendBuffer( u32 timeout ) +{ + _buf_cs.Enter(); + + _FlushSendBuffer( timeout, &_buf ); + _FlushSendBuffer( timeout, &_gbuf ); + + _buf_cs.Leave(); +} + + +//------------------------------------------------------------------------------ + +void +MultipacketSender::_FlushSendBuffer( u32 timeout, Buffer* buf ) +{ + // expected to be called between '_buf_cs' enter/leave + + if( buf->buffer.B.count ) + { + // compress data + + unsigned comp_sz = Compressor.compressed_size( buf->buffer.B.count ); + u8 packet_data[MaxMultipacketSize]; + MultipacketHeader* header = (MultipacketHeader*)packet_data; + + R_ASSERT(comp_sz < sizeof(packet_data)-sizeof(MultipacketHeader)); + R_ASSERT(comp_sz < 65535); + + comp_sz = Compressor.Compress( packet_data+sizeof(MultipacketHeader), sizeof(packet_data)-sizeof(MultipacketHeader), + buf->buffer.B.data, buf->buffer.B.count + ); + + header->tag = NET_TAG_MERGED; + header->unpacked_size = (u16)buf->buffer.B.count; + + + // dump/log if needed + + #if NET_LOG_PACKETS + Msg( "#send %smulti-packet %u flags= %08X", + (buf->last_flags & DPNSEND_IMMEDIATELLY)?"IMMEDIATE ":"", + buf->buffer.B.count, buf->last_flags + ); + #endif // NET_LOG_PACKETS + + if( strstr( Core.Params,"-dump_traffic") ) + { + static bool first_time = true; + FILE* dump = fopen( "raw-out-traffic.bins", (first_time)?"wb":"ab" ); + + if( first_time ) + { + fwrite( "BINS", 4, 1, dump ); + first_time = false; + } + + u16 sz = u16(buf->buffer.B.count); + + fwrite( &sz, sizeof(u16), 1, dump ); + fwrite( buf->buffer.B.data, buf->buffer.B.count, 1, dump ); + fclose( dump ); + } + + + // do send + + _SendTo_LL( packet_data, comp_sz+sizeof(MultipacketHeader), buf->last_flags, timeout ); + buf->buffer.B.count = 0; + } // if buffer not empty +} + + +//------------------------------------------------------------------------------ + +void +MultipacketReciever::RecievePacket( const void* packet_data, u32 packet_sz, u32 param ) +{ + MultipacketHeader* header = (MultipacketHeader*)packet_data; + u8 data[MaxMultipacketSize]; + + if ( header->tag != NET_TAG_MERGED && header->tag != NET_TAG_NONMERGED ) + return; + + Compressor.Decompress( data, sizeof(data), + (u8*)packet_data+sizeof(MultipacketHeader), packet_sz-sizeof(MultipacketHeader) + ); + + #if NET_LOG_PACKETS + Msg( "#receive multi-packet %u", packet_sz ); + #endif + + if( strstr( Core.Params,"-dump_traffic") ) + { + static bool first_time = true; + FILE* dump = fopen( "raw-in-traffic.bins", (first_time)?"wb":"ab" ); + + if( first_time ) + { + fwrite( "BINS", 4, 1, dump ); + first_time = false; + } + + u16 sz = header->unpacked_size; + + fwrite( &sz, sizeof(u16), 1, dump ); + fwrite( data, header->unpacked_size, 1, dump ); + fclose( dump ); + } + + + bool is_multi_packet = header->tag == NET_TAG_MERGED; + u32 processed_sz = 0; + u8* dat = data; + + while( processed_sz < header->unpacked_size ) + { + u32 size = (is_multi_packet) + ? u32(*((u16*)dat)) + : header->unpacked_size; + + if( is_multi_packet ) + dat += sizeof(u16); + + #if NET_LOG_PACKETS + Msg( " packet %u", size ); + #endif + + + //PrintParsedPacket("-- LL Receiving:", 1, dat, size); + + _Recieve( dat, size, param ); + + dat += size; + processed_sz += size + ((is_multi_packet) ? sizeof(u16) : 0); + } +} + +void XRNETSERVER_API DumpNetCompressorStats(bool brief) +{ + Compressor.DumpStats(brief); +} + diff --git a/xrNetServer/NET_Common.h b/xrNetServer/NET_Common.h new file mode 100644 index 00000000000..cce0c8b64b1 --- /dev/null +++ b/xrNetServer/NET_Common.h @@ -0,0 +1,99 @@ +#if !defined _INCDEF_NETCOMMON_H_ +#define _INCDEF_NETCOMMON_H_ +#pragma once +//============================================================================== + +struct GameDescriptionData +{ + string128 map_name; + string128 map_version; + string512 download_url; +}; + +#define NET_MERGE_PACKETS 1 +#define NET_TAG_MERGED 0xE1 +#define NET_TAG_NONMERGED 0xE0 + +#define NET_USE_COMPRESSION 1 +#define NET_TAG_COMPRESSED 0xC1 +#define NET_TAG_NONCOMPRESSED 0xC0 + +#define NET_USE_LZO_COMPRESSION 1 +#define NET_USE_COMPRESSION_CRC 1 + +#define NET_LOG_PACKETS 0 +#define NET_LOG_COMPRESSION 0 +#define NET_DUMP_COMPRESSION 0 + + +#define NET_GUARANTEEDPACKET_DEFAULT 0 +#define NET_GUARANTEEDPACKET_IGNORE 1 +#define NET_GUARANTEEDPACKET_SEPARATE 2 + +extern XRNETSERVER_API int psNET_GuaranteedPacketMode; + +/*#ifdef DEBUG +void PrintParsedPacket(const char* message, u16 message_type, const void* packet_data, u32 packet_size); +#endif*/ + +//============================================================================== + +class XRNETSERVER_API +MultipacketSender +{ +public: + MultipacketSender(); + virtual ~MultipacketSender() {} + + void SendPacket( const void* packet_data, u32 packet_sz, u32 flags, u32 timeout ); + void FlushSendBuffer( u32 timeout ); + + +protected: + + virtual void _SendTo_LL( const void* data, u32 size, u32 flags, u32 timeout ) =0; + + +private: + + struct Buffer; + + + void _FlushSendBuffer( u32 timeout, Buffer* buf ); + + struct + Buffer + { + Buffer() : last_flags(0) { buffer.B.count = 0; } + + NET_Packet buffer; + u32 last_flags; + }; + + Buffer _buf; + Buffer _gbuf; + xrCriticalSection _buf_cs; +}; + + +//============================================================================== + +class XRNETSERVER_API +MultipacketReciever +{ +public: + + virtual ~MultipacketReciever() {} + + void RecievePacket( const void* packet_data, u32 packet_sz, u32 param=0 ); + + +protected: + + virtual void _Recieve( const void* data, u32 data_size, u32 param ) =0; +}; + + +//============================================================================== +#endif // _INCDEF_NETCOMMON_H_ + diff --git a/xrNetServer/NET_Compressor.cpp b/xrNetServer/NET_Compressor.cpp new file mode 100644 index 00000000000..6906209eb13 --- /dev/null +++ b/xrNetServer/NET_Compressor.cpp @@ -0,0 +1,549 @@ +// NET_Compressor.cpp: implementation of the NET_Compressor class. +// +////////////////////////////////////////////////////////////////////// +#include "stdafx.h" +#pragma hdrstop + +#include "NET_Common.h" +#include "NET_Compressor.h" + + + + + +#if NET_USE_COMPRESSION + +# ifdef DEBUG +# pragma warning(push) +# pragma warning(disable:4995) +# include +# pragma warning(pop) +# endif // DEBUG + +# include + +# if NET_USE_LZO_COMPRESSION +# define ENCODE rtc9_compress +# define DECODE rtc9_decompress +# else // NET_USE_LZO_COMPRESSION +# include "../xrCore/ppmd_compressor.h" +# define ENCODE ppmd_compress +# define DECODE ppmd_decompress +# endif // NET_USE_LZO_COMPRESSION + +#endif // NET_USE_COMPRESSION + + + +#if 1//def DEBUG +//static FILE* OriginalTrafficDump = NULL; +//static FILE* CompressedTrafficDump = NULL; +static FILE* RawTrafficDump = NULL; +static FILE* CompressionDump = NULL; +#endif // DEBUG + +#define NOWARN + + +// size of range encoding code values + +#define PPM_CODE_BITS 32 +#define PPM_TOP_VALUE ((NET_Compressor::code_value)1 << (PPM_CODE_BITS-1)) + +#define SHIFT_BITS (PPM_CODE_BITS - 9) +#define EXTRA_BITS ((PPM_CODE_BITS-2) % 8 + 1) +#define PPM_BOTTOM_VALUE (PPM_TOP_VALUE >> 8) + + +/* +// c is written as first byte in the datastream +// one could do without c, but then you have an additional if +// per outputbyte. +void NET_Compressor::start_encoding ( BYTE* dest, u32 header_size ) +{ + dest += header_size-1; + RNGC.low = 0; // Full code range + RNGC.range = PPM_TOP_VALUE; + RNGC.buffer = 0; + RNGC.help = 0; // No bytes to follow + RNGC.bytecount = 0; + RNGC.ptr = dest; +} + +// I do the normalization before I need a defined state instead of +// after messing it up. This simplifies starting and ending. +void NET_Compressor::encode_normalize ( ) +{ + while( RNGC.range <= PPM_BOTTOM_VALUE ) // do we need renormalisation? + { + if( RNGC.low < code_value(0xff) << SHIFT_BITS ) // no carry possible --> output + { + RNGC.byte_out( RNGC.buffer ); + for( ; RNGC.help; RNGC.help--) + RNGC.byte_out(0xff); + RNGC.buffer = (BYTE)(RNGC.low >> SHIFT_BITS); + } + else if( RNGC.low & PPM_TOP_VALUE ) // carry now, no future carry + { + RNGC.byte_out( RNGC.buffer+1 ); + for(; RNGC.help; RNGC.help--) + RNGC.byte_out(0); + RNGC.buffer = (BYTE)(RNGC.low >> SHIFT_BITS); + } + else // passes on a potential carry + { + RNGC.help++; + } + + RNGC.range <<= 8; + RNGC.low = (RNGC.low<<8) & (PPM_TOP_VALUE-1); + RNGC.bytecount ++; + } +} + +// Encode a symbol using frequencies +// sy_f is the interval length (frequency of the symbol) +// lt_f is the lower end (frequency sum of < symbols) +// tot_f is the total interval length (total frequency sum) +// or (faster): tot_f = (code_value)1<> shift; + code_value tmp = r * lt_f; + + RNGC.low += tmp; + + if ((lt_f+sy_f) >> shift) RNGC.range -= tmp; + else RNGC.range = r * sy_f; +} + +// Finish encoding +// actually not that many bytes need to be output, but who +// cares. I output them because decode will read them :) +// the return value is the number of bytes written +u32 NET_Compressor::done_encoding ( ) +{ + encode_normalize(); // now we have a normalized state + + RNGC.bytecount += 3; + + u32 tmp = ((RNGC.low & (PPM_BOTTOM_VALUE-1)) < ((RNGC.bytecount&0xffffffL)>>1)) + ? (RNGC.low >> SHIFT_BITS) + : (RNGC.low >> SHIFT_BITS) + 1; + + if( tmp > 0xff ) // we have a carry + { + RNGC.byte_out( RNGC.buffer+1 ); + + for( ; RNGC.help; RNGC.help-- ) + RNGC.byte_out(0); + } + else // no carry + { + RNGC.byte_out( RNGC.buffer ); + + for( ; RNGC.help; RNGC.help-- ) + RNGC.byte_out(0xff); + } + + RNGC.byte_out( (BYTE)(tmp & 0xff) ); + RNGC.byte_out( 0 ); + + return RNGC.bytecount; +} + +// Start the decoder +int NET_Compressor::start_decoding ( BYTE* src, u32 header_size ) +{ + src += header_size; + RNGC.ptr = src; + RNGC.buffer = RNGC.byte_in(); + RNGC.low = RNGC.buffer >> (8-EXTRA_BITS); + RNGC.range = (code_value)1 << EXTRA_BITS; + return 0; +} + +void NET_Compressor::decode_normalize ( ) +{ + while( RNGC.range <= PPM_BOTTOM_VALUE ) + { + RNGC.low = (RNGC.low<<8) | ((RNGC.buffer<> (8-EXTRA_BITS); + RNGC.range <<= 8; + } +} + + +// Calculate culmulative frequency for next symbol. Does NO update! +// tot_f is the total frequency +// or: totf is (code_value)1<=tot_f) ? (tot_f-1) : (tmp); +} + +NET_Compressor::freq NET_Compressor::decode_culshift ( freq shift ) +{ + decode_normalize(); + RNGC.help = RNGC.range>>shift; + + freq tmp = RNGC.low/RNGC.help; + + return (tmp>>shift) ? ((code_value(1)<36); + if(g_net_compressor_gather_stats && b_compress_packet) + { + _p = m_stats.get(count); + _p->hit_count += 1; + m_stats.total_uncompressed_bytes += count; + } + + VERIFY(dest); + VERIFY(src); + VERIFY(count); + +#if 1//def DEBUG + if( strstr(Core.Params,"-dump_traffic") ) + { +// fwrite( src,count,1,OriginalTrafficDump ); +// fflush( OriginalTrafficDump ); + } +#endif // DEBUG + +#if !NET_USE_COMPRESSION + + CopyMemory(dest,src,count); + return (u16(count)); + +#else // !NET_USE_COMPRESSION + + R_ASSERT(dest_size >= compressed_size(count)); + + u32 compressed_size = count; + u32 offset = 1; + + #if NET_USE_COMPRESSION_CRC + offset += sizeof(u32); + #endif // NET_USE_COMPRESSION_CRC + + if( !psNET_direct_connect && g_net_compressor_enabled && b_compress_packet) + { + CS.Enter (); + compressed_size = offset + ENCODE( dest+offset, dest_size-offset, src, count ); + + if(g_net_compressor_gather_stats) + m_stats.total_compressed_bytes += compressed_size; + + CS.Leave(); + } + + if( compressed_size < count ) + { + *dest = NET_TAG_COMPRESSED; + + #if NET_USE_COMPRESSION_CRC + boost::crc_32_type temp; + temp.process_block( dest+offset, dest+compressed_size ); + u32 crc = temp.checksum(); + + *((u32*)(dest + 1)) = crc; + #endif // NET_USE_COMPRESSION_CRC + + #if NET_LOG_COMPRESSION + Msg( "#compress %u->%u %02X (%08X)", count, compressed_size, *dest, *((u32*)(src+1)) ); + #endif + #if NET_DUMP_COMPRESSION + #if NET_USE_LZO_COMPRESSION + static const char* compressor_name = "LZO"; + #else + static const char* compressor_name = "PPMd"; + #endif + + if( !CompressionDump ) + CompressionDump = fopen( "net-compression.log", "w+b" ); + + fprintf( CompressionDump, "%s compress %2.0f%% %u->%u\r\n", + compressor_name, + 100.0f*float(compressed_size)/float(count), count, compressed_size + ); + #endif // NET_DUMP_COMPRESSION + } + else + { + if(g_net_compressor_gather_stats && b_compress_packet) + _p->unlucky_attempts +=1; + + *dest = NET_TAG_NONCOMPRESSED; + + compressed_size = count + 1; + CopyMemory( dest+1, src, count ); + + #if NET_LOG_COMPRESSION + Msg( "#compress/as-is %u->%u %02X", count, compressed_size, *dest ); + #endif + } + if(g_net_compressor_gather_stats && b_compress_packet) + _p->compressed_size += compressed_size; + + #if 1//def DEBUG +// if( strstr(Core.Params,"-dump_traffic")) +// { +// fwrite(dest,compressed_size,1,CompressedTrafficDump); +// fflush(CompressedTrafficDump); +// } + #endif // DEBUG + + #ifdef DEBUG +/* + BYTE *src_back = (BYTE*)_alloca(count); + Decompress (src_back,count,dest,compressed_size); + BYTE *I = src_back; + BYTE *E = src_back + count; + BYTE *J = src; + for ( ; I != E; ++I, ++J) + VERIFY (*I == *J); + +*/ +// CS.Leave (); + #endif // DEBUG + + return (u16(compressed_size)); + +#endif // if !NET_USE_COMPRESSION +} + + + +u16 NET_Compressor::Decompress (BYTE* dest, const u32 &dest_size, BYTE* src, const u32 &count) +{ + VERIFY(dest); + VERIFY(src); + VERIFY(count); + + #if NET_LOG_COMPRESSION + Msg( "#decompress %u %02X (%08X)", count, src[0], *((u32*)(src+1)) ); + #endif + + #if NET_USE_COMPRESSSION + if( src[0] != NET_TAG_COMPRESSED && src[0] != NET_TAG_NONCOMPRESSED ) + { + Msg( "! invalid compression-tag %02X", src[0] ); + __asm { int 3 } + } + #endif NET_USE_COMPRESSSION + + +#if !NET_USE_COMPRESSION + + CopyMemory(dest,src,count); + + return (u16(count)); + +#else + + if( *src != NET_TAG_COMPRESSED ) + { + if (count) { + CopyMemory ( dest, src+1, count-1 ); + return ( u16(count-1) ); + } + + return ( 0 ); + } + + u32 offset = 1; + + #if NET_USE_COMPRESSION_CRC + offset += sizeof(u32); + #endif // NET_USE_COMPRESSION_CRC + + #if NET_USE_COMPRESSION_CRC + boost::crc_32_type temp; + temp.process_block (src + offset,src + count); + u32 crc = temp.checksum(); +// Msg ("decompressed %d -> ? [0x%08x]",count,crc); + if( crc != *((u32*)(src + 1)) ) + Msg( "!CRC mismatch" ); + + R_ASSERT2(crc == *((u32*)(src + 1)),make_string("crc is different! (0x%08x != 0x%08x)",crc,*((u32*)(src + 1)))); + #endif // NET_USE_COMPRESSION_CRC + + CS.Enter(); + u32 uncompressed_size = DECODE( dest, dest_size, src+offset, count-offset ); + CS.Leave(); + + return (u16(uncompressed_size)); + +#endif // !NET_USE_COMPRESSION +} + +void NET_Compressor::DumpStats(bool brief) +{ + xr_map::const_iterator it = m_stats.m_packets.begin(); + xr_map::const_iterator it_e = m_stats.m_packets.end(); + + Msg("---------NET_Compressor::DumpStats-----------"); + + Msg("Active=[%s]",g_net_compressor_enabled?"yes":"no"); + + Msg("uncompressed [%d]",m_stats.total_uncompressed_bytes); + Msg("compressed [%d]",m_stats.total_compressed_bytes); + + u32 total_hits = 0; + u32 unlucky_hits = 0; + + for(; it!=it_e; ++it) + { + total_hits += it->second.hit_count; + unlucky_hits += it->second.unlucky_attempts; + if(!brief) + { + Msg ("size[%d] count[%d] unlucky[%d] avg_c[%d]",it->first, it->second.hit_count, it->second.unlucky_attempts, iFloor(float(it->second.compressed_size)/float(it->second.hit_count)) ); + } + } + Msg("total [%d]", total_hits); + Msg("unlucky [%d]", unlucky_hits); +} \ No newline at end of file diff --git a/xrNetServer/NET_Compressor.h b/xrNetServer/NET_Compressor.h new file mode 100644 index 00000000000..60e441ef2a5 --- /dev/null +++ b/xrNetServer/NET_Compressor.h @@ -0,0 +1,39 @@ +#if !defined(AFX_NET_COMPRESSOR_H__21E1ED1C_BF92_4BF0_94A8_18A27486EBFD__INCLUDED_) +#define AFX_NET_COMPRESSOR_H__21E1ED1C_BF92_4BF0_94A8_18A27486EBFD__INCLUDED_ +#pragma once + +#include "../xrcore/xrSyncronize.h" + +class XRNETSERVER_API NET_Compressor +{ + xrCriticalSection CS; + + struct SCompressorStats + { + u32 total_uncompressed_bytes; + u32 total_compressed_bytes; + + struct SStatPacket{ + u32 hit_count; + u32 unlucky_attempts; + u32 compressed_size; + SStatPacket ():hit_count(0),unlucky_attempts(0),compressed_size(0){} + }; + xr_map m_packets; + + SCompressorStats():total_uncompressed_bytes(0),total_compressed_bytes(0){} + SStatPacket* get(u32 size) {return &(m_packets[size]);}; + } m_stats; + +public: + NET_Compressor (); + ~NET_Compressor (); + + u16 compressed_size (const u32 &count); + u16 Compress (BYTE* dest, const u32 &dest_size, BYTE* src, const u32 &count); // return size of compressed + u16 Decompress (BYTE* dest, const u32 &dest_size, BYTE* src, const u32 &count); // return size of compressed + void DumpStats (bool brief); +}; + +#endif // !defined(AFX_NET_COMPRESSOR_H__21E1ED1C_BF92_4BF0_94A8_18A27486EBFD__INCLUDED_) + diff --git a/xrNetServer/NET_Log.cpp b/xrNetServer/NET_Log.cpp new file mode 100644 index 00000000000..9c3fed9fa2c --- /dev/null +++ b/xrNetServer/NET_Log.cpp @@ -0,0 +1,137 @@ +#include "stdafx.h" +#include "net_log.h" +//--------------------------------------------------------- +string64 PacketName[] = { + "M_UPDATE", // DUAL: Update state + "M_SPAWN", // DUAL: Spawning, full state + + "M_SV_CONFIG_NEW_CLIENT", + "M_SV_CONFIG_GAME", + "M_SV_CONFIG_FINISHED", + + "M_MIGRATE_DEACTIVATE", // TO: Changing server, just deactivate + "M_MIGRATE_ACTIVATE", // TO: Changing server", full state + + "M_CHAT", // DUAL: + + "M_EVENT", // Game Event + "M_CL_INPUT", // Client Input Data + //----------- for E3 ----------------------------- + "M_CL_UPDATE", + "M_UPDATE_OBJECTS", + //------------------------------------------------- + "M_CLIENTREADY", // Client has finished to load level and are ready to play + + "M_CHANGE_LEVEL", // changing level + "M_LOAD_GAME", + "M_RELOAD_GAME", + "M_SAVE_GAME", + "M_SAVE_PACKET", + + "M_SWITCH_DISTANCE", + "M_GAMEMESSAGE", // Game Message + "M_EVENT_PACK", // Pack of M_EVENT + + //----------------------------------------------------- + "M_GAMESPY_CDKEY_VALIDATION_CHALLENGE", + "M_GAMESPY_CDKEY_VALIDATION_CHALLENGE_RESPOND", + "M_CLIENT_CONNECT_RESULT", + "M_CLIENT_REQUEST_CONNECTION_DATA", + + "M_CHAT_MESSAGE", + "M_CHANGE_LEVEL_GAME", + //----------------------------------------------------- + "M_CL_PING_CHALLENGE", + "M_CL_PING_CHALLENGE_RESPOND", + //----------------------------------------------------- + "M_PAUSE_GAME", + //----------------------------------------------------- + "M_AUTH_CHALLENGE", + "M_CL_AUTH", + "M_BULLET_CHECK_RESPOND", + //----------------------------------------------------- + "M_STATISTIC_UPDATE", + "M_STATISTIC_UPDATE_RESPOND", + //----------------------------------------------------- + "M_PLAYER_FIRE", + //----------------------------------------------------- + "M_MOVE_PLAYERS", + "M_MOVE_PLAYERS_RESPOND", + + "MSG_FORCEDWORD" +}; +//--------------------------------------------------------- +INetLog::INetLog(LPCSTR sFileName, u32 dwStartTime) +#ifdef PROFILE_CRITICAL_SECTIONS + :m_cs(MUTEX_PROFILE_ID(NET_Log)) +#endif // PROFILE_CRITICAL_SECTIONS +{ + xr_strcpy(m_cFileName, sFileName); + + m_pLogFile = NULL; + m_pLogFile = fopen(sFileName, "wb"); + m_dwStartTime = 0;//dwStartTime; + +} + +INetLog::~INetLog() +{ + FlushLog(); + if (m_pLogFile) fclose(m_pLogFile); + m_pLogFile = NULL; +} + +void INetLog::FlushLog() +{ + if (m_pLogFile) + { + for(xr_vector::iterator it = m_aLogPackets.begin(); it != m_aLogPackets.end(); it++) + { + SLogPacket* pLPacket = &(*it); + if (pLPacket->m_u16Type >= sizeof(PacketName)/sizeof(PacketName[0])) + fprintf(m_pLogFile, "%s %10d %10d %10d\n", pLPacket->m_bIsIn ? "In:" : "Out:", pLPacket->m_u32Time, pLPacket->m_u16Type, pLPacket->m_u32Size); + else + fprintf(m_pLogFile, "%s %10d %10s %10d\n", pLPacket->m_bIsIn ? "In:" : "Out:", pLPacket->m_u32Time, PacketName[pLPacket->m_u16Type], pLPacket->m_u32Size); + }; + }; + + m_aLogPackets.clear(); +} + +void INetLog::LogPacket(u32 Time, NET_Packet* pPacket, bool IsIn) +{ + if (!pPacket) return; + + m_cs.Enter(); + + SLogPacket NewPacket; + + NewPacket.m_u16Type = *((u16*)&pPacket->B.data); + NewPacket.m_u32Size = pPacket->B.count; + NewPacket.m_u32Time = Time - m_dwStartTime; + NewPacket.m_bIsIn = IsIn; + + m_aLogPackets.push_back(NewPacket); + if (m_aLogPackets.size() > 100) FlushLog(); + + m_cs.Leave(); +}; + +void INetLog::LogData(u32 Time, void* data, u32 size, bool IsIn) +{ + if (!data) return; + + m_cs.Enter(); + + SLogPacket NewPacket; + + NewPacket.m_u16Type = *((u16*)data); + NewPacket.m_u32Size = size; + NewPacket.m_u32Time = Time - m_dwStartTime; + NewPacket.m_bIsIn = IsIn; + + m_aLogPackets.push_back(NewPacket); + if (m_aLogPackets.size() > 100) FlushLog(); + + m_cs.Leave(); +} \ No newline at end of file diff --git a/xrNetServer/NET_Log.h b/xrNetServer/NET_Log.h new file mode 100644 index 00000000000..776d0190b9f --- /dev/null +++ b/xrNetServer/NET_Log.h @@ -0,0 +1,74 @@ +#pragma once + +#include "net_shared.h" +struct SLogPacket +{ + u32 m_u32Time; + u32 m_u32Size; + u16 m_u16Type; + string64 m_sTypeStr; + bool m_bIsIn; +}; +class INetLog +{ +private: + FILE* m_pLogFile; + string1024 m_cFileName; + u32 m_dwStartTime; + + xrCriticalSection m_cs; + + xr_vector m_aLogPackets; + + void FlushLog(); + +public: + INetLog(LPCSTR sFileName, u32 dwStartTime); + ~INetLog(); + + void LogPacket(u32 Time, NET_Packet* pPacket, bool IsIn = FALSE); + void LogData(u32 Time, void* data, u32 size, bool IsIn = FALSE); +}; + +/* +// Singleton template definition +template class CSingleton { +private: + static T* _self; + static int _refcount; +public: + //whether singleton will delete itself on FreeInst + //when _refcount = 0 + //otherwise user should call DestroySingleton() manually + static bool _on_self_delete; +public: + CSingleton () {} + virtual ~CSingleton () {_self=NULL;} + + static void DestroySingleton () { + if(!_self) return; + Log ("DestroySingleton::RefCounter:",_refcount); + VERIFY(_on_self_delete == false); + VERIFY(_refcount == 0); + xr_delete(_self); + }; +public: + static T* Instance () { + if(!_self) _self=xr_new(); + ++_refcount; + return _self; + } + void FreeInst () { + if(0 == --_refcount) { + if(_on_self_delete){ + CSingleton *ptr = this; + xr_delete(ptr); + } + } + } +}; + +template T* CSingleton::_self = NULL; +template int CSingleton::_refcount = 0; +template bool CSingleton::_on_self_delete = true; +*/ \ No newline at end of file diff --git a/xrNetServer/NET_Messages.h b/xrNetServer/NET_Messages.h new file mode 100644 index 00000000000..d94db3d9050 --- /dev/null +++ b/xrNetServer/NET_Messages.h @@ -0,0 +1,32 @@ +#pragma once +#pragma pack(push,1) + +#define DPNSEND_IMMEDIATELLY 0x0100 + +IC u32 net_flags (BOOL bReliable=FALSE, BOOL bSequental=TRUE, BOOL bHighPriority=FALSE, + BOOL bSendImmediatelly = FALSE) +{ + return + (bReliable?DPNSEND_GUARANTEED:DPNSEND_NOCOMPLETE) | + (bSequental?0:DPNSEND_NONSEQUENTIAL) | + (bHighPriority?DPNSEND_PRIORITY_HIGH:0) | + (bSendImmediatelly?DPNSEND_IMMEDIATELLY:0) + ; +} +struct MSYS_CONFIG +{ + u32 sign1; // 0x12071980; + u32 sign2; // 0x26111975; +}; + +struct MSYS_PING +{ + u32 sign1; // 0x12071980; + u32 sign2; // 0x26111975; + u32 dwTime_ClientSend; + u32 dwTime_Server; + u32 dwTime_ClientReceive; +}; + + +#pragma pack(pop) diff --git a/xrNetServer/NET_PlayersMonitor.h b/xrNetServer/NET_PlayersMonitor.h new file mode 100644 index 00000000000..cf2d033b91d --- /dev/null +++ b/xrNetServer/NET_PlayersMonitor.h @@ -0,0 +1,274 @@ +#ifndef NET_PLAYERS_MONITOR +#define NET_PLAYERS_MONITOR + +#include "net_shared.h" +#include "NET_Common.h" +#include "../xrCore/fastdelegate.h" + +class IClient; + +class PlayersMonitor +{ +private: + typedef xr_vector players_collection_t; + xrCriticalSection csPlayers; + players_collection_t net_Players; + players_collection_t net_Players_disconnected; + bool now_iterating_in_net_players; + bool now_iterating_in_net_players_disconn; +#ifdef DEBUG + DWORD iterator_thread_id; +#endif +public: + PlayersMonitor() + { + now_iterating_in_net_players = false; + now_iterating_in_net_players_disconn = false; +#ifdef DEBUG + iterator_thread_id = 0; +#endif + } +#ifdef DEBUG + bool IsCurrentThreadIteratingOnClients() const + { + if (now_iterating_in_net_players || now_iterating_in_net_players_disconn) + { + if (iterator_thread_id == GetCurrentThreadId()) + { + return true; + } + } + return false; + } +#endif + template + void ForEachClientDo (ActionFunctor & functor) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + now_iterating_in_net_players = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + for (players_collection_t::iterator i = net_Players.begin(), + ie = net_Players.end(); i != ie; ++i) + { + VERIFY2(*i != NULL, "IClient ptr is NULL"); + functor(*i); + } + now_iterating_in_net_players = false; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + } + void ForEachClientDo (fastdelegate::FastDelegate1 & fast_delegate) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + now_iterating_in_net_players = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + for (players_collection_t::iterator i = net_Players.begin(), + ie = net_Players.end(); i != ie; ++i) + { + VERIFY2(*i != NULL, "IClient ptr is NULL"); + fast_delegate(*i); + } + now_iterating_in_net_players = false; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + } + template + u32 ForFoundClientsDo (SearchPredicate const & predicate, ActionFunctor & functor) + { + u32 ret_count = 0; + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + now_iterating_in_net_players = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + players_collection_t::iterator players_endi = net_Players.end(); + players_collection_t::iterator temp_iter = std::find_if( + net_Players.begin(), + players_endi, + predicate); + + while (temp_iter != players_endi) + { + VERIFY2(*temp_iter != NULL, "IClient ptr is NULL"); + functor(*temp_iter); + temp_iter = std::find_if(++temp_iter, players_endi, predicate); + } + now_iterating_in_net_players = false; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + return ret_count; + } + + template + IClient* FindAndEraseClient (SearchPredicate const & predicate) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + VERIFY(!now_iterating_in_net_players); + now_iterating_in_net_players = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + players_collection_t::iterator client_iter = std::find_if( + net_Players.begin(), + net_Players.end(), + predicate); + IClient* ret_client = NULL; + if (client_iter != net_Players.end()) + { + ret_client = *client_iter; + net_Players.erase(client_iter); + } + now_iterating_in_net_players = false; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + return ret_client; + } + template + IClient* GetFoundClient (SearchPredicate const & predicate) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + players_collection_t::iterator client_iter = std::find_if( + net_Players.begin(), + net_Players.end(), + predicate); + IClient* ret_client = NULL; + if (client_iter != net_Players.end()) + { + ret_client = *client_iter; + } + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + return ret_client; + } + void AddNewClient (IClient* new_client) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + VERIFY(!now_iterating_in_net_players); + net_Players.push_back(new_client); + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + } + + /*template + void ForEachDisconnectedClientDo (ActionFunctor & functor) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + now_iterating_in_net_players_disconn = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + std::for_each(net_Players_disconnected.begin(), net_Players_disconnected.end(), functor); + now_iterating_in_net_players_disconn = false; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + } + template + IClient* FindAndEraseDisconnectedClient (SearchPredicate const & predicate) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + VERIFY(!now_iterating_in_net_players_disconn); + now_iterating_in_net_players_disconn = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + players_collection_t::iterator client_iter = std::find_if( + net_Players_disconnected.begin(), + net_Players_disconnected.end(), + predicate); + IClient* ret_client = NULL; + if (client_iter != net_Players_disconnected.end()) + { + ret_client = *client_iter; + net_Players_disconnected.erase(client_iter); + } + now_iterating_in_net_players_disconn = false; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + return ret_client; + } + template + IClient* GetFoundDisconnectedClient (SearchPredicate const & predicate) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + now_iterating_in_net_players_disconn = true; +#ifdef DEBUG + iterator_thread_id = GetCurrentThreadId(); +#endif + players_collection_t::iterator client_iter = std::find_if( + net_Players_disconnected.begin(), + net_Players_disconnected.end(), + predicate); + now_iterating_in_net_players_disconn = false; + IClient* ret_client = NULL; + if (client_iter != net_Players_disconnected.end()) + ret_client = *client_iter; + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + return ret_client; + } + void AddNewDisconnectedClient (IClient* new_client) + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + VERIFY(!now_iterating_in_net_players_disconn); + net_Players_disconnected.push_back(new_client); + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + }*/ + + u32 ClientsCount () + { + //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csPlayers [%d]", GetCurrentThreadId()).c_str()); + u32 ret_count = net_Players.size(); + //Msg("-S- Leaving from csPlayers [%d]", GetCurrentThreadId()); + csPlayers.Leave(); + return ret_count; + } + //WARNING! for iteration in vector use ForEachClientDo ! + //This function can be used carefully (single call) + /*IClient* GetClientByIndex (u32 index) + { + csPlayers.Enter(); + IClient* ret_client = net_Players[index]; + csPlayers.Leave(); + return ret_client; + }*/ +}; //class PlayersMonitor + +#endif //#ifndef NET_PLAYERS_MONITOR \ No newline at end of file diff --git a/xrNetServer/NET_Server.cpp b/xrNetServer/NET_Server.cpp new file mode 100644 index 00000000000..3f1ccbe84ba --- /dev/null +++ b/xrNetServer/NET_Server.cpp @@ -0,0 +1,1021 @@ +#include "stdafx.h" +#include "dxerr.h" +#include "NET_Common.h" +#include "net_server.h" +#include + +#include "NET_Log.h" +#include "../xrGameSpy/xrGameSpy_MainDefs.h" + +#pragma warning(push) +#pragma warning(disable:4995) +#include +#pragma warning(pop) + +static INetLog* pSvNetLog = NULL; + +#define NET_BANNED_STR "Player banned by server!" +#define NET_PROTECTED_SERVER_STR "Access denied by protected server for this player!" +#define NET_NOTFOR_SUBNET_STR "Your IP does not present in server's subnet" + +void dump_URL (LPCSTR p, IDirectPlay8Address* A); + +LPCSTR nameTraffic = "traffic.net"; + +XRNETSERVER_API int psNET_ServerUpdate = 30; // FPS +XRNETSERVER_API int psNET_ServerPending = 3; + +XRNETSERVER_API ClientID BroadcastCID(0xffffffff); + +void ip_address::set(LPCSTR src_string) +{ + u32 buff[4]; + int cnt = sscanf(src_string, "%d.%d.%d.%d", &buff[0], &buff[1], &buff[2], &buff[3]); + if(cnt==4) + { + m_data.a1 = u8(buff[0]&0xff); + m_data.a2 = u8(buff[1]&0xff); + m_data.a3 = u8(buff[2]&0xff); + m_data.a4 = u8(buff[3]&0xff); + }else + { + Msg ("! Bad ipAddress format [%s]",src_string); + m_data.data = 0; + } +} + +xr_string ip_address::to_string() const +{ + string128 res; + xr_sprintf (res,sizeof(res),"%d.%d.%d.%d", m_data.a1, m_data.a2, m_data.a3, m_data.a4); + return res; +} + +void IBannedClient::Load(CInifile& ini, const shared_str& sect) +{ + HAddr.set (sect.c_str()); + + tm _tm_banned; + const shared_str& time_to = ini.r_string(sect,"time_to"); + int res_t = sscanf( time_to.c_str(), + "%02d.%02d.%d_%02d:%02d:%02d", + &_tm_banned.tm_mday, + &_tm_banned.tm_mon, + &_tm_banned.tm_year, + &_tm_banned.tm_hour, + &_tm_banned.tm_min, + &_tm_banned.tm_sec); + VERIFY(res_t==6); + + _tm_banned.tm_mon -= 1; + _tm_banned.tm_year -= 1900; + + BanTime = mktime(&_tm_banned); + + Msg("- loaded banned client %s to %s", HAddr.to_string().c_str(), BannedTimeTo().c_str()); +} + +void IBannedClient::Save(CInifile& ini) +{ + ini.w_string (HAddr.to_string().c_str(), "time_to", BannedTimeTo().c_str()); +} + +xr_string IBannedClient::BannedTimeTo() const +{ + string256 res; + tm* _tm_banned; + _tm_banned = _localtime64(&BanTime); + xr_sprintf ( res, sizeof(res), + "%02d.%02d.%d_%02d:%02d:%02d", + _tm_banned->tm_mday, + _tm_banned->tm_mon+1, + _tm_banned->tm_year+1900, + _tm_banned->tm_hour, + _tm_banned->tm_min, + _tm_banned->tm_sec); + + return res; +} + +IClient::IClient( CTimer* timer ) + : stats(timer), + server(NULL) +{ + dwTime_LastUpdate = 0; + flags.bLocal = FALSE; + flags.bConnected = FALSE; + flags.bReconnect = FALSE; + flags.bVerified = TRUE; +} + +IClient::~IClient() +{ +} + +void IClientStatistic::Update(DPN_CONNECTION_INFO& CI) +{ + u32 time_global = TimeGlobal(device_timer); + if (time_global-dwBaseTime >= 999) + { + dwBaseTime = time_global; + + mps_recive = CI.dwMessagesReceived - mps_receive_base; + mps_receive_base= CI.dwMessagesReceived; + + u32 cur_msend = CI.dwMessagesTransmittedHighPriority+CI.dwMessagesTransmittedNormalPriority+CI.dwMessagesTransmittedLowPriority; + mps_send = cur_msend - mps_send_base; + mps_send_base = cur_msend; + + dwBytesSendedPerSec = dwBytesSended; + dwBytesSended = 0; + dwBytesReceivedPerSec = dwBytesReceived; + dwBytesReceived = 0; + } + ci_last = CI; +} + +// {0218FA8B-515B-4bf2-9A5F-2F079D1759F3} +static const GUID NET_GUID = +{ 0x218fa8b, 0x515b, 0x4bf2, { 0x9a, 0x5f, 0x2f, 0x7, 0x9d, 0x17, 0x59, 0xf3 } }; +// {8D3F9E5E-A3BD-475b-9E49-B0E77139143C} +static const GUID CLSID_NETWORKSIMULATOR_DP8SP_TCPIP = +{ 0x8d3f9e5e, 0xa3bd, 0x475b, { 0x9e, 0x49, 0xb0, 0xe7, 0x71, 0x39, 0x14, 0x3c } }; + +static HRESULT WINAPI Handler (PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage) +{ + IPureServer* C = (IPureServer*)pvUserContext; + return C->net_Handler (dwMessageType,pMessage); +} + + +//------------------------------------------------------------------------------ + +void +IClient::_SendTo_LL( const void* data, u32 size, u32 flags, u32 timeout ) +{ + R_ASSERT(server); + server->IPureServer::SendTo_LL( ID, const_cast(data), size, flags, timeout ); +} + + +//------------------------------------------------------------------------------ +IClient* IPureServer::ID_to_client (ClientID ID, bool ScanAll) +{ + if ( 0 == ID.value() ) return NULL; + IClient* ret_client = GetClientByID(ID); + if (ret_client || !ScanAll) + return ret_client; + + return NULL; +} + +void +IPureServer::_Recieve( const void* data, u32 data_size, u32 param ) +{ + if (data_size >= NET_PacketSizeLimit) { + Msg ("! too large packet size[%d] received, DoS attack?", data_size); + return; + } + + NET_Packet packet; + ClientID id; + + id.set( param ); + packet.construct( data, data_size ); + //DWORD currentThreadId = GetCurrentThreadId(); + //Msg("-S- Entering to csMessages from _Receive [%d]", currentThreadId); + csMessage.Enter(); + //LogStackTrace( + // make_string("-S- Entered to csMessages [%d]", currentThreadId).c_str()); + //--------------------------------------- + if( psNET_Flags.test(NETFLAG_LOG_SV_PACKETS) ) + { + if( !pSvNetLog) + pSvNetLog = xr_new("logs\\net_sv_log.log", TimeGlobal(device_timer)); + + if( pSvNetLog ) + pSvNetLog->LogPacket( TimeGlobal(device_timer), &packet, TRUE ); + } + //--------------------------------------- + u32 result = OnMessage( packet, id ); + //Msg("-S- Leaving from csMessages [%d]", currentThreadId); + csMessage.Leave(); + + if( result ) + SendBroadcast( id, packet, result ); +} + +//============================================================================== + +IPureServer::IPureServer (CTimer* timer, BOOL Dedicated) + : m_bDedicated(Dedicated) +#ifdef PROFILE_CRITICAL_SECTIONS + ,csPlayers(MUTEX_PROFILE_ID(IPureServer::csPlayers)) + ,csMessage(MUTEX_PROFILE_ID(IPureServer::csMessage)) +#endif // PROFILE_CRITICAL_SECTIONS +{ + device_timer = timer; + stats.clear (); + stats.dwSendTime = TimeGlobal(device_timer); + SV_Client = NULL; + NET = NULL; + net_Address_device = NULL; + pSvNetLog = NULL;//xr_new("logs\\net_sv_log.log", TimeGlobal(device_timer)); +#ifdef DEBUG + sender_functor_invoked = false; +#endif +} + +IPureServer::~IPureServer () +{ + for (u32 it=0; it 32 || dwMaxPlayers<1) dwMaxPlayers = 32; +#ifdef DEBUG + Msg("MaxPlayers = %d", dwMaxPlayers); +#endif // #ifdef DEBUG + + //------------------------------------------------------------------- + BOOL bPortWasSet = FALSE; + u32 dwServerPort = START_PORT_LAN_SV; + if (strstr(options, "portsv=")) + { + const char* ServerPort = strstr(options, "portsv=") + 7; + string64 tmpStr = ""; + if (strchr(ServerPort, '/')) + strncpy_s(tmpStr, ServerPort, strchr(ServerPort, '/') - ServerPort); + else + strncpy_s(tmpStr, ServerPort, 63); + dwServerPort = atol(tmpStr); + clamp(dwServerPort, u32(START_PORT), u32(END_PORT)); + bPortWasSet = TRUE; //this is not casual game + } + //------------------------------------------------------------------- + +if(!psNET_direct_connect) +{ + //--------------------------- +#ifdef DEBUG + string1024 tmp; +#endif // DEBUG +// HRESULT CoInitializeExRes = CoInitializeEx(NULL, 0); +// if (CoInitializeExRes != S_OK && CoInitializeExRes != S_FALSE) +// { +// DXTRACE_ERR(tmp, CoInitializeExRes); +// CHK_DX(CoInitializeExRes); +// }; + //--------------------------- + // Create the IDirectPlay8Client object. + HRESULT CoCreateInstanceRes = CoCreateInstance (CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Server, (LPVOID*) &NET); + //--------------------------- + if (CoCreateInstanceRes != S_OK) + { + DXTRACE_ERR(tmp, CoCreateInstanceRes ); + CHK_DX(CoCreateInstanceRes ); + } + //--------------------------- + + // Initialize IDirectPlay8Client object. +#ifdef DEBUG + CHK_DX(NET->Initialize (this, Handler, 0)); +#else + CHK_DX(NET->Initialize (this, Handler, DPNINITIALIZE_DISABLEPARAMVAL)); +#endif + + BOOL bSimulator = FALSE; + if (strstr(Core.Params,"-netsim")) bSimulator = TRUE; + + + // dump_URL ("! sv ", net_Address_device); + + // Set server-player info + DPN_APPLICATION_DESC dpAppDesc; + DPN_PLAYER_INFO dpPlayerInfo; + WCHAR wszName [] = L"XRay Server"; + + ZeroMemory (&dpPlayerInfo, sizeof(DPN_PLAYER_INFO)); + dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); + dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; + dpPlayerInfo.pwszName = wszName; + dpPlayerInfo.pvData = NULL; + dpPlayerInfo.dwDataSize = NULL; + dpPlayerInfo.dwPlayerFlags = 0; + + CHK_DX(NET->SetServerInfo( &dpPlayerInfo, NULL, NULL, DPNSETSERVERINFO_SYNC ) ); + + // Set server/session description + WCHAR SessionNameUNICODE[4096]; + CHK_DX(MultiByteToWideChar(CP_ACP, 0, session_name, -1, SessionNameUNICODE, 4096 )); + // Set server/session description + + // Now set up the Application Description + ZeroMemory (&dpAppDesc, sizeof(DPN_APPLICATION_DESC)); + dpAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); + dpAppDesc.dwFlags = DPNSESSION_CLIENT_SERVER | DPNSESSION_NODPNSVR; + dpAppDesc.guidApplication = NET_GUID; + dpAppDesc.pwszSessionName = SessionNameUNICODE; + dpAppDesc.dwMaxPlayers = (m_bDedicated) ? (dwMaxPlayers+2) : (dwMaxPlayers+1); + dpAppDesc.pvApplicationReservedData = &game_descr; + dpAppDesc.dwApplicationReservedDataSize = sizeof(game_descr); + + WCHAR SessionPasswordUNICODE[4096]; + if (xr_strlen(password_str)) + { + CHK_DX(MultiByteToWideChar(CP_ACP, 0, password_str, -1, SessionPasswordUNICODE, 4096 )); + dpAppDesc.dwFlags |= DPNSESSION_REQUIREPASSWORD; + dpAppDesc.pwszPassword = SessionPasswordUNICODE; + }; + + // Create our IDirectPlay8Address Device Address, --- Set the SP for our Device Address + net_Address_device = NULL; + CHK_DX(CoCreateInstance (CLSID_DirectPlay8Address,NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address,(LPVOID*) &net_Address_device )); + CHK_DX(net_Address_device->SetSP (bSimulator? &CLSID_NETWORKSIMULATOR_DP8SP_TCPIP : &CLSID_DP8SP_TCPIP )); + + DWORD dwTraversalMode = DPNA_TRAVERSALMODE_NONE; + CHK_DX(net_Address_device->AddComponent(DPNA_KEY_TRAVERSALMODE, &dwTraversalMode, sizeof(dwTraversalMode), DPNA_DATATYPE_DWORD)); + + HRESULT HostSuccess = S_FALSE; + // We are now ready to host the app and will try different ports + psNET_Port = dwServerPort; + while (HostSuccess != S_OK) + { + CHK_DX(net_Address_device->AddComponent (DPNA_KEY_PORT, &psNET_Port, sizeof(psNET_Port), DPNA_DATATYPE_DWORD )); + + HostSuccess = NET->Host + ( + &dpAppDesc, // AppDesc + &net_Address_device, 1, // Device Address + NULL, NULL, // Reserved + NULL, // Player Context + 0 ); // dwFlags + if (HostSuccess != S_OK) + { +// xr_string res = Debug.error2string(HostSuccess); + if (bPortWasSet) + { + Msg("! IPureServer : port %d is BUSY!", psNET_Port); + return ErrConnect; + } + else + { + Msg("! IPureServer : port %d is BUSY!", psNET_Port); + } + + psNET_Port++; + if (psNET_Port > END_PORT_LAN) + { + return ErrConnect; + } + } + else + { + Msg("- IPureServer : created on port %d!", psNET_Port); + } + }; + + CHK_DX(HostSuccess); + +} //psNET_direct_connect + +//. config_Load (); + + if(!psNET_direct_connect) + { + BannedList_Load (); + IpList_Load(); + } + + return ErrNoError; +} + +void IPureServer::Disconnect () +{ +//. config_Save (); + + if (!psNET_direct_connect) + { + BannedList_Save (); + IpList_Unload (); + } + + if( NET ) NET->Close(0); + + // Release interfaces + _RELEASE (net_Address_device); + _RELEASE (NET); +} + +HRESULT IPureServer::net_Handler(u32 dwMessageType, PVOID pMessage) +{ + // HRESULT hr = S_OK; + + switch (dwMessageType) + { + case DPN_MSGID_ENUM_HOSTS_QUERY : + { + PDPNMSG_ENUM_HOSTS_QUERY msg = PDPNMSG_ENUM_HOSTS_QUERY(pMessage); + if (0 == msg->dwReceivedDataSize) return S_FALSE; + if (!stricmp((const char*)msg->pvReceivedData, "ToConnect")) return S_OK; + if (*((const GUID*) msg->pvReceivedData) != NET_GUID) return S_FALSE; + if (!OnCL_QueryHost()) return S_FALSE; + return S_OK; + }break; + case DPN_MSGID_CREATE_PLAYER : + { + PDPNMSG_CREATE_PLAYER msg = PDPNMSG_CREATE_PLAYER(pMessage); + const u32 max_size = 1024; + char bufferData [max_size]; + DWORD bufferSize = max_size; + ZeroMemory (bufferData,bufferSize); + string512 res; + + // retreive info + DPN_PLAYER_INFO* Pinfo = (DPN_PLAYER_INFO*) bufferData; + Pinfo->dwSize = sizeof(DPN_PLAYER_INFO); + HRESULT _hr = NET->GetClientInfo( msg->dpnidPlayer, Pinfo, &bufferSize, 0 ); + if( _hr == DPNERR_INVALIDPLAYER ) + { + Assign_ServerType( res ); //once + break; // server player + } + + CHK_DX (_hr); + + //string64 cname; + //CHK_DX( WideCharToMultiByte( CP_ACP, 0, Pinfo->pwszName, -1, cname, sizeof(cname) , 0, 0 ) ); + + SClientConnectData cl_data; + //xr_strcpy( cl_data.name, cname ); + + if( Pinfo->pvData && Pinfo->dwDataSize == sizeof(cl_data) ) + { + cl_data = *((SClientConnectData*)Pinfo->pvData); + } + cl_data.clientID.set( msg->dpnidPlayer ); + + new_client( &cl_data ); + } + break; + case DPN_MSGID_DESTROY_PLAYER: + { + PDPNMSG_DESTROY_PLAYER msg = PDPNMSG_DESTROY_PLAYER(pMessage); + IClient* tmp_client = net_players.GetFoundClient( + ClientIdSearchPredicate(static_cast(msg->dpnidPlayer)) + ); + if (tmp_client) + { + tmp_client->flags.bConnected = FALSE; + tmp_client->flags.bReconnect = FALSE; + OnCL_Disconnected (tmp_client); + // real destroy + client_Destroy (tmp_client); + } + } + break; + case DPN_MSGID_RECEIVE: + { + + PDPNMSG_RECEIVE pMsg = PDPNMSG_RECEIVE(pMessage); + void* m_data = pMsg->pReceiveData; + u32 m_size = pMsg->dwReceiveDataSize; + DPNID m_sender = pMsg->dpnidSender; + + MSYS_PING* m_ping = (MSYS_PING*)m_data; + + if ((m_size>2*sizeof(u32)) && (m_ping->sign1==0x12071980) && (m_ping->sign2==0x26111975)) + { + // this is system message + if (m_size==sizeof(MSYS_PING)) + { + // ping - save server time and reply + m_ping->dwTime_Server = TimerAsync(device_timer); + ClientID ID; ID.set(m_sender); + // IPureServer::SendTo_LL (ID,m_data,m_size,net_flags(FALSE,FALSE,TRUE)); + IPureServer::SendTo_Buf (ID,m_data,m_size,net_flags(FALSE,FALSE,TRUE, TRUE)); + } + } + else + { + MultipacketReciever::RecievePacket( pMsg->pReceiveData, pMsg->dwReceiveDataSize, m_sender ); + } + } break; + + case DPN_MSGID_INDICATE_CONNECT : + { + PDPNMSG_INDICATE_CONNECT msg = (PDPNMSG_INDICATE_CONNECT)pMessage; + + ip_address HAddr; + GetClientAddress (msg->pAddressPlayer, HAddr); + + if (GetBannedClient(HAddr)) + { + msg->dwReplyDataSize = sizeof(NET_BANNED_STR); + msg->pvReplyData = NET_BANNED_STR; + return S_FALSE; + }; + //first connected client is SV_Client so if it is NULL then this server client tries to connect ;) + if (SV_Client && !m_ip_filter.is_ip_present(HAddr.m_data.data)) + { + msg->dwReplyDataSize = sizeof(NET_NOTFOR_SUBNET_STR); + msg->pvReplyData = NET_NOTFOR_SUBNET_STR; + return S_FALSE; + } + }break; + } + return S_OK; +} + +void IPureServer::Flush_Clients_Buffers () +{ + #if NET_LOG_PACKETS + Msg( "#flush server send-buf" ); + #endif + + struct LocalSenderFunctor + { + static void FlushBuffer(IClient* client) + { + client->MultipacketSender::FlushSendBuffer(0); + } + }; + + net_players.ForEachClientDo( + LocalSenderFunctor::FlushBuffer + ); +} + +void IPureServer::SendTo_Buf(ClientID id, void* data, u32 size, u32 dwFlags, u32 dwTimeout) +{ + IClient* tmp_client = net_players.GetFoundClient( + ClientIdSearchPredicate(id)); + VERIFY(tmp_client); + tmp_client->MultipacketSender::SendPacket(data, size, dwFlags, dwTimeout); +} + + +void IPureServer::SendTo_LL(ClientID ID/*DPNID ID*/, void* data, u32 size, u32 dwFlags, u32 dwTimeout) +{ + // if (psNET_Flags.test(NETFLAG_LOG_SV_PACKETS)) pSvNetLog->LogData(TimeGlobal(device_timer), data, size); + if (psNET_Flags.test(NETFLAG_LOG_SV_PACKETS)) + { + if (!pSvNetLog) pSvNetLog = xr_new("logs\\net_sv_log.log", TimeGlobal(device_timer)); + if (pSvNetLog) pSvNetLog->LogData(TimeGlobal(device_timer), data, size); + } + + // send it + DPN_BUFFER_DESC desc; + desc.dwBufferSize = size; + desc.pBufferData = LPBYTE(data); + +#ifdef _DEBUG + u32 time_global = TimeGlobal(device_timer); + if (time_global - stats.dwSendTime >= 999) + { + stats.dwBytesPerSec = (stats.dwBytesPerSec*9 + stats.dwBytesSended)/10; + stats.dwBytesSended = 0; + stats.dwSendTime = time_global; + }; + if ( ID.value() ) + stats.dwBytesSended += size; +#endif + + // verify + VERIFY (desc.dwBufferSize); + VERIFY (desc.pBufferData); + + DPNHANDLE hAsync = 0; + HRESULT _hr = NET->SendTo( + ID.value(), + &desc,1, + dwTimeout, + 0,&hAsync, + dwFlags | DPNSEND_COALESCE + ); + + +// Msg("- IPureServer::SendTo_LL [%d]", size); + + if (SUCCEEDED(_hr) || (DPNERR_CONNECTIONLOST==_hr)) return; + + R_CHK (_hr); + +} + +void IPureServer::SendTo (ClientID ID/*DPNID ID*/, NET_Packet& P, u32 dwFlags, u32 dwTimeout) +{ + SendTo_LL( ID, P.B.data, P.B.count, dwFlags, dwTimeout ); +} + +void IPureServer::SendBroadcast_LL(ClientID exclude, void* data, u32 size, u32 dwFlags) +{ + struct ClientExcluderPredicate + { + ClientID id_to_exclude; + ClientExcluderPredicate(ClientID exclude) : + id_to_exclude(exclude) + {} + bool operator()(IClient* client) + { + if (client->ID == id_to_exclude) + return false; + if (!client->flags.bConnected) + return false; + return true; + } + }; + struct ClientSenderFunctor + { + IPureServer* m_owner; + void* m_data; + u32 m_size; + u32 m_dwFlags; + ClientSenderFunctor(IPureServer* owner, void* data, u32 size, u32 dwFlags) : + m_owner(owner), m_data(data), m_size(size), m_dwFlags(dwFlags) + {} + void operator()(IClient* client) + { + m_owner->SendTo_LL(client->ID, m_data, m_size, m_dwFlags); + } + }; + ClientSenderFunctor temp_functor(this, data, size, dwFlags); + net_players.ForFoundClientsDo(ClientExcluderPredicate(exclude), temp_functor); +} + +void IPureServer::SendBroadcast(ClientID exclude, NET_Packet& P, u32 dwFlags) +{ + // Perform broadcasting + SendBroadcast_LL( exclude, P.B.data, P.B.count, dwFlags ); +} + +u32 IPureServer::OnMessage (NET_Packet& P, ClientID sender) // Non-Zero means broadcasting with "flags" as returned +{ + /* + u16 m_type; + P.r_begin (m_type); + switch (m_type) + { + case M_CHAT: + { + char buffer[256]; + P.r_string(buffer); + printf ("RECEIVE: %s\n",buffer); + } + break; + } + */ + + return 0; +} + +void IPureServer::OnCL_Connected (IClient* CL) +{ + Msg("* Player 0x%08x connected.\n", CL->ID.value()); +} +void IPureServer::OnCL_Disconnected (IClient* CL) +{ + Msg("* Player 0x%08x disconnected.\n", CL->ID.value()); +} + +BOOL IPureServer::HasBandwidth (IClient* C) +{ + u32 dwTime = TimeGlobal(device_timer); + u32 dwInterval = 0; + + if(psNET_direct_connect) + { + UpdateClientStatistic (C); + C->dwTime_LastUpdate = dwTime; + dwInterval = 1000; + return TRUE; + } + + if (psNET_ServerUpdate != 0) dwInterval = 1000/psNET_ServerUpdate; + if (psNET_Flags.test(NETFLAG_MINIMIZEUPDATES)) dwInterval = 1000; // approx 2 times per second + + HRESULT hr; + if (psNET_ServerUpdate != 0 && (dwTime-C->dwTime_LastUpdate)>dwInterval) + { + // check queue for "empty" state + DWORD dwPending; + hr = NET->GetSendQueueInfo(C->ID.value(),&dwPending,0,0); + if (FAILED(hr)) return FALSE; + + if (dwPending > u32(psNET_ServerPending)) + { + C->stats.dwTimesBlocked++; + return FALSE; + }; + + UpdateClientStatistic(C); + // ok + C->dwTime_LastUpdate = dwTime; + return TRUE; + } + return FALSE; +} + +void IPureServer::UpdateClientStatistic (IClient* C) +{ + // Query network statistic for this client + DPN_CONNECTION_INFO CI; + ZeroMemory (&CI,sizeof(CI)); + CI.dwSize = sizeof(CI); + if(!psNET_direct_connect) + { + HRESULT hr = NET->GetConnectionInfo(C->ID.value(),&CI,0); + if (FAILED(hr)) return; + } + C->stats.Update (CI); +} + +void IPureServer::ClearStatistic () +{ + stats.clear(); + struct StatsClearFunctor + { + static void Clear(IClient* client) + { + client->stats.Clear(); + } + }; + net_players.ForEachClientDo(StatsClearFunctor::Clear); +}; + +/*bool IPureServer::DisconnectClient (IClient* C) +{ + if (!C) return false; + + string64 Reason = "st_kicked_by_server"; + HRESULT res = NET->DestroyClient(C->ID.value(), Reason, xr_strlen(Reason)+1, 0); + CHK_DX(res); + return true; +}*/ + +bool IPureServer::DisconnectClient (IClient* C, LPCSTR Reason) +{ + if (!C) return false; + + HRESULT res = NET->DestroyClient(C->ID.value(), Reason, xr_strlen(Reason)+1, 0); + CHK_DX(res); + return true; +} + +bool IPureServer::DisconnectAddress (const ip_address& Address, LPCSTR reason) +{ + u32 players_count = net_players.ClientsCount(); + buffer_vector PlayersToDisconnect( + _alloca(players_count * sizeof(IClient*)), + players_count + ); + struct ToDisconnectFillerFunctor + { + IPureServer* m_owner; + buffer_vector* dest; + ip_address const* address_to_disconnect; + ToDisconnectFillerFunctor(IPureServer* owner, buffer_vector* dest_disconnect, ip_address const* address) : + m_owner(owner), dest(dest_disconnect), address_to_disconnect(address) + {} + void operator()(IClient* client) + { + ip_address tmp_address; + m_owner->GetClientAddress(client->ID, tmp_address); + if (*address_to_disconnect == tmp_address) + { + dest->push_back(client); + }; + } + }; + ToDisconnectFillerFunctor tmp_functor(this, &PlayersToDisconnect, &Address); + net_players.ForEachClientDo(tmp_functor); + + buffer_vector::iterator it = PlayersToDisconnect.begin(); + buffer_vector::iterator it_e = PlayersToDisconnect.end(); + + for ( ;it!=it_e; ++it) + { + DisconnectClient(*it, reason); + } + return true; +} + +bool IPureServer::GetClientAddress (IDirectPlay8Address* pClientAddress, ip_address& Address, DWORD* pPort) +{ + WCHAR wstrHostname[ 256 ] = {0}; + DWORD dwSize = sizeof(wstrHostname); + DWORD dwDataType = 0; + CHK_DX(pClientAddress->GetComponentByName( DPNA_KEY_HOSTNAME, wstrHostname, &dwSize, &dwDataType )); + + string256 HostName; + CHK_DX(WideCharToMultiByte(CP_ACP,0,wstrHostname,-1,HostName,sizeof(HostName),0,0)); + + Address.set (HostName); + + if (pPort != NULL) + { + DWORD dwPort = 0; + DWORD dwPortSize = sizeof(dwPort); + DWORD dwPortDataType = DPNA_DATATYPE_DWORD; + CHK_DX(pClientAddress->GetComponentByName( DPNA_KEY_PORT, &dwPort, &dwPortSize, &dwPortDataType )); + *pPort = dwPort; + }; + + return true; +}; + +bool IPureServer::GetClientAddress (ClientID ID, ip_address& Address, DWORD* pPort) +{ + IDirectPlay8Address* pClAddr = NULL; + CHK_DX(NET->GetClientAddress (ID.value(), &pClAddr, 0)); + + return GetClientAddress (pClAddr, Address, pPort); +}; + +IBannedClient* IPureServer::GetBannedClient(const ip_address& Address) +{ + for (u32 it=0; itHAddr == Address ) + return pBClient; + } + return NULL; +}; + +void IPureServer::BanClient(IClient* C, u32 BanTime) +{ + ip_address ClAddress; + GetClientAddress (C->ID, ClAddress); + BanAddress (ClAddress, BanTime); +}; + +void IPureServer::BanAddress(const ip_address& Address, u32 BanTimeSec) +{ + if (GetBannedClient(Address)) + { + Msg("Already banned\n"); + return; + }; + + IBannedClient* pNewClient = xr_new(); + pNewClient->HAddr = Address; + time (&pNewClient->BanTime); + pNewClient->BanTime += BanTimeSec; + if (pNewClient) + { + BannedAddresses.push_back (pNewClient); + BannedList_Save (); + } +}; + +void IPureServer::UnBanAddress (const ip_address& Address) +{ + if (!GetBannedClient(Address)) + { + Msg("! Can't find address %s in ban list.", Address.to_string().c_str() ); + return; + }; + + for (u32 it=0; itHAddr == Address) + { + xr_delete (BannedAddresses[it]); + BannedAddresses.erase (BannedAddresses.begin()+it); + Msg ("Unbanning %s", Address.to_string().c_str() ); + BannedList_Save (); + break; + } + }; +}; + +void IPureServer::Print_Banned_Addreses () +{ + Msg("- ----banned ip list begin-------"); + for (u32 i=0; iHAddr.to_string().c_str(), pBClient->BannedTimeTo().c_str() ); + } + Msg("- ----banned ip list end-------"); +} + +void IPureServer::BannedList_Save () +{ + string_path temp; + FS.update_path (temp,"$app_data_root$", GetBannedListName()); + + CInifile ini(temp,FALSE,FALSE,TRUE); + + for (u32 it=0; itSave (ini); + }; +} + +void IPureServer::BannedList_Load() +{ + string_path temp; + FS.update_path (temp,"$app_data_root$", GetBannedListName()); + + CInifile ini(temp); + + CInifile::RootIt it = ini.sections().begin(); + CInifile::RootIt it_e = ini.sections().end(); + + for( ;it!=it_e; ++it) + { + const shared_str& sect_name = (*it)->Name; + IBannedClient* Cl = xr_new(); + Cl->Load (ini, sect_name); + BannedAddresses.push_back (Cl); + } +} + +void IPureServer::IpList_Load() +{ + Msg("* Initializing IP filter."); + m_ip_filter.load(); +} +void IPureServer::IpList_Unload() +{ + Msg("* Deinitializing IP filter."); + m_ip_filter.unload(); +} +bool IPureServer::IsPlayerIPDenied(u32 ip_address) +{ + return !m_ip_filter.is_ip_present(ip_address); +} + +bool banned_client_comparer(IBannedClient* C1, IBannedClient* C2) +{ + return C1->BanTime > C2->BanTime; +} + +void IPureServer::UpdateBannedList() +{ + if(!BannedAddresses.size()) return; + std::sort(BannedAddresses.begin(),BannedAddresses.end(), banned_client_comparer ); + time_t T; + time (&T); + + IBannedClient* Cl = BannedAddresses.back(); + if(Cl->BanTimeHAddr; + UnBanAddress (Address); + } +} + +LPCSTR IPureServer::GetBannedListName() +{ + return "banned_list_ip.ltx"; +} \ No newline at end of file diff --git a/xrNetServer/NET_Server.h b/xrNetServer/NET_Server.h new file mode 100644 index 00000000000..f8e6ed683c9 --- /dev/null +++ b/xrNetServer/NET_Server.h @@ -0,0 +1,295 @@ +#pragma once + +#include "net_shared.h" +#include "ip_filter.h" +#include "NET_Common.h" +#include "NET_PlayersMonitor.h" + +struct SClientConnectData +{ + ClientID clientID; + string64 name; + string64 pass; + u32 process_id; + + SClientConnectData() + { + name[0] = pass[0] = 0; + process_id = 0; + } +}; + +// ----------------------------------------------------- + +class IPureServer; + +struct XRNETSERVER_API ip_address +{ + union{ + struct{ + u8 a1; + u8 a2; + u8 a3; + u8 a4; + }; + u32 data; + }m_data; + void set (LPCSTR src_string); + xr_string to_string () const; + + bool operator == (const ip_address& other) const + { + return (m_data.data==other.m_data.data) || + ( (m_data.a1==other.m_data.a1) && + (m_data.a2==other.m_data.a2) && + (m_data.a3==other.m_data.a3) && + (m_data.a4==0) ); + } +}; + +class XRNETSERVER_API +IClient : public MultipacketSender +{ +public: + struct Flags + { + u32 bLocal : 1; + u32 bConnected : 1; + u32 bReconnect : 1; + u32 bVerified : 1; + }; + + IClient( CTimer* timer ); + virtual ~IClient(); + + IClientStatistic stats; + + ClientID ID; + string128 m_guid; + shared_str name; + shared_str pass; + + Flags flags; // local/host/normal + u32 dwTime_LastUpdate; + + ip_address m_cAddress; + DWORD m_dwPort; + u32 process_id; + + IPureServer* server; + +private: + + virtual void _SendTo_LL( const void* data, u32 size, u32 flags, u32 timeout ); +}; + + +IC bool operator== (IClient const* pClient, ClientID const& ID) { return pClient->ID == ID; } + +class XRNETSERVER_API IServerStatistic +{ +public: + void clear() + { + bytes_out = bytes_out_real = 0; + bytes_in = bytes_in_real = 0; + + dwBytesSended = 0; + dwSendTime = 0; + dwBytesPerSec = 0; + } + + u32 bytes_out,bytes_out_real; + u32 bytes_in, bytes_in_real; + + u32 dwBytesSended; + u32 dwSendTime; + u32 dwBytesPerSec; +}; + + +class XRNETSERVER_API IBannedClient +{ +public: + ip_address HAddr; + time_t BanTime; + + IBannedClient () + { + HAddr.m_data.data = 0; + BanTime = 0; + }; + void Load(CInifile& ini, const shared_str& sect); + void Save(CInifile& ini); + + xr_string BannedTimeTo() const; +}; + + +//============================================================================== + +struct ClientIdSearchPredicate +{ + ClientID clientId; + ClientIdSearchPredicate(ClientID clientIdToSearch) : + clientId(clientIdToSearch) + { + } + inline bool operator()(IClient* client) const + { + return client->ID == clientId; + } +}; + + +class CServerInfo; + +class XRNETSERVER_API +IPureServer + : private MultipacketReciever +{ +public: + enum EConnect + { + ErrConnect, + ErrMax, + ErrNoError = ErrMax, + }; +protected: + shared_str connect_options; + IDirectPlay8Server* NET; + IDirectPlay8Address* net_Address_device; + + NET_Compressor net_Compressor; + + PlayersMonitor net_players; + //xrCriticalSection csPlayers; + //xr_vector net_Players; + //xr_vector net_Players_disconnected; + IClient* SV_Client; + + int psNET_Port; + + + xr_vector BannedAddresses; + ip_filter m_ip_filter; + + // + xrCriticalSection csMessage; + + void client_link_aborted (ClientID ID); + void client_link_aborted (IClient* C); + + // Statistic + IServerStatistic stats; + CTimer* device_timer; + BOOL m_bDedicated; + + IClient* ID_to_client (ClientID ID, bool ScanAll = false); + + virtual IClient* new_client ( SClientConnectData* cl_data ) =0; + bool GetClientAddress (IDirectPlay8Address* pClientAddress, ip_address& Address, DWORD* pPort = NULL); + + IBannedClient* GetBannedClient (const ip_address& Address); + void BannedList_Save (); + void BannedList_Load (); + void IpList_Load (); + void IpList_Unload (); + LPCSTR GetBannedListName (); + + void UpdateBannedList (); +public: + IPureServer (CTimer* timer, BOOL Dedicated = FALSE); + virtual ~IPureServer (); + HRESULT net_Handler (u32 dwMessageType, PVOID pMessage); + + virtual EConnect Connect (LPCSTR session_name, GameDescriptionData & game_descr); + virtual void Disconnect (); + + // send + virtual void SendTo_LL (ClientID ID, void* data, u32 size, u32 dwFlags=DPNSEND_GUARANTEED, u32 dwTimeout=0); + virtual void SendTo_Buf (ClientID ID, void* data, u32 size, u32 dwFlags=DPNSEND_GUARANTEED, u32 dwTimeout=0); + virtual void Flush_Clients_Buffers (); + + void SendTo (ClientID ID, NET_Packet& P, u32 dwFlags=DPNSEND_GUARANTEED, u32 dwTimeout=0); + void SendBroadcast_LL (ClientID exclude, void* data, u32 size, u32 dwFlags=DPNSEND_GUARANTEED); + virtual void SendBroadcast (ClientID exclude, NET_Packet& P, u32 dwFlags=DPNSEND_GUARANTEED); + + // statistic + const IServerStatistic* GetStatistic () { return &stats; } + void ClearStatistic (); + void UpdateClientStatistic (IClient* C); + + // extended functionality + virtual u32 OnMessage (NET_Packet& P, ClientID sender); // Non-Zero means broadcasting with "flags" as returned + virtual void OnCL_Connected (IClient* C); + virtual void OnCL_Disconnected (IClient* C); + virtual bool OnCL_QueryHost () { return true; }; + + virtual IClient* client_Create () = 0; // create client info + virtual void client_Replicate () = 0; // replicate current state to client + virtual void client_Destroy (IClient* C) = 0; // destroy client info + + //IC u32 client_Count () { return net_Players.size(); } + //IC IClient* client_Get (u32 num) { return net_Players[num]; } + + //IC u32 disconnected_client_Count () { return net_Players_disconnected.size(); } + //IC IClient* disconnected_client_Get (u32 num) { return net_Players_disconnected[num]; } + + BOOL HasBandwidth (IClient* C); + + IC int GetPort () { return psNET_Port; }; + bool GetClientAddress (ClientID ID, ip_address& Address, DWORD* pPort = NULL); +// bool DisconnectClient (IClient* C); + virtual bool DisconnectClient (IClient* C, LPCSTR Reason); + virtual bool DisconnectAddress (const ip_address& Address, LPCSTR reason); + virtual void BanClient (IClient* C, u32 BanTime); + virtual void BanAddress (const ip_address& Address, u32 BanTime); + virtual void UnBanAddress (const ip_address& Address); + void Print_Banned_Addreses (); + + virtual bool Check_ServerAccess( IClient* CL, string512& reason ) { return true; } + virtual void Assign_ServerType( string512& res ) {}; + virtual void GetServerInfo( CServerInfo* si ) {}; + + u32 GetClientsCount () { return net_players.ClientsCount(); }; + IClient* GetServerClient () { return SV_Client; }; + template + IClient* FindClient (SearchPredicate const & predicate) { return net_players.GetFoundClient(predicate); } + template + void ForEachClientDo (ActionFunctor & action) { net_players.ForEachClientDo(action); } + template + void ForEachClientDoSender(SenderFunctor & action) { + csMessage.Enter(); +#ifdef DEBUG + sender_functor_invoked = true; +#endif //#ifdef DEBUG + net_players.ForEachClientDo(action); +#ifdef DEBUG + sender_functor_invoked = false; +#endif //#ifdef DEBUG + csMessage.Leave(); + } + //template + //void ForEachDisconnectedClientDo(ActionFunctor & action) { net_players.ForEachDisconnectedClientDo(action); }; +#ifdef DEBUG + bool IsPlayersMonitorLockedByMe() const { return net_players.IsCurrentThreadIteratingOnClients() && !sender_functor_invoked; }; +#endif + bool IsPlayerIPDenied(u32 ip_address); + //WARNING! very bad method :( + //IClient* client_Get (u32 index) {return net_players.GetClientByIndex(index);}; + IClient* GetClientByID (ClientID clientId) {return net_players.GetFoundClient(ClientIdSearchPredicate(clientId));}; + //IClient* GetDisconnectedClientByID(ClientID clientId) {return net_players.GetFoundDisconnectedClient(ClientIdSearchPredicate(clientId));} + + + const shared_str& GetConnectOptions () const {return connect_options;} + + +private: +#ifdef DEBUG + bool sender_functor_invoked; +#endif + + virtual void _Recieve( const void* data, u32 data_size, u32 param ); +}; + diff --git a/xrNetServer/NET_Shared.h b/xrNetServer/NET_Shared.h new file mode 100644 index 00000000000..43f4e5071bf --- /dev/null +++ b/xrNetServer/NET_Shared.h @@ -0,0 +1,78 @@ +#pragma once +#ifdef XR_NETSERVER_EXPORTS + #define XRNETSERVER_API __declspec(dllexport) +#else + #define XRNETSERVER_API __declspec(dllimport) + + #ifndef _EDITOR + #pragma comment(lib, "xrNetServer" ) + #endif +#endif + +#include "../xrCore/net_utils.h" +#include +#include "net_messages.h" + + + +#include "net_compressor.h" + +XRNETSERVER_API extern ClientID BroadcastCID; + +XRNETSERVER_API extern Flags32 psNET_Flags; +XRNETSERVER_API extern int psNET_ClientUpdate; +XRNETSERVER_API extern int get_psNET_ClientUpdate(); +XRNETSERVER_API extern int psNET_ClientPending; +XRNETSERVER_API extern char psNET_Name[]; +XRNETSERVER_API extern int psNET_ServerUpdate; +XRNETSERVER_API extern int get_psNET_ServerUpdate(); +XRNETSERVER_API extern int psNET_ServerPending; + +XRNETSERVER_API extern BOOL psNET_direct_connect; + +enum { + NETFLAG_MINIMIZEUPDATES = (1<<0), + NETFLAG_DBG_DUMPSIZE = (1<<1), + NETFLAG_LOG_SV_PACKETS = (1<<2), + NETFLAG_LOG_CL_PACKETS = (1<<3), +}; + +IC u32 TimeGlobal (CTimer* timer) { return timer->GetElapsed_ms(); } +IC u32 TimerAsync (CTimer* timer) { return TimeGlobal (timer); } + +class XRNETSERVER_API IClientStatistic +{ + DPN_CONNECTION_INFO ci_last; + u32 mps_recive, mps_receive_base; + u32 mps_send, mps_send_base; + u32 dwBaseTime; + CTimer* device_timer; +public: + IClientStatistic (CTimer* timer){ ZeroMemory(this,sizeof(*this)); device_timer=timer; dwBaseTime=TimeGlobal(device_timer); } + + void Update (DPN_CONNECTION_INFO& CI); + + IC u32 getPing () { return ci_last.dwRoundTripLatencyMS; } + IC u32 getBPS () { return ci_last.dwThroughputBPS; } + IC u32 getPeakBPS () { return ci_last.dwPeakThroughputBPS; } + IC u32 getDroppedCount () { return ci_last.dwPacketsDropped; } + IC u32 getRetriedCount () { return ci_last.dwPacketsRetried; } + IC u32 getMPS_Receive () { return mps_recive; } + IC u32 getMPS_Send () { return mps_send; } + IC u32 getReceivedPerSec () { return dwBytesReceivedPerSec; } + IC u32 getSendedPerSec () { return dwBytesSendedPerSec; } + + + IC void Clear () { CTimer* timer = device_timer; ZeroMemory(this,sizeof(*this)); device_timer=timer; dwBaseTime=TimeGlobal(device_timer); } + + //----------------------------------------------------------------------- + u32 dwTimesBlocked; + + u32 dwBytesSended; + u32 dwBytesSendedPerSec; + + u32 dwBytesReceived; + u32 dwBytesReceivedPerSec; + +}; + diff --git a/xrNetServer/ip_filter.cpp b/xrNetServer/ip_filter.cpp new file mode 100644 index 00000000000..6fb70ad4314 --- /dev/null +++ b/xrNetServer/ip_filter.cpp @@ -0,0 +1,116 @@ +#include "stdafx.h" +#include "ip_filter.h" +#include "..\xrCore\xr_ini.h" + +ip_filter::ip_filter() +{ +} +ip_filter::~ip_filter() +{ + for (subnets_coll_t::iterator i = m_all_subnets.begin(), + ie = m_all_subnets.end(); i != ie; ++i) + { + xr_delete(*i); + } +} + +struct subnet_comparator : public std::binary_function +{ + bool operator()(subnet_item const * left, subnet_item const * right) const + { + return ((left->subnet_ip.data & left->subnet_mask) < (right->subnet_ip.data & right->subnet_mask)); + } +}; + +struct ip_searcher : public std::binary_function +{ + bool operator()(subnet_item const * left, subnet_item const * right) const + { + if (left->subnet_mask) + { + return ((left->subnet_ip.data & left->subnet_mask) < (right->subnet_ip.data & left->subnet_mask)); + } + return ((left->subnet_ip.data & right->subnet_mask) < (right->subnet_ip.data & right->subnet_mask)); + } +}; + +static void hton_bo(u32 const source_ip, subnet_item & dest) +{ + subnet_item source; + source.subnet_ip.data = source_ip; + dest.subnet_ip.a1 = source.subnet_ip.a4; + dest.subnet_ip.a2 = source.subnet_ip.a3; + dest.subnet_ip.a3 = source.subnet_ip.a2; + dest.subnet_ip.a4 = source.subnet_ip.a1; +} + +#define SUBNET_LIST_SECT_NAME "subnet_list" +u32 ip_filter::load() +{ + string_path temp; + FS.update_path (temp,"$app_data_root$", "ip_filter.ltx"); + CInifile ini(temp); + + if (!ini.section_exist(SUBNET_LIST_SECT_NAME)) + return 0; + + for (u32 i = 0, line_count = ini.line_count(SUBNET_LIST_SECT_NAME); + i != line_count; ++i) + { + LPCSTR address; + LPCSTR line; + ini.r_line(SUBNET_LIST_SECT_NAME, i, &address, &line); + if (!xr_strlen(address)) + continue; + + subnet_item* tmp_item = xr_new(); + unsigned int parse_data[5]; + unsigned int parsed_params = sscanf_s( + address, "%u.%u.%u.%u/%u", + &parse_data[0], + &parse_data[1], + &parse_data[2], + &parse_data[3], + &parse_data[4] + ); + if ((parsed_params != 5) || + (parse_data[0] > 255) || + (parse_data[1] > 255) || + (parse_data[2] > 255) || + (parse_data[3] > 255) || + (parse_data[4] == 0)) + { + VERIFY2(0, make_string("! ERROR: bad subnet: %s", address).c_str()); + xr_delete(tmp_item); + continue; + } + + tmp_item->subnet_ip.data = parse_data[3] | (parse_data[2] << 8) | (parse_data[1] << 16) | (parse_data[0] << 24); + unsigned int zero_count = 32 - parse_data[4]; + tmp_item->subnet_mask = (u32(-1) >> zero_count) << zero_count; + m_all_subnets.push_back(tmp_item); + }; + std::sort(m_all_subnets.begin(), m_all_subnets.end(), subnet_comparator()); + return m_all_subnets.size(); +} + +bool ip_filter::is_ip_present(u32 ip_address) +{ + if (m_all_subnets.size() == 0) + return true; + subnet_item tmp_fake_item; + hton_bo(ip_address, tmp_fake_item); + tmp_fake_item.subnet_mask = 0; + return std::binary_search(m_all_subnets.begin(), m_all_subnets.end(), &tmp_fake_item, ip_searcher()); +} + +void ip_filter::unload() +{ + for (subnets_coll_t::iterator i = m_all_subnets.begin(), //delete_data(m_all_subnets); + ie = m_all_subnets.end(); i != ie; ++i) + { + xr_delete(*i); + } + m_all_subnets.clear(); +} + diff --git a/xrNetServer/ip_filter.h b/xrNetServer/ip_filter.h new file mode 100644 index 00000000000..7e77449f8e6 --- /dev/null +++ b/xrNetServer/ip_filter.h @@ -0,0 +1,39 @@ +#ifndef NET_SERVER_IP_FILTER +#define NET_SERVER_IP_FILTER + +struct subnet_item +{ + union + { + struct + { + u8 a1; + u8 a2; + u8 a3; + u8 a4; + }; + u32 data; + } subnet_ip; //IN NBO !!! + u32 subnet_mask; + subnet_item() + { + subnet_ip.data = 0; + subnet_mask = 0; + } +}; + + +class ip_filter +{ + typedef xr_vector subnets_coll_t; + subnets_coll_t m_all_subnets; +public: + ip_filter (); + ~ip_filter (); + + u32 load (); + void unload (); + bool is_ip_present (u32 ip_address); +}; + +#endif //#ifndef NET_SERVER_IP_FILTER \ No newline at end of file diff --git a/xrNetServer/stdafx.cpp b/xrNetServer/stdafx.cpp new file mode 100644 index 00000000000..e7307662a9a --- /dev/null +++ b/xrNetServer/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +#pragma comment(lib, "xrCore" ) +#pragma comment(lib, "dxguid.lib" ) diff --git a/xrNetServer/stdafx.h b/xrNetServer/stdafx.h new file mode 100644 index 00000000000..3538a250393 --- /dev/null +++ b/xrNetServer/stdafx.h @@ -0,0 +1,24 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// +// Third generation by Oles. + +#ifndef stdafxH +#define stdafxH + +#pragma once + +#include "../xrCore/xrCore.h" + +#pragma warning(push) +#pragma warning(disable:4995) +#include +#pragma warning(pop) + +#include "NET_Shared.h" + +#define _RELEASE(x) { if(x) { (x)->Release(); (x)=NULL; } } +#define _SHOW_REF(msg, x) { if(x) { x->AddRef(); Log(msg,u32(x->Release()));}} + +#endif //stdafxH diff --git a/xrNetServer/xrNetServer.vcproj b/xrNetServer/xrNetServer.vcproj new file mode 100644 index 00000000000..e965239b4e8 --- /dev/null +++ b/xrNetServer/xrNetServer.vcproj @@ -0,0 +1,796 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrParticles/noise.cpp b/xrParticles/noise.cpp new file mode 100644 index 00000000000..c3e0b045e1a --- /dev/null +++ b/xrParticles/noise.cpp @@ -0,0 +1,202 @@ +#include "stdafx.h" +#pragma hdrstop + +#include "noise.h" + +#ifndef _EDITOR +#include + +__forceinline int iFloor_SSE( float const x ) +{ + return _mm_cvtt_ss2si( _mm_set_ss( x ) ); +} +#endif + +//============================================================================== +// Perlin's noise from Texturing and Modeling... +#define B 256 + +#define DOT(a,b) ( a[0]*b[0] + a[1]*b[1] + a[2]*b[2]) +#define AT(rx,ry,rz) (rx*q[0] + ry*q[1] + rz*q[2] ); +#define S_CURVE(t) ( t*t*(3.f-2.f*t) ) +#define LERP(t, a, b) ( a + t*(b-a) ) + +#ifndef _EDITOR + #define PN_SETUP(i,b0,b1,r0,r1) \ + t = vec[i] + 10000.f;\ + tt = iFloor_SSE(t); \ + b0 = tt & (B-1);\ + b1 = (b0+1) & (B-1);\ + r0 = t - float(tt);\ + r1 = r0 - 1.f; +#else + + #define PN_SETUP(i,b0,b1,r0,r1) \ + t = vec[i] + 10000.f;\ + b0 = iFloor(t) & (B-1);\ + b1 = (b0+1) & (B-1);\ + r0 = t - iFloor(t);\ + r1 = r0 - 1.f; + +#endif + +static int p[B+B+2]; +static float g[B+B+2][3]; + +//-------------------------------------------------------------------- +void noise3Init() +{ + int i, j, k; + float v[3], s; + int rnd; + + srand(1); + + for(i = 0; i < B; i++ ) + { + do + { + for(j = 0; j < 3; j++) + { + rnd = rand(); + v[j] = float((rnd % (B+B)) - B) / B; + } + s = DOT(v,v); + } while ( s > 1.0 ); + s = _sqrt(s); + for (j = 0; j < 3; j++) + g[i][j] = v[j] / s; + } + + for (i = 0; i < B; i++) + p[i] = i; + + for (i = B; i > 0; i -= 2) + { + rnd = rand(); + k = p[i]; + p[i] = p[ (j = rnd%B) ]; + p[j] = k; + } + + for (i = 0; i < B+2; i++) + { + p[B+i] = p[i]; + for (j = 0; j < 3; j++) + g[B+i][j] = g[i][j]; + } +} + +//-------------------------------------------------------------------- + +float noise3(const Fvector& vec) +{ + int bx0, bx1; + int by0, by1; + int bz0, bz1; + int b00, b10, b01, b11; + float rx0, rx1; + float ry0, ry1; + float rz0, rz1; + float *q; + float sx, sy, sz; + float a, b, c, d, t, u, v; + int i, j, tt; + + PN_SETUP(0, bx0, bx1, rx0, rx1); + PN_SETUP(1, by0, by1, ry0, ry1); + PN_SETUP(2, bz0, bz1, rz0, rz1); + + i = p[bx0]; + j = p[bx1]; + + b00 = p[ i+by0 ]; + b10 = p[ j+by0 ]; + b01 = p[ i+by1 ]; + b11 = p[ j+by1 ]; + + sx = S_CURVE(rx0); + sy = S_CURVE(ry0); + sz = S_CURVE(rz0); + + q = g[ b00+bz0 ]; u = AT(rx0, ry0, rz0); + q = g[ b10+bz0 ]; v = AT(rx1, ry0, rz0); + a = LERP( sx, u, v ); + + q = g[ b01+bz0 ]; u = AT(rx0, ry1, rz0); + q = g[ b11+bz0 ]; v = AT(rx1, ry1, rz0); + b = LERP( sx, u, v ); + + c = LERP(sy, a, b); + + q = g[ b00+bz1 ]; u = AT(rx0, ry0, rz1); + q = g[ b10+bz1 ]; v = AT(rx1, ry0, rz1); + a = LERP( sx, u, v ); + + q = g[ b01+bz1 ]; u = AT(rx0, ry1, rz1); + q = g[ b11+bz1 ]; v = AT(rx1, ry1, rz1); + b = LERP( sx, u, v ); + + d = LERP(sy, a, b); + + return 1.5f * LERP(sz, c, d); +} + +//-------------------------------------------------------------------- +float fractalsum3(const Fvector& v, float freq, int octaves) +{ + /* already initialized somewhere + if (start) { + start = 0; + noise3Init(); + } + */ + + int i; + float sum = 0.0; + Fvector v_; + float boost = freq; + v_[0] = v[0]*freq; + v_[1] = v[1]*freq; + v_[2] = v[2]*freq; + + for (i = 0; i < octaves; i++ ) + { + sum += noise3(v_)/freq; + freq *= 2.059f; + v_[0] = v[0]*freq; + v_[1] = v[1]*freq; + v_[2] = v[2]*freq; + } + return sum*boost; +} + +//-------------------------------------------------------------------- +float turbulence3(const Fvector& v, float freq, int octaves) +{ + /* Not used now + if (start) { + start = 0; + noise3Init(); + } + */ + + int i; + float sum = 0.0; + Fvector v_; + float boost = freq; + v_[0] = v[0]*freq; + v_[1] = v[1]*freq; + v_[2] = v[2]*freq; + + for (i = 0; i < octaves; i++ ) + { + sum += _abs(noise3(v_))/freq; + freq *= 2.059f; + v_[0] = v[0]*freq; + v_[1] = v[1]*freq; + v_[2] = v[2]*freq; + } + return sum*boost; +} + diff --git a/xrParticles/noise.h b/xrParticles/noise.h new file mode 100644 index 00000000000..3084df7e76a --- /dev/null +++ b/xrParticles/noise.h @@ -0,0 +1,8 @@ +#ifndef noiseH +#define noiseH + +float noise3(const Fvector& vec); +float fractalsum3(const Fvector& v, float freq, int octaves); +float turbulence3(const Fvector& v, float freq, int octaves); + +#endif diff --git a/xrParticles/particle_actions.cpp b/xrParticles/particle_actions.cpp new file mode 100644 index 00000000000..c0b114534dc --- /dev/null +++ b/xrParticles/particle_actions.cpp @@ -0,0 +1,6 @@ +//--------------------------------------------------------------------------- +#include "stdafx.h" +#pragma hdrstop + +#include "particle_actions.h" + diff --git a/xrParticles/particle_actions.h b/xrParticles/particle_actions.h new file mode 100644 index 00000000000..c5ca38f1014 --- /dev/null +++ b/xrParticles/particle_actions.h @@ -0,0 +1,50 @@ +//--------------------------------------------------------------------------- +#ifndef particle_actionsH +#define particle_actionsH + + +namespace PAPI{ +// refs + struct ParticleEffect; + struct PARTICLES_API ParticleAction + { + enum{ + ALLOW_ROTATE = (1<<1) + }; + Flags32 m_Flags; + PActionEnum type; // Type field + ParticleAction (){m_Flags.zero();} + + virtual void Execute (ParticleEffect *pe, const float dt, float& m_max) = 0; + virtual void Transform (const Fmatrix& m) = 0; + + virtual void Load (IReader& F)=0; + virtual void Save (IWriter& F)=0; + }; + DEFINE_VECTOR(ParticleAction*,PAVec,PAVecIt); + class ParticleActions{ + PAVec actions; + bool m_bLocked; + public: + ParticleActions() {actions.reserve(4);m_bLocked=false; } + ~ParticleActions() {clear(); } + IC void clear () + { + R_ASSERT(!m_bLocked); + for (PAVecIt it=actions.begin(); it!=actions.end(); it++) + xr_delete(*it); + actions.clear(); + } + IC void append (ParticleAction* pa) {R_ASSERT(!m_bLocked);actions.push_back(pa); } + IC bool empty () {return actions.empty();} + IC PAVecIt begin () {return actions.begin();} + IC PAVecIt end () {return actions.end(); } + IC int size () {return actions.size(); } + IC void resize (int cnt) {R_ASSERT(!m_bLocked);actions.resize(cnt); } + void copy (ParticleActions* src); + void lock () {R_ASSERT(!m_bLocked);m_bLocked=true;} + void unlock () {R_ASSERT(m_bLocked);m_bLocked=false;} + }; +}; +//--------------------------------------------------------------------------- +#endif diff --git a/xrParticles/particle_actions_collection.cpp b/xrParticles/particle_actions_collection.cpp new file mode 100644 index 00000000000..c3e023e118a --- /dev/null +++ b/xrParticles/particle_actions_collection.cpp @@ -0,0 +1,1835 @@ +#include "stdafx.h" +#pragma hdrstop + +#include "particle_actions_collection.h" +#include "particle_effect.h" + +using namespace PAPI; + +void PAPI::PAAvoid::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + + switch(position.type) + { + case PDPlane: + { + if(look_ahead < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float dist = m.pos * position.p2 + position.radius1; + + if(dist < look_ahead) + { + float vm = m.vel.length(); + pVector Vn = m.vel / vm; + // float dot = Vn * position.p2; + + pVector tmp = (position.p2 * (magdt / (dist*dist+epsilon))) + Vn; + m.vel = tmp * (vm / tmp.length()); + } + } + } + else + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float dist = m.pos * position.p2 + position.radius1; + + float vm = m.vel.length(); + pVector Vn = m.vel / vm; + // float dot = Vn * position.p2; + + pVector tmp = (position.p2 * (magdt / (dist*dist+epsilon))) + Vn; + m.vel = tmp * (vm / tmp.length()); + } + } + } + break; + case PDRectangle: + { + // Compute the inverse matrix of the plane basis. + pVector &u = position.u; + pVector &v = position.v; + + // The normalized bases are needed inside the loop. + pVector un = u / position.radius1Sqr; + pVector vn = v / position.radius2Sqr; + + // w = u cross v + float wx = u.y*v.z-u.z*v.y; + float wy = u.z*v.x-u.x*v.z; + float wz = u.x*v.y-u.y*v.x; + + float det = 1/(wz*u.x*v.y-wz*u.y*v.x-u.z*wx*v.y-u.x*v.z*wy+v.z*wx*u.y+u.z*v.x*wy); + + pVector s1((v.y*wz-v.z*wy), (v.z*wx-v.x*wz), (v.x*wy-v.y*wx)); + s1 *= det; + pVector s2((u.y*wz-u.z*wy), (u.z*wx-u.x*wz), (u.x*wy-u.y*wx)); + s2 *= -det; + + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt * look_ahead); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float distold = m.pos * position.p2 + position.radius1; + float distnew = pnext * position.p2 + position.radius1; + + // Opposite signs if product < 0 + // There is no faster way to do this. + if(distold * distnew >= 0) + continue; + + float nv = position.p2 * m.vel; + float t = -distold / nv; + + // Actual intersection point p(t) = pos + vel t + pVector phit(m.pos + m.vel * t); + + // Offset from origin in plane, p - origin + pVector offset(phit - position.p1); + + // Dot product with basis vectors of old frame + // in terms of new frame gives position in uv frame. + float upos = offset * s1; + float vpos = offset * s2; + + // Did it cross plane outside triangle? + if(upos < 0 || vpos < 0 || upos > 1 || vpos > 1) + continue; + + // A hit! A most palpable hit! + // Compute distance to the three edges. + pVector uofs = (un * (un * offset)) - offset; + float udistSqr = uofs.length2(); + pVector vofs = (vn * (vn * offset)) - offset; + float vdistSqr = vofs.length2(); + + pVector foffset((u + v) - offset); + pVector fofs = (un * (un * foffset)) - foffset; + float fdistSqr = fofs.length2(); + pVector gofs = (un * (un * foffset)) - foffset; + float gdistSqr = gofs.length2(); + + pVector S; + if(udistSqr <= vdistSqr && udistSqr <= fdistSqr + && udistSqr <= gdistSqr) S = uofs; + else if(vdistSqr <= fdistSqr && vdistSqr <= gdistSqr) S = vofs; + else if(fdistSqr <= gdistSqr) S = fofs; + else S = gofs; + + S.normalize_safe(); + + // We now have a vector3 to safety. + float vm = m.vel.length(); + pVector Vn = m.vel / vm; + + // Blend S into V. + pVector tmp = (S * (magdt / (t*t+epsilon))) + Vn; + m.vel = tmp * (vm / tmp.length()); + } + } + break; + case PDTriangle: + { + // Compute the inverse matrix of the plane basis. + pVector &u = position.u; + pVector &v = position.v; + + // The normalized bases are needed inside the loop. + pVector un = u / position.radius1Sqr; + pVector vn = v / position.radius2Sqr; + + // f is the third (non-basis) triangle edge. + pVector f = v - u; + pVector fn(f); + fn.normalize_safe(); + + // w = u cross v + float wx = u.y*v.z-u.z*v.y; + float wy = u.z*v.x-u.x*v.z; + float wz = u.x*v.y-u.y*v.x; + + float det = 1/(wz*u.x*v.y-wz*u.y*v.x-u.z*wx*v.y-u.x*v.z*wy+v.z*wx*u.y+u.z*v.x*wy); + + pVector s1((v.y*wz-v.z*wy), (v.z*wx-v.x*wz), (v.x*wy-v.y*wx)); + s1 *= det; + pVector s2((u.y*wz-u.z*wy), (u.z*wx-u.x*wz), (u.x*wy-u.y*wx)); + s2 *= -det; + + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt * look_ahead); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float distold = m.pos * position.p2 + position.radius1; + float distnew = pnext * position.p2 + position.radius1; + + // Opposite signs if product < 0 + // Is there a faster way to do this? + if(distold * distnew >= 0) + continue; + + float nv = position.p2 * m.vel; + float t = -distold / nv; + + // Actual intersection point p(t) = pos + vel t + pVector phit(m.pos + m.vel * t); + + // Offset from origin in plane, p - origin + pVector offset(phit - position.p1); + + // Dot product with basis vectors of old frame + // in terms of new frame gives position in uv frame. + float upos = offset * s1; + float vpos = offset * s2; + + // Did it cross plane outside triangle? + if(upos < 0 || vpos < 0 || (upos + vpos) > 1) + continue; + + // A hit! A most palpable hit! + // Compute distance to the three edges. + pVector uofs = (un * (un * offset)) - offset; + float udistSqr = uofs.length2(); + pVector vofs = (vn * (vn * offset)) - offset; + float vdistSqr = vofs.length2(); + pVector foffset(offset - u); + pVector fofs = (fn * (fn * foffset)) - foffset; + float fdistSqr = fofs.length2(); + pVector S; + if(udistSqr <= vdistSqr && udistSqr <= fdistSqr) S = uofs; + else if(vdistSqr <= fdistSqr) S = vofs; + else S = fofs; + + S.normalize_safe(); + + // We now have a vector3 to safety. + float vm = m.vel.length(); + pVector Vn = m.vel / vm; + + // Blend S into V. + pVector tmp = (S * (magdt / (t*t+epsilon))) + Vn; + m.vel = tmp * (vm / tmp.length()); + } + } + break; + case PDDisc: + { + float r1Sqr = _sqr(position.radius1); + float r2Sqr = _sqr(position.radius2); + + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt * look_ahead); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. radius1Sqr stores d. + float distold = m.pos * position.p2 + position.radius1Sqr; + float distnew = pnext * position.p2 + position.radius1Sqr; + + // Opposite signs if product < 0 + // Is there a faster way to do this? + if(distold * distnew >= 0) + continue; + + // Find position at the crossing point by parameterizing + // p(t) = pos + vel * t + // Solve dist(p(t),plane) = 0 e.g. + // n * p(t) + D = 0 -> + // n * p + t (n * v) + D = 0 -> + // t = -(n * p + D) / (n * v) + // Could factor n*v into distnew = distold + n*v and save a bit. + // Safe since n*v != 0 assured by quick rejection test. + // This calc is indep. of dt because we have established that it + // will hit before dt. We just want to know when. + float nv = position.p2 * m.vel; + float t = -distold / nv; + + // Actual intersection point p(t) = pos + vel t + pVector phit(m.pos + m.vel * t); + + // Offset from origin in plane, phit - origin + pVector offset(phit - position.p1); + + float rad = offset.length2(); + + if(rad > r1Sqr || rad < r2Sqr) + continue; + + // A hit! A most palpable hit! + pVector S = offset; + S.normalize_safe(); + + // We now have a vector3 to safety. + float vm = m.vel.length(); + pVector Vn = m.vel / vm; + + // Blend S into V. + pVector tmp = (S * (magdt / (t*t+epsilon))) + Vn; + m.vel = tmp * (vm / tmp.length()); + } + } + break; + case PDSphere: + { + float rSqr = position.radius1 * position.radius1; + + // See which particles are aimed toward the sphere. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // First do a ray-sphere intersection test and + // see if it's soon enough. + // Can I do this faster without t? + float vm = m.vel.length(); + pVector Vn = m.vel / vm; + + pVector L = position.p1 - m.pos; + float v = L * Vn; + + float disc = rSqr - (L * L) + v * v; + if(disc < 0) + continue; // I'm not heading toward it. + + // Compute length for second rejection test. + float t = v - _sqrt(disc); + if(t < 0 || t > (vm * look_ahead)) + continue; + + // Get a vector3 to safety. + pVector C = Vn ^ L; + C.normalize_safe(); + pVector S = Vn ^ C; + + // Blend S into V. + pVector tmp = (S * (magdt / (t*t+epsilon))) + Vn; + m.vel = tmp * (vm / tmp.length()); + } + } + break; + } +} +void PAPI::PAAvoid::Transform(const Fmatrix& m) +{ + position.transform(positionL,m); +} +//------------------------------------------------------------------------------------------------- + +void PABounce::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + switch(position.type) + { + case PDTriangle: + { + // Compute the inverse matrix of the plane basis. + pVector &u = position.u; + pVector &v = position.v; + + // w = u cross v + float wx = u.y*v.z-u.z*v.y; + float wy = u.z*v.x-u.x*v.z; + float wz = u.x*v.y-u.y*v.x; + + float det = 1/(wz*u.x*v.y-wz*u.y*v.x-u.z*wx*v.y-u.x*v.z*wy+v.z*wx*u.y+u.z*v.x*wy); + + pVector s1((v.y*wz-v.z*wy), (v.z*wx-v.x*wz), (v.x*wy-v.y*wx)); + s1 *= det; + pVector s2((u.y*wz-u.z*wy), (u.z*wx-u.x*wz), (u.x*wy-u.y*wx)); + s2 *= -det; + + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float distold = m.pos * position.p2 + position.radius1; + float distnew = pnext * position.p2 + position.radius1; + + // Opposite signs if product < 0 + // Is there a faster way to do this? + if(distold * distnew >= 0) + continue; + + // Find position at the crossing point by parameterizing + // p(t) = pos + vel * t + // Solve dist(p(t),plane) = 0 e.g. + // n * p(t) + D = 0 -> + // n * p + t (n * v) + D = 0 -> + // t = -(n * p + D) / (n * v) + // Could factor n*v into distnew = distold + n*v and save a bit. + // Safe since n*v != 0 assured by quick rejection test. + // This calc is indep. of dt because we have established that it + // will hit before dt. We just want to know when. + float nv = position.p2 * m.vel; + float t = -distold / nv; + + // Actual intersection point p(t) = pos + vel t + pVector phit(m.pos + m.vel * t); + + // Offset from origin in plane, p - origin + pVector offset(phit - position.p1); + + // Dot product with basis vectors of old frame + // in terms of new frame gives position in uv frame. + float upos = offset * s1; + float vpos = offset * s2; + + // Did it cross plane outside triangle? + if(upos < 0 || vpos < 0 || (upos + vpos) > 1) + continue; + + // A hit! A most palpable hit! + + // Compute tangential and normal components of velocity + pVector vn(position.p2 * nv); // Normal Vn = (V.N)N + pVector vt(m.vel - vn); // Tangent Vt = V - Vn + + // Compute new velocity heading out: + // Don't apply friction if tangential velocity < cutoff + if(vt.length2() <= cutoffSqr) + m.vel = vt - vn * resilience; + else + m.vel = vt * oneMinusFriction - vn * resilience; + } + } + break; + case PDDisc: + { + float r1Sqr = _sqr(position.radius1); + float r2Sqr = _sqr(position.radius2); + + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. radius1Sqr stores d. + float distold = m.pos * position.p2 + position.radius1Sqr; + float distnew = pnext * position.p2 + position.radius1Sqr; + + // Opposite signs if product < 0 + // Is there a faster way to do this? + if(distold * distnew >= 0) + continue; + + // Find position at the crossing point by parameterizing + // p(t) = pos + vel * t + // Solve dist(p(t),plane) = 0 e.g. + // n * p(t) + D = 0 -> + // n * p + t (n * v) + D = 0 -> + // t = -(n * p + D) / (n * v) + // Could factor n*v into distnew = distold + n*v and save a bit. + // Safe since n*v != 0 assured by quick rejection test. + // This calc is indep. of dt because we have established that it + // will hit before dt. We just want to know when. + float nv = position.p2 * m.vel; + float t = -distold / nv; + + // Actual intersection point p(t) = pos + vel t + pVector phit(m.pos + m.vel * t); + + // Offset from origin in plane, phit - origin + pVector offset(phit - position.p1); + + float rad = offset.length2(); + + if(rad > r1Sqr || rad < r2Sqr) + continue; + + // A hit! A most palpable hit! + + // Compute tangential and normal components of velocity + pVector vn(position.p2 * nv); // Normal Vn = (V.N)N + pVector vt(m.vel - vn); // Tangent Vt = V - Vn + + // Compute new velocity heading out: + // Don't apply friction if tangential velocity < cutoff + if(vt.length2() <= cutoffSqr) + m.vel = vt - vn * resilience; + else + m.vel = vt * oneMinusFriction - vn * resilience; + } + } + break; + case PDPlane: + { + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float distold = m.pos * position.p2 + position.radius1; + float distnew = pnext * position.p2 + position.radius1; + + // Opposite signs if product < 0 + if(distold * distnew >= 0) + continue; + + // Compute tangential and normal components of velocity + float nmag = m.vel * position.p2; + pVector vn(position.p2 * nmag); // Normal Vn = (V.N)N + pVector vt(m.vel - vn); // Tangent Vt = V - Vn + + // Compute new velocity heading out: + // Don't apply friction if tangential velocity < cutoff + if(vt.length2() <= cutoffSqr) + m.vel = vt - vn * resilience; + else + m.vel = vt * oneMinusFriction - vn * resilience; + } + } + break; + case PDRectangle: + { + // Compute the inverse matrix of the plane basis. + pVector &u = position.u; + pVector &v = position.v; + + // w = u cross v + float wx = u.y*v.z-u.z*v.y; + float wy = u.z*v.x-u.x*v.z; + float wz = u.x*v.y-u.y*v.x; + + float det = 1/(wz*u.x*v.y-wz*u.y*v.x-u.z*wx*v.y-u.x*v.z*wy+v.z*wx*u.y+u.z*v.x*wy); + + pVector s1((v.y*wz-v.z*wy), (v.z*wx-v.x*wz), (v.x*wy-v.y*wx)); + s1 *= det; + pVector s2((u.y*wz-u.z*wy), (u.z*wx-u.x*wz), (u.x*wy-u.y*wx)); + s2 *= -det; + + // See which particles bounce. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's current and next positions cross plane. + // If not, couldn't bounce, so keep going. + pVector pnext(m.pos + m.vel * dt); + + // p2 stores the plane normal (the a,b,c of the plane eqn). + // Old and new distances: dist(p,plane) = n * p + d + // radius1 stores -n*p, which is d. + float distold = m.pos * position.p2 + position.radius1; + float distnew = pnext * position.p2 + position.radius1; + + // Opposite signs if product < 0 + if(distold * distnew >= 0) + continue; + + // Find position at the crossing point by parameterizing + // p(t) = pos + vel * t + // Solve dist(p(t),plane) = 0 e.g. + // n * p(t) + D = 0 -> + // n * p + t (n * v) + D = 0 -> + // t = -(n * p + D) / (n * v) + float t = -distold / (position.p2 * m.vel); + + // Actual intersection point p(t) = pos + vel t + pVector phit(m.pos + m.vel * t); + + // Offset from origin in plane, p - origin + pVector offset(phit - position.p1); + + // Dot product with basis vectors of old frame + // in terms of new frame gives position in uv frame. + float upos = offset * s1; + float vpos = offset * s2; + + // Crossed plane outside bounce region if !(0<=[uv]pos<=1) + if(upos < 0 || upos > 1 || vpos < 0 || vpos > 1) + continue; + + // A hit! A most palpable hit! + + // Compute tangential and normal components of velocity + float nmag = m.vel * position.p2; + pVector vn(position.p2 * nmag); // Normal Vn = (V.N)N + pVector vt(m.vel - vn); // Tangent Vt = V - Vn + + // Compute new velocity heading out: + // Don't apply friction if tangential velocity < cutoff + if(vt.length2() <= cutoffSqr) + m.vel = vt - vn * resilience; + else + m.vel = vt * oneMinusFriction - vn * resilience; + } + } + break; + case PDSphere: + { + // Sphere that particles bounce off + // The particles are always forced out of the sphere. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // See if particle's next position is inside domain. + // If so, bounce it. + pVector pnext(m.pos + m.vel * dt); + + if(position.Within(pnext)) + { + // See if we were inside on previous timestep. + BOOL pinside = position.Within(m.pos); + + // Normal to surface. This works for a sphere. Isn't + // computed quite right, should extrapolate particle + // position to surface. + pVector n(m.pos - position.p1); + n.normalize_safe(); + + // Compute tangential and normal components of velocity + float nmag = m.vel * n; + + pVector vn(n * nmag); // Normal Vn = (V.N)N + pVector vt = m.vel - vn; // Tangent Vt = V - Vn + + if(pinside) + { + // Previous position was inside. If normal component of + // velocity points in, reverse it. This effectively + // repels particles which would otherwise be trapped + // in the sphere. + if(nmag < 0) + m.vel = vt - vn; + } + else + { + // Previous position was outside -> particle will cross + // surface boundary. Reverse normal component of velocity, + // and apply friction (if Vt >= cutoff) and resilience. + + // Compute new velocity heading out: + // Don't apply friction if tangential velocity < cutoff + if(vt.length2() <= cutoffSqr) + m.vel = vt - vn * resilience; + else + m.vel = vt * oneMinusFriction - vn * resilience; + } + } + } + } + } +} +void PABounce::Transform(const Fmatrix& m) +{ + position.transform(positionL,m); +} +//------------------------------------------------------------------------------------------------- + +// Set the secondary position of each particle to be its position. +void PACopyVertexB::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + u32 i; + + if(copy_pos) + { + for(i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + m.posB = m.pos; + } + } +/* + if(copy_vel) + { + for(i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + m.velB = m.vel; + } + } +*/ +} +void PACopyVertexB::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Dampen velocities +void PADamping::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + // This is important if dt is != 1. + pVector one(1,1,1); + pVector scale(one - ((one - damping) * dt)); + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + float vSqr = m.vel.length2(); + + if(vSqr >= vlowSqr && vSqr <= vhighSqr) + { + m.vel.x *= scale.x; + m.vel.y *= scale.y; + m.vel.z *= scale.z; + } + } +} +void PADamping::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Exert force on each particle away from explosion center +void PAExplosion::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float radius = velocity * age; + float magdt = magnitude * dt; + float oneOverSigma = 1.0f / stdev; + float inexp = -0.5f*_sqr(oneOverSigma); + float outexp = ONEOVERSQRT2PI * oneOverSigma; + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir (m.pos - center); + float distSqr = dir.length2(); + float dist = _sqrt(distSqr); + float DistFromWaveSqr = _sqr(radius - dist); + + float Gd = expf(DistFromWaveSqr * inexp) * outexp; + + m.vel += dir * (Gd * magdt / ((dist+EPS) * (distSqr + epsilon))); + } + + age += dt; +} +void PAExplosion::Transform(const Fmatrix& m) +{ + m.transform_tiny(center,centerL); +} +//------------------------------------------------------------------------------------------------- + +// Follow the next particle in the list +void PAFollow::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count - 1; i++) + { + Particle &m = effect->particles[i]; + + // Accelerate toward the particle after me in the list. + pVector tohim(effect->particles[i+1].pos - m.pos); // tohim = p1 - p0 + float tohimlenSqr = tohim.length2(); + + if(tohimlenSqr < max_radiusSqr) + { + // Compute force exerted between the two bodies + m.vel += tohim * (magdt / (_sqrt(tohimlenSqr) * (tohimlenSqr + epsilon))); + } + } + } + else + { + for(u32 i = 0; i < effect->p_count - 1; i++) + { + Particle &m = effect->particles[i]; + + // Accelerate toward the particle after me in the list. + pVector tohim(effect->particles[i+1].pos - m.pos); // tohim = p1 - p0 + float tohimlenSqr = tohim.length2(); + + // Compute force exerted between the two bodies + m.vel += tohim * (magdt / (_sqrt(tohimlenSqr) * (tohimlenSqr + epsilon))); + } + } +} +void PAFollow::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Inter-particle gravitation +void PAGravitate::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Add interactions with other particles + for(u32 j = i + 1; j < effect->p_count; j++) + { + Particle &mj = effect->particles[j]; + + pVector tohim(mj.pos - m.pos); // tohim = p1 - p0 + float tohimlenSqr = tohim.length2()+EPS_S; + + if(tohimlenSqr < max_radiusSqr) + { + // Compute force exerted between the two bodies + pVector acc(tohim * (magdt / (_sqrt(tohimlenSqr) * (tohimlenSqr + epsilon)))); + + m.vel += acc; + mj.vel -= acc; + } + } + } + } + else + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Add interactions with other particles + for(u32 j = i + 1; j < effect->p_count; j++) + { + Particle &mj = effect->particles[j]; + + pVector tohim(mj.pos - m.pos); // tohim = p1 - p0 + float tohimlenSqr = tohim.length2()+EPS_S; + + // Compute force exerted between the two bodies + pVector acc(tohim * (magdt / (_sqrt(tohimlenSqr) * (tohimlenSqr + epsilon)))); + + m.vel += acc; + mj.vel -= acc; + } + } + } +} +void PAGravitate::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Acceleration in a constant direction +void PAGravity::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + pVector ddir(direction * dt); + + for(u32 i = 0; i < effect->p_count; i++) + { + // Step velocity with acceleration + effect->particles[i].vel += ddir; + } +} +void PAGravity::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Accelerate particles along a line +void PAJet::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir(m.pos - center); + + // Distance to jet (force drops as 1/r^2) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = dir.length2(); + + if(rSqr < max_radiusSqr) + { + pVector accel; + acc.Generate(accel); + + // Step velocity with acceleration + m.vel += accel * (magdt / (rSqr + epsilon)); + } + } + } + else + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir(m.pos - center); + + // Distance to jet (force drops as 1/r^2) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = dir.length2(); + + pVector accel; + acc.Generate(accel); + + // Step velocity with acceleration + m.vel += accel * (magdt / (rSqr + epsilon)); + } + } +} +void PAJet::Transform(const Fmatrix& m) +{ + m.transform_tiny (center,centerL); + acc.transform_dir (accL,m); +} +//------------------------------------------------------------------------------------------------- + +// Accelerate particles form center +void PAScatter::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir(m.pos - center); + + // Distance to jet (force drops as 1/r^2) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = dir.length2(); + + if(rSqr < max_radiusSqr) + { + pVector accel; + accel = dir/_sqrt(rSqr); + +// acc.Generate(accel); + + // Step velocity with acceleration + m.vel += accel * (magdt / (rSqr + epsilon)); + } + } + } + else + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir(m.pos - center); + + // Distance to jet (force drops as 1/r^2) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = dir.length2(); + + pVector accel; + accel = dir/_sqrt(rSqr); + + // Step velocity with acceleration + m.vel += accel * (magdt / (rSqr + epsilon)); + } + } +} +void PAScatter::Transform(const Fmatrix& m) +{ + m.transform_tiny (center,centerL); +} +//------------------------------------------------------------------------------------------------- + +// Get rid of older particles +void PAKillOld::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + // Must traverse list in reverse order so Remove will work + tm_max = age_limit; + for(int i = effect->p_count-1; i >= 0; i--) + { + Particle &m = effect->particles[i]; + + if(!((m.age < age_limit) ^ kill_less_than)) + effect->Remove(i); + } +} +void PAKillOld::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Match velocity to near neighbors +void PAMatchVelocity::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Add interactions with other particles + for(u32 j = i + 1; j < effect->p_count; j++) + { + Particle &mj = effect->particles[j]; + + pVector tohim(mj.pos - m.pos); // tohim = p1 - p0 + float tohimlenSqr = tohim.length2(); + + if(tohimlenSqr < max_radiusSqr) + { + // Compute force exerted between the two bodies + pVector acc(mj.vel * (magdt / (tohimlenSqr + epsilon))); + + m.vel += acc; + mj.vel -= acc; + } + } + } + } + else + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Add interactions with other particles + for(u32 j = i + 1; j < effect->p_count; j++) + { + Particle &mj = effect->particles[j]; + + pVector tohim(mj.pos - m.pos); // tohim = p1 - p0 + float tohimlenSqr = tohim.length2(); + + // Compute force exerted between the two bodies + pVector acc(mj.vel * (magdt / (tohimlenSqr + epsilon))); + + m.vel += acc; + mj.vel -= acc; + } + } + } +} +void PAMatchVelocity::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +void PAMove::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + // Step particle positions forward by dt, and age the particles. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + // move + m.age += dt; + m.posB = m.pos; +// m.velB = m.vel; + m.pos += m.vel * dt; + } +} +void PAMove::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Accelerate particles towards a line +void PAOrbitLine::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle from base of line. + pVector f(m.pos - p); + + pVector w(axis * (f * axis)); + + // Direction from particle to nearest point on line. + pVector into = w - f; + + // Distance to line (force drops as 1/r^2, normalize by 1/r) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = into.length2(); + + if(rSqr < max_radiusSqr) + // Step velocity with acceleration + m.vel += into * (magdt / (_sqrt(rSqr) + (rSqr + epsilon))); + } + } + else + { + // Removed because it causes pipeline stalls. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle from base of line. + pVector f(m.pos - p); + + pVector w(axis * (f * axis)); + + // Direction from particle to nearest point on line. + pVector into = w - f; + + // Distance to line (force drops as 1/r^2, normalize by 1/r) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = into.length2(); + + // Step velocity with acceleration + m.vel += into * (magdt / (_sqrt(rSqr) + (rSqr + epsilon))); + } + } +} +void PAOrbitLine::Transform(const Fmatrix& m) +{ + m.transform_tiny(p,pL); + m.transform_dir(axis,axisL); +} +//------------------------------------------------------------------------------------------------- + +// Accelerate particles towards a point +void PAOrbitPoint::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir(center - m.pos); + + // Distance to gravity well (force drops as 1/r^2, normalize by 1/r) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = dir.length2(); + + // Step velocity with acceleration + if(rSqr < max_radiusSqr) + m.vel += dir * (magdt / (_sqrt(rSqr) + (rSqr + epsilon))); + } + } + else + { + // Avoids pipeline stalls. + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Figure direction to particle. + pVector dir(center - m.pos); + + // Distance to gravity well (force drops as 1/r^2, normalize by 1/r) + // Soften by epsilon to avoid tight encounters to infinity + float rSqr = dir.length2(); + + // Step velocity with acceleration + m.vel += dir * (magdt / (_sqrt(rSqr) + (rSqr + epsilon))); + } + } +} +void PAOrbitPoint::Transform(const Fmatrix& m) +{ + m.transform_tiny(center,centerL); +} +//------------------------------------------------------------------------------------------------- + +// Accelerate in random direction each time step +void PARandomAccel::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + pVector acceleration; + gen_acc.Generate(acceleration); + + // dt will affect this by making a higher probability of + // being near the original velocity after unit time. Smaller + // dt approach a normal distribution instead of a square wave. + m.vel += acceleration * dt; + } +} +void PARandomAccel::Transform(const Fmatrix& m) +{ + gen_acc.transform_dir(gen_accL,m); +} +//------------------------------------------------------------------------------------------------- + +// Immediately displace position randomly +void PARandomDisplace::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + pVector displacement; + gen_disp.Generate(displacement); + + // dt will affect this by making a higher probability of + // being near the original position after unit time. Smaller + // dt approach a normal distribution instead of a square wave. + m.pos += displacement * dt; + } +} +void PARandomDisplace::Transform(const Fmatrix& m) +{ + gen_disp.transform_dir(gen_dispL,m); +} +//------------------------------------------------------------------------------------------------- + +// Immediately assign a random velocity +void PARandomVelocity::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + pVector velocity; + gen_vel.Generate(velocity); + + // Shouldn't multiply by dt because velocities are + // invariant of dt. How should dt affect this? + m.vel = velocity; + } +} +void PARandomVelocity::Transform(const Fmatrix& m) +{ + gen_vel.transform_dir(gen_velL,m); +} +//------------------------------------------------------------------------------------------------- + +#if 0 +// Produce coefficients of a velocity function v(t)=at^2 + bt + c +// satisfying initial x(0)=x0,v(0)=v0 and desired x(t)=xf,v(t)=vf, +// where x = x(0) + integrate(v(T),0,t) +static inline void _pconstrain(float x0, float v0, float xf, float vf, + float t, float *a, float *b, float *c) +{ + *c = v0; + *b = 2 * (-t*vf - 2*t*v0 + 3*xf - 3*x0) / (t * t); + *a = 3 * (t*vf + t*v0 - 2*xf + 2*x0) / (t * t * t); +} +#endif + +// Over time, restore particles to initial positions +// Put all particles on the surface of a statue, explode the statue, +// and then suck the particles back to the original position. Cool! +void PARestore::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + if(time_left <= 0) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Already constrained, keep it there. + m.pos = m.posB; + m.vel = pVector(0,0,0); + } + } + else + { + float t = time_left; + float dtSqr = dt * dt; + float tSqrInv2dt = dt * 2.0f / (t * t); + float tCubInv3dtSqr = dtSqr * 3.0f / (t * t * t); + + for(u32 i = 0; i < effect->p_count; i++) + { +#if 1 + Particle &m = effect->particles[i]; + + // Solve for a desired-behavior velocity function in each axis + // _pconstrain(m.pos.x, m.vel.x, m.posB.x, 0., timeLeft, &a, &b, &c); + + // Figure new velocity at next timestep + // m.vel.x = a * dtSqr + b * dt + c; + + float b = (-2*t*m.vel.x + 3*m.posB.x - 3*m.pos.x) * tSqrInv2dt; + float a = (t*m.vel.x - m.posB.x - m.posB.x + m.pos.x + m.pos.x) * tCubInv3dtSqr; + + // Figure new velocity at next timestep + m.vel.x += a + b; + + b = (-2*t*m.vel.y + 3*m.posB.y - 3*m.pos.y) * tSqrInv2dt; + a = (t*m.vel.y - m.posB.y - m.posB.y + m.pos.y + m.pos.y) * tCubInv3dtSqr; + + // Figure new velocity at next timestep + m.vel.y += a + b; + + b = (-2*t*m.vel.z + 3*m.posB.z - 3*m.pos.z) * tSqrInv2dt; + a = (t*m.vel.z - m.posB.z - m.posB.z + m.pos.z + m.pos.z) * tCubInv3dtSqr; + + // Figure new velocity at next timestep + m.vel.z += a + b; +#else + Particle &m = effect->particles[i]; + + // XXX Optimize this. + // Solve for a desired-behavior velocity function in each axis + float a, b, c; // Coefficients of velocity function needed + + _pconstrain(m.pos.x, m.vel.x, m.posB.x, 0., + timeLeft, &a, &b, &c); + + // Figure new velocity at next timestep + m.vel.x = a * dtSqr + b * dt + c; + + _pconstrain(m.pos.y, m.vel.y, m.posB.y, 0., + timeLeft, &a, &b, &c); + + // Figure new velocity at next timestep + m.vel.y = a * dtSqr + b * dt + c; + + _pconstrain(m.pos.z, m.vel.z, m.posB.z, 0., + timeLeft, &a, &b, &c); + + // Figure new velocity at next timestep + m.vel.z = a * dtSqr + b * dt + c; + +#endif + } + } + + time_left -= dt; +} +void PARestore::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Kill particles with positions on wrong side of the specified domain +void PASink::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + // Must traverse list in reverse order so Remove will work + for(int i = effect->p_count-1; i >= 0; i--) + { + Particle &m = effect->particles[i]; + + // Remove if inside/outside flag matches object's flag + if(!(position.Within(m.pos) ^ kill_inside)) + effect->Remove(i); + } +} +void PASink::Transform(const Fmatrix& m) +{ + position.transform(positionL,m); +} +//------------------------------------------------------------------------------------------------- + +// Kill particles with velocities on wrong side of the specified domain +void PASinkVelocity::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + // Must traverse list in reverse order so Remove will work + for(int i = effect->p_count-1; i >= 0; i--) + { + Particle &m = effect->particles[i]; + + // Remove if inside/outside flag matches object's flag + if(!(velocity.Within(m.vel) ^ kill_inside)) + effect->Remove(i); + } +} +void PASinkVelocity::Transform(const Fmatrix& m) +{ + velocity.transform_dir(velocityL,m); +} +//------------------------------------------------------------------------------------------------- + +// Randomly add particles to the system +void PASource::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + if (m_Flags.is(flSilent)) return; + + int rate = int(floor(particle_rate * dt)); + + // Dither the fraction particle in time. + if(drand48() < particle_rate * dt - float(rate)) + rate++; + + // Don't emit more than it can hold. + if(effect->p_count + rate > effect->max_particles) + rate = effect->max_particles - effect->p_count; + + pVector pos, posB, vel, col, siz, rt; + + if(m_Flags.is(u32(flVertexB_tracks))){ + for(int i = 0; i < rate; i++){ + position.Generate (pos); + size.Generate (siz); if (m_Flags.is(flSingleSize)) siz.set(siz.x,siz.x,siz.x); + rot.Generate (rt); + velocity.Generate (vel); vel += parent_vel; + color.Generate (col); + float ag = age + NRand(age_sigma); + + effect->Add (pos, pos, siz, rt, vel, color_argb_f(alpha, col.x, col.y, col.z), ag); + } + }else{ + for(int i = 0; i < rate; i++){ + position.Generate (pos); + size.Generate (siz); if (m_Flags.is(flSingleSize)) siz.set(siz.x,siz.x,siz.x); + rot.Generate (rt); + velocity.Generate (vel); vel += parent_vel; + color.Generate (col); + float ag = age + NRand(age_sigma); + + effect->Add (pos, posB, siz, rt, vel, color_argb_f(alpha, col.x, col.y, col.z), ag); + } + } +} +void PASource::Transform(const Fmatrix& m) +{ + position.transform(positionL,m); + velocity.transform_dir(velocityL,m); +} +//------------------------------------------------------------------------------------------------- + +void PASpeedLimit::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float min_sqr = min_speed*min_speed; + float max_sqr = max_speed*max_speed; + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + float sSqr = m.vel.length2(); + if(sSqrmax_sqr) + { + float s = _sqrt(sSqr); + m.vel *= (max_speed/s); + } + } +} +void PASpeedLimit::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Change color of all particles toward the specified color +void PATargetColor::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float scaleFac = scale * dt; + Fcolor c_p,c_t; + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + if(m.agetimeTo*tm_max ) continue; + + c_p.set (m.color); + c_t.set (c_p.r+(color.x-c_p.r)*scaleFac, c_p.g+(color.y-c_p.g)*scaleFac, c_p.b+(color.z-c_p.b)*scaleFac, c_p.a+(alpha-c_p.a)*scaleFac); + m.color = c_t.get(); + } +} +void PATargetColor::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Change sizes of all particles toward the specified size +void PATargetSize::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float scaleFac_x = scale.x * dt; + float scaleFac_y = scale.y * dt; + float scaleFac_z = scale.z * dt; + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + pVector dif(size - m.size); + dif.x *= scaleFac_x; + dif.y *= scaleFac_y; + dif.z *= scaleFac_z; + m.size += dif; + } +} +void PATargetSize::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Change rotation of all particles toward the specified velocity +void PATargetRotate::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float scaleFac = scale * dt; + + pVector r = pVector(_abs(rot.x),_abs(rot.y),_abs(rot.z)); + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; +// m.rot += (r - m.rot) * scaleFac; + pVector sign(m.rot.x>=0.f?scaleFac:-scaleFac,m.rot.y>=0.f?scaleFac:-scaleFac,m.rot.z>=0.f?scaleFac:-scaleFac); + pVector dif((r.x-_abs(m.rot.x))*sign.x,(r.y-_abs(m.rot.y))*sign.x,(r.z-_abs(m.rot.z))*sign.x); + m.rot += dif; + } +} +void PATargetRotate::Transform(const Fmatrix&){;} +//------------------------------------------------------------------------------------------------- + +// Change velocity of all particles toward the specified velocity +void PATargetVelocity::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float scaleFac = scale * dt; + + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + m.vel += (velocity - m.vel) * scaleFac; + } +} +void PATargetVelocity::Transform(const Fmatrix& m) +{ + m.transform_dir(velocity,velocityL); +} +//------------------------------------------------------------------------------------------------- + +// Immediately displace position using vortex +// Vortex tip at center, around axis, with magnitude +// and tightness exponent +void PAVortex::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + float magdt = magnitude * dt; + float max_radiusSqr = max_radius * max_radius; + + if(max_radiusSqr < P_MAXFLOAT) + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Vector from tip of vortex + pVector offset(m.pos - center); + + // Compute distance from particle to tip of vortex. + float rSqr = offset.length2(); + + // Don't do anything to particle if too close or too far. + if(rSqr > max_radiusSqr) + continue; + + float r = _sqrt(rSqr); + + // Compute normalized offset vector3. + pVector offnorm(offset / r); + + // Construct orthogonal vector3 frame in which to rotate + // transformed point around origin + float axisProj = offnorm * axis; // offnorm . axis + + // Components of offset perpendicular and parallel to axis + pVector w(axis * axisProj); // parallel component + pVector u(offnorm - w); // perpendicular component + + // Perpendicular component completing frame: + pVector v(axis ^ u); + + // Figure amount of rotation + // Resultant is (cos theta) u + (sin theta) v + float theta = magdt / (rSqr + epsilon); + float s = _sin(theta); + float c = _cos(theta); + + offset = (u * c + v * s + w) * r; + + // Translate back to object space + m.pos = offset + center; + } + } + else + { + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + // Vector from tip of vortex + pVector offset(m.pos - center); + + // Compute distance from particle to tip of vortex. + float rSqr = offset.length2(); + + float r = _sqrt(rSqr); + + // Compute normalized offset vector3. + pVector offnorm(offset / r); + + // Construct orthogonal vector3 frame in which to rotate + // transformed point around origin + float axisProj = offnorm * axis; // offnorm . axis + + // Components of offset perpendicular and parallel to axis + pVector w(axis * axisProj); // parallel component + pVector u(offnorm - w); // perpendicular component + + // Perpendicular component completing frame: + pVector v(axis ^ u); + + // Figure amount of rotation + // Resultant is (cos theta) u + (sin theta) v + float theta = magdt / (rSqr + epsilon); + float s = _sin(theta); + float c = _cos(theta); + + offset = (u * c + v * s + w) * r; + + // Translate back to object space + m.pos = offset + center; + } + } +} +void PAVortex::Transform(const Fmatrix& m) +{ + m.transform_tiny(center,centerL); + m.transform_dir(axis,axisL); +} +//------------------------------------------------------------------------------------------------- + +// Turbulence +#include "noise.h" + +static int noise_start = 1; +extern void noise3Init(); + +#ifndef _EDITOR + +#include +#include "../xrCPU_Pipe/ttapi.h" +#pragma comment(lib,"xrCPU_Pipe.lib") + +__forceinline __m128 _mm_load_fvector( const Fvector& v ) +{ + __m128 R1,R2; + + R1 = _mm_load_ss( (float*) &v.x ); // R1 = 0 | 0 | 0 | v.x + R2 = _mm_load_ss( (float*) &v.y ); // R2 = 0 | 0 | 0 | v.y + R1 = _mm_unpacklo_ps( R1 , R2 ); // R1 = 0 | 0 | v.y | v.x + R2 = _mm_load_ss( (float*) &v.z ); // R2 = 0 | 0 | 0 | v.z + R1 = _mm_movelh_ps( R1 , R2 ); // R1 = 0 | v.z | v.y | v.x + + return R1; +} + +__forceinline void _mm_store_fvector( Fvector& v , const __m128 R1 ) +{ + __m128 R2; + + _mm_store_ss( (float*) &v.x , R1 ); + R2 = _mm_unpacklo_ps( R1 , R1 ); // R2 = v.y | v.y | v.x | v.x + R2 = _mm_movehl_ps( R2 , R2 ); // R2 = v.y | v.y | v.y | v.y + _mm_store_ss( (float*) &v.y , R2 ); + R2 = _mm_movehl_ps( R1 , R1 ); // R2 = 0 | v.z | 0 | v.z + _mm_store_ss( (float*) &v.z , R2 ); +} + + +struct TES_PARAMS { + u32 p_from; + u32 p_to; + ParticleEffect* effect; + pVector offset; + float age; + float epsilon; + float frequency; + int octaves; + float magnitude; +}; + +void PATurbulenceExecuteStream( LPVOID lpvParams ) +{ + pVector pV; + pVector vX; + pVector vY; + pVector vZ; + + TES_PARAMS* pParams = (TES_PARAMS *) lpvParams; + + u32 p_from = pParams->p_from; + u32 p_to = pParams->p_to; + ParticleEffect* effect = pParams->effect; + pVector offset = pParams->offset; + float age = pParams->age; + float epsilon = pParams->epsilon; + float frequency = pParams->frequency; + int octaves = pParams->octaves; + float magnitude = pParams->magnitude; + + for(u32 i = p_from; i < p_to; i++) + { + Particle &m = effect->particles[i]; + + pV.mad(m.pos,offset,age); + vX.set(pV.x+epsilon,pV.y,pV.z); + vY.set(pV.x,pV.y+epsilon,pV.z); + vZ.set(pV.x,pV.y,pV.z+epsilon); + + float d = fractalsum3(pV, frequency, octaves); + + pVector D; + + D.x = fractalsum3(vX, frequency, octaves); + D.y = fractalsum3(vY, frequency, octaves); + D.z = fractalsum3(vZ, frequency, octaves); + + __m128 _D = _mm_load_fvector( D ); + __m128 _d = _mm_set1_ps( d ); + __m128 _magnitude = _mm_set1_ps( magnitude ); + __m128 _mvel = _mm_load_fvector( m.vel ); + _D = _mm_sub_ps( _D , _d ); + _D = _mm_mul_ps( _D , _magnitude ); + + __m128 _vmo = _mm_mul_ps( _mvel , _mvel ); // _vmo = 00 | zz | yy | xx + __m128 _tmp = _mm_movehl_ps( _vmo , _vmo ); // _tmp = 00 | zz | 00 | zz + _vmo = _mm_add_ss( _vmo , _tmp ); // _vmo = 00 | zz | yy | xx + zz + _tmp = _mm_unpacklo_ps( _vmo , _vmo ); // _tmp = yy | yy | xx + zz | xx + zz + _tmp = _mm_movehl_ps( _tmp , _tmp ); // _tmp = yy | yy | yy | yy + _vmo = _mm_add_ss( _vmo , _tmp ); // _vmo = 00 | zz | yy | xx + yy + zz + _vmo = _mm_sqrt_ss( _vmo ); // _vmo = 00 | zz | yy | vmo + + _mvel = _mm_add_ps( _mvel , _D ); + + __m128 _vmn = _mm_mul_ps( _mvel , _mvel ); // _vmn = 00 | zz | yy | xx + _tmp = _mm_movehl_ps( _vmn , _vmn ); // _tmp = 00 | zz | 00 | zz + _vmn = _mm_add_ss( _vmn , _tmp ); // _vmn = 00 | zz | yy | xx + zz + _tmp = _mm_unpacklo_ps( _vmn , _vmn ); // _tmp = yy | yy | xx + zz | xx + zz + _tmp = _mm_movehl_ps( _tmp , _tmp ); // _tmp = yy | yy | yy | yy + _vmn = _mm_add_ss( _vmn , _tmp ); // _vmn = 00 | zz | yy | xx + yy + zz + _vmn = _mm_sqrt_ss( _vmn ); // _vmn = 00 | zz | yy | vmn + + _vmo = _mm_div_ss( _vmo , _vmn ); // _vmo = 00 | zz | yy | scale + + _vmo = _mm_shuffle_ps( _vmo , _vmo , _MM_SHUFFLE( 0 , 0 , 0 , 0 ) ); // _vmo = scale | scale | scale | scale + _mvel = _mm_mul_ps( _mvel , _vmo ); + + _mm_store_fvector( m.vel , _mvel ); + } + +} + + +void PATurbulence::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + if ( noise_start ) { + noise_start = 0; + noise3Init(); + }; + + age += dt; + + u32 p_cnt = effect->p_count; + + u32 nWorkers = ttapi_GetWorkersCount(); + + if ( p_cnt < ( nWorkers * 64 ) ) + nWorkers = 1; + + TES_PARAMS* tesParams = (TES_PARAMS*) _alloca( sizeof(TES_PARAMS) * nWorkers ); + + // Give ~1% more for the last worker + // to minimize wait in final spin + u32 nSlice = p_cnt / 128; + + u32 nStep = ( ( p_cnt - nSlice ) / nWorkers ); + + for ( u32 i = 0 ; i < nWorkers ; ++i ) { + tesParams[i].p_from = i * nStep; + tesParams[i].p_to = ( i == ( nWorkers - 1 ) ) ? p_cnt : ( tesParams[i].p_from + nStep ); + + tesParams[i].effect = effect; + tesParams[i].offset = offset; + tesParams[i].age = age; + tesParams[i].epsilon = epsilon; + tesParams[i].frequency = frequency; + tesParams[i].octaves = octaves; + tesParams[i].magnitude = magnitude; + + ttapi_AddWorker( PATurbulenceExecuteStream , (LPVOID) &tesParams[i] ); + } + + ttapi_RunAllWorkers(); + +} + +#else + +void PATurbulence::Execute(ParticleEffect *effect, const float dt, float& tm_max) +{ + if ( noise_start ) { + noise_start = 0; + noise3Init(); + }; + + pVector pV; + pVector vX; + pVector vY; + pVector vZ; + age += dt; + for(u32 i = 0; i < effect->p_count; i++) + { + Particle &m = effect->particles[i]; + + pV.mad(m.pos,offset,age); + vX.set(pV.x+epsilon,pV.y,pV.z); + vY.set(pV.x,pV.y+epsilon,pV.z); + vZ.set(pV.x,pV.y,pV.z+epsilon); + + pVector D; + float d = fractalsum3(pV, frequency, octaves); + D.x = (fractalsum3(vX, frequency, octaves) - d)*(float)magnitude; + D.y = (fractalsum3(vY, frequency, octaves) - d)*(float)magnitude; + D.z = (fractalsum3(vZ, frequency, octaves) - d)*(float)magnitude; + + float velMagOrig = m.vel.magnitude(); + m.vel.add (D); + float velMagNow = m.vel.magnitude(); + float valMagScale = velMagOrig/velMagNow; + m.vel.mul(valMagScale); + } +} +#endif + + +void PATurbulence::Transform(const Fmatrix& m){} +//------------------------------------------------------------------------------------------------- + diff --git a/xrParticles/particle_actions_collection.h b/xrParticles/particle_actions_collection.h new file mode 100644 index 00000000000..314d0ae04f6 --- /dev/null +++ b/xrParticles/particle_actions_collection.h @@ -0,0 +1,304 @@ +//--------------------------------------------------------------------------- +#ifndef particle_actions_collectionH +#define particle_actions_collectionH + +#include "particle_actions.h" +#include "particle_core.h" +namespace PAPI{ +#define _METHODS virtual void Load (IReader& F);\ + virtual void Save (IWriter& F);\ + virtual void Execute (ParticleEffect *pe, const float dt, float& m_max);\ + virtual void Transform (const Fmatrix& m); + + struct PARTICLES_API PAAvoid : public ParticleAction + { + pDomain positionL; // Avoid region (in local space) + pDomain position; // Avoid region + float look_ahead; // how many time units ahead to look + float magnitude; // what percent of the way to go each time + float epsilon; // add to r^2 for softening + + _METHODS; + }; + + struct PARTICLES_API PABounce : public ParticleAction + { + pDomain positionL; // Bounce region (in local space) + pDomain position; // Bounce region + float oneMinusFriction; // Friction tangent to surface + float resilience; // Resilence perpendicular to surface + float cutoffSqr; // cutoff velocity; friction applies iff v > cutoff + + _METHODS; + }; + + struct PARTICLES_API PACopyVertexB : public ParticleAction + { + BOOL copy_pos; // True to copy pos to posB. + + _METHODS; + }; + + struct PARTICLES_API PADamping : public ParticleAction + { + pVector damping; // Damping constant applied to velocity + float vlowSqr; // Low and high cutoff velocities + float vhighSqr; + + _METHODS; + }; + + struct PARTICLES_API PAExplosion : public ParticleAction + { + pVector centerL; // The center of the explosion (in local space) + pVector center; // The center of the explosion + float velocity; // Of shock wave + float magnitude; // At unit radius + float stdev; // Sharpness or width of shock wave + float age; // How long it's been going on + float epsilon; // Softening parameter + + _METHODS; + }; + + struct PARTICLES_API PAFollow : public ParticleAction + { + float magnitude; // The grav of each particle + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PAGravitate : public ParticleAction + { + float magnitude; // The grav of each particle + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PAGravity : public ParticleAction + { + pVector directionL; // Amount to increment velocity (in local space) + pVector direction; // Amount to increment velocity + + _METHODS; + }; + + struct PARTICLES_API PAJet : public ParticleAction + { + pVector centerL; // Center of the fan (in local space) + pDomain accL; // Acceleration vector domain (in local space) + pVector center; // Center of the fan + pDomain acc; // Acceleration vector domain + float magnitude; // Scales acceleration + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PAKillOld : public ParticleAction + { + float age_limit; // Exact age at which to kill particles. + BOOL kill_less_than; // True to kill particles less than limit. + + _METHODS; + }; + + struct PARTICLES_API PAMatchVelocity : public ParticleAction + { + float magnitude; // The grav of each particle + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PAMove : public ParticleAction + { + _METHODS; + }; + + struct PARTICLES_API PAOrbitLine : public ParticleAction + { + pVector pL, axisL; // Endpoints of line to which particles are attracted (in local space) + pVector p, axis; // Endpoints of line to which particles are attracted + float magnitude; // Scales acceleration + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PAOrbitPoint : public ParticleAction + { + pVector centerL; // Point to which particles are attracted (in local space) + pVector center; // Point to which particles are attracted + float magnitude; // Scales acceleration + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PARandomAccel : public ParticleAction + { + pDomain gen_accL; // The domain of random accelerations.(in local space) + pDomain gen_acc; // The domain of random accelerations. + + _METHODS; + }; + + struct PARTICLES_API PARandomDisplace : public ParticleAction + { + pDomain gen_dispL; // The domain of random displacements.(in local space) + pDomain gen_disp; // The domain of random displacements. + + _METHODS; + }; + + struct PARTICLES_API PARandomVelocity : public ParticleAction + { + pDomain gen_velL; // The domain of random velocities.(in local space) + pDomain gen_vel; // The domain of random velocities. + + _METHODS; + }; + + struct PARTICLES_API PARestore : public ParticleAction + { + float time_left; // Time remaining until they should be in position. + + _METHODS; + }; + + struct PARTICLES_API PAScatter : public ParticleAction + { + pVector centerL; // Center of the fan (in local space) + pVector center; // Center of the fan + float magnitude; // Scales acceleration + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PASink : public ParticleAction + { + BOOL kill_inside; // True to dispose of particles *inside* domain + pDomain positionL; // Disposal region (in local space) + pDomain position; // Disposal region + + _METHODS; + }; + + struct PARTICLES_API PASinkVelocity : public ParticleAction + { + BOOL kill_inside; // True to dispose of particles with vel *inside* domain + pDomain velocityL; // Disposal region (in local space) + pDomain velocity; // Disposal region + + _METHODS; + }; + + struct PARTICLES_API PASpeedLimit : public ParticleAction + { + float min_speed; // Clamp speed to this minimum. + float max_speed; // Clamp speed to this maximum. + + _METHODS; + }; + + struct PARTICLES_API PASource : public ParticleAction + { + enum{ + flSingleSize = (1ul<<29ul),// True to get positionB from position. + flSilent = (1ul<<30ul), + flVertexB_tracks = (1ul<<31ul),// True to get positionB from position. + fl_FORCEDWORD = u32(-1) + }; + pDomain positionL; // Choose a position in this domain. (local_space) + pDomain velocityL; // Choose a velocity in this domain. (local_space) + pDomain position; // Choose a position in this domain. + pDomain velocity; // Choose a velocity in this domain. + pDomain rot; // Choose a rotation in this domain. + pDomain size; // Choose a size in this domain. + pDomain color; // Choose a color in this domain. + float alpha; // Alpha of all generated particles + float particle_rate;// Particles to generate per unit time + float age; // Initial age of the particles + float age_sigma; // St. dev. of initial age of the particles + pVector parent_vel; + float parent_motion; + + _METHODS; + }; + + struct PARTICLES_API PATargetColor : public ParticleAction + { + PATargetColor():timeFrom(0.0f),timeTo(1.0f){} + pVector color; // Color to shift towards + float alpha; // Alpha value to shift towards + float scale; // Amount to shift by (1 == all the way) + float timeFrom; + float timeTo; + + _METHODS; + }; + + struct PARTICLES_API PATargetSize : public ParticleAction + { + pVector size; // Size to shift towards + pVector scale; // Amount to shift by per frame (1 == all the way) + + _METHODS; + }; + + struct PARTICLES_API PATargetRotate : public ParticleAction + { + pVector rot; // Rotation to shift towards + float scale; // Amount to shift by per frame (1 == all the way) + + _METHODS; + }; + + struct PARTICLES_API PATargetVelocity : public ParticleAction + { + pVector velocityL; // Velocity to shift towards (in local space) + pVector velocity; // Velocity to shift towards + float scale; // Amount to shift by (1 == all the way) + + _METHODS; + }; + + struct PARTICLES_API PAVortex : public ParticleAction + { + pVector centerL; // Center of vortex (in local space) + pVector axisL; // Axis around which vortex is applied (in local space) + pVector center; // Center of vortex + pVector axis; // Axis around which vortex is applied + float magnitude; // Scale for rotation around axis + float epsilon; // Softening parameter + float max_radius; // Only influence particles within max_radius + + _METHODS; + }; + + struct PARTICLES_API PATurbulence : public ParticleAction + { + float frequency; // Frequency + int octaves; // Octaves + float magnitude; // Scale for rotation around axis + float epsilon; // Softening parameter + pVector offset; // Offset + float age; + + _METHODS; + }; +}; + +//--------------------------------------------------------------------------- +#endif diff --git a/xrParticles/particle_actions_collection_io.cpp b/xrParticles/particle_actions_collection_io.cpp new file mode 100644 index 00000000000..e1cdbe222a6 --- /dev/null +++ b/xrParticles/particle_actions_collection_io.cpp @@ -0,0 +1,480 @@ +#include "stdafx.h" +#pragma hdrstop + +#include "particle_actions_collection.h" +using namespace PAPI; + +void ParticleAction::Load (IReader& F) +{ + m_Flags.assign (F.r_u32()); + type = (PActionEnum)F.r_u32(); +} +void ParticleAction::Save (IWriter& F) +{ + F.w_u32 (m_Flags.get()); + F.w_u32 (type); +} + +void PAAvoid::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r (&position,sizeof(pDomain)); + look_ahead = F.r_float(); + magnitude = F.r_float(); + epsilon = F.r_float(); + positionL = position; +} +void PAAvoid::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w (&position,sizeof(pDomain)); + F.w_float (look_ahead); + F.w_float (magnitude); + F.w_float (epsilon); +} + +void PABounce::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r (&position,sizeof(pDomain)); + oneMinusFriction= F.r_float(); + resilience = F.r_float(); + cutoffSqr = F.r_float(); + positionL = position; +} +void PABounce::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w (&position,sizeof(pDomain)); + F.w_float (oneMinusFriction); + F.w_float (resilience); + F.w_float (cutoffSqr); +} + +void PACopyVertexB::Load (IReader& F) +{ + ParticleAction::Load (F); + copy_pos = F.r_u32(); +} +void PACopyVertexB::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_u32 (copy_pos); +} + +void PADamping::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (damping); + vlowSqr = F.r_float (); + vhighSqr = F.r_float (); +} +void PADamping::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (damping); + F.w_float (vlowSqr); + F.w_float (vhighSqr); +} + +void PAExplosion::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (center); + velocity = F.r_float(); + magnitude = F.r_float(); + stdev = F.r_float(); + age = F.r_float(); + epsilon = F.r_float(); + centerL = center; +} +void PAExplosion::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (center); + F.w_float (velocity); + F.w_float (magnitude); + F.w_float (stdev); + F.w_float (age); + F.w_float (epsilon); +} + +void PAFollow::Load (IReader& F) +{ + ParticleAction::Load (F); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); +} +void PAFollow::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PAGravitate::Load (IReader& F) +{ + ParticleAction::Load (F); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); +} +void PAGravitate::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PAGravity::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (direction); + directionL = direction; +} +void PAGravity::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (direction); +} + +void PAJet::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (center); + F.r (&acc,sizeof(pDomain)); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); + centerL = center; + accL = acc; +} +void PAJet::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (center); + F.w (&acc,sizeof(pDomain)); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PAKillOld::Load (IReader& F) +{ + ParticleAction::Load (F); + age_limit = F.r_float (); + kill_less_than = F.r_u32 (); +} +void PAKillOld::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (age_limit); + F.w_u32 (kill_less_than); +} + +void PAMatchVelocity::Load (IReader& F) +{ + ParticleAction::Load (F); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); +} +void PAMatchVelocity::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PAMove::Load (IReader& F) +{ + ParticleAction::Load (F); +} +void PAMove::Save (IWriter& F) +{ + ParticleAction::Save (F); +} + +void PAOrbitLine::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (p); + F.r_fvector3 (axis); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); + pL = p; + axisL = axis; +} +void PAOrbitLine::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (p); + F.w_fvector3 (axis); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PAOrbitPoint::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (center); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); + centerL = center; +} +void PAOrbitPoint::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (center); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PARandomAccel::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r (&gen_acc,sizeof(pDomain)); + gen_accL = gen_acc; +} +void PARandomAccel::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w (&gen_acc,sizeof(pDomain)); +} + +void PARandomDisplace::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r (&gen_disp,sizeof(pDomain)); + gen_dispL = gen_disp; +} +void PARandomDisplace::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w (&gen_disp,sizeof(pDomain)); +} + +void PARandomVelocity::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r (&gen_vel,sizeof(pDomain)); + gen_velL = gen_vel; +} +void PARandomVelocity::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w (&gen_vel,sizeof(pDomain)); +} + +void PARestore::Load (IReader& F) +{ + ParticleAction::Load (F); + time_left = F.r_float(); +} +void PARestore::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (time_left); +} + +void PAScatter::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (center); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); + centerL = center; +} +void PAScatter::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (center); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PASink::Load (IReader& F) +{ + ParticleAction::Load (F); + kill_inside = F.r_u32(); + F.r (&position,sizeof(pDomain)); + positionL = position; +} +void PASink::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_u32 (kill_inside); + F.w (&position,sizeof(pDomain)); +} + +void PASinkVelocity::Load (IReader& F) +{ + ParticleAction::Load (F); + kill_inside = F.r_u32(); + F.r (&velocity,sizeof(pDomain)); + velocityL = velocity; +} +void PASinkVelocity::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_u32 (kill_inside); + F.w (&velocity,sizeof(pDomain)); +} + +void PASpeedLimit::Load (IReader& F) +{ + ParticleAction::Load (F); + min_speed = F.r_float(); + max_speed = F.r_float(); +} +void PASpeedLimit::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (min_speed); + F.w_float (max_speed); +} + +void PASource::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r (&position,sizeof(pDomain)); + F.r (&velocity,sizeof(pDomain)); + F.r (&rot,sizeof(pDomain)); + F.r (&size,sizeof(pDomain)); + F.r (&color,sizeof(pDomain)); + alpha = F.r_float(); + particle_rate = F.r_float(); + age = F.r_float(); + age_sigma = F.r_float(); + F.r_fvector3 (parent_vel); + parent_motion = F.r_float(); + positionL = position; + velocityL = velocity; +} +void PASource::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w (&position,sizeof(pDomain)); + F.w (&velocity,sizeof(pDomain)); + F.w (&rot,sizeof(pDomain)); + F.w (&size,sizeof(pDomain)); + F.w (&color,sizeof(pDomain)); + F.w_float (alpha); + F.w_float (particle_rate); + F.w_float (age); + F.w_float (age_sigma); + F.w_fvector3 (parent_vel); + F.w_float (parent_motion); +} + +void PATargetColor::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (color); + alpha = F.r_float(); + scale = F.r_float(); + timeFrom = F.r_float(); + timeTo = F.r_float(); +} + +void PATargetColor::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (color); + F.w_float (alpha); + F.w_float (scale); + F.w_float (timeFrom); + F.w_float (timeTo); +} + +void PATargetSize::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (size); + F.r_fvector3 (scale); +} +void PATargetSize::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (size); + F.w_fvector3 (scale); +} + +void PATargetRotate::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (rot); + scale = F.r_float(); +} +void PATargetRotate::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (rot); + F.w_float (scale); +} + +void PATargetVelocity::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (velocity); + scale = F.r_float(); + velocityL = velocity; +} +void PATargetVelocity::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (velocity); + F.w_float (scale); +} + +void PAVortex::Load (IReader& F) +{ + ParticleAction::Load (F); + F.r_fvector3 (center); + F.r_fvector3 (axis); + magnitude = F.r_float(); + epsilon = F.r_float(); + max_radius = F.r_float(); + centerL = center; + axisL = axis; +} +void PAVortex::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_fvector3 (center); + F.w_fvector3 (axis); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_float (max_radius); +} + +void PATurbulence::Load (IReader& F) +{ + ParticleAction::Load (F); + frequency = F.r_float(); + octaves = F.r_s32(); + magnitude = F.r_float(); + epsilon = F.r_float(); + F.r_fvector3 (offset); +} +void PATurbulence::Save (IWriter& F) +{ + ParticleAction::Save (F); + F.w_float (frequency); + F.w_s32 (octaves); + F.w_float (magnitude); + F.w_float (epsilon); + F.w_fvector3 (offset); +} + + diff --git a/xrParticles/particle_core.cpp b/xrParticles/particle_core.cpp new file mode 100644 index 00000000000..2b0c847ba7d --- /dev/null +++ b/xrParticles/particle_core.cpp @@ -0,0 +1,451 @@ +//--------------------------------------------------------------------------- +#include "stdafx.h" +#pragma hdrstop + +#include "particle_core.h" + +using namespace PAPI; + +// To offset [0 .. 1] vectors to [-.5 .. .5] +static pVector vHalf(0.5, 0.5, 0.5); + +ICF pVector RandVec() +{ + return pVector(drand48(), drand48(), drand48()); +} + +// Return a random number with a normal distribution. +float PAPI::NRand(float sigma) +{ +#define ONE_OVER_SIGMA_EXP (1.0f / 0.7975f) + + if(sigma == 0) return 0; + + float y; + do + { + y = -logf(drand48()); + } + while(drand48() > expf(-_sqr(y - 1.0f)*0.5f)); + + if(rand() & 0x1) + return y * sigma * ONE_OVER_SIGMA_EXP; + else + return -y * sigma * ONE_OVER_SIGMA_EXP; +} +//////////////////////////////////////////////////////////////////////////////// +// Stuff for the pDomain. +pDomain::pDomain(PDomainEnum dtype, float a0, float a1, + float a2, float a3, float a4, float a5, + float a6, float a7, float a8) +{ + type = dtype; + switch(type) + { + case PDPoint: + p1 = pVector(a0, a1, a2); + break; + case PDLine: + { + p1 = pVector(a0, a1, a2); + pVector tmp(a3, a4, a5); + // p2 is vector3 from p1 to other endpoint. + p2 = tmp - p1; + } + break; + case PDBox: + // p1 is the min corner. p2 is the max corner. + if(a0 < a3) + { + p1.x = a0; p2.x = a3; + } + else + { + p1.x = a3; p2.x = a0; + } + if(a1 < a4) + { + p1.y = a1; p2.y = a4; + } + else + { + p1.y = a4; p2.y = a1; + } + if(a2 < a5) + { + p1.z = a2; p2.z = a5; + } + else + { + p1.z = a5; p2.z = a2; + } + break; + case PDTriangle: + { + p1 = pVector(a0, a1, a2); + pVector tp2 = pVector(a3, a4, a5); + pVector tp3 = pVector(a6, a7, a8); + + u = tp2 - p1; + v = tp3 - p1; + + // The rest of this is needed for bouncing. + radius1Sqr = u.length(); + pVector tu = u / radius1Sqr; + radius2Sqr = v.length(); + pVector tv = v / radius2Sqr; + + p2 = tu ^ tv; // This is the non-unit normal. + p2.normalize_safe(); // Must normalize it. + + // radius1 stores the d of the plane eqn. + radius1 = -(p1 * p2); + } + break; + case PDRectangle: + { + p1 = pVector(a0, a1, a2); + u = pVector(a3, a4, a5); + v = pVector(a6, a7, a8); + + // The rest of this is needed for bouncing. + radius1Sqr = u.length(); + pVector tu = u / radius1Sqr; + radius2Sqr = v.length(); + pVector tv = v / radius2Sqr; + + p2 = tu ^ tv; // This is the non-unit normal. + p2.normalize_safe(); // Must normalize it. + + // radius1 stores the d of the plane eqn. + radius1 = -(p1 * p2); + } + break; + case PDPlane: + { + p1 = pVector(a0, a1, a2); + p2 = pVector(a3, a4, a5); + p2.normalize_safe(); // Must normalize it. + + // radius1 stores the d of the plane eqn. + radius1 = -(p1 * p2); + } + break; + case PDSphere: + p1 = pVector(a0, a1, a2); + if(a3 > a4) + { + radius1 = a3; radius2 = a4; + } + else + { + radius1 = a4; radius2 = a3; + } + radius1Sqr = radius1 * radius1; + radius2Sqr = radius2 * radius2; + break; + case PDCone: + case PDCylinder: + { + // p2 is a vector3 from p1 to the other end of cylinder. + // p1 is apex of cone. + + p1 = pVector(a0, a1, a2); + pVector tmp(a3, a4, a5); + p2 = tmp - p1; + + if(a6 > a7) + { + radius1 = a6; radius2 = a7; + } + else + { + radius1 = a7; radius2 = a6; + } + radius1Sqr = _sqr(radius1); + + // Given an arbitrary nonzero vector3 n, make two orthonormal + // vectors u and v forming a frame [u,v,n.normalize()]. + pVector n = p2; + float p2l2 = n.length2(); // Optimize this. + n.normalize_safe(); + + // radius2Sqr stores 1 / (p2.p2) + // XXX Used to have an actual if. + radius2Sqr = p2l2 ? 1.0f / p2l2 : 0.0f; + + // Find a vector3 orthogonal to n. + pVector basis(1.0f, 0.0f, 0.0f); + if(_abs(basis * n) > 0.999) + basis = pVector(0.0f, 1.0f, 0.0f); + + // Project away N component, normalize and cross to get + // second orthonormal vector3. + u = basis - n * (basis * n); + u.normalize_safe(); + v = n ^ u; + } + break; + case PDBlob: + { + p1 = pVector(a0, a1, a2); + radius1 = a3; + float tmp = 1.f/radius1; + radius2Sqr = -0.5f*_sqr(tmp); + radius2 = ONEOVERSQRT2PI * tmp; + } + break; + case PDDisc: + { + p1 = pVector(a0, a1, a2); // Center point + p2 = pVector(a3, a4, a5); // Normal (not used in Within and Generate) + p2.normalize_safe(); + + if(a6 > a7) + { + radius1 = a6; radius2 = a7; + } + else + { + radius1 = a7; radius2 = a6; + } + + // Find a vector3 orthogonal to n. + pVector basis(1.0f, 0.0f, 0.0f); + if(_abs(basis * p2) > 0.999) + basis = pVector(0.0f, 1.0f, 0.0f); + + // Project away N component, normalize and cross to get + // second orthonormal vector3. + u = basis - p2 * (basis * p2); + u.normalize_safe(); + v = p2 ^ u; + radius1Sqr = -(p1 * p2); // D of the plane eqn. + } + break; + } +} + +// Determines if pos is inside the domain +BOOL pDomain::Within(const pVector &pos) const +{ + switch (type) + { + case PDBox: + return !((pos.x < p1.x) || (pos.x > p2.x) || + (pos.y < p1.y) || (pos.y > p2.y) || + (pos.z < p1.z) || (pos.z > p2.z)); + case PDPlane: + // Distance from plane = n * p + d + // Inside is the positive half-space. + return pos * p2 >= -radius1; + case PDSphere: + { + pVector rvec(pos - p1); + float rSqr = rvec.length2(); + return rSqr <= radius1Sqr && rSqr >= radius2Sqr; + } + case PDCylinder: + case PDCone: + { + // This is painful and slow. Might be better to do quick + // accept/reject tests. + // Let p2 = vector3 from base to tip of the cylinder + // x = vector3 from base to test point + // x . p2 + // dist = ------ = projected distance of x along the axis + // p2. p2 ranging from 0 (base) to 1 (tip) + // + // rad = x - dist * p2 = projected vector3 of x along the base + // p1 is the apex of the cone. + + pVector x(pos - p1); + + // Check axial distance + // radius2Sqr stores 1 / (p2.p2) + float dist = (p2 * x) * radius2Sqr; + if(dist < 0.0f || dist > 1.0f) + return FALSE; + + // Check radial distance; scale radius along axis for cones + pVector xrad = x - p2 * dist; // Radial component of x + float rSqr = xrad.length2(); + + if(type == PDCone) + return (rSqr <= _sqr(dist * radius1) && + rSqr >= _sqr(dist * radius2)); + else + return (rSqr <= radius1Sqr && rSqr >= _sqr(radius2)); + } + case PDBlob: + { + pVector x(pos - p1); + // return exp(-0.5 * xSq * Sqr(oneOverSigma)) * ONEOVERSQRT2PI * oneOverSigma; + float Gx = expf(x.length2() * radius2Sqr) * radius2; + return (drand48() < Gx); + } + case PDPoint: + case PDLine: + case PDRectangle: + case PDTriangle: + case PDDisc: + default: + return FALSE; // XXX Is there something better? + } +} + +// Generate a random point uniformly distrbuted within the domain +void pDomain::Generate(pVector &pos) const +{ + switch (type) + { + case PDPoint: + pos = p1; + break; + case PDLine: + pos = p1 + p2 * drand48(); + break; + case PDBox: + // Scale and translate [0,1] random to fit box + pos.x = p1.x + (p2.x - p1.x) * drand48(); + pos.y = p1.y + (p2.y - p1.y) * drand48(); + pos.z = p1.z + (p2.z - p1.z) * drand48(); + break; + case PDTriangle: + { + float r1 = drand48(); + float r2 = drand48(); + if(r1 + r2 < 1.0f) + pos = p1 + u * r1 + v * r2; + else + pos = p1 + u * (1.0f-r1) + v * (1.0f-r2); + } + break; + case PDRectangle: + pos = p1 + u * drand48() + v * drand48(); + break; + case PDPlane: // How do I sensibly make a point on an infinite plane? + pos = p1; + break; + case PDSphere: + // Place on [-1..1] sphere + pos = RandVec() - vHalf; + pos.normalize_safe(); + + // Scale unit sphere pos by [0..r] and translate + // (should distribute as r^2 law) + if(radius1 == radius2) + pos = p1 + pos * radius1; + else + pos = p1 + pos * (radius2 + drand48() * (radius1 - radius2)); + break; + case PDCylinder: + case PDCone: + { + // For a cone, p2 is the apex of the cone. + float dist = drand48(); // Distance between base and tip + float theta = drand48() * 2.0f * float(M_PI); // Angle around axis + // Distance from axis + float r = radius2 + drand48() * (radius1 - radius2); + + float x = r * _cos(theta); // Weighting of each frame vector3 + float y = r * _sin(theta); + + // Scale radius along axis for cones + if(type == PDCone) + { + x *= dist; + y *= dist; + } + + pos = p1 + p2 * dist + u * x + v * y; + } + break; + case PDBlob: + pos.x = p1.x + NRand(radius1); + pos.y = p1.y + NRand(radius1); + pos.z = p1.z + NRand(radius1); + + break; + case PDDisc: + { + float theta = drand48() * 2.0f * float(M_PI); // Angle around normal + // Distance from center + float r = radius2 + drand48() * (radius1 - radius2); + + float x = r * _cos(theta); // Weighting of each frame vector3 + float y = r * _sin(theta); + + pos = p1 + u * x + v * y; + } + break; + default: + pos = pVector(0,0,0); + } +} + +void pDomain::transform(const pDomain& domain, const Fmatrix& m) +{ + switch (type) + { + case PDBox:{ + Fbox* bb_dest=(Fbox*)&p1; + Fbox* bb_from=(Fbox*)&domain.p1; + bb_dest->xform(*bb_from,m); + }break; + case PDPlane: + m.transform_tiny(p1,domain.p1); + m.transform_dir(p2,domain.p2); + // radius1 stores the d of the plane eqn. + radius1 = -(p1 * p2); + break; + case PDSphere: + m.transform_tiny(p1,domain.p1); + break; + case PDCylinder: + case PDCone: + m.transform_tiny(p1,domain.p1); + m.transform_dir(p2,domain.p2); + m.transform_dir(u,domain.u); + m.transform_dir(v,domain.v); + break; + case PDBlob: + m.transform_tiny(p1,domain.p1); + break; + case PDPoint: + m.transform_tiny(p1,domain.p1); + break; + case PDLine: + m.transform_tiny(p1,domain.p1); + m.transform_dir(p2,domain.p2); + break; + case PDRectangle: + m.transform_tiny(p1,domain.p1); + m.transform_dir(p2,domain.p2); + m.transform_dir(u,domain.u); + m.transform_dir(v,domain.v); + break; + case PDTriangle: + m.transform_tiny(p1,domain.p1); + m.transform_dir(p2,domain.p2); + m.transform_dir(u,domain.u); + m.transform_dir(v,domain.v); + break; + case PDDisc: + m.transform_tiny(p1,domain.p1); + m.transform_dir(p2,domain.p2); + m.transform_dir(u,domain.u); + m.transform_dir(v,domain.v); + break; + default: + NODEFAULT; + } +} + +void pDomain::transform_dir(const pDomain& domain, const Fmatrix& m) +{ + Fmatrix M=m; + M.c.set(0,0,0); + transform(domain,M); +} + diff --git a/xrParticles/particle_core.h b/xrParticles/particle_core.h new file mode 100644 index 00000000000..816a4271111 --- /dev/null +++ b/xrParticles/particle_core.h @@ -0,0 +1,40 @@ +//--------------------------------------------------------------------------- +#ifndef particle_coreH +#define particle_coreH + +#define SQRT2PI 2.506628274631000502415765284811045253006f +#define ONEOVERSQRT2PI (1.f/SQRT2PI) + +namespace PAPI{ + #pragma pack (push,4) + struct PARTICLES_API pDomain + { + PDomainEnum type; // PABoxDomain, PASphereDomain, PAConeDomain... + pVector p1, p2; // Box vertices, Sphere center, Cylinder/Cone ends + pVector u, v; // Orthonormal basis vectors for Cylinder/Cone + float radius1; // Outer radius + float radius2; // Inner radius + float radius1Sqr; // Used for fast Within test of spheres, + float radius2Sqr; // and for mag. of u and v vectors for plane. + + BOOL Within (const pVector &) const; + void Generate (pVector &) const; + // transformation + void transform (const pDomain& domain, const Fmatrix& m); + void transform_dir (const pDomain& domain, const Fmatrix& m); + // This constructor is used when default constructing a + // ParticleAction that has a pDomain. + IC pDomain (){} + // Construct a domain in the standard way. + pDomain (PDomainEnum dtype, + float a0=0.0f, float a1=0.0f, float a2=0.0f, + float a3=0.0f, float a4=0.0f, float a5=0.0f, + float a6=0.0f, float a7=0.0f, float a8=0.0f); + }; + #pragma pack (pop) + // misc + float NRand (float sigma = 1.0f); +}; +//--------------------------------------------------------------------------- +#endif + \ No newline at end of file diff --git a/xrParticles/particle_effect.cpp b/xrParticles/particle_effect.cpp new file mode 100644 index 00000000000..5948a549991 --- /dev/null +++ b/xrParticles/particle_effect.cpp @@ -0,0 +1,5 @@ +#include "stdafx.h" +#pragma hdrstop + +#include "particle_effect.h" + diff --git a/xrParticles/particle_effect.h b/xrParticles/particle_effect.h new file mode 100644 index 00000000000..b0fc93ba820 --- /dev/null +++ b/xrParticles/particle_effect.h @@ -0,0 +1,96 @@ +//--------------------------------------------------------------------------- +#ifndef particle_effectH +#define particle_effectH + +namespace PAPI{ + // A effect of particles - Info and an array of Particles + struct ParticleEffect + { + u32 p_count; // Number of particles currently existing. + u32 max_particles; // Max particles allowed in effect. + u32 particles_allocated; // Actual allocated size. + Particle* particles; // Actually, num_particles in size + OnBirthParticleCB b_cb; + OnDeadParticleCB d_cb; + void* owner; + u32 param; + + public: + ParticleEffect (int mp) + { + owner = 0; + param = 0; + b_cb = 0; + d_cb = 0; + p_count = 0; + max_particles = mp; + particles_allocated = max_particles; + particles = xr_alloc(max_particles); + } + ~ParticleEffect () + { + xr_free (particles); + } + IC int Resize (u32 max_count) + { + // Reducing max. + if(particles_allocated >= max_count) + { + max_particles = max_count; + + // May have to kill particles. + if(p_count > max_particles) + p_count = max_particles; + + return max_count; + } + + // Allocate particles. + Particle* new_particles = xr_alloc(max_count); + if(new_particles==NULL){ + // ERROR - Not enough memory. Just give all we've got. + max_particles = particles_allocated; + return max_particles; + } + + CopyMemory (new_particles, particles, p_count * sizeof(Particle)); + xr_free (particles); + particles = new_particles; + + max_particles = max_count; + particles_allocated = max_count; + return max_count; + } + IC void Remove (int i) + { + if (0==p_count) return; + Particle& m = particles[i]; + if (d_cb) d_cb(owner,param,m,i); + m = particles[--p_count]; // �� ������ ������� �������� !!! (dependence ParticleGroup) + } + + IC BOOL Add (const pVector &pos, const pVector &posB, + const pVector &size, const pVector &rot, const pVector &vel, u32 color, + const float age = 0.0f, u16 frame=0, u16 flags=0) + { + if(p_count >= max_particles) return FALSE; + else{ + Particle& P = particles[p_count]; + P.pos = pos; + P.posB = posB; + P.size = size; + P.rot = rot; + P.vel = vel; + P.color = color; + P.age = age; + P.frame = frame; + P.flags.assign(flags); + if (b_cb) b_cb(owner,param,P,p_count); + p_count++; + return TRUE; + } + } + }; +}; +//--------------------------------------------------------------------------- +#endif diff --git a/xrParticles/particle_manager.cpp b/xrParticles/particle_manager.cpp new file mode 100644 index 00000000000..a40b885c805 --- /dev/null +++ b/xrParticles/particle_manager.cpp @@ -0,0 +1,287 @@ +//--------------------------------------------------------------------------- +#include "stdafx.h" +#pragma hdrstop + +#include "particle_manager.h" +#include "particle_effect.h" +#include "particle_actions_collection.h" + +using namespace PAPI; + +// system +CParticleManager PM; +PARTICLES_API IParticleManager* PAPI::ParticleManager(){ return &PM; } + +// +CParticleManager::CParticleManager () +{ +} + +CParticleManager::~CParticleManager () +{ +} + +ParticleEffect* CParticleManager::GetEffectPtr(int effect_id) +{ + R_ASSERT(effect_id>=0&&effect_id<(int)effect_vec.size()); + return effect_vec[effect_id]; +} + +ParticleActions* CParticleManager::GetActionListPtr(int a_list_num) +{ + R_ASSERT(a_list_num>=0&&a_list_num<(int)m_alist_vec.size()); + return m_alist_vec[a_list_num]; +} + +// create +int CParticleManager::CreateEffect(u32 max_particles) +{ + int eff_id = -1; + for(int i=0; i<(int)effect_vec.size(); i++) + if(!effect_vec[i]){ eff_id=i; break;} + + if (eff_id<0){ + // Couldn't find a big enough gap. Reallocate. + eff_id = effect_vec.size(); + effect_vec.push_back (0); + } + + effect_vec[eff_id] = xr_new(max_particles); + + return eff_id; +} +void CParticleManager::DestroyEffect(int effect_id) +{ + R_ASSERT(effect_id>=0&&effect_id<(int)effect_vec.size()); + xr_delete(effect_vec[effect_id]); +} +int CParticleManager::CreateActionList() +{ + int list_id = -1; + for(u32 i=0; i(); + + return list_id; +} +void CParticleManager::DestroyActionList(int alist_id) +{ + R_ASSERT(alist_id>=0&&alist_id<(int)m_alist_vec.size()); + xr_delete(m_alist_vec[alist_id]); +} + +// control +void CParticleManager::PlayEffect(int effect_id, int alist_id) +{ + // effect +// ParticleEffect* pe = GetEffectPtr(effect_id); + // Execute the specified action list. + ParticleActions* pa = GetActionListPtr(alist_id); + VERIFY (pa); + if(pa == NULL) return; // ERROR + pa->lock(); + // Step through all the actions in the action list. + for(PAVecIt it=pa->begin(); it!=pa->end(); ++it) + { + VERIFY((*it)); + switch((*it)->type){ + case PASourceID: static_cast(*it)->m_Flags.set(PASource::flSilent,FALSE); break; + case PAExplosionID: static_cast(*it)->age = 0.f; break; + case PATurbulenceID:static_cast(*it)->age = 0.f; break; + } + } + pa->unlock(); +} + +void CParticleManager::StopEffect(int effect_id, int alist_id, BOOL deffered) +{ + // Execute the specified action list. + ParticleActions* pa = GetActionListPtr(alist_id); + VERIFY (pa); + if(pa == NULL) return; // ERROR + pa->lock(); + + // Step through all the actions in the action list. + for(PAVecIt it=pa->begin(); it!=pa->end(); it++){ + switch((*it)->type){ + case PASourceID: static_cast(*it)->m_Flags.set(PASource::flSilent,TRUE); break; + } + } + if (!deffered){ + // effect + ParticleEffect* pe = GetEffectPtr(effect_id); + pe->p_count = 0; + } + pa->unlock(); +} + +// update&render +void CParticleManager::Update(int effect_id, int alist_id, float dt) +{ + ParticleEffect* pe = GetEffectPtr(effect_id); + ParticleActions* pa = GetActionListPtr(alist_id); + + VERIFY(pa); + VERIFY(pe); + + pa->lock(); + + // Step through all the actions in the action list. + float kill_old_time = 1.0f; + for(PAVecIt it=pa->begin(); it!=pa->end(); it++) + { + VERIFY((*it)); + (*it)->Execute (pe, dt, kill_old_time); + } + pa->unlock(); +} +void CParticleManager::Render(int effect_id) +{ +// ParticleEffect* pe = GetEffectPtr(effect_id); +} +void CParticleManager::Transform(int alist_id, const Fmatrix& full, const Fvector& vel) +{ + // Execute the specified action list. + ParticleActions* pa = GetActionListPtr(alist_id); + VERIFY(pa); + + if(pa == NULL) return; // ERROR + pa->lock(); + + Fmatrix mT; mT.translate(full.c); + + // Step through all the actions in the action list. + for(PAVecIt it=pa->begin(); it!=pa->end(); it++){ + BOOL r = (*it)->m_Flags.is(ParticleAction::ALLOW_ROTATE); + const Fmatrix& m = r?full:mT; + (*it)->Transform(m); + switch((*it)->type) + { + case PASourceID: + static_cast(*it)->parent_vel = pVector(vel.x,vel.y,vel.z)*static_cast(*it)->parent_motion; + break; + } + } + pa->unlock(); +} + +// effect +void CParticleManager::RemoveParticle(int effect_id, u32 p_id) +{ + ParticleEffect *pe = GetEffectPtr(effect_id); + pe->Remove (p_id); +} +void CParticleManager::SetMaxParticles(int effect_id, u32 max_particles) +{ + ParticleEffect *pe = GetEffectPtr(effect_id); + pe->Resize (max_particles); +} +void CParticleManager::SetCallback(int effect_id, OnBirthParticleCB b, OnDeadParticleCB d, void* owner, u32 param) +{ + ParticleEffect *pe = GetEffectPtr(effect_id); + pe->b_cb = b; + pe->d_cb = d; + pe->owner = owner; + pe->param = param; +} +void CParticleManager::GetParticles(int effect_id, Particle*& particles, u32& cnt) +{ + ParticleEffect *pe = GetEffectPtr(effect_id); + particles = pe->particles; + cnt = pe->p_count; +} +u32 CParticleManager::GetParticlesCount (int effect_id) +{ + ParticleEffect *pe = GetEffectPtr(effect_id); + return pe->p_count; +} + +// action +ParticleAction* CParticleManager::CreateAction(PActionEnum type) +{ + ParticleAction* pa = 0; + switch(type){ + case PAAvoidID: pa = xr_new(); break; + case PABounceID: pa = xr_new(); break; + case PACopyVertexBID: pa = xr_new(); break; + case PADampingID: pa = xr_new(); break; + case PAExplosionID: pa = xr_new(); break; + case PAFollowID: pa = xr_new(); break; + case PAGravitateID: pa = xr_new(); break; + case PAGravityID: pa = xr_new(); break; + case PAJetID: pa = xr_new(); break; + case PAKillOldID: pa = xr_new(); break; + case PAMatchVelocityID: pa = xr_new(); break; + case PAMoveID: pa = xr_new(); break; + case PAOrbitLineID: pa = xr_new(); break; + case PAOrbitPointID: pa = xr_new(); break; + case PARandomAccelID: pa = xr_new(); break; + case PARandomDisplaceID: pa = xr_new(); break; + case PARandomVelocityID: pa = xr_new(); break; + case PARestoreID: pa = xr_new(); break; + case PASinkID: pa = xr_new(); break; + case PASinkVelocityID: pa = xr_new(); break; + case PASourceID: pa = xr_new(); break; + case PASpeedLimitID: pa = xr_new(); break; + case PATargetColorID: pa = xr_new(); break; + case PATargetSizeID: pa = xr_new(); break; + case PATargetRotateID: pa = xr_new(); break; + case PATargetRotateDID: pa = xr_new(); break; + case PATargetVelocityID: pa = xr_new(); break; + case PATargetVelocityDID: pa = xr_new(); break; + case PAVortexID: pa = xr_new(); break; + case PATurbulenceID: pa = xr_new(); break; + case PAScatterID: pa = xr_new(); break; + default: NODEFAULT; + } + pa->type = type; + return pa; +} +u32 CParticleManager::LoadActions(int alist_id, IReader& R) +{ + // Execute the specified action list. + ParticleActions* pa = GetActionListPtr(alist_id); + VERIFY(pa); + pa->clear (); + if (R.length()) + { + u32 cnt = R.r_u32(); + for (u32 k=0; kLoad (R); + pa->append (act); + } + } + return pa->size(); +} +void CParticleManager::SaveActions(int alist_id, IWriter& W) +{ + // Execute the specified action list. + ParticleActions* pa = GetActionListPtr(alist_id); + VERIFY(pa); + pa->lock(); + W.w_u32 (pa->size()); + for (PAVecIt it=pa->begin(); it!=pa->end(); it++) + (*it)->Save (W); + pa->unlock(); +} + + + + + + + + diff --git a/xrParticles/particle_manager.h b/xrParticles/particle_manager.h new file mode 100644 index 00000000000..91463102ab6 --- /dev/null +++ b/xrParticles/particle_manager.h @@ -0,0 +1,52 @@ +//--------------------------------------------------------------------------- +#ifndef particle_managerH +#define particle_managerH +//--------------------------------------------------------------------------- +#include "particle_actions.h" + +namespace PAPI{ + class CParticleManager: public IParticleManager + { + // These are static because all threads access the same effects. + // All accesses to these should be locked. + DEFINE_VECTOR (ParticleEffect*,ParticleEffectVec,ParticleEffectVecIt); + DEFINE_VECTOR (ParticleActions*,ParticleActionsVec,ParticleActionsVecIt); + ParticleEffectVec effect_vec; + ParticleActionsVec m_alist_vec; + public: + CParticleManager (); + virtual ~CParticleManager (); + // Return an index into the list of particle effects where + ParticleEffect* GetEffectPtr (int effect_id); + ParticleActions* GetActionListPtr (int alist_id); + + // create&destroy + virtual int CreateEffect (u32 max_particles); + virtual void DestroyEffect (int effect_id); + virtual int CreateActionList (); + virtual void DestroyActionList (int alist_id); + + // control + virtual void PlayEffect (int effect_id, int alist_id); + virtual void StopEffect (int effect_id, int alist_id, BOOL deffered=TRUE); + + // update&render + virtual void Update (int effect_id, int alist_id, float dt); + virtual void Render (int effect_id); + virtual void Transform (int alist_id, const Fmatrix& m, const Fvector& velocity); + + // effect + virtual void RemoveParticle (int effect_id, u32 p_id); + virtual void SetMaxParticles (int effect_id, u32 max_particles); + virtual void SetCallback (int effect_id, OnBirthParticleCB b, OnDeadParticleCB d, void* owner, u32 param); + virtual void GetParticles (int effect_id, Particle*& particles, u32& cnt); + virtual u32 GetParticlesCount (int effect_id); + + // action + virtual ParticleAction* CreateAction (PActionEnum action_id); + virtual u32 LoadActions (int alist_id, IReader& R); + virtual void SaveActions (int alist_id, IWriter& W); + }; +}; +//--------------------------------------------------------------------------- +#endif diff --git a/xrParticles/psystem.h b/xrParticles/psystem.h new file mode 100644 index 00000000000..e5cdd057648 --- /dev/null +++ b/xrParticles/psystem.h @@ -0,0 +1,160 @@ +#ifndef PSystemH +#define PSystemH +#pragma once + +#ifdef XR_PARTICLES_EXPORTS + #define PARTICLES_API __declspec(dllexport) +#else + #define PARTICLES_API __declspec(dllimport) + #ifdef _EDITOR + #pragma comment(lib,"x:\\xrParticlesB.lib") + #else + #pragma comment(lib,"xrParticles.lib") + #endif +#endif + +// Actually this must be < sqrt(MAXFLOAT) since we store this value squared. +#define P_MAXFLOAT 1.0e16f + +#ifdef MAXINT + #define P_MAXINT MAXINT +#else + #define P_MAXINT 0x7fffffff +#endif + +#define drand48() ::Random.randF() +//#define drand48() (((float) rand())/((float) RAND_MAX)) + +namespace PAPI{ + class pVector : public Fvector + { + public: + IC pVector (float ax, float ay, float az) { set(ax,ay,az); } + IC pVector () {} + IC float length () const { return _sqrt(x*x+y*y+z*z); } + IC float length2 () const { return (x*x+y*y+z*z); } + IC float operator* (const pVector &a) const { return x*a.x + y*a.y + z*a.z; } + IC pVector operator* (const float s) const { return pVector(x*s, y*s, z*s); } + IC pVector operator/ (const float s) const { float invs = 1.0f / s; return pVector(x*invs, y*invs, z*invs); } + IC pVector operator+ (const pVector& a) const { return pVector(x+a.x, y+a.y, z+a.z); } + IC pVector operator- (const pVector& a) const { return pVector(x-a.x, y-a.y, z-a.z); } + IC pVector operator- () { x = -x; y = -y; z = -z; return *this; } + IC pVector& operator+= (const pVector& a) { x += a.x;y += a.y;z += a.z; return *this; } + IC pVector& operator-= (const pVector& a) { x -= a.x;y -= a.y;z -= a.z; return *this; } + IC pVector& operator*= (const float a) { x *= a; y *= a; z *= a; return *this; } + IC pVector& operator/= (const float a) { float b = 1.0f / a; x *= b; y *= b; z *= b; return *this; } + IC pVector& operator= (const pVector& a) { x = a.x;y = a.y;z = a.z;return *this; } + IC pVector operator^ (const pVector& b) const { return pVector(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x); } + }; + // A single particle + struct Particle + { + enum{ + ANIMATE_CCW = (1<<0), + }; + pVector pos; // 12 + pVector posB; // 12 + pVector vel; // 12 + pVector size; // 12 + pVector rot; // 12 60 + u32 color; // 4 + float age; // 4 + u16 frame; // 2 + Flags16 flags; // 2 + }; // 72 + + typedef void (* OnBirthParticleCB) (void* owner, u32 param, PAPI::Particle& P, u32 idx); + typedef void (* OnDeadParticleCB) (void* owner, u32 param, PAPI::Particle& P, u32 idx); + ////////////////////////////////////////////////////////////////////// + // Type codes for domains + enum PDomainEnum + { + PDPoint = 0, // Single point + PDLine = 1, // Line segment + PDTriangle = 2, // Triangle + PDPlane = 3, // Arbitrarily-oriented plane + PDBox = 4, // Axis-aligned box + PDSphere = 5, // Sphere + PDCylinder = 6, // Cylinder + PDCone = 7, // Cone + PDBlob = 8, // Gaussian blob + PDDisc = 9, // Arbitrarily-oriented disc + PDRectangle = 10, // Rhombus-shaped planar region + domain_enum_force_dword = u32(-1) + }; + ////////////////////////////////////////////////////////////////////// + // Type codes for all actions + enum PActionEnum + { + PAAvoidID, // Avoid entering the domain of space. + PABounceID, // Bounce particles off a domain of space. + PACallActionListID_obsolette, // + PACopyVertexBID, // Set the secondary position from current position. + PADampingID, // Dampen particle velocities. + PAExplosionID, // An Explosion. + PAFollowID, // Accelerate toward the previous particle in the effect. + PAGravitateID, // Accelerate each particle toward each other particle. + PAGravityID, // Acceleration in the given direction. + PAJetID, // + PAKillOldID, // + PAMatchVelocityID, // + PAMoveID, // + PAOrbitLineID, // + PAOrbitPointID, // + PARandomAccelID, // + PARandomDisplaceID, // + PARandomVelocityID, // + PARestoreID, // + PASinkID, // + PASinkVelocityID, // + PASourceID, // + PASpeedLimitID, // + PATargetColorID, // + PATargetSizeID, // + PATargetRotateID, // + PATargetRotateDID, // + PATargetVelocityID, // + PATargetVelocityDID,// + PAVortexID, // + PATurbulenceID, // + PAScatterID, // + action_enum_force_dword = u32(-1) + }; + struct ParticleAction; + + class IParticleManager{ + public: + IParticleManager (){} + virtual ~IParticleManager (){} + + // create&destroy + virtual int CreateEffect (u32 max_particles)=0; + virtual void DestroyEffect (int effect_id)=0; + virtual int CreateActionList ()=0; + virtual void DestroyActionList (int alist_id)=0; + + // control + virtual void PlayEffect (int effect_id, int alist_id)=0; + virtual void StopEffect (int effect_id, int alist_id, BOOL deffered=TRUE)=0; + + // update&render + virtual void Update (int effect_id, int alist_id, float dt)=0; + virtual void Render (int effect_id)=0; + virtual void Transform (int alist_id, const Fmatrix& m, const Fvector& velocity)=0; + + // effect + virtual void RemoveParticle (int effect_id, u32 p_id)=0; + virtual void SetMaxParticles (int effect_id, u32 max_particles)=0; + virtual void SetCallback (int effect_id, OnBirthParticleCB b, OnDeadParticleCB d, void* owner, u32 param)=0; + virtual void GetParticles (int effect_id, Particle*& particles, u32& cnt)=0; + virtual u32 GetParticlesCount (int effect_id)=0; + + // action + virtual ParticleAction* CreateAction (PActionEnum type)=0; + virtual u32 LoadActions (int alist_id, IReader& R)=0; + virtual void SaveActions (int alist_id, IWriter& W)=0; + }; + + PARTICLES_API IParticleManager* ParticleManager (); +}; +#endif //PSystemH diff --git a/xrParticles/stdafx.cpp b/xrParticles/stdafx.cpp new file mode 100644 index 00000000000..785a48beec9 --- /dev/null +++ b/xrParticles/stdafx.cpp @@ -0,0 +1,6 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + diff --git a/xrParticles/stdafx.h b/xrParticles/stdafx.h new file mode 100644 index 00000000000..2112ae2a02f --- /dev/null +++ b/xrParticles/stdafx.h @@ -0,0 +1,22 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// +// Third generation by Oles. + +#ifndef stdafxH +#define stdafxH + +#pragma once + +#include "../xrCore/xrCore.h" + +#include "psystem.h" + +#ifdef __BORLANDC__ +#pragma comment( lib, "x:\\xrCoreB.lib" ) +#else +#pragma comment( lib, "xrCore.lib" ) +#endif + +#endif //stdafxH diff --git a/xrParticles/xrParticles.vcproj b/xrParticles/xrParticles.vcproj new file mode 100644 index 00000000000..ae66e48d7d4 --- /dev/null +++ b/xrParticles/xrParticles.vcproj @@ -0,0 +1,778 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrParticles/xrParticlesB.bpf b/xrParticles/xrParticlesB.bpf new file mode 100644 index 00000000000..7e0f6a59fb5 --- /dev/null +++ b/xrParticles/xrParticlesB.bpf @@ -0,0 +1,3 @@ +This file is used by the project manager only and should be treated like the project file + +DllEntryPoint \ No newline at end of file diff --git a/xrParticles/xrParticlesB.bpr b/xrParticles/xrParticlesB.bpr new file mode 100644 index 00000000000..81a76c33367 --- /dev/null +++ b/xrParticles/xrParticlesB.bpr @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[Version Info] +IncludeVerInfo=0 +AutoIncBuild=0 +MajorVer=1 +MinorVer=0 +Release=0 +Build=34 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1058 +CodePage=1251 + +[Version Info Keys] +CompanyName= +FileDescription= +FileVersion=1.0.0.34 +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=1.0.0.0 +Comments= + +[HistoryLists\hlIncludePath] +Count=26 +Item0=$(BCB)\include;$(BCB)\include\vcl;$(CORE_DIR) +Item1=$(VC_INCLUDE);$(BCB)\include;$(BCB)\include\vcl;$(CORE_DIR) +Item2=P:\Editors\ParticleEditor;$(BCB)\include;$(BCB)\include\vcl;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;P:\xrCore +Item3=P:\Editors\ParticleEditor;$(BCB)\include;$(BCB)\include\vcl;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;P:\xrCore;R:\SDK\DirectX9.0_sum_2004\Include +Item4=P:\Editors\ParticleEditor;R:\SDK\DirectX9.0_sum_2004\Include;C:\Rad\Borland\CBuilder6\Projects;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;P:\xrCore +Item5=R:\SDK\DirectX9.0_sum_2004\Include;C:\Rad\Borland\CBuilder6\Projects;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;P:\xrCore +Item6=C:\Rad\Borland\CBuilder6\Projects;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;P:\xrCore +Item7=C:\Rad\Borland\CBuilder6\Projects;R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;P:\xrCore +Item8=C:\Rad\Borland\CBuilder6\Projects;R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;R:\VS7.NET\Vc7\atlmfc\include;P:\xrCore +Item9=R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;R:\VS7.NET\Vc7\atlmfc\include;P:\xrCore +Item10=R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;R:\VS7.NET\Vc7\atlmfc\include +Item11=R:\SDK\DirectX8.1\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;R:\VS7.NET\Vc7\atlmfc\include +Item12=R:\SDK\DirectX8.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;R:\VS7.NET\Vc7\atlmfc\include +Item13=R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;R:\VS7.NET\Vc7\atlmfc\include;$(BCB)\include\mfc +Item14=R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source;$(BCB)\include\mfc +Item15=R:\SDK\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source +Item16=R:\DirectX9.0\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source +Item17=R:\DirectX9\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source +Item18=R:\DirectX8.1\include;$(BCB)\include;$(BCB)\include\vcl;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source +Item19=..\LevelOptions\Engine;..\LevelOptions\Editor;..\LevelOptions;Editor;R:\DirectX8.1\include;$(BCB)\include;$(BCB)\include\vcl;engine;P:\MagicFM_Borland\Sdk\Include;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source +Item20=Editor;R:\DirectX8.1\include\;$(BCB)\include;$(BCB)\include\vcl;engine;P:\MagicFM_Borland\Sdk\Include\;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code\Source +Item21=Editor;Engine\Blenders;R:\Borland\Components\Eldos\Code\Source\;r:\borland\components\alexmx\;lib\DX;R:\DirectX8.1\include\;c:\rad\Borland\CBuilder5\Bin\;c:\rad\borland\CBuilder5\Projects\;$(BCB)\include;$(BCB)\include\vcl;engine;edit;Import\LWO;Collide;P:\MagicFM_Borland\Sdk\Include\;c:\rad\borland\components\extbtn\;c:\rad\borland\components\multi\;c:\rad\borland\components\renderwindow\;C:\RAD\borland\Components\RX\Units\;C:\RAD\borland\Components\ElTree\Code\Source\ +Item22=Engine\Blenders;R:\Borland\Components\Eldos\Code\Source\;r:\borland\components\alexmx\;lib\DX;R:\DirectX8.1\include\;c:\rad\Borland\CBuilder5\Bin\;c:\rad\borland\CBuilder5\Projects\;$(BCB)\include;$(BCB)\include\vcl;engine;edit;Import\LWO;Collide;P:\MagicFM_Borland\Sdk\Include\;c:\rad\borland\components\extbtn\;c:\rad\borland\components\multi\;c:\rad\borland\components\renderwindow\;C:\RAD\borland\Components\RX\Units\;C:\RAD\borland\Components\ElTree\Code\Source\ +Item23=$(BCB)\include;shared;$(BCB)\include\vcl;edit;edit\Shader;Import\LWO;Collide;P:\MagicFM_Borland\Sdk\Include\;c:\rad\borland\components\extbtn\;c:\rad\borland\components\multi\;c:\rad\borland\components\renderwindow\;C:\RAD\borland\Components\RX\Units\;C:\RAD\borland\Components\ElTree\Code\Source\ +Item24=$(BCB)\include;$(BCB)\include\vcl;edit +Item25=$(BCB)\include;$(BCB)\include\vcl + +[HistoryLists\hlLibraryPath] +Count=25 +Item0=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;$(COMPONENTS)\Elpack\code;$(OUT_LIB_DIR);$(COMPONENTS)\alexMX +Item1=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;$(COMPONENTS)\Elpack\code;$(OUT_LIB_DIR) +Item2=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;$(COMPONENTS)\Elpack\code +Item3=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk +Item4=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;x:\stalker_addon\libraries;X:\stalker_addon\sources\sdk\components\ElPack\Code;x:\libraries +Item5=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;x:\stalker_addon\libraries;X:\stalker_addon\sources\sdk\components\ElPack\Code +Item6=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;x:\stalker_addon\libraries +Item7=$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;$(BCB)\Lib\Psdk;x:\libraries +Item8=P:\Editors\ParticleEditor;C:\Rad\Borland\CBuilder6\Projects;c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;\Editors\lib\dx;\Editors\lib +Item9=C:\Rad\Borland\CBuilder6\Projects;c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;\Editors\lib\dx;\Editors\lib +Item10=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;\Editors\lib\dx;\Editors\lib +Item11=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;..\Editors\lib\dx;..\Editors\lib +Item12=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;..\lib\dx;..\lib +Item13=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;lib;lib\dx +Item14=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk;lib +Item15=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk +Item16=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code;R:\Borland\CBuilder6\Lib\Psdk\ +Item17=c:\rad\borland\CBuilder5\Projects;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code +Item18=..\LevelOptions\Engine;..\LevelOptions\Editor;..\LevelOptions;c:\rad\borland\CBuilder5\Projects;engine;editor;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code +Item19=c:\rad\borland\CBuilder5\Projects\;engine;editor;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;R:\Borland\Components6\AlexMX;R:\Borland\Components6\ElPack\Code +Item20=c:\rad\borland\CBuilder5\Projects\;engine;editor;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;r:\borland\components\alexmx\;R:\Borland\Components\Eldos\Code\Source\;R:\Borland\Components\Eldos\Code\ +Item21=Editor;shared;edit;edit\Shader;Collide;Import\LWO;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;c:\rad\borland\components\renderwindow\;c:\rad\borland\components\extbtn\;c:\rad\borland\components\multi\;C:\RAD\borland\Components\RX\Units\;C:\RAD\borland\Components\ElTree\Code\Source\ +Item22=shared;edit;edit\Shader;Collide;Import\LWO;$(BCB)\lib;$(BCB)\lib\obj;$(BCB)\Projects\Lib;c:\rad\borland\components\renderwindow\;c:\rad\borland\components\extbtn\;c:\rad\borland\components\multi\;C:\RAD\borland\Components\RX\Units\;C:\RAD\borland\Components\ElTree\Code\Source\ +Item23=edit;$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib +Item24=$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib + +[HistoryLists\hlDebugSourcePath] +Count=1 +Item0=$(BCB)\source\vcl + +[HistoryLists\hlConditionals] +Count=4 +Item0=_EDITOR;XR_PARTICLES_EXPORTS;_DEBUG +Item1=_EDITOR;XR_PARTICLES_EXPORTS +Item2=_EDITOR;PARTICLEDLL_EXPORTS;_DEBUG +Item3=_EDITOR;_PARTICLEDLLB;PARTICLEDLL_EXPORTS;_DEBUG + +[HistoryLists\hlIntOutputDir] +Count=6 +Item0=x:\intermediate_ed\particles +Item1=$(OUTPUT_INTERMEDIATE_DIR)\particles +Item2=$(OUTPUT_INTERMEDIATE_DIR) +Item3=$(OUTPUT_INTERMEDIATE_DIR)\ +Item4=x:\intermediate_ed +Item5=Intermediate + +[HistoryLists\hlFinalOutputDir] +Count=7 +Item0=$(OUTPUT_BINARIES_DIR)\ +Item1=x:\stalker_addon\binaries\ +Item2=x:\binaries\ +Item3=x:\binaries +Item4=x:\ +Item5=x:\build\ +Item6=x:\build + +[HistoryLists\hIBPIOutputDir] +Count=5 +Item0=x:\stalker_addon\libraries +Item1=$(OUTPUT_LIBRARIES_DIR) +Item2=$(OUTPUT_LIBRARIES_DIR)\ +Item3=x:\libraries +Item4=x:\ + +[Debugging] +DebugSourceDirs=$(BCB)\source\vcl + +[Parameters] +RunParams=-wf x:\resources +Launcher= +UseLauncher=0 +DebugCWD= +HostApplication=x:\binaries\ParticleEditor.exe +RemoteHost= +RemotePath= +RemoteLauncher= +RemoteCWD= +RemoteDebug=0 + +[Compiler] +ShowInfoMsgs=0 +LinkDebugVcl=0 +LinkCGLIB=0 + +[CORBA] +AddServerUnit=1 +AddClientUnit=1 +PrecompiledHeaders=1 + +[Language] +ActiveLang= +ProjectLang= +RootDir= + +[Linker] +LibPrefix= +LibSuffix= +LibVersion= + + \ No newline at end of file diff --git a/xrPhysics/ActorCameraCollision.cpp b/xrPhysics/ActorCameraCollision.cpp new file mode 100644 index 00000000000..734d90a4518 --- /dev/null +++ b/xrPhysics/ActorCameraCollision.cpp @@ -0,0 +1,356 @@ +#include "stdafx.h" + +//#include "Actor.h" +#include "actorcameracollision.h" + +#include "../xrEngine/CameraBase.h" +#include "../xrEngine/gamemtllib.h" + +#include "phworld.h" +#include "phcollidevalidator.h" +#include "PHShell.h" +#include "matrix_utils.h" +#include "iphysicsshellholder.h" + +//#include "ai/stalker/ai_stalker.h" +#include "GeometryBits.h" +//#include "characterphysicssupport.h" +#ifdef DEBUG +# include "debug_output.h" +#endif +CPhysicsShell* actor_camera_shell = NULL; +#ifdef DEBUG +BOOL dbg_draw_camera_collision = FALSE; +#endif +static bool cam_collided = false; +static bool cam_step = false; +extern dJointGroupID ContactGroup; +static const float camera_collision_sckin_depth = 0.04f; +float camera_collision_character_skin_depth = 0.4f; +float camera_collision_character_shift_z = 0.3f; +static const float camera_collision_character_gl_shift_y = 0.8f; +static void cammera_shell_collide_callback_common( bool& do_collide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ) +{ + if( !do_collide ) + return; + do_collide = false; + SGameMtl* oposite_matrial = bo1 ? material_1 : material_2 ; + if(oposite_matrial->Flags.test(SGameMtl::flPassable)) + return; + + dxGeomUserData *my_data = retrieveGeomUserData( bo1 ? c.geom.g1 : c.geom.g2 ); + dxGeomUserData *oposite_data = retrieveGeomUserData( bo1 ? c.geom.g2 : c.geom.g1 ) ; + + VERIFY( my_data ); + if( oposite_data && oposite_data->ph_ref_object == my_data->ph_ref_object ) + return; + if( c.geom.depth > camera_collision_sckin_depth/2.f ) + cam_collided = true; + + if( !cam_step ) + return; + c.surface.mu = 0; + + dJointID contact_joint = dJointCreateContactSpecial(0, ContactGroup, &c);//dJointCreateContact(0, ContactGroup, &c);// + CPHObject* obj = (CPHObject*)my_data->callback_data; + VERIFY( obj ); +#ifdef DEBUG + if( dbg_draw_camera_collision ) + debug_output().DBG_DrawContact( c ); +#endif + obj->Island().DActiveIsland()->ConnectJoint(contact_joint); + + if(bo1) + dJointAttach (contact_joint, dGeomGetBody(c.geom.g1), 0); + else + dJointAttach (contact_joint, 0, dGeomGetBody(c.geom.g2)); + +} +static const float soft_cfm_for_geometry = 0.01f; +static const float soft_cfm_for_controllers = 0.05f; + +static void cammera_shell_collide_callback( bool& do_collide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ) +{ + c.surface.soft_cfm =soft_cfm_for_geometry; + + dxGeomUserData *oposite_data = retrieveGeomUserData( bo1 ? c.geom.g2 : c.geom.g1 ) ; + + if( oposite_data && oposite_data->ph_object && oposite_data->ph_object->CastType()==CPHObject::tpCharacter) + c.surface.soft_cfm =soft_cfm_for_controllers; + + cammera_shell_collide_callback_common(do_collide,bo1,c,material_1,material_2); +} + +static void cammera_shell_character_collide_callback( bool& do_collide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ) +{ + dxGeomUserData *oposite_data = retrieveGeomUserData( bo1 ? c.geom.g2 : c.geom.g1 ) ; + do_collide = false; + if( !oposite_data || !oposite_data->ph_object || oposite_data->ph_object->CastType()!=CPHObject::tpCharacter) + return; + + if(!oposite_data->ph_ref_object || !(oposite_data->ph_ref_object->IsStalker()) ) + return; + + do_collide = true; + c.surface.soft_cfm =soft_cfm_for_controllers; + cammera_shell_collide_callback_common(do_collide,bo1,c,material_1,material_2); +} + + +static void get_viewport_geom(Fvector &box, Fmatrix &form, const CCameraBase &camera , float _viewport_near ) +{ + box.z = _viewport_near / 2.f; + tviewport_size ( inl_ph_world().Device(), _viewport_near, camera, box.x, box.y ); + form.identity(); + form.i.set( camera.Right() ); + form.j.set( camera.Up() ); + form.k.set( camera.Direction() ); + form.c.mad( camera.Position(), camera.Direction(), _viewport_near/2.f ); +#ifdef DEBUG + if( !_valid( form ) ) + { + dump( "form", form ); + dump( "camera.Right()", camera.Right() ); + dump( "camera.Up()", camera.Up() ); + dump( "camera.Direction()", camera.Direction() ); + dump( "camera.Position()", camera.Position() ); + dump( "box", box ); + VERIFY(false); + } +#endif +} + +static const float actor_camera_hudge_mass = 10.f; +static const float actor_camera_hudge_mass_size = 10000000.f; +CPhysicsShell * create_camera_shell( IPhysicsShellHolder *actor ) +{ + VERIFY(actor); + //CGameObject *actor = smart_cast( Level().CurrentEntity() ); + //VERIFY( Level().CurrentEntity() ); + CPhysicsShell *shell = P_build_SimpleShell( actor, actor_camera_hudge_mass , true ); + CPhysicsElement* roote = shell->get_ElementByStoreOrder( 0 ); + //Fobb obb; obb.m_halfsize.set(0.5f,0.5f,0.5f); obb.m_rotate.identity();obb.m_translate.set(0,0,0); + Fcylinder cyl;cyl.m_center.set(0,-0.8f,0);cyl.m_direction.set(0,1,0);cyl.m_height = 1.8f; cyl.m_radius = 0.5f; + //roote->add_Box(obb); + CODEGeom* character_test_geom = smart_cast(xr_new(cyl)); + character_test_geom->build( Fvector().set( 0, 0, 0 ) );//roote->mass_Center() + VERIFY(smart_cast(roote)); + CPHElement *eeroot = static_cast( roote ); + + character_test_geom->set_body( eeroot->get_body() ); + //character_test_geom->set_ref_object(smart_cast(actor)); + character_test_geom->set_ref_object( actor ); + CPHGeometryBits::set_ignore_static( *character_test_geom ); + roote->add_geom( character_test_geom ); + VERIFY( shell ); + shell->set_ApplyByGravity( false ); + shell->set_ObjectContactCallback( cammera_shell_collide_callback ); + character_test_geom->set_obj_contact_cb( cammera_shell_character_collide_callback ); + shell->set_ContactCallback( 0 ); + shell->set_CallbackData( smart_cast(shell) ); + dMass m; + dMassSetSphere(&m,1,actor_camera_hudge_mass_size ); + dMassAdjust( &m, actor_camera_hudge_mass ); + shell->setEquelInertiaForEls( m ); + VERIFY( roote ); + roote->set_local_mass_center( Fvector().set(0,0,0) ); + VERIFY( roote->numberOfGeoms() ); + CODEGeom *root_geom = roote->geometry( 0 ); + VERIFY( root_geom ); + root_geom->set_local_form_bt( Fidentity ); + shell->DisableCollision(); + shell->Disable(); + return shell; +} + + + +const u16 cam_correction_steps_num = 100; +void update_current_entity_camera_collision( IPhysicsShellHolder* l_actor ) +{ + + if( actor_camera_shell && + actor_camera_shell->get_ElementByStoreOrder( 0 )->PhysicsRefObject() + != + l_actor ) + destroy_physics_shell( actor_camera_shell ); + + if( !actor_camera_shell ) + actor_camera_shell = create_camera_shell( l_actor ); +} + +void get_camera_box( Fvector &box_size, Fmatrix &xform, const CCameraBase & camera, float _viewport_near) +{ + get_viewport_geom ( box_size, xform, camera, _viewport_near ); + box_size.add(Fvector().set(camera_collision_sckin_depth,camera_collision_sckin_depth,camera_collision_sckin_depth)); +} +void get_old_camera_box( Fvector &old_box_size, Fmatrix &old_form, const CPhysicsElement *roote, const CBoxGeom* box ) +{ + roote->GetGlobalTransformDynamic( &old_form ); + box->get_size( old_box_size ); +} + +void set_camera_collision( const Fvector &box_size, const Fmatrix &xform, CPhysicsElement *roote, CBoxGeom* box ) +{ + Fvector bs = box_size; + bs.z=box_size.z*2.f; + bs.y=box_size.y*1.5f; + + box->set_size( bs ); + Fmatrix m = Fidentity; + m.c.z-= box_size.z; + m.c.y-= box_size.y*0.5f; + box->set_local_form_bt( m ); + //CBoxGeom* character_collision_geom = smart_cast( roote->geometry( 1 ) ); + CCylinderGeom* character_collision_geom = smart_cast( roote->geometry( 1 ) ); + VERIFY( character_collision_geom ); + const Fvector character_collision_box_size = + Fvector().add( box_size, + Fvector().set( camera_collision_character_skin_depth, + camera_collision_character_skin_depth, + camera_collision_character_skin_depth + ) + ); + //character_collision_geom->set_size( character_collision_box_size ); + character_collision_geom->set_radius( character_collision_box_size.x ); + VERIFY( _valid(xform) ); + Fmatrix character_collision_geom_local_xform( Fmatrix().invert(xform) ); + Fvector shift_fv = Fvector().mul( xform.k, camera_collision_character_shift_z ); + shift_fv.y = 0; + character_collision_geom_local_xform.transform_dir( shift_fv ); + + //character_collision_geom_local_xform.c.set( 0, -0.8f, 0 ); + character_collision_geom_local_xform.c.set( + Fvector().mul( character_collision_geom_local_xform.j, -camera_collision_character_gl_shift_y ).add( + Fvector( ).set( shift_fv ) + ) + ); + //character_collision_geom_local_xform.c.y =-0.8f; + character_collision_geom->set_local_form_bt( character_collision_geom_local_xform ); + roote->SetTransform( xform, mh_clear ); +} + +void do_collide_and_move(const Fmatrix &xform, IPhysicsShellHolder* l_actor, CPhysicsShell *shell, CPhysicsElement *roote ) +{ + /////////////////////////////////////////////////////////////////// + VERIFY( ph_world ); + VERIFY( !ph_world->Processing() ); + cam_collided = false; + cam_step = false; + VERIFY( l_actor ); + //VERIFY( l_actor->character_physics_support() ); + //VERIFY( l_actor->character_physics_support()->movement() ); + //l_actor->character_physics_support()->movement()->CollisionEnable( FALSE ); + l_actor->MovementCollisionEnable( false ); + shell->EnableCollision(); + shell->CollideAll(); + + if(cam_collided) + { +#ifdef DEBUG + //debug_output().PH_DBG_Clear(); + //debug_output().DBG_OpenCashedDraw(); +#endif + cam_step = true; + for( u16 i = 0; i < cam_correction_steps_num; ++i ) + { + shell->set_LinearVel( Fvector().set(0,0,0) ); + shell->set_AngularVel( Fvector().set(0,0,0) ); + roote->setQuaternion( Fquaternion().set( xform ) ); + cam_collided = false; + shell->PureStep(); + if( !cam_collided ) + break; + } + cam_step = false; +#ifdef DEBUG + //debug_output().DBG_ClosedCashedDraw( 5000 ); +#endif + } + + shell->DisableCollision(); + //l_actor->character_physics_support()->movement()->CollisionEnable( TRUE ); + l_actor->MovementCollisionEnable( true ); + shell->Disable(); +} + +bool do_collide_not_move(const Fmatrix &xform, IPhysicsShellHolder* l_actor, CPhysicsShell *shell, CPhysicsElement *roote) +{ + /////////////////////////////////////////////////////////////////// + VERIFY( ph_world ); + VERIFY( !ph_world->Processing() ); + cam_collided = false; + cam_step = false; + VERIFY( l_actor ); + //VERIFY( l_actor->character_physics_support() ); + //VERIFY( l_actor->character_physics_support()->movement() ); + //l_actor->character_physics_support()->movement()->CollisionEnable( FALSE ); + l_actor->MovementCollisionEnable( false ); + shell->EnableCollision(); + shell->CollideAll(); + shell->DisableCollision(); + //l_actor->character_physics_support()->movement()->CollisionEnable( TRUE ); + l_actor->MovementCollisionEnable( true ); + shell->Disable(); + return cam_collided; +} + +bool test_camera_box( const Fvector &box_size, const Fmatrix &xform, IPhysicsShellHolder* l_actor ) +{ + //CPhysicsShellHolder* l_actor = smart_cast( Level().CurrentEntity() ); + VERIFY( l_actor ); + update_current_entity_camera_collision( l_actor ); + + CPhysicsShell *shell = actor_camera_shell; + VERIFY( shell ); + CPhysicsElement *roote = shell->get_ElementByStoreOrder( 0 ); + VERIFY( roote ); + CODEGeom *root_geom = roote->geometry( 0 ); + VERIFY( root_geom ); + CBoxGeom* box = smart_cast( root_geom ); + VERIFY( box ); + Fvector old_box_size; Fmatrix old_form; + get_old_camera_box( old_box_size, old_form, roote, box ); + + set_camera_collision( box_size, xform, roote, box ); + bool ret = do_collide_not_move( xform, l_actor, shell, roote ); + set_camera_collision( old_box_size, old_form, roote, box ); + + return ret; +} + +void collide_camera( CCameraBase & camera, float _viewport_near, IPhysicsShellHolder *l_actor ) +{ + //CPhysicsShellHolder* l_actor = smart_cast( Level().CurrentEntity() ); + VERIFY( l_actor ); + update_current_entity_camera_collision( l_actor ); + Fvector box_size; Fmatrix xform; + get_camera_box( box_size, xform , camera, _viewport_near ); + CPhysicsShell *shell = actor_camera_shell; + VERIFY( shell ); + CPhysicsElement *roote = shell->get_ElementByStoreOrder( 0 ); + VERIFY( roote ); + CODEGeom *root_geom = roote->geometry( 0 ); + VERIFY( root_geom ); + CBoxGeom* box = smart_cast( root_geom ); + VERIFY( box ); + Fvector old_box_size; Fmatrix old_form; + get_old_camera_box( old_box_size, old_form, roote, box ); + if( clamp_change( old_form, xform, EPS,EPS,EPS,EPS) && Fvector().sub( old_box_size, box_size ).magnitude() < EPS ) + return; + set_camera_collision( box_size, xform, roote, box ); +#ifdef DEBUG + if( dbg_draw_camera_collision ) + { + debug_output().DBG_DrawMatrix( Fmatrix().translate( xform.c ), 1 ); + shell->dbg_draw_geometry( 1, D3DCOLOR_XRGB(0, 0, 255 ) ); + } +#endif + do_collide_and_move( xform, l_actor, shell, roote ); +#ifdef DEBUG + if( dbg_draw_camera_collision ) + shell->dbg_draw_geometry( 1, D3DCOLOR_XRGB(0, 255, 0 ) ); +#endif + roote->GetGlobalPositionDynamic( &camera.vPosition ); + camera.vPosition.mad( camera.Direction(), -_viewport_near/2.f ); +} \ No newline at end of file diff --git a/xrPhysics/ActorCameraCollision.h b/xrPhysics/ActorCameraCollision.h new file mode 100644 index 00000000000..f516ca62d77 --- /dev/null +++ b/xrPhysics/ActorCameraCollision.h @@ -0,0 +1,12 @@ +#pragma once +class CPhysicsShell; +class CCameraBase; +class IPhysicsShellHolder; +extern XRPHYSICS_API CPhysicsShell* actor_camera_shell; +#ifdef DEBUG +extern XRPHYSICS_API BOOL dbg_draw_camera_collision; +extern XRPHYSICS_API float camera_collision_character_skin_depth ; +extern XRPHYSICS_API float camera_collision_character_shift_z ; +#endif +XRPHYSICS_API bool test_camera_box( const Fvector &box_size, const Fmatrix &xform, IPhysicsShellHolder* l_actor ); +XRPHYSICS_API void collide_camera( CCameraBase & camera, float _viewport_near , IPhysicsShellHolder *l_actor ); diff --git a/xrPhysics/BlockAllocator.h b/xrPhysics/BlockAllocator.h new file mode 100644 index 00000000000..442dd37019f --- /dev/null +++ b/xrPhysics/BlockAllocator.h @@ -0,0 +1,118 @@ +#ifndef BLOCK_ALLOCATOR_H +#define BLOCK_ALLOCATOR_H +template +class CBlockAllocator +{ + u32 block_count; + u32 block_position; + T* current_block; + xr_vector blocks; +public: + IC T* add() + { + if(block_position==block_size)next_block(); + ++block_position; + return ¤t_block[block_position-1]; + } + IC void empty() + { + block_count=0; + if(blocks.size()) + { + block_position=0; + current_block=blocks[0]; + } + else + { + block_position=block_size; + } + } + CBlockAllocator() + { + init(); + } + ~CBlockAllocator() + { + clear(); + } + IC void init () + { + block_position=block_size; + block_count=0; + current_block=NULL; + } + IC void clear() + { + xr_vector::iterator i=blocks.begin(),e=blocks.end(); + for(;i!=e;++i) xr_free(*i); + blocks.clear(); + init(); + } +private: +///////////////////////////////////////////////////////////////// + IC void add_block() + { + blocks.push_back(xr_alloc(block_size)); + }; + IC void next_block() + { + + if(block_count==blocks.size()) add_block(); + current_block=blocks[block_count]; + ++block_count; + block_position=0; + } +//////////////////////////////////////////////////////////////// +public: + template + IC void for_each(const _Predicate &pred) + { + if(! current_block) return; + xr_vector::iterator i = blocks.begin(); + xr_vector::iterator e = blocks.begin()+block_count; + u32 j; + for ( ; i != e; ++i) + { + for(j=0;j ().construct(pointer(position)); + } + + IC void construct_back() + { + xr_allocator_t ().construct(back_pointer()); + } +}; + + +#endif \ No newline at end of file diff --git a/xrPhysics/CalculateTriangle.h b/xrPhysics/CalculateTriangle.h new file mode 100644 index 00000000000..530d70bec15 --- /dev/null +++ b/xrPhysics/CalculateTriangle.h @@ -0,0 +1,189 @@ +#include "ExtendedGeom.h" +#include "MathUtils.h" +//#include "Level.h" +#include "Geometry.h" +#include "tri-colliderknoopc/dtricollidermath.h" +//#include "../xrengine/IGame_Level.h" +#include "ode_redefine.h" +#include "../xrcdb/xr_area.h" +//#include "phworld.h" +#pragma warning(disable:4995) +#pragma warning(disable:4267) +ICF void GetNormal(CDB::TRI*XTri,Fvector &n, const Fvector* V_array ) +{ + //VERIFY(g_pGameLevel); + //const Fvector* V_array=inl_ph_world().ObjectSpace().GetStaticVerts(); + Fvector sd1;sd1.sub(V_array[XTri->verts[1]],V_array[XTri->verts[0]]); + Fvector sd2;sd2.sub(V_array[XTri->verts[2]],V_array[XTri->verts[1]]); + n.crossproduct(sd1,sd2); +} +ICF void CalculateInitTriangle(CDB::TRI* XTri,Triangle& triangle, const Fvector* V_array ) +{ + //VERIFY(g_pGameLevel); + //const Fvector* V_array=inl_ph_world().ObjectSpace().GetStaticVerts(); + const float* VRT[3]={(dReal*)&V_array[XTri->verts[0]],(dReal*)&V_array[XTri->verts[1]],(dReal*)&V_array[XTri->verts[2]]}; + dVectorSub(triangle.side0,VRT[1],VRT[0]) ; + dVectorSub(triangle.side1,VRT[2],VRT[1]) ; + triangle.T=XTri ; + dCROSS(triangle.norm,=,triangle.side0,triangle.side1) ; + cast_fv(triangle.norm).normalize() ; + triangle.pos=dDOT(VRT[0],triangle.norm) ; +} +ICF void CalculateTriangle(CDB::TRI* XTri,const float* pos,Triangle& triangle, const Fvector* V_array) +{ + CalculateInitTriangle(XTri,triangle, V_array); + triangle.dist=dDOT(pos,triangle.norm)-triangle.pos; +} +ICF void CalculateTriangle( CDB::TRI* XTri, dGeomID g, Triangle& triangle, const Fvector* V_array ) +{ + dVector3 v ; + dMatrix3 m ; + const float *p =NULL ; + const float *r =NULL ; + VERIFY ( g ) ; + CODEGeom::get_final_tx ( g, p, r, v, m ) ; + VERIFY ( p ) ; + CalculateTriangle ( XTri, p, triangle, V_array ) ; + +} + +inline bool TriContainPoint(const dReal* v0,const dReal* v1,const dReal* v2, + const dReal* triSideAx0,const dReal* triSideAx1,const dReal* triSideAx2, + const dReal* triAx, const dReal* pos,u16 &c){ + c=0; + dVector3 cross0, cross1, cross2; + dCROSS(cross0,=,triAx,triSideAx0); + if(dDOT(cross0,pos)T; + const float* VRT[3]={(dReal*)&V_array[XTri->verts[0]],(dReal*)&V_array[XTri->verts[1]],(dReal*)&V_array[XTri->verts[2]]}; + return TriContainPoint(VRT[0],VRT[1],VRT[2],T->norm,T->side0,T->side1,pos,c); +} + +enum ETriDist +{ + tdBehind, + tdPlane, + tdSide, + tdVert +}; + +IC float DistToFragmenton(const dReal *point,const dReal* pt1, const dReal* pt2,dReal *p,dReal* to_point,u16 &c) +{ + dVector3 V={pt2[0]-pt1[0],pt2[1]-pt1[1],pt2[2]-pt1[2]}; + dVector3 L={pt1[0]-point[0],pt1[1]-point[1],pt1[2]-point[2]}; + dReal sq_mag_V=dDOT(V,V); + dReal dot_L_V=dDOT(L,V); + dReal t=-dot_L_V/sq_mag_V;//t + if(t<0.f) + { + c=1; + dVectorSet(p,pt1); + dVectorSet(to_point,L); + return dSqrt(dDOT(L,L)); + } + else if (t>1.f) + { + c=2; + dVectorSet(p,pt2); + dVectorSub(L,pt2,point); + dVectorSet(to_point,L); + return dSqrt(dDOT(L,L)); + } + c=0; + dVector3 Pc={pt1[0]+t*V[0],pt1[1]+t*V[1],pt1[2]+t*V[2]}; + dVectorSet(p,Pc); + dVector3 Dc={point[0]-Pc[0],point[1]-Pc[1],point[2]-Pc[2]}; + dVectorSet(to_point,Dc); + return dSqrt(dDOT(Dc,Dc)); +} +ICF float DistToTri(Triangle* T,const float *pos,float *dir,float* p,ETriDist &c,const Fvector *V_array) +{ + if(!TriPlaneContainPoint(T)) + { + c=tdBehind; return -1.f; + } + u16 code; + if(TriContainPoint(T,pos,code, V_array )) + { + c=tdPlane; + + cast_fv(p).mad(cast_fv(pos), cast_fv(T->norm), -T->dist); + cast_fv(dir).invert(cast_fv(T->norm)); + return T->dist; + } + CDB::TRI *XTri=T->T; + const float* VRT[3]={(dReal*)&V_array[XTri->verts[0]],(dReal*)&V_array[XTri->verts[1]],(dReal*)&V_array[XTri->verts[2]]}; + u16 cd=u16(-1); + float tdist=0.f; + + switch (code) + { + case 1: tdist=DistToFragmenton(pos,VRT[0],VRT[1],p,dir,cd);break; + case 2: tdist=DistToFragmenton(pos,VRT[1],VRT[2],p,dir,cd);break; + case 3: tdist=DistToFragmenton(pos,VRT[2],VRT[0],p,dir,cd);break; + default: NODEFAULT; + } + switch (cd) + { + case 0: + if(tdist>EPS_S) cast_fv(dir).mul(1.f/tdist); + c=tdSide; + return tdist; + case 1: + dVectorSet(p,VRT[code-1]); + break; + case 2: + dVectorSet(p,VRT[code%3]); + break; + default: NODEFAULT; + } + dVectorSub(dir,p,pos); + float sqd=dDOT(dir,dir); + if(sqd>EPS_S) + { + tdist=dSqrt(sqd); + cast_fv(dir).mul(1.f/tdist); + } + else tdist =0.f; + return tdist; + //u16 c2; + //float tdist2=DistToFragmenton(pos,VRT[0],VRT[1],p,dir,c); + //u16 c3; + //float tdist3=DistToFragmenton(pos,VRT[0],VRT[1],p,dir,c); + //u16 cc;float tdist; + //MIN_OF(tdist1,cc=c1;tdist=tdist1,tdist2,cc=c2;tdist=tdist2,tdist3,cc=c3;tdist=tdist3); + + //return _min(_min(DistToFragmenton(pos))) +} +#pragma warning(default:4995) +#pragma warning(default:4267) \ No newline at end of file diff --git a/xrPhysics/CycleConstStorage.h b/xrPhysics/CycleConstStorage.h new file mode 100644 index 00000000000..95489ad78c9 --- /dev/null +++ b/xrPhysics/CycleConstStorage.h @@ -0,0 +1,33 @@ +#ifndef CYCLE_CONST_STORAGE_H +#define CYCLE_CONST_STORAGE_H + +template +class CCycleConstStorage +{ + T array[size]; + int first; + IC int position( int i ) const { return (first+i)%size; } +public: + IC CCycleConstStorage() + { + first=0; + } + IC void fill_in(const T& val) + { + std::fill(array,array+size,val); + } + IC void push_back(T& val) + { + array[first]=val; + first =position( 1 ); + } + IC T& operator [] (int i) + { + return array[ position( i ) ]; + } + IC const T& operator [] (int i) const + { + return array[ position( i ) ]; + } +}; +#endif \ No newline at end of file diff --git a/xrPhysics/DamageSource.h b/xrPhysics/DamageSource.h new file mode 100644 index 00000000000..41cbbfdac00 --- /dev/null +++ b/xrPhysics/DamageSource.h @@ -0,0 +1,11 @@ +#pragma once + + +class IDamageSource +{ +public: + virtual ~IDamageSource () {} ; + virtual void SetInitiator (u16 id) =0 ; + virtual u16 Initiator () =0 ; + virtual IDamageSource *cast_IDamageSource () =0 ;//{return this ;} +}; \ No newline at end of file diff --git a/xrPhysics/DisablingParams.cpp b/xrPhysics/DisablingParams.cpp new file mode 100644 index 00000000000..ecda96ffe6d --- /dev/null +++ b/xrPhysics/DisablingParams.cpp @@ -0,0 +1,44 @@ +#include "stdafx.h" +#include "DisablingParams.h" + + + +SAllDDWParams worldDisablingParams = + { + //object + { + {0.001f , 0.1f } , //translational vel , accel + {0.005f , 0.05f } , //rotational vel , accel + 64 //level2 frames 2^ + } , + 1.5f //reanable factor + }; + + + +void SOneDDOParams::Mul(float v) +{ + velocity *= v ; + acceleration *= v ; +} + +void SAllDDOParams::Reset() +{ + *this=worldDisablingParams.objects_params; +} + +void SAllDDOParams::Load(CInifile* ini) +{ + Reset() ; + if(!ini) return ; + if(!ini->section_exist("disable")) return ; + if(ini->line_exist("disable","linear_factor")) translational .Mul(ini->r_float("disable","linear_factor")) ; + if(ini->line_exist("disable","angular_factor")) rotational .Mul(ini->r_float("disable","angular_factor")) ; + if(ini->line_exist("disable","change_count")) + { + int ch_cnt=ini->r_s8("disable","change_count"); + if(ch_cnt<0)L2frames=L2frames >> u16(-ch_cnt); + else L2frames=L2frames << u16(ch_cnt); + VERIFY(ch_cnt<4 && L2frames!=0 ); + } +} \ No newline at end of file diff --git a/xrPhysics/DisablingParams.h b/xrPhysics/DisablingParams.h new file mode 100644 index 00000000000..9cfb32fbf0f --- /dev/null +++ b/xrPhysics/DisablingParams.h @@ -0,0 +1,29 @@ +#ifndef DISABLING_PARAMS_H +#define DISABLING_PARAMS_H +struct SOneDDOParams +{ + void Mul (float v) ; + float velocity ; + float acceleration ; +}; + +struct XRPHYSICS_API SAllDDOParams +{ + void Reset () ; + void Load (CInifile* ini) ; + SOneDDOParams translational ; + SOneDDOParams rotational ; + u16 L2frames ; +}; + +struct SAllDDWParams +{ + SAllDDOParams objects_params ; + float reanable_factor ; +}; + + + +extern SAllDDWParams worldDisablingParams ; + +#endif \ No newline at end of file diff --git a/xrPhysics/ElevatorState.cpp b/xrPhysics/ElevatorState.cpp new file mode 100644 index 00000000000..1bf10d4ba6b --- /dev/null +++ b/xrPhysics/ElevatorState.cpp @@ -0,0 +1,410 @@ +#include "stdafx.h" +#include "ElevatorState.h" +#include "IClimableObject.h" +#include "PHCharacter.h" +#include "MathUtils.h" +#include "PHWorld.h" +#include "../xrengine/device.h" +#ifdef DEBUG +#include "../xrEngine/Statgraph.h" +#include "debug_output.h" +#endif +static const float getting_on_dist =0.3f; +static const float getting_out_dist =0.4f; +static const float start_climbing_dist =0.f; +static const float stop_climbing_dist =0.1f; +static const float out_dist =1.5f; + +static const float look_angle_cosine =0.9238795f;//22.5 +static const float lookup_angle_sine =0.34202014f;//20 +extern class CPHWorld *ph_world; +CElevatorState::CElevatorState() +{ + m_state=clbNoLadder; + m_ladder=NULL; + m_character=NULL; +} + +float CElevatorState::ClimbDirection() +{ + VERIFY(m_ladder&&m_character); + Fvector d; + m_ladder->DToPlain(m_character,d); + float dir=m_character->ControlAccel().dotproduct(d); + if(dir>EPS_L)dir*=(m_character->CamDir().y+lookup_angle_sine); + return dir; +} + +void CElevatorState::PhTune(float step) +{ + VERIFY(m_character&&m_character->b_exist&&m_character->is_active()); + if(!m_ladder) return; + switch(m_state) + { + case clbNone :UpdateStNone() ; break; + case clbNearUp :UpdateStNearUp() ; break; + case clbNearDown :UpdateStNearDown() ; break; + case clbClimbingUp :UpdateStClimbingUp() ; break; + case clbClimbingDown :UpdateStClimbingDown() ; break; + case clbDepart :UpdateDepart() ; break; + case clbNoLadder :m_ladder = NULL ; break; + } + +} + +void CElevatorState::PhDataUpdate(float step) +{ + +} + +void CElevatorState::InitContact(dContact* c,bool &do_collide,u16 ,u16 ) +{ + +} + +void CElevatorState::SetElevator(IClimableObject* climable) +{ + Fvector d; + float dist=climable->DDToAxis(m_character,d); + if(m_ladder==climable||dist>out_dist) return; + if(m_ladder && m_ladder->DDToAxis(m_character,d)get_body(),0); + + if((new_state!=clbClimbingUp&&new_state!=clbClimbingDown) && + (m_state==clbClimbingUp||m_state==clbClimbingDown) + )dBodySetGravityMode(m_character->get_body(),1); + + //if(new_state==clbDepart) InitDepart(); + NewState(); + m_state=new_state; +} +void CElevatorState::UpdateStNone() +{ + VERIFY(m_ladder&&m_character); + Fvector d;m_ladder->DToPlain(m_character,d); + if( m_ladder->BeforeLadder(m_character)&& + m_ladder->InTouch(m_character)&& + dXZDotNormalized( d, m_character->CamDir() ) > look_angle_cosine ) + { + + if(ClimbDirection()>0.f) + { + SwitchState(clbClimbingUp); + } + else + { + SwitchState(clbClimbingDown); + } + } + else + { + Fvector temp; + float d_to_lower=m_ladder->DDLowerP(m_character,temp),d_to_upper=m_ladder->DDUpperP(m_character,temp); + if(d_to_lowerFootRadius() > d_to_lower) + SwitchState(clbNearDown); + } + else + { + if(getting_on_dist+m_character->FootRadius() > d_to_upper) + SwitchState(clbNearUp); + } + } +} + +void CElevatorState::UpdateStNearUp() +{ + VERIFY(m_ladder&&m_character); + Fvector d; + + if( m_ladder->InTouch(m_character) && + m_character->CamDir().y<-M_PI/20.f && + //d.dotproduct(m_character->ControlAccel())<0.f&& + //ClimbDirection()<0.f&& + m_ladder->DDToPlain(m_character,d)>m_character->FootRadius()/3.f&& + m_ladder->BeforeLadder(m_character,0.1f) + ) + SwitchState(clbClimbingDown); + float dist=m_ladder->DDUpperP(m_character,d); + if(dist-m_character->FootRadius()>out_dist)SwitchState((clbNoLadder)); +} + +void CElevatorState::UpdateStNearDown() +{ + VERIFY(m_ladder&&m_character); + Fvector d; + float dist=m_ladder->DDLowerP(m_character,d); + if( m_ladder->InTouch(m_character)&& + dXZDotNormalized(d,m_character->CamDir())>look_angle_cosine&& + d.dotproduct(m_character->ControlAccel())>0.f&& + ClimbDirection()>0.f&& + m_ladder->BeforeLadder(m_character) + )SwitchState(clbClimbingUp); + if(dist-m_character->FootRadius()>out_dist)SwitchState((clbNoLadder)); +} + + +void CElevatorState::UpdateStClimbingDown() +{ + VERIFY(m_ladder&&m_character); + Fvector d; + + if(ClimbDirection()>0.f&&m_ladder->BeforeLadder(m_character)) + SwitchState(clbClimbingUp); + float to_ax=m_ladder->DDToAxis(m_character,d); + Fvector ca;ca.set(m_character->ControlAccel()); + float control_a=to_mag_and_dir(ca); + if(!fis_zero(to_ax)&&!fis_zero(control_a)&&abs(-ca.dotproduct(Fvector(m_ladder->Norm()).normalize()))AxDistToLowerP(m_character)-m_character->FootRadius()AxDistToUpperP(m_character)<-m_character->FootRadius())SwitchState(clbNoLadder); + + Fvector vel; + m_character->GetVelocity(vel); + if(vel.y>EPS_S) + { + m_character->ApplyForce(0.f,-m_character->Mass()*ph_world->Gravity(),0.f); + } + //if(to_ax-m_character->FootRadius()>out_dist) + // SwitchState((clbNone)); + //if(fis_zero(control_a)) + // m_character->ApplyForce(d,m_character->Mass()); +} + +void CElevatorState::UpdateStClimbingUp() +{ + VERIFY(m_ladder&&m_character); + Fvector d; + + if(ClimbDirection()<0.f&&m_ladder->BeforeLadder(m_character)) + SwitchState(clbClimbingDown); + float to_ax=m_ladder->DDToAxis(m_character,d); + Fvector ca;ca.set(m_character->ControlAccel()); + float control_a=to_mag_and_dir(ca); + if(!fis_zero(to_ax)&&!fis_zero(control_a)&&abs(-ca.dotproduct(Fvector(m_ladder->Norm()).normalize()))AxDistToUpperP(m_character)+m_character->FootRadius()FootRadius()>out_dist) + // SwitchState((clbNone)); + //if(fis_zero(control_a)) + // m_character->ApplyForce(d,m_character->Mass()); +} +void CElevatorState::UpdateClimbingCommon(const Fvector &d_to_ax,float to_ax,const Fvector& control_accel,float ca) +{ + VERIFY(m_ladder&&m_character); + if(to_ax-m_character->FootRadius()>out_dist) + SwitchState((clbNoLadder)); + if(fis_zero(ca)&&d_to_ax.dotproduct(m_ladder->Norm())<0.f) + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgLadder)) + { +//. Msg("force applied"); + } +#endif + m_character->ApplyForce(d_to_ax,m_character->Mass()*ph_world->Gravity());// + + } +} +bool CElevatorState::GetControlDir(Fvector& dir) +{ + bool ret=true; + VERIFY(m_ladder&&m_character); + Fvector d; + float dist; + switch(m_state) + { + case clbDepart : + case clbNoLadder : + case clbNone : break; + case clbNearUp : dist= m_ladder->DDUpperP(m_character,d); + if( dXZDotNormalized(d,m_character->CamDir())>look_angle_cosine&& + !fis_zero(dist,EPS_L)&&m_character->ControlAccel().dotproduct(d)>0.f) dir.set(d); + break; + case clbNearDown : + dist=m_ladder->DDLowerP(m_character,d); + if(dXZDotNormalized(d,m_character->CamDir())>look_angle_cosine&& + !fis_zero(dist,EPS_L)&&m_character->ControlAccel().dotproduct(d)>0.f) dir.set(d); + break; + case clbClimbingUp : m_ladder->DDAxis(dir); + m_ladder->DDToAxis(m_character,d); + dir.add(d);dir.normalize(); + break; + case clbClimbingDown : m_ladder->DDToAxis(m_character,d); + if(m_ladder->BeforeLadder(m_character)||d.dotproduct(dir)>0.f) + { + m_ladder->DDAxis(dir); + dir.invert(); + dir.add(d);dir.normalize(); + } + else + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgLadder)) + { + Msg("no c dir"); + } +#endif + ret=false; + } + break; + } + return ret; +} +static const float depart_dist=2.f; +static const u32 depart_time=3000; +void CElevatorState::UpdateDepart() +{ + VERIFY(m_ladder&&m_character); + Fvector temp; + float d_to_lower=m_ladder->DDLowerP(m_character,temp),d_to_upper=m_ladder->DDUpperP(m_character,temp); + if(d_to_lowerFootRadius() > d_to_lower) + SwitchState(clbNearDown); + } + else + { + if(getting_on_dist+m_character->FootRadius() > d_to_upper) + SwitchState(clbNearUp); + } + + //Fvector p;m_character->GetFootCenter(p); + //p.sub(m_start_position); + //if( p.magnitude()>depart_dist || + // Device.dwTimeGlobal-m_start_time>depart_time) + SwitchState(clbNoLadder); + +} + +void CElevatorState::NewState() +{ + VERIFY(m_character); + m_start_time=inl_ph_world().Device().dwTimeGlobal; + m_character->GetFootCenter(m_start_position); +} + +void CElevatorState::Depart() +{ + VERIFY(m_character); + if(m_ladder && ClimbingState())SwitchState(clbDepart); +} +void CElevatorState::GetLeaderNormal(Fvector& dir) +{ + if(!m_ladder) return; + VERIFY(m_ladder&&m_character); + m_ladder->DDNorm(dir); + //Fvector d; + //m_ladder->DToAxis(m_character,d); + //if(dir.dotproduct(d)>0.f) dir.invert(); +} + +void CElevatorState::GetJumpDir(const Fvector& accel,Fvector& dir) +{ + VERIFY(m_ladder&&m_character); + Fvector norm,side; + m_ladder->DDNorm(norm); + m_ladder->DDSide(side); + Fvector ac;ac.set(accel).normalize_safe(); + float side_component=ac.dotproduct(side); + dir.set(norm); + if(_abs(side_component)>M_SQRT1_2) + { + if(side_component<0.f)side.invert(); + dir.add(side); + dir.normalize_safe(); + } +} + +void CElevatorState::Deactivate() +{ + SwitchState(clbNoLadder); + m_state=clbNoLadder; + m_ladder=NULL; + m_character=NULL; +} + + + +CElevatorState::SEnertionState CElevatorState:: m_etable[clbNoState][clbNoState]= +{ +// clbNone clbNearUp clbNearDown clbClimbingUp clbClimbingDown clbDepart clbNoLadder +/*clbNone */ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, //clbNone +/*clbNearUp */ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, //clbNearUp +/*clbNearDown */ {{0,0}, {0.0f,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, //clbNearDown +/*clbClimbingUp */ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, //clbClimbingUp +/*clbClimbingDown */ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, //clbClimbingDown +/*clbDepart */ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {depart_dist,depart_time}}, //clbDepart +/*clbNoLadder */ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} //clbNoLadder +}; + +bool CElevatorState::StateSwitchInertion(Estate new_state) +{ + Fvector p;m_character->GetFootCenter(p); + p.sub(m_start_position); + if(m_etable[m_state][new_state].distMaterial(); + return true; +} + +void CElevatorState::NetRelcase ( IPhysicsShellHolder* O ) +{ + if(!O || !m_ladder || O != m_ladder->cast_IPhysicsShellHolder() ) + return; + + m_state=clbNoLadder; + m_ladder=NULL; + +} \ No newline at end of file diff --git a/xrPhysics/ElevatorState.h b/xrPhysics/ElevatorState.h new file mode 100644 index 00000000000..23fa36a69fa --- /dev/null +++ b/xrPhysics/ElevatorState.h @@ -0,0 +1,67 @@ +#ifndef ELEVATOR_STAETE +#define ELEVATOR_STAETE + +#include "ielevatorstate.h" +class CPHCharacter; +struct dContact; +struct SGameMtl; +class IClimableObject; + +class CElevatorState : + public IElevatorState +{ +public: + +private: + Estate m_state; + + struct SEnertionState { + float dist; + u32 time; + }; + +static SEnertionState m_etable[CElevatorState::clbNoState][CElevatorState::clbNoState]; + +IClimableObject *m_ladder; +CPHCharacter *m_character; +Fvector m_start_position;//for depart state +u32 m_start_time; +public: + CElevatorState (); + void PhTune (float step) ; + void SetCharacter (CPHCharacter *character); + void SetElevator (IClimableObject* climable); + void EvaluateState (); + bool GetControlDir (Fvector& dir); + void GetJumpDir (const Fvector& accel,Fvector& dir); + void GetLeaderNormal (Fvector& dir); + bool Active (){return m_ladder && m_state!=clbNone;} + bool NearDown (){return m_state == clbNearDown;} + bool NearState (){return m_state==clbNearUp || m_state == clbNearDown;} + bool ClimbingState ()const{return m_state==clbClimbingUp || m_state == clbClimbingDown;} + void Depart (); + float ClimbDirection (); + void Deactivate (); + bool UpdateMaterial ( u16 &materil_idx ); +IC Estate State (){return m_state;} +private: + void NewState (); + + void PhDataUpdate (float step) ; + void InitContact (dContact* c,bool &do_collide,u16 /*material_idx_1*/,u16 /*material_2*/) ; + void SwitchState (Estate new_state); + bool StateSwitchInertion (Estate new_state); + void UpdateStNone (); + void UpdateStNearUp (); + void UpdateStNearDown (); + void UpdateStClimbingUp (); + void UpdateStClimbingDown (); + void UpdateClimbingCommon (const Fvector &d_to_ax,float to_ax,const Fvector& control_accel,float ca); + void UpdateDepart (); +public: + void NetRelcase ( IPhysicsShellHolder* O ); + + +}; + +#endif \ No newline at end of file diff --git a/xrPhysics/ExtendedGeom.cpp b/xrPhysics/ExtendedGeom.cpp new file mode 100644 index 00000000000..000a3736899 --- /dev/null +++ b/xrPhysics/ExtendedGeom.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "extendedgeom.h" +#include "dcylinder/dcylinder.h" +bool IsCyliderContact(const dContact& c) +{ + int geomClass = -1; + if(dGeomGetBody(c.geom.g1)) + { + geomClass =dGeomGetClass(retrieveGeom(c.geom.g1)); + } + else + { + geomClass=dGeomGetClass(retrieveGeom(c.geom.g2)); + } + + //is_cyl= (geomClass==dCylinderClassUser); + return (geomClass==dCylinderClassUser); +} + +//dxGeomUserData* PHGeomGetUserData( dxGeom* geom ) +//{ +// return dGeomGetUserData(geom); +//} + +dxGeomUserData* PHRetrieveGeomUserData(dGeomID geom) +{ + return retrieveGeomUserData( geom ); +} + + void get_user_data( dxGeomUserData* &gd1, dxGeomUserData* &gd2, bool bo1, const dContactGeom &geom ) +{ + + if( bo1 ) + { + gd1 =retrieveGeomUserData( geom.g1 ); + gd2 =retrieveGeomUserData( geom.g2 ); + } + else + { + gd2 =retrieveGeomUserData( geom.g1 ); + gd1 =retrieveGeomUserData( geom.g2 ); + } +} + +// bool dGeomUserDataHasCallback(dxGeom* geom,ObjectContactCallbackFun *obj_callback) +//{ +// geom=retrieveGeom(geom); +// if(geom&&dGeomGetUserData(geom)&&(dGeomGetUserData(geom))->object_callbacks) +// return (dGeomGetUserData(geom))->object_callbacks->HasCallback(obj_callback); +// else return false; +//} \ No newline at end of file diff --git a/xrPhysics/ExtendedGeom.h b/xrPhysics/ExtendedGeom.h new file mode 100644 index 00000000000..569e440c615 --- /dev/null +++ b/xrPhysics/ExtendedGeom.h @@ -0,0 +1,300 @@ +#ifndef EXTENDED_GEOM +#define EXTENDED_GEOM + +#ifndef dSINGLE + #define dSINGLE +#endif +#include "PHObject.h" +//#include "ode_include.h" +#include "../3rd party/ode/include/ode/common.h" +#include "../3rd party/ode/include/ode/collision.h" +#include "physicscommon.h" +#include "MathUtils.h" +#ifdef DEBUG +#include "debug_output.h" +#endif + + +#ifdef DEBUG +//extern u32 dbg_total_saved_tries ; +#endif +class IPhysicsShellHolder; + + + + + +class CObjectContactCallback +{ + + CObjectContactCallback *next ; + ObjectContactCallbackFun *callback ; + public: + CObjectContactCallback (ObjectContactCallbackFun *c) + :callback(c) + { + next=NULL; VERIFY(c); + } + ~CObjectContactCallback() + { + xr_delete(next); + } + void Add(ObjectContactCallbackFun *c) + { + VERIFY(c); + VERIFY(callback!=c); + + if(next) + { + next->Add(c); + } + else + { + next=xr_new(c); + } + } + bool HasCallback(ObjectContactCallbackFun *c) + { + for(CObjectContactCallback*i=this;i;i=i->next) + { + VERIFY(i->callback); + if(c==i->callback) return true; + } + return false; + } + +static void RemoveCallback(CObjectContactCallback* &callbacks,ObjectContactCallbackFun *c) + { + if(!callbacks) return; + VERIFY(c); + VERIFY(callbacks->callback); + + if(c==callbacks->callback) + { + CObjectContactCallback *del=callbacks; + callbacks=callbacks->next; + del->next=NULL; + xr_delete(del); + VERIFY(!callbacks||!callbacks->HasCallback(c)); + } else{ + for(CObjectContactCallback *i=callbacks->next,*p=callbacks;i;) + { + + VERIFY(p->callback); + VERIFY(i->callback); + VERIFY(i); + VERIFY(p); + if(c==i->callback) + { + CObjectContactCallback *del=i; + p->next=i->next;del->next=NULL;xr_delete(del); + VERIFY(!callbacks->HasCallback(c)); + break; + } + i=i->next; + p=p->next; + VERIFY(p->next==i); + } + } + } + + void Call(bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2) + { + for(CObjectContactCallback*i=this;i;i=i->next) + { + VERIFY(i->callback); + i->callback(do_colide,bo1,c,material_1,material_2); + } + } +}; + +class CGameObject; +struct dxGeomUserData +{ + dVector3 last_pos ; + bool pushing_neg,pushing_b_neg,b_static_colide ; + CDB::TRI *neg_tri,*b_neg_tri ; + CPHObject *ph_object ; + IPhysicsShellHolder *ph_ref_object ; + u16 material ; + u16 tri_material ; + ContactCallbackFun *callback ; + void *callback_data ; +// ObjectContactCallbackFun *object_callback ; + CObjectContactCallback *object_callbacks ; + u16 element_position ; + u16 bone_id ; + xr_vector cashed_tries ; + Fvector last_aabb_size ; + Fvector last_aabb_pos ; + +// struct ContactsParameters +// { +// dReal damping; +// dReal spring; +// dReal bonce; +// dReal bonce_vel; +// dReal mu; +// unsigned int maxc; +// }; +}; + +IC dxGeomUserData* dGeomGetUserData(dxGeom* geom) +{ + return (dxGeomUserData*) dGeomGetData(geom); +} + +//XRPHYSICS_API dxGeomUserData* PHGeomGetUserData( dxGeom* geom ); + + +IC dGeomID retrieveGeom(dGeomID geom) +{ + if(dGeomGetClass(geom)==dGeomTransformClass) + return dGeomTransformGetGeom(geom); + else + return geom; +} +XRPHYSICS_API dxGeomUserData* PHRetrieveGeomUserData(dGeomID geom); +IC dxGeomUserData* retrieveGeomUserData(dGeomID geom) +{ + return dGeomGetUserData(retrieveGeom(geom)); + //if(dGeomGetClass(geom)==dGeomTransformClass) + // return dGeomGetUserData(dGeomTransformGetGeom(geom)); + //else + // return dGeomGetUserData(geom); +} + +XRPHYSICS_API void get_user_data( dxGeomUserData* &gd1, dxGeomUserData* &gd2, bool bo1, const dContactGeom &geom ); + + +IC IPhysicsShellHolder* retrieveRefObject(dGeomID geom) +{ + dxGeomUserData* ud=dGeomGetUserData(retrieveGeom(geom)); + if(ud)return ud->ph_ref_object; + else return NULL; +} +IC void dGeomCreateUserData(dxGeom* geom) +{ + if(!geom) return; + dGeomSetData(geom,xr_new()); + (dGeomGetUserData(geom))->pushing_neg=false; + (dGeomGetUserData(geom))->pushing_b_neg=false; + (dGeomGetUserData(geom))->b_static_colide=true; + + (dGeomGetUserData(geom))->last_pos[0]=-dInfinity; + (dGeomGetUserData(geom))->last_pos[1]=-dInfinity; + (dGeomGetUserData(geom))->last_pos[2]=-dInfinity; + + + (dGeomGetUserData(geom))->ph_object=NULL; + (dGeomGetUserData(geom))->material=0; + (dGeomGetUserData(geom))->tri_material=0; + (dGeomGetUserData(geom))->callback=NULL; + (dGeomGetUserData(geom))->object_callbacks=NULL; + (dGeomGetUserData(geom))->ph_ref_object=NULL; + (dGeomGetUserData(geom))->element_position=u16(-1); + (dGeomGetUserData(geom))->bone_id=u16(-1); + (dGeomGetUserData(geom))->callback_data=NULL; + + (dGeomGetUserData(geom))->last_aabb_size.set(0,0,0); + //((dxGeomUserData*)dGeomGetData(geom))->ContactsParameters::mu=1.f; + //((dxGeomUserData*)dGeomGetData(geom))->ContactsParameters::damping=1.f; + //((dxGeomUserData*)dGeomGetData(geom))->ContactsParameters::spring=1.f; + //((dxGeomUserData*)dGeomGetData(geom))->ContactsParameters::bonce=0.f; + //((dxGeomUserData*)dGeomGetData(geom))->ContactsParameters::bonce_vel=0.f; +} + + + +IC void dGeomDestroyUserData(dxGeom* geom) +{ + if(!geom) return ; + dxGeomUserData* P = dGeomGetUserData(geom) ; + if(P) + { +#ifdef DEBUG + debug_output().dbg_total_saved_tries()-=P->cashed_tries.size() ; +#endif + P->cashed_tries .clear() ; + xr_delete (P->object_callbacks) ; + } + xr_delete (P) ; + dGeomSetData (geom,0) ; +} + +IC void dGeomUserDataSetCallbackData(dxGeom* geom,void *cd) +{ + (dGeomGetUserData(geom))->callback_data=cd; +} +IC void dGeomUserDataSetPhObject(dxGeom* geom,CPHObject* phObject) +{ + (dGeomGetUserData(geom))->ph_object=phObject; +} + +IC void dGeomUserDataSetPhysicsRefObject(dxGeom* geom,IPhysicsShellHolder* phRefObject) +{ + (dGeomGetUserData(geom))->ph_ref_object=phRefObject; +} + +IC void dGeomUserDataSetContactCallback(dxGeom* geom,ContactCallbackFun* callback) +{ + (dGeomGetUserData(geom))->callback=callback; +} + +IC void dGeomUserDataSetObjectContactCallback(dxGeom* geom,ObjectContactCallbackFun *obj_callback) +{ + xr_delete((dGeomGetUserData(geom))->object_callbacks); + if(obj_callback)(dGeomGetUserData(geom))->object_callbacks=xr_new(obj_callback); +} + +IC void dGeomUserDataAddObjectContactCallback(dxGeom* geom,ObjectContactCallbackFun *obj_callback) +{ + if((dGeomGetUserData(geom))->object_callbacks) + { + (dGeomGetUserData(geom))->object_callbacks->Add(obj_callback); + } + else dGeomUserDataSetObjectContactCallback(geom,obj_callback); +} + +IC void dGeomUserDataRemoveObjectContactCallback(dxGeom* geom,ObjectContactCallbackFun *obj_callback) +{ + CObjectContactCallback::RemoveCallback((dGeomGetUserData(geom))->object_callbacks,(obj_callback)); +} + +//XRPHYSICS_API bool dGeomUserDataHasCallback(dxGeom* geom,ObjectContactCallbackFun *obj_callback); + +IC void dGeomUserDataSetElementPosition(dxGeom* geom,u16 e_pos) +{ + (dGeomGetUserData(geom))->element_position=e_pos; +} +IC void dGeomUserDataSetBoneId(dxGeom* geom,u16 bone_id) +{ + (dGeomGetUserData(geom))->bone_id=bone_id; +} +IC void dGeomUserDataResetLastPos(dxGeom* geom) +{ + (dGeomGetUserData(geom))->last_pos[0]=-dInfinity; + (dGeomGetUserData(geom))->last_pos[1]=-dInfinity; + (dGeomGetUserData(geom))->last_pos[2]=-dInfinity; + (dGeomGetUserData(geom))->pushing_neg=false; + (dGeomGetUserData(geom))->pushing_b_neg=false; + (dGeomGetUserData(geom))->b_static_colide=true; + + (dGeomGetUserData(geom))->last_aabb_size.set(0,0,0); + +} +IC void dGeomUserDataClearCashedTries(dxGeom* geom) +{ + dxGeomUserData* P = dGeomGetUserData(geom); + +#ifdef DEBUG + debug_output().dbg_total_saved_tries()-=P->cashed_tries.size(); +#endif + P->cashed_tries.clear(); + P->last_aabb_size.set(0.f,0.f,0.f); +} +#ifdef DEBUG +XRPHYSICS_API bool IsCyliderContact(const dContact& c); +#endif + +#endif \ No newline at end of file diff --git a/xrPhysics/Geometry.cpp b/xrPhysics/Geometry.cpp new file mode 100644 index 00000000000..d6dfeb3947b --- /dev/null +++ b/xrPhysics/Geometry.cpp @@ -0,0 +1,807 @@ +#include "stdafx.h" +#include "Geometry.h" +#include "PHDynamicData.h" +#include "ExtendedGeom.h" +#include "dcylinder//dCylinder.h" + +#include "../xrEngine/bone.h" + +//global +#ifdef DEBUG +# include "debug_output.h" +#endif // #ifdef DEBUG + +static void computeFinalTx(dGeomID geom_transform,dReal* final_pos,dReal* final_R) +{ + R_ASSERT2(dGeomGetClass(geom_transform)==dGeomTransformClass,"is not a geom transform"); + dGeomID obj=dGeomTransformGetGeom(geom_transform); + const dReal *R =dGeomGetRotation(geom_transform); + const dReal *pos=dGeomGetPosition(geom_transform); + dMULTIPLY0_331 (final_pos,R,dGeomGetPosition(obj)); + final_pos[0] += pos[0]; + final_pos[1] += pos[1]; + final_pos[2] += pos[2]; + dMULTIPLY0_333 (final_R,R,dGeomGetRotation(obj)); +} + +void GetBoxExtensions(dGeomID box,const dReal* axis, + const dReal *pos, const dReal *rot, + float center_prg,dReal* lo_ext,dReal* hi_ext) +{ + R_ASSERT2(dGeomGetClass(box)==dBoxClass,"is not a box"); + dVector3 length; + dGeomBoxGetLengths(box,length); + dReal dif=dDOT(pos,axis)-center_prg; + dReal ful_ext=dFabs(dDOT14(axis,rot+0))*length[0] + +dFabs(dDOT14(axis,rot+1))*length[1] + +dFabs(dDOT14(axis,rot+2))*length[2]; + ful_ext/=2.f; + *lo_ext=-ful_ext+dif; + *hi_ext=ful_ext+dif; +} + +void GetCylinderExtensions(dGeomID cyl,const dReal* axis, + const dReal *pos, const dReal *rot, + float center_prg,dReal* lo_ext,dReal* hi_ext) +{ + R_ASSERT2(dGeomGetClass(cyl)==dCylinderClassUser,"is not a cylinder"); + dReal radius,length; + dGeomCylinderGetParams(cyl,&radius,&length); + dReal dif=dDOT(pos,axis)-center_prg; + dReal _cos=dFabs(dDOT14(axis,rot+1)); + dReal cos1=dDOT14(axis,rot+0); + dReal cos3=dDOT14(axis,rot+2); + dReal _sin=_sqrt(cos1*cos1+cos3*cos3); + length/=2.f; + dReal ful_ext=_cos*length+_sin*radius; + *lo_ext=-ful_ext+dif; + *hi_ext=ful_ext+dif; +} + +void GetSphereExtensions(dGeomID sphere,const dReal* axis, + const dReal *pos, + float center_prg,dReal* lo_ext,dReal* hi_ext) +{ + R_ASSERT2(dGeomGetClass(sphere)==dSphereClass,"is not a sphere"); + dReal radius=dGeomSphereGetRadius(sphere); + dReal dif=dDOT(pos,axis)-center_prg; + *lo_ext=-radius+dif; + *hi_ext=radius+dif; +} + +void TransformedGeometryExtensionLocalParams(dGeomID geom_transform,const dReal* axis,float center_prg,dReal* local_axis,dReal& local_center_prg) +{ + R_ASSERT2(dGeomGetClass(geom_transform)==dGeomTransformClass,"is not a geom transform"); + const dReal* rot=dGeomGetRotation(geom_transform); + const dReal* pos=dGeomGetPosition(geom_transform); + dVector3 local_pos; + + dMULTIPLY1_331(local_axis,rot,axis); + dMULTIPLY1_331(local_pos,rot,pos); + local_center_prg=center_prg-dDOT(local_pos,local_axis); +} + + + +CODEGeom::CODEGeom() +{ + m_geom_transform=NULL; + m_bone_id=u16(-1); +} + +CODEGeom::~CODEGeom() +{ + if(m_geom_transform) destroy(); +} + +void CODEGeom::get_mass(dMass& m,const Fvector& ref_point, float density) +{ + get_mass(m); + dMassAdjust(&m,density*volume()); + Fvector l; + l.sub(local_center(),ref_point); + dMassTranslate(&m,l.x,l.y,l.z); +} + +void CODEGeom::get_mass(dMass& m,const Fvector& ref_point) +{ + get_mass(m); + Fvector l; + l.sub(local_center(),ref_point); + dMassTranslate(&m,l.x,l.y,l.z); +} + +void CODEGeom::add_self_mass(dMass& m,const Fvector& ref_point, float density) +{ + dMass self_mass; + get_mass(self_mass,ref_point,density); + dMassAdd(&m,&self_mass); +} + +void CODEGeom::add_self_mass(dMass& m,const Fvector& ref_point) +{ + dMass self_mass; + get_mass(self_mass,ref_point); + dMassAdd(&m,&self_mass); +} + +void CODEGeom::get_local_center_bt(Fvector& center) +{ + if(! m_geom_transform) return; + if(!geom()) //geom is not transformed + { + center.set(0.f,0.f,0.f); + } + center.set(*((const Fvector*)dGeomGetPosition(geom()))); +} +void CODEGeom::get_local_form_bt(Fmatrix& form) +{ + PHDynamicData::DMXPStoFMX(dGeomGetRotation(geom()),dGeomGetPosition(geom()),form); +} +void CODEGeom::get_global_center_bt(Fvector& center) +{ + center.set(*((const Fvector*)dGeomGetPosition(m_geom_transform))); + dVector3 add; + dMULTIPLY0_331 (add,dGeomGetRotation(m_geom_transform),dGeomGetPosition(geom())); + center.x += add[0]; + center.y += add[1]; + center.z += add[2]; +} +void CODEGeom:: get_xform( Fmatrix& form ) const +{ + VERIFY ( m_geom_transform ); + const dReal *rot =NULL ; + const dReal *pos =NULL ; + dVector3 p ; + dMatrix3 r ; + get_final_tx_bt( pos, rot, p, r ) ; + + PHDynamicData::DMXPStoFMX( rot, pos, form ); +} + +bool CODEGeom:: collide_fluids () const +{ + return !m_flags.test( SBoneShape::sfNoFogCollider ); +} +void CODEGeom:: get_Box ( Fmatrix& form, Fvector& sz )const +{ + get_xform( form ); + Fvector c; + t_get_box( this, form, sz, c ); + form.c = c; +} +/* +void CODEGeom::get_global_form_bt(Fmatrix& form) +{ + dMULTIPLY0_331 ((dReal*)(&form.c),dGeomGetRotation(m_geom_transform),dGeomGetPosition(geom())); + form.c.add(*((const Fvector*)dGeomGetPosition(m_geom_transform))); + dMULTIPLY3_333 ((dReal*)(&form),dGeomGetRotation(m_geom_transform),dGeomGetRotation(geom())); + //PHDynamicData::DMXtoFMX((dReal*)(&form),form); +} +*/ +void CODEGeom::set_static_ref_form(const Fmatrix& form) +{ + dGeomSetPosition(geometry_transform(),form.c.x,form.c.y,form.c.z); + Fmatrix33 m33; + m33.set(form); + dMatrix3 R; + PHDynamicData::FMX33toDMX(m33,R); + dGeomSetRotation(geometry_transform(),R); +} +void CODEGeom:: clear_motion_history( bool set_unspecified ) +{ + dGeomUserDataResetLastPos(geom()); + if( set_unspecified ) + return; + get_global_center_bt( cast_fv ( dGeomGetUserData( geom() )->last_pos ) ); +#ifdef DEBUG + Fmatrix m; + get_xform( m ); + if( Fvector().sub( m.c, cast_fv ( dGeomGetUserData( geom() )->last_pos ) ).magnitude() > EPS ) + Msg("! WRONG THING" ); +#endif +} + +void CODEGeom::set_build_position(const Fvector& /*ref_point*/) +{ + clear_motion_history( true ); +} + +void CODEGeom::set_body(dBodyID body) +{ + if(m_geom_transform) dGeomSetBody(m_geom_transform,body); +} + +void CODEGeom::add_to_space(dSpaceID space) +{ + if(m_geom_transform) dSpaceAdd(space,m_geom_transform); +} +void CODEGeom::remove_from_space(dSpaceID space) +{ + if(m_geom_transform) dSpaceRemove(space,m_geom_transform); +} +void CODEGeom::clear_cashed_tries() +{ + if(!m_geom_transform)return; + dGeomID g=geom(); + if(g) + { + VERIFY(dGeomGetUserData(g)); + dGeomUserDataClearCashedTries(g); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataClearCashedTries(m_geom_transform); + } +} +void CODEGeom::set_material(u16 ul_material) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomGetUserData(geom())->material=ul_material; + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomGetUserData(m_geom_transform)->material=ul_material; + } +} + +void CODEGeom::set_contact_cb(ContactCallbackFun* ccb) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomUserDataSetContactCallback(geom(),ccb); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataSetContactCallback(m_geom_transform,ccb); + } +} + +void CODEGeom::set_obj_contact_cb(ObjectContactCallbackFun* occb) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomUserDataSetObjectContactCallback(geom(),occb); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataSetObjectContactCallback(m_geom_transform,occb); + } +} +void CODEGeom::add_obj_contact_cb(ObjectContactCallbackFun* occb) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomUserDataAddObjectContactCallback(geom(),occb); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataAddObjectContactCallback(m_geom_transform,occb); + } +} +void CODEGeom::remove_obj_contact_cb(ObjectContactCallbackFun* occb) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomUserDataRemoveObjectContactCallback(geom(),occb); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataRemoveObjectContactCallback(m_geom_transform,occb); + } +} +void CODEGeom::set_callback_data(void *cd) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomUserDataSetCallbackData(geom(),cd); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataSetCallbackData(m_geom_transform,cd); + } +} +void* CODEGeom::get_callback_data() +{ + if(!m_geom_transform) return NULL; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + return dGeomGetUserData(geom())->callback_data; + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + return dGeomGetUserData(m_geom_transform)->callback_data; + } +} +void CODEGeom::set_ref_object(IPhysicsShellHolder* ro) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomUserDataSetPhysicsRefObject(geom(),ro); + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomUserDataSetPhysicsRefObject(m_geom_transform,ro); + } +} + +void CODEGeom::set_ph_object(CPHObject* o) +{ + if(!m_geom_transform) return; + if(geom()) + { + VERIFY(dGeomGetUserData(geom())); + dGeomGetUserData(geom())->ph_object=o; + } + else + { + VERIFY(dGeomGetUserData(m_geom_transform)); + dGeomGetUserData(m_geom_transform)->ph_object=o; + } +} +void CODEGeom::move_local_basis(const Fmatrix& inv_new_mul_old) +{ + Fmatrix new_form; + get_local_form (new_form); + new_form.mulA_43 (inv_new_mul_old); + set_local_form (new_form); +} +void CODEGeom::build(const Fvector& ref_point) +{ + init(); + set_build_position(ref_point); +} +void CODEGeom::init() +{ + dGeomID geom=create(); + m_geom_transform=dCreateGeomTransform(0); + dGeomTransformSetCleanup(m_geom_transform,0); + dGeomSetData(m_geom_transform,0); + dGeomTransformSetGeom(m_geom_transform,geom); + dGeomTransformSetInfo(m_geom_transform,1); + dGeomCreateUserData(geom); + dGeomUserDataSetBoneId(geom,m_bone_id); +} +void CODEGeom::destroy() +{ + if(!m_geom_transform) return; + if(geom()) + { + dGeomDestroyUserData(geom()); + dGeomDestroy(geom()); + dGeomTransformSetGeom(m_geom_transform,0); + } + dGeomDestroyUserData(m_geom_transform); + dGeomDestroy(m_geom_transform); + m_geom_transform=NULL; +} + +CBoxGeom::CBoxGeom(const Fobb& box) +{ + m_box=box; +} + +void CBoxGeom::get_mass(dMass& m) +{ + Fvector& hside=m_box.m_halfsize; + dMassSetBox(&m,1.f,hside.x*2.f,hside.y*2.f,hside.z*2.f); + dMatrix3 DMatx; + PHDynamicData::FMX33toDMX(m_box.m_rotate,DMatx); + dMassRotate(&m,DMatx); +} + +float CBoxGeom::volume() +{ + return m_box.m_halfsize.x*m_box.m_halfsize.y*m_box.m_halfsize.z*8.f; +} + +float CBoxGeom::radius() +{ + return m_box.m_halfsize.x; +} +void CODEGeom::get_final_tx_bt(const dReal* &p, const dReal* &R,dReal *bufV, dReal *bufM) const +{ + VERIFY(m_geom_transform); + //dGeomID g = geometry_bt() ; + get_final_tx (m_geom_transform,p,R,bufV,bufM) ; + +} +void CODEGeom::get_final_tx(dGeomID g,const dReal* &p,const dReal* &R,dReal * bufV, dReal* bufM) +{ + if(is_transform(g)) + { + computeFinalTx(g,bufV,bufM); + R=bufM;p=bufV; + }else + { + R=dGeomGetRotation(g); + p=dGeomGetPosition(g); + } +} + + +void CODEGeom:: set_local_form_bt ( const Fmatrix& xform ) +{ + dMatrix3 R; + PHDynamicData::FMXtoDMX( xform,R ); + dGeomSetRotation( geom(), R ); + dGeomSetPosition( geom(), xform.c.x, xform.c.y, xform.c.z ); +} + +void CBoxGeom::get_Extensions( const Fvector& axis, float center_prg, float& lo_ext, float& hi_ext ) const +{ + + VERIFY ( m_geom_transform ); + const dReal *rot =NULL ; + const dReal *pos =NULL ; + dVector3 p ; + dMatrix3 r ; + dGeomID g =geometry_bt() ; + get_final_tx_bt( pos, rot, p, r ) ; + GetBoxExtensions( g, cast_fp(axis), pos, rot, center_prg, &lo_ext, &hi_ext ); +} + +void CBoxGeom::get_max_area_dir_bt(Fvector& dir) +{ + dVector3 length,ddir; + dGeomBoxGetLengths (geometry(),length); + dReal S1=length[0]*length[1],S2=length[0]*length[2],S3=length[1]*length[2]; + const dReal* R= dGeomGetRotation(geometry()); + if(S1>S2) + { + if(S1>S3) + { + ddir[0]=R[2];ddir[1]=R[6];ddir[2]=R[10];//S1 + } + else + { + ddir[0]=R[0];ddir[1]=R[4];ddir[2]=R[8];//S3 + } + } + else + { + if(S2>S3) + { + ddir[0]=R[1];ddir[1]=R[5];ddir[2]=R[9];//S2 + } + else + { + ddir[0]=R[0];ddir[1]=R[4];ddir[2]=R[8];//S3 + } + } + + if(geom()) + { + const dReal* TR=dGeomGetRotation(geometry_transform()); + dir.x=dDOT(ddir,TR); + dir.y=dDOT(ddir,TR+4); + dir.z=dDOT(ddir,TR+8); + } + else + { + dir.x=ddir[0]; + dir.y=ddir[1]; + dir.z=ddir[2]; + } +} + +const Fvector& CBoxGeom::local_center() +{ + return m_box.m_translate; +} + +void CBoxGeom::get_local_form(Fmatrix& form) +{ + form._14=0; + form._24=0; + form._34=0; + form._44=1; + form.i.set(m_box.m_rotate.i); + form.j.set(m_box.m_rotate.j); + form.k.set(m_box.m_rotate.k); + form.c.set(m_box.m_translate); +} +void CBoxGeom::set_local_form(const Fmatrix& form) +{ + m_box.m_rotate.i.set(form.i); + m_box.m_rotate.j.set(form.j); + m_box.m_rotate.k.set(form.k); + m_box.m_translate.set(form.c); +} + + +dGeomID CBoxGeom::create() +{ + +return dCreateBox(0, + m_box.m_halfsize.x*2.f, + m_box.m_halfsize.y*2.f, + m_box.m_halfsize.z*2.f + ); +} +void CBoxGeom::set_size(const Fvector& half_size ) +{ + m_box.m_halfsize.set( half_size ); + VERIFY( geom() ); + dGeomBoxSetLengths( geom(), + m_box.m_halfsize.x*2.f, + m_box.m_halfsize.y*2.f, + m_box.m_halfsize.z*2.f + ); +} + + + +void CBoxGeom::get_size(Fvector& half_size ) const +{ + VERIFY( geom() ); + dGeomBoxGetLengths( geom(), + cast_fp( half_size ) + ); + half_size.mul( 0.5f ); + +} +void CBoxGeom::set_build_position(const Fvector& ref_point) +{ + + inherited::set_build_position(ref_point); + + dVector3 local_position={m_box.m_translate.x-ref_point.x, + m_box.m_translate.y-ref_point.y, + m_box.m_translate.z-ref_point.z + }; + dGeomSetPosition(geom(), + local_position[0], + local_position[1], + local_position[2] + ); + dMatrix3 R; + PHDynamicData::FMX33toDMX(m_box.m_rotate,R); + dGeomSetRotation(geom(),R); +} + +CSphereGeom::CSphereGeom(const Fsphere& sphere) +{ + m_sphere=sphere; +} +void CSphereGeom::get_mass(dMass& m) +{ + dMassSetSphere(&m,1.f,m_sphere.R); +} + +float CSphereGeom::volume() +{ + return 4.f*M_PI*m_sphere.R*m_sphere.R*m_sphere.R/3.f; +} + +float CSphereGeom::radius() +{ + return m_sphere.R; +} + +void CSphereGeom::get_Extensions( const Fvector& axis, float center_prg, float& lo_ext, float& hi_ext )const +{ + VERIFY ( m_geom_transform ); + const dReal *rot =NULL ; + const dReal *pos =NULL ; + dVector3 p ; + dMatrix3 r ; + dGeomID g =geometry_bt() ; + get_final_tx_bt( pos, rot, p, r ) ; + GetSphereExtensions( g, cast_fp( axis ), pos, center_prg, &lo_ext, &hi_ext ); +} +const Fvector& CSphereGeom::local_center() +{ + return m_sphere.P; +} + +void CSphereGeom::get_local_form(Fmatrix& form) +{ + form.identity(); + form.c.set(m_sphere.P); +} +void CSphereGeom::set_local_form(const Fmatrix& form) +{ + m_sphere.P.set(form.c); +} +dGeomID CSphereGeom::create() +{ + return dCreateSphere(0,m_sphere.R); +} + +void CSphereGeom::set_build_position(const Fvector& ref_point) +{ + + inherited::set_build_position(ref_point); + dVector3 local_position={ + m_sphere.P.x-ref_point.x, + m_sphere.P.y-ref_point.y, + m_sphere.P.z-ref_point.z + }; + + dGeomSetPosition(geom(),local_position[0],local_position[1],local_position[2]); +} + +CCylinderGeom::CCylinderGeom(const Fcylinder& cyl) +{ + m_cylinder=cyl; +} +void CCylinderGeom::get_mass(dMass& m) +{ + dMassSetCylinder(&m,1.f,2,m_cylinder.m_radius,m_cylinder.m_height); + dMatrix3 DMatx; + Fmatrix33 m33; + m33.j.set(m_cylinder.m_direction); + Fvector::generate_orthonormal_basis(m33.j,m33.k,m33.i); + PHDynamicData::FMX33toDMX(m33,DMatx); + dMassRotate(&m,DMatx); +} + +float CCylinderGeom::volume() +{ + return M_PI*m_cylinder.m_radius*m_cylinder.m_radius*m_cylinder.m_height; +} + +float CCylinderGeom::radius() +{ + return m_cylinder.m_radius; +} + +void CCylinderGeom::get_Extensions( const Fvector& axis, float center_prg, float& lo_ext, float& hi_ext )const +{ + VERIFY (m_geom_transform) ; + const dReal *rot =NULL ; + const dReal *pos =NULL ; + dVector3 p ; + dMatrix3 r ; + dGeomID g =geometry_bt() ; + get_final_tx_bt( pos, rot, p, r ) ; + GetCylinderExtensions( g, cast_fp( axis ), pos, rot, center_prg, &lo_ext, &hi_ext ); +} + + +void CCylinderGeom::set_radius( float r ) +{ + m_cylinder.m_radius = r; + VERIFY( geom() ); + dGeomCylinderSetParams ( geom(), m_cylinder.m_radius, m_cylinder.m_height ); +} + + +const Fvector& CCylinderGeom::local_center() +{ + return m_cylinder.m_center; +} + +void CCylinderGeom::get_local_form(Fmatrix& form) +{ + form._14=0; + form._24=0; + form._34=0; + form._44=1; + form.j.set(m_cylinder.m_direction); + Fvector::generate_orthonormal_basis(form.j,form.k,form.i); + form.c.set(m_cylinder.m_center); +} +void CCylinderGeom::set_local_form(const Fmatrix& form) +{ + m_cylinder.m_center.set(form.c); + m_cylinder.m_direction.set(form.j); +} +dGeomID CCylinderGeom::create() +{ +return dCreateCylinder( + 0, + m_cylinder.m_radius, + m_cylinder.m_height + ); +} +void CCylinderGeom::set_build_position(const Fvector& ref_point) +{ + + inherited::set_build_position(ref_point); + dVector3 local_position={ + m_cylinder.m_center.x-ref_point.x, + m_cylinder.m_center.y-ref_point.y, + m_cylinder.m_center.z-ref_point.z + }; + + dGeomSetPosition( + geom(), + local_position[0], + local_position[1], + local_position[2] + ); + dMatrix3 R; + Fmatrix33 m33; + m33.j.set(m_cylinder.m_direction); + Fvector::generate_orthonormal_basis(m33.j,m33.k,m33.i); + PHDynamicData::FMX33toDMX(m33,R); + dGeomSetRotation(geom(),R); +} + + + +#ifdef DEBUG +void CODEGeom:: dbg_draw ( float scale, u32 color, Flags32 flags )const +{ + Fmatrix m; + get_xform( m ); + debug_output().DBG_DrawMatrix( m, 0.02f ); + debug_output().DBG_DrawPoint( m.c, 0.001f, D3DCOLOR_XRGB(0, 255, 255 ) ); +} + + + +void CBoxGeom:: dbg_draw ( float scale, u32 color, Flags32 flags )const +{ + inherited::dbg_draw( scale, color, flags ); + + dGeomID g = geom(); + VERIFY( g ); + + Fmatrix m; + get_xform( m ); + + dVector3 l; + dGeomBoxGetLengths( g, l ); + + debug_output().DBG_DrawOBB( m, cast_fv( l ).mul( 0.5f ), color ); +} + +void CSphereGeom:: dbg_draw ( float scale, u32 color, Flags32 flags )const +{ + inherited::dbg_draw( scale, color, flags ); + + Fmatrix m; + get_xform( m ); + + dGeomID g = geom(); + VERIFY( g ); + dGeomSphereGetRadius( g ); + + debug_output().DBG_DrawPoint( m.c, dGeomSphereGetRadius( g ), color ); + +} + +void CCylinderGeom:: dbg_draw ( float scale, u32 color, Flags32 flags )const +{ + inherited::dbg_draw( scale, color, flags ); + + dGeomID g = geom(); + VERIFY( g ); + + Fmatrix m; + get_xform( m ); + + float r = 1, h = 1; + dGeomCylinderGetParams( g, &r, &h ); + Fvector ext( Fvector().set( r, h*0.5f, r ) ); + debug_output().DBG_DrawOBB( m, ext, color ); +} +#endif \ No newline at end of file diff --git a/xrPhysics/Geometry.h b/xrPhysics/Geometry.h new file mode 100644 index 00000000000..6fc5ff2f9dc --- /dev/null +++ b/xrPhysics/Geometry.h @@ -0,0 +1,218 @@ +#ifndef GEOMETRY_H +#define GEOMETRY_H +#include "PhysicsCommon.h" +#include "ExtendedGeom.h" +#include "mathutilsode.h" +#include "../xrEngine/iphysicsgeometry.h" + +//this is equivalent dMULTIPLYOP0_333 whith consequent transposion of A +#define dMULTIPLYOP3_333(A,op,B,C) \ + (A)[0] op dDOT14((B), (C)); \ + (A)[1] op dDOT14((B+4),(C)); \ + (A)[2] op dDOT14((B+8),(C)); \ + (A)[4] op dDOT14((B), (C+1)); \ + (A)[5] op dDOT14((B+4),(C+1)); \ + (A)[6] op dDOT14((B+8),(C+1)); \ + (A)[8] op dDOT14((B), (C+2)); \ + (A)[9] op dDOT14((B+4),(C+2)); \ + (A)[10] op dDOT14((B+8),(C+2)); + +inline void dMULTIPLY3_333(dReal *A, const dReal *B, const dReal *C) +{ dMULTIPLYOP3_333(A,=,B,C) } + + +class CGameObject; +class CPHObject; +class XRPHYSICS_API CODEGeom: +public IPhysicsGeometry +{ +protected: + dGeomID m_geom_transform; + u16 m_bone_id; + Flags16 m_flags; +protected: + + +public: + //get + virtual float volume () =0; + virtual void get_mass ( dMass& m ) =0; //unit dencity mass; + void get_mass ( dMass& m,const Fvector& ref_point, float density) ; + void get_mass ( dMass& m,const Fvector& ref_point) ; + void add_self_mass ( dMass& m,const Fvector& ref_point) ; + void add_self_mass ( dMass& m,const Fvector& ref_point, float density) ; + void get_local_center_bt ( Fvector& center ) ; //for built + void get_global_center_bt( Fvector& center ) ; //for built + void get_local_form_bt ( Fmatrix& form ) ; //for built + virtual void get_xform ( Fmatrix& form ) const ; +#ifdef DEBUG + virtual void dbg_draw ( float scale, u32 color, Flags32 flags ) const; +#endif + virtual void get_Box ( Fmatrix& form, Fvector& sz )const ; + virtual bool collide_fluids () const ; + void set_static_ref_form (const Fmatrix& form) ; //for built + virtual void get_max_area_dir_bt (Fvector& dir) =0; + virtual float radius () =0; + virtual void get_Extensions (const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext)const =0; + + void clear_cashed_tries () ; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + IC dGeomID geom() + { + return dGeomTransformGetGeom(m_geom_transform); + } + IC dGeomID geometry_transform () + { + return m_geom_transform; + } + IC dGeomID geometry() + { + return m_geom_transform ? (geom() ? geom() : m_geom_transform) : NULL; + } + IC dGeomID geometry_bt() + { + if(is_transformed_bt()) return geom() ; + else return geometry_transform(); + + } + IC const dGeomID geom()const + { + return dGeomTransformGetGeom(m_geom_transform); + } + IC const dGeomID geometry_transform ()const + { + return m_geom_transform; + } + IC const dGeomID geometry()const + { + return m_geom_transform ? (geom() ? geom() : m_geom_transform) : NULL; + } + IC const dGeomID geometry_bt()const + { + if(is_transformed_bt()) return geom() ; + else return geometry_transform(); + + } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ICF static bool is_transform(dGeomID g) + { + return dGeomGetClass(g)==dGeomTransformClass; + } + IC bool is_transformed_bt() const + { + return is_transform(m_geom_transform); + } + IC u16& element_position() + { + return dGeomGetUserData(geometry())->element_position; + } +virtual const Fvector& local_center () =0; +virtual void get_local_form (Fmatrix& form) =0; +virtual void set_local_form (const Fmatrix& form) =0; + void set_local_form_bt ( const Fmatrix& xform ) ; + //set + //element part + void set_body (dBodyID body) ; + void set_bone_id (u16 id) {m_bone_id=id ;} + u16 bone_id () {return m_bone_id ;} + void set_shape_flags ( const Flags16 &_flags ) { m_flags = _flags ;} + void add_to_space (dSpaceID space) ; + void remove_from_space (dSpaceID space) ; + void set_material (u16 ul_material) ; + void set_contact_cb (ContactCallbackFun* ccb) ; + void set_obj_contact_cb (ObjectContactCallbackFun* occb) ; + void add_obj_contact_cb (ObjectContactCallbackFun* occb) ; + void remove_obj_contact_cb(ObjectContactCallbackFun* occb) ; + void set_callback_data (void *cd) ; + void *get_callback_data () ; + void set_ref_object (IPhysicsShellHolder* ro) ; + void set_ph_object (CPHObject* o) ; + + //build/destroy +protected: + void init () ; + void get_final_tx_bt ( const dReal* &p, const dReal* &R, dReal * bufV, dReal* bufM ) const; + virtual dGeomID create () =0; +public: + static void get_final_tx ( dGeomID g, const dReal* &p, const dReal* &R,dReal * bufV, dReal* bufM ); + void build ( const Fvector& ref_point ) ; + virtual void set_build_position ( const Fvector& ref_point ) ;//for build geom + void clear_motion_history( bool set_unspecified ); + void move_local_basis ( const Fmatrix& inv_new_mul_old ) ; + void destroy () ; + CODEGeom () ; + virtual ~ CODEGeom () ; +}; + +class CBoxGeom : public CODEGeom +{ + typedef CODEGeom inherited ; + Fobb m_box; +public: + CBoxGeom (const Fobb& box) ; +// virtual ~CBoxGeom (const Fobb& box) ; + virtual float volume () ; + virtual float radius () ; + virtual void get_Extensions (const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext)const ; + virtual void get_max_area_dir_bt (Fvector& dir) ; + virtual void get_mass (dMass& m) ;//unit dencity mass; +virtual const Fvector& local_center () ; + virtual void get_local_form (Fmatrix& form) ; +virtual void set_local_form (const Fmatrix& form) ; + virtual dGeomID create () ; + virtual void set_build_position (const Fvector& ref_point) ; + void set_size (const Fvector& half_size ) ; + void get_size (Fvector& half_size ) const ; +private: +#ifdef DEBUG + virtual void dbg_draw ( float scale, u32 color, Flags32 flags ) const ; +#endif +}; + +class CSphereGeom : public CODEGeom +{ + typedef CODEGeom inherited ; + Fsphere m_sphere; +public: + CSphereGeom (const Fsphere& sphere) ; + virtual float volume () ; + virtual float radius () ; + virtual void get_Extensions (const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext)const; + virtual void get_max_area_dir_bt (Fvector& dir) {}; + virtual void get_mass (dMass& m) ;//unit dencity mass; +virtual const Fvector& local_center () ; + virtual void get_local_form (Fmatrix& form) ; + virtual void set_local_form (const Fmatrix& form) ; + virtual dGeomID create () ; + virtual void set_build_position (const Fvector& ref_point) ; + +private: +#ifdef DEBUG + virtual void dbg_draw ( float scale, u32 color, Flags32 flags ) const; +#endif +}; +class CCylinderGeom : public CODEGeom +{ + typedef CODEGeom inherited ; + Fcylinder m_cylinder; +public: + CCylinderGeom (const Fcylinder& cyl) ; + virtual float volume () ; + virtual float radius () ; + virtual void get_Extensions (const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext)const; + virtual void get_max_area_dir_bt (Fvector& dir) {}; +virtual const Fvector& local_center () ; + virtual void get_mass (dMass& m) ;//unit dencity mass; + virtual void get_local_form (Fmatrix& form) ; + virtual void set_local_form (const Fmatrix& form) ; + virtual dGeomID create () ; + virtual void set_build_position (const Fvector& ref_point) ; + void set_radius ( float r ) ; + private: +#ifdef DEBUG + virtual void dbg_draw ( float scale, u32 color, Flags32 flags ) const; +#endif +}; +#endif //GEOMETRY_H \ No newline at end of file diff --git a/xrPhysics/GeometryBits.cpp b/xrPhysics/GeometryBits.cpp new file mode 100644 index 00000000000..52782abdbed --- /dev/null +++ b/xrPhysics/GeometryBits.cpp @@ -0,0 +1,26 @@ +#include "stdafx.h" + +#include "GeometryBits.h" + +#include "phworld.h" +#include "geometry.h" + +static enum geom_category { + gct_static = 1<< 0, + gct_dynamic = 1<< 1 +}; + + +void CPHGeometryBits::init_geom( CODEGeom &g ) +{ + +} + +void CPHGeometryBits::init_geom( CPHMesh &g ) +{ + dGeomSetCategoryBits( g.GetGeom(), gct_static ); +} +void CPHGeometryBits::set_ignore_static( CODEGeom &g ) +{ + dGeomSetCollideBits( g.geometry_transform(), dGeomGetCollideBits(g.geometry_transform()) & ~gct_static ); +} \ No newline at end of file diff --git a/xrPhysics/GeometryBits.h b/xrPhysics/GeometryBits.h new file mode 100644 index 00000000000..6101a5053d1 --- /dev/null +++ b/xrPhysics/GeometryBits.h @@ -0,0 +1,12 @@ +#pragma once + + +class CPHMesh; +class CODEGeom; +class CPHGeometryBits +{ + public: + static void init_geom( CODEGeom &g ); + static void init_geom( CPHMesh &g ); + static void set_ignore_static( CODEGeom &g ); +}; \ No newline at end of file diff --git a/xrPhysics/IActivationShape.cpp b/xrPhysics/IActivationShape.cpp new file mode 100644 index 00000000000..e1829456d34 --- /dev/null +++ b/xrPhysics/IActivationShape.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "iactivationshape.h" +#include "phactivationshape.h" +#include "physics.h" +#include "iphysicsshellholder.h" +#include "phcollidevalidator.h" +void ActivateShapeExplosive( IPhysicsShellHolder* self_obj, const Fvector &size, Fvector &out_size, Fvector &in_out_pos) +{ + ////////////// + CPHActivationShape activation_shape;//Fvector start_box;m_PhysicMovementControl.Box().getsize(start_box); + activation_shape.Create(in_out_pos,size,self_obj); + + CPHCollideValidator::SetCharacterClassNotCollide(activation_shape); + + dBodySetGravityMode(activation_shape.ODEBody(),0); + activation_shape.Activate(size,1,1.f,M_PI/8.f); + in_out_pos.set(activation_shape.Position()); + activation_shape.Size(out_size); + activation_shape.Destroy(); +////////// +} + +void ActivateShapePhysShellHolder(IPhysicsShellHolder *obj, const Fmatrix &in_xform, const Fvector &in_size, Fvector &in_pos, Fvector &out_pos ) +{ + CPHActivationShape activation_shape; + activation_shape.Create (in_pos,in_size,obj); + activation_shape.set_rotation (in_xform); + if(obj->ObjectPPhysicsShell()) + { + activation_shape.collide_bits () = obj->ObjectPPhysicsShell()->collide_bits (); + activation_shape.collide_class_bits () = obj->ObjectPPhysicsShell()->collide_class_bits (); + } + activation_shape.Activate (in_size,1,1.f,M_PI/8.f); + + + + out_pos = activation_shape.Position(); + VERIFY (valid_pos(out_pos,phBoundaries)); + activation_shape.Destroy (); + + +#ifdef DEBUG + if (!valid_pos(out_pos,phBoundaries)) { + Msg("not valid position %f,%f,%f",out_pos.x,out_pos.y,out_pos.z); + Msg("size %f,%f,%f",in_size.x,in_size.y,in_size.z); + Msg("Object: %s",obj->ObjectName()); + Msg("Visual: %s",obj->ObjectNameVisual()); + //Msg("Object pos %f,%f,%f",Position().x,Position().y,Position().z); + } +#endif // DEBUG + +} + +bool ActivateShapeCharacterPhysicsSupport( Fvector &out_pos, const Fvector &vbox,const Fvector &activation_pos,const Fmatrix &mXFORM, bool not_collide_characters, bool set_rotation, IPhysicsShellHolder *m_EntityAlife ) +{ + CPHActivationShape activation_shape; + activation_shape.Create(activation_pos,vbox,m_EntityAlife); + if( not_collide_characters ) + { + CPHCollideValidator::SetCharacterClassNotCollide(activation_shape); + } + if( set_rotation ) + activation_shape.set_rotation( mXFORM ); + bool ret = activation_shape.Activate(vbox,1,1.f,M_PI/8.f); + out_pos.set(activation_shape.Position()); + activation_shape.Destroy(); + return ret; +} diff --git a/xrPhysics/IActivationShape.h b/xrPhysics/IActivationShape.h new file mode 100644 index 00000000000..198be15e087 --- /dev/null +++ b/xrPhysics/IActivationShape.h @@ -0,0 +1,5 @@ +#pragma once +class IPhysicsShellHolder; +XRPHYSICS_API void ActivateShapeExplosive ( IPhysicsShellHolder* self_obj, const Fvector &size, Fvector &out_size, Fvector &in_out_pos); +XRPHYSICS_API void ActivateShapePhysShellHolder (IPhysicsShellHolder *obj, const Fmatrix &in_xform, const Fvector &in_size, Fvector &in_pos, Fvector &out_pos ); +XRPHYSICS_API bool ActivateShapeCharacterPhysicsSupport ( Fvector &out_pos, const Fvector &vbox,const Fvector &activation_pos,const Fmatrix &mXFORM, bool not_collide_characters, bool set_rotation, IPhysicsShellHolder *m_EntityAlife ); \ No newline at end of file diff --git a/xrPhysics/IColisiondamageInfo.h b/xrPhysics/IColisiondamageInfo.h new file mode 100644 index 00000000000..0b3ee9acb13 --- /dev/null +++ b/xrPhysics/IColisiondamageInfo.h @@ -0,0 +1,22 @@ +#ifndef I_COLLISION_DAMAGE_INFO_H +#define I_COLLISION_DAMAGE_INFO_H +//struct SCollisionHitCallback; +class ICollisionHitCallback; +class ICollisionDamageInfo +{ +public: + virtual float ContactVelocity () const =0; + virtual void HitDir (Fvector &dir) const =0; + virtual const Fvector& HitPos () const =0; + virtual u16 DamageInitiatorID () const =0; + virtual CObject *DamageInitiator () const =0; + virtual ALife::EHitType HitType () const =0; + virtual ICollisionHitCallback *HitCallback () const =0; + virtual void Reinit () =0; + virtual void SetInitiated () =0; + virtual bool IsInitiated () const =0; + virtual bool GetAndResetInitiated () =0; +protected: + virtual ~ICollisionDamageInfo () = 0 {} +}; +#endif \ No newline at end of file diff --git a/xrPhysics/ICollideValidator.h b/xrPhysics/ICollideValidator.h new file mode 100644 index 00000000000..2d38f6b4edc --- /dev/null +++ b/xrPhysics/ICollideValidator.h @@ -0,0 +1,4 @@ +#pragma once + +typedef u32 CGID; +XRPHYSICS_API CGID RegisterGroup (); \ No newline at end of file diff --git a/xrPhysics/IElevatorState.h b/xrPhysics/IElevatorState.h new file mode 100644 index 00000000000..c4042a01e3d --- /dev/null +++ b/xrPhysics/IElevatorState.h @@ -0,0 +1,22 @@ +#pragma once + +enum Estate +{ + clbNone =0 , + clbNearUp , + clbNearDown , + clbClimbingUp , + clbClimbingDown , + clbDepart , + clbNoLadder , + clbNoState +}; +class IPhysicsShellHolder; +class IElevatorState +{ +public: + virtual Estate State () = 0; + virtual void NetRelcase ( IPhysicsShellHolder* O ) = 0; +protected: + virtual ~IElevatorState() = 0 {} +}; \ No newline at end of file diff --git a/xrPhysics/IPHCapture.h b/xrPhysics/IPHCapture.h new file mode 100644 index 00000000000..b383c876a39 --- /dev/null +++ b/xrPhysics/IPHCapture.h @@ -0,0 +1,16 @@ +#pragma once +class IPhysicsShellHolder; +class IPHCapture +{ +public: + virtual bool Failed () =0; + virtual void RemoveConnection( IPhysicsShellHolder* O ) = 0; + virtual void Release () =0; +protected: + virtual ~IPHCapture() =0 {} +}; +class CPHCharacter; +struct NearestToPointCallback; +XRPHYSICS_API IPHCapture *phcapture_create(CPHCharacter *ch, IPhysicsShellHolder* object, NearestToPointCallback* cb /*=0*/ ); +XRPHYSICS_API IPHCapture *phcapture_create(CPHCharacter *ch, IPhysicsShellHolder* object,u16 element); +XRPHYSICS_API void phcapture_destroy(IPHCapture* &c); \ No newline at end of file diff --git a/xrPhysics/IPHStaticGeomShell.h b/xrPhysics/IPHStaticGeomShell.h new file mode 100644 index 00000000000..fd39cb411e6 --- /dev/null +++ b/xrPhysics/IPHStaticGeomShell.h @@ -0,0 +1,17 @@ +#pragma once +#include "physicsexternalcommon.h" +class IPHStaticGeomShell +{ + protected: + virtual ~IPHStaticGeomShell() =0{} + // virtual void set_ObjectContactCallback (ObjectContactCallbackFun* callback); +}; + +class IPhysicsShellHolder; +class IClimableObject; +XRPHYSICS_API IPHStaticGeomShell *P_BuildStaticGeomShell(IPhysicsShellHolder* obj,ObjectContactCallbackFun* object_contact_callback); +XRPHYSICS_API IPHStaticGeomShell *P_BuildLeaderGeomShell( IClimableObject* obj, ObjectContactCallbackFun* callback, const Fobb &b ); +XRPHYSICS_API void DestroyStaticGeomShell( IPHStaticGeomShell* &p ); + +//CPHStaticGeomShell* P_BuildStaticGeomShell(CGameObject* obj,ObjectContactCallbackFun* object_contact_callback,Fobb &b); +//void P_BuildStaticGeomShell(CPHStaticGeomShell* shell,CGameObject* obj,ObjectContactCallbackFun* object_contact_callback,Fobb &b); \ No newline at end of file diff --git a/xrPhysics/IPHWorld.h b/xrPhysics/IPHWorld.h new file mode 100644 index 00000000000..1800c0b3ccb --- /dev/null +++ b/xrPhysics/IPHWorld.h @@ -0,0 +1,54 @@ +#pragma once +#include "physicsexternalcommon.h" +#include "iphysics_scripted.h" +class CPhysicsShell; +class IPHWorldUpdateCallbck +{ +public: + virtual void update_step () = 0; + virtual void phys_shell_relcase (CPhysicsShell* sh) = 0; +protected: + virtual ~IPHWorldUpdateCallbck() {} +}; + +class IPHWorld: + public iphysics_scripted_class +{ + public: + virtual ~IPHWorld () {} + virtual float Gravity () = 0; + virtual void SetGravity ( float g ) = 0; + virtual bool Processing () = 0; + virtual u32 CalcNumSteps (u32 dTime) = 0; + virtual u64 &StepsNum () = 0; + + virtual float FrameTime () = 0; + virtual void Freeze () = 0; + virtual void UnFreeze () = 0; + virtual void Step () = 0; + virtual void SetStep ( float s ) = 0; + virtual void StepNumIterations ( int num_it ) = 0; + virtual void set_default_contact_shotmark (ContactCallbackFun *f) = 0; + virtual void set_default_character_contact_shotmark(ContactCallbackFun *f) = 0; + virtual void set_step_time_callback (PhysicsStepTimeCallback* cb) = 0; + virtual void set_update_callback ( IPHWorldUpdateCallbck* cb) = 0; +#ifdef DEBUG + virtual u16 ObjectsNumber () = 0; + virtual u16 UpdateObjectsNumber () = 0; + virtual void OnRender () = 0; +#endif + +}; + +extern "C" XRPHYSICS_API IPHWorld * __stdcall physics_world(); +class CObjectSpace; +class CObjectList; +class CRenderDeviceBase; +extern "C" XRPHYSICS_API void __stdcall create_physics_world( bool mt, CObjectSpace* os, CObjectList *lo, CRenderDeviceBase *dv ); +extern "C" XRPHYSICS_API void __stdcall destroy_physics_world(); +class CGameMtlLibrary; +extern "C" XRPHYSICS_API void __stdcall set_mtl_lib(CGameMtlLibrary * l); +extern "C" XRPHYSICS_API CObjectSpace* __stdcall create_object_space(); +struct hdrCFORM; +extern "C" XRPHYSICS_API CObjectSpace* __stdcall mesh_create_object_space(Fvector* verts, CDB::TRI* tris, const hdrCFORM &H, CDB::build_callback build_callback); +extern "C" XRPHYSICS_API void __stdcall destroy_object_space(CObjectSpace* &os); \ No newline at end of file diff --git a/xrPhysics/IPhysicsShellHolder.h b/xrPhysics/IPhysicsShellHolder.h new file mode 100644 index 00000000000..e4324144812 --- /dev/null +++ b/xrPhysics/IPhysicsShellHolder.h @@ -0,0 +1,69 @@ +#pragma once +class ICollisionDamageInfo; +class IDamageSource; +//class IKinematics; +//class IRenderVisual; +class IKinematics; +class CPhysicsShell; +class IPHCapture; +class IPhysicsShellHolder; +class CPHSoundPlayer; +class ICollisionDamageReceiver; +class ICollisionForm; +class ICollisionHitCallback +{ +public: + virtual void call( IPhysicsShellHolder* obj, float min_cs, float max_cs, float &cs,float &hl, ICollisionDamageInfo* di ) = 0; + virtual ~ICollisionHitCallback() {} +}; + +#ifdef DEBUG + enum EDumpType + { + base, + poses, + vis_geom, + props, + full, + full_capped + }; +#endif + +class IPhysicsShellHolder +{ + public: + + virtual Fmatrix& _BCL ObjectXFORM () =0; + virtual Fvector& _BCL ObjectPosition () =0; + virtual LPCSTR _BCL ObjectName () const =0; + virtual LPCSTR _BCL ObjectNameVisual () const =0; + virtual LPCSTR _BCL ObjectNameSect () const =0; + virtual bool _BCL ObjectGetDestroy () const =0; + virtual ICollisionHitCallback* _BCL ObjectGetCollisionHitCallback () =0; + virtual u16 _BCL ObjectID () const =0; + virtual ICollisionForm* _BCL ObjectCollisionModel () =0; +// virtual IRenderVisual* _BCL ObjectVisual () =0; + virtual IKinematics* _BCL ObjectKinematics () =0; + virtual IDamageSource* _BCL ObjectCastIDamageSource () =0; + virtual void _BCL ObjectProcessingDeactivate () =0; + virtual void _BCL ObjectProcessingActivate () =0; + virtual void _BCL ObjectSpatialMove () =0; + virtual CPhysicsShell*& _BCL ObjectPPhysicsShell () =0; + virtual void _BCL enable_notificate () =0; + virtual bool _BCL has_parent_object () =0; + virtual void _BCL on_physics_disable () =0; + virtual IPHCapture* _BCL PHCapture () =0; + virtual bool _BCL IsInventoryItem () =0; + virtual bool _BCL IsActor () =0; + virtual bool _BCL IsStalker () =0; + //virtual void SetWeaponHideState ( u16 State, bool bSet )=0; + virtual void _BCL HideAllWeapons ( bool v ) =0;//(SetWeaponHideState(INV_STATE_BLOCK_ALL,true)) + virtual void _BCL MovementCollisionEnable ( bool enable ) =0; + virtual CPHSoundPlayer* _BCL ObjectPhSoundPlayer () =0; + virtual ICollisionDamageReceiver* _BCL ObjectPhCollisionDamageReceiver () =0; + virtual void _BCL BonceDamagerCallback ( float &damage_factor )=0; +#ifdef DEBUG + virtual std::string _BCL dump(EDumpType type) const =0; +#endif +}; + diff --git a/xrPhysics/MathUtils.cpp b/xrPhysics/MathUtils.cpp new file mode 100644 index 00000000000..bceaf4c01c5 --- /dev/null +++ b/xrPhysics/MathUtils.cpp @@ -0,0 +1,486 @@ +#include "stdafx.h" +#include "mathutils.h" +#include "../3rd party/ode/include/ode/common.h" +XRPHYSICS_API const float phInfinity = dInfinity; +/* +#include "MathUtils.h" +enum EBoxSideNearestPointCode +{ + box_inside , + side_invisible , + on_side , + on_edge , + on_vertex +}; +EBoxSideNearestPointCode GetNearestPointOnOBBSide(const Fmatrix &xform,const Fvector ¢er,const Fvector &sides,u16 side,const Fvector &p,Fvector &point) +{ + //to plane dist + const Fvector &norm=xform[side]; + u16 side1=(side+1)%3,side2=(side+2)%3; + float h=sides[side],h1=sides[side1],h2=sides[side2]; + //Fvector vdiffc;vdiffc.sub(center,p); + float c_prg=norm.dotproduct(center); + float p_prg=norm.dotproduct(p); + float diffc=c_prg-p_prg;norm.dotproduct(vdiffc); + float diffs; + if(diffc<0.f) + { + diffs=diffc+h; + point.set(norm); + point.mul(diffs); + point.add(p); + Fvector d;d.sub(center,point); + bool inside1 =_abs(d[side1])0.f) + { + if(inside1&&inside2) return box_inside; + else return side_invisible; + } + else + { + if(inside1&&inside2) return on_side; + else if(inside1) + { + float dd=h2-_abs(d[side2]); + Fvector s;s.set(xform[side2]);s. + } + } + } + float diffs=diffc<0.f ? diffc+h : diffc-h; +} +*/ +IC bool RAYvsCYLINDER(const Fcylinder& c_cylinder, const Fvector &S, const Fvector &D, float &R, BOOL bCull) +{ + + const float &r=c_cylinder.m_radius; + float h=c_cylinder.m_height/2.f; + const Fvector& p=S; + const Fvector& dir=D; + + const Fvector &c=c_cylinder.m_center; + const Fvector &ax=c_cylinder.m_direction; + //c.set(-IM.c.dotproduct(IM.i),-IM.c.dotproduct(IM.j),-IM.c.dotproduct(IM.k)); + //Fvector ax;ax.set(IM.i.z,IM.j.z,IM.k.z);//?? + +////////////////////////////////////////////////////////////// + Fvector v; v .sub (c,p) ; + float cs =dir .dotproduct (ax) ; + float Lc =v .dotproduct (ax) ; + float Lr =v .dotproduct (dir) ; + //////////////////////////////////////////////// + float sq_cos=cs*cs; + float sq_sin=1-sq_cos; + float v_smag=v.square_magnitude(); + const float sq_r=r*r; + + if(sq_sinsq_r) return false; + float r_dist=_sqrt(sq_r-sq_dist)+h; + tr1=Lr-r_dist; + + if(tr1>R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=Lr+r_dist; + if(tr2<0.f) return false;// + if(tr2h+r)return false; + float sq_dist=v_smag-Lr*Lr-Lc*Lc; + if(sq_dist>sq_r) return false; + float lc_h=abs_c_dist-h; + if(lc_h>0.f) + { + float sq_sphere_dist=lc_h*lc_h+sq_dist*sq_dist; + if(sq_sphere_dist>sq_r)return false; + float diff=_sqrt(sq_r-sq_sphere_dist); + tr1=Lr-diff; + if(tr1>R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=Lr+diff; + if(tr2<0.f) return false;// + if(tr2R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=Lr+diff; + if(tr2<0.f) return false;// + if(tr2 radius + //v^2+tc^2+tr^2-2*(cos*tc*tr-Lc*tc+Lr*tr) + + float sq_nearest_dist=v_smag+tr*tr+tc*tc-2*(cs*tc*tr-Lc*tc+Lr*tr); + + if(sq_nearest_dist>sq_r) return false; + //float max_c_diff=//; + + float sq_horde=(sq_r-sq_nearest_dist) ; + + //float horde=_sqrt(sq_horde) ; + float sq_c_diff=sq_horde*sq_cos*r_sq_sin ; + float c_diff=_sqrt(sq_c_diff) ;//ccc + float cp1=tc-c_diff ; + float cp2=tc+c_diff ; + + + //cp1h) + { + //sphere + float tc_h=tc-h;//!! hi (=)/; + float sq_sphere_dist=sq_sin*tc_h*tc_h; + if(sq_sphere_dist>sq_horde)return false; + float tr_c=tr-tc_h*cs;// + float diff=_sqrt(sq_horde-sq_sphere_dist); + tr1=tr_c-diff; + if(tr1>R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=tr_c+diff; + if(tr2<0.f) return false;// + if(tr2sq_horde)return false; + float tr_c=tr-tc_h*cs;//!! + float diff=_sqrt(sq_horde-sq_sphere_dist); + tr1=tr_c-diff; + if(tr1>R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=tr_c+diff; + if(tr2<0.f) return false;// + if(tr20.f) + { + if(cp1 >-h) + { + if(cp2R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=tr+diff; + if(tr2<0.f) return false;// + if(tr2R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + float tc_h=tc-h ; + float sq_sphere_dist=sq_sin*tc_h*tc_h; + //if(sq_sphere_dist>sq_horde)return false ; + float tr_c=tr-tc_h*cs ; + float diff=_sqrt(sq_horde-sq_sphere_dist) ; + tr2=tr_c+diff ; + if(tr2<0.f) return false ;// + if(tr2sq_horde)return false; + float diff=_sqrt(sq_horde-sq_sphere_dist) ; + float tr_c=tr-tc_h*cs ; + tr1=tr_c-diff ; + if(tr1>R) return false ;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + float diff=c_diff/cs ; + tr2=tr+diff ; + if(tr2<0.f) return false ;// + if(tr2R) return false ;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + float tc_h=tc-h ; + float tr_c=tr-tc_h*cs ; + float diff=_sqrt(sq_horde-sq_sin*tc_h*tc_h) ; + tr2=tr_c+diff ; + if(tr2-h) + { + if(cp2R) return false;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tr2=tr+diff; + if(tr2<0.f) return false;// + if(tr2-h&&cp2>h + + + float tc_h=tc-h; //hi sphere/cyl + float tr_c=tr-tc_h*cs; + float diff=_sqrt(sq_horde-sq_sin*tc_h*tc_h); + tr1=tr_c-diff; + if(tr1>R) return false ;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + diff=-c_diff/cs; + tr2=tr+diff; + if(tr2<0.f) return false;// + if(tr2R) return false ;// + if(tr1<0.f) + { + if(bCull)return false; + else{ + //mixed//lo + float tc_h=tc+h; + float tr_c=tr-tc_h*cs; + diff=_sqrt(sq_horde-sq_sin*tc_h*tc_h); + tr2=tr_c+diff; + if(tr2<0.f) return false;// + if(tr2=h + { + //-(--)- //sphere hi&&lo + + float tc_h=tc-h ; + float tr_c=tr-tc_h*cs ; + float diff=_sqrt(sq_horde-sq_sin*tc_h*tc_h) ; + tr1=tr_c-diff ; + if(tr1>R) return false ;// + ///////////////////////////////////////////// + if(tr1<0.f) + { + if(bCull)return false; + else{ + tc_h=tc+h ; + tr_c=tr-tc_h*cs ; + diff=_sqrt(sq_horde-sq_sin*tc_h*tc_h) ; + tr2=tr_c+diff ; + if(tr2<0.f) return false ;// + if(tr2EPS) k*=acos(cosinus)/_sqrt(sinus_2); + w.mul(k); +} + +IC float to_mag_and_dir(const Fvector &in_v,Fvector &out_v) +{ + float mag=in_v.magnitude(); + if(!fis_zero(mag)) + out_v.mul(in_v,1.f/mag); + else + out_v.set(0.f,0.f,0.f); + return mag; +} + +IC float to_mag_and_dir(Fvector &in_out_v) +{ + return to_mag_and_dir(in_out_v,in_out_v); +} + +IC void to_vector(Fvector &v,float mag,const Fvector dir) +{ + v.mul(dir,mag); +} + +IC void prg_pos_on_axis(const Fvector &in_ax_p,const Fvector &in_ax_d,Fvector &in_out_pos) +{ + in_out_pos.sub(in_ax_p); + float ax_mag=in_ax_d.magnitude(); + float prg=in_out_pos.dotproduct(in_ax_d)/ax_mag; + in_out_pos.set(in_ax_d); + in_out_pos.mul(prg/ax_mag); + in_out_pos.add(in_ax_p); +} +IC float prg_pos_on_plane(const Fvector &in_norm,float d,const Fvector &in_pos,Fvector &out_pos) +{ + float prg=d-in_pos.dotproduct(in_norm); + Fvector diff;diff.set(in_norm);diff.mul(prg); + out_pos.add(in_pos,diff); + return prg; +} + +IC void prg_on_normal( const Fvector &in_norm, const Fvector &in_dir, Fvector &out_dir ) +{ + float prg=-in_dir.dotproduct(in_norm); + Fvector diff;diff.set(in_norm);diff.mul(prg); + out_dir.add(in_dir,diff); + return; +} + +IC void restrict_vector_in_dir(Fvector& V,const Fvector& dir) +{ + Fvector sub;sub.set(dir); + float dotpr =dir.dotproduct(V); + if(dotpr>0.f) + { + sub.mul(dotpr); + V.sub(sub); + } +} +IC bool check_obb_sise(const Fobb& obb) +{ + return (!fis_zero(obb.m_halfsize.x,EPS_L)|| + !fis_zero(obb.m_halfsize.y,EPS_L)|| + !fis_zero(obb.m_halfsize.z,EPS_L) + ); + +} + +IC float fsignum(float val) +{ + return val<0.f ? -1.f : 1.f ; +} + +IC void save_max(float& max,float val) +{ + if(val>max)max=val; +} +IC void save_min(float& min,float val) +{ + if(vallimit)val=limit; +} + +IC void limit_below(float& val,float limit) +{ + if(valy){\ + if (x>z) {on_x;}\ + else {on_z;}\ + }\ + else\ +{\ + if (y>z) {on_y;}\ + else {on_z;}\ +} + +#define MIN_OF(x,on_x,y,on_y,z,on_z)\ + if(xz){ on_x1;on_z2;}else{on_z1;on_x2;}}\ + else {on_x1;on_y2;}\ +} + +#define SORT(x,on_x1,on_x2,on_x3,y,on_y1,on_y2,on_y3,z,on_z1,on_z2,on_z3)\ + if(xz){ on_x1;on_z2;on_y3;}else{on_z1;on_x2;on_y3;}}\ + else {on_x1;on_y2;on_z3;}\ +} +////////////////////////////////////////////////////////////////////////////////////// + +struct SInertVal +{ + float val; +const float inertion; + SInertVal(float inert): inertion (inert){R_ASSERT(inert>0.f&&inert<1.f);} +IC void new_val (float new_val) + { + val=inertion*val+(1-inertion)*new_val; + } +private: + SInertVal& operator = (SInertVal& v) + { + R_ASSERT(false); + } +}; + +IC float DET(const Fmatrix &a){ + return + (( a._11 * ( a._22 * a._33 - a._23 * a._32 ) - + a._12 * ( a._21 * a._33 - a._23 * a._31 ) + + a._13 * ( a._21 * a._32 - a._22 * a._31 ) )); +} + + +IC bool valid_pos(const Fvector &P,const Fbox &B){ + Fbox BB=B;BB.grow(100000); + return !!BB.contains(P) ; +} + + + +#ifdef DEBUG +const float DET_CHECK_EPS =0.15f ;//scale -35% !? ;) +const float DET_CHECK_FATAL_EPS =0.8f ;//scale -35% !? ;) +#define VERIFY_RMATRIX(M) {\ + float d=DET(M);\ + if( !fsimilar(d,1.f,DET_CHECK_EPS) ){\ + \ + Msg("! matrix: %s ",get_string(M).c_str()); \ + Msg("! determinant: %f ",d); \ + Msg("! Is not valid rotational matrix");\ + VERIFY(fsimilar(d,1.f,DET_CHECK_FATAL_EPS));\ + }}; +#else +#define VERIFY_RMATRIX(M) +#endif +#endif \ No newline at end of file diff --git a/xrPhysics/MathUtilsOde.h b/xrPhysics/MathUtilsOde.h new file mode 100644 index 00000000000..5d40bc4d285 --- /dev/null +++ b/xrPhysics/MathUtilsOde.h @@ -0,0 +1,109 @@ +#pragma once + +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/include/ode/common.h" +#include "../3rd party/ode/include/ode/odemath.h" +#include "../3rd party/ode/include/ode/objects.h" +#include "../3rd party/ode/include/ode/rotation.h" +#include "../3rd party/ode/include/ode/compatibility.h" +#include "../3rd party/ode/include/ode/collision.h" +#include "../3rd party/ode/include/ode/matrix.h" + +#include "mathutils.h" +#include "ode_redefine.h" + +static const dReal accurate_normalize_epsilon = 1.192092896e-05F; + +ICF void accurate_normalize(float* a) +{ + dReal sqr_magnitude = a[0]*a[0] + a[1]*a[1] + a[2]*a[2]; + + if (sqr_magnitude > accurate_normalize_epsilon) + { + dReal l = dRecipSqrt(sqr_magnitude); + a[0] *= l; + a[1] *= l; + a[2] *= l; + return; + } + + dReal a0,a1,a2,aa0,aa1,aa2,l; + VERIFY (a); + a0 = a[0]; + a1 = a[1]; + a2 = a[2]; + aa0 = dFabs(a0); + aa1 = dFabs(a1); + aa2 = dFabs(a2); + if (aa1 > aa0) { + if (aa2 > aa1) { + goto aa2_largest; + } + else { // aa1 is largest + a0 /= aa1; + a2 /= aa1; + l = dRecipSqrt (a0*a0 + a2*a2 + 1); + a[0] = a0*l; + a[1] = (float)_copysign(l,a1); + a[2] = a2*l; + } + } + else { + if (aa2 > aa0) { +aa2_largest: // aa2 is largest + a0 /= aa2; + a1 /= aa2; + l = dRecipSqrt (a0*a0 + a1*a1 + 1); + a[0] = a0*l; + a[1] = a1*l; + a[2] = (float)_copysign(l,a2); + } + else { // aa0 is largest + if (aa0 <= 0) { + // dDEBUGMSG ("vector has zero size"); ... this messace is annoying + a[0] = 1; // if all a's are zero, this is where we'll end up. + a[1] = 0; // return a default unit length vector. + a[2] = 0; + return; + } + a1 /= aa0; + a2 /= aa0; + l = dRecipSqrt (a1*a1 + a2*a2 + 1); + a[0] = (float)_copysign(l,a0); + a[1] = a1*l; + a[2] = a2*l; + } + } +} + +IC bool dVectorLimit(const float* v,float l,float* lv) +{ + float mag = _sqrt(dDOT(v,v)); + if(mag>l) + { + float f=mag/l; + lv[0]=v[0]/f;lv[1]=v[1]/f;lv[2]=v[2]/f; + return true; + } + else + { + dVectorSet(lv,v); + return false; + } +} + +IC void dVectorInterpolate(float* res,const float* from,const float* to,float k) //changes to +{ + dVector3 tov; + dVectorSet(res,from); + dVectorSet(tov,to); + dVectorInterpolate(res,tov,k); +} + +float E_NL( dBodyID b1, dBodyID b2, const dReal* norm ); + +float E_NlS( dBodyID body, const dReal* norm, float norm_sign );//if body c.geom.g1 norm_sign + else - + +#pragma warning(default:4995) +#pragma warning(default:4267) \ No newline at end of file diff --git a/xrPhysics/MovementBoxDynamicActivate.cpp b/xrPhysics/MovementBoxDynamicActivate.cpp new file mode 100644 index 00000000000..08ba668b250 --- /dev/null +++ b/xrPhysics/MovementBoxDynamicActivate.cpp @@ -0,0 +1,449 @@ +#include "stdafx.h" + +#include "movementboxdynamicactivate.h" + +#include "ExtendedGeom.h" +#include "MathUtils.h" +#include "Physics.h" +#include "ph_valid_ode.h" +#include "MathUtilsOde.h" +#include "iphysicsshellholder.h" +#include "phcharacter.h" +#include "../xrEngine/gamemtllib.h" + +ObjectContactCallbackFun* saved_callback = 0 ; +static float max_depth = 0.f ; + +struct STestCallbackPars +{ + static float calback_friction_factor ; + static float depth_to_use_force ; + static float callback_force_factor ; + static float depth_to_change_softness_pars ; + static float callback_cfm_factor ; + static float callback_erp_factor ; + static float decrement_depth ; + static float max_real_depth ; +}; + + +float STestCallbackPars::calback_friction_factor = 0.0f ; +float STestCallbackPars::depth_to_use_force = 0.3f ; +float STestCallbackPars::callback_force_factor = 10.f ; +float STestCallbackPars::depth_to_change_softness_pars = 0.00f ; +float STestCallbackPars::callback_cfm_factor = world_cfm*0.00001f; +float STestCallbackPars::callback_erp_factor = 1.f ; +float STestCallbackPars::decrement_depth = 0.f ; +float STestCallbackPars::max_real_depth = 0.2f ; +struct STestFootCallbackPars +{ + static float calback_friction_factor ; + static float depth_to_use_force ; + static float callback_force_factor ; + static float depth_to_change_softness_pars ; + static float callback_cfm_factor ; + static float callback_erp_factor ; + static float decrement_depth ; + static float max_real_depth ; +}; + + +float STestFootCallbackPars::calback_friction_factor = 0.3f ; +float STestFootCallbackPars::depth_to_use_force = 0.3f ; +float STestFootCallbackPars::callback_force_factor = 10.f ; +float STestFootCallbackPars::depth_to_change_softness_pars = 0.00f ; +float STestFootCallbackPars::callback_cfm_factor = world_cfm*0.00001f; +float STestFootCallbackPars::callback_erp_factor = 1.f ; +float STestFootCallbackPars::decrement_depth = 0.05f ; +float STestFootCallbackPars::max_real_depth = 0.2f ; +template +void TTestDepthCallback (bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2) +{ + if(saved_callback)saved_callback(do_colide,bo1,c,material_1,material_2); + + if(do_colide&&!material_1->Flags.test(SGameMtl::flPassable) &&!material_2->Flags.test(SGameMtl::flPassable)) + { + float& depth=c.geom.depth; + float test_depth=depth-Pars.decrement_depth; + save_max(max_depth,test_depth); + c.surface.mu*=Pars.calback_friction_factor; + if(test_depth>Pars.depth_to_use_force) + { + float force = Pars.callback_force_factor*ph_world->Gravity(); + dBodyID b1=dGeomGetBody(c.geom.g1); + dBodyID b2=dGeomGetBody(c.geom.g2); + if(b1)dBodyAddForce(b1,c.geom.normal[0]*force,c.geom.normal[1]*force,c.geom.normal[2]*force); + if(b2)dBodyAddForce(b2,-c.geom.normal[0]*force,-c.geom.normal[1]*force,-c.geom.normal[2]*force); + dxGeomUserData* ud1=retrieveGeomUserData(c.geom.g1); + dxGeomUserData* ud2=retrieveGeomUserData(c.geom.g2); + + if(ud1) + { + CPhysicsShell* phsl=ud1->ph_ref_object->ObjectPPhysicsShell(); + if(phsl) phsl->Enable(); + } + + if(ud2) + { + CPhysicsShell* phsl=ud2->ph_ref_object->ObjectPPhysicsShell(); + if(phsl) phsl->Enable(); + } + + + do_colide=false; + } + else if(test_depth>Pars.depth_to_change_softness_pars) + { + c.surface.soft_cfm=Pars.callback_cfm_factor; + c.surface.soft_erp=Pars.callback_erp_factor; + } + limit_above(depth,Pars.max_real_depth); + } + +} + +ObjectContactCallbackFun* TestDepthCallback = &TTestDepthCallback; +ObjectContactCallbackFun* TestFootDepthCallback = &TTestDepthCallback; +/////////////////////////////////////////////////////////////////////////////////////// +class CVelocityLimiter : + public CPHUpdateObject +{ + dBodyID m_body; +public: + float l_limit; + float y_limit; +private: + dVector3 m_safe_velocity; + dVector3 m_safe_position; +public: + CVelocityLimiter(dBodyID b,float l,float yl) + { + R_ASSERT(b); + m_body=b; + dVectorSet(m_safe_velocity,dBodyGetLinearVel(m_body)); + dVectorSet(m_safe_position,dBodyGetPosition(m_body)); + l_limit=l; + y_limit=yl; + } + virtual ~CVelocityLimiter() + { + Deactivate(); + m_body =0; + } + + + bool VelocityLimit() + { + const float *linear_velocity =dBodyGetLinearVel(m_body); + //limit velocity + bool ret=false; + if(dV_valid(linear_velocity)) + { + dReal mag; + Fvector vlinear_velocity;vlinear_velocity.set(cast_fv(linear_velocity)); + mag=_sqrt(linear_velocity[0]*linear_velocity[0]+linear_velocity[2]*linear_velocity[2]);// + if(mag>l_limit) + { + dReal f=mag/l_limit; + //dBodySetLinearVel(m_body,linear_velocity[0]/f,linear_velocity[1],linear_velocity[2]/f);///f + vlinear_velocity.x/=f;vlinear_velocity.z/=f; + ret=true; + } + mag=_abs(linear_velocity[1]); + if(mag>y_limit) + { + vlinear_velocity.y=linear_velocity[1]/mag*y_limit; + ret=true; + } + dBodySetLinearVel(m_body,vlinear_velocity.x,vlinear_velocity.y,vlinear_velocity.z); + return ret; + } + else + { + dBodySetLinearVel(m_body,m_safe_velocity[0],m_safe_velocity[1],m_safe_velocity[2]); + return true; + } + } + virtual void PhDataUpdate(dReal step) + { + const float *linear_velocity =dBodyGetLinearVel(m_body); + + if(VelocityLimit()) + { + dBodySetPosition(m_body, + m_safe_position[0]+linear_velocity[0]*fixed_step, + m_safe_position[1]+linear_velocity[1]*fixed_step, + m_safe_position[2]+linear_velocity[2]*fixed_step); + } + + if(!dV_valid(dBodyGetPosition(m_body))) + dBodySetPosition(m_body,m_safe_position[0]-m_safe_velocity[0]*fixed_step, + m_safe_position[1]-m_safe_velocity[1]*fixed_step, + m_safe_position[2]-m_safe_velocity[2]*fixed_step); + + + dVectorSet(m_safe_position,dBodyGetPosition(m_body)); + dVectorSet(m_safe_velocity,linear_velocity); + } + + virtual void PhTune(dReal step) + { + + VelocityLimit(); + } + +}; +//////////////////////////////////////////////////////////////////////////////////// +class CGetContactForces: + public CPHUpdateObject +{ + dBodyID m_body; + float m_max_force_self; + float m_max_torque_self; + + float m_max_force_self_y; + float m_max_force_self_sd; + + float m_max_force_others; + float m_max_torque_others; +public: + CGetContactForces(dBodyID b) + { + R_ASSERT(b); + m_body=b; + InitValues(); + } + float mf_slf(){return m_max_force_self;} + float mf_othrs(){return m_max_force_others;} + float mt_slf(){return m_max_torque_self;} + float mt_othrs(){return m_max_torque_others;} + + float mf_slf_y(){return m_max_force_self_y;} + float mf_slf_sd(){return m_max_force_self_sd;} +protected: + virtual void PhTune(dReal step) + { + InitValues(); + int num=dBodyGetNumJoints(m_body); + for(int i=0;inode[1].body; + bool b_body_second=(b_joint->node[1].body==m_body); + dReal* self_force=feedback->f1; + dReal* self_torque=feedback->t1; + dReal* othrers_force=feedback->f2; + dReal* othrers_torque=feedback->t2; + if(b_body_second) + { + other_body=b_joint->node[0].body; + self_force=feedback->f2; + self_torque=feedback->t2; + othrers_force=feedback->f1; + othrers_torque=feedback->t1; + } + + save_max(m_max_force_self,_sqrt(dDOT( self_force,self_force))); + save_max(m_max_torque_self,_sqrt(dDOT( self_torque,self_torque))); + save_max(m_max_force_self_y,_abs(self_force[1])); + save_max(m_max_force_self_sd,_sqrt(self_force[0]*self_force[0]+self_force[2]*self_force[2])); + if(other_body) + { + dVector3 shoulder;dVectorSub(shoulder,dJointGetPositionContact(joint),dBodyGetPosition(other_body)); + dReal shoulder_lenght=_sqrt(dDOT(shoulder,shoulder)); + + save_max(m_max_force_others,_sqrt(dDOT( othrers_force,othrers_force))); + if(!fis_zero(shoulder_lenght)) + save_max(m_max_torque_others,_sqrt(dDOT( othrers_torque,othrers_torque))/shoulder_lenght); + } + } + } + } + +private: + void InitValues() + { + m_max_force_self = 0.f; + m_max_torque_self = 0.f; + m_max_force_others = 0.f; + m_max_torque_others = 0.f; + m_max_force_self_y = 0.f; + m_max_force_self_sd = 0.f; + } +}; +///////////////////////////////////////////////////////////////////////////////////// +bool ActivateBoxDynamic( IPHMovementControl* mov_control, bool character_exist, DWORD id, int num_it/*=8*/, int num_steps/*5*/, float resolve_depth/*=0.01f*/ ) +{ + ///////////////////////////////////////////////////////////////////////////// + //m_PhysicMovementControl->ActivateBox(id); + VERIFY( mov_control ); + VERIFY( mov_control->character() ); + + mov_control->character()->CPHObject::activate(); + ph_world->Freeze(); + //UnFreeze(); //if(m_character) m_character->UnFreeze(); + mov_control->character()->UnFreeze(); + + //saved_callback=ObjectContactCallback(); + + /* ObjectContactCallbackFun* CPHMovementControl::ObjectContactCallback() + { + if(m_character) + return m_character->ObjectContactCallBack(); + else return NULL; + }*/ + + saved_callback= mov_control->character()->ObjectContactCallBack(); + + +// SetOjectContactCallback(TestDepthCallback); + + // void CPHMovementControl:: SetOjectContactCallback (ObjectContactCallbackFun* callback) + //{ + // if(m_character) + // m_character->SetObjectContactCallback(callback); + //} + mov_control->character()->SetObjectContactCallback(TestDepthCallback); + + + //SetFootCallBack(TestFootDepthCallback); + //void CPHMovementControl:: SetFootCallBack (ObjectContactCallbackFun* callback) + //{ + // VERIFY(m_character); + // m_character->SetWheelContactCallback(callback); + //} + mov_control->character()->SetWheelContactCallback(TestFootDepthCallback); + + + max_depth=0.f; + + + + //////////////////////////////////pars/////////////////////////////////////////// +// int num_it=8; +// int num_steps=5; +// float resolve_depth=0.01f; + + + if(!character_exist) + { + num_it=20; + num_steps=1; + resolve_depth=0.1f; + } + /////////////////////////////////////////////////////////////////////// + float fnum_it=float(num_it); + float fnum_steps=float(num_steps); + float fnum_steps_r=1.f/fnum_steps; + + + + //const Fbox& box =Box(); + float pass= character_exist ? _abs(mov_control->Box().getradius()-mov_control->Boxes()[id].getradius()) : mov_control->Boxes()[id].getradius(); + float max_vel=pass/2.f/fnum_it/fnum_steps/fixed_step; + float max_a_vel=M_PI/8.f/fnum_it/fnum_steps/fixed_step; + VERIFY( mov_control->character() ); + dBodySetForce(mov_control->character()->get_body(),0.f,0.f,0.f); + dBodySetLinearVel(mov_control->character()->get_body(),0.f,0.f,0.f); + + //Calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + mov_control->actor_calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + + CVelocityLimiter vl(mov_control->character()->get_body(),max_vel,max_vel); + max_vel=1.f/fnum_it/fnum_steps/fixed_step; + + bool ret=false; + mov_control->character()->SwitchOFFInitContact(); + mov_control->character()->SetStaticContactCallBack( 0 ); + vl.Activate(); + vl.l_limit*=(fnum_it*fnum_steps/5.f); + vl.y_limit=vl.l_limit; +////////////////////////////////////////////////////////////////////////////////////////////////////// + for(int m=0;30>m;++m) + { + //Calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + mov_control->actor_calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + + //EnableCharacter(); + //void CPHMovementControl::EnableCharacter () + //{ + // if( m_character && m_character->b_exist ) + // m_character->Enable(); + //} + VERIFY(mov_control->character()->b_exist); + mov_control->character()->Enable(); + + mov_control->character()->ApplyForce(0,ph_world->Gravity()*mov_control->character()->Mass(),0); + max_depth=0.f; + ph_world->Step(); + if(max_depth < resolve_depth) + { + break; + } + ph_world->CutVelocity(max_vel,max_a_vel); + } + vl.l_limit/=(fnum_it*fnum_steps/5.f); + vl.y_limit=vl.l_limit; +///////////////////////////////////// + + for(int m=0;num_steps>m;++m) + { + float param =fnum_steps_r*(1+m); + mov_control->InterpolateBox(id,param); + ret=false; + for(int i=0;num_it>i;++i){ + max_depth=0.f; + //Calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + mov_control->actor_calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + //EnableCharacter(); + mov_control->character()->Enable(); + mov_control->character()->ApplyForce(0,ph_world->Gravity()*mov_control->character()->Mass(),0); + ph_world->Step(); + ph_world->CutVelocity(max_vel,max_a_vel); + if(max_depth < resolve_depth) + { + ret=true; + break; + } + } + if(!ret) break; + } + + mov_control->character()->SwitchInInitContact(); + mov_control->character()->SetStaticContactCallBack( ph_world->default_character_contact_shotmark() ); + vl.Deactivate(); + + ph_world->UnFreeze(); + + //SetOjectContactCallback(saved_callback); + //void CPHMovementControl:: SetOjectContactCallback (ObjectContactCallbackFun* callback) + //{ + // if(m_character) + // m_character->SetObjectContactCallback(callback); + //} + mov_control->character()->SetObjectContactCallback(saved_callback); + saved_callback=0; + + + return ret; +////////////////////////////////////////////////////////////////////////////////////////// +} \ No newline at end of file diff --git a/xrPhysics/MovementBoxDynamicActivate.h b/xrPhysics/MovementBoxDynamicActivate.h new file mode 100644 index 00000000000..1ee0708e6da --- /dev/null +++ b/xrPhysics/MovementBoxDynamicActivate.h @@ -0,0 +1,15 @@ +#pragma once +class CPHCharacter; +class IPHMovementControl +{ +public: + virtual CPHCharacter *character () = 0; + virtual void actor_calculate (Fvector& vAccel,const Fvector& camDir, float ang_speed, float jump, float dt, bool bLight) =0; + virtual const Fbox *Boxes ( ) = 0; + virtual const Fbox &Box ( ) = 0; + virtual void InterpolateBox (DWORD id,float k) = 0; +}; + +XRPHYSICS_API bool ActivateBoxDynamic( IPHMovementControl* mov_control, bool character_exist, DWORD id, int num_it/*=8*/,int num_steps/*5*/, float resolve_depth/*=0.01f*/ ); + + diff --git a/xrPhysics/PHAICharacter.cpp b/xrPhysics/PHAICharacter.cpp new file mode 100644 index 00000000000..07f0cd422c6 --- /dev/null +++ b/xrPhysics/PHAICharacter.cpp @@ -0,0 +1,220 @@ +#include "stdafx.h" + + +#include "PHDynamicData.h" +#include "Physics.h" +#include "ExtendedGeom.h" +#include "../xrEngine/cl_intersect.h" +#include "tri-colliderKNoOPC\__aabb_tri.h" + +#include "phaicharacter.h" +#include "../xrengine/device.h" + +#ifdef DEBUG +//# include "../xrEngine/StatGraph.h" +# include "debug_output.h" +//# include "level.h" +//# include "debug_renderer.h" +#endif + +CPHAICharacter::CPHAICharacter() +{ + m_forced_physics_control=false; +} +void CPHAICharacter::Create(dVector3 sizes) +{ + inherited::Create(sizes); + + m_forced_physics_control=false;//. +} +bool CPHAICharacter::TryPosition(Fvector pos,bool exact_state){ + if(!b_exist) return false; + if(m_forced_physics_control||JumpState()) return false;//b_was_on_object||b_on_object|| + if( DoCollideObj ()) return false; + Fvector current_pos; + GetPosition(current_pos); + Fvector cur_vel;GetVelocity(cur_vel); + + Fvector displace;displace.sub(pos,current_pos); + float disp_mag=displace.magnitude(); + + if( fis_zero( disp_mag ) || fis_zero( inl_ph_world().Device().fTimeDelta ) ) + return true ; + const u32 max_steps = 15 ; + const float fmax_steps = float ( max_steps ) ; + float fsteps_num = 1.f ; + u32 steps_num = 1 ; + float disp_pstep = FootRadius ( ); + float rest = 0.f; + + float parts = disp_mag / disp_pstep ; + fsteps_num = floor ( parts ); + steps_num = iFloor ( parts ); + if( steps_num > max_steps ) + { + steps_num = max_steps ; + fsteps_num = fmax_steps ; + disp_pstep = disp_mag / fsteps_num ; + } + rest = disp_mag - fsteps_num * disp_pstep ; + + Fvector vel;vel.mul(displace,disp_pstep/fixed_step/disp_mag); + bool ret=true; + int save_gm=dBodyGetGravityMode(m_body); + dBodySetGravityMode(m_body,0); + for(u32 i=0;steps_num>i;++i) + { + SetVelocity(vel); + Enable(); + if(!step_single(fixed_step)) + { + SetVelocity(cur_vel); + ret= false; + break; + } + } + + vel.mul(displace,rest/fixed_step/disp_mag); + SetVelocity(vel); + Enable(); + ret = step_single(fixed_step); + + + dBodySetGravityMode(m_body,save_gm); + SetVelocity(cur_vel); + Fvector pos_new;GetPosition(pos_new); + +#if 0 + Fvector dif;dif .sub( pos, pos_new ); + float dif_m = dif.magnitude(); + if(ret&&dif_m>EPS_L) + { + Msg("dif vec %f,%f,%f \n",dif.x,dif.y,dif.z); + Msg("dif mag %f \n",dif_m); + } +#endif + + SetPosition(pos_new); + m_last_move.sub(pos_new,current_pos).mul(1.f/inl_ph_world().Device().fTimeDelta); + m_body_interpolation.UpdatePositions(); + m_body_interpolation.UpdatePositions(); + if(ret) + Disable(); + m_collision_damage_info.m_contact_velocity=0.f; + return ret; +} +/* +void CPHAICharacter:: SetPosition (const Fvector &pos) +{ + //m_vDesiredPosition.set(pos); + inherited::SetPosition(pos); + +} +*/ +/* +void CPHAICharacter::BringToDesired(float time,float velocity,float force) +{ + Fvector pos,move; + GetPosition(pos); + + move.sub(m_vDesiredPosition,pos); + move.y=0.f; + float dist=move.magnitude(); + + float vel; + if(dist>EPS_L*100.f) + { + vel=dist/time; + move.mul(1.f/dist); + } + else if(dist>EPS_L*10.f) + { + vel=dist*dist*dist; + move.mul(1.f/dist); + } + else + { + vel=0.f; + move.set(0,0,0); + } + + if(vel>velocity)//&&velocity>EPS_L + vel=velocity; + + if(velocityFlags.test(SGameMtl::flActorObstacle))||(material_2&&material_2->Flags.test(SGameMtl::flActorObstacle))) + do_collide=true; + inherited::InitContact(c,do_collide,material_idx_1,material_idx_2); + if(is_control||b_lose_control||b_jumping) + c->surface.mu = 0.00f; + dxGeomUserData* D1=retrieveGeomUserData(c->geom.g1); + dxGeomUserData* D2=retrieveGeomUserData(c->geom.g2); + if(D1&&D2&&D1->ph_object&&D2->ph_object&&D1->ph_object->CastType()==tpCharacter&&D2->ph_object->CastType()==tpCharacter) + { + b_on_object=true; + b_valide_wall_contact=false; + } +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgNeverUseAiPhMove))do_collide=false; +#endif +} +/* +EEnvironment CPHAICharacter::CheckInvironment() +{ + + return inherited::CheckInvironment(); +} +*/ +#ifdef DEBUG +void CPHAICharacter::OnRender() +{ + inherited::OnRender(); +#if 0 + if(!b_exist) return; + + Fvector pos; + GetDesiredPosition(pos); + pos.y+=m_radius; + + + Fvector scale; + scale.set(0.35f,0.35f,0.35f); + Fmatrix M; + M.identity(); + M.scale(scale); + M.c.set(pos); + + + Level().debug_renderer().draw_ellipse(M, 0xffffffff); +#endif +} +#endif \ No newline at end of file diff --git a/xrPhysics/PHAICharacter.h b/xrPhysics/PHAICharacter.h new file mode 100644 index 00000000000..6c240cf2417 --- /dev/null +++ b/xrPhysics/PHAICharacter.h @@ -0,0 +1,31 @@ +#pragma once +#include "PHSimpleCharacter.h" +class CPHAICharacter : public CPHSimpleCharacter +{ + typedef CPHSimpleCharacter inherited; + + + bool m_forced_physics_control; +public: + CPHAICharacter (); + virtual CPHAICharacter *CastAICharacter () {return this;} + //virtual void SetPosition (const Fvector &pos); + //virtual void SetDesiredPosition (const Fvector& pos) {m_vDesiredPosition.set(pos) ;} + //virtual void GetDesiredPosition (Fvector& dpos) {dpos.set(m_vDesiredPosition) ;} + virtual void ValidateWalkOn () ; +// virtual void BringToDesired (float time,float velocity,float force=1.f) ; + virtual bool TryPosition (Fvector pos,bool exact_state) ; + virtual void Jump (const Fvector& jump_velocity) ; + virtual void SetMaximumVelocity (dReal vel) {m_max_velocity=vel ;} + virtual void InitContact (dContact* c,bool &do_collide,u16 material_idx_1,u16 material_idx_2) ; + virtual void SetForcedPhysicsControl (bool v){m_forced_physics_control=v;} + virtual bool ForcedPhysicsControl (){return m_forced_physics_control;} + virtual void Create (dVector3 sizes) ; +private: + virtual void UpdateStaticDamage (dContact* c,SGameMtl* tri_material,bool bo1){} + //virtual EEnvironment CheckInvironment (); +#ifdef DEBUG + virtual void OnRender () ; +#endif + +}; \ No newline at end of file diff --git a/xrPhysics/PHActivationShape.cpp b/xrPhysics/PHActivationShape.cpp new file mode 100644 index 00000000000..820e0fc1159 --- /dev/null +++ b/xrPhysics/PHActivationShape.cpp @@ -0,0 +1,385 @@ +#include "stdafx.h" +#include "PHActivationShape.h" + +#include "Physics.h" +#include "MathUtils.h" +#include "phvalidevalues.h" + +#include "Extendedgeom.h" +#include "SpaceUtils.h" +#include "MathUtils.h" +#include "../xrEngine/gamemtllib.h" +//#include "Level.h" +#include "PHWorld.h" +#include "../3rd party/ode/ode/src/util.h" + +#ifdef DEBUG +# include "debug_output.h" +#endif // DEBUG + +#include "PHDynamicData.h" +#include "../xrserverentities/PHSynchronize.h" +#include "../xrserverentities/phnetstate.h" +static float max_depth =0.f; +static float friction_factor =0.f; +static const float cfm =1.e-10f; +static const float erp =1.f; +/* +static const float static_cfm =1.e-10f; +static const float static_erp =1.f; + +static const float dynamic_cfm = 1.f;//static_cfm;// +static const float dynamic_erp = 1.f / 1000.f;//static_erp;// +*/ + +#ifdef DEBUG +#define CHECK_POS(pos,msg,br) if (!valid_pos(pos,phBoundaries)){Msg("pos:%f,%f,%f",pos.x,pos.y,pos.z);Msg(msg);VERIFY(!br);} + +#else +#define CHECK_POS(pos,msg,br) +#endif +extern int dTriListClass; + +static void ActivateTestDepthCallback (bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2) +{ + + if(!do_colide|| + material_1->Flags.test(SGameMtl::flPassable) || + material_2->Flags.test(SGameMtl::flPassable) + ) + return; + + float& depth=c.geom.depth; + float test_depth=depth; + save_max(max_depth,test_depth); + c.surface.mu*=friction_factor; + c.surface.soft_cfm=cfm; + c.surface.soft_erp=erp; +/* + + + VERIFY(dTriListClass != dGeomGetClass(c.geom.g2)); + bool cl_statics = (dTriListClass == dGeomGetClass(c.geom.g1)); + VERIFY( bo1 || cl_statics ); + CPHObject* self = static_cast ( ( (CPHActivationShape*)(PHRetrieveGeomUserData( bo1 ? c.geom.g1 : c.geom.g2 )->callback_data) ) ); + VERIFY( self ); + + if( cl_statics ) + { + c.surface.soft_cfm=static_cfm; + c.surface.soft_erp=static_erp; + dJointID contact_joint = dJointCreateContactSpecial( 0, ContactGroup, &c ); + self->DActiveIsland()->ConnectJoint(contact_joint); + dJointAttach(contact_joint, dGeomGetBody(c.geom.g1), dGeomGetBody(c.geom.g2)); + do_colide = false; + return; + } + + c.surface.soft_cfm=dynamic_cfm; + c.surface.soft_erp=dynamic_erp; + + dxGeomUserData* data_oposite = retrieveGeomUserData( bo1 ? c.geom.g2 : c.geom.g1 ); + + if( !data_oposite || !data_oposite->ph_object ) + return; + + CPHObject* obj1 = 0, *obj2 = 0; + if(bo1) + { + obj1 = self; + obj2 = data_oposite->ph_object; + } else + { + obj2 = self; + obj1 = data_oposite->ph_object; + } + + do_colide = false; + + VERIFY( obj1 && obj2 ); + + int max_contacts; + if( !obj1->DActiveIsland()->CanMerge(obj2->DActiveIsland(),max_contacts ) ) + return; + if( max_contacts < 1 ) + return; + + dJointID contact_joint = dJointCreateContactSpecial( 0, ContactGroup, &c ); + obj1->DActiveIsland()->ConnectJoint(contact_joint); + dJointAttach (contact_joint, dGeomGetBody(c.geom.g1), dGeomGetBody(c.geom.g2)); + + obj1->DActiveIsland()->Merge( obj2->DActiveIsland() ); + obj2->EnableObject( obj1 ); + */ + +} + +void StaticEnvironment ( bool& do_colide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ) +{ + dJointID contact_joint = dJointCreateContact(0, ContactGroup, &c); + + if(bo1) + { + ((CPHActivationShape*)(retrieveGeomUserData(c.geom.g1)->callback_data))->DActiveIsland()->ConnectJoint(contact_joint); + dJointAttach (contact_joint, dGeomGetBody(c.geom.g1), 0); + } + else + { + ((CPHActivationShape*)(retrieveGeomUserData(c.geom.g2)->callback_data))->DActiveIsland()->ConnectJoint(contact_joint); + dJointAttach (contact_joint, 0, dGeomGetBody(c.geom.g2)); + } + do_colide=false; +} +void GetMaxDepthCallback (bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2) +{ + + if(!do_colide || + material_1->Flags.test(SGameMtl::flPassable) || + material_2->Flags.test(SGameMtl::flPassable) + ) + return; + + float& depth=c.geom.depth; + float test_depth=depth; + //save_max(max_depth,test_depth); + max_depth+=test_depth; +} + +void RestoreVelocityState(V_PH_WORLD_STATE& state) +{ + V_PH_WORLD_STATE::iterator i=state.begin(),e=state.end(); + for(;e!=i;++i) + { + CPHSynchronize& sync=*i->first; + SPHNetState& old_s =i->second; + SPHNetState new_s;sync.get_State(new_s); + new_s.angular_vel.set(old_s.angular_vel); + new_s.linear_vel.set(old_s.linear_vel); + new_s.enabled=old_s.enabled; + sync.set_State(new_s); + } +} + +CPHActivationShape::CPHActivationShape() +{ + m_geom=NULL; + m_body=NULL; + m_flags.zero(); + m_flags.set(flFixedRotation,TRUE); +} +CPHActivationShape::~CPHActivationShape() +{ + VERIFY(!m_body&&!m_geom); +} +void CPHActivationShape::Create(const Fvector start_pos,const Fvector start_size,IPhysicsShellHolder* ref_obj,EType _type/*=etBox*/,u16 flags) +{ + VERIFY(ref_obj); + R_ASSERT(_valid( start_pos ) ); + R_ASSERT( _valid( start_size ) ); + + m_body = dBodyCreate (0) ; + dMass m; + dMassSetSphere(&m,1.f,100000.f); + dMassAdjust(&m,1.f); + dBodySetMass(m_body,&m); + switch(_type) + { + case etBox: + m_geom = dCreateBox (0,start_size.x,start_size.y,start_size.z) ; + break; + + case etSphere: + m_geom = dCreateSphere (0,start_size.x); + break; + }; + + dGeomCreateUserData (m_geom) ; + dGeomUserDataSetObjectContactCallback(m_geom,ActivateTestDepthCallback) ; + dGeomUserDataSetPhysicsRefObject(m_geom,ref_obj) ; + dGeomSetBody (m_geom,m_body) ; + dBodySetPosition (m_body,start_pos.x,start_pos.y,start_pos.z) ; + Island() .AddBody (m_body) ; + dBodyEnable (m_body) ; + m_safe_state .create(m_body) ; + spatial_register () ; + m_flags.set(flags,TRUE); +} +void CPHActivationShape:: Destroy () +{ + VERIFY(m_geom&&m_body) ; + spatial_unregister () ; + CPHObject::deactivate () ; + dGeomDestroyUserData (m_geom) ; + dGeomDestroy (m_geom) ; + m_geom =NULL ; + dBodyDestroy (m_body) ; + m_body =NULL ; +} +bool CPHActivationShape:: Activate (const Fvector need_size,u16 steps,float max_displacement,float max_rotation,bool un_freeze_later/* =false*/) +{ + +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawDeathActivationBox)) + { + debug_output().DBG_OpenCashedDraw(); + Fmatrix M; + PHDynamicData::DMXPStoFMX(dBodyGetRotation(m_body),dBodyGetPosition(m_body),M); + Fvector v;dGeomBoxGetLengths(m_geom,cast_fp(v));v.mul(0.5f); + debug_output().DBG_DrawOBB(M,v,D3DCOLOR_XRGB(0,255,0)); + } +#endif + VERIFY(m_geom&&m_body); + CPHObject::activate(); + ph_world->Freeze(); + UnFreeze(); + max_depth=0.f; + + dGeomUserDataSetObjectContactCallback(m_geom,GetMaxDepthCallback) ; + //ph_world->Step(); + ph_world->StepTouch(); + u16 num_it =15; + float fnum_it=float(num_it); + float fnum_steps=float(steps); + float fnum_steps_r=1.f/fnum_steps; + float resolve_depth=0.01f; + float max_vel=max_depth/fnum_it*fnum_steps_r/fixed_step; + float limit_l_vel=_max(_max(need_size.x,need_size.y),need_size.z)/fnum_it*fnum_steps_r/fixed_step; + + if(limit_l_vel>default_l_limit) + limit_l_vel=default_l_limit; + + if(max_vel>limit_l_vel) + max_vel=limit_l_vel; + + float max_a_vel=max_rotation/fnum_it*fnum_steps_r/fixed_step; + + if(max_a_vel>default_w_limit) + max_a_vel=default_w_limit; + + //ph_world->CutVelocity(0.f,0.f); + dGeomUserDataSetCallbackData(m_geom,this); + dGeomUserDataSetObjectContactCallback( m_geom, ActivateTestDepthCallback ); + if( m_flags.test( flStaticEnvironment ) ) + dGeomUserDataAddObjectContactCallback(m_geom,StaticEnvironment); + max_depth=0.f; + + Fvector from_size; + Fvector step_size,size; + dGeomBoxGetLengths(m_geom,cast_fp(from_size)); + step_size.sub(need_size,from_size); + step_size.mul(fnum_steps_r); + size.set(from_size); + bool ret=false; + V_PH_WORLD_STATE temp_state; + ph_world->GetState(temp_state); + for(int m=0;steps>m;++m) + { + //float param =fnum_steps_r*(1+m); + //InterpolateBox(id,param); + size.add(step_size); + dGeomBoxSetLengths(m_geom,size.x,size.y,size.z); + u16 attempts=10; + do{ + + ret=false; + for(int i=0;num_it>i;++i) + { + max_depth=0.f; + ph_world->Step(); + CHECK_POS(Position(),"pos after ph_world->Step()",false); + ph_world->CutVelocity(max_vel,max_a_vel); + CHECK_POS(Position(),"pos after CutVelocity",true); + //if(m==0&&i==0)ph_world->GetState(temp_state); + if(max_depth < resolve_depth) + { + ret=true; + break; + } + } + attempts--; + }while(!ret&&attempts>0); +#ifdef DEBUG +// Msg("correction attempts %d",10-attempts); +#endif + + } + RestoreVelocityState(temp_state); + CHECK_POS(Position(),"pos after RestoreVelocityState(temp_state);",true); + if(!un_freeze_later)ph_world->UnFreeze(); +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawDeathActivationBox)) + { + debug_output().DBG_OpenCashedDraw(); + Fmatrix M; + PHDynamicData::DMXPStoFMX(dBodyGetRotation(m_body),dBodyGetPosition(m_body),M); + Fvector v;v.set(need_size);v.mul(0.5f); + debug_output().DBG_DrawOBB(M,v,D3DCOLOR_XRGB(0,255,255)); + debug_output().DBG_ClosedCashedDraw(30000); + } +#endif + return ret; +} +const Fvector& CPHActivationShape:: Position () +{ + return cast_fv(dBodyGetPosition(m_body)); +} +void CPHActivationShape:: Size (Fvector &size) +{ + dGeomBoxGetLengths(m_geom,cast_fp(size)); +} + +void CPHActivationShape:: PhDataUpdate (dReal step) +{ + m_safe_state.new_state(m_body); +} +void CPHActivationShape:: PhTune (dReal step) +{ + +} +dGeomID CPHActivationShape:: dSpacedGeom () +{ + return m_geom; +} +void CPHActivationShape:: get_spatial_params () +{ + spatialParsFromDGeom(m_geom,spatial.sphere.P,AABB,spatial.sphere.R); +} + +void CPHActivationShape:: InitContact (dContact* c,bool& do_collide,u16 ,u16 ) +{ + +} + +void CPHActivationShape::CutVelocity(float l_limit,float /*a_limit*/) +{ + dVector3 limitedl,diffl; + if(dVectorLimit(dBodyGetLinearVel(m_body),l_limit,limitedl)) + { + dVectorSub(diffl,limitedl,dBodyGetLinearVel(m_body)); + dBodySetLinearVel(m_body,diffl[0],diffl[1],diffl[2]); + dBodySetAngularVel(m_body,0.f,0.f,0.f); + dxStepBody(m_body,fixed_step); + dBodySetLinearVel(m_body,limitedl[0],limitedl[1],limitedl[2]); + } +} + +void CPHActivationShape:: set_rotation (const Fmatrix &sof) +{ + dMatrix3 rot;PHDynamicData::FMXtoDMX(sof,rot); + dBodySetRotation(ODEBody(),rot); + m_safe_state.set_rotation( rot ); +} + + + + +#ifdef DEBUG +IPhysicsShellHolder* CPHActivationShape::ref_object () +{ + VERIFY(m_geom); + dxGeomUserData* ud = retrieveGeomUserData( m_geom ); + VERIFY( ud ); + return ud->ph_ref_object; + +} +#endif \ No newline at end of file diff --git a/xrPhysics/PHActivationShape.h b/xrPhysics/PHActivationShape.h new file mode 100644 index 00000000000..4c607551110 --- /dev/null +++ b/xrPhysics/PHActivationShape.h @@ -0,0 +1,52 @@ +#ifndef PH_ACTIVATION_SHAPE +#define PH_ACTIVATION_SHAPE +#endif + +#include "phvalidevalues.h" +#include "PHObject.h" +class IPhysicsShellHolder; +class CPHActivationShape : public CPHObject +{ +dBodyID m_body ; +dGeomID m_geom ; +Flags16 m_flags ; +CSafeFixedRotationState m_safe_state ; + +#ifdef DEBUG +virtual IPhysicsShellHolder *ref_object (); +#endif + +public: +enum EType +{ + etBox, + etCylinder, + etSphere +}; + +enum { + flFixedRotation =1<<0, + flFixedPosition =1<<1, + flStaticEnvironment =1<<2, + flGravity =1<<3 + }; + CPHActivationShape () ; + ~CPHActivationShape () ; + void Create (const Fvector start_pos,const Fvector start_size,IPhysicsShellHolder* ref_obj,EType type=etBox,u16 flags=0) ; + void Destroy () ; + bool Activate (const Fvector need_size,u16 steps,float max_displacement,float max_rotation,bool un_freeze_later =false) ; +const Fvector &Position () ; + void Size (Fvector &size) ; + dBodyID ODEBody () {return m_body ;} + void set_rotation (const Fmatrix &rot) ; +private: +virtual void PhDataUpdate (dReal step) ; +virtual void PhTune (dReal step) ; +virtual void CutVelocity (float l_limit,float a_limit) ; +virtual void InitContact (dContact* c,bool& do_collide,u16 ,u16 ) ; +virtual dGeomID dSpacedGeom () ; +virtual void get_spatial_params () ; +virtual u16 get_elements_number () {return 0;} +virtual CPHSynchronize *get_element_sync (u16 element) {return NULL;} + +}; \ No newline at end of file diff --git a/xrPhysics/PHActorCharacter.cpp b/xrPhysics/PHActorCharacter.cpp new file mode 100644 index 00000000000..d641dbaf7ec --- /dev/null +++ b/xrPhysics/PHActorCharacter.cpp @@ -0,0 +1,427 @@ +#include "stdafx.h" +#include "phactorcharacter.h" +#include "Extendedgeom.h" +#include "PhysicsCommon.h" +//#include "GameObject.h" +#include "IPhysicsShellHolder.h" +//#include "ai/stalker/ai_stalker.h" +//#include "Actor.h" +#include "../xrEngine/gamemtllib.h" +//#include "level.h" + +//const float JUMP_HIGHT=0.5; +const float JUMP_UP_VELOCITY=6.0f;//5.6f; +const float JUMP_INCREASE_VELOCITY_RATE=1.2f; +//#ifdef DEBUG +//XRPHYSICS_API BOOL use_controllers_separation = TRUE; +//#endif +CPHActorCharacter::CPHActorCharacter( bool single_game ): b_single_game(single_game) +{ + SetRestrictionType(rtActor); + + //std::fill(m_restrictors_index,m_restrictors_index+CPHCharacter::rtNone,end(m_restrictors)); + //m_restrictors_index[CPHCharacter::rtStalker] =begin(m_restrictors)+0; + //m_restrictors_index[CPHCharacter::rtMonsterMedium] =begin(m_restrictors)+1; + + { + m_restrictors.resize(3); + m_restrictors[0]=(xr_new()); + m_restrictors[1]=xr_new(); + m_restrictors[2]=(xr_new()); + } +} + +CPHActorCharacter::~CPHActorCharacter(void) +{ + ClearRestrictors(); +} +static u16 slide_material_index = GAMEMTL_NONE_IDX; +void CPHActorCharacter::Create(dVector3 sizes) +{ + if(b_exist) return; + inherited::Create(sizes); + if(!b_single_game) + { + ClearRestrictors(); + } + RESTRICTOR_I i=begin(m_restrictors),e=end(m_restrictors); + for(;e!=i;++i) + { + (*i)->Create(this,sizes); + } + + if(m_phys_ref_object) + { + SetPhysicsRefObject(m_phys_ref_object); + } + if(slide_material_index == GAMEMTL_NONE_IDX) + { + GameMtlIt mi = GMLibrary().GetMaterialIt("materials\\earth_slide"); + if( mi != GMLibrary().LastMaterial ()) + slide_material_index =u16( mi - GMLibrary().FirstMaterial() ); + //slide_material_index = GMLibrary().GetMaterialIdx("earth_slide"); + } +} +void CPHActorCharacter:: ValidateWalkOn () +{ + + if( LastMaterialIDX( ) == slide_material_index ) + b_clamb_jump = false; + else + inherited::ValidateWalkOn(); +} +void SPHCharacterRestrictor::Create(CPHCharacter* ch,dVector3 sizes) +{ + VERIFY(ch); + if(m_character)return; + m_character=ch; + m_restrictor=dCreateCylinder(0,m_restrictor_radius,sizes[1]); + dGeomSetPosition(m_restrictor,0.f,sizes[1]/2.f,0.f); + m_restrictor_transform=dCreateGeomTransform(0); + dGeomTransformSetCleanup(m_restrictor_transform,0); + dGeomTransformSetInfo(m_restrictor_transform,1); + dGeomTransformSetGeom(m_restrictor_transform,m_restrictor); + dGeomCreateUserData(m_restrictor); + dGeomGetUserData(m_restrictor)->b_static_colide=false; + + dGeomSetBody(m_restrictor_transform,m_character->get_body()); + dSpaceAdd(m_character->dSpace(),m_restrictor_transform); + dGeomUserDataSetPhObject(m_restrictor,(CPHObject*)m_character); + switch(m_type) { + case rtStalker:static_cast(this)->Create(ch,sizes); + break; + case rtStalkerSmall:static_cast(this)->Create(ch,sizes); + break; + case rtMonsterMedium:static_cast(this)->Create(ch,sizes); + break; + default:NODEFAULT; + } + +} + +RESTRICTOR_I CPHActorCharacter::Restrictor(ERestrictionType rtype) +{ + R_ASSERT2(rtype0)(*Restrictor(rtype))->SetRadius(r); +} + +void SPHCharacterRestrictor::SetRadius(float r) +{ + m_restrictor_radius=r; + if(m_character) + { + float h; + dGeomCylinderGetParams(m_restrictor,&r,&h); + dGeomCylinderSetParams(m_restrictor,m_restrictor_radius,h); + } +} +void CPHActorCharacter::Destroy() +{ + if(!b_exist) return; + RESTRICTOR_I i=begin(m_restrictors),e=end(m_restrictors); + for(;e!=i;++i) + { + (*i)->Destroy(); + } + inherited::Destroy(); +} +void CPHActorCharacter::ClearRestrictors() +{ + RESTRICTOR_I i=begin(m_restrictors),e=end(m_restrictors); + for(;e!=i;++i) + { + (*i)->Destroy(); + xr_delete(*i); + } + m_restrictors.clear(); +} +void SPHCharacterRestrictor::Destroy() +{ + if(m_restrictor) { + dGeomDestroyUserData(m_restrictor); + dGeomDestroy(m_restrictor); + m_restrictor=NULL; + } + + if(m_restrictor_transform){ + dGeomDestroyUserData(m_restrictor_transform); + m_restrictor_transform=NULL; + } + m_character=NULL; +} +void CPHActorCharacter::SetPhysicsRefObject(IPhysicsShellHolder* ref_object) +{ + inherited::SetPhysicsRefObject(ref_object); + RESTRICTOR_I i=begin(m_restrictors),e=end(m_restrictors); + for(;e!=i;++i) + { + (*i)->SetPhysicsRefObject(ref_object); + } +} +void SPHCharacterRestrictor::SetPhysicsRefObject(IPhysicsShellHolder* ref_object) +{ + if(m_character) + dGeomUserDataSetPhysicsRefObject(m_restrictor,ref_object); +} +void CPHActorCharacter::SetMaterial (u16 material) +{ + inherited::SetMaterial(material); + if(!b_exist) return; + RESTRICTOR_I i=begin(m_restrictors),e=end(m_restrictors); + for(;e!=i;++i) + { + (*i)->SetMaterial(material); + } +} +void SPHCharacterRestrictor::SetMaterial(u16 material) +{ + dGeomGetUserData(m_restrictor)->material=material; +} +void CPHActorCharacter::SetAcceleration(Fvector accel) +{ + Fvector cur_a,input_a;float cur_mug,input_mug; + cur_a.set(m_acceleration);cur_mug=m_acceleration.magnitude(); + if(!fis_zero(cur_mug))cur_a.mul(1.f/cur_mug); + input_a.set(accel);input_mug=accel.magnitude(); + if(!fis_zero(input_mug))input_a.mul(1.f/input_mug); + if(!cur_a.similar(input_a,0.05f)||!fis_zero(input_mug-cur_mug,0.5f)) + inherited::SetAcceleration(accel); +} +bool CPHActorCharacter:: CanJump () +{ + return !b_lose_control && + LastMaterialIDX( ) != slide_material_index && + (m_ground_contact_normal[1]>0.5f + || + m_elevator_state.ClimbingState()); +} +void CPHActorCharacter::Jump(const Fvector& accel) +{ + if(!b_exist) return; + if(CanJump()) + { + b_jump=true; + const dReal* vel=dBodyGetLinearVel(m_body); + dReal amag =m_acceleration.magnitude(); + if(amag<1.f)amag=1.f; + if(m_elevator_state.ClimbingState()) + { + m_elevator_state.GetJumpDir(m_acceleration,m_jump_accel); + m_jump_accel.mul(JUMP_UP_VELOCITY/2.f); + //if(accel.square_magnitude()>EPS_L)m_jump_accel.mul(4.f); + } + else{ + m_jump_accel.set(vel[0]*JUMP_INCREASE_VELOCITY_RATE+m_acceleration.x/amag*0.2f,jump_up_velocity,vel[2]*JUMP_INCREASE_VELOCITY_RATE +m_acceleration.z/amag*0.2f); + } + Enable(); + } +} +void CPHActorCharacter::SetObjectContactCallback(ObjectContactCallbackFun* callback) +{ + inherited::SetObjectContactCallback(callback); + +} + +void CPHActorCharacter::Disable() +{ + inherited::Disable(); +} + + +struct SFindPredicate +{ + SFindPredicate(const dContact* ac,bool *b) + { + c=ac; + b1=b; + } + bool *b1 ; + const dContact *c ; + bool operator () (SPHCharacterRestrictor* o) + { + *b1=c->geom.g1==o->m_restrictor_transform; + return *b1||c->geom.g2==o->m_restrictor_transform; + } +}; + +static void BigVelSeparate(dContact* c,bool &do_collide) +{ + VERIFY( c ); +#ifdef DEBUG + //if( !use_controllers_separation ) + //return; +#endif + if(!do_collide) + return; + dxGeomUserData* dat1 = retrieveGeomUserData(c->geom.g1); + dxGeomUserData* dat2 = retrieveGeomUserData(c->geom.g2); + + if( !dat1 || !dat2 || + !dat1->ph_object || !dat2->ph_object || + dat1->ph_object->CastType() != CPHObject::tpCharacter || + dat2->ph_object->CastType() != CPHObject::tpCharacter + ) + return; + + //float spr = Spring( c->surface.soft_cfm,c->surface.soft_erp); + //float dmp = Damping( c->surface.soft_cfm,c->surface.soft_erp); + //spr *=0.001f; + //dmp *=10.f; + //float cfm = Cfm( spr, dmp ); + //float e = Erp( spr, dmp ); + c->surface.soft_cfm *= 100.f; + c->surface.soft_erp *=0.1f; + //MulSprDmp(c->surface.soft_cfm,c->surface.soft_erp ,0.1f,10); + + CPHCharacter* ch1 = static_cast(dat1->ph_object); + CPHCharacter* ch2 = static_cast(dat2->ph_object); + Fvector v1, v2; + ch1->GetVelocity(v1); + ch2->GetVelocity(v2); + if(v1.square_magnitude()<4.f && + v2.square_magnitude()<4.f + ) + return; + c->surface.mu =1.00f; + + dJointID contact_joint1 = dJointCreateContactSpecial(0, ContactGroup, c); + dJointID contact_joint2 = dJointCreateContactSpecial(0, ContactGroup, c); + + ch1->Enable(); + ch2->Enable(); + + dat1->ph_object->Island().DActiveIsland()->ConnectJoint(contact_joint1); + dat2->ph_object->Island().DActiveIsland()->ConnectJoint(contact_joint2); + + dJointAttach (contact_joint1, dGeomGetBody(c->geom.g1), 0); + + dJointAttach (contact_joint2, 0, dGeomGetBody(c->geom.g2)); + + do_collide=false; + +} + +void CPHActorCharacter::InitContact(dContact* c,bool &do_collide,u16 material_idx_1,u16 material_idx_2 ) +{ + + bool b1; + SFindPredicate fp(c,&b1); + RESTRICTOR_I r=std::find_if(begin(m_restrictors),end(m_restrictors),fp); + bool b_restrictor=(r!=end(m_restrictors)); + SGameMtl* material_1=GMLibrary().GetMaterialByIdx(material_idx_1); + SGameMtl* material_2=GMLibrary().GetMaterialByIdx(material_idx_2); + if((material_1&&material_1->Flags.test(SGameMtl::flActorObstacle))||(material_2&&material_2->Flags.test(SGameMtl::flActorObstacle))) + do_collide=true; + if(b_single_game) + { + + if(b_restrictor) + { + b_side_contact=true; + //MulSprDmp(c->surface.soft_cfm,c->surface.soft_erp,def_spring_rate,def_dumping_rate); + c->surface.mu =0.00f; + } + else + inherited::InitContact(c,do_collide,material_idx_1,material_idx_2); + if(b_restrictor&& + do_collide&& + !(b1 ? static_cast(retrieveGeomUserData(c->geom.g2)->ph_object)->ActorMovable():static_cast(retrieveGeomUserData(c->geom.g1)->ph_object)->ActorMovable()) + ) + { + dJointID contact_joint = dJointCreateContactSpecial(0, ContactGroup, c); + Enable(); + CPHObject::Island().DActiveIsland()->ConnectJoint(contact_joint); + if(b1) + dJointAttach (contact_joint, dGeomGetBody(c->geom.g1), 0); + else + dJointAttach (contact_joint, 0, dGeomGetBody(c->geom.g2)); + do_collide=false; + m_friction_factor*=0.1f; + + } + //BigVelSeparate( c, do_collide ); + } + else + { + + dxGeomUserData* D1=retrieveGeomUserData(c->geom.g1); + dxGeomUserData* D2=retrieveGeomUserData(c->geom.g2); + if(D1&&D2) + { + IPhysicsShellHolder* A1=(D1->ph_ref_object); + IPhysicsShellHolder* A2=(D2->ph_ref_object); + if( A1 && A2 && A1->IsActor() && A2->IsActor() ) + { + do_collide=do_collide&&!b_restrictor&&(A1->ObjectPPhysicsShell()==0)==(A2->ObjectPPhysicsShell()==0); + c->surface.mu=1.f; + } + } + + if(do_collide)inherited::InitContact(c,do_collide,material_idx_1,material_idx_2); + BigVelSeparate( c, do_collide ); + } +} + +void CPHActorCharacter::ChooseRestrictionType (ERestrictionType my_type,float my_depth,CPHCharacter *ch) +{ +if (my_type!=rtStalker||(ch->RestrictionType()!=rtStalker&&ch->RestrictionType()!=rtStalkerSmall))return; +float checkR=m_restrictors[rtStalkerSmall]->m_restrictor_radius;//1.5f;//+m_restrictors[rtStalker]->m_restrictor_radius)/2.f; + +switch(ch->RestrictionType()) +{ +case rtStalkerSmall: + if( ch->ObjectRadius() > checkR ) + { + //if(my_depth>0.05f) + ch->SetNewRestrictionType(rtStalker); + Enable(); + //else ch->SetRestrictionType(rtStalker); +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask1().test(ph_m1_DbgActorRestriction)) + Msg("restriction ready to change small -> large"); +#endif + } + break; +case rtStalker: + if( ch->ObjectRadius() < checkR ) + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask1().test(ph_m1_DbgActorRestriction)) + Msg("restriction change large -> small"); +#endif + ch->SetRestrictionType(rtStalkerSmall); + Enable(); + } + break; +default:NODEFAULT; +} + +} + +void CPHActorCharacter ::update_last_material() +{ + if( ignore_material( *p_lastMaterialIDX ) ) + inherited::update_last_material(); +} + +float free_fly_up_force_limit = 4000.f; +void CPHActorCharacter::PhTune( dReal step ) +{ + inherited::PhTune( step ); + if(b_lose_control&&!b_external_impulse)// + { + const float* force = dBodyGetForce( m_body ); + float fy = force[1]; + if(fy>free_fly_up_force_limit) + fy = free_fly_up_force_limit; + dBodySetForce(m_body, + force[0], + fy, + force[2] + ); + } +} \ No newline at end of file diff --git a/xrPhysics/PHActorCharacter.h b/xrPhysics/PHActorCharacter.h new file mode 100644 index 00000000000..2d66ea1c928 --- /dev/null +++ b/xrPhysics/PHActorCharacter.h @@ -0,0 +1,122 @@ +#pragma once +#include "phsimplecharacter.h" +#include "PHActorCharacterInline.h" + +class CPhysicShellHolder; +struct SPHCharacterRestrictor +{ + SPHCharacterRestrictor (ERestrictionType Ttype) + { + m_type=Ttype; + m_character=NULL; + m_restrictor=NULL; + m_restrictor_transform=NULL; + m_restrictor_radius=0.1f; + } + ~SPHCharacterRestrictor () + { + Destroy(); + }; + CPHCharacter* m_character; + ERestrictionType m_type; + + dGeomID m_restrictor; + dGeomID m_restrictor_transform; + float m_restrictor_radius; + void SetObjectContactCallback (ObjectContactCallbackFun* callback); + void SetMaterial (u16 material); + void Create (CPHCharacter* ch,dVector3 sizes); + void Destroy (void); + void SetPhysicsRefObject (IPhysicsShellHolder* ref_object); + void SetRadius (float r); +}; + +template +struct TPHCharacterRestrictor : public SPHCharacterRestrictor +{ + TPHCharacterRestrictor():SPHCharacterRestrictor(Ttype){} + void Create(CPHCharacter* ch,dVector3 sizes) + { + dGeomUserDataSetObjectContactCallback(m_restrictor,RestrictorCallBack); + } +static void RestrictorCallBack (bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2) + { + do_colide=false; + dBodyID b1 = dGeomGetBody(c.geom.g1); + dBodyID b2 = dGeomGetBody(c.geom.g2); + if(!(b1&&b2)) return; + dxGeomUserData *ud1 = retrieveGeomUserData(c.geom.g1); + dxGeomUserData *ud2 = retrieveGeomUserData(c.geom.g2); + if(!(ud1&&ud2))return; + + CPHObject *o1 = NULL;if(ud1)o1=ud1->ph_object; + CPHObject *o2 = NULL;if(ud2)o2=ud2->ph_object; + if(!(o1&&o2)) return; + if(o1->CastType()!=CPHObject::tpCharacter||o2->CastType()!=CPHObject::tpCharacter) return; + + CPHCharacter* ch1 = static_cast(o1); + CPHCharacter* ch2 = static_cast(o2); + + if(bo1) + { + ch1 -> ChooseRestrictionType(Ttype,c.geom.depth,ch2); + do_colide = ch2->TouchRestrictor(Ttype); + } + else + { + ch2 -> ChooseRestrictionType(Ttype,c.geom.depth,ch1); + do_colide = ch1->TouchRestrictor(Ttype); + } + } + }; +DEFINE_VECTOR(SPHCharacterRestrictor*,RESRICTORS_V,RESTRICTOR_I); +//typedef SPHCharacterRestrictor* RESRICTORS_V[2]; +//typedef SPHCharacterRestrictor** RESTRICTOR_I; +IC RESTRICTOR_I begin(RESRICTORS_V& v) +{ + //return v; + return v.begin(); +} + +IC RESTRICTOR_I end(RESRICTORS_V& v) +{ + //return v+sizeof(RESRICTORS_V)/sizeof(SPHCharacterRestrictor*); + return v.end(); +} + +class CPHActorCharacter : + public CPHSimpleCharacter +{ + typedef CPHSimpleCharacter inherited; + + RESRICTORS_V m_restrictors; + float m_speed_goal; + bool b_single_game; +public: + typedef TPHCharacterRestrictor stalker_restrictor; + typedef TPHCharacterRestrictor stalker_small_restrictor; + typedef TPHCharacterRestrictor medium_monster_restrictor; +public: + virtual CPHActorCharacter *CastActorCharacter (){return this;} + virtual void SetObjectContactCallback (ObjectContactCallbackFun* callback); + virtual void SetMaterial (u16 material); + virtual void Create (dVector3 sizes); + virtual void Destroy (void); + virtual void SetPhysicsRefObject (IPhysicsShellHolder* ref_object); + virtual void SetAcceleration (Fvector accel); + virtual void Disable (); + virtual void Jump (const Fvector& jump_velocity); + virtual void InitContact (dContact* c,bool &do_collide,u16 material_idx_1 ,u16 material_idx_2); + virtual void SetRestrictorRadius (ERestrictionType rtype,float r); +virtual void ChooseRestrictionType (ERestrictionType my_type,float my_depth,CPHCharacter *ch); + CPHActorCharacter ( bool single_game ); + virtual ~CPHActorCharacter (void); +private: + virtual void ValidateWalkOn (); + bool CanJump (); + virtual void update_last_material (); + virtual void PhTune ( dReal step ); +private: + void ClearRestrictors (); + RESTRICTOR_I Restrictor (ERestrictionType rtype); +}; diff --git a/xrPhysics/PHActorCharacterInline.h b/xrPhysics/PHActorCharacterInline.h new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/xrPhysics/PHActorCharacterInline.h @@ -0,0 +1 @@ + diff --git a/xrPhysics/PHBaseBodyEffector.h b/xrPhysics/PHBaseBodyEffector.h new file mode 100644 index 00000000000..7423b89e715 --- /dev/null +++ b/xrPhysics/PHBaseBodyEffector.h @@ -0,0 +1,16 @@ +#ifndef PH_BASE_BODY_EFFECTOR_H +#define PH_BASE_BODY_EFFECTOR_H + +//#include "ode_include.h" +#include "../3rd party/ode/include/ode/common.h" +class CPHBaseBodyEffector +{ +protected: + dBodyID m_body; +public: + void Init(dBodyID body) + { + m_body=body; + } +}; +#endif \ No newline at end of file diff --git a/xrPhysics/PHCapture.cpp b/xrPhysics/PHCapture.cpp new file mode 100644 index 00000000000..115691ce28f --- /dev/null +++ b/xrPhysics/PHCapture.cpp @@ -0,0 +1,400 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +#include "StdAfx.h" + +#include "PHCapture.h" +#include "phcharacter.h" +#include "Physics.h" +#include "ExtendedGeom.h" + +//#include "entity_alive.h" +//#include "phmovementcontrol.h" +#include "../Include/xrRender/Kinematics.h" +#include "iphysicsshellholder.h" +#include "../xrengine/bone.h" +#include "../xrengine/device.h" +#include "mathutilsode.h" +#include "phelement.h" + +//#include "characterphysicssupport.h" +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +IPHCapture *phcapture_create(CPHCharacter *ch, IPhysicsShellHolder* object, NearestToPointCallback* cb /*=0*/ ) +{ +//m_capture=xr_new(m_character, +// object, +// cb +// ); + VERIFY( ch ); + //VERIFY( object ); + //VERIFY( cb ); + return xr_new(ch, + object, + cb + ); +} +IPHCapture *phcapture_create(CPHCharacter *ch, IPhysicsShellHolder* object,u16 element) +{ + VERIFY( ch ); + return xr_new(ch, + object, + element + ); +} +void phcapture_destroy(IPHCapture* &c) +{ + CPHCapture* capture = smart_cast(c); + xr_delete(capture); + c = 0; +} + +void CPHCapture::CreateBody() +{ + m_body= dBodyCreate(0); + m_island.AddBody(m_body); + dMass m; + dMassSetSphere(&m,1.f,1000000.f); + dMassAdjust(&m,100000.f); + dBodySetMass(m_body,&m); + dBodySetGravityMode(m_body,0); +} + +CPHCapture::~CPHCapture() +{ + Deactivate(); +} + +bool CPHCapture::Invalid() +{ + return + !m_taget_object->ObjectPPhysicsShell()|| + !m_taget_object->ObjectPPhysicsShell()->isActive()|| + !m_character->b_exist; +} + +void CPHCapture::PhDataUpdate(dReal /**step/**/) +{ + + switch(e_state) + { + case cstFree: + break; + case cstPulling: PullingUpdate(); + break; + case cstCaptured: CapturedUpdate(); + break; + case cstReleased: ReleasedUpdate(); + break; + default: NODEFAULT; + } +} + +void CPHCapture::PhTune(dReal /**step/**/) +{ + if(e_state == cstFree) + return; + + //if(!m_taget_object->PPhysicsShell()) { + // b_failed=true; + // return; //. hack + //} + VERIFY(m_character && m_character->b_exist); + VERIFY(m_taget_object); + VERIFY(m_taget_object->ObjectPPhysicsShell()); + VERIFY(m_taget_object->ObjectPPhysicsShell()->isFullActive()); + VERIFY( m_taget_element ); + VERIFY( m_taget_element->isFullActive()); + VERIFY( m_island.DActiveIsland() == &m_island ); + + bool act_capturer=m_character->CPHObject::is_active(); + bool act_taget=m_taget_object->ObjectPPhysicsShell()->isEnabled(); + + b_disabled=!act_capturer&&!act_taget; + if(act_capturer) + { + m_taget_element->Enable(); + } + if(act_taget) + { + m_character->Enable(); + } + switch(e_state) + { + case cstPulling: ; + break; + case cstCaptured: + { + if(b_disabled) + dBodyDisable(m_body); + else + { + m_character->Island().Merge(&m_island); + m_taget_element->PhysicsShell()->PIsland()->Merge(&m_island); + VERIFY(!m_island.IsActive()); + } + } + break; + case cstReleased: ; + break; + default: NODEFAULT; + } + +} + +void CPHCapture::PullingUpdate() +{ + if(!m_taget_element->isActive()||inl_ph_world().Device().dwTimeGlobal-m_time_start>m_capture_time) + { + Release(); + return; + } + + Fvector dir; + Fvector capture_bone_position; + //CObject* object=smart_cast(m_character->PhysicsRefObject()); + capture_bone_position.set(m_capture_bone->mTransform.c); + m_character->PhysicsRefObject()->ObjectXFORM().transform_tiny(capture_bone_position); + m_taget_element->GetGlobalPositionDynamic(&dir); + dir.sub(capture_bone_position,dir); + float dist=dir.magnitude(); + if(dist>m_pull_distance) + { + Release(); + return; + } + dir.mul(1.f/dist); + if(dist(m_taget_element) ); + CPHElement * e = static_cast(m_taget_element); + dJointAttach(m_joint,m_body,e->get_body()); + dJointAttach(m_ajoint,m_body,e->get_body()); + dJointSetFeedback (m_joint, &m_joint_feedback); + dJointSetFeedback (m_ajoint, &m_joint_feedback); + dJointSetBallAnchor(m_joint,capture_bone_position.x,capture_bone_position.y,capture_bone_position.z); + + + dJointSetAMotorAxis (m_ajoint, 0, 1, dir.x, dir.y, dir.z); + + if(dir.x>EPS) + { + if(dir.y>EPS) + { + float mag=dir.x*dir.x+dir.y*dir.y; + dJointSetAMotorAxis (m_ajoint, 2, 2, -dir.y/mag, dir.x/mag, 0.f); + } + else if(dir.z>EPS) + { + float mag=dir.x*dir.x+dir.z*dir.z; + dJointSetAMotorAxis (m_ajoint, 2, 2, -dir.z/mag,0.f,dir.x/mag); + } + else + { + dJointSetAMotorAxis (m_ajoint, 2, 2, 1.f,0.f,0.f); + } + } + else + { + if(dir.y>EPS) + { + + if(dir.z>EPS) + { + float mag=dir.y*dir.y+dir.z*dir.z; + dJointSetAMotorAxis (m_ajoint, 2, 2,0.f,-dir.z/mag,dir.y/mag); + } + else + { + dJointSetAMotorAxis (m_ajoint, 2, 2, 0.f,1.f,0.f); + } + } + else + { + dJointSetAMotorAxis (m_ajoint, 2, 2, 0.f,0.f,1.f); + } + } + //float hi=-M_PI/2.f,lo=-hi; + //dJointSetAMotorParam(m_ajoint,dParamLoStop ,lo); + //dJointSetAMotorParam(m_ajoint,dParamHiStop ,hi); + //dJointSetAMotorParam(m_ajoint,dParamLoStop2 ,lo); + //dJointSetAMotorParam(m_ajoint,dParamHiStop2 ,hi); + //dJointSetAMotorParam(m_ajoint,dParamLoStop3 ,lo); + //dJointSetAMotorParam(m_ajoint,dParamHiStop3 ,hi); + + + dJointSetAMotorParam(m_ajoint,dParamFMax ,m_capture_force*0.2f); + dJointSetAMotorParam(m_ajoint,dParamVel ,0.f); + + dJointSetAMotorParam(m_ajoint,dParamFMax2 ,m_capture_force*0.2f); + dJointSetAMotorParam(m_ajoint,dParamVel2 ,0.f); + + dJointSetAMotorParam(m_ajoint,dParamFMax3 ,m_capture_force*0.2f); + dJointSetAMotorParam(m_ajoint,dParamVel3 ,0.f); + + +/////////////////////////////////// + float sf=0.1f,df=10.f; + + float erp=ERP(world_spring*sf,world_damping*df); + float cfm=CFM(world_spring*sf,world_damping*df); + dJointSetAMotorParam(m_ajoint,dParamStopERP ,erp); + dJointSetAMotorParam(m_ajoint,dParamStopCFM ,cfm); + + dJointSetAMotorParam(m_ajoint,dParamStopERP2 ,erp); + dJointSetAMotorParam(m_ajoint,dParamStopCFM2 ,cfm); + + dJointSetAMotorParam(m_ajoint,dParamStopERP3 ,erp); + dJointSetAMotorParam(m_ajoint,dParamStopCFM3 ,cfm); + ///////////////////////////////////////////////////////////////////// + ///dJointSetAMotorParam(m_joint1,dParamFudgeFactor ,0.1f); + //dJointSetAMotorParam(m_joint1,dParamFudgeFactor2 ,0.1f); + //dJointSetAMotorParam(m_joint1,dParamFudgeFactor3 ,0.1f); + ///////////////////////////////////////////////////////////////////////////// + sf=0.1f,df=10.f; + erp=ERP(world_spring*sf,world_damping*df); + cfm=CFM(world_spring*sf,world_damping*df); + dJointSetAMotorParam(m_ajoint,dParamCFM ,cfm); + dJointSetAMotorParam(m_ajoint,dParamCFM2 ,cfm); + dJointSetAMotorParam(m_ajoint,dParamCFM3 ,cfm); + + +/////////////////////////// + + //dJointSetAMotorParam(m_ajoint,dParamLoStop ,0.f); + //dJointSetAMotorParam(m_ajoint,dParamHiStop ,0.f); + m_taget_element->set_LinearVel ( Fvector().set( 0 ,0, 0 ) ); + m_taget_element->set_AngularVel( Fvector().set( 0 ,0, 0 ) ); + + + m_taget_element->set_DynamicLimits(); + //m_taget_object->PPhysicsShell()->set_JointResistance() + e_state=cstCaptured; + return; + } + m_taget_element->applyForce(dir,m_pull_force); +} + +void CPHCapture::CapturedUpdate() +{ + m_island.Unmerge(); + if(m_character->CPHObject::is_active()) + { + m_taget_element->Enable(); + } + + if(!m_taget_element->isActive()||dDOT(m_joint_feedback.f2,m_joint_feedback.f2)>m_capture_force*m_capture_force) + { + Release(); + return; + } + + float mag=dSqrt(dDOT(m_joint_feedback.f1,m_joint_feedback.f1)); + + //m_back_force=m_back_force*0.999f+ ((magm_capture_force/2.2f) + { + float f=mag/(m_capture_force/15.f); + m_character->ApplyForce(m_joint_feedback.f1[0]/f,m_joint_feedback.f1[1]/f,m_joint_feedback.f1[2]/f); + } + + Fvector capture_bone_position; + //CObject* object=smart_cast(m_character->PhysicsRefObject()); + capture_bone_position.set(m_capture_bone->mTransform.c); + m_character->PhysicsRefObject()->ObjectXFORM().transform_tiny(capture_bone_position); + dBodySetPosition(m_body,capture_bone_position.x,capture_bone_position.y,capture_bone_position.z); +} + +void CPHCapture::ReleasedUpdate() +{ + if(b_disabled) return; + if(!b_collide) + { + e_state=cstFree; + m_taget_element->Enable(); + } + b_collide=false; +} + +void CPHCapture::ReleaseInCallBack() +{ + // if(!b_failed) return; + b_collide=true; +} + + +void CPHCapture::object_contactCallbackFun(bool& do_colide,bool bo1,dContact& c,SGameMtl * /*material_1*/,SGameMtl * /*material_2*/) +{ + + dxGeomUserData *l_pUD1 = NULL; + dxGeomUserData *l_pUD2 = NULL; + l_pUD1 = retrieveGeomUserData(c.geom.g1); + l_pUD2 = retrieveGeomUserData(c.geom.g2); + + if(! l_pUD1) return; + if(!l_pUD2) return; + + //CEntityAlive* capturer=smart_cast(l_pUD1->ph_ref_object); + IPhysicsShellHolder* capturer=(l_pUD1->ph_ref_object); + if(capturer) + { + IPHCapture* icapture=capturer->PHCapture(); + CPHCapture* capture = static_cast(icapture); + if(capture) + { + if(capture->m_taget_element->PhysicsRefObject()==l_pUD2->ph_ref_object) + { + do_colide = false; + capture->m_taget_element->Enable(); + if(capture->e_state==CPHCapture::cstReleased) + capture->ReleaseInCallBack(); + } + + } + + + } + + capturer=l_pUD2->ph_ref_object; + if(capturer) + { + CPHCapture* capture=static_cast(capturer->PHCapture()); + if(capture) + { + if(capture->m_taget_element->PhysicsRefObject()==l_pUD1->ph_ref_object) + { + do_colide = false; + capture->m_taget_element->Enable(); + if(capture->e_state==CPHCapture::cstReleased) + capture->ReleaseInCallBack(); + } + + } + + } +} +void CPHCapture::RemoveConnection(IPhysicsShellHolder* O) +{ + if( m_taget_object==O ) + { + Deactivate(); + } +} + +void CPHCapture::NetRelcase (CPhysicsShell *s) +{ + VERIFY( s ); + VERIFY( s->get_ElementByStoreOrder(0) ); + VERIFY( s->get_ElementByStoreOrder(0)->PhysicsRefObject() ); + RemoveConnection(s->get_ElementByStoreOrder(0)->PhysicsRefObject()); +} \ No newline at end of file diff --git a/xrPhysics/PHCapture.h b/xrPhysics/PHCapture.h new file mode 100644 index 00000000000..9b05c7bf830 --- /dev/null +++ b/xrPhysics/PHCapture.h @@ -0,0 +1,80 @@ +#pragma once +#ifndef PH_CAPTURE_H +#define PH_CAPTURE_H + +//#include "phobject.h" +#include "phupdateobject.h" +//#include "gameobject.h" +//#include "physicsshellholder.h" +#include "phisland.h" +#include "../3rd party/ode/include/ode/common.h" +#include "iphcapture.h" +class IPhysicsShellHolder; +class CPHCharacter; +class CPhysicsElement; +struct NearestToPointCallback; +class CPHCapture : + public CPHUpdateObject, + public IPHCapture +{ +public: + CPHCapture (CPHCharacter *a_character,IPhysicsShellHolder *a_taget_object, NearestToPointCallback* cb /*=0*/); + CPHCapture (CPHCharacter *a_character,IPhysicsShellHolder *a_taget_object,u16 a_taget_elemrnt); +virtual ~CPHCapture (); + +bool Failed (){return e_state == cstFree;} + +void Release (); +void RemoveConnection(IPhysicsShellHolder* O); + +protected: +CPHCharacter *m_character; +CPhysicsElement* m_taget_element; +IPhysicsShellHolder* m_taget_object; +dJointID m_joint; +dJointID m_ajoint; +dJointFeedback m_joint_feedback; +Fvector m_capture_pos; +float m_back_force; +float m_pull_force; +float m_capture_force; +float m_capture_distance; +float m_pull_distance; +u32 m_capture_time; +u32 m_time_start; +CBoneInstance *m_capture_bone; +dBodyID m_body; +CPHIsland m_island; +//bool b_failed; +bool b_collide; +bool b_disabled; +bool b_character_feedback; + +private: + enum + { + cstPulling, + cstCaptured, + cstReleased, + cstFree, + cstFailed + } e_state; + + void PullingUpdate(); + void CapturedUpdate(); + void ReleasedUpdate(); + void ReleaseInCallBack(); + void Init( ); + + void Deactivate(); + void CreateBody(); + bool Invalid(); +static void object_contactCallbackFun(bool& do_colide,bool bo1,dContact& c,SGameMtl* /*material_1*/,SGameMtl* /*material_2*/); + +///////////CPHObject///////////////////////////// + virtual void PhDataUpdate(dReal step); + virtual void PhTune(dReal step); + virtual void NetRelcase (CPhysicsShell *s); + +}; +#endif \ No newline at end of file diff --git a/xrPhysics/PHCaptureInit.cpp b/xrPhysics/PHCaptureInit.cpp new file mode 100644 index 00000000000..209582c504f --- /dev/null +++ b/xrPhysics/PHCaptureInit.cpp @@ -0,0 +1,309 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +#include "StdAfx.h" +#include "phcharacter.h" +#include "Physics.h" +#include "ExtendedGeom.h" +#include "PHCapture.h" +//#include "Entity.h" +//#include "inventory_item.h" +#include "../Include/xrRender/Kinematics.h" +//#include "Actor.h" +//#include "Inventory.h" +//#include "CaptureBoneCallback.h" +#include "iphysicsshellholder.h" +#include "../xrengine/bone.h" +#include "../xrengine/device.h" +extern class CPHWorld *ph_world; +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +bool can_capture( CPHCharacter *a_character, IPhysicsShellHolder *a_taget_object ) +{ + if(!a_taget_object || + !a_taget_object->ObjectPPhysicsShell() || + !a_taget_object->ObjectPPhysicsShell()->isActive() || + a_taget_object->IsInventoryItem() || + !a_character || + !a_character->b_exist || + !a_character->PhysicsRefObject() || + //!a_character->PhysicsRefObject()->ObjectVisual( ) + !a_character->PhysicsRefObject()->ObjectKinematics( ) + ) return false; + + //IKinematics* p_kinematics = smart_cast( a_character->PhysicsRefObject()->ObjectVisual( ) ); + IKinematics* p_kinematics = a_character->PhysicsRefObject()->ObjectKinematics( ) ; + VERIFY( p_kinematics ); + CInifile* ini = p_kinematics->LL_UserData(); + if(!ini || + !ini->section_exist( "capture" ) + ) return false; + return true; +} + +bool can_capture( CPHCharacter *a_character, IPhysicsShellHolder *a_taget_object, u16 a_taget_element ) +{ + + if( !can_capture( a_character, a_taget_object) || + a_taget_element == BI_NONE || + //!a_taget_object->ObjectVisual() + !a_taget_object->ObjectKinematics() + ) return false; + + //IKinematics* K= smart_cast( a_taget_object->ObjectVisual( ) ); + IKinematics* K= a_taget_object->ObjectKinematics( ) ; + + if(!K || !K->LL_GetBoneInstance(a_taget_element).callback_param() ) + return false; + return true; +} + +static CBoneInstance * get_capture_bone( CPHCharacter *a_character ) +{ + VERIFY( a_character ); + VERIFY( a_character->PhysicsRefObject() ); + //IKinematics* p_kinematics = smart_cast( a_character->PhysicsRefObject()->ObjectVisual( ) ); + IKinematics* p_kinematics = a_character->PhysicsRefObject()->ObjectKinematics( ) ; + VERIFY( p_kinematics ); + CInifile* ini = p_kinematics->LL_UserData(); + VERIFY( ini ); + VERIFY( ini->section_exist( "capture" ) ); + u16 capture_bone_id =p_kinematics->LL_BoneID( ini->r_string( "capture", "bone" ) ); + + R_ASSERT2( capture_bone_id != BI_NONE, "wrong capture bone" ); + + return &p_kinematics->LL_GetBoneInstance( capture_bone_id ); + +} + +/* +CPHCharacter *m_character; +CPhysicsElement* m_taget_element; +IPhysicsShellHolder* m_taget_object; +dJointID m_joint; +dJointID m_ajoint; +dJointFeedback m_joint_feedback; +Fvector m_capture_pos; +float m_back_force; +float m_pull_force; +float m_capture_force; +float m_capture_distance; +float m_pull_distance; +u32 m_capture_time; +u32 m_time_start; +CBoneInstance *m_capture_bone; +dBodyID m_body; +CPHIsland m_island; +//bool b_failed; +bool b_collide; +bool b_disabled; +bool b_character_feedback; +*/ + +CPHCapture::CPHCapture ( CPHCharacter *a_character, IPhysicsShellHolder *a_taget_object, NearestToPointCallback* cb /*=0*/ ): + m_joint ( NULL ) , + m_ajoint ( NULL ) , + m_body ( NULL ) , + m_taget_object ( a_taget_object ) , + m_character ( a_character ) , + b_disabled ( false ) , + b_character_feedback ( false ) , + e_state ( cstFree ) , +/////////////////////////////////////////////////////////////// + m_taget_element (0) , + //dJointFeedback m_joint_feedback; , + m_capture_pos (Fvector().set(0,0,0)) , + m_back_force ( 0 ) , + m_pull_force ( 0 ) , + m_capture_force ( 0 ) , + m_capture_distance ( 0 ) , + m_capture_time ( 0 ) , + m_time_start ( 0 ) , + m_capture_bone ( 0 ) , + //CPHIsland m_island; + b_collide ( false ) + +{ + if( !can_capture( a_character, a_taget_object) ) + return; + + VERIFY( m_taget_object ); + VERIFY( m_taget_object->ObjectPPhysicsShell() ); + VERIFY( a_character ); + m_capture_bone =get_capture_bone( a_character ); + VERIFY( m_capture_bone ); + m_taget_element =m_taget_object->ObjectPPhysicsShell()->NearestToPoint( m_capture_bone->mTransform.c, cb ); + if( ! m_taget_element ) + return; + Init( ); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + CPHCapture::CPHCapture(CPHCharacter *a_character,IPhysicsShellHolder *a_taget_object,u16 a_taget_element): + m_joint ( NULL ) , + m_ajoint ( NULL ) , + m_body ( NULL ) , + b_disabled ( false ) , + b_character_feedback ( false ) , + m_taget_object ( a_taget_object ) , + m_character ( a_character ) , + e_state ( cstFree ) , + +/////////////////////////////////////////////////////////////// + m_taget_element (0) , + //dJointFeedback m_joint_feedback; , + m_capture_pos (Fvector().set(0,0,0)) , + m_back_force ( 0 ) , + m_pull_force ( 0 ) , + m_capture_force ( 0 ) , + m_capture_distance ( 0 ) , + m_capture_time ( 0 ) , + m_time_start ( 0 ) , + m_capture_bone ( 0 ) , + //CPHIsland m_island; + b_collide ( false ) + + +{ + + if( !can_capture( a_character, a_taget_object, a_taget_element ) ) + return; + VERIFY( m_taget_object ); + VERIFY( a_character ); + m_capture_bone =get_capture_bone( a_character ) ; + + //IRenderVisual* V=m_taget_object->ObjectVisual( ); + //VERIFY( V ); + + //IKinematics* K= smart_cast( m_taget_object->ObjectVisual( ) ); + IKinematics* K= m_taget_object->ObjectKinematics( ) ; + VERIFY( K ); + + CBoneInstance& tag_bone=K->LL_GetBoneInstance( a_taget_element ); + VERIFY( tag_bone.callback_param( ) ); + + m_taget_element =(CPhysicsElement*)tag_bone.callback_param(); + VERIFY( m_taget_element ); + + Init( ); +} + +void CPHCapture::Init( ) +{ + VERIFY( m_taget_element ); + VERIFY( m_character ); + VERIFY( m_character->PhysicsRefObject() ); + //VERIFY( m_character->PhysicsRefObject()->ObjectVisual( ) ); + VERIFY( m_character->PhysicsRefObject()->ObjectKinematics( ) ); + VERIFY( m_capture_bone ); + + //IKinematics* p_kinematics = smart_cast( m_character->PhysicsRefObject()->ObjectVisual( ) ); + IKinematics* p_kinematics = m_character->PhysicsRefObject()->ObjectKinematics( ) ; + VERIFY( p_kinematics ); + CInifile * ini = p_kinematics->LL_UserData(); + VERIFY( ini ); + + Fvector dir; + Fvector capture_bone_position; + capture_bone_position.set(m_capture_bone->mTransform.c); + b_character_feedback=true; + (m_character->PhysicsRefObject())->ObjectXFORM().transform_tiny(capture_bone_position); + + m_taget_element->GetGlobalPositionDynamic(&dir); + dir.sub(capture_bone_position,dir); + + m_pull_distance=ini->r_float("capture","pull_distance"); + if(dir.magnitude()>m_pull_distance) + return; + + float pool_force_factor=4.f; + m_capture_distance =ini->r_float("capture","distance"); //distance + m_capture_force =ini->r_float("capture","capture_force"); //capture force + m_capture_time =ini->r_u32("capture","time_limit")*1000; //time; + m_time_start =inl_ph_world().Device().dwTimeGlobal; + float max_pull_force =ini->r_float("capture","pull_force"); //pull force + m_pull_force =pool_force_factor*ph_world->Gravity()*m_taget_element->PhysicsShell()->getMass(); + if(m_pull_force>max_pull_force) + m_pull_force=max_pull_force; + float pulling_vel_scale =ini->r_float("capture","velocity_scale"); // + + m_taget_element->set_DynamicLimits(default_l_limit*pulling_vel_scale,default_w_limit*pulling_vel_scale); + //m_taget_element->PhysicsShell()->set_ObjectContactCallback(object_contactCallbackFun); + m_character->SetObjectContactCallback(object_contactCallbackFun); + m_island.Init(); + //CActor* A=smart_cast(m_character->PhysicsRefObject()); + IPhysicsShellHolder* A=(m_character->PhysicsRefObject()); + if(A->IsActor()) + { + //A->SetWeaponHideState(INV_STATE_BLOCK_ALL,true); + A->HideAllWeapons(true); + } + CPHUpdateObject::Activate(); + e_state = cstPulling; +} + +void CPHCapture::Release() +{ + if( e_state==cstReleased || e_state== cstFree ) + return; + VERIFY( m_island.DActiveIsland() == &m_island ); + + if( m_joint ) + { + m_island.RemoveJoint(m_joint); + dJointDestroy(m_joint); + } + m_joint=NULL; + if( m_ajoint ) + { + m_island.RemoveJoint( m_ajoint ); + dJointDestroy(m_ajoint); + } + m_ajoint=NULL; + + if(m_body) + { + m_island.RemoveBody( m_body ); + dBodyDestroy(m_body); + } + m_body=NULL; + + if(e_state==cstPulling&&m_taget_element&&!m_taget_object->ObjectGetDestroy()&&m_taget_object->ObjectPPhysicsShell()&&m_taget_object->ObjectPPhysicsShell()->isActive()) + { + m_taget_element->set_DynamicLimits(); + } + + b_collide=true; + //CActor* A=smart_cast(m_character->PhysicsRefObject()); + IPhysicsShellHolder* A=(m_character->PhysicsRefObject()); + if(A) + { + A->HideAllWeapons(false); + //A->SetWeaponHideState(INV_STATE_BLOCK_ALL,false); +//. A->inventory().setSlotsBlocked(false); + } + + e_state=cstReleased; +} +#include "phelement.h" +void CPHCapture::Deactivate() +{ + + Release(); + if(m_taget_element) + { + VERIFY(dynamic_cast(m_taget_element)); + + m_taget_element->Enable(); + } + //if(m_taget_object&&m_taget_element&&!m_taget_object->getDestroy()&&m_taget_object->m_pPhysicsShell&&m_taget_object->m_pPhysicsShell->isActive()) + //{ + // m_taget_element->set_ObjectContactCallback(0); + + //} + if(m_character) + m_character->SetObjectContactCallback(0); + CPHUpdateObject::Deactivate(); + e_state =cstFree; + m_character =NULL; + m_taget_object =NULL; + m_taget_element =NULL; +} \ No newline at end of file diff --git a/xrPhysics/PHCharacter.cpp b/xrPhysics/PHCharacter.cpp new file mode 100644 index 00000000000..8c8f1627e22 --- /dev/null +++ b/xrPhysics/PHCharacter.cpp @@ -0,0 +1,243 @@ +#include "stdafx.h" + +#include "phcharacter.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "ExtendedGeom.h" +#include "iphysicsshellholder.h" + +#include "../xrEngine/cl_intersect.h" +#include "../xrEngine/gamemtllib.h" + +#include "tri-colliderKNoOPC\__aabb_tri.h" +#include "../3rd party/ode/ode/src/util.h" +#include "ph_valid_ode.h" +#include "Phaicharacter.h" +#include "phactorcharacter.h" + +CPHCharacter::CPHCharacter(void): + CPHDisablingTranslational() +{ + +m_params.acceleration =0.001f ; +m_params.velocity =0.0001f ; +m_body =NULL ; +m_safe_velocity[0] =0.f ; +m_safe_velocity[1] =0.f ; +m_safe_velocity[2] =0.f ; +m_mean_y =0.f ; +m_new_restriction_type=m_restriction_type =rtNone ; +b_actor_movable =true ; +p_lastMaterialIDX =&lastMaterialIDX ; +lastMaterialIDX =GAMEMTL_NONE_IDX ; +injuriousMaterialIDX =GAMEMTL_NONE_IDX ; +m_creation_step =u64(-1) ; +b_in_touch_resrtrictor =false ; +m_current_object_radius =-1.f ; +} + +CPHCharacter::~CPHCharacter(void) +{ + +} + +void CPHCharacter::FreezeContent() +{ + + dBodyDisable(m_body); + CPHObject::FreezeContent(); +} +void CPHCharacter::UnFreezeContent() +{ + + dBodyEnable(m_body); + CPHObject::UnFreezeContent(); +} +void CPHCharacter::getForce(Fvector& force) +{ + if(!b_exist)return; + force.set(*(Fvector*)dBodyGetForce(m_body)); +} +void CPHCharacter::setForce(const Fvector &force) +{ + if(!b_exist)return; + dBodySetForce(m_body,force.x,force.y,force.z); +} + + +void CPHCharacter::get_State(SPHNetState& state) +{ + GetPosition(state.position); + m_body_interpolation.GetPosition(state.previous_position,0); + GetVelocity(state.linear_vel); + getForce(state.force); + + state.angular_vel.set(0.f,0.f,0.f); + state.quaternion.identity(); + state.previous_quaternion.identity(); + state.torque.set(0.f,0.f,0.f); +// state.accel = GetAcceleration(); +// state.max_velocity = GetMaximumVelocity(); + + if(!b_exist) + { + state.enabled=false; + return; + } + state.enabled=CPHObject::is_active();//!!dBodyIsEnabled(m_body); +} +void CPHCharacter::set_State(const SPHNetState& state) +{ + m_body_interpolation.SetPosition(state.previous_position,0); + m_body_interpolation.SetPosition(state.position,1); + SetPosition(state.position); + SetVelocity(state.linear_vel); + setForce(state.force); + +// SetAcceleration(state.accel); +// SetMaximumVelocity(state.max_velocity); + + if(!b_exist) return; + if(state.enabled) + { + Enable(); + }; + if(!state.enabled ) + { + Disable(); + }; + VERIFY2(dBodyStateValide(m_body),"WRONG BODYSTATE WAS SET"); +} + +void CPHCharacter::Disable() +{ + + CPHObject::deactivate(); + dBodyDisable(m_body); + m_body_interpolation.ResetPositions(); +} + +void CPHCharacter::Enable() +{ + if(!b_exist) return; + CPHObject::activate(); + dBodyEnable(m_body); + +} + + + + + + + +void CarHitCallback(bool& /**do_colide/**/,dContact& /**c/**/) +{ + +} + +void CPHCharacter::GetSavedVelocity(Fvector& vvel) +{ + + if(IsEnabled())vvel.set(m_safe_velocity); + else GetVelocity(vvel); +} + +void CPHCharacter::CutVelocity(float l_limit,float /*a_limit*/) +{ + dVector3 limitedl,diffl; + if(dVectorLimit(dBodyGetLinearVel(m_body),l_limit,limitedl)) + { + dVectorSub(diffl,limitedl,dBodyGetLinearVel(m_body)); + dBodySetLinearVel(m_body,diffl[0],diffl[1],diffl[2]); + dBodySetAngularVel(m_body,0.f,0.f,0.f); + dxStepBody(m_body,fixed_step); + dBodySetLinearVel(m_body,limitedl[0],limitedl[1],limitedl[2]); + } +} + +const Fmatrix& CPHCharacter::XFORM () const +{ + return m_phys_ref_object->ObjectXFORM();//>renderable.xform; +} +void CPHCharacter::get_LinearVel ( Fvector& velocity ) const +{ + GetVelocity( velocity ); + +} +void CPHCharacter::get_AngularVel ( Fvector& velocity ) const +{ + velocity.set(0,0,0); +} + +const Fvector &CPHCharacter::mass_Center () const +{ + return cast_fv( dBodyGetLinearVel(m_body) ); +} + + +void CPHCharacter::get_body_position( Fvector &p ) +{ + VERIFY(b_exist); + VERIFY(get_body()); + p.set(cast_fv(dBodyGetPosition(get_body()))); +} + +void virtual_move_collide_callback( bool& do_collide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ) +{ + if( !do_collide ) + return; + do_collide = false; + SGameMtl* oposite_matrial = bo1 ? material_1 : material_2 ; + if(oposite_matrial->Flags.test(SGameMtl::flPassable)) + return; + + dxGeomUserData *my_data = retrieveGeomUserData( bo1 ? c.geom.g1 : c.geom.g2 ); + dxGeomUserData *oposite_data = retrieveGeomUserData( bo1 ? c.geom.g2 : c.geom.g1 ) ; + VERIFY( my_data ); + if( oposite_data && oposite_data->ph_ref_object == my_data->ph_ref_object ) + return; + + //if( c.geom.depth > camera_collision_sckin_depth/2.f ) + //cam_collided = true; + //if( !cam_step ) + //return; + + c.surface.mu = 0; + c.surface.soft_cfm =0.01f; + dJointID contact_joint = dJointCreateContact(0, ContactGroup, &c);//dJointCreateContactSpecial(0, ContactGroup, &c); + CPHObject* obj = (CPHObject*)my_data->callback_data; + VERIFY( obj ); + + obj->Island().DActiveIsland()->ConnectJoint(contact_joint); + + if(bo1) + dJointAttach (contact_joint, dGeomGetBody(c.geom.g1), 0); + else + dJointAttach (contact_joint, 0, dGeomGetBody(c.geom.g2)); + +} + +void CPHCharacter:: fix_body_rotation () +{ + dBodyID b= get_body();//GetBody(); + if(b) + { + dMatrix3 R; + dRSetIdentity (R); + dBodySetAngularVel(b,0.f,0.f,0.f); + dBodySetRotation(b,R); + } +} + + + +CPHCharacter *create_ai_character() +{ + return xr_new (); +} +CPHCharacter *create_actor_character( bool single_game ) +{ + return xr_new ( single_game ); +} + diff --git a/xrPhysics/PHCharacter.h b/xrPhysics/PHCharacter.h new file mode 100644 index 00000000000..1145f5a9bef --- /dev/null +++ b/xrPhysics/PHCharacter.h @@ -0,0 +1,214 @@ +#pragma once +#ifndef dSINGLE + #define dSINGLE +#endif +#include "PHObject.h" +#include "PHInterpolation.h" +#include "../xrserverentities/PHSynchronize.h" +#include "PHDisabling.h" + +#include "../xrEngine/iphysicsshell.h" + + +class IPhysicsShellHolder; +class IClimableObject; +class CGameObject; +class ICollisionDamageInfo; +class CElevatorState; +class CPHActorCharacter; +class CPHAICharacter; +namespace ALife { + enum EHitType; +}; + static enum EEnvironment + { + peOnGround, + peAtWall, + peInAir + }; + + +class CPHCharacter : + public CPHObject, + public CPHSynchronize, + public CPHDisablingTranslational, + public IPhysicsElement +#if 0 +#ifdef DEBUG + ,public pureRender +#endif +#endif +{ +public: + +u64 m_creation_step ; +bool b_exist ; +protected: + +////////////////////////// dynamic + +CPHInterpolation m_body_interpolation; +dBodyID m_body; +IPhysicsShellHolder* m_phys_ref_object; + + +dReal m_mass; +bool was_enabled_before_freeze; + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +u16* p_lastMaterialIDX; +u16 lastMaterialIDX; +u16 injuriousMaterialIDX; +/////////////////////////////////////////////////////////////////////////// +dVector3 m_safe_velocity; +dVector3 m_safe_position; +dReal m_mean_y; +public: + +private: + +#ifdef DEBUG + virtual IPhysicsShellHolder *ref_object () { return PhysicsRefObject () ;} +#endif + +protected: +ERestrictionType m_new_restriction_type; +ERestrictionType m_restriction_type; +bool b_actor_movable; + +bool b_in_touch_resrtrictor ; +float m_current_object_radius ; +public: + virtual ECastType CastType (){return CPHObject::tpCharacter;} + virtual CPHActorCharacter *CastActorCharacter (){return NULL;} + virtual CPHAICharacter *CastAICharacter (){return NULL;} + ERestrictionType RestrictionType (){return m_restriction_type;} + void SetNewRestrictionType (ERestrictionType rt){m_new_restriction_type=rt;} + void SetRestrictionType (ERestrictionType rt){m_new_restriction_type=m_restriction_type=rt;} + void SetObjectRadius (float R){m_current_object_radius=R;} + float ObjectRadius (){return m_current_object_radius;} + virtual void ChooseRestrictionType (ERestrictionType my_type,float my_depth,CPHCharacter *ch) {} + virtual bool UpdateRestrictionType (CPHCharacter* ach) =0; + virtual void FreezeContent () ; + virtual void UnFreezeContent () ; + virtual dBodyID get_body () {return m_body;} + virtual void fix_body_rotation () ; + virtual dSpaceID dSpace () =0; + virtual void get_body_position ( Fvector &p ) ; virtual void Disable () ; + virtual void ReEnable () {;} + virtual void Enable () ; //!! + virtual void SwitchOFFInitContact () =0; + virtual void SwitchInInitContact () =0; + virtual bool IsEnabled () =0; + bool ActorMovable () {return b_actor_movable;} + void SetActorMovable (bool v) {b_actor_movable=v;} +virtual const ICollisionDamageInfo *CollisionDamageInfo()const =0; +virtual ICollisionDamageInfo *CollisionDamageInfo() =0; +virtual void Reinit () =0; +void SetPLastMaterialIDX (u16* p) {p_lastMaterialIDX=p;} +const u16 &LastMaterialIDX ()const {return *p_lastMaterialIDX;} + u16 InjuriousMaterialIDX ()const {return injuriousMaterialIDX;} + +virtual void SetHitType (ALife::EHitType type) =0; +virtual bool TouchRestrictor (ERestrictionType rttype) =0; +virtual void SetElevator (IClimableObject* climable) {}; +virtual void SetMaterial (u16 material) =0 ; +virtual void SetMaximumVelocity (dReal /**vel/**/) {} //!! +virtual dReal GetMaximumVelocity () {return 0;} +virtual void SetJupmUpVelocity (dReal /**velocity/**/) {} //!! +virtual void IPosition (Fvector& /**pos/**/) {} +virtual u16 ContactBone () {return 0;} +virtual void DeathPosition (Fvector& /**deathPos/**/) {} +virtual void ApplyImpulse (const Fvector& /**dir/**/,const dReal /**P/**/) {} +virtual void ApplyForce (const Fvector& force) =0 ; +virtual void ApplyForce (const Fvector& dir,float force) =0 ; +virtual void ApplyForce (float x,float y, float z) =0 ; +virtual void AddControlVel (const Fvector& vel) =0 ; +virtual void Jump (const Fvector& jump_velocity) =0 ; +virtual bool JumpState () =0 ; +virtual EEnvironment CheckInvironment () =0 ; +virtual bool ContactWas () =0 ; +virtual void GroundNormal (Fvector &norm) =0 ; +virtual void Create (dVector3 /**sizes/**/) =0 ; +virtual void Destroy (void) =0 ; +virtual void SetBox (const dVector3 &sizes) =0 ; +virtual void SetAcceleration (Fvector accel) =0 ; +virtual void SetForcedPhysicsControl (bool v){} +virtual bool ForcedPhysicsControl () {return false;} +virtual void SetCamDir (const Fvector& cam_dir) =0 ; +virtual const Fvector& CamDir ()const =0 ; +virtual Fvector GetAcceleration () =0 ; +virtual void SetPosition (const Fvector &pos) =0 ; +virtual void SetApplyGravity (BOOL flag) { dBodySetGravityMode(m_body,flag); } +virtual void SetObjectContactCallbackData ( void* callback ) =0 ; +virtual void SetObjectContactCallback (ObjectContactCallbackFun* callback) =0 ; +virtual void SetWheelContactCallback (ObjectContactCallbackFun* callback) =0 ; +virtual void SetStaticContactCallBack (ContactCallbackFun* calback) =0 ; +virtual ObjectContactCallbackFun* ObjectContactCallBack () {return NULL;} +virtual void GetVelocity (Fvector& vvel)const =0 ; +virtual void GetSavedVelocity (Fvector& vvel) ; +virtual void GetSmothedVelocity (Fvector& vvel) =0 ; +virtual void SetVelocity (Fvector vel) =0 ; +virtual void SetAirControlFactor (float factor) =0 ; +virtual void GetPosition (Fvector& vpos) =0 ; +virtual void GetBodyPosition (Fvector& vpos) =0 ; +virtual const Fvector &BodyPosition ()const =0 ; +virtual void GetFootCenter (Fvector& vpos) {vpos.set(*(Fvector*)dBodyGetPosition(m_body));} +virtual void SetMas (dReal mass) =0 ; +virtual void SetCollisionDamageFactor (float f) =0 ; +virtual float Mass () =0 ; +virtual void SetPhysicsRefObject (IPhysicsShellHolder* ref_object) =0 ; +virtual void SetNonInteractive (bool v) =0 ; +virtual void SetRestrictorRadius (ERestrictionType rtype,float r) {}; +virtual IPhysicsShellHolder* PhysicsRefObject () {return m_phys_ref_object;} + +//AICharacter +virtual void GetDesiredPosition (Fvector& /**dpos/**/) {} +virtual void SetDesiredPosition (const Fvector& /**pos/**/) {} +virtual void BringToDesired (float /**time/**/,float /**velocity/**/,float force=1.f) {} +virtual bool TryPosition (Fvector /**pos/**/,bool) {return false;} +virtual bool TouchBorder () {return false;} +virtual void getForce (Fvector& force) ; +virtual void setForce (const Fvector& force) ; +virtual float FootRadius () =0 ; +virtual void get_State ( SPHNetState& state) ; +virtual void set_State (const SPHNetState& state) ; +virtual void cv2obj_Xfrom (const Fquaternion& q,const Fvector& pos, Fmatrix& xform) {;} +virtual void cv2bone_Xfrom (const Fquaternion& q,const Fvector& pos, Fmatrix& xform) {;} +virtual const Fvector& ControlAccel ()const =0; +virtual float &FrictionFactor () =0; +virtual void CutVelocity (float l_limit,float a_limit) ; +virtual u16 get_elements_number () {return 1;}; +virtual CPHSynchronize *get_element_sync (u16 element) {VERIFY(element==0);return static_cast(this);}; +virtual CElevatorState *ElevatorState () =0; +public: +virtual void Freeze () =0;//{ Freeze(); } +virtual void UnFreeze () =0;//{ UnFreeze(); } +virtual void step (float dt) =0;//{ step( dt ); } +virtual void collision_disable () =0;//{ collision_disable(); } +virtual void collision_enable () =0;//{ collision_enable(); } +protected: +virtual const Fmatrix &XFORM () const ; +virtual void get_LinearVel ( Fvector& velocity ) const ; +virtual void get_AngularVel ( Fvector& velocity ) const ; +virtual u16 numberOfGeoms () const { return 0; } +virtual const IPhysicsGeometry*geometry ( u16 i ) const { return 0; } +virtual const Fvector &mass_Center () const ; + +virtual void get_xform ( Fmatrix& form ) const { form.set( XFORM()); } +virtual bool collide_fluids () const { return true ; } +public: +virtual void update_last_material() =0; +virtual void NetRelcase ( IPhysicsShellHolder* O ) {}; +public: + CPHCharacter (void) ; +virtual ~CPHCharacter (void) ; +}; + +XRPHYSICS_API void virtual_move_collide_callback( bool& do_collide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ); +XRPHYSICS_API CPHCharacter *create_ai_character(); +XRPHYSICS_API CPHCharacter *create_actor_character( bool single_game ); + + diff --git a/xrPhysics/PHCollideValidator.cpp b/xrPhysics/PHCollideValidator.cpp new file mode 100644 index 00000000000..6d5359d567b --- /dev/null +++ b/xrPhysics/PHCollideValidator.cpp @@ -0,0 +1,121 @@ +#include "stdafx.h" +#include "PHObject.h" +#include "phcollidevalidator.h" + +CGID CPHCollideValidator::freeGroupID=0; +_flags CPHCollideValidator::ClassFlags={CLClassBits(0)}; +_flags CPHCollideValidator::ClassNCFlags={CLClassBits(0)}; +_flags CPHCollideValidator::NonTypeFlags={CLClassBits(0)}; +void CPHCollideValidator::Init() +{ + freeGroupID=0; + NonTypeFlags.set(cbNCGroupObject,TRUE); + + ClassFlags.set(cbClassDynamic|cbClassCharacter|cbClassSmall|cbClassRagDoll|cbClassAnimated,TRUE); + ClassNCFlags.set(cbNCClassCharacter|cbNCClassSmall|cbNCClassDynamic|cbNCClassRagDoll|cbNCClassAnimated,TRUE); + +} +CGID CPHCollideValidator::RegisterGroup() +{ + ++freeGroupID; + return freeGroupID-1; +} + +void CPHCollideValidator::InitObject(CPHObject& obj) +{ + obj.collide_class_bits().assign(0); + obj.collide_class_bits().set(cbClassDynamic,TRUE); + obj.collide_bits()=0; +} +void CPHCollideValidator::RegisterObjToGroup(CGID group,CPHObject& obj) +{ + R_ASSERT(group ClassFlags; +static _flags ClassNCFlags; +static _flags NonTypeFlags; +}; + + +#endif \ No newline at end of file diff --git a/xrPhysics/PHContactBodyEffector.cpp b/xrPhysics/PHContactBodyEffector.cpp new file mode 100644 index 00000000000..08968d0a3c9 --- /dev/null +++ b/xrPhysics/PHContactBodyEffector.cpp @@ -0,0 +1,62 @@ +#include "stdafx.h" +#include "PHContactBodyEffector.h" +#include "ExtendedGeom.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PhysicsCommon.h" +#include "../xrEngine/gamemtllib.h" +#include "mathutilsode.h" +void CPHContactBodyEffector::Init(dBodyID body,const dContact& contact,SGameMtl* material) +{ + CPHBaseBodyEffector::Init(body); + m_contact=contact; + m_recip_flotation=1.f-material->fFlotationFactor; + m_material=material; +} +void CPHContactBodyEffector::Merge(const dContact& contact, SGameMtl* material) +{ + m_recip_flotation=_max(1.f-material->fFlotationFactor,m_recip_flotation); + //m_contact.geom.normal[0]+=contact.geom.normal[0]; + //m_contact.geom.normal[1]+=contact.geom.normal[1]; + //m_contact.geom.normal[2]+=contact.geom.normal[2]; +} + +void CPHContactBodyEffector::Apply() +{ + const dReal* linear_velocity =dBodyGetLinearVel(m_body); + dReal linear_velocity_smag =dDOT(linear_velocity,linear_velocity); + dReal linear_velocity_mag =_sqrt(linear_velocity_smag); + dReal effect =10000.f*m_recip_flotation*m_recip_flotation; + dMass mass; + dBodyGetMass(m_body,&mass); + dReal l_air=linear_velocity_mag*effect;//force/velocity !!! + if(l_air>mass.mass/fixed_step) l_air=mass.mass/fixed_step;//validate + + if(!fis_zero(l_air)) + { + dVector3 force={ + -linear_velocity[0]*l_air, + -linear_velocity[1]*l_air, + -linear_velocity[2]*l_air, + 0.f + }; + + if(!m_material->Flags.is(SGameMtl::flPassable)) + { + dVector3& norm=m_contact.geom.normal; + accurate_normalize(norm); + dMass m; + dBodyGetMass(m_body,&m); + dReal prg=1.f*dDOT(force,norm);//+dDOT(linear_velocity,norm)*m.mass/fixed_step + force[0]-=prg*norm[0]; + force[1]-=prg*norm[1]; + force[2]-=prg*norm[2]; + } + dBodyAddForce( + m_body, + force[0], + force[1], + force[2] + ); + } + dBodySetData(m_body,NULL); +} \ No newline at end of file diff --git a/xrPhysics/PHContactBodyEffector.h b/xrPhysics/PHContactBodyEffector.h new file mode 100644 index 00000000000..a1889ac6d57 --- /dev/null +++ b/xrPhysics/PHContactBodyEffector.h @@ -0,0 +1,16 @@ +#ifndef PH_CONTACT_BODY_EFFECTOR_H +#define PH_CONTACT_BODY_EFFECTOR_H +#include "PHBaseBodyEffector.h" +#include "../3rd party/ode/include/ode/contact.h" +struct SGameMtl; +class CPHContactBodyEffector : public CPHBaseBodyEffector +{ +dContact m_contact; +float m_recip_flotation; +SGameMtl* m_material; +public: +void Init(dBodyID body,const dContact& contact,SGameMtl* material); +void Merge(const dContact& contact, SGameMtl* material); +void Apply(); +}; +#endif //PH_CONTACT_BODY_EFFECTOR_H \ No newline at end of file diff --git a/xrPhysics/PHDefs.h b/xrPhysics/PHDefs.h new file mode 100644 index 00000000000..51531388d70 --- /dev/null +++ b/xrPhysics/PHDefs.h @@ -0,0 +1,20 @@ +#ifndef PHDEFS_H +#define PHDEFS_H +class CPHElement; +class CPHJoint; +class CPhysicsShell; + +//class CPHFracture; +class CShellSplitInfo; + +typedef std::pair shell_root; + +DEFINE_VECTOR(CPHElement*,ELEMENT_STORAGE,ELEMENT_I) +typedef xr_vector::const_iterator ELEMENT_CI; +DEFINE_VECTOR(CPHJoint*,JOINT_STORAGE,JOINT_I) +DEFINE_VECTOR(shell_root,PHSHELL_PAIR_VECTOR,SHELL_PAIR_I) +typedef xr_vector::reverse_iterator SHELL_PAIR_RI; + +typedef xr_vector::reverse_iterator ELEMENT_RI; + +#endif \ No newline at end of file diff --git a/xrPhysics/PHDisabling.cpp b/xrPhysics/PHDisabling.cpp new file mode 100644 index 00000000000..6baf6adc1b3 --- /dev/null +++ b/xrPhysics/PHDisabling.cpp @@ -0,0 +1,273 @@ +#include "stdafx.h" +#include "PHDisabling.h" +#include "PhysicsCommon.h" +#include "Physics.h" +#include "mathutilsode.h" +#ifdef DEBUG +#include "debug_output.h" +#endif + +extern CPHWorld* ph_world; +SDisableVector::SDisableVector() +{ + Init(); +} + + + +void SDisableVector::Reset() +{ + sum.set(0.f,0.f,0.f); +} + +void SDisableVector::Init() +{ + previous.set(0.f,0.f,0.f); + Reset(); +} + +float SDisableVector::Update(const Fvector& new_vector) +{ + Fvector dif; + dif.sub(new_vector,previous); + previous.set(new_vector); + sum.add(dif); + return dif.magnitude(); +} + +float SDisableVector::UpdatePrevious(const Fvector& new_vector) +{ + Fvector dif; + dif.sub(new_vector,previous); + previous.set(new_vector); + return dif.magnitude(); +} + +float SDisableVector::SumMagnitude() +{ + return sum.magnitude(); +} + +SDisableUpdateState::SDisableUpdateState() +{ + Reset(); +} + + + +void SDisableUpdateState::Reset() +{ + disable = false ; + enable = false ; +} + +SDisableUpdateState& SDisableUpdateState::operator &= (SDisableUpdateState& lstate) +{ + disable = disable && lstate.disable; + enable = enable || lstate.enable; + return *this; +} + +CBaseDisableData::CBaseDisableData(): m_disabled(false), m_last_frame_updated(u16(-1)) +{ + + m_frames =worldDisablingParams.objects_params.L2frames ; + Reinit(); + +} + +void CBaseDisableData::Reinit() +{ + m_count =m_frames ; + if(ph_world) + m_count=m_count+ph_world->disable_count ; + m_stateL1 .Reset() ; + m_stateL2 .Reset() ; + +} +void CBaseDisableData::Disabling() +{ + + + VERIFY(ph_world); + if(ph_world->IsFreezed()) + return; + if( m_last_frame_updated == ph_world->StepsShortCnt() ) + return; + m_last_frame_updated = ph_world->StepsShortCnt(); + dBodyID body = get_body(); + m_count--; + + UpdateL1(); + + CheckState(m_stateL1); + + if(m_count==0)//ph_world->disable_count==dis_frames//m_count==m_frames + { + UpdateL2(); + CheckState(m_stateL2); + m_count=m_frames; + } + const dReal* force=dBodyGetForce(body); + const dReal* torqu=dBodyGetTorque(body); + if(dDOT(force,force)>0.f || dDOT(torqu,torqu)>0.f) m_disabled=false; + if(dBodyIsEnabled(body)) + { + ReEnable(); + if(!m_disabled&& (ph_world->disable_count!=m_count%worldDisablingParams.objects_params.L2frames)) + { + m_count=m_frames+ph_world->disable_count; + } + } + if(m_disabled) + Disable();//dBodyDisable(body); + +} + +void CPHDisablingBase::Reinit() +{ + m_mean_velocity.Init() ; + m_mean_acceleration.Init() ; + CBaseDisableData::Reinit() ; + bool disable=!dBodyIsEnabled(get_body()); + m_stateL1.disable=disable; + m_stateL1.enable=!disable; + m_stateL2.disable=disable; + m_stateL2.enable=!disable; +} +void CPHDisablingBase::UpdateValues(const Fvector &new_pos,const Fvector &new_vel) +{ + + if(m_count m_params.velocity*worldDisablingParams.reanable_factor || + accel > m_params.acceleration*worldDisablingParams.reanable_factor) + state.enable=true ; + } +protected: + + SDisableVector m_mean_velocity ; + SDisableVector m_mean_acceleration ; + SOneDDOParams m_params ; +}; + +class CPHDisablingRotational : + public CPHDisablingBase +{ +public: + CPHDisablingRotational () ; + void Reinit () ; + virtual void UpdateL1 () ; + virtual void set_DisableParams (const SAllDDOParams& params) ; +}; + +class CPHDisablingTranslational : + public CPHDisablingBase +{ +public: + CPHDisablingTranslational () ; + void Reinit () ; + virtual void UpdateL1 () ; + virtual void set_DisableParams (const SAllDDOParams& params) ; +}; + +class CPHDisablingFull : + public CPHDisablingTranslational, + public CPHDisablingRotational +{ +public: + void Reinit () ; + virtual void UpdateL1 () ; + virtual void UpdateL2 () ; + virtual void set_DisableParams (const SAllDDOParams& params) ; +}; +#endif \ No newline at end of file diff --git a/xrPhysics/PHDynamicData.cpp b/xrPhysics/PHDynamicData.cpp new file mode 100644 index 00000000000..51c3ac83322 --- /dev/null +++ b/xrPhysics/PHDynamicData.cpp @@ -0,0 +1,207 @@ +// PHDynamicData.cpp: implementation of the PHDynamicData class. +// +////////////////////////////////////////////////////////////////////// +#include "stdafx.h" +#include "PHDynamicData.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#if 0 + +PHDynamicData::PHDynamicData() +{ + numOfChilds=0; + //Childs=NULL; + p_parent_body_interpolation=NULL; +} + +PHDynamicData::~PHDynamicData() +{ + if(numOfChilds){ + //for(unsigned int i=0;i0) + //Childs[childNum].Childs=new PHDynamicData[numOfchilds]; + Childs[childNum].Childs.resize(numOfchilds); + else + //Childs[childNum].Childs=NULL; + Childs[childNum].numOfChilds=0; + + Childs[childNum].geom=NULL; + Childs[childNum].transform=NULL; + return true; + } + else return false; +} + +void PHDynamicData::CalculateR_N_PosOfChilds(dBodyID parent) +{ + Fmatrix parent_transform;//,mYM; + //mYM.rotateY (deg2rad(-90.f)); + DMXPStoFMX(dBodyGetRotation(parent),dBodyGetPosition(parent),parent_transform); + DMXPStoFMX(dBodyGetRotation(body),dBodyGetPosition(body),BoneTransform); + parent_transform.mulB_43 (ZeroTransform); + //parent_transform.mulA(mYM); + parent_transform.invert (); + + //BoneTransform.mulA(mYM); + BoneTransform.mulA_43 (parent_transform); + + for(unsigned int i=0;iInterpolateRotation(parent_transform); + p_parent_body_interpolation->InterpolatePosition(parent_transform.c); + + body_interpolation.InterpolateRotation(transform); + + body_interpolation.InterpolatePosition(transform.c); + parent_transform.mulB_43 (ZeroTransform); + + parent_transform.invert(); + + + //BoneTransform.mulA(parent_transform); + transform.mulA_43 (parent_transform); +} +PHDynamicData * PHDynamicData::GetChild(unsigned int ChildNum) +{ + if(ChildNum 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class PHDynamicData +{ +public: +dVector3 pos; +dMatrix3 R; +Fmatrix BoneTransform; +private: +dBodyID body; +CPHInterpolation* p_parent_body_interpolation; +CPHInterpolation body_interpolation; +dGeomID geom; +dGeomID transform; +//PHDynamicData* Childs; +//xr_vector Childs; +unsigned int numOfChilds; +Fmatrix ZeroTransform; +public: + inline void UpdateInterpolation(){ + body_interpolation.UpdatePositions(); + body_interpolation.UpdateRotations(); + } + void UpdateInterpolationRecursive() ; + void InterpolateTransform(Fmatrix& transform); + void InterpolateTransformVsParent(Fmatrix& transform); +// PHDynamicData& operator [] (unsigned int i) {return Childs[i];}; + void Destroy(); + void Create(unsigned int numOfchilds,dBodyID Body); + void CalculateData(void); + PHDynamicData * GetChild(unsigned int ChildNum); + bool SetChild(unsigned int ChildNum,unsigned int numOfchilds,dBodyID body); + void SetAsZero(); + void SetAsZeroRecursive(); + void SetZeroTransform(Fmatrix& aTransform); + PHDynamicData(unsigned int numOfchilds,dBodyID body); + PHDynamicData(); +// virtual ~PHDynamicData(); + void GetWorldMX(Fmatrix& aTransform){ + dMatrix3 R; + dQtoR(dBodyGetQuaternion(body),R); + DMXPStoFMX(R,dBodyGetPosition(body),aTransform); + } + void GetTGeomWorldMX(Fmatrix& aTransform){ + if(!transform) return; + Fmatrix NormTransform,Transform; + dVector3 P0={0,0,0,-1}; + Fvector Translate,Translate1; + //compute_final_tx(geom); + //dQtoR(dBodyGetQuaternion(body),R); + DMXPStoFMX(dBodyGetRotation(body),P0,NormTransform); + DMXPStoFMX(dGeomGetRotation(dGeomTransformGetGeom(transform)),P0,Transform); + + + dVectorSet((dReal*)&Translate,dGeomGetPosition(dGeomTransformGetGeom(transform))); + dVectorSet((dReal*)&Translate1,dBodyGetPosition(body)); + + aTransform.identity (); + aTransform.translate_over (Translate); + aTransform.mulA_43 (NormTransform); + aTransform.translate_over (Translate1); + aTransform.mulA_43 (Transform); + + // Translate.add(Translate1); + //transform.translate_over(Translate1); + + //transform.translate_add + //normalTransform=oMatrix4x4(dGeomGetRotation(dGeomTransformGetGeom(geom)))*normalTransform; + //oMatrix4x4 meshTransform(normalTransform); + + //meshTransform.PreTranslate(oVector3(dGeomGetPosition(dGeomTransformGetGeom(geom)))); + //meshTransform.PostTranslate(oVector3(dBodyGetPosition(body))); + } + static inline void DMXPStoFMX(const dReal* R,const dReal* pos,Fmatrix& aTransform){ + + CopyMemory(&aTransform,R,sizeof(dMatrix3)); + aTransform.transpose(); + CopyMemory(&aTransform.c,pos,sizeof(Fvector)); + aTransform._14=0.f; + aTransform._24=0.f; + aTransform._34=0.f; + aTransform._44=1.f; + }; + static inline void DMXtoFMX(const dReal* R,Fmatrix& aTransform){ + aTransform._11=R[0]; + aTransform._12=R[4]; + aTransform._13=R[8]; + aTransform._14=0.f; + + aTransform._21=R[1]; + aTransform._22=R[5]; + aTransform._23=R[9]; + aTransform._24=0.f; + + aTransform._31=R[2]; + aTransform._32=R[6]; + aTransform._33=R[10]; + aTransform._34=0.f; + aTransform._44=1.f; + }; + static inline void FMX33toDMX(const Fmatrix33& aTransform,dReal* R){ + R[0]=aTransform._11; + R[4]=aTransform._12; + R[8]=aTransform._13; + + R[1]=aTransform._21; + R[5]=aTransform._22; + R[9]=aTransform._23; + + R[2]=aTransform._31; + R[6]=aTransform._32; + R[10]=aTransform._33; + }; + static inline void FMXtoDMX(const Fmatrix& aTransform,dReal* R){ + R[0]=aTransform._11; + R[4]=aTransform._12; + R[8]=aTransform._13; + + R[1]=aTransform._21; + R[5]=aTransform._22; + R[9]=aTransform._23; + + R[2]=aTransform._31; + R[6]=aTransform._32; + R[10]=aTransform._33; + }; +private: + void CalculateR_N_PosOfChilds(dBodyID parent); +public: + bool SetGeom(dGeomID ageom); + bool SetTransform(dGeomID ageom); +}; + +#endif // !defined(AFX_PHDynamicData_H__ACC01646_B581_4639_B78C_30311432021B__INCLUDED_) diff --git a/xrPhysics/PHElement.cpp b/xrPhysics/PHElement.cpp new file mode 100644 index 00000000000..2259a75f7cc --- /dev/null +++ b/xrPhysics/PHElement.cpp @@ -0,0 +1,1696 @@ +#include "StdAfx.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PHFracture.h" +#include "PHContactBodyEffector.h" +#include "MathUtils.h" +#include "matrix_utils.h" +#include "IPhysicsShellHolder.h" +#include "ph_valid_ode.h" +//#include "game_object_space.h" +//#include "../Include/xrRender/Kinematics.h" +#include "../Include/xrRender/Kinematics.h" +#include "../Include/xrRender/KinematicsAnimated.h" +#include "../3rd party/ode/ode/src/util.h" + +#ifdef DEBUG +# include "debug_output.h" +//# include "objectdump.h" +#endif // DEBUG + +/////////////////////////////////////////////////////////////// +#pragma warning(disable:4995) +#pragma warning(disable:4267) + +#include "../3rd party/ode/ode/src/collision_kernel.h" + + +#pragma warning(default:4267) +#pragma warning(default:4995) +/////////////////////////////////////////////////////////////////// + +#include "ExtendedGeom.h" + +#include "PHShell.h" +#include "PHElement.h" +#include "PHElementInline.h" +extern CPHWorld* ph_world; + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +//////Implementation for CPhysicsElement +CPHElement::CPHElement() //aux +{ + m_w_limit = default_w_limit; + m_l_limit = default_l_limit; + m_l_scale=default_l_scale; + m_w_scale=default_w_scale; + + //push_untill=0; + + //temp_for_push_out=NULL; + + m_body=NULL; + //bActive=false; + //bActivating=false; + m_flags.set(flActive,FALSE); + m_flags.set(flActivating,FALSE); + m_parent_element=NULL; + m_shell=NULL; + + + k_w=default_k_w; + k_l=default_k_l;//1.8f; + m_fratures_holder=NULL; + //b_enabled_onstep=false; + //m_flags.set(flEnabledOnStep,FALSE); + m_flags.assign(0); + mXFORM.identity(); + m_mass.setZero(); + m_mass_center.set(0,0,0); + m_volume=0.f; +} + +void CPHElement::add_Box (const Fobb& V) +{ + CPHGeometryOwner::add_Box(V); +} + + +void CPHElement::add_Sphere (const Fsphere& V) +{ + CPHGeometryOwner::add_Sphere(V); +} + +void CPHElement::add_Cylinder (const Fcylinder& V) +{ + CPHGeometryOwner::add_Cylinder(V); +} + +void CPHElement:: build (){ + + m_body=dBodyCreate(0);//phWorld + //m_saved_contacts=dJointGroupCreate (0); + //b_contacts_saved=false; + dBodyDisable(m_body); + //dBodySetFiniteRotationMode(m_body,1); + //dBodySetFiniteRotationAxis(m_body,0,0,0); + VERIFY2(dMass_valide(&m_mass),"Element has bad mass"); + if(m_geoms.empty()) + { + Fix(); + } + else + { + VERIFY2(m_mass.mass>0.f,"Element has bad mass"); + dBodySetMass(m_body,&m_mass); + } + + VERIFY_BOUNDARIES2(m_mass_center,phBoundaries,PhysicsRefObject(),"m_mass_center"); + + dBodySetPosition(m_body,m_mass_center.x,m_mass_center.y,m_mass_center.z); + + CPHDisablingTranslational::Reinit(); + /////////////////////////////////////////////////////////////////////////////////////// + CPHGeometryOwner::build(); + set_body(m_body); +} + +void CPHElement::RunSimulation() +{ + //if(push_untill) + //push_untill+=Device.dwTimeGlobal; + + if(group_space()) + dSpaceAdd(m_shell->dSpace(),(dGeomID)group_space()); + + //else + // if(!m_geoms.empty())(*m_geoms.begin())->add_to_space(m_shell->dSpace()); + if(!m_body->world) + { + //dWorldAddBody(phWorld, m_body); + m_shell->Island().AddBody(m_body); + } + dBodyEnable(m_body); +} + +void CPHElement::destroy () +{ + //dJointGroupDestroy(m_saved_contacts); + CPHGeometryOwner::destroy(); + if(m_body)//&&m_body->world + { + if(m_body->world)m_shell->Island().RemoveBody(m_body); + dBodyDestroy(m_body); + m_body=NULL; + } + DestroyGroupSpace(); + +} + +void CPHElement::calculate_it_data(const Fvector& mc,float mas) +{ + float density=mas/m_volume; + calculate_it_data_use_density(mc,density); +} + +static float static_dencity; +void CPHElement::calc_it_fract_data_use_density(const Fvector& mc,float density) +{ + m_mass_center.set(mc); + dMassSetZero(&m_mass); + static_dencity=density; + recursive_mass_summ(0,m_fratures_holder->m_fractures.begin()); +} +void CPHElement::set_local_mass_center(const Fvector &mc ) +{ + m_mass_center.set(mc); + dVectorSet( m_mass.c, cast_fp( mc ) ); +} +dMass CPHElement::recursive_mass_summ(u16 start_geom,FRACTURE_I cur_fracture) +{ + dMass end_mass; + dMassSetZero(&end_mass); + GEOM_I i_geom=m_geoms.begin()+start_geom, e=m_geoms.begin()+cur_fracture->m_start_geom_num; + for(;i_geom!=e;++i_geom)(*i_geom)->add_self_mass(end_mass,m_mass_center,static_dencity); + dMassAdd(&m_mass,&end_mass); + start_geom=cur_fracture->m_start_geom_num; + ++cur_fracture; + if(m_fratures_holder->m_fractures.end() != cur_fracture) + cur_fracture->SetMassParts(m_mass,recursive_mass_summ(start_geom,cur_fracture)); + return end_mass; +} +void CPHElement:: setDensity (float M) +{ + calculate_it_data_use_density(get_mc_data(),M); +} + +void CPHElement:: setMass (float M) +{ + + calculate_it_data(get_mc_data(),M); +} + +void CPHElement:: setDensityMC (float M,const Fvector& mass_center) +{ + m_mass_center.set(mass_center); + calc_volume_data(); + calculate_it_data_use_density(mass_center,M); +} + +void CPHElement:: setMassMC (float M,const Fvector& mass_center) +{ + m_mass_center.set(mass_center); + calc_volume_data(); + calculate_it_data(mass_center,M); +} + + + +void CPHElement::Start() +{ + build(); + RunSimulation(); +} + +void CPHElement::Deactivate() +{ + VERIFY(isActive()); + + destroy(); + m_flags.set(flActive,FALSE); + m_flags.set(flActivating,FALSE); + //bActive=false; + //bActivating=false; + IKinematics* K=m_shell->PKinematics(); + if(K) + { + if( K->LL_GetBoneInstance(m_SelfID).callback_type() == bctPhysics ) + ClearBoneCallback(); + } +} + +void CPHElement::SetTransform(const Fmatrix &m0, motion_history_state history_state ){ + VERIFY2(_valid(m0), make_string( "invalid_form_in_set_transform" ) + ( PhysicsRefObject()->dump(full_capped) ) ); + VERIFY2(valid_pos( m0.c ), dbg_valide_pos_string( m0.c, PhysicsRefObject(), "invalid_form_in_set_transform" ) ); + Fvector mc; + CPHGeometryOwner::get_mc_vs_transform(mc,m0); + VERIFY_BOUNDARIES2(mc,phBoundaries,PhysicsRefObject(),"mass center in set transform"); + dBodySetPosition(m_body,mc.x,mc.y,mc.z); + Fmatrix33 m33; + m33.set(m0); + dMatrix3 R; + PHDynamicData::FMX33toDMX(m33,R); + dBodySetRotation(m_body,R); + CPHDisablingFull::Reinit(); + + VERIFY2(dBodyGetPosition(m_body),"not valide safe position"); + VERIFY2(dBodyGetLinearVel(m_body),"not valide safe velocity"); + m_flags.set(flUpdate,TRUE); + m_shell->spatial_move(); + if( history_state != mh_not_clear ) + CPHGeometryOwner::clear_motion_history( mh_unspecified == history_state ); +} + +void CPHElement::getQuaternion(Fquaternion& quaternion) +{ + if(!isActive()) return; + const float* q=dBodyGetQuaternion(m_body); + quaternion.set(-q[0],q[1],q[2],q[3]); + VERIFY(_valid(quaternion)); +} +void CPHElement::setQuaternion(const Fquaternion& quaternion) +{ + VERIFY(_valid(quaternion)); + if(!isActive()) return; + dQuaternion q={-quaternion.w,quaternion.x,quaternion.y,quaternion.z}; + dBodySetQuaternion(m_body,q); + CPHDisablingRotational::Reinit(); + m_flags.set(flUpdate,TRUE); + m_shell->spatial_move(); +} +void CPHElement::GetGlobalPositionDynamic(Fvector* v) +{ + if(!isActive()) return; + v->set((*(Fvector*)dBodyGetPosition(m_body))); + VERIFY(_valid(*v)); +} + +void CPHElement::SetGlobalPositionDynamic(const Fvector& position) +{ + if(!isActive()) return; + VERIFY(_valid(position)); + VERIFY_BOUNDARIES2(position,phBoundaries,PhysicsRefObject(),"SetGlobalPosition argument "); + dBodySetPosition(m_body,position.x,position.y,position.z); + CPHDisablingTranslational::Reinit(); + m_flags.set(flUpdate,TRUE); + m_shell->spatial_move(); +} + +void CPHElement::TransformPosition(const Fmatrix &form, motion_history_state history_state ) +{ + if(!isActive())return; + VERIFY(_valid(form)); + R_ASSERT2(m_body,"body is not created"); + Fmatrix bm; + PHDynamicData::DMXPStoFMX(dBodyGetRotation(m_body),dBodyGetPosition(m_body),bm); + Fmatrix new_bm; + new_bm.mul(form,bm); + dMatrix3 dBM; + PHDynamicData::FMXtoDMX(new_bm,dBM); + dBodySetRotation(m_body,dBM); + VERIFY_BOUNDARIES2(new_bm.c,phBoundaries,PhysicsRefObject(),"TransformPosition dest pos"); + dBodySetPosition(m_body,new_bm.c.x,new_bm.c.y,new_bm.c.z); + CPHDisablingFull::Reinit(); + m_body_interpolation.ResetPositions(); + m_body_interpolation.ResetRotations(); + m_flags.set(flUpdate,TRUE); + if( history_state != mh_not_clear ) + clear_motion_history( mh_unspecified == history_state ); + m_shell->spatial_move(); +} +CPHElement::~CPHElement () +{ + VERIFY(!isActive()); + DeleteFracturesHolder(); +} + +void CPHElement:: SetBoneCallback () +{ + IKinematics* K = m_shell->PKinematics(); + VERIFY( K ); + K->LL_GetBoneInstance(m_SelfID).set_callback(bctPhysics,m_shell->GetBonesCallback(), cast_PhysicsElement( this ) ); +} +void CPHElement:: ClearBoneCallback () +{ + IKinematics* K = m_shell->PKinematics(); + K->LL_GetBoneInstance(m_SelfID).reset_callback(); +} + +void CPHElement::Activate(const Fmatrix &transform,const Fvector& lin_vel,const Fvector& ang_vel,bool disable){ + VERIFY(!isActive()); + mXFORM.set(transform); + Start(); + SetTransform(transform, mh_unspecified ); + + dBodySetLinearVel(m_body,lin_vel.x,lin_vel.y,lin_vel.z); + + dBodySetAngularVel(m_body,ang_vel.x,ang_vel.y,ang_vel.z); + VERIFY(dBodyStateValide(m_body)); +// dVectorSet(m_safe_position,dBodyGetPosition(m_body)); +// dQuaternionSet(m_safe_quaternion,dBodyGetQuaternion(m_body)); +// dVectorSet(m_safe_velocity,dBodyGetLinearVel(m_body)); + + m_body_interpolation.SetBody(m_body); + + if(disable) dBodyDisable(m_body); + m_flags.set(flActive,TRUE); + m_flags.set(flActivating,TRUE); + if(m_shell->PKinematics()) + SetBoneCallback(); +} +void CPHElement::Activate(const Fmatrix &m0,float dt01,const Fmatrix &m2,bool disable){ + + Fvector lvel,avel; + lvel.set(m2.c.x-m0.c.x,m2.c.y-m0.c.y,m2.c.z-m0.c.z); + avel.set(0.f,0.f,0.f); + Activate(m0,lvel,avel,disable); + +} + + +void CPHElement::Activate(bool disable, bool /*not_set_bone_callbacks*/ ){ + + Fvector lvel,avel; + lvel.set(0.f,0.f,0.f); + avel.set(0.f,0.f,0.f); + Activate(mXFORM,lvel,avel,disable); + +} + +void CPHElement::Activate(const Fmatrix& start_from,bool disable){ + VERIFY(_valid(start_from)); + Fmatrix globe; + globe.mul_43(start_from,mXFORM); + + Fvector lvel,avel; + lvel.set(0.f,0.f,0.f); + avel.set(0.f,0.f,0.f); + Activate(globe,lvel,avel,disable); + +} + +void CPHElement::Update(){ + if(!isActive()) return; + if(m_flags.test(flActivating)) m_flags.set(flActivating,FALSE); + if( !dBodyIsEnabled(m_body)&&!m_flags.test(flUpdate)/*!bUpdate*/) return; + + InterpolateGlobalTransform(&mXFORM); + VERIFY2(_valid(mXFORM),"invalid position in update"); +} + +void CPHElement::PhTune(dReal step) +{ + if(!isActive()) return; + CPHContactBodyEffector* contact_effector= + (CPHContactBodyEffector*) dBodyGetData(m_body); + if(contact_effector)contact_effector->Apply(); + VERIFY_BOUNDARIES2(cast_fv(dBodyGetPosition(m_body)),phBoundaries,PhysicsRefObject(),"PhTune body position"); +} +void CPHElement::PhDataUpdate(dReal step){ + + if(! isActive())return; + + ///////////////skip for disabled elements//////////////////////////////////////////////////////////// + //b_enabled_onstep=!!dBodyIsEnabled(m_body); + //VERIFY_BOUNDARIES2(cast_fv(dBodyGetPosition(m_body)),phBoundaries,PhysicsRefObject(),"PhDataUpdate begin, body position"); +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawMassCenters)) + { + debug_output().DBG_DrawPoint(cast_fv(dBodyGetPosition(m_body)),0.03f,D3DCOLOR_XRGB(255,0,0)); + } +#endif + + m_flags.set(flEnabledOnStep,!!dBodyIsEnabled(m_body)); + if(!m_flags.test(flEnabledOnStep)/*!b_enabled_onstep*/) return; + + + + //////////////////////////////////base pointers///////////////////////////////////////////////// + const dReal* linear_velocity = dBodyGetLinearVel(m_body) ; + const dReal* angular_velocity = dBodyGetAngularVel(m_body) ; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////scale velocity/////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + VERIFY(dV_valid(linear_velocity)); +#ifdef DEBUG + if(!dV_valid(angular_velocity)) + { + Msg("angular vel %f,%f,%f",angular_velocity[0],angular_velocity[1],angular_velocity[2]); + Msg("linear vel %f,%f,%f",linear_velocity[0],linear_velocity[1],linear_velocity[2]); + Msg("position %f,%f,%f",dBodyGetPosition(m_body)[0],dBodyGetPosition(m_body)[1],dBodyGetPosition(m_body)[2]); + Msg("quaternion %f,%f,%f,%f",dBodyGetQuaternion(m_body)[0],dBodyGetQuaternion(m_body)[1],dBodyGetQuaternion(m_body)[2],dBodyGetQuaternion(m_body)[3]); + Msg("matrix"); + Msg("x %f,%f,%f",dBodyGetRotation(m_body)[0],dBodyGetRotation(m_body)[4],dBodyGetRotation(m_body)[8]); + Msg("y %f,%f,%f",dBodyGetRotation(m_body)[1],dBodyGetRotation(m_body)[5],dBodyGetRotation(m_body)[9]); + Msg("z %f,%f,%f",dBodyGetRotation(m_body)[2],dBodyGetRotation(m_body)[6],dBodyGetRotation(m_body)[10]); + IPhysicsShellHolder* ph=PhysicsRefObject(); + Msg("name visual %s",ph->ObjectNameVisual()); + Msg("name obj %s",ph->ObjectName()); + Msg("name section %s",ph->ObjectNameSect()); + VERIFY2(0,"bad angular velocity"); + } +#endif + VERIFY(!fis_zero(m_l_scale)); + VERIFY(!fis_zero(m_w_scale)); + dBodySetLinearVel( + m_body, + linear_velocity[0] /m_l_scale , + linear_velocity[1] /m_l_scale , + linear_velocity[2] /m_l_scale + ); + dBodySetAngularVel( + m_body, + angular_velocity[0] /m_w_scale , + angular_velocity[1] /m_w_scale , + angular_velocity[2] /m_w_scale + ); + + + ///////////////////scale changes values directly so get base values after it///////////////////////// + /////////////////////////////base values//////////////////////////////////////////////////////////// + dReal linear_velocity_smag = dDOT(linear_velocity,linear_velocity); + dReal linear_velocity_mag = _sqrt(linear_velocity_smag); + + dReal angular_velocity_smag = dDOT(angular_velocity,angular_velocity); + dReal angular_velocity_mag = _sqrt(angular_velocity_smag); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////limit velocity & secure ///////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + ////////////////limit linear vel//////////////////////////////////////////////////////////////////////////////////////// + + VERIFY(dV_valid(linear_velocity)); + if(linear_velocity_mag>m_l_limit) + { + CutVelocity(m_l_limit,m_w_limit); + VERIFY_BOUNDARIES2(cast_fv(dBodyGetPosition(m_body)),phBoundaries,PhysicsRefObject(),"PhDataUpdate end, body position"); + linear_velocity_smag = dDOT(linear_velocity,linear_velocity); + linear_velocity_mag = _sqrt(linear_velocity_smag); + angular_velocity_smag = dDOT(angular_velocity,angular_velocity); + angular_velocity_mag = _sqrt(angular_velocity_smag); + } + ////////////////secure position/////////////////////////////////////////////////////////////////////////////////// + const dReal* position=dBodyGetPosition(m_body); + VERIFY(dV_valid(position)); + /////////////////limit & secure angular vel/////////////////////////////////////////////////////////////////////////////// + VERIFY(dV_valid(angular_velocity)); + + if(angular_velocity_mag>m_w_limit) + { + CutVelocity(m_l_limit,m_w_limit); + angular_velocity_smag = dDOT(angular_velocity,angular_velocity); + angular_velocity_mag = _sqrt(angular_velocity_smag); + linear_velocity_smag = dDOT(linear_velocity,linear_velocity); + linear_velocity_mag = _sqrt(linear_velocity_smag); + } + + ////////////////secure rotation//////////////////////////////////////////////////////////////////////////////////////// + { + + VERIFY(dQ_valid(dBodyGetQuaternion(m_body))); + + + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////disable/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if(dBodyIsEnabled(m_body)) Disabling(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////position update/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + VERIFY(dBodyStateValide(m_body)); + VERIFY2(dV_valid(dBodyGetPosition(m_body)),"invalid body position"); + VERIFY2(dV_valid(dBodyGetQuaternion(m_body)),"invalid body rotation"); +/* + if(!valid_pos(cast_fv(dBodyGetPosition(m_body)),phBoundaries)) //hack + { //hack + Fvector pos; //hack + m_body_interpolation.GetPosition(pos,0); //hack + dBodySetPosition(m_body,pos.x,pos.y,pos.z); //hack + } //hack +*/ + VERIFY_BOUNDARIES2(cast_fv(dBodyGetPosition(m_body)),phBoundaries,PhysicsRefObject(),"PhDataUpdate end, body position"); + UpdateInterpolation (); + + if(!dBodyIsEnabled(m_body)) + return; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////air resistance///////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + if(!fis_zero(k_w)) + dBodyAddTorque( + m_body, + -angular_velocity[0]*k_w, + -angular_velocity[1]*k_w, + -angular_velocity[2]*k_w + ); + + dMass mass; + dBodyGetMass(m_body,&mass); + dReal l_air=linear_velocity_mag*k_l;//force/velocity !!! + if(l_air>mass.mass/fixed_step) l_air=mass.mass/fixed_step;//validate + + if(!fis_zero(l_air)) + dBodyAddForce( + m_body, + -linear_velocity[0]*l_air, + -linear_velocity[1]*l_air, + -linear_velocity[2]*l_air + ); + +} + +void CPHElement::Enable() { + if(!isActive()) return; + m_shell->EnableObject(0); + if(dBodyIsEnabled(m_body)) return; + dBodyEnable(m_body); +} + +void CPHElement::Disable() { + +// return; + if(!isActive()||!dBodyIsEnabled(m_body)) return; + FillInterpolation(); + + dBodyDisable(m_body); +} + +void CPHElement::ReEnable(){ + + //dJointGroupEmpty(m_saved_contacts); + //b_contacts_saved=false; + +} + +void CPHElement::Freeze() +{ + if(!m_body) return; + + m_flags.set(flWasEnabledBeforeFreeze,!!dBodyIsEnabled(m_body)); + dBodyDisable(m_body); +} +void CPHElement::UnFreeze() +{ + if(!m_body) return; + if(m_flags.test(flWasEnabledBeforeFreeze)/*was_enabled_before_freeze*/)dBodyEnable(m_body); +} + +bool dbg_draw_ph_force_apply = false; + +void CPHElement::applyImpulseVsMC(const Fvector& pos,const Fvector& dir, float val) +{ + if(!isActive()||m_flags.test(flFixed)) return; + if( !dBodyIsEnabled(m_body)) dBodyEnable(m_body); + ///////////////////////////////////////////////////////////////////////// + Fvector impulse; + val/=fixed_step; + impulse.set(dir); + impulse.mul(val); +#ifdef DEBUG + if( dbg_draw_ph_force_apply ) + { + Fvector draw_pos; draw_pos.add( cast_fv( dBodyGetPosition( m_body ) ), pos ); + debug_output().DBG_OpenCashedDraw(); + debug_output().DBG_DrawLine( draw_pos, Fvector().add( draw_pos, dir ), D3DCOLOR_XRGB(255,0,0) ); + debug_output().DBG_ClosedCashedDraw( 50000 ); + } +#endif + dBodyAddForceAtRelPos(m_body, impulse.x,impulse.y,impulse.z,pos.x, pos.y,pos.z); + BodyCutForce(m_body,m_l_limit,m_w_limit); + //////////////////////////////////////////////////////////////////////// +} +void CPHElement::applyImpulseVsGF(const Fvector& pos,const Fvector& dir, float val) +{ + VERIFY(_valid(pos)&&_valid(dir)&&_valid(val)); + if(!isActive()||m_flags.test(flFixed)) return; + if( !dBodyIsEnabled(m_body)) dBodyEnable(m_body); + ///////////////////////////////////////////////////////////////////////// +#ifdef DEBUG + if( dbg_draw_ph_force_apply ) + { + debug_output().DBG_OpenCashedDraw(); + debug_output().DBG_DrawLine( pos, Fvector().add( pos, dir ), D3DCOLOR_XRGB(255,05,0) ); + debug_output().DBG_ClosedCashedDraw( 50000 ); + } +#endif + ///////////////////////////////////////////////////////////////////////// + Fvector impulse; + val/=fixed_step; + impulse.set(dir); + impulse.mul(val); + dBodyAddForceAtPos(m_body, impulse.x,impulse.y,impulse.z,pos.x, pos.y,pos.z); + BodyCutForce(m_body,m_l_limit,m_w_limit); + VERIFY(dBodyStateValide(m_body)); + //////////////////////////////////////////////////////////////////////// +} +void CPHElement:: applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val,u16 id) +{ + + VERIFY(_valid(pos)&&_valid(dir)&&_valid(val)); + if(!isActive()||m_flags.test(flFixed)) return; + Fvector body_pos; + if(id!=BI_NONE) + { + if(id==m_SelfID) + { + body_pos.sub(pos,m_mass_center); + } + else + { + IKinematics* K=m_shell->PKinematics(); + if(K) + { + Fmatrix(). + mul_43( Fmatrix().invert( K->LL_GetTransform( m_SelfID ) ), + K->LL_GetTransform( id ) ) + .transform(body_pos,pos); + body_pos.sub(m_mass_center); + } + else + { + body_pos.set(0.f,0.f,0.f); + } + } + } + else + { + body_pos.set(0.f,0.f,0.f); + } +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phHitApplicationPoints)) + { + debug_output().DBG_OpenCashedDraw(); + Fvector dbg_position;dbg_position.set(body_pos); + dMULTIPLY0_331 (cast_fp(dbg_position),dBodyGetRotation(m_body),cast_fp(body_pos)); + dbg_position.add(cast_fv(dBodyGetPosition(m_body))); + debug_output().DBG_DrawPoint(dbg_position,0.01f,D3DCOLOR_XRGB(255,255,255)); + debug_output().DBG_DrawLine(cast_fv(dBodyGetPosition(m_body)),dbg_position,D3DCOLOR_XRGB(255,255,255)); + debug_output().DBG_DrawLine(dbg_position,Fvector().add(dbg_position,Fvector().mul(dir,0.4f)),D3DCOLOR_XRGB(255,0,255)); + debug_output().DBG_ClosedCashedDraw(10000); + } +#endif + applyImpulseVsMC(body_pos,dir,val); + if(m_fratures_holder) + { + ///impulse.add(*((Fvector*)dBodyGetPosition(m_body))); + Fvector impulse;impulse.set(dir);impulse.mul(val/fixed_step); + m_fratures_holder->AddImpact(impulse,body_pos,m_shell->BoneIdToRootGeom(id)); + } +} +void CPHElement::applyImpact(const SPHImpact& I) +{ + Fvector pos; + pos.add(I.point,m_mass_center); + Fvector dir; + dir.set(I.force); + float val=I.force.magnitude(); + + if(!fis_zero(val)&& GeomByBoneID(I.geom)) + { + + dir.mul(1.f/val); + applyImpulseTrace(pos,dir,val,I.geom); + } + +} +void CPHElement::InterpolateGlobalTransform(Fmatrix* m){ + if(!m_flags.test(flUpdate)) + { + GetGlobalTransformDynamic(m); + VERIFY(_valid(*m)); + return; + } + m_body_interpolation.InterpolateRotation(*m); + m_body_interpolation.InterpolatePosition(m->c); + MulB43InverceLocalForm(*m); + m_flags.set(flUpdate,FALSE); + VERIFY(_valid(*m)); +} +void CPHElement::GetGlobalTransformDynamic(Fmatrix* m) const +{ + PHDynamicData::DMXPStoFMX(dBodyGetRotation(m_body),dBodyGetPosition(m_body),*m); + MulB43InverceLocalForm(*m); + VERIFY(_valid(*m)); +} + +void CPHElement::InterpolateGlobalPosition(Fvector* v){ + m_body_interpolation.InterpolatePosition(*v); + VERIFY(_valid(*v)); +} + + + + +void CPHElement::build(bool disable){ + + if(isActive()) return; + //bActive=true; + //bActivating=true; + m_flags.set(flActive,TRUE); + m_flags.set(flActivating,TRUE); + build(); + // if(place_current_forms) + { + + SetTransform(mXFORM, mh_unspecified ); + } + + m_body_interpolation.SetBody(m_body); + //previous_f[0]=dInfinity; + if(disable) dBodyDisable(m_body); + + +} + +void CPHElement::RunSimulation(const Fmatrix& start_from) +{ + + RunSimulation(); + // if(place_current_forms) + { + Fmatrix globe; + globe.mul(start_from,mXFORM); + SetTransform(globe, mh_unspecified ); + } + //dVectorSet(m_safe_position,dBodyGetPosition(m_body)); + //dQuaternionSet(m_safe_quaternion,dBodyGetQuaternion(m_body)); + //dVectorSet(m_safe_velocity,dBodyGetLinearVel(m_body)); + +} + + + +void CPHElement::StataticRootBonesCallBack(CBoneInstance* B) +{ + VERIFY( false ); + Fmatrix parent; + VERIFY2( isActive(),"the element is not active"); + VERIFY(_valid(m_shell->mXFORM)); + //VERIFY2(fsimilar(DET(B->mTransform),1.f,DET_CHECK_EPS),"Bones callback resive 0 matrix"); + VERIFY_RMATRIX(B->mTransform); + VERIFY(valid_pos(B->mTransform.c,phBoundaries)); + if(m_flags.test(flActivating)) + { + //if(!dBodyIsEnabled(m_body)) + // dBodyEnable(m_body); + VERIFY(!ph_world->Processing()); + VERIFY(_valid(B->mTransform)); + VERIFY(!m_shell->dSpace()->lock_count); + mXFORM.set(B->mTransform); + //m_start_time=Device.fTimeGlobal; + Fmatrix global_transform; + //if(m_parent_element) + global_transform.mul_43(m_shell->mXFORM,mXFORM); + SetTransform(global_transform, mh_unspecified ); + + FillInterpolation(); + //bActivating=false; + m_flags.set(flActivating,FALSE); + if(!m_parent_element) + { + m_shell->m_object_in_root.set(mXFORM); + m_shell->m_object_in_root.invert(); + m_shell->SetNotActivating(); + } + B->set_callback_overwrite(TRUE); + //VERIFY2(fsimilar(DET(B->mTransform),1.f,DET_CHECK_EPS),"Bones callback returns 0 matrix"); + VERIFY_RMATRIX(B->mTransform); + VERIFY(valid_pos(B->mTransform.c,phBoundaries)); + //return; + } + + + + //VERIFY2(fsimilar(DET(B->mTransform),1.f,DET_CHECK_EPS),"Bones callback returns 0 matrix"); + VERIFY_RMATRIX(B->mTransform); + VERIFY(valid_pos(B->mTransform.c,phBoundaries)); + //if( !m_shell->is_active() && !m_flags.test(flUpdate)/*!bUpdate*/ ) return; + + { + //InterpolateGlobalTransform(&mXFORM); + parent.invert (m_shell->mXFORM); + B->mTransform.mul_43 (parent,mXFORM); + } + //VERIFY2(fsimilar(DET(B->mTransform),1.f,DET_CHECK_EPS),"Bones callback returns 0 matrix"); + VERIFY_RMATRIX(B->mTransform); + VERIFY(valid_pos(B->mTransform.c,phBoundaries)); + VERIFY2(_valid(B->mTransform),"Bones callback returns bad matrix"); + //else + //{ + + // InterpolateGlobalTransform(&m_shell->mXFORM); + // mXFORM.identity(); + // B->mTransform.set(mXFORM); + //parent.set(B->mTransform); + //parent.invert(); + //m_shell->mXFORM.mulB(parent); + + //} + + +} + +//void CPHElement::BoneGlPos(Fmatrix &m, const CBoneInstance* B) const +void CPHElement::BoneGlPos(Fmatrix &m, const Fmatrix &BoneTransform) const +{ + VERIFY(m_shell); + m.mul_43(m_shell->mXFORM, BoneTransform); +} + +void CPHElement::GetAnimBonePos(Fmatrix &bp) +{ + VERIFY(m_shell->PKinematics()); + IKinematics *pK = m_shell->PKinematics(); + //IKinematicsAnimated *ak = pK->dcast_PKinematicsAnimated(); + //VERIFY(ak); + CBoneInstance *BI = &pK->LL_GetBoneInstance(m_SelfID); + if(!BI->callback())//. + { + bp.set(BI->mTransform); + return; + } + + pK->Bone_GetAnimPos( bp, m_SelfID, u8(-1), true ); + +} + +IC bool put_in_range( Fvector &v, float range ) +{ + VERIFY( range > EPS_S ); + float sq_mag=v.square_magnitude( ); + if( sq_mag > range*range ) + { + float mag=_sqrt( sq_mag ); + v.mul( range/mag ); + return true; + } + return false; +} + + + +bool CPHElement::AnimToVel( float dt, float l_limit, float a_limit ) +{ + VERIFY(m_shell); + VERIFY(m_shell->PKinematics()); + //CBoneInstance *BI = &m_shell->PKinematics()->LL_GetBoneInstance(m_SelfID); +// +// Fmatrix bp;BoneGlPos(bp,BI); +// + IPhysicsShellHolder *ph = PhysicsRefObject(); + VERIFY(ph); + Fmatrix bpl;GetAnimBonePos(bpl); + Fmatrix bp;bp.mul_43(ph->ObjectXFORM(),bpl); + //BoneGlPos(bp,BI); + + Fmatrix cp; + GetGlobalTransformDynamic(&cp); + + //Fquaternion q0; q0.set(cp); + + cp.invert(); + Fmatrix diff;diff.mul_43(cp,bp); + if(dtProcessing(), PhysicsRefObject()->ObjectNameSect() ); + VERIFY( _valid( BoneTransform ) ); + VERIFY( !m_shell->dSpace()->lock_count ); + + //mXFORM.set( B->mTransform ); + + //Fmatrix global_transform; + BoneGlPos( mXFORM, BoneTransform ); + SetTransform( mXFORM, history_state ); + FillInterpolation( ); +} +void CPHElement::ToBonePos(const CBoneInstance* B, motion_history_state history_state ) +{ + VERIFY( B ); + ToBonePos(B->mTransform, history_state ); +} + +void CPHElement::SetBoneCallbackOverwrite( bool v ) +{ + VERIFY(m_shell); + VERIFY(m_shell->PKinematics()); + m_shell->PKinematics()->LL_GetBoneInstance(m_SelfID).set_callback_overwrite (v); +} + + + +void CPHElement::BonesCallBack( CBoneInstance* B ) +{ + + VERIFY ( isActive() ); + VERIFY( _valid( m_shell->mXFORM ) ); + //VERIFY2(fsimilar(DET(B->mTransform),1.f,DET_CHECK_EPS),"Bones callback receive 0 matrix"); + VERIFY_RMATRIX( B->mTransform ); + VERIFY_BOUNDARIES2( B->mTransform.c, phBoundaries, PhysicsRefObject(), "BonesCallBack incoming bone position" ); + + if( m_flags.test( flActivating ) ) + { + ActivatingPos(B->mTransform); + B->set_callback_overwrite( TRUE ); + } + + VERIFY_RMATRIX( B->mTransform ); + VERIFY( valid_pos( B->mTransform.c, phBoundaries ) ); + + CalculateBoneTransform( B->mTransform ); + +// Fmatrix parent; +// parent.invert ( m_shell->mXFORM ); +// B->mTransform.mul_43( parent, mXFORM ); + + VERIFY_RMATRIX( B->mTransform ); + VERIFY( valid_pos( B->mTransform.c, phBoundaries ) ); + VERIFY2( _valid( B->mTransform ), "Bones callback returns bad matrix" ); + +} + +void CPHElement::set_PhysicsRefObject(IPhysicsShellHolder* ref_object) +{ + CPHGeometryOwner::set_PhysicsRefObject(ref_object); +} + + +void CPHElement::set_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + CPHGeometryOwner::set_ObjectContactCallback(callback); +} +void CPHElement::add_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + CPHGeometryOwner::add_ObjectContactCallback(callback); +} +void CPHElement::remove_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + CPHGeometryOwner::remove_ObjectContactCallback(callback); +} +ObjectContactCallbackFun* CPHElement::get_ObjectContactCallback() +{ + return CPHGeometryOwner::get_ObjectContactCallback(); +} +void CPHElement::set_CallbackData(void * cd) +{ + CPHGeometryOwner::set_CallbackData(cd); +} +void* CPHElement:: get_CallbackData () +{ + return CPHGeometryOwner::get_CallbackData(); +} +void CPHElement::set_ContactCallback(ContactCallbackFun* callback) +{ + //push_untill=0; + CPHGeometryOwner::set_ContactCallback(callback); +} + +void CPHElement::SetMaterial(u16 m) +{ + CPHGeometryOwner::SetMaterial(m); +} + +dMass* CPHElement::getMassTensor() //aux +{ + return &m_mass; +} + +void CPHElement::setInertia(const dMass& M) +{ + m_mass=M; + if(!isActive()||m_flags.test(flFixed))return; + dBodySetMass(m_body,&M); +} + +void CPHElement::addInertia(const dMass& M) +{ + dMassAdd(&m_mass,&M); + if(!isActive())return; + dBodySetMass(m_body,&m_mass); +} +void CPHElement::get_LinearVel(Fvector& velocity) const +{ + if( !isActive()|| + ( !m_flags.test( flAnimated ) && !dBodyIsEnabled( m_body ) ) + ) + { + velocity.set(0,0,0); + return; + } + dVectorSet((dReal*)&velocity,dBodyGetLinearVel(m_body)); + +} +void CPHElement::get_AngularVel (Fvector& velocity) const +{ + if( !isActive()|| + ( !m_flags.test( flAnimated ) && !dBodyIsEnabled( m_body ) ) + ) + { + velocity.set(0,0,0); + return; + } + dVectorSet((dReal*)&velocity,dBodyGetAngularVel(m_body)); +} + + +void CPHElement::set_LinearVel (const Fvector& velocity) +{ + + if(!isActive()||m_flags.test(flFixed)) return; + VERIFY2(_valid(velocity),"not valid arqument velocity"); + Fvector vel = velocity; +#ifdef DEBUG + if( velocity.magnitude() > m_l_limit ) + Msg(" CPHElement::set_LinearVel set velocity magnitude is too large %f",velocity.magnitude()); +#endif + put_in_range(vel,m_l_limit); + dBodySetLinearVel(m_body,vel.x,vel.y,vel.z); + //dVectorSet(m_safe_velocity,dBodyGetLinearVel(m_body)); +} + + +void CPHElement::set_AngularVel (const Fvector& velocity) +{ + VERIFY(_valid(velocity)); + if(!isActive()||m_flags.test(flFixed)) return; + + Fvector vel = velocity; +#ifdef DEBUG + if( velocity.magnitude() > m_w_limit ) + Msg("CPHElement::set_AngularVel set velocity magnitude is too large %f",velocity.magnitude()); +#endif + put_in_range(vel,m_w_limit); + dBodySetAngularVel(m_body,vel.x,vel.y,vel.z); +} + +void CPHElement::getForce(Fvector& force) +{ + if(!isActive()) return; + force.set(*(Fvector*)dBodyGetForce(m_body)); + VERIFY(dBodyStateValide(m_body)); +} +void CPHElement::getTorque(Fvector& torque) +{ + if(!isActive()) return; + torque.set(*(Fvector*)dBodyGetTorque(m_body)); + VERIFY(dBodyStateValide(m_body)); +} +void CPHElement::setForce(const Fvector& force) +{ + if(!isActive()||m_flags.test(flFixed)) return; + if( !dBodyIsEnabled(m_body)) dBodyEnable(m_body); + m_shell->EnableObject(0); + dBodySetForce(m_body,force.x,force.y,force.z); + BodyCutForce(m_body,m_l_limit,m_w_limit); + VERIFY(dBodyStateValide(m_body)); +} +void CPHElement::setTorque(const Fvector& torque) +{ + if(!isActive()||m_flags.test(flFixed)) return; + if( !dBodyIsEnabled(m_body)) dBodyEnable(m_body); + m_shell->EnableObject(0); + dBodySetTorque(m_body,torque.x,torque.y,torque.z); + BodyCutForce(m_body,m_l_limit,m_w_limit); + VERIFY(dBodyStateValide(m_body)); +} + +void CPHElement::applyForce(const Fvector& dir, float val) //aux +{ + applyForce (dir.x*val,dir.y*val,dir.z*val); +} +void CPHElement::applyForce(float x,float y,float z) //called anywhere ph state influent +{ + VERIFY(_valid(x)&&_valid(y)&&_valid(z)); + if(!isActive())return;//hack?? + if(m_flags.test(flFixed)) return; + if( !dBodyIsEnabled(m_body)) dBodyEnable(m_body); + m_shell->EnableObject(0); + dBodyAddForce(m_body,x,y,z); + BodyCutForce(m_body,m_l_limit,m_w_limit); + VERIFY(dBodyStateValide(m_body)); +} + +void CPHElement::applyImpulse(const Fvector& dir, float val)//aux +{ + + applyForce(dir.x*val/fixed_step,dir.y*val/fixed_step,dir.z*val/fixed_step); +} + + + +void CPHElement::add_Shape(const SBoneShape& shape,const Fmatrix& offset) +{ + CPHGeometryOwner::add_Shape(shape,offset); +} + +void CPHElement::add_Shape(const SBoneShape& shape) +{ + CPHGeometryOwner::add_Shape(shape); +} + + + +void CPHElement:: add_geom ( CODEGeom* g ) +{ + Fmatrix gf; + g->get_xform( gf ); + + Fmatrix bf; + PHDynamicData::DMXPStoFMX( dBodyGetRotation( m_body ), dBodyGetPosition( m_body ), bf ); + + Fmatrix diff = Fmatrix().mul_43( Fmatrix().invert( bf ), gf ) ; + + dMatrix3 m; + PHDynamicData::FMXtoDMX( diff, m ); + + VERIFY(g->geom()); + dGeomSetPosition( g->geom(), diff.c.x, diff.c.y, diff.c.z ); + dGeomSetRotation( g->geom(), m ); + + g->set_body( m_body ); + CPHGeometryOwner::add_geom( g ); + +} + +void CPHElement:: remove_geom ( CODEGeom* g ) +{ + g->set_body( 0 ); + CPHGeometryOwner::remove_geom(g); +} + + + +#pragma todo(remake it using Geometry functions) + +void CPHElement::add_Mass(const SBoneShape& shape,const Fmatrix& offset,const Fvector& mass_center,float mass,CPHFracture* fracture) +{ + + dMass m; + dMatrix3 DMatx; + switch(shape.type) + { + case SBoneShape::stBox : + { + dMassSetBox(&m,1.f,shape.box.m_halfsize.x*2.f,shape.box.m_halfsize.y*2.f,shape.box.m_halfsize.z*2.f); + dMassAdjust(&m,mass); + Fmatrix box_transform; + shape.box.xform_get(box_transform); + PHDynamicData::FMX33toDMX(shape.box.m_rotate,DMatx); + dMassRotate(&m,DMatx); + dMassTranslate(&m,shape.box.m_translate.x-mass_center.x,shape.box.m_translate.y-mass_center.y,shape.box.m_translate.z-mass_center.z); + break; + } + case SBoneShape::stSphere : + { + shape.sphere; + dMassSetSphere(&m,1.f,shape.sphere.R); + dMassAdjust(&m,mass); + dMassTranslate(&m,shape.sphere.P.x-mass_center.x,shape.sphere.P.y-mass_center.y,shape.sphere.P.z-mass_center.z); + break; + } + + + case SBoneShape::stCylinder : + { + const Fvector& pos=shape.cylinder.m_center; + Fvector l; + l.sub(pos,mass_center); + dMassSetCylinder(&m,1.f,2,shape.cylinder.m_radius,shape.cylinder.m_height); + dMassAdjust(&m,mass); + dMatrix3 DMatx; + Fmatrix33 m33; + m33.j.set(shape.cylinder.m_direction); + Fvector::generate_orthonormal_basis(m33.j,m33.k,m33.i); + PHDynamicData::FMX33toDMX(m33,DMatx); + dMassRotate(&m,DMatx); + dMassTranslate(&m,l.x,l.y,l.z); + break; + } + + case SBoneShape::stNone : + break; + default: NODEFAULT; + } + PHDynamicData::FMXtoDMX(offset,DMatx); + dMassRotate(&m,DMatx); + + Fvector mc; + offset.transform_tiny(mc,mass_center); + //calculate _new mass_center + //new_mc=(m_mass_center*m_mass.mass+mc*mass)/(mass+m_mass.mass) + Fvector tmp1; + tmp1.set(m_mass_center); + tmp1.mul(m_mass.mass); + Fvector tmp2; + tmp2.set(mc); + tmp2.mul(mass); + Fvector new_mc; + new_mc.add(tmp1,tmp2); + new_mc.mul(1.f/(mass+m_mass.mass)); + mc.sub(new_mc); + dMassTranslate(&m,mc.x,mc.y,mc.z); + m_mass_center.sub(new_mc); + dMassTranslate(&m_mass,m_mass_center.x,m_mass_center.y,m_mass_center.z); + if(m_fratures_holder) + { + m_fratures_holder->DistributeAdditionalMass(u16(m_geoms.size()-1),m); + } + if(fracture) + { + fracture->MassAddToSecond(m); + } + R_ASSERT2(dMass_valide(&m),"bad bone mass params"); + dMassAdd(&m_mass,&m); + R_ASSERT2(dMass_valide(&m),"bad result mass params"); + m_mass_center.set(new_mc); +} + +void CPHElement::set_BoxMass(const Fobb& box, float mass) +{ + dMassSetZero(&m_mass); + m_mass_center.set(box.m_translate); + const Fvector& hside=box.m_halfsize; + dMassSetBox(&m_mass,1,hside.x*2.f,hside.y*2.f,hside.z*2.f); + dMassAdjust(&m_mass,mass); + dMatrix3 DMatx; + PHDynamicData::FMX33toDMX(box.m_rotate,DMatx); + dMassRotate(&m_mass,DMatx); + +} + +void CPHElement::calculate_it_data_use_density(const Fvector& mc,float density) +{ + dMassSetZero(&m_mass); + GEOM_I i_geom=m_geoms.begin(),e=m_geoms.end(); + for(;i_geom!=e;++i_geom)(*i_geom)->add_self_mass(m_mass,mc,density); + VERIFY2(dMass_valide(&m_mass),"non valide mass obtained!"); +} + +float CPHElement::getRadius() +{ + return CPHGeometryOwner::getRadius(); +} + +void CPHElement::set_DynamicLimits(float l_limit,float w_limit) +{ + m_l_limit=l_limit; + m_w_limit=w_limit; +} + +void CPHElement::set_DynamicScales(float l_scale/* =default_l_scale */,float w_scale/* =default_w_scale */) +{ + m_l_scale=l_scale; + m_w_scale=w_scale; +} + +void CPHElement::set_DisableParams (const SAllDDOParams& params) +{ + CPHDisablingFull::set_DisableParams(params); +} + + + + +void CPHElement::get_Extensions(const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext) const +{ + CPHGeometryOwner::get_Extensions(axis,center_prg,lo_ext,hi_ext); +} + +const Fvector& CPHElement::mass_Center()const +{ + VERIFY(dBodyStateValide(m_body)); + return *((const Fvector*)dBodyGetPosition(m_body)); +} + +CPhysicsShell* CPHElement::PhysicsShell() +{ + return smart_cast(m_shell); +} + +CPHShell* CPHElement::PHShell() +{ + return (m_shell); +} +void CPHElement::SetShell(CPHShell* p) +{ + if(!m_body||!m_shell) + { + m_shell=p; + return; + } + if(m_shell!=p) + { + m_shell->Island().RemoveBody(m_body); + p->Island().AddBody(m_body); + m_shell=p; + } + +} +void CPHElement::PassEndGeoms(u16 from,u16 to,CPHElement* dest) +{ + GEOM_I i_from=m_geoms.begin()+from,e=m_geoms.begin()+to; + u16 shift=to-from; + GEOM_I i=i_from; + for(;i!=e;++i) + { + //(*i)->remove_from_space( group_space() ); + group_remove( *(*i) ); + //(*i)->add_to_space(dest->m_group); + //(*i)->set_body(dest->m_body); + (*i)->set_body(0); + u16& element_pos=(*i)->element_position(); + element_pos=element_pos-shift; + } + GEOM_I last=m_geoms.end(); + for(;i!=last;++i) + { + u16& element_pos=(*i)->element_position(); + element_pos=element_pos-shift; + } + + dest->m_geoms.insert(dest->m_geoms.end(),i_from,e); + dest->b_builded=true; + m_geoms.erase(i_from,e); +} +void CPHElement::SplitProcess(ELEMENT_PAIR_VECTOR &new_elements) +{ + m_fratures_holder->SplitProcess(this,new_elements); + if(!m_fratures_holder->m_fractures.size()) xr_delete(m_fratures_holder); +} +void CPHElement::DeleteFracturesHolder() +{ + xr_delete(m_fratures_holder); +} + +void CPHElement::CreateSimulBase() +{ + m_body=dBodyCreate(0); + m_shell->Island().AddBody(m_body); + //m_saved_contacts=dJointGroupCreate (0); + //b_contacts_saved=false; + dBodyDisable(m_body); + //CPHGeometryOwner::CreateGroupSpace( ); +} +void CPHElement::ReAdjustMassPositions(const Fmatrix &shift_pivot,float density) +{ + + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + (*i)->move_local_basis(shift_pivot); + } + if(m_shell->PKinematics()) + { + float mass; + get_mc_kinematics(m_shell->PKinematics(),m_mass_center,mass); + calculate_it_data(m_mass_center,mass); + } + else + { + + setDensity(density); + } + + dBodySetMass(m_body,&m_mass); + //m_inverse_local_transform.identity(); + //m_inverse_local_transform.c.set(m_mass_center); + //m_inverse_local_transform.invert(); + //dBodySetPosition(m_body,m_mass_center.x,m_mass_center.y,m_mass_center.z); +} +void CPHElement::ResetMass(float density) +{ + Fvector tmp,shift_mc; + + tmp.set(m_mass_center); + + + setDensity(density); + dBodySetMass(m_body,&m_mass); + + shift_mc.sub(m_mass_center,tmp); + tmp.set(*(Fvector *)dBodyGetPosition(m_body)); + tmp.add(shift_mc); + + + //bActivating = true; + m_flags.set(flActivating,TRUE); + + CPHGeometryOwner::setPosition(m_mass_center); +} +void CPHElement::ReInitDynamics(const Fmatrix &shift_pivot,float density) +{ + VERIFY(_valid(shift_pivot)&&_valid(density)); + ReAdjustMassPositions(shift_pivot,density); + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + (*i)->set_build_position(m_mass_center); + (*i)->set_body(m_body); + //if(object_contact_callback)geom.set_obj_contact_cb(object_contact_callback); + //if(m_phys_ref_object) geom.set_ref_object(m_phys_ref_object); +/* + if(m_group) + { + (*i)->add_to_space((dSpaceID)m_group); + } +*/ + group_add(*(*i)); + } +} + +void CPHElement::PresetActive() +{ + if(isActive()) return; + + CBoneInstance& B=m_shell->PKinematics()->LL_GetBoneInstance(m_SelfID); + mXFORM.set(B.mTransform); + //m_start_time=Device.fTimeGlobal; + Fmatrix global_transform; + global_transform.mul_43(m_shell->mXFORM, mXFORM); + SetTransform(global_transform, mh_unspecified ); + + if(!m_parent_element) + { + m_shell->m_object_in_root.set(mXFORM); + m_shell->m_object_in_root.invert(); + + } + //dVectorSet(m_safe_position,dBodyGetPosition(m_body)); + //dQuaternionSet(m_safe_quaternion,dBodyGetQuaternion(m_body)); + //dVectorSet(m_safe_velocity,dBodyGetLinearVel(m_body)); + + ////////////////////////////////////////////////////////////// + //initializing values for disabling////////////////////////// + ////////////////////////////////////////////////////////////// + VERIFY(dBodyStateValide(m_body)); + m_body_interpolation.SetBody(m_body); + FillInterpolation(); + //bActive=true; + m_flags.set(flActive,TRUE); + RunSimulation(); + VERIFY(dBodyStateValide(m_body)); +} + + +bool CPHElement::isBreakable() +{ + return !!m_fratures_holder; +} +u16 CPHElement::setGeomFracturable(CPHFracture& fracture) +{ + if(!m_fratures_holder) m_fratures_holder=xr_new(); + return m_fratures_holder->AddFracture(fracture); +} + +CPHFracture& CPHElement::Fracture(u16 num) +{ + R_ASSERT2(m_fratures_holder,"no fractures!"); + return m_fratures_holder->Fracture(num); +} +u16 CPHElement::numberOfGeoms()const +{ + return CPHGeometryOwner::numberOfGeoms(); +} + + +void CPHElement::cv2bone_Xfrom(const Fquaternion& q,const Fvector& pos, Fmatrix& xform) +{ + VERIFY2(_valid(q)&&_valid(pos),"cv2bone_Xfrom receive wrong data"); + xform.rotation(q); + xform.c.set(pos); + //xform.mulB(m_inverse_local_transform); + MulB43InverceLocalForm(xform); + VERIFY2(_valid(xform),"cv2bone_Xfrom returns wrong data"); +} +void CPHElement::cv2obj_Xfrom(const Fquaternion& q,const Fvector& pos, Fmatrix& xform) +{ + + cv2bone_Xfrom(q,pos,xform); + xform.mulB_43(m_shell->m_object_in_root); + VERIFY2(_valid(xform),"cv2obj_Xfrom returns wrong data"); +} + +void CPHElement::set_ApplyByGravity(bool flag) +{ + if(!isActive()||m_flags.test(flFixed)) return; + dBodySetGravityMode(m_body,flag); +} +bool CPHElement::get_ApplyByGravity() +{ + return (!!dBodyGetGravityMode(m_body)); +} + +void CPHElement::Fix() +{ + m_flags.set(flFixed,TRUE); + FixBody(m_body); +} + +void CPHElement::SetAnimated( bool v ) +{ + m_flags.set( flAnimated, BOOL( v ) ); +} + +void CPHElement::ReleaseFixed() +{ + if(!isFixed()) return; + m_flags.set(flFixed,FALSE); + if(!isActive())return; + dBodySetMass(m_body,&m_mass); +} +void CPHElement::applyGravityAccel (const Fvector& accel) +{ + VERIFY(_valid(accel)); + if(m_flags.test(flFixed)) return; + if( !dBodyIsEnabled(m_body)) dBodyEnable(m_body); + m_shell->EnableObject(0); + Fvector val; + val.set(accel); + val.mul(m_mass.mass); + //ApplyGravityAccel(m_body,(const dReal*)(&accel)); + applyForce(val.x,val.y,val.z); +} + + +void CPHElement::CutVelocity(float l_limit,float a_limit) +{ + + if(!isActive())return; + VERIFY(_valid(l_limit)&&_valid(a_limit)); + dVector3 limitedl,limiteda,diffl,diffa; + bool blimitl=dVectorLimit(dBodyGetLinearVel(m_body),l_limit,limitedl); + bool blimita=dVectorLimit(dBodyGetAngularVel(m_body),a_limit,limiteda); + + if(blimitl||blimita) + { + dVectorSub(diffl,limitedl,dBodyGetLinearVel(m_body)); + dVectorSub(diffa,limiteda,dBodyGetAngularVel(m_body)); + dBodySetLinearVel(m_body,diffl[0],diffl[1],diffl[2]); + dBodySetAngularVel(m_body,diffa[0],diffa[1],diffa[2]); + dxStepBody(m_body,fixed_step); + dBodySetLinearVel(m_body,limitedl[0],limitedl[1],limitedl[2]); + dBodySetAngularVel(m_body,limiteda[0],limiteda[1],limiteda[2]); + } +} +void CPHElement::ClearDestroyInfo() +{ + xr_delete(m_fratures_holder); +} + +void CPHElement::GetPointVel( Fvector &res_vel, const Fvector & point ) const +{ + dVector3 res; + //Fvector res_vel; + dBodyGetPointVel(get_bodyConst(),point.x,point.y,point.z,res); + CopyMemory (&res_vel,res,sizeof(Fvector)); +} + +#ifdef DEBUG + +void CPHElement::dbg_draw_velocity ( float scale, u32 color ) +{ + VERIFY( isActive() ); + VERIFY( m_shell ); + VERIFY( m_shell->PKinematics() ); + Fmatrix bone; + GetGlobalTransformDynamic( &bone ); + VERIFY( m_body ); + dVector3 res; + dBodyGetPointVel( m_body, bone.c.x, bone.c.y, bone.c.z, res ); + debug_output().DBG_DrawPoint( bone.c, 0.01f, color ); + debug_output().DBG_DrawLine( bone.c, Fvector().add( bone.c, cast_fv( res ).mul( scale ) ) , color ); + //m_shell->PKinematics()->LL_GetTransform() +} + +static void dBodyGetPointForce (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + VERIFY (b); + dVector3 p; + p[0] = px - b->pos[0]; + p[1] = py - b->pos[1]; + p[2] = pz - b->pos[2]; + p[3] = 0; + result[0] = b->facc[0]; + result[1] = b->facc[1]; + result[2] = b->facc[2]; + dCROSS (result,+=,b->tacc,p); +} + +void CPHElement::dbg_draw_force ( float scale, u32 color ) +{ + VERIFY( isActive() ); + VERIFY( m_shell ); + VERIFY( m_shell->PKinematics() ); + Fmatrix bone; + GetGlobalTransformDynamic( &bone ); + VERIFY( m_body ); + dVector3 res; + dBodyGetPointForce( m_body, bone.c.x, bone.c.y, bone.c.z, res ); + debug_output().DBG_DrawPoint( bone.c, 0.01f, color ); + debug_output().DBG_DrawLine( bone.c, Fvector().add( bone.c, cast_fv( res ).mul( scale ) ) , color ); +} + +void CPHElement:: dbg_draw_geometry( float scale, u32 color, Flags32 flags /*= Flags32().assign( 0 )*/ ) const +{ + CPHGeometryOwner::dbg_draw( scale, color, flags ); +} +#endif +//bool CPHElement::CheckBreakConsistent() +//{ +// if(!m_fratures_holder) return true; +// m_fratures_holder->m_fractures +// m_fratures_holder->Fracture() +//}) return true; +// m_fratures_holder->m_fractures +// m_fratures_holder->Fracture() +//} \ No newline at end of file diff --git a/xrPhysics/PHElement.h b/xrPhysics/PHElement.h new file mode 100644 index 00000000000..a3877ba8be3 --- /dev/null +++ b/xrPhysics/PHElement.h @@ -0,0 +1,294 @@ +///////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +///////////////////////////Implemetation//for//CPhysicsElement////////////////// +//////////////////////////////////////////////////////////////////////////////// +#include "Geometry.h" +#include "phdefs.h" +#include "PhysicsCommon.h" +#include "../xrserverentities/PHSynchronize.h" +#include "PHDisabling.h" +#include "PHGeometryOwner.h" +#include "PHInterpolation.h" +#include "PHFracture.h" +#include "physics_scripted.h" +#ifndef PH_ELEMENT +#define PH_ELEMENT +class CPHElement; +class CPHShell; + + +struct SPHImpact; +class CPHFracturesHolder; + +class CPHElement : + public CPhysicsElement , + public CPHSynchronize, + public CPHDisablingFull, + public CPHGeometryOwner, + public cphysics_scripted +{ + friend class CPHFracturesHolder; + + //float m_start_time; //uu ->to shell ?? //aux + dMass m_mass; //e ?? //bl + dBodyID m_body; //e //st + dReal m_l_scale; // ->to shell ?? //bl + dReal m_w_scale; // ->to shell ?? //bl + CPHElement *m_parent_element; //bool ! //bl + CPHShell *m_shell; //e //bl + CPHInterpolation m_body_interpolation; //e //bl + CPHFracturesHolder *m_fratures_holder; //e //bl + + dReal m_w_limit ; //->to shell ?? //bl + dReal m_l_limit ; //->to shell ?? //bl +// dVector3 m_safe_position; //e //st +// dQuaternion m_safe_quaternion; +// dVector3 m_safe_velocity; //e //st +// Fmatrix m_inverse_local_transform; //e //bt + dReal k_w; //->to shell ?? //st + dReal k_l; //->to shell ?? //st + //ObjectContactCallbackFun* temp_for_push_out; //->to shell ?? //aux + //u32 push_untill; //->to shell ?? //st + Flags8 m_flags; // + enum + { + flActive = 1<<0, + flActivating = 1<<1, + flUpdate = 1<<2, + flWasEnabledBeforeFreeze= 1<<3, + flEnabledOnStep = 1<<4, + flFixed = 1<<5, + flAnimated = 1<<6 + }; +// bool was_enabled_before_freeze; +// bool bUpdate; //->to shell ?? //st +// bool b_enabled_onstep; +private: +////////////////////////////////////////////Interpolation///////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void FillInterpolation () //interpolation called anywhere visual influent + { + m_body_interpolation.ResetPositions(); + m_body_interpolation.ResetRotations(); + //bUpdate=true; + m_flags.set(flUpdate,TRUE); + } +IC void UpdateInterpolation () //interpolation called from ph update visual influent + { + ///VERIFY(dBodyStateValide(m_body)); + m_body_interpolation.UpdatePositions(); + m_body_interpolation.UpdateRotations(); + //bUpdate=true; + m_flags.set(flUpdate,TRUE); + } +public: +////////////////////////////////////////////////Geometry///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void add_Sphere (const Fsphere& V); //aux + virtual void add_Box (const Fobb& V); //aux + virtual void add_Cylinder (const Fcylinder& V); //aux + virtual void add_Shape (const SBoneShape& shape); //aux + virtual void add_Shape (const SBoneShape& shape,const Fmatrix& offset); //aux + virtual CODEGeom* last_geom (){return CPHGeometryOwner::last_geom();} + virtual CODEGeom* geometry ( u16 i ){ return CPHGeometryOwner::Geom( i ); } + virtual const IPhysicsGeometry* geometry ( u16 i )const { return CPHGeometryOwner::Geom( i ); }; + virtual void add_geom ( CODEGeom* g ); + virtual void remove_geom ( CODEGeom* g ); + virtual bool has_geoms (){return CPHGeometryOwner::has_geoms();} + virtual void set_ContactCallback (ContactCallbackFun* callback); //aux (may not be) + virtual void set_ObjectContactCallback (ObjectContactCallbackFun* callback); //called anywhere ph state influent + virtual void add_ObjectContactCallback (ObjectContactCallbackFun* callback); //called anywhere ph state influent + virtual void remove_ObjectContactCallback (ObjectContactCallbackFun* callback); + virtual void set_CallbackData (void * cd); + virtual void *get_CallbackData (); + virtual ObjectContactCallbackFun *get_ObjectContactCallback (); + virtual void set_PhysicsRefObject (IPhysicsShellHolder* ref_object); //aux + virtual IPhysicsShellHolder* PhysicsRefObject (){return m_phys_ref_object;} //aux + virtual void SetMaterial (u16 m); //aux + virtual void SetMaterial (LPCSTR m){CPHGeometryOwner::SetMaterial(m);} //aux + virtual u16 numberOfGeoms ()const; //aux + virtual const Fvector& local_mass_Center () {return CPHGeometryOwner::local_mass_Center();} //aux + virtual float getVolume () {return CPHGeometryOwner::get_volume();} //aux + virtual void get_Extensions (const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext) const ; //aux + virtual void get_MaxAreaDir (Fvector& dir){CPHGeometryOwner::get_MaxAreaDir(dir);} + virtual float getRadius (); + virtual void GetPointVel ( Fvector &res_vel, const Fvector & point ) const; +////////////////////////////////////////////////////Mass///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +private: + void calculate_it_data (const Fvector& mc,float mass); //aux + void calculate_it_data_use_density (const Fvector& mc,float density); //aux + void calc_it_fract_data_use_density (const Fvector& mc,float density);//sets element mass and fractures parts mass //aux + dMass recursive_mass_summ (u16 start_geom,FRACTURE_I cur_fracture); //aux +public: // + virtual const Fvector& mass_Center ()const ; //aux + virtual void setDensity (float M); //aux + virtual float getDensity (){return m_mass.mass/m_volume;} //aux + virtual void setMassMC (float M,const Fvector& mass_center); //aux + virtual void setDensityMC (float M,const Fvector& mass_center); //aux + virtual void set_local_mass_center (const Fvector &mc ); + virtual void setInertia (const dMass& M); //aux + virtual void addInertia (const dMass& M); + virtual void add_Mass (const SBoneShape& shape,const Fmatrix& offset,const Fvector& mass_center,float mass,CPHFracture* fracture=NULL);//aux + virtual void set_BoxMass (const Fobb& box, float mass); //aux + virtual void setMass (float M); //aux + virtual float getMass (){return m_mass.mass;} //aux + virtual dMass* getMassTensor (); //aux + void ReAdjustMassPositions (const Fmatrix &shift_pivot,float density); //aux + void ResetMass (float density); //aux + void CutVelocity (float l_limit,float a_limit); +///////////////////////////////////////////////////PushOut/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +private: // + +public: // +//////////////////////////////////////////////Disable///////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void Disable () ; // + virtual void ReEnable () ; // + void Enable () ; //aux + virtual bool isEnabled () const {return isActive()&&dBodyIsEnabled(m_body);} + virtual bool isFullActive () const {return isActive()&&!m_flags.test(flActivating);} + virtual bool isActive () const {return !!m_flags.test(flActive);} + virtual void Freeze () ; // + virtual void UnFreeze () ; // + virtual bool EnabledStateOnStep () {return dBodyIsEnabled(m_body)||m_flags.test(flEnabledOnStep);} // +////////////////////////////////////////////////Updates/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool AnimToVel ( float dt, float l_limit,float a_limit ); + //void BoneGlPos (Fmatrix &m, const CBoneInstance* B)const; + void BoneGlPos (Fmatrix &m, const Fmatrix &BoneTransform)const; + void ToBonePos (const CBoneInstance* B, motion_history_state history_state ); + void ToBonePos (const Fmatrix &BoneTransform, motion_history_state history_state ); + IC void ActivatingPos (const Fmatrix &BoneTransform); + IC void CalculateBoneTransform ( Fmatrix &bone_transform )const; + +#ifdef DEBUG + virtual void dbg_draw_velocity ( float scale, u32 color ); + virtual void dbg_draw_force ( float scale, u32 color ); + virtual void dbg_draw_geometry ( float scale, u32 color, Flags32 flags = Flags32().assign( 0 ) ) const; +#endif + void SetBoneCallbackOverwrite (bool v); + void _BCL BonesCallBack (CBoneInstance* B); //called from updateCL visual influent + void StataticRootBonesCallBack (CBoneInstance* B); + void PhDataUpdate (dReal step); //ph update + void PhTune (dReal step); //ph update + virtual void Update (); //called update CL visual influence +//////////////////////////////////////////////////Dynamics//////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAirResistance (dReal linear=default_k_l, dReal angular=default_k_w) //aux (may not be) + { // + k_w= angular; // + k_l=linear; // + } // + virtual void GetAirResistance (float &linear, float &angular) // + { // + linear= k_l; // + angular=k_w; // + } + virtual void applyImpact (const SPHImpact& impact); // + virtual void applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val,const u16 id) ; //called anywhere ph state influent + virtual void set_DisableParams (const SAllDDOParams& params) ; // + virtual void set_DynamicLimits (float l_limit=default_l_limit,float w_limit=default_w_limit); //aux (may not be) + virtual void set_DynamicScales (float l_scale=default_l_scale,float w_scale=default_w_scale); //aux (may not be) + virtual void Fix (); + virtual void SetAnimated ( bool v ); + virtual void ReleaseFixed (); + virtual bool isFixed (){return !!(m_flags.test(flFixed));} + virtual void applyForce (const Fvector& dir, float val); //aux + virtual void applyForce (float x,float y,float z); //called anywhere ph state influent + virtual void applyImpulse (const Fvector& dir, float val);//aux + virtual void applyImpulseVsMC (const Fvector& pos,const Fvector& dir, float val); // + virtual void applyImpulseVsGF (const Fvector& pos,const Fvector& dir, float val); // + virtual void _BCL applyGravityAccel (const Fvector& accel); + virtual void getForce (Fvector& force); + virtual void getTorque (Fvector& torque); + virtual void get_LinearVel (Fvector& velocity) const; //aux + virtual void get_AngularVel (Fvector& velocity) const; //aux + virtual void set_LinearVel (const Fvector& velocity); //called anywhere ph state influent + virtual void set_AngularVel (const Fvector& velocity); //called anywhere ph state influent + virtual void setForce (const Fvector& force); // + virtual void setTorque (const Fvector& torque); // + virtual void set_ApplyByGravity (bool flag) ; // + virtual bool get_ApplyByGravity () ; // +///////////////////////////////////////////////////Net//////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void get_State ( SPHNetState& state); // + virtual void set_State (const SPHNetState& state); // + virtual void net_Import (NET_Packet& P) ; + virtual void net_Export (NET_Packet& P) ; +///////////////////////////////////////////////////Position/////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetTransform (const Fmatrix& m0, motion_history_state history_state ); // + virtual void TransformPosition (const Fmatrix &form, motion_history_state history_state ); + virtual void getQuaternion (Fquaternion& quaternion); // + virtual void setQuaternion (const Fquaternion& quaternion); // + virtual void SetGlobalPositionDynamic (const Fvector& position); // + virtual void GetGlobalPositionDynamic (Fvector* v); // + virtual void cv2obj_Xfrom (const Fquaternion& q,const Fvector& pos, Fmatrix& xform); // + virtual void cv2bone_Xfrom (const Fquaternion& q,const Fvector& pos, Fmatrix& xform); // + virtual void _BCL InterpolateGlobalTransform (Fmatrix* m); //called UpdateCL vis influent + virtual void InterpolateGlobalPosition (Fvector* v); //aux + virtual void GetGlobalTransformDynamic (Fmatrix* m) const ; //aux +IC void InverceLocalForm (Fmatrix&) ; +IC void MulB43InverceLocalForm (Fmatrix&) const; + +////////////////////////////////////////////////////Structure///////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual CPhysicsShell* PhysicsShell (); //aux + CPHShell* PHShell (); + virtual void set_ParentElement (CPhysicsElement* p){ m_parent_element=(CPHElement*)p; } //aux +#ifdef DEBUG + CPhysicsElement* parent_element (){ return m_parent_element; } +#endif + void SetShell (CPHShell* p); //aux + virtual dBodyID get_body () {return m_body;} //aux + virtual const dBodyID get_bodyConst ()const {return m_body;} //aux +//////////////////////////////////////////////////////Breakable////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + IC CPHFracturesHolder* FracturesHolder (){return m_fratures_holder;} //aux + IC const CPHFracturesHolder* constFracturesHolder ()const{return m_fratures_holder;} //aux + void DeleteFracturesHolder (); // + virtual bool isBreakable (); //aux + virtual u16 setGeomFracturable (CPHFracture& fracture); //aux + virtual CPHFracture& Fracture (u16 num); //aux + void SplitProcess (ELEMENT_PAIR_VECTOR &new_elements); //aux + void PassEndGeoms (u16 from,u16 to,CPHElement* dest); //aux +////////////////////////////////////////////////////Build/Activate//////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void Activate (const Fmatrix& m0, float dt01, const Fmatrix& m2,bool disable=false); //some isues not to be aux + virtual void Activate (const Fmatrix &transform,const Fvector& lin_vel,const Fvector& ang_vel,bool disable=false);//some isues not to be aux + virtual void Activate (bool disable=false, bool not_set_bone_callbacks = false); //some isues not to be aux + virtual void Activate (const Fmatrix& start_from, bool disable=false); //some isues not to be aux + virtual void Deactivate (); //aux //aux + void SetBoneCallback (); + void ClearBoneCallback (); + void CreateSimulBase ();//create body & cpace //aux + void ReInitDynamics (const Fmatrix &shift_pivot,float density); //set body & geom positions + void PresetActive (); // + void build (); //aux + void build (bool disable); //aux + void destroy (); //called anywhere ph state influent + void Start (); //aux + void RunSimulation (); //called anywhere ph state influent + void RunSimulation (const Fmatrix& start_from); // + void ClearDestroyInfo (); + void GetAnimBonePos (Fmatrix &bp); + // bool CheckBreakConsistent () + CPHElement (); //aux + virtual ~CPHElement (); //aux +private: + virtual iphysics_scripted &get_scripted () { return *this ;} +public: +}; + + + + + + +IC CPHElement* cast_PHElement(CPhysicsElement* e){return static_cast(static_cast(e));} +IC CPHElement* cast_PHElement(void* e){return static_cast(static_cast(e));} +IC CPhysicsElement* cast_PhysicsElement(CPHElement* e){return static_cast(static_cast(e));} +#endif \ No newline at end of file diff --git a/xrPhysics/PHElementInline.h b/xrPhysics/PHElementInline.h new file mode 100644 index 00000000000..1f7438ee244 --- /dev/null +++ b/xrPhysics/PHElementInline.h @@ -0,0 +1,43 @@ + + +IC void CPHElement::InverceLocalForm(Fmatrix& m) +{ + m.identity(); + m.c.set(m_mass_center); + m.invert(); +} + +IC void CPHElement::MulB43InverceLocalForm(Fmatrix& m) const +{ + Fvector ic;ic.set(m_mass_center); + ic.invert(); + m.transform_dir(ic); + m.c.add(ic); +} + + +IC void CPHElement::CalculateBoneTransform( Fmatrix &bone_transform )const +{ + Fmatrix parent; + parent.invert ( m_shell->mXFORM ); + bone_transform.mul_43( parent, mXFORM ); +} + +IC void CPHElement::ActivatingPos(const Fmatrix &BoneTransform) +{ + ToBonePos( BoneTransform, mh_unspecified ); + m_flags.set( flActivating, FALSE ); + if( !m_parent_element ) + m_shell->SetObjVsShellTransform(BoneTransform); + + //{ + // m_shell->m_object_in_root.set( B->mTransform ); + // m_shell->m_object_in_root.invert( ); + // m_shell->SetNotActivating( ); + //} + //VERIFY2(fsimilar(DET(B->mTransform),1.f,DET_CHECK_EPS),"Bones callback returns 0 matrix"); + + VERIFY_RMATRIX( BoneTransform ); + VERIFY( valid_pos( BoneTransform.c, phBoundaries ) ); + return; +} \ No newline at end of file diff --git a/xrPhysics/PHElementNetState.cpp b/xrPhysics/PHElementNetState.cpp new file mode 100644 index 00000000000..50af65dcade --- /dev/null +++ b/xrPhysics/PHElementNetState.cpp @@ -0,0 +1,69 @@ +#include "StdAfx.h" +#include "physicsshell.h" +#include "phinterpolation.h" +#include "phelement.h" +#include "phobject.h" +#include "phworld.h" +#include "phshell.h" + +void CPHElement::get_State(SPHNetState& state) +{ + GetGlobalPositionDynamic(&state.position); + getQuaternion(state.quaternion); + m_body_interpolation.GetPosition(state.previous_position,0); + m_body_interpolation.GetRotation(state.previous_quaternion,0); + get_LinearVel(state.linear_vel); + get_AngularVel(state.angular_vel); + getForce(state.force); + getTorque(state.torque); + if(!isActive()) + { + state.enabled=false; + return; + } + state.enabled=!!dBodyIsEnabled(m_body); +} +void CPHElement::set_State(const SPHNetState& state) +{ + //bUpdate=true; + m_flags.set(flUpdate,TRUE); + SetGlobalPositionDynamic(state.position); + setQuaternion(state.quaternion); + m_body_interpolation.SetPosition(state.previous_position,0); + m_body_interpolation.SetRotation(state.previous_quaternion,0); + m_body_interpolation.SetPosition(state.position,1); + m_body_interpolation.SetRotation(state.quaternion,1); + set_LinearVel(state.linear_vel); + set_AngularVel(state.angular_vel); + setForce(state.force); + setTorque(state.torque); + if(!isActive()) return; +#if 1 + if(state.enabled&& !dBodyIsEnabled(m_body)) + { + dBodyEnable(m_body); + m_shell->EnableObject(0); + } + if(!state.enabled && dBodyIsEnabled(m_body)) + { + m_shell->DisableObject(); + Disable(); + } +#endif + CPHDisablingFull::Reinit(); + m_flags.set(flUpdate,TRUE); +} + +void CPHElement ::net_Export(NET_Packet& P) +{ + SPHNetState state; + get_State(state); + state.net_Export(P); +} + +void CPHElement::net_Import(NET_Packet& P) +{ + SPHNetState state; + state.net_Import(P); + set_State(state); +} \ No newline at end of file diff --git a/xrPhysics/PHFracture.cpp b/xrPhysics/PHFracture.cpp new file mode 100644 index 00000000000..935ba24f9e1 --- /dev/null +++ b/xrPhysics/PHFracture.cpp @@ -0,0 +1,602 @@ +#include "stdafx.h" +#include "PHFracture.h" +#include "Physics.h" +#include "PHElement.h" +#include "PHShell.h" +#include "console_vars.h" + +#include "../Include/xrRender/Kinematics.h" +#include "ph_valid_ode.h" +#include "../xrEngine/bone.h" + +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/ode/src/joint.h" +#pragma warning(default:4995) +#pragma warning(default:4267) +extern class CPHWorld *ph_world; +static const float torque_factor=10000000.f; +CPHFracturesHolder::CPHFracturesHolder() +{ + m_has_breaks=false; +} +CPHFracturesHolder::~CPHFracturesHolder() +{ + m_has_breaks=false; + m_fractures.clear(); + m_impacts.clear(); + m_feedbacks.clear(); +} +void CPHFracturesHolder::ApplyImpactsToElement(CPHElement* E) +{ + PH_IMPACT_I i=m_impacts.begin(),e=m_impacts.end(); + BOOL ac_state=E->isActive(); + //E->bActive=true; + E->m_flags.set(CPHElement::flActive,TRUE); + for(;e!=i;++i) + { + E->applyImpact(*i); + } + //E->bActive=ac_state; + E->m_flags.set(CPHElement::flActive,ac_state); +} +element_fracture CPHFracturesHolder::SplitFromEnd(CPHElement* element,u16 fracture) +{ + FRACTURE_I fract_i =m_fractures.begin()+fracture; + u16 geom_num =fract_i->m_start_geom_num; + u16 end_geom_num =fract_i->m_end_geom_num; + SubFractureMass (fracture); + + CPHElement* new_element =cast_PHElement(P_create_Element()); + new_element->m_SelfID=fract_i->m_bone_id; + new_element->mXFORM.set(element->mXFORM); + element->PassEndGeoms(geom_num,end_geom_num,new_element); + ///////////////////////////////////////////// + IKinematics* pKinematics= element->m_shell->PKinematics(); + const CBoneInstance& new_bi=pKinematics->LL_GetBoneInstance(new_element->m_SelfID); + const CBoneInstance& old_bi=pKinematics->LL_GetBoneInstance(element->m_SelfID); + + + + Fmatrix shift_pivot; + shift_pivot.set (new_bi.mTransform); + shift_pivot.invert (); + shift_pivot.mulB_43 (old_bi.mTransform); + ///////////////////////////////////////////// + float density=element->getDensity(); + new_element->SetShell(element->PHShell()); + Fmatrix current_transtform; + element->GetGlobalTransformDynamic(¤t_transtform); + InitNewElement(new_element,shift_pivot,density); + Fmatrix shell_form; + element->PHShell()->GetGlobalTransformDynamic(&shell_form); + current_transtform.mulA_43 (shell_form); + new_element->SetTransform (current_transtform, mh_unspecified ); + + + //dBodyID new_element_body=new_element->get_body(); + //dBodyAddForce(new_element_body,fract_i->m_pos_in_element[0], + // fract_i->m_pos_in_element[1], + // fract_i->m_pos_in_element[2]); + ApplyImpactsToElement(new_element); + + //dBodyAddTorque(new_element->get_body(),fract_i->m_break_force, + // fract_i->m_break_torque, + // fract_i->m_add_torque_z); + //BodyCutForce(new_element_body,default_l_limit,default_w_limit); + element_fracture ret =mk_pair(new_element,(CShellSplitInfo)(*fract_i)); + + if(m_fractures.size()-fracture>0) + { + if(new_element->m_fratures_holder==NULL)//create fractures holder if it was not created before + { + new_element->m_fratures_holder=xr_new(); + } + PassEndFractures(fracture,new_element); + } + + return ret; +} + +void CPHFracturesHolder::PassEndFractures(u16 from,CPHElement* dest) +{ + FRACTURE_I i=m_fractures.begin(),i_from=m_fractures.begin()+from,e=m_fractures.end(); + u16 end_geom=i_from->m_end_geom_num; + u16 begin_geom_num=i_from->m_start_geom_num; + u16 leaved_geoms=begin_geom_num; + u16 passed_geoms=end_geom-begin_geom_num; + if(i_from==e) return; + + for(;i!=i_from;++i)//correct end geoms for fractures leaved in source + { + u16& cur_end_geom=i->m_end_geom_num; + if(cur_end_geom>begin_geom_num) cur_end_geom=cur_end_geom-passed_geoms; + } + + i++; // omit used fracture; + //these to be passed + for(;i!=e;i++)//itterate antil a fracture where geom num > end geom num + { + u16 &cur_end_geom =i->m_end_geom_num; + u16 &cur_geom =i->m_start_geom_num; + if(cur_geom>=end_geom) break; + cur_end_geom=cur_end_geom-leaved_geoms; + cur_geom=cur_geom-leaved_geoms; + } + FRACTURE_I i_to=i; + for(;i!=e;++i)//correct data in the rest leaved fractures + { + u16 &cur_end_geom =i->m_end_geom_num; + u16 &cur_geom =i->m_start_geom_num; + cur_end_geom =cur_end_geom-passed_geoms; + cur_geom =cur_geom-passed_geoms; + } + + if(i_from + 1 != i_to)//insure it!! + { + + CPHFracturesHolder* &dest_fract_holder=dest->m_fratures_holder; + if(!dest_fract_holder) dest_fract_holder=xr_new(); + //pass fractures not including end fracture + dest_fract_holder->m_fractures.insert(dest_fract_holder->m_fractures.end(),i_from+1,i_to); + + //u16 deb=u16(i_to-i_from-1); + //deb++;deb--; + } + m_fractures.erase(i_from,i_to);//erase along whith used fracture +} +void CPHFracturesHolder::SplitProcess(CPHElement* element,ELEMENT_PAIR_VECTOR &new_elements) +{ + //FRACTURE_RI i=m_fractures.rbegin(),e=m_fractures.rend();//reversed + u16 i=u16(m_fractures.size()-1); + + for(;i!=u16(-1);i--) + { + if(m_fractures[i].Breaked()) + { + //float density = element->getDensity(); + new_elements.push_back(SplitFromEnd(element,i)); + //element->ResetMass(density); + } + } + + +} + +void CPHFracturesHolder::InitNewElement(CPHElement* element,const Fmatrix &shift_pivot,float density) +{ +element->CreateSimulBase(); +element->ReInitDynamics(shift_pivot,density); +VERIFY(dBodyStateValide(element->get_body())); +} + +void CPHFracturesHolder::PhTune(dBodyID body) +{ + //iterate through all body's joints and set joints feedbacks where is not already set + //contact feedbacks stored in global storage - ContactFeedBacks wich cleared on each step + //breacable joints already has their feedbacks, + //feedbacks for rest noncontact joints stored in m_feedbacks in runtime in this function and + //and killed by destructor + + //int dBodyGetNumJoints (dBodyID b); + //dJointID dBodyGetJoint (dBodyID, int index); + //dJointGetType + //dJointTypeContact + + int num=dBodyGetNumJoints(body); + for(int i=0;iJointDestroyInfo())) dJointSetFeedback(joint,ContactFeedBacks.add()); + //if(!dJointGetFeedback(joint)) + //{ + // m_feedbacks.push_back(dJointFeedback()); + // dJointSetFeedback(joint,&m_feedbacks.back()); + //} + } + } + +} +bool CPHFracturesHolder::PhDataUpdate(CPHElement* element) +{ + FRACTURE_I i=m_fractures.begin(),e=m_fractures.end(); + for(;i!=e;++i) + { + m_has_breaks=i->Update(element)||m_has_breaks; + } + if(!m_has_breaks)m_impacts.clear(); + return m_has_breaks; + +} + +void CPHFracturesHolder::AddImpact(const Fvector& force,const Fvector& point,u16 id) +{ + m_impacts.push_back(SPHImpact(force,point,id)); +} +u16 CPHFracturesHolder::AddFracture(const CPHFracture& fracture) +{ + m_fractures.push_back(fracture); + return u16(m_fractures.size()-1); +} +CPHFracture& CPHFracturesHolder::Fracture(u16 num) +{ + R_ASSERT2(numm_start_geom_num,"fracture does not initialized!"); + + if(f_i->m_end_geom_num==u16(-1))f_i->MassAddToSecond(m) ; + else f_i->MassAddToFirst(m) ; + + + + //f_i->MassAddToFirst(m); + } +} +void CPHFracturesHolder::SubFractureMass(u16 fracture_num) +{ + FRACTURE_I f_i=m_fractures.begin(),f_e=m_fractures.end(); + FRACTURE_I fracture=f_i+fracture_num; + u16 start_geom=fracture->m_start_geom_num; + u16 end_geom =fracture->m_end_geom_num; + dMass& second_mass=fracture->m_secondM; + dMass& first_mass=fracture->m_firstM; + for(;f_i!=f_e;++f_i) + { + if(f_i==fracture) continue; + R_ASSERT2(start_geom!=f_i->m_start_geom_num,"Double fracture!!!"); + + + if(start_geom>f_i->m_start_geom_num) + { + + if(end_geom<=f_i->m_end_geom_num) f_i->MassSubFromSecond(second_mass);//tag fracture is in current + else + { + R_ASSERT2(start_geom>=f_i->m_end_geom_num,"Odd fracture!!!"); + f_i->MassSubFromFirst(second_mass);//tag fracture is ouside current + } + } + else + { + + if(end_geom>=f_i->m_end_geom_num) f_i->MassSubFromFirst(first_mass);//current fracture is in tag + else + { + R_ASSERT2(end_geom<=f_i->m_start_geom_num,"Odd fracture!!!"); + f_i->MassSubFromFirst(second_mass);//tag fracture is ouside current + } + } + } +} + +CPHFracture::CPHFracture() +{ +//m_bone_id=bone_id; +//m_position.set(position); +//m_direction.set(direction); +//m_break_force=break_force; +//m_break_torque=break_torque; +m_start_geom_num=u16(-1); +m_end_geom_num =u16(-1); +m_breaked=false; +} + +//#define DBG_BREAK +bool CPHFracture::Update(CPHElement* element) +{ + + ////itterate through impacts & calculate + dBodyID body=element->get_body(); + //const Fvector& v_bodyvel=*((Fvector*)dBodyGetLinearVel(body)); + CPHFracturesHolder* holder=element->FracturesHolder(); + PH_IMPACT_STORAGE& impacts=holder->Impacts(); + + Fvector second_part_force,first_part_force,second_part_torque,first_part_torque; + second_part_force.set(0.f,0.f,0.f); + first_part_force.set(0.f,0.f,0.f); + second_part_torque.set(0.f,0.f,0.f); + first_part_torque.set(0.f,0.f,0.f); + + //const Fvector& body_local_pos=element->local_mass_Center(); + const Fvector& body_global_pos=*(const Fvector*)dBodyGetPosition(body); + Fvector body_to_first, body_to_second; + body_to_first.set(*((const Fvector*)m_firstM.c));//,body_local_pos + body_to_second.set(*((const Fvector*)m_secondM.c));//,body_local_pos + //float body_to_first_smag=body_to_first.square_magnitude(); + //float body_to_second_smag=body_to_second.square_magnitude(); + int num=dBodyGetNumJoints(body); + for(int i=0;inode[1].body==body); + Fvector joint_position; + if(dJointGetType(joint)==dJointTypeContact) + { + dxJointContact* c_joint=(dxJointContact*)joint; + dGeomID first_geom=c_joint->contact.geom.g1; + dGeomID second_geom=c_joint->contact.geom.g2; + joint_position.set(*(Fvector*)c_joint->contact.geom.pos); + if(dGeomGetClass(first_geom)==dGeomTransformClass) + { + first_geom=dGeomTransformGetGeom(first_geom); + } + if(dGeomGetClass(second_geom)==dGeomTransformClass) + { + second_geom=dGeomTransformGetGeom(second_geom); + } + dxGeomUserData* UserData; + UserData=dGeomGetUserData(first_geom); + if(UserData) + { + u16 el_position=UserData->element_position; + //define if the contact applied to second part; + if(el_positionnumberOfGeoms()&& + el_position>=m_start_geom_num&& + el_positionGeom(el_position)->geometry() + ) applied_to_second=true; + } + UserData=dGeomGetUserData(second_geom); + if(UserData) + { + u16 el_position=UserData->element_position; + if(el_positionnumberOfGeoms()&& + el_position>=m_start_geom_num&& + el_positionGeom(el_position)->geometry() + ) applied_to_second=true; + } + + } + else + { + CPHJoint* J = (CPHJoint*) dJointGetData(joint); + if(!J)continue;//hack.. + J->PSecondElement()->InterpolateGlobalPosition(&joint_position); + CODEGeom* root_geom=J->RootGeom(); + if(root_geom) + { + u16 el_position=root_geom->element_position(); + if(element==J->PFirst_element()&& + el_positionnumberOfGeoms()&& + el_position>=m_start_geom_num&& + el_positionf2); + second_part_force.add(joint_force); + Fvector torque; + torque.crossproduct(shoulder,joint_force); + second_part_torque.add(torque); + + } + else + { + + Fvector joint_force; + joint_force.set(*(const Fvector*)feedback->f1); + second_part_force.add(joint_force); + + Fvector torque; + torque.crossproduct(shoulder,joint_force); + second_part_torque.add(torque); + } + } + else + { + Fvector shoulder; + shoulder.sub(body_to_joint,body_to_first); + if(b_body_second) + { + + Fvector joint_force; + joint_force.set(*(const Fvector*)feedback->f2); + first_part_force.add(joint_force); + Fvector torque; + torque.crossproduct(shoulder,joint_force); + first_part_torque.add(torque); + } + else + { + Fvector joint_force; + joint_force.set(*(const Fvector*)feedback->f1); + first_part_force.add(joint_force); + Fvector torque; + torque.crossproduct(shoulder,joint_force); + first_part_torque.add(torque); + } + } + + } + + PH_IMPACT_I i_i=impacts.begin(),i_e=impacts.end(); + for(;i_i!=i_e;i_i++) + { + u16 geom = i_i->geom; + + if((geom>=m_start_geom_num&&geomforce); + force.mul(ph_console::phRigidBreakWeaponFactor); + Fvector second_to_point; + second_to_point.sub(body_to_second,i_i->point); + //force.mul(30.f); + second_part_force.add(force); + Fvector torque; + torque.crossproduct(second_to_point,force); + second_part_torque.add(torque); + } + else + { + Fvector force; + force.set(i_i->force); + Fvector first_to_point; + first_to_point.sub(body_to_first,i_i->point); + //force.mul(4.f); + first_part_force.add(force); + Fvector torque; + torque.crossproduct(first_to_point,force); + second_part_torque.add(torque); + } + } + Fvector gravity_force; + gravity_force.set(0.f,-ph_world->Gravity()*m_firstM.mass,0.f); + first_part_force.add(gravity_force); + second_part_force.add(gravity_force); + dMatrix3 glI1,glI2,glInvI,tmp; + + // compute inertia tensors in global frame + dMULTIPLY2_333 (tmp,body->invI,body->R); + dMULTIPLY0_333 (glInvI,body->R,tmp); + + dMULTIPLY2_333 (tmp,m_firstM.I,body->R); + dMULTIPLY0_333 (glI1,body->R,tmp); + + dMULTIPLY2_333 (tmp,m_secondM.I,body->R); + dMULTIPLY0_333 (glI2,body->R,tmp); + //both parts have eqiual start angular vel same as have body so we ignore it + + //compute breaking torque + ///break_torque=glI2*glInvI*first_part_torque-glI1*glInvI*second_part_torque+crossproduct(second_in_bone,second_part_force)-crossproduct(first_in_bone,first_part_force) + Fvector break_torque,vtemp; + + dMULTIPLY0_331 ((float*)&break_torque,glInvI,(float*)&first_part_torque); + dMULTIPLY0_331 ((float*)&break_torque,glI2,(float*)&break_torque); + + dMULTIPLY0_331 ((float*)&vtemp,glInvI,(float*)&second_part_torque); + dMULTIPLY0_331 ((float*)&vtemp,glI1,(float*)&vtemp); + break_torque.sub(vtemp); + + //Fvector first_in_bone,second_in_bone; + //first_in_bone.sub(*((const Fvector*)m_firstM.c),m_pos_in_element); + //second_in_bone.sub(*((const Fvector*)m_secondM.c),m_pos_in_element); + + //vtemp.crossproduct(second_in_bone,second_part_force); + //break_torque.add(vtemp); + //vtemp.crossproduct(first_in_bone,first_part_force); + //break_torque.sub(vtemp); +#ifdef DBG_BREAK + float btm_dbg=break_torque.magnitude()*ph_console::phBreakCommonFactor/torque_factor; +#endif + if(break_torque.magnitude()*ph_console::phBreakCommonFactor>m_break_torque*torque_factor) + { + //m_break_torque.set(second_part_torque); + m_pos_in_element.set(second_part_force); + m_break_force=second_part_torque.x; + m_break_torque=second_part_torque.y; + m_add_torque_z=second_part_torque.z; + m_breaked=true; +#ifndef DBG_BREAK + return m_breaked; +#endif + } + + Fvector break_force;//=1/(m1+m2)*(F1*m2-F2*m1)+r2xT2/(r2^2)-r1xT1/(r1^2) + break_force.set(first_part_force); + break_force.mul(m_secondM.mass); + vtemp.set(second_part_force); + vtemp.mul(m_firstM.mass); + break_force.sub(vtemp); + break_force.mul(1.f/element->getMass());//element->getMass()//body->mass.mass + + //vtemp.crossproduct(second_in_bone,second_part_torque); + //break_force.add(vtemp); + //vtemp.crossproduct(first_in_bone,first_part_torque); + //break_force.sub(vtemp); + + float bfm=break_force.magnitude()*ph_console::phBreakCommonFactor; + + if(m_break_force element_fracture; +typedef xr_vector::reverse_iterator ELEMENT_PAIR_RI; +typedef xr_vector::reverse_iterator FRACTURE_RI; +DEFINE_VECTOR(element_fracture,ELEMENT_PAIR_VECTOR,ELEMENT_PAIR_I) + +class CPHFracturesHolder //stored in CPHElement +{ +friend class CPHElement; +friend class CPHShellSplitterHolder; +bool m_has_breaks; + +FRACTURE_STORAGE m_fractures; +PH_IMPACT_STORAGE m_impacts; //filled in anytime from CPHElement applyImpulseTrace cleared in PhDataUpdate +CFEEDBACK_STORAGE m_feedbacks; //this store feedbacks for non contact joints +public: +CPHFracturesHolder (); + +~CPHFracturesHolder (); +void DistributeAdditionalMass (u16 geom_num,const dMass& m);// +void SubFractureMass (u16 fracture_num); +void AddImpact (const Fvector& force,const Fvector& point,u16 id); +PH_IMPACT_STORAGE& Impacts (){return m_impacts;} + +CPHFracture& LastFracture (){return m_fractures.back();} +protected: +private: + +u16 CheckFractured (); //returns first breaked fracture + +element_fracture SplitFromEnd (CPHElement* element,u16 geom_num); +void InitNewElement (CPHElement* element,const Fmatrix &shift_pivot,float density); +void PassEndFractures(u16 from,CPHElement* dest); +public: +void SplitProcess (CPHElement* element,ELEMENT_PAIR_VECTOR &new_elements); +u16 AddFracture (const CPHFracture& fracture); +CPHFracture& Fracture (u16 num); +void PhTune (dBodyID body); //set feedback for joints called from PhTune of ShellSplitterHolder +bool PhDataUpdate (CPHElement* element); //collect joints and external impacts in fractures Update which set m_fractured; called from PhDataUpdate of ShellSplitterHolder returns true if has breaks +void ApplyImpactsToElement(CPHElement* element); +}; + +IC void sub_diapasones(u16 &from1,u16 &to1,const u16 &from0,const u16 &to0) +{ + if(from0==to0 ||from1==to1|| to1<=from0||to1==u16(-1)) return; + R_ASSERT(from0>=from1&&to0<=to1); + u16 dip=to0-from0; + to1=to1-dip; +} + +#endif PH_FRACTURE_H \ No newline at end of file diff --git a/xrPhysics/PHGeometryOwner.cpp b/xrPhysics/PHGeometryOwner.cpp new file mode 100644 index 00000000000..7a80060c6f7 --- /dev/null +++ b/xrPhysics/PHGeometryOwner.cpp @@ -0,0 +1,484 @@ +#include "stdafx.h" +#include "PHGeometryOwner.h" +#include "phworld.h" + +#include "../Include/xrRender/Kinematics.h" +#include "../xrEngine/bone.h" + +CPHGeometryOwner::CPHGeometryOwner() +{ + b_builded=false; + m_mass_center.set(0,0,0); + VERIFY( ph_world ); + //contact_callback=ContactShotMark;//ph_world->default_contact_shotmark(); + contact_callback=ph_world->default_contact_shotmark(); + object_contact_callback=NULL; + ul_material=GMLibrary().GetMaterialIdx("objects\\small_box"); + m_group=NULL; + m_phys_ref_object=NULL; +} + +CPHGeometryOwner::~CPHGeometryOwner() +{ + GEOM_I i_geom=m_geoms.begin(),e=m_geoms.end(); + for(;i_geom!=e;++i_geom)xr_delete(*i_geom); + m_geoms.clear(); + DestroyGroupSpace(); + //if( b_builded ) + //{ + //VERIFY( m_group ); + //if( m_group ) + // dSpaceDestroy( m_group ); + + //} +} +void CPHGeometryOwner::group_add( CODEGeom& g ) +{ + if(!m_group) + { + CreateGroupSpace(); + } + VERIFY( m_group ); + { + g.add_to_space((dSpaceID)m_group); + } +} + +void CPHGeometryOwner::group_remove( CODEGeom& g ) +{ + VERIFY( m_group ); + g.remove_from_space( m_group ); + if( dSpaceGetNumGeoms( m_group ) ==0 ) + DestroyGroupSpace(); +} + +void CPHGeometryOwner:: build_Geom (CODEGeom& geom) +{ + + geom.build(m_mass_center); + //geom.set_body(m_body); + geom.set_material(ul_material); + if(contact_callback)geom.set_contact_cb(contact_callback); + if(object_contact_callback)geom.set_obj_contact_cb(object_contact_callback); + if(m_phys_ref_object) geom.set_ref_object(m_phys_ref_object); + //VERIFY( m_group ); + group_add( geom ); + +} + +void CPHGeometryOwner::build_Geom(u16 i) +{ + CODEGeom& geom=*m_geoms[i]; + build_Geom(geom); + geom.element_position()=i; +} + +void CPHGeometryOwner::build() +{ + if(b_builded) return; + //if(m_geoms.size()>1)//add/remove geom issues + //VERIFY(!m_group); + + u16 geoms_size=u16(m_geoms.size()); + for(u16 i=0;idestroy(); + } + b_builded=false; +} +void CPHGeometryOwner::set_body(dBodyID body) +{ + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_body(body); +} + +Fvector CPHGeometryOwner:: get_mc_data (){ + Fvector s; + float pv; + m_mass_center.set(0,0,0); + m_volume=0.f; + GEOM_I i_geom=m_geoms.begin(),e=m_geoms.end(); + for(;i_geom!=e;++i_geom) + { + pv=(*i_geom)->volume(); + s.mul((*i_geom)->local_center(),pv); + m_volume+=pv; + m_mass_center.add(s); + } + m_mass_center.mul(1.f/m_volume); + return m_mass_center; +} + +Fvector CPHGeometryOwner:: get_mc_geoms (){ + ////////////////////to be implemented + Fvector mc; + mc.set(0.f,0.f,0.f); + return mc; +} +void CPHGeometryOwner::get_mc_kinematics(IKinematics* K,Fvector& mc,float& mass) +{ + + mc.set(0.f,0.f,0.f); + mass=0.f; + m_volume=0.f; + GEOM_I i_geom=m_geoms.begin(),e=m_geoms.end(); + for(;i_geom!=e;++i_geom) + { + const IBoneData& data=K->GetBoneData((*i_geom)->bone_id()); + Fvector add; + mass+=data.get_mass(); + m_volume+=(*i_geom)->volume(); + add.set(data.get_center_of_mass()); + add.mul(data.get_mass()); + mc.add(add); + } + mc.mul(1.f/mass); +} +void CPHGeometryOwner:: calc_volume_data () +{ + m_volume=0.f; + GEOM_I i_geom=m_geoms.begin(),e=m_geoms.end(); + for(;i_geom!=e;++i_geom) + { + m_volume+=(*i_geom)->volume(); + } +} + +void CPHGeometryOwner::SetMaterial(u16 m) +{ + ul_material=m; + if(!b_builded) return; + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_material(m); +} + +void CPHGeometryOwner::SetPhObjectInGeomData(CPHObject* O) +{ + if(!b_builded) return; + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_ph_object(O); +} + +dGeomID CPHGeometryOwner::dSpacedGeometry() +{ + if(!b_builded) return 0; + VERIFY( m_group ); + //if(m_group) + return (dGeomID) group_space();//(dGeomID)m_group; + //else return (*m_geoms.begin())->geometry_transform(); +} + +void CPHGeometryOwner:: add_Box (const Fobb& V) +{ + Fobb box; + box=V; + if(box.m_halfsize.x<0.005f) box.m_halfsize.x=0.005f; + if(box.m_halfsize.y<0.005f) box.m_halfsize.y=0.005f; + if(box.m_halfsize.z<0.005f) box.m_halfsize.z=0.005f; + m_geoms.push_back(smart_cast(xr_new(box))); + +} + +void CPHGeometryOwner:: add_Sphere (const Fsphere& V) +{ + m_geoms.push_back(smart_cast(xr_new(V))); +} + +void CPHGeometryOwner::add_Cylinder (const Fcylinder& V) +{ + m_geoms.push_back(smart_cast(xr_new(V))); +} + + +void CPHGeometryOwner::add_Shape(const SBoneShape& shape,const Fmatrix& offset) +{ + switch(shape.type) { + case SBoneShape::stBox : + { + Fobb box=shape.box; + Fmatrix m; + m.set(offset); + //Fmatrix position; + //position.set(box.m_rotate); + //position.c.set(box.m_translate); + //position.mulA(offset); + //box.m_rotate.set(position); + //box.m_translate.set(position.c); + box.transform(box,m); + add_Box(box); + break; + } + case SBoneShape::stSphere : + { + Fsphere sphere=shape.sphere; + offset.transform_tiny(sphere.P); + add_Sphere(sphere); + break; + } + + + case SBoneShape::stCylinder : + { + Fcylinder C=shape.cylinder; + offset.transform_tiny(C.m_center); + offset.transform_dir(C.m_direction); + add_Cylinder(C); + break; + } + + + case SBoneShape::stNone : + break; + default: NODEFAULT; + } +} + +void CPHGeometryOwner::add_Shape(const SBoneShape& shape) +{ + switch(shape.type) { + case SBoneShape::stBox : + { + add_Box(shape.box); + break; + } + case SBoneShape::stSphere : + { + add_Sphere(shape.sphere); + break; + } + + + case SBoneShape::stCylinder : + { + add_Cylinder(shape.cylinder); + break; + } + + case SBoneShape::stNone : + break; + default: NODEFAULT; + } +} + + +void CPHGeometryOwner::set_ContactCallback(ContactCallbackFun* callback) +{ + contact_callback=callback; + if(!b_builded)return; + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_contact_cb(callback); +} + + +void CPHGeometryOwner::set_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + object_contact_callback= callback; + if(!b_builded)return; + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_obj_contact_cb(callback); +} + +void CPHGeometryOwner::add_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + + if(!object_contact_callback) + { + object_contact_callback= callback; + } + if(!b_builded)return; + { + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->add_obj_contact_cb(callback); + } +} + +void CPHGeometryOwner::remove_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + + if(object_contact_callback==callback) + { + object_contact_callback= NULL; + } + if(!b_builded)return; + { + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->remove_obj_contact_cb(callback); + } +} + +ObjectContactCallbackFun* CPHGeometryOwner::get_ObjectContactCallback() +{ + return object_contact_callback; +} +void CPHGeometryOwner::set_CallbackData(void * cd) +{ + VERIFY(b_builded); + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_callback_data(cd); +} +void* CPHGeometryOwner::get_CallbackData() +{ + VERIFY(b_builded); + return (*m_geoms.begin())->get_callback_data (); +} +void CPHGeometryOwner::set_PhysicsRefObject(IPhysicsShellHolder* ref_object) +{ + m_phys_ref_object=ref_object; + if(!b_builded) return; + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_ref_object(ref_object); +} + +u16 CPHGeometryOwner::numberOfGeoms() const +{ + return (u16)m_geoms.size(); +} + +void CPHGeometryOwner::get_Extensions(const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext) const +{ + t_get_extensions( m_geoms,axis, center_prg, lo_ext, hi_ext ); + /* + lo_ext=dInfinity;hi_ext=-dInfinity; + GEOM_CI i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + float temp_lo_ext,temp_hi_ext; + (*i)->get_Extensions(axis,center_prg,temp_lo_ext,temp_hi_ext); + if(lo_ext>temp_lo_ext)lo_ext=temp_lo_ext; + if(hi_extget_max_area_dir_bt(dir); +} +float CPHGeometryOwner::getRadius() +{ + if(!m_geoms.empty()) return m_geoms.back()->radius(); + else return 0.f; +} + +void CPHGeometryOwner::get_mc_vs_transform(Fvector& mc,const Fmatrix& m) +{ + mc.set(m_mass_center); + m.transform_tiny(mc); + VERIFY2(_valid(mc),"invalid mc in_set_transform"); +} + +void CPHGeometryOwner::setStaticForm(const Fmatrix& form) +{ + if(!b_builded) return; + Fmatrix f; + f.set(form); + get_mc_vs_transform(f.c,form); + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) (*i)->set_static_ref_form(f); +} + +void CPHGeometryOwner::setPosition(const Fvector& pos) +{ + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + (*i)->set_build_position(pos); + } +} +void CPHGeometryOwner::CreateGroupSpace() +{ + VERIFY(!m_group); + m_group=dSimpleSpaceCreate(0); + dSpaceSetCleanup(m_group,0); + +} +void CPHGeometryOwner:: DestroyGroupSpace() +{ + if(m_group){ + dGeomDestroy((dGeomID)m_group); + m_group=NULL; + } +} +struct SFindPred +{ + u16 m_val; + SFindPred(u16 val) + { + m_val=val; + } +bool operator () (CODEGeom* g) + { + return g->bone_id()==m_val; + } +}; +CODEGeom* CPHGeometryOwner::GeomByBoneID(u16 bone_id) +{ + + GEOM_I g=std::find_if(m_geoms.begin(),m_geoms.end(),SFindPred(bone_id)); + if(g!=m_geoms.end()) + { + return *g; + } + else + { + return NULL; + } +} + +void CPHGeometryOwner::clear_cashed_tries() +{ + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + (*i)->clear_cashed_tries(); + } +} + +void CPHGeometryOwner::clear_motion_history( bool set_unspecified ) +{ + GEOM_I i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + (*i)->clear_motion_history( set_unspecified ); + } +} + +void CPHGeometryOwner::add_geom( CODEGeom* g ) +{ + VERIFY( b_builded ); + VERIFY( m_group ); + m_geoms.push_back( g ); + group_add( *g ); + //g->add_to_space( m_group ); +} + +void CPHGeometryOwner::remove_geom( CODEGeom* g ) +{ + VERIFY( b_builded ); + VERIFY( m_group ); + GEOM_I gi = std::find( m_geoms.begin(), m_geoms.end(), g ); + VERIFY( gi != m_geoms.end()); + //(*gi)->remove_from_space( m_group ); + group_remove( *g ); + m_geoms.erase( gi ); +} + +#ifdef DEBUG +void CPHGeometryOwner::dbg_draw( float scale, u32 color, Flags32 flags )const +{ + VERIFY( b_builded ); + GEOM_CI i=m_geoms.begin(),e=m_geoms.end(); + for(;i!=e;++i) + { + (*i)->dbg_draw( scale, color, flags ); + } +} +#endif \ No newline at end of file diff --git a/xrPhysics/PHGeometryOwner.h b/xrPhysics/PHGeometryOwner.h new file mode 100644 index 00000000000..8b7e3a704e2 --- /dev/null +++ b/xrPhysics/PHGeometryOwner.h @@ -0,0 +1,107 @@ +#ifndef PH_GEOMETRY_OWNER_H +#define PH_GEOMETRY_OWNER_H +#include "Geometry.h" +#include "../xrEngine/gamemtllib.h" + +DEFINE_VECTOR(CODEGeom*,GEOM_STORAGE,GEOM_I) +typedef xr_vector::const_iterator GEOM_CI; +struct SBoneShape; +class IKinematics; + +class CPHGeometryOwner +{ +protected: + GEOM_STORAGE m_geoms; //e + //bl + bool b_builded; +private: + dSpaceID m_group; //e //bl +protected: + Fvector m_mass_center; //e ?? //bl + IPhysicsShellHolder* m_phys_ref_object; //->to shell ?? //bl + float m_volume; //e ?? //bl + u16 ul_material; //e ?? //bl + ContactCallbackFun* contact_callback; //->to shell ?? //bt + ObjectContactCallbackFun* object_contact_callback;//->to shell ?? //st +public: + /// + void add_Sphere (const Fsphere& V); //aux + void add_Box (const Fobb& V); //aux + void add_Cylinder (const Fcylinder& V); //aux + void add_Shape (const SBoneShape& shape); //aux + void add_Shape (const SBoneShape& shape,const Fmatrix& offset); //aux + CODEGeom* last_geom (){if(m_geoms.empty())return NULL; return m_geoms.back();} //aux + bool has_geoms (){return !m_geoms.empty();} + void add_geom ( CODEGeom* g ); + void remove_geom ( CODEGeom* g ); +protected: + void group_add ( CODEGeom& g ); + void group_remove ( CODEGeom& g ); +public: + + void set_ContactCallback (ContactCallbackFun* callback); //aux (may not be) + void set_ObjectContactCallback (ObjectContactCallbackFun* callback); //called anywhere ph state influent + void add_ObjectContactCallback (ObjectContactCallbackFun* callback); //called anywhere ph state influent + void remove_ObjectContactCallback (ObjectContactCallbackFun* callback); //called anywhere ph state influent + void set_CallbackData (void * cd); + void *get_CallbackData (); + ObjectContactCallbackFun *get_ObjectContactCallback (); + void set_PhysicsRefObject (IPhysicsShellHolder* ref_object); //aux + IPhysicsShellHolder* PhysicsRefObject (){return m_phys_ref_object;} //aux + void SetPhObjectInGeomData (CPHObject* O); +#ifdef DEBUG + void dbg_draw ( float scale, u32 color, Flags32 flags )const; +#endif + void SetMaterial (u16 m) ; + void SetMaterial (LPCSTR m){SetMaterial(GMLibrary().GetMaterialIdx(m));} //aux + IC CODEGeom* Geom (u16 num) {R_ASSERT2 (num +void t_get_extensions( const xr_vector& geoms, const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext) +{ + lo_ext=dInfinity;hi_ext=-dInfinity; + xr_vector::const_iterator i=geoms.begin(),e=geoms.end(); + for(;i!=e;++i) + { + float temp_lo_ext,temp_hi_ext; + (*i)->get_Extensions(axis,center_prg,temp_lo_ext,temp_hi_ext); + if(lo_ext>temp_lo_ext)lo_ext=temp_lo_ext; + if(hi_extm_frame_time/fixed_step); + //else + //pos.lerp(*bkp_pos,bk_pos,ph_world->FrameTime(b_frame_mark)/fixed_step); +} + + + +void CPHInterpolation::InterpolateRotation(Fmatrix& rot){ + Fquaternion q; + float t = ph_world->m_frame_time/fixed_step; + VERIFY (t>=0.f && t<=1.f); + //if(!b_udating_rotations) + q.slerp(qRotations[0],qRotations[1],t); +// else + //q.slerp(*bkp_quat,bk_quat,t); + rot.rotation(q); +} + +void CPHInterpolation::ResetPositions() +{ + VERIFY2(dBodyStateValide(m_body),"Invalid body state"); + qPositions.fill_in(*((Fvector*) dBodyGetPosition(m_body))); +} + +void CPHInterpolation::ResetRotations() +{ + VERIFY2(dBodyStateValide(m_body),"Invalid body state"); + const dReal* dQ=dBodyGetQuaternion(m_body); + Fquaternion fQ; + fQ.set(-dQ[0],dQ[1],dQ[2],dQ[3]); + qRotations.fill_in(fQ); +} + +void CPHInterpolation::GetRotation(Fquaternion& q, u16 num) +{ + if(!m_body) return; + q.set(qRotations[num]); +} + +void CPHInterpolation::GetPosition(Fvector& p,u16 num) +{ + if(!m_body) return; + p.set(qPositions[num]); +} +void CPHInterpolation::SetPosition(const Fvector& p, u16 num) +{ + if(!m_body) return; + qPositions[num].set(p); +} + +void CPHInterpolation::SetRotation(const Fquaternion& q, u16 num) +{ + if(!m_body) return; + qRotations[num]=q; +} \ No newline at end of file diff --git a/xrPhysics/PHInterpolation.h b/xrPhysics/PHInterpolation.h new file mode 100644 index 00000000000..81e8bd8a8c5 --- /dev/null +++ b/xrPhysics/PHInterpolation.h @@ -0,0 +1,29 @@ +#include "CycleConstStorage.h" +#ifndef PHINTERPOLATON_H +#define PHINTERPOLATON_H + +//#include "ode_include.h" +#include "../3rd party/ode/include/ode/common.h" + +class CPHInterpolation { + +public: +CPHInterpolation(); +void SetBody(dBodyID body); +static const u16 PH_INTERPOLATION_POINTS=2; +void InterpolatePosition (Fvector& pos); +void InterpolateRotation (Fmatrix& rot); +void UpdatePositions (); +void UpdateRotations (); +void ResetPositions (); +void ResetRotations (); +void GetRotation (Fquaternion& q, u16 num); +void GetPosition (Fvector& p, u16 num); +void SetRotation (const Fquaternion& q, u16 num); +void SetPosition (const Fvector& p, u16 num); +private: + dBodyID m_body; + CCycleConstStorage qPositions; + CCycleConstStorage qRotations; +}; +#endif \ No newline at end of file diff --git a/xrPhysics/PHIsland.cpp b/xrPhysics/PHIsland.cpp new file mode 100644 index 00000000000..5c39e6c4f10 --- /dev/null +++ b/xrPhysics/PHIsland.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include "PHIsland.h" +#include "physics.h" +#include "ph_valid_ode.h" +void CPHIsland:: Step(dReal step) +{ + if(!m_flags.is_active()) return; + //dWorldStepFast1 (DWorld(), fixed_step, phIterations/*+Random.randI(0,phIterationCycle)*/); + if(m_flags.is_exact_integration_prefeared() && nj < max_joint_allowed_for_exeact_integration) + dWorldStep(DWorld(),fixed_step); + else + dWorldQuickStep (DWorld(), fixed_step); + //dWorldStep(DWorld(),fixed_step); +} + +void CPHIsland::Enable() +{ + if(!m_flags.is_active()) return; + + for (dxBody *body = DWorld()->firstbody; body; body = (dxBody *) body->next)body->flags &= ~dxBodyDisabled; + +} +void CPHIsland::Repair() +{ + if(!m_flags.is_active()) return; + dBodyID body; + for (body = firstbody; body; body = (dxBody *) body->next) + { + if(!dV_valid(dBodyGetAngularVel(body))) + dBodySetAngularVel(body,0.f,0.f,0.f); + if(!dV_valid(dBodyGetLinearVel(body))) + dBodySetLinearVel(body,0.f,0.f,0.f); + if(!dV_valid(dBodyGetPosition(body))) + dBodySetPosition(body,0.f,0.f,0.f); + if(!dQ_valid(dBodyGetQuaternion(body))) + { + dQuaternion q={1.f,0.f,0.f,0.f};//dQSetIdentity(q); + dBodySetQuaternion(body,q); + } + } +} \ No newline at end of file diff --git a/xrPhysics/PHIsland.h b/xrPhysics/PHIsland.h new file mode 100644 index 00000000000..70fe433eb5b --- /dev/null +++ b/xrPhysics/PHIsland.h @@ -0,0 +1,257 @@ +#ifndef PH_ISLAND_H +#define PH_ISLAND_H + +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/ode/src/objects.h" +#include "../3rd party/ode/ode/src/joint.h" +#pragma warning(default:4995) +#pragma warning(default:4267) + +#include "../3rd party/ode/include/ode/objects.h" + +#include "PhysicsCommon.h" + + + +class CPHIslandFlags +{ + static const int base = 8 ; + static const int shift_to_variable = base/2 ; + static const int mask_static = 0xf ; + Flags8 flags ; + + enum + { + stActive = 1<<0, + flPrefereExactIntegration = 1<<1 + }; +public: + + CPHIslandFlags () {init();} + + IC void init () {flags.zero();flags.set(stActive,TRUE);unmerge();} + IC BOOL is_active () {return flags.test(stActive<m_nb; +} +IC bool IsJointGroun() +{ + return nj>m_nj; +} +IC bool CheckSize() +{ + return njnj; +} + +IC int MaxBodies(CPHIsland* island) +{ + return BODIES_LIMIT-nb-island->nb; +} + +IC bool CanMerge(CPHIsland* island,int& MAX_JOINTS) +{ + MAX_JOINTS=MaxJoints(island); + return MAX_JOINTS>0 && ((nb+island->nb)m_flags.is_active()) m_self_active=m_self_active->m_self_active; +} +IC void Merge(CPHIsland* island) +{ + //VERIFY2(b_active&&island->b_active,"no active island"); + CPHIsland* first_island=DActiveIsland(); + CPHIsland* second_island=island->DActiveIsland(); + if(first_island==second_island)return; + + *(second_island->m_joints_tail)=first_island->firstjoint; + first_island->firstjoint=second_island->firstjoint; + if(0==first_island->nj&&0!=second_island->nj) + { + first_island->m_joints_tail=second_island->m_joints_tail; + } + + *(second_island->m_bodies_tail)=first_island->firstbody; + first_island->firstbody=second_island->firstbody; + + first_island->nj+=second_island->nj; + first_island->nb+=second_island->nb; + VERIFY(!(*(first_island->m_bodies_tail))); + VERIFY(!(*(first_island->m_joints_tail))); + VERIFY(!((!(first_island->nj))&&(first_island->firstjoint))); + second_island->m_self_active=first_island; + //second_island->b_active=false; + m_flags.merge(second_island->m_flags); +} +IC void Unmerge() +{ + firstjoint=m_first_joint; + firstbody=m_first_body; + if(!m_nj) + { + m_joints_tail=&firstjoint; + *m_joints_tail=0; + } + else + { + firstjoint->tome=(dObject**)&firstjoint; + } + *m_joints_tail=0; + *m_bodies_tail=0; + //b_active=true; + m_flags.unmerge(); + m_self_active=this; + nj=m_nj; + nb=m_nb; + +} +IC void Init() +{ + //b_active=true; + m_flags.init(); + m_nj=nj=0; + m_nb=nb=0; + m_first_joint=firstjoint=0; + m_first_body=firstbody=0; + m_joints_tail=&firstjoint; + m_bodies_tail=&firstbody; + m_self_active=this; +} +IC void AddBody(dxBody* body) +{ + VERIFY2(m_nj==nj&&m_nb==nb&& m_flags.is_active(),"can not remove/add during processing phase"); + dWorldAddBody(DWorld(),body); + m_first_body=body; + if(m_nb==0) + { + m_bodies_tail=(dxBody**)&body->next; + } + m_nb++; +} +IC void RemoveBody(dxBody* body) +{ + VERIFY2(m_nj==nj&&m_nb==nb && m_flags.is_active() ,"can not remove/add during processing phase"); + if(m_first_body==body)m_first_body=(dxBody*)body->next; + if(m_bodies_tail==(dxBody**)(&(body->next))) + { + m_bodies_tail=(dxBody**)body->tome; + } + dWorldRemoveBody((dxWorld*)this,body); + m_nb--; +} +IC void AddJoint(dxJoint* joint) +{ + VERIFY2(m_nj==nj&&m_nb==nb&&m_flags.is_active(),"can not remove/add during processing phase"); + dWorldAddJoint(DWorld(),joint); + m_first_joint=joint; + if(!m_nj) + { + VERIFY(joint->next==0); + m_joints_tail=(dxJoint**)(&(joint->next)); + + } + m_nj++; +} + +IC void ConnectJoint(dxJoint* joint) +{ + if(!nj) + { + m_joints_tail=(dxJoint**)(&(joint->next)); + VERIFY(!firstjoint); + } + dWorldAddJoint(DWorld(),joint); + VERIFY(!(*(m_joints_tail))); +} + +IC void DisconnectJoint(dxJoint* joint) +{ + dWorldRemoveJoint(DWorld(),joint); +} + +IC void ConnectBody(dxBody* body) +{ + dWorldAddBody(DWorld(),body); +} +IC void DisconnectBody(dxBody* body) +{ + dWorldRemoveBody(DWorld(),body); +} +IC void RemoveJoint(dxJoint* joint) +{ + VERIFY2(m_nj==nj&&m_nb==nb&&m_flags.is_active(),"can not remove/add during processing phase"); + if(m_first_joint==joint) + m_first_joint=(dxJoint*)joint->next; + if(m_joints_tail==(dxJoint**)(&(joint->next))) + { + m_joints_tail=(dxJoint**)joint->tome; + } + dWorldRemoveJoint(DWorld(),joint); + VERIFY(!*(m_joints_tail)); + m_nj--; +} +void SetPrefereExactIntegration(){m_flags.set_prefere_exact_integration();} +void Step(dReal step); +void Enable(); +void Repair(); +protected: +private: +}; +#endif \ No newline at end of file diff --git a/xrPhysics/PHItemList.h b/xrPhysics/PHItemList.h new file mode 100644 index 00000000000..ac857c4fb49 --- /dev/null +++ b/xrPhysics/PHItemList.h @@ -0,0 +1,103 @@ +#ifndef PH_ITEM_LIST_H +#define PH_ITEM_LIST_H +/* +#define DECLARE_PHLIST_ITEM(class_name) public:\ + class CPHListItem\ + {\ + friend class CPHItemList;\ + friend class CPHItemList::iterator;\ + class_name* next;\ + class_name** tome;\ + };\ + private: +*/ +#define DECLARE_PHLIST_ITEM(class_name) friend class CPHItemList;\ + friend class CPHItemList::iterator;\ + class_name* next;\ + class_name** tome; +#define DECLARE_PHSTACK_ITEM(class_name) DECLARE_PHLIST_ITEM(class_name)\ + friend class CPHItemStack;\ + u16 stack_pos; + +//#define TPI(item) ((T::CPHListItem*)item) + +template + class CPHItemList + { + T *first_next ; + T **last_tome ; + protected: + u16 size ; + + public: + + class iterator; + typedef class iterator + { + + T *my_ptr; + public: + iterator(){my_ptr=0;} + iterator(T* i){ my_ptr=i; } + iterator operator ++ () {return my_ptr=((my_ptr)->next);} + T* operator * () {return my_ptr;} + bool operator != (iterator right){return my_ptr!=right.my_ptr;} + }; + CPHItemList () { empty();} + u16 count () {return size;} + void push_back (T* item) + { + *(last_tome)=item; + item->tome= last_tome; + last_tome=&((item)->next); + item->next=0; + size++; + } + void move_items (CPHItemList& sourse_list) + { + if(!sourse_list.first_next) return; + *(last_tome)=sourse_list.first_next; + sourse_list.first_next->tome= last_tome; + last_tome=sourse_list.last_tome; + size=size+sourse_list.size; + sourse_list.empty(); + } + void erase (iterator i) + { + T* item=*i; + T* next=item->next; + *(item->tome)=next; + if(next)next->tome=item->tome; + else last_tome=item->tome; + size--; + } + void empty () + { + last_tome=&first_next; + first_next=0; + size=0; + } + iterator begin() + { + return iterator(first_next); + } + iterator end() + { + return iterator(0); + } + }; + +template + class CPHItemStack : + public CPHItemList + { + public: + void push_back (T* item) + { + item->stack_pos=size; + CPHItemList::push_back(item); + } + }; +#define DEFINE_PHITEM_LIST(T,N,I) typedef CPHItemList N; typedef CPHItemList::iterator I; +#define DEFINE_PHITEM_STACK(T,N,I) typedef CPHItemStack N; typedef CPHItemStack::iterator I; +#endif diff --git a/xrPhysics/PHJoint.cpp b/xrPhysics/PHJoint.cpp new file mode 100644 index 00000000000..353306fd2a5 --- /dev/null +++ b/xrPhysics/PHJoint.cpp @@ -0,0 +1,1550 @@ +#include "StdAfx.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PHJointDestroyInfo.h" +/////////////////////////////////////////////////////////////// +///#pragma warning(disable:4995) +////#include "../xrEngine/ode/src/collision_kernel.h" +//#include <../ode/src/joint.h> +//#include <../ode/src/objects.h> + +//#pragma warning(default:4995) +/////////////////////////////////////////////////////////////////// + +#include "ExtendedGeom.h" + +#include "PHElement.h" +#include "PHJoint.h" +#include "PHShell.h" + +const float hinge2_spring=20000.f; +const float hinge2_damping=1000.f; + +IC dBodyID body_for_joint(CPhysicsElement* ee) +{ + VERIFY(smart_cast(ee)); + CPHElement * e = static_cast (ee); + return e->isFixed() ? 0 : e->get_body();//return e->get_body();// +} +IC void SwapLimits(float &lo,float &hi) +{ + float t=-lo; + lo=-hi; + hi=t; +} +CPHJoint::~CPHJoint(){ + xr_delete(m_destroy_info); + VERIFY(!bActive); + axes.clear(); + if(m_back_ref)*m_back_ref=NULL; +}; + +void CPHJoint::SetBackRef(CPhysicsJoint** j) +{ + R_ASSERT2(*j==static_cast(this),"wronng reference"); + m_back_ref=j; +} +void CPHJoint::CreateBall() +{ + + m_joint=dJointCreateBall(0,0); + Fvector pos; + Fmatrix first_matrix,second_matrix; + CPHElement* first=(pFirst_element); + CPHElement* second=(pSecond_element); + + VERIFY(first&&second); + first->GetGlobalTransformDynamic(&first_matrix); + second->GetGlobalTransformDynamic(&second_matrix); +pos.set(0,0,0); + switch(vs_anchor){ +case vs_first :first_matrix.transform_tiny(pos,anchor); break; +case vs_second:second_matrix.transform_tiny(pos,anchor); break; +case vs_global:pShell->mXFORM.transform_tiny(pos,anchor);break; +default:NODEFAULT; + } + + + + dJointAttach(m_joint,body_for_joint(first),body_for_joint(second)); + dJointSetBallAnchor(m_joint,pos.x,pos.y,pos.z); + +} + + + +void CPHJoint::CreateHinge() +{ + + m_joint=dJointCreateHinge(0,0); + + Fvector pos; + Fmatrix first_matrix,second_matrix; + Fvector axis; + + + CPHElement* first=(pFirst_element); + CPHElement* second=(pSecond_element); + VERIFY(first&&second); + first->GetGlobalTransformDynamic(&first_matrix); + second->GetGlobalTransformDynamic(&second_matrix); + +pos.set(0,0,0); +switch(vs_anchor) +{ +case vs_first :first_matrix.transform_tiny(pos,anchor); break; +case vs_second:second_matrix.transform_tiny(pos,anchor); break; +case vs_global:pShell->mXFORM.transform_tiny(pos,anchor);break; +default:NODEFAULT; +} + + + axis.set(0,0,0); + + first_matrix.invert(); + + Fmatrix rotate; + rotate.mul(first_matrix,second_matrix); + + float hi,lo; + CalcAxis(0,axis,lo,hi,first_matrix,second_matrix,rotate); + dBodyID b1=body_for_joint(first);if(!b1)axis.invert();//SwapLimits(lo,hi); + dJointAttach(m_joint,b1,body_for_joint(second)); + + dJointSetHingeAnchor(m_joint,pos.x,pos.y,pos.z); + dJointSetHingeAxis(m_joint,axis.x,axis.y,axis.z); + + dJointSetHingeParam(m_joint,dParamLoStop ,lo); + dJointSetHingeParam(m_joint,dParamHiStop ,hi); + if(axes[0].force>0.f){ + dJointSetHingeParam(m_joint,dParamFMax ,axes[0].force); + dJointSetHingeParam(m_joint,dParamVel ,axes[0].velocity); + } + dJointSetHingeParam(m_joint,dParamStopERP ,axes[0].erp); + dJointSetHingeParam(m_joint,dParamStopCFM ,axes[0].cfm); + + dJointSetHingeParam(m_joint,dParamCFM ,m_cfm); +} + + +void CPHJoint::CreateHinge2() +{ + + m_joint=dJointCreateHinge2(0,0); + + Fvector pos; + Fmatrix first_matrix,second_matrix; + Fvector axis; + CPHElement* first=(pFirst_element); + CPHElement* second=(pSecond_element); + VERIFY(first&&second); + first->GetGlobalTransformDynamic(&first_matrix); + second->GetGlobalTransformDynamic(&second_matrix); + pos.set(0,0,0); + switch(vs_anchor) + { + case vs_first :first_matrix.transform_tiny(pos,anchor); break; + case vs_second:second_matrix.transform_tiny(pos,anchor); break; + case vs_global:pShell->mXFORM.transform_tiny(pos,anchor);break; + default:NODEFAULT; + } + ////////////////////////////////////// + + dBodyID b1=body_for_joint(first); + dJointAttach(m_joint,b1,body_for_joint(second)); + dJointSetHinge2Anchor(m_joint,pos.x,pos.y,pos.z); + + ///////////////////////////////////////////// + + Fmatrix first_matrix_inv; + first_matrix_inv.set(first_matrix); + first_matrix_inv.invert(); + Fmatrix rotate; + + rotate.mul(first_matrix_inv,second_matrix); + ///////////////////////////////////////////// + + float lo; + float hi; + ////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////// + axis.set(0,0,0); + CalcAxis(0,axis,lo,hi,first_matrix,second_matrix,rotate); + if(!b1)axis.invert();//SwapLimits(lo,hi); + dJointSetHinge2Axis1 (m_joint, axis.x, axis.y, axis.z); + + + dJointSetHinge2Param(m_joint,dParamLoStop ,lo); + dJointSetHinge2Param(m_joint,dParamHiStop ,hi); + + if(!(axes[0].force<0.f)){ + dJointSetHinge2Param(m_joint,dParamFMax,axes[0].force); + dJointSetHinge2Param(m_joint,dParamVel ,axes[0].velocity); + } + + CalcAxis(1,axis,lo,hi,first_matrix,second_matrix,rotate); + + dJointSetHinge2Axis2 (m_joint, axis.x, axis.y, axis.z); + + dJointSetHinge2Param(m_joint,dParamLoStop2 ,lo); + dJointSetHinge2Param(m_joint,dParamHiStop2 ,hi); + if(!(axes[1].force<0.f)){ + dJointSetHinge2Param(m_joint,dParamFMax2 ,axes[1].force); + dJointSetHinge2Param(m_joint,dParamVel2 ,axes[1].velocity); + } + ////////////////////////////////////////////////////////////////// + + dJointSetHinge2Param(m_joint, dParamSuspensionERP, m_erp); + dJointSetHinge2Param(m_joint, dParamSuspensionCFM, m_cfm); + //dJointSetHinge2Param(m_joint, dParamStopERP, 1.f); + //dJointSetHinge2Param(m_joint, dParamStopCFM,0.f); + dJointSetHinge2Param(m_joint, dParamStopERP,axes[0].erp); + dJointSetHinge2Param(m_joint, dParamStopCFM,axes[0].cfm); +} +void CPHJoint::CreateSlider() +{ + Fvector pos; + Fmatrix first_matrix,second_matrix; + Fvector axis; + CPHElement* first=(pFirst_element); + CPHElement* second=(pSecond_element); + + VERIFY(first); + first->GetGlobalTransformDynamic(&first_matrix); + dBodyID body1=body_for_joint(first); + VERIFY(second); + second->GetGlobalTransformDynamic(&second_matrix); + dBodyID body2=body_for_joint(second); + + + pos.set(0,0,0); + switch(vs_anchor){ + case vs_first :first_matrix.transform_tiny(pos,anchor); break; + case vs_second:second_matrix.transform_tiny(pos,anchor); break; + case vs_global:pShell->mXFORM.transform_tiny(pos,anchor);break; + default:NODEFAULT; + } + ////////////////////////////////////// + + + m_joint=dJointCreateSlider(0,0); + dJointAttach(m_joint,body1,body2); + if (body1) + { + axes[0].vs=vs_first; + axes[1].vs=vs_first; + } + else + if (body2) + { + axes[0].vs=vs_second; + axes[1].vs=vs_second; + } + + + + m_joint1=dJointCreateAMotor(0,0); + dJointSetAMotorMode (m_joint1, dAMotorEuler); + dJointSetAMotorNumAxes (m_joint1, 1); + + dJointAttach(m_joint1,body1,body2); + + ///////////////////////////////////////////// + + Fmatrix first_matrix_inv; + first_matrix_inv.set(first_matrix); + first_matrix_inv.invert(); + Fmatrix rotate; + rotate.mul(first_matrix_inv,second_matrix); + ///////////////////////////////////////////// + + float lo; + float hi; + ////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////// + axis.set(0,0,0); + //axis 0 + CalcAxis(0,axis,lo,hi,first_matrix,second_matrix,rotate); + //if(body1)axis.invert();//SwapLimits(lo,hi);!!! + + dJointSetSliderAxis(m_joint, -axis.x, -axis.y, -axis.z); + + dJointSetSliderParam( m_joint, dParamLoStop, axes[0].low ); + dJointSetSliderParam( m_joint, dParamHiStop, axes[0].high ); + + if(!(axes[0].force<0.f)){ + dJointSetSliderParam( m_joint,dParamFMax, axes[0].force ); + dJointSetSliderParam( m_joint,dParamVel, axes[0].velocity ); + } + dJointSetSliderParam( m_joint, dParamStopERP ,axes[0].erp ); + dJointSetSliderParam( m_joint, dParamStopCFM ,axes[0].cfm ); + + //axis 1 + + CalcAxis(1,axis,lo,hi,first_matrix,second_matrix,rotate); + if(!body1)axis.invert();//SwapLimits(lo,hi); + int rel = body1 ? 1 : 2; + dJointSetAMotorAxis (m_joint1, 0,rel, axis.x, axis.y, axis.z); + dJointSetAMotorParam(m_joint1,dParamLoStop ,lo); + dJointSetAMotorParam(m_joint1,dParamHiStop ,hi); + if(!(axes[1].force<0.f)){ + dJointSetAMotorParam(m_joint1,dParamFMax ,axes[1].force); + dJointSetAMotorParam(m_joint1,dParamVel ,axes[1].velocity); + } + + + + dJointSetAMotorParam(m_joint1,dParamStopERP ,axes[1].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM ,axes[1].cfm); + + + ///////////////////////////////////////////////////////////////////// + ///dJointSetAMotorParam(m_joint1,dParamFudgeFactor ,0.1f); + //dJointSetAMotorParam(m_joint1,dParamFudgeFactor2 ,0.1f); + //dJointSetAMotorParam(m_joint1,dParamFudgeFactor3 ,0.1f); + ///////////////////////////////////////////////////////////////////////////// + dJointSetAMotorParam(m_joint1,dParamCFM ,m_cfm); + dJointSetSliderParam(m_joint,dParamCFM,m_cfm); +} + +#ifdef ODE_SLOW_SOLVER +#define FIX_BY_ONE_HINGE +#endif +void CPHJoint::CreateFullControl() +{ + + + Fvector pos; + Fmatrix first_matrix,second_matrix; + Fvector axis; + CPHElement* first=(pFirst_element); + CPHElement* second=(pSecond_element); + VERIFY(first); + first->GetGlobalTransformDynamic(&first_matrix); + dBodyID body1=body_for_joint(first); + VERIFY(second); + second->GetGlobalTransformDynamic(&second_matrix); + dBodyID body2=body_for_joint(second); + + + + +pos.set(0,0,0); +switch(vs_anchor){ +case vs_first :first_matrix.transform_tiny(pos,anchor); break; +case vs_second:second_matrix.transform_tiny(pos,anchor); break; +case vs_global:pShell->mXFORM.transform_tiny(pos,anchor);break; +default:NODEFAULT; + } + ////////////////////////////////////// + + + + m_joint=dJointCreateBall(0,0); + dJointAttach(m_joint,body1,body2); + dJointSetBallAnchor(m_joint,pos.x,pos.y,pos.z); + + + + m_joint1=dJointCreateAMotor(0,0); + dJointSetAMotorMode (m_joint1, dAMotorEuler); + dJointSetAMotorNumAxes (m_joint1, 3); + + dJointAttach(m_joint1,body1,body2); + + ///////////////////////////////////////////// + + Fmatrix first_matrix_inv; + first_matrix_inv.set(first_matrix); + first_matrix_inv.invert(); + Fmatrix rotate; + rotate.mul(first_matrix_inv,second_matrix); + ///////////////////////////////////////////// + + float lo; + float hi; + ////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////// + axis.set(0,0,0); + //axis 0 + CalcAxis(0,axis,lo,hi,first_matrix,second_matrix,rotate); + if(!body1)axis.invert();//SwapLimits(lo,hi); + dJointSetAMotorAxis (m_joint1, 0, 1, axis.x, axis.y, axis.z); + dJointSetAMotorParam(m_joint1,dParamLoStop ,lo); + dJointSetAMotorParam(m_joint1,dParamHiStop ,hi); + + if(!(axes[0].force<0.f)){ + dJointSetAMotorParam(m_joint1,dParamFMax ,axes[0].force); + dJointSetAMotorParam(m_joint1,dParamVel ,axes[0].velocity); + } + + //axis 1 + CalcAxis(1,axis,lo,hi,first_matrix,second_matrix,rotate); + if(!body1)axis.invert();//SwapLimits(lo,hi); + dJointSetAMotorParam(m_joint1,dParamLoStop2 ,lo); + dJointSetAMotorParam(m_joint1,dParamHiStop2 ,hi); + if(!(axes[1].force<0.f)){ + dJointSetAMotorParam(m_joint1,dParamFMax2 ,axes[1].force); + dJointSetAMotorParam(m_joint1,dParamVel2 ,axes[1].velocity); + } + + //axis 2 + CalcAxis(2,axis,lo,hi,first_matrix,second_matrix,rotate); + if(!body1)axis.invert();//SwapLimits(lo,hi); + dJointSetAMotorAxis (m_joint1, 2, 2, axis.x, axis.y, axis.z); + dJointSetAMotorParam(m_joint1,dParamLoStop3 ,lo); + dJointSetAMotorParam(m_joint1,dParamHiStop3 ,hi); + if(!(axes[2].force<0.f)){ + dJointSetAMotorParam(m_joint1,dParamFMax3 ,axes[2].force); + dJointSetAMotorParam(m_joint1,dParamVel3 ,axes[2].velocity); + } + + dJointSetAMotorParam(m_joint1,dParamStopERP ,axes[0].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM ,axes[0].cfm); + + dJointSetAMotorParam(m_joint1,dParamStopERP2 ,axes[1].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM2 ,axes[1].cfm); + + dJointSetAMotorParam(m_joint1,dParamStopERP3 ,axes[2].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM3 ,axes[2].cfm); +///////////////////////////////////////////////////////////////////// + ///dJointSetAMotorParam(m_joint1,dParamFudgeFactor ,0.1f); + //dJointSetAMotorParam(m_joint1,dParamFudgeFactor2 ,0.1f); + //dJointSetAMotorParam(m_joint1,dParamFudgeFactor3 ,0.1f); +///////////////////////////////////////////////////////////////////////////// + dJointSetAMotorParam(m_joint1,dParamCFM ,m_cfm); + dJointSetAMotorParam(m_joint1,dParamCFM2 ,m_cfm); + dJointSetAMotorParam(m_joint1,dParamCFM3 ,m_cfm); +} + + +void CPHJoint::SetAnchor(const float x,const float y,const float z) +{ + vs_anchor=vs_global; + anchor.set(x,y,z); +} + +void CPHJoint::SetAnchorVsFirstElement(const float x,const float y,const float z) +{ + vs_anchor=vs_first; + anchor.set(x,y,z); +} + +void CPHJoint::SetAnchorVsSecondElement(const float x,const float y,const float z) +{ + vs_anchor=vs_second; + anchor.set(x,y,z); +} + +void CPHJoint::SetAxisDir(const float x,const float y,const float z,const int axis_num) +{ + int ax=axis_num; + LimitAxisNum(ax); + //if(-1==ax) return; + VERIFY( -1 != ax ); + axes[ax].vs=vs_global; + axes[ax].direction.set(x,y,z); + + SetAxisDirDynamic( axes[ax].direction, axis_num ); + +} + +void CPHJoint::SetAxisDirDynamic(const Fvector& orientation,const int axis_num) +{ + VERIFY( axis_num>=0 ); + VERIFY( axis_num<=2 ); + + switch(eType){ + + case hinge2: + switch( axis_num ) + { + case 0: dJointSetHinge2Axis1 (m_joint, orientation[0], orientation[1], orientation[2] );break; + case 1: dJointSetHinge2Axis2 (m_joint, orientation[0], orientation[1], orientation[2] );break; + default: NODEFAULT; + } + break; + case slider: + switch( axis_num ) + { + + case 0: dJointSetSliderParam(m_joint,dParamFMax ,axes[0].force);break; + case 1: dJointSetAMotorParam(m_joint1,dParamFMax ,axes[1].force);break; + default: NODEFAULT; + } + break; + case ball: + break; + case hinge: + dJointSetHingeAxis( m_joint, orientation[0], orientation[1], orientation[2] ); + break; + case full_control: + dJointSetAMotorAxis (m_joint1, axis_num, 1, orientation[0], orientation[1], orientation[2] ); + break; + default: R_ASSERT2( false, "type not supported" ); + } +} + +void CPHJoint::SetAxisDirVsFirstElement(const float x,const float y,const float z,const int axis_num) +{ + int ax=axis_num; + LimitAxisNum(ax); + if(-1==ax) return; + axes[ax].vs=vs_first; + axes[ax].direction.set(x,y,z); +} + +void CPHJoint::SetAxisDirVsSecondElement(const float x,const float y,const float z,const int axis_num) +{ + int ax=axis_num; + LimitAxisNum(ax); + if(-1==ax) return; + axes[ax].vs=vs_second; + axes[ax].direction.set(x,y,z); + +} + +void CPHJoint::SetLimits(const float low, const float high, const int axis_num) +{ + if(!(pFirst_element&&pSecond_element)) + return; + + int ax=axis_num; + LimitAxisNum(ax); + if(-1==ax)return; + + Fvector axis; + switch(axes[ax].vs){ + case vs_first :pFirst_element->mXFORM.transform_dir(axis,axes[ax].direction); break; + case vs_second:pSecond_element->mXFORM.transform_dir(axis,axes[ax].direction); break; + case vs_global: + default: axis.set(axes[ax].direction); + } + + axes[ax].low=low; + axes[ax].high=high; + Fmatrix m1,m2; + m1.set(pFirst_element->mXFORM); + m1.invert(); + m2.mul(m1,pSecond_element->mXFORM); + //m2.mul(pSecond_element->mXFORM,m1); + + + + float zer; + //axis_angleB(m2,axis,zer); + axis_angleA(m2,axes[ax].direction,zer); + + axes[ax].zero=zer; + //m2.invert(); + //axes[ax].zero_transform.set(m2); + if(bActive) + SetLimitsActive(axis_num); +} + + +CPHJoint::CPHJoint(CPhysicsJoint::enumType type ,CPhysicsElement* first,CPhysicsElement* second) +{ + + pShell=NULL; + m_bone_id=u16(-1); + m_back_ref =NULL; + m_destroy_info=NULL; + pFirstGeom =NULL; + pFirst_element=cast_PHElement(first); + pSecond_element=cast_PHElement(second); + m_joint=NULL; + m_joint1=NULL; + eType=type; + bActive=false; + +#ifndef ODE_SLOW_SOLVER + m_erp=world_erp; + m_cfm=world_cfm; +#else + m_erp=world_erp; + m_cfm=world_cfm; +#endif + + SPHAxis axis,axis2,axis3; + axis2.set_direction(1,0,0); + axis3.direction.crossproduct(axis.direction,axis3.direction); + vs_anchor=vs_first; + + switch(eType){ + case ball: ; break; + case hinge: axes.push_back(axis); + break; + case hinge2: + axes.push_back(axis); + axes.push_back(axis2); + break; + case full_control: + axes.push_back(axis); + axes.push_back(axis2); + axes.push_back(axis3); + case slider: + axes.push_back(axis); + axes.push_back(axis); + } + +} + +void CPHJoint::SetLimitsVsFirstElement(const float low, const float high,const int axis_num) +{ +} + +void CPHJoint::SetLimitsVsSecondElement(const float low, const float high,const int axis_num) +{ +} + +void CPHJoint::Create() +{ + if(bActive) return; + switch(eType){ + case ball: CreateBall(); break; + case hinge: CreateHinge(); break; + case hinge2: CreateHinge2(); break; + case full_control: CreateFullControl(); break; + case slider: CreateSlider(); break; + } + if(m_destroy_info) + { + dJointSetFeedback(m_joint,m_destroy_info->JointFeedback()); + if(m_joint1)dJointSetFeedback(m_joint1,m_destroy_info->JointFeedback()); + } + dJointSetData(m_joint,(void*)this); + if(m_joint1)dJointSetData(m_joint1,(void*)this); + bActive=true; +} +void CPHJoint::RunSimulation() +{ + pShell->Island().AddJoint(m_joint); + ///dWorldAddJoint(phWorld,m_joint); + if(m_joint1) + { + //dWorldAddJoint(phWorld,m_joint1); + pShell->Island().AddJoint(m_joint1); + } +} +void CPHJoint::Activate() +{ + Create(); + RunSimulation(); +} +void CPHJoint::Deactivate() +{ + if(!bActive) return; + switch(eType){ + case ball: ; + case hinge: ; + case hinge2: ; + if(m_joint->world)pShell->Island().RemoveJoint(m_joint); + dJointDestroy(m_joint); + break; + case full_control: + case slider: + if(m_joint->world)pShell->Island().RemoveJoint(m_joint); + if(m_joint1->world)pShell->Island().RemoveJoint(m_joint1); + dJointDestroy(m_joint); + dJointDestroy(m_joint1); + m_joint1=NULL; + break; + } + m_joint=NULL; + bActive=false; +} +void CPHJoint::ReattachFirstElement(CPHElement* new_element) +{ + Deactivate(); + pFirst_element=(new_element); + Activate(); + //dJointAttach(m_joint,pFirst_element->get_body(),pSecond_element->get_body()); + //if(m_joint1)dJointAttach(m_joint1,pFirst_element->get_body(),pSecond_element->get_body()); +} +void CPHJoint::SetForceAndVelocity (const float force,const float velocity,const int axis_num) +{ + if(pShell&&pShell->isActive())pShell->Enable(); + SetForce(force,axis_num); + SetVelocity(velocity,axis_num); +} + +void CPHJoint::GetMaxForceAndVelocity(float &force,float &velocity,int axis_num) +{ + force=axes[axis_num].force; + velocity=axes[axis_num].velocity; +} + + +void CPHJoint::SetForce (const float force,const int axis_num){ + int ax; + ax=axis_num; + LimitAxisNum(ax); + + if(ax==-1) + switch(eType){ + case ball: return; + case hinge: + axes[0].force=force; + break; + case hinge2: ; + case slider: ; + axes[0].force=force; + axes[1].force=force; + break; + case full_control: + axes[0].force=force; + axes[1].force=force; + axes[2].force=force; + break; + } + + else{ + axes[ax].force=force; + } + + if(bActive) + { + SetForceActive(ax); + } +} + + +void CPHJoint::SetForceActive (const int axis_num) +{ + switch(eType){ + + case hinge2:switch(axis_num) + { + case -1: + dJointSetHinge2Param(m_joint,dParamFMax ,axes[0].force); + dJointSetHinge2Param(m_joint,dParamFMax2 ,axes[1].force); + case 0: dJointSetHinge2Param(m_joint,dParamFMax ,axes[0].force);break; + case 1: dJointSetHinge2Param(m_joint,dParamFMax2 ,axes[1].force);break; + } + break; + case slider:switch(axis_num) + { + case -1: + dJointSetSliderParam(m_joint,dParamFMax ,axes[0].force); + dJointSetAMotorParam(m_joint1,dParamFMax ,axes[1].force); + case 0: dJointSetSliderParam(m_joint,dParamFMax ,axes[0].force);break; + case 1: dJointSetAMotorParam(m_joint1,dParamFMax ,axes[1].force);break; + } + break; + case ball: break; + case hinge: dJointSetHingeParam(m_joint,dParamFMax ,axes[0].force); + break; + + + + case full_control: + switch(axis_num){ + case -1: + dJointSetAMotorParam(m_joint1,dParamFMax ,axes[0].force); + dJointSetAMotorParam(m_joint1,dParamFMax2 ,axes[1].force); + dJointSetAMotorParam(m_joint1,dParamFMax3 ,axes[2].force); + case 0:dJointSetAMotorParam(m_joint1,dParamFMax ,axes[0].force);break; + case 1:dJointSetAMotorParam(m_joint1,dParamFMax2 ,axes[1].force);break; + case 2:dJointSetAMotorParam(m_joint1,dParamFMax3 ,axes[2].force);break; + } + break; + } +} + +void CPHJoint::SetVelocity (const float velocity,const int axis_num){ + int ax; + ax=axis_num; + LimitAxisNum(ax); + + + if(ax==-1) + switch(eType){ + case ball: return; + case hinge: + axes[0].velocity=velocity; + break; + case hinge2: ; + case slider: ; + axes[0].velocity=velocity; + axes[1].velocity=velocity; + break; + case full_control: + axes[0].velocity=velocity; + axes[1].velocity=velocity; + axes[2].velocity=velocity; + break; + } + + else{ + axes[ax].velocity=velocity; + } + + if(bActive) + { + SetVelocityActive(ax); + } +} + +void CPHJoint::SetVelocityActive(const int axis_num) +{ + switch(eType){ + + case hinge2:switch(axis_num) + { + case -1: + dJointSetHinge2Param(m_joint,dParamVel ,axes[0].velocity); + dJointSetHinge2Param(m_joint,dParamVel2 ,axes[1].velocity); + case 0: dJointSetHinge2Param(m_joint,dParamVel ,axes[0].velocity);break; + case 1: dJointSetHinge2Param(m_joint,dParamVel2 ,axes[1].velocity);break; + } + break; + case slider:switch(axis_num) + { + case -1: + dJointSetSliderParam(m_joint,dParamVel ,axes[0].velocity); + dJointSetAMotorParam(m_joint1,dParamVel ,axes[1].velocity); + case 0: dJointSetSliderParam(m_joint,dParamVel ,axes[0].velocity);break; + case 1: dJointSetAMotorParam(m_joint1,dParamVel ,axes[1].velocity);break; + } + break; + case ball: break; + case hinge: dJointSetHingeParam(m_joint,dParamVel ,axes[0].velocity); + break; + + + + case full_control: + switch(axis_num){ + case -1: + dJointSetAMotorParam(m_joint1,dParamVel ,axes[0].velocity); + dJointSetAMotorParam(m_joint1,dParamVel2 ,axes[1].velocity); + dJointSetAMotorParam(m_joint1,dParamVel3 ,axes[2].velocity); + case 0:dJointSetAMotorParam(m_joint1,dParamVel ,axes[0].velocity);break; + case 1:dJointSetAMotorParam(m_joint1,dParamVel2 ,axes[1].velocity);break; + case 2:dJointSetAMotorParam(m_joint1,dParamVel3 ,axes[2].velocity);break; + } + break; + } +} +void CPHJoint::SetLoLimitDynamic(int axis_num, float limit ) +{ + + VERIFY( axis_num>=0 ); + VERIFY( axis_num<=2 ); + VERIFY( bActive ); + switch(eType){ + + case hinge2: + VERIFY( axis_num == 0 ); + //axes[0].low = limit; + VERIFY( m_joint ); + dJointSetHinge2Param( m_joint,dParamLoStop ,limit ); + break; + case slider: + VERIFY( axis_num <= 1 ); + switch(axis_num) + { + case 0: //axes[0].low = limit; + VERIFY( m_joint ); + dJointSetSliderParam(m_joint,dParamLoStop ,limit); + break; + case 1: //axes[1].low = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1, dParamLoStop ,limit); + break; + default: NODEFAULT; + } + break; + case ball: + break; + case hinge: + //axes[0].low = limit; + VERIFY( m_joint ); + dJointSetHingeParam( m_joint, dParamLoStop , limit ); + break; + case full_control: + switch(axis_num) + { + case 0: //axes[0].low = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1,dParamLoStop ,limit); + break; + case 1: //axes[1].low = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1,dParamLoStop2 ,limit); + break; + case 2: //axes[2].low = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1,dParamLoStop3 ,limit); + break; + default: NODEFAULT; + } + break; + default: R_ASSERT2( false, "type is not supported" ); + } +} + + +void CPHJoint::SetHiLimitDynamic(int axis_num, float limit ) +{ + + VERIFY( axis_num>=0 ); + VERIFY( axis_num<=2 ); + VERIFY( bActive ); + switch(eType){ + + case hinge2: + VERIFY( axis_num == 0 ); + VERIFY( m_joint ); + //axes[0].high = limit; + dJointSetHinge2Param( m_joint,dParamHiStop ,limit ); + break; + case slider: + VERIFY( axis_num <= 1 ); + switch(axis_num) + { + case 0: //axes[0].high = limit; + VERIFY( m_joint ); + dJointSetSliderParam(m_joint,dParamHiStop ,limit); + break; + case 1: //axes[1].high = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1, dParamHiStop ,limit); + break; + default: NODEFAULT; + } + break; + case ball: + break; + case hinge: + //axes[0].high = limit; + VERIFY( m_joint ); + dJointSetHingeParam( m_joint, dParamHiStop , limit ); + break; + case full_control: + switch(axis_num) + { + case 0: //axes[0].high = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1,dParamHiStop ,limit); + break; + case 1: //axes[1].high = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1,dParamHiStop2 ,limit); + break; + case 2: //axes[2].high = limit; + VERIFY( m_joint1 ); + dJointSetAMotorParam(m_joint1,dParamHiStop3 ,limit); + break; + default: NODEFAULT; + } + break; + default: R_ASSERT2( false, "type is not supported" ); + } +} + +/* +float CPHJoint::GetAxisAngle(int axis_num) +{ + float ret=dInfinity; + switch(eType){ + case hinge2: ret= dJointGetHinge2Angle1(m_joint);break; + case ball: ret= dInfinity;break; + case hinge: ret= dJointGetHingeAngle(m_joint);break; + case full_control: ret= dJointGetAMotorAngle(m_joint1,axis_num);break; + case slider: + switch (axis_num){ + case 0: ret= dJointGetSliderPosition(m_joint);break; + case 1: ret= dJointGetAMotorAngle(m_joint1,0);break; + };break; + default: R_ASSERT2( false, "type not supported" ); break; + + } +} +*/ +void CPHJoint::SetLimitsActive(int axis_num) +{ + switch(eType){ + + case hinge2: + switch(axis_num) + { + case -1: + case 0: + case 1: + dJointSetHinge2Param(m_joint,dParamLoStop ,axes[0].low); + dJointSetHinge2Param(m_joint,dParamHiStop,axes[0].high);break; + } + break; + case slider:switch(axis_num) + { + case -1: + dJointSetSliderParam(m_joint,dParamLoStop ,axes[0].low); + dJointSetSliderParam(m_joint,dParamHiStop ,axes[0].high); + dJointSetAMotorParam(m_joint1,dParamLoStop ,axes[1].low); + dJointSetAMotorParam(m_joint1,dParamHiStop ,axes[1].high); + case 0: dJointSetSliderParam(m_joint,dParamLoStop ,axes[0].low); + dJointSetSliderParam(m_joint,dParamHiStop ,axes[0].high);break; + case 1: dJointSetAMotorParam(m_joint1,dParamLoStop ,axes[1].low); + dJointSetAMotorParam(m_joint1,dParamHiStop ,axes[1].high);break; + } + break; + case ball: break; + case hinge: dJointSetHingeParam(m_joint,dParamLoStop ,axes[0].low); + dJointSetHingeParam(m_joint,dParamHiStop ,axes[0].high); + break; + + + + case full_control: + switch(axis_num){ + case -1: + dJointSetAMotorParam(m_joint1,dParamLoStop ,axes[0].low); + dJointSetAMotorParam(m_joint1,dParamLoStop ,axes[0].low); + dJointSetAMotorParam(m_joint1,dParamLoStop2 ,axes[1].low); + dJointSetAMotorParam(m_joint1,dParamHiStop2 ,axes[1].high); + dJointSetAMotorParam(m_joint1,dParamHiStop3 ,axes[2].high); + dJointSetAMotorParam(m_joint1,dParamHiStop3 ,axes[2].high); + case 0:dJointSetAMotorParam(m_joint1,dParamLoStop ,axes[0].low); + dJointSetAMotorParam(m_joint1,dParamHiStop ,axes[0].high); + break; + case 1:dJointSetAMotorParam(m_joint1,dParamLoStop2 ,axes[1].low); + dJointSetAMotorParam(m_joint1,dParamHiStop2 ,axes[1].high); + break; + case 2:dJointSetAMotorParam(m_joint1,dParamLoStop3 ,axes[2].low); + dJointSetAMotorParam(m_joint1,dParamHiStop3 ,axes[2].high); + break; + } + break; + } +} + +float CPHJoint::GetAxisAngleRate( int axis_num ) +{ + + float ret=0.f; + VERIFY( axis_num>=0 ); + VERIFY( axis_num<=2 ); + VERIFY( bActive ); + + switch(eType){ + case hinge2: + VERIFY(m_joint); + VERIFY( axis_num<=1 ); + if( axis_num == 0 ) + ret= dJointGetHinge2Angle1Rate(m_joint); + else + ret= dJointGetHinge2Angle2Rate(m_joint); + break; + + case ball: ret= 0.f;break; + case hinge: VERIFY(m_joint); + ret= dJointGetHingeAngleRate(m_joint); + break; + case full_control: VERIFY(m_joint1); + ret= dJointGetAMotorAngleRate(m_joint1,axis_num); + break; + case slider: + switch (axis_num) + { + case 0: VERIFY(m_joint); + ret= dJointGetSliderPositionRate(m_joint); + break; + case 1: VERIFY(m_joint1); + ret= dJointGetAMotorAngleRate(m_joint1,0); + break; + };break; + default: R_ASSERT2( false, "type not supported" ); break; + + } + return ret;// body_for_joint(pFirst_element) ? ret : - + +} + +float CPHJoint::GetAxisAngle(int axis_num) +{ + float ret=dInfinity; + switch(eType){ + case hinge2: ret= dJointGetHinge2Angle1(m_joint);break; + case ball: ret= dInfinity;break; + case hinge: ret= dJointGetHingeAngle(m_joint);break; + case full_control: ret= dJointGetAMotorAngle(m_joint1,axis_num);break; + case slider: + switch (axis_num){ + case 0: ret= dJointGetSliderPosition(m_joint);break; + case 1: ret= dJointGetAMotorAngle(m_joint1,0);break; + };break; + default: R_ASSERT2( false, "type not supported" ); break; + + } + return ret;// body_for_joint(pFirst_element) ? ret : - +} + +void CPHJoint::LimitAxisNum(int &axis_num) +{ + if(axis_num<-1) + { + axis_num=-1; + return; + } + + switch(eType){ + case ball: axis_num=-1; + break; + case hinge: axis_num=0; + break; + case slider: + case hinge2: axis_num= axis_num>1 ? 1 : axis_num; + break; + + case full_control: axis_num= axis_num>2 ? 2 : axis_num; + break; + + } + +} + +void CPHJoint::SetAxis(const SPHAxis& axis,const int axis_num) +{ +int ax=axis_num; +LimitAxisNum(ax); +if(ax==-1) + switch(eType){ + case ball: + break; + case hinge: + axes[0]=axis; + break; + case hinge2: ; + case slider: ; + axes[0]=axis; + axes[1]=axis; + break; + case full_control: + axes[0]=axis; + axes[1]=axis; + axes[2]=axis; + break; + } +else + axes[ax]=axis; +} + +void CPHJoint::SetAxisSDfactors(float spring_factor,float damping_factor,int axis_num) + +{ + int ax=axis_num; + LimitAxisNum(ax); + if(ax==-1) + { + switch(eType){ + case ball: + break; + case hinge: + axes[0].set_sd_factors(spring_factor,damping_factor,eType); + break; + case hinge2: ; + case slider: ; + axes[0].set_sd_factors(spring_factor,damping_factor,eType); + axes[1].set_sd_factors(spring_factor,damping_factor,eType); + break; + + case full_control: + axes[0].set_sd_factors(spring_factor,damping_factor,eType); + axes[1].set_sd_factors(spring_factor,damping_factor,eType); + axes[2].set_sd_factors(spring_factor,damping_factor,eType); + break; + } + + if(bActive)SetLimitsSDfactorsActive(); + } + else + { + axes[ax].set_sd_factors(spring_factor,damping_factor,eType); + if(bActive)SetAxisSDfactorsActive(ax); + } +} + + +void CPHJoint::SetJointSDfactors(float spring_factor,float damping_factor) +{ + switch(eType){ + case hinge2: + m_cfm=CFM(hinge2_spring*spring_factor,hinge2_damping*damping_factor); + m_erp=ERP(hinge2_spring*spring_factor,hinge2_damping*damping_factor); + break; + case ball: ; + case hinge: ; + case full_control: ; + case slider: ; + m_erp=ERP(world_spring*spring_factor,world_damping*damping_factor); + m_cfm=CFM(world_spring*spring_factor,world_damping*damping_factor); + break; + } + if(bActive) SetJointSDfactorsActive(); +} + +void CPHJoint::SetJointSDfactorsActive() +{ + switch(eType){ + case hinge2: dJointSetHinge2Param(m_joint, dParamSuspensionERP, m_erp); + dJointSetHinge2Param(m_joint, dParamSuspensionCFM, m_cfm); break ; + case ball: break ; + case hinge: dJointSetHingeParam(m_joint,dParamCFM ,m_cfm); break ; + case full_control: dJointSetAMotorParam(m_joint1,dParamCFM ,m_cfm); + dJointSetAMotorParam(m_joint1,dParamCFM2 ,m_cfm); + dJointSetAMotorParam(m_joint1,dParamCFM3 ,m_cfm); break ; + case slider: dJointSetSliderParam(m_joint,dParamCFM ,m_cfm); break ; + } +} +void CPHJoint::SetLimitsSDfactorsActive() +{ + switch(eType){ + case hinge2: dJointSetHinge2Param(m_joint, dParamStopERP,axes[0].erp); + dJointSetHinge2Param(m_joint, dParamStopCFM,axes[0].cfm); break ; + case ball: break ; + case hinge: dJointSetHingeParam(m_joint,dParamStopERP ,axes[0].erp); + dJointSetHingeParam(m_joint,dParamStopCFM ,axes[0].cfm); break ; + case full_control: dJointSetAMotorParam(m_joint1,dParamStopERP ,axes[0].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM ,axes[0].cfm); + dJointSetAMotorParam(m_joint1,dParamStopERP2 ,axes[1].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM2 ,axes[1].cfm); + dJointSetAMotorParam(m_joint1,dParamStopERP3 ,axes[2].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM3 ,axes[2].cfm); break ; + case slider: dJointSetSliderParam(m_joint,dParamStopERP,axes[0].erp); + dJointSetSliderParam(m_joint,dParamStopCFM,axes[0].cfm); + dJointSetAMotorParam(m_joint1,dParamStopERP ,axes[1].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM ,axes[1].cfm); break ; + + } +} +void CPHJoint::SetAxisSDfactorsActive(int axis_num) +{ + LimitAxisNum(axis_num); + + switch(eType){ + case hinge2: dJointSetHinge2Param(m_joint, dParamStopERP,axes[0].erp); + dJointSetHinge2Param(m_joint, dParamStopCFM,axes[0].cfm); + break ; + case ball: break ; + case hinge: dJointSetHingeParam(m_joint,dParamStopERP ,axes[0].erp); + dJointSetHingeParam(m_joint,dParamStopCFM ,axes[0].cfm); + break ; + case full_control: switch(axis_num) + { + case 0: + dJointSetAMotorParam(m_joint1,dParamStopERP ,axes[axis_num].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM ,axes[0].cfm); + break; + case 1: + dJointSetAMotorParam(m_joint1,dParamStopERP2 ,axes[1].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM2 ,axes[1].cfm); + break; + case 2: + dJointSetAMotorParam(m_joint1,dParamStopERP3 ,axes[2].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM3 ,axes[2].cfm); + break; + } + break; + case slider: switch(axis_num) + { + case 0: + dJointSetSliderParam(m_joint,dParamStopERP,axes[0].erp); + dJointSetSliderParam(m_joint,dParamStopCFM,axes[0].cfm); + case 1: + dJointSetAMotorParam(m_joint1,dParamStopERP ,axes[1].erp); + dJointSetAMotorParam(m_joint1,dParamStopCFM ,axes[1].cfm); + } + break ; + + + } +} + + + +void CPHJoint::SetJointFudgefactorActive(float factor) +{ + VERIFY( bActive ); + switch(eType) + { + case hinge2: VERIFY(m_joint); + dJointSetHinge2Param( m_joint, dParamFudgeFactor, factor ); + break ; + case ball: break ; + case hinge: VERIFY(m_joint); + dJointSetHingeParam( m_joint,dParamFudgeFactor ,factor ); + break; + + case full_control: VERIFY(m_joint1); + dJointSetAMotorParam( m_joint1,dParamFudgeFactor, factor ); + dJointSetAMotorParam(m_joint1,dParamFudgeFactor2, factor ); + dJointSetAMotorParam(m_joint1,dParamFudgeFactor3, factor ); + break; + + case slider: VERIFY(m_joint); + dJointSetSliderParam( m_joint,dParamFudgeFactor, factor ); + VERIFY(m_joint1); + dJointSetAMotorParam( m_joint1, dParamFudgeFactor ,factor ); + break ; + + } +} + + +void CPHJoint::GetJointSDfactors(float& spring_factor,float& damping_factor) +{ +spring_factor =SPRING(m_cfm,m_erp); +damping_factor=DAMPING(m_cfm,m_erp); +if(eType==hinge2) + { + spring_factor/=hinge2_spring; + damping_factor/=hinge2_damping; + } +else + { + spring_factor/=world_spring; + damping_factor/=world_damping; + } +} +void CPHJoint::GetAxisSDfactors(float& spring_factor,float& damping_factor,int axis_num) +{ + LimitAxisNum(axis_num); + spring_factor=SPRING(axes[axis_num].cfm,axes[axis_num].erp)/world_spring; + damping_factor=DAMPING(axes[axis_num].cfm,axes[axis_num].erp)/world_damping; +} +u16 CPHJoint::GetAxesNumber() +{ + return u16(axes.size()); +} +void CPHJoint::CalcAxis(int ax_num,Fvector& axis, float& lo,float& hi,const Fmatrix& first_matrix,const Fmatrix& second_matrix,const Fmatrix& rotate) +{ + switch(axes[ax_num].vs) + { + case vs_first :first_matrix.transform_dir(axis,axes[ax_num].direction) ; break; + case vs_second:second_matrix.transform_dir(axis,axes[ax_num].direction) ; break; + case vs_global:pShell->mXFORM.transform_dir(axis,axes[ax_num].direction);break; + default: NODEFAULT; + } + lo=axes[ax_num].low; + hi=axes[ax_num].high; + if(lo<-M_PI){ + hi-=(lo+M_PI); + lo=-M_PI; + } + if(lo>0.f) { + hi-=lo; + lo=0.f; + } + if(hi>M_PI) { + lo-=(hi-M_PI); + hi=M_PI; + } + if(hi<0.f) { + lo-=hi; + hi=0.f; + } +} + +void CPHJoint::CalcAxis(int ax_num,Fvector& axis,float& lo,float& hi,const Fmatrix& first_matrix,const Fmatrix& second_matrix) +{ + switch(axes[ax_num].vs) + { + + case vs_first :first_matrix.transform_dir(axis,axes[ax_num].direction); break; + case vs_second:second_matrix.transform_dir(axis,axes[ax_num].direction); break; + case vs_global:pShell->mXFORM.transform_dir(axis,axes[ax_num].direction);break; + default: NODEFAULT; + } + + + Fmatrix inv_first_matrix; + inv_first_matrix.set(first_matrix); + inv_first_matrix.invert(); + + Fmatrix rotate; + rotate.mul(inv_first_matrix,second_matrix); + + float shift_angle; + axis_angleA(rotate,axes[ax_num].direction,shift_angle); + + shift_angle-=axes[ax_num].zero; + + if(shift_angle>M_PI) shift_angle-=2.f*M_PI; + if(shift_angle<-M_PI) shift_angle+=2.f*M_PI; + + + lo=axes[ax_num].low;//+shift_angle; + hi=axes[ax_num].high;//+shift_angle; + if(lo<-M_PI){ + hi-=(lo+M_PI); + lo=-M_PI; + } + if(lo>0.f) { + hi-=lo; + lo=0.f; + } + if(hi>M_PI) { + lo-=(hi-M_PI); + hi=M_PI; + } + if(hi<0.f) { + lo-=hi; + hi=0.f; + } + + +} + +void CPHJoint::GetLimits (float& lo_limit,float& hi_limit,int axis_num) +{ + LimitAxisNum(axis_num); + if( body_for_joint(pFirst_element)) + { + + lo_limit=axes[axis_num].low; + hi_limit=axes[axis_num].high; + }else + { + lo_limit=-axes[axis_num].high; + hi_limit=-axes[axis_num].low; + } +} + + +void CPHJoint::GetAxisDir(int num, Fvector& axis, eVs& vs) +{ +LimitAxisNum(num); +vs=axes[num].vs; +axis.set(axes[num].direction); +} + +void CPHJoint::GetAxisDirDynamic(int num,Fvector& axis) +{ + LimitAxisNum(num); + dVector3 result; + switch(eType) + { + + case ball: ; + return; + case hinge: dJointGetHingeAxis (m_joint,result); + break; + case hinge2: if(num) dJointGetHinge2Axis2 (m_joint,result); + else dJointGetHinge2Axis1 (m_joint,result); + break; + case full_control: dJointGetAMotorAxis (m_joint1,num,result); + break; + case slider: dJointGetSliderAxis(m_joint,result); + break; + default: R_ASSERT2(false, "type not supported"); + } + axis.set(result[0],result[1],result[2]); +} + +void CPHJoint::GetAnchorDynamic(Fvector& anchor) +{ + + dVector3 result; + switch(eType) + { + case hinge: dJointGetHingeAnchor (m_joint,result); + break; + case hinge2: dJointGetHingeAnchor (m_joint,result); + break; + case ball: ; + case full_control: dJointGetBallAnchor (m_joint,result); + break; + case slider: R_ASSERT2(false,"position of slider joint is undefinite"); + break; + default: R_ASSERT2(false,"type not supported"); + break; + } + anchor.set(result[0],result[1],result[2]); +} + +CPHJoint::SPHAxis::SPHAxis(){ + high=dInfinity; + low=-dInfinity; + zero=0.f; + //erp=ERP(world_spring/5.f,world_damping*5.f); + //cfm=CFM(world_spring/5.f,world_damping*5.f); +#ifndef ODE_SLOW_SOLVER + erp=world_erp; + cfm=world_cfm; +#else + erp=0.3f; + cfm=0.000001f; +#endif + direction.set(0,0,1); + vs=vs_first; + force=0.f; + velocity=0.f; +} + +void CPHJoint::SPHAxis::set_sd_factors(float sf,float df,enumType jt) +{ + switch(jt) + { + case hinge2: +#ifndef ODE_SLOW_SOLVER + cfm=0.f; + erp=1.f; + break; +#endif + case ball: ; + case hinge: ; + case full_control: ; + case slider: ; + erp=ERP(world_spring*sf,world_damping*df); + cfm=CFM(world_spring*sf,world_damping*df); + break; + } +} +CPhysicsElement* CPHJoint::PFirst_element() +{ + return cast_PhysicsElement(pFirst_element); +} +CPhysicsElement* CPHJoint::PSecond_element() +{ + return cast_PhysicsElement(pSecond_element); +} +void CPHJoint::SetBreakable(float force,float torque) +{ + if(!m_destroy_info) m_destroy_info=xr_new(force,torque); +} + +void CPHJoint::SetShell(CPHShell* p) +{ + if(!m_joint||!pShell) + { + pShell=p; + return; + } + if(pShell!=p) + { + pShell->Island().RemoveJoint(m_joint); + p->Island().AddJoint(m_joint); + if(m_joint1) + { + pShell->Island().RemoveJoint(m_joint1); + p->Island().AddJoint(m_joint1); + } + pShell=p; + } +} +void CPHJoint::ClearDestroyInfo() +{ + xr_delete(m_destroy_info); +} + +bool CPHJoint::IsWheelJoint () +{ + return dJointGetType(GetDJoint())==dJointTypeHinge2; +} +bool CPHJoint::IsHingeJoint () +{ + return dJointGetType(GetDJoint())==dJointTypeHinge; +} \ No newline at end of file diff --git a/xrPhysics/PHJoint.h b/xrPhysics/PHJoint.h new file mode 100644 index 00000000000..583d25fedfb --- /dev/null +++ b/xrPhysics/PHJoint.h @@ -0,0 +1,253 @@ +///////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +#ifndef PH_JOINT +#define PH_JOINT +#include "PhysicsShell.h" +#include "../3rd party/ode/include/ode/common.h" +#include "physics_scripted.h" +class CPHJointDestroyInfo; +class CPHJoint: + public CPhysicsJoint, + public cphysics_scripted +{ +/////////////////////////////////////////////////////// + u16 m_bone_id ; + CPHElement *pFirst_element ; + CPHElement *pSecond_element ; + CODEGeom *pFirstGeom ; + ///////////////////////////////////////////////////////// + CPHShell *pShell ; + dJointID m_joint ; + dJointID m_joint1 ; + CPhysicsJoint **m_back_ref ; + CPHJointDestroyInfo *m_destroy_info ; + float m_erp ; //joint erp + float m_cfm ; //joint cfm +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + struct SPHAxis { + float high ; //high limit + float low ; //law limit + float zero ; //zero angle position + float erp ; //limit erp + float cfm ; //limit cfm + eVs vs ; //coordinate system + float force ; //max force + float velocity ; //velocity to achieve + Fvector direction ; //axis direction + IC void set_limits (float h, float l) {high=h; low=l ;} + IC void set_direction (const Fvector& v) {direction.set(v) ;} + IC void set_direction (const float x,const float y,const float z) {direction.set(x,y,z) ;} + IC void set_param (const float e,const float c) {erp=e;cfm=c ;} + void set_sd_factors (float sf,float df,enumType jt) ; + SPHAxis (); + }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + xr_vector axes ; + Fvector anchor ; + eVs vs_anchor ; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void CreateBall () ; + void CreateHinge () ; + void CreateHinge2 () ; + void CreateFullControl () ; + void CreateSlider () ; + void LimitAxisNum (int &axis_num) ; + void SetForceActive (const int axis_num) ; + void SetVelocityActive (const int axis_num) ; + void SetLimitsActive (int axis_num) ; + void CalcAxis (int ax_num,Fvector& axis,float& lo,float& hi,const Fmatrix& first_matrix,const Fmatrix& second_matrix) ; + void CalcAxis (int ax_num,Fvector& axis,float& lo,float& hi,const Fmatrix& first_matrix,const Fmatrix& second_matrix,const Fmatrix& rotate) ; + virtual u16 GetAxesNumber () ; + virtual void SetAxisSDfactors (float spring_factor,float damping_factor,int axis_num) ; + virtual void SetJointSDfactors (float spring_factor,float damping_factor) ; + virtual void SetJointSDfactorsActive () ; + virtual void SetLimitsSDfactorsActive () ; + virtual void SetAxisSDfactorsActive (int axis_num) ; + virtual void SetJointFudgefactorActive ( float factor ) ; + + virtual void SetAxis (const SPHAxis& axis,const int axis_num) ; + virtual void SetAnchor (const Fvector& position) {SetAnchor(position.x,position.y,position.z);} + virtual void SetAnchorVsFirstElement (const Fvector& position) {SetAnchorVsFirstElement(position.x,position.y,position.z) ;} + virtual void SetAnchorVsSecondElement (const Fvector& position) {SetAnchorVsSecondElement(position.x,position.y,position.z) ;} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAxisDir (const Fvector& orientation,const int axis_num) {SetAxisDir(orientation.x,orientation.y,orientation.z,axis_num) ;} + virtual void SetAxisDirVsFirstElement (const Fvector& orientation,const int axis_num) {SetAxisDirVsFirstElement(orientation.x,orientation.y,orientation.z,axis_num) ;} + virtual void SetAxisDirVsSecondElement (const Fvector& orientation,const int axis_num) {SetAxisDirVsSecondElement(orientation.x,orientation.y,orientation.z,axis_num) ;} + virtual void SetAxisDirDynamic (const Fvector& orientation,const int axis_num) ; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetLimits (const float low,const float high,const int axis_num) ; + virtual void SetLimitsVsFirstElement (const float low,const float high,const int axis_num) ; + virtual void SetLimitsVsSecondElement (const float low,const float high,const int axis_num) ; + virtual void SetHiLimitDynamic (int axis_num, float limit ) ; + virtual void SetLoLimitDynamic (int axis_num, float limit ) ; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAnchor (const float x,const float y,const float z) ; + virtual void SetAnchorVsFirstElement (const float x,const float y,const float z) ; + virtual void SetAnchorVsSecondElement (const float x,const float y,const float z) ; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAxisDir (const float x,const float y,const float z,const int axis_num) ; + virtual void SetAxisDirVsFirstElement (const float x,const float y,const float z,const int axis_num) ; + virtual void SetAxisDirVsSecondElement (const float x,const float y,const float z,const int axis_num) ; +public: + virtual CPhysicsElement *PFirst_element () ; + virtual CPhysicsElement *PSecond_element () ; + virtual u16 BoneID () {return m_bone_id ;} + virtual void SetBoneID (u16 bone_id) {m_bone_id=bone_id ;} +IC CPHElement *PFirstElement () {return pFirst_element ;} +IC CPHElement *PSecondElement () {return pSecond_element ;} + virtual void Activate () ; + virtual void Create () ; + virtual void RunSimulation () ; + virtual void SetBackRef (CPhysicsJoint **j) ; + virtual void SetForceAndVelocity (const float force,const float velocity=0.f,const int axis_num=-1) ; + virtual void SetForce (const float force,const int axis_num=-1) ; + virtual void SetVelocity (const float velocity=0.f,const int axis_num=-1) ; + virtual void SetBreakable (float force, float torque) ; + virtual bool isBreakable () {return !!m_destroy_info;} + virtual dJointID GetDJoint () {return m_joint ;} + virtual dJointID GetDJoint1 () {return m_joint1 ;} + virtual void GetLimits (float& lo_limit,float& hi_limit,int axis_num) ; + virtual void GetAxisDir (int num,Fvector& axis,eVs& vs) ; + virtual void GetAxisDirDynamic (int num,Fvector& axis) ; + virtual void GetAnchorDynamic (Fvector& anchor) ; + virtual bool IsWheelJoint (); + virtual bool IsHingeJoint (); + virtual void GetAxisSDfactors (float& spring_factor,float& damping_factor,int axis_num) ; + virtual void GetJointSDfactors (float& spring_factor,float& damping_factor) ; + virtual void GetMaxForceAndVelocity (float &force,float &velocity,int axis_num) ; + virtual float GetAxisAngle (int axis_num) ; + virtual float GetAxisAngleRate (int axis_num) ; + virtual void Deactivate () ; + void ReattachFirstElement (CPHElement* new_element) ; + CODEGeom *&RootGeom () {return pFirstGeom ;} + virtual CPHJointDestroyInfo *JointDestroyInfo () {return m_destroy_info ;} + CPHJoint (CPhysicsJoint::enumType type ,CPhysicsElement* first,CPhysicsElement* second) ; + virtual ~CPHJoint () ; + void SetShell (CPHShell* p) ; + + void ClearDestroyInfo (); +private: + virtual iphysics_scripted &get_scripted () { return *this ;} +public: +}; + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +IC void own_axis(const Fmatrix& m,Fvector& axis){ + if(m._11==1.f) {axis.set(1.f,0.f,0.f); return;} + float k=m._13*m._21-m._11*m._23+m._23; + + if(k==0.f){ + if(m._13==0.f) {axis.set(0.f,0.f,1.f);return;} + float k1=m._13/(1.f-m._11); + axis.z=_sqrt(1.f/(1.f+k1*k1)); + axis.x=axis.z*k1; + axis.y=0.f; + return; + } + + float k_zy=-(m._12*m._21-m._11*m._22+m._11+m._22-1.f)/k; + float k_xy=(m._12+m._13*k_zy)/(1.f-m._11); + axis.y=_sqrt(1.f/(k_zy*k_zy+k_xy*k_xy+1.f)); + axis.x=axis.y*k_xy; + axis.z=axis.y*k_zy; + return; +} + + + +IC void own_axis_angle(const Fmatrix& m,Fvector& axis,float& angle){ + own_axis(m,axis); + Fvector ort1,ort2; + if(!(axis.z==0.f&&axis.y==0.f)){ + ort1.set(0.f,-axis.z,axis.y); + ort2.crossproduct(axis,ort1); + } + else{ + ort1.set(0.f,1.f,0.f); + ort2.crossproduct(axis,ort1); + } + ort1.normalize(); + ort2.normalize(); + + Fvector ort1_t; + m.transform_dir(ort1_t,ort1); + + float cosinus=ort1.dotproduct(ort1_t); + float sinus=ort2.dotproduct(ort1_t); + angle=acosf(cosinus); + if(sinus<0.f) angle= -angle; + +} + +IC void axis_angleB(const Fmatrix& m, const Fvector& axis,float& angle){ + + Fvector ort1,ort2; + if(!(fis_zero(axis.z)&&fis_zero(axis.y))){ + ort1.set(0.f,-axis.z,axis.y); + ort2.crossproduct(axis,ort1); + } + else{ + ort1.set(0.f,1.f,0.f); + ort2.crossproduct(axis,ort1); + } + ort1.normalize(); + ort2.normalize(); + Fvector ort1_t; + m.transform_dir(ort1_t,ort1); + Fvector ort_r; + float pr1,pr2; + pr1=ort1.dotproduct(ort1_t); + pr2=ort2.dotproduct(ort1_t); + if(pr1==0.f&&pr2==0.f){angle=0.f;return;} + ort_r.set(pr1*ort1.x+pr2*ort2.x, + pr1*ort1.y+pr2*ort2.y, + pr1*ort1.z+pr2*ort2.z); + + ort_r.normalize(); + float cosinus=ort1.dotproduct(ort_r); + float sinus=ort2.dotproduct(ort_r); + angle=acosf(cosinus); + if(sinus<0.f) angle= -angle; +} + + + +IC void axis_angleA(const Fmatrix& m, const Fvector& axis,float& angle){ + + Fvector ort1,ort2,axis_t; + m.transform_dir(axis_t,axis); + if(!(fis_zero(axis_t.z)&&fis_zero(axis_t.y))){ + ort1.set(0.f,-axis_t.z,axis_t.y); + ort2.crossproduct(axis_t,ort1); + } + else{ + ort1.set(0.f,1.f,0.f); + ort2.crossproduct(axis_t,ort1); + } + ort1.normalize(); + ort2.normalize(); + Fvector ort1_t; + m.transform_dir(ort1_t,ort1); + Fvector ort_r; + float pr1,pr2; + pr1=ort1.dotproduct(ort1_t); + pr2=ort2.dotproduct(ort1_t); + if(pr1==0.f&&pr2==0.f){angle=0.f;return;} + ort_r.set(pr1*ort1.x+pr2*ort2.x, + pr1*ort1.y+pr2*ort2.y, + pr1*ort1.z+pr2*ort2.z); + + ort_r.normalize(); + float cosinus=ort1.dotproduct(ort_r); + float sinus=ort2.dotproduct(ort_r); + angle=acosf(cosinus); + if(sinus<0.f) angle= -angle; + //if(angle>M_PI) angle=angle-2.f*M_PI; + //if(angle<-M_PI) angle=angle+2.f*M_PI; +} +#endif \ No newline at end of file diff --git a/xrPhysics/PHJointDestroyInfo.cpp b/xrPhysics/PHJointDestroyInfo.cpp new file mode 100644 index 00000000000..b79a189b2df --- /dev/null +++ b/xrPhysics/PHJointDestroyInfo.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "PHJointDestroyInfo.h" +#include "PhysicsCommon.h" +#include "mathutilsode.h" +#include "console_vars.h" +CPHJointDestroyInfo::CPHJointDestroyInfo(float break_force,float break_torque) +{ + //m_bone_id=bone_id; + m_sq_break_force=break_force*break_force; + m_sq_break_torque=break_torque*break_torque; + dVectorSetZero(m_joint_feedback.f1); + dVectorSetZero(m_joint_feedback.f2); + dVectorSetZero(m_joint_feedback.t1); + dVectorSetZero(m_joint_feedback.t2); + m_breaked=false; +} + +bool CPHJointDestroyInfo::Update() +{ + dReal sq_breack_force=m_sq_break_force/ph_console::phBreakCommonFactor; + if(dDOT(m_joint_feedback.f1,m_joint_feedback.f1)>sq_breack_force) + { + m_breaked=true; + return true; + } + if(dDOT(m_joint_feedback.f2,m_joint_feedback.f2)>sq_breack_force) + { + m_breaked=true; + return true; + } + if(dDOT(m_joint_feedback.t1,m_joint_feedback.t1)>sq_breack_force) + { + m_breaked=true; + return true; + } + if(dDOT(m_joint_feedback.t2,m_joint_feedback.t2)>sq_breack_force) + { + m_breaked=true; + return true; + } + return false; +} \ No newline at end of file diff --git a/xrPhysics/PHJointDestroyInfo.h b/xrPhysics/PHJointDestroyInfo.h new file mode 100644 index 00000000000..3537d41a139 --- /dev/null +++ b/xrPhysics/PHJointDestroyInfo.h @@ -0,0 +1,25 @@ +#ifndef PHJOINT_DESTROY_INFO_H +#define PHJOINT_DESTROY_INFO_H + +//#include "ode_include.h" +#include "../3rd party/ode/include/ode/common.h" +class CPHJointDestroyInfo +{ +friend class CPHShellSplitterHolder; +friend class CPHShell; +dJointFeedback m_joint_feedback; +float m_sq_break_force; +float m_sq_break_torque; +u16 m_end_element; +u16 m_end_joint; +bool m_breaked; +public: + CPHJointDestroyInfo (float break_force,float break_torque); +IC dJointFeedback* JointFeedback (){return &m_joint_feedback;} + +IC bool Breaked (){return m_breaked;}; + bool Update (); +}; + + +#endif PHJOINT_DESTROY_INFO_H \ No newline at end of file diff --git a/xrPhysics/PHMoveStorage.cpp b/xrPhysics/PHMoveStorage.cpp new file mode 100644 index 00000000000..c0c15f67730 --- /dev/null +++ b/xrPhysics/PHMoveStorage.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "phmovestorage.h" +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/ode/src/collision_kernel.h" +#pragma warning(default:4995) +#pragma warning(default:4267) +struct dxGeomTransform : public dxGeom { + dxGeom *obj; // object that is being transformed + int cleanup; // 1 to destroy obj when destroyed + int infomode; // 1 to put Tx geom in dContactGeom g1 + + // cached final object transform (body tx + relative tx). this is set by + // computeAABB(), and it is valid while the AABB is valid. + dVector3 final_pos; + dMatrix3 final_R; + dxGeomTransform::dxGeomTransform (dSpaceID space) : dxGeom (space,1) + { + type = dGeomTransformClass; + obj = 0; + cleanup = 0; + infomode = 0; + dSetZero (final_pos,4); + dRSetIdentity (final_R); + } +}; +void CPHPositionsPairs::Positions(const Fvector* &p0,const Fvector* &p1) +{ + CODEGeom *g=*geom; + if(g->is_transformed_bt()) + { + g->geometry_transform()->recomputeAABB(); + p0=(const Fvector*)dGeomGetUserData(g->geom())->last_pos; + p1=(const Fvector*)((dxGeomTransform*)g->geometry_transform())->final_pos; + } + else + { + p1=(const Fvector*)dGeomGetPosition(g->geometry_transform()); + p0=(const Fvector*)dGeomGetUserData(g->geometry_transform())->last_pos; + } + +} \ No newline at end of file diff --git a/xrPhysics/PHMoveStorage.h b/xrPhysics/PHMoveStorage.h new file mode 100644 index 00000000000..169199f5286 --- /dev/null +++ b/xrPhysics/PHMoveStorage.h @@ -0,0 +1,55 @@ +#ifndef PHMOVESTORAGE_H +#define PHMOVESTORAGE_H +#include "phgeometryowner.h" +//DEFINE_VECTOR(dReal *&,POSITIONS_STORAGE,POSITIONS_I); + +class CPHPositionsPairs +{ + GEOM_I geom; +public: + CPHPositionsPairs(GEOM_I i) + { + geom=i; + } + void Positions(const Fvector *&p0,const Fvector *&p1); + IC CPHPositionsPairs& operator ++ () + { + ++geom; + return *this; + } + IC dGeomID dGeom() + { + return (*geom)->geometry_transform(); + } + IC CPHPositionsPairs& operator ++ (int) + { + geom++; + return *this; + } + IC CPHPositionsPairs& operator = (const CPHPositionsPairs& right) + { + geom=right.geom; + } + IC bool operator == (const CPHPositionsPairs& right ) const + { + return geom==right.geom; + } + IC bool operator != (const CPHPositionsPairs& right ) const + { + return geom!=right.geom; + } +}; + +class CPHMoveStorage +{ + GEOM_STORAGE m_trace_geometries; +public: + typedef CPHPositionsPairs iterator; + IC iterator begin () {return CPHPositionsPairs(m_trace_geometries.begin());} + IC iterator end () {return CPHPositionsPairs(m_trace_geometries.end());} + IC bool empty ()const {return m_trace_geometries.empty();} + void add (CODEGeom* g) {m_trace_geometries.push_back(g);} + void clear () {m_trace_geometries.clear();} +}; + +#endif \ No newline at end of file diff --git a/xrPhysics/PHObject.cpp b/xrPhysics/PHObject.cpp new file mode 100644 index 00000000000..d0a67426384 --- /dev/null +++ b/xrPhysics/PHObject.cpp @@ -0,0 +1,259 @@ +#include "stdafx.h" +#include "Physics.h" +#include "PHObject.h" +#include "PHWorld.h" +#include "PHMoveStorage.h" +#include "dRayMotions.h" +#include "PHCollideValidator.h" +#include "console_vars.h" +#ifdef DEBUG +#include "debug_output.h" +#endif +extern CPHWorld* ph_world; + +CPHObject::CPHObject () : ISpatial(g_SpatialSpacePhysic) +{ + m_flags.flags = 0; + spatial.type |= STYPE_PHYSIC; + m_island.Init (); + m_check_count =0; + CPHCollideValidator::InitObject (*this); +} + +void CPHObject::activate() +{ + R_ASSERT2(dSpacedGeom(),"trying to activate destroyed or not created object!"); + if(m_flags.test(st_activated))return; + if(m_flags.test(st_freezed)) {UnFreeze();return;} + if(m_flags.test(st_recently_deactivated))remove_from_recently_deactivated(); + ph_world->AddObject(this); + vis_update_activate(); + m_flags.set(st_activated,TRUE); +} + +void CPHObject::EnableObject(CPHObject* obj) +{ + activate(); +} + +void CPHObject::deactivate() +{ + if(!m_flags.test(st_activated))return; + VERIFY2(m_island.IsActive(),"can not do it during processing"); + ph_world->RemoveObject(PH_OBJECT_I(this)); + vis_update_deactivate(); + m_flags.set(st_activated,FALSE); +} + +void CPHObject::put_in_recently_deactivated() +{ + VERIFY(!m_flags.test(st_activated)&&!m_flags.test(st_freezed)); + if(m_flags.test(st_recently_deactivated))return; + m_check_count=u8(ph_console::ph_tri_clear_disable_count); + m_flags.set(st_recently_deactivated,TRUE); + ph_world->AddRecentlyDisabled(this); +} +void CPHObject::remove_from_recently_deactivated() +{ + if(!m_flags.test(st_recently_deactivated))return; + m_check_count=0; + m_flags.set(st_recently_deactivated,FALSE); + ph_world->RemoveFromRecentlyDisabled(PH_OBJECT_I(this)); +} +void CPHObject::check_recently_deactivated() +{ + if(m_check_count==0){ + ClearRecentlyDeactivated(); + remove_from_recently_deactivated(); + } + else m_check_count--; +} +void CPHObject::spatial_move() +{ + get_spatial_params(); + ISpatial::spatial_move(); + m_flags.set(st_dirty,TRUE); +} + +void CPHObject::Collide() +{ + if(m_flags.test(fl_ray_motions)) + { + CPHMoveStorage* tracers=MoveStorage(); + CPHMoveStorage::iterator I=tracers->begin(),E=tracers->end(); + for(;E!=I;I++) + { + const Fvector *from=0, *to=0; + Fvector dir; + I.Positions(from,to); + if(from->x==-dInfinity) continue; + dir.sub(*to,*from); + float magnitude=dir.magnitude(); + if(magnitudeq_ray(ph_world->r_spatial,0,STYPE_PHYSIC,*from,dir,magnitude);//|ISpatial_DB::O_ONLYFIRST +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawRayMotions)) + { + debug_output().DBG_OpenCashedDraw(); + debug_output().DBG_DrawLine(*from,Fvector().add(*from,Fvector().mul(dir,magnitude)),D3DCOLOR_XRGB(0,255,0)); + debug_output().DBG_ClosedCashedDraw(30000); + } + +#endif + qResultVec& result=ph_world->r_spatial; + qResultIt i=result.begin(),e=result.end(); + for(;i!=e;++i) { + CPHObject* obj2=static_cast(*i); + if(obj2==this || !obj2->m_flags.test(st_dirty)) continue; + dGeomID motion_ray=ph_world->GetMotionRayGeom(); + dGeomRayMotionSetGeom(motion_ray,I.dGeom()); + dGeomRayMotionsSet(motion_ray,(const dReal*) from,(const dReal*)&dir,magnitude); + NearCallback(this,obj2,motion_ray,obj2->dSpacedGeom()); + } + } + } + CollideDynamics (); +/////////////////////////////// + if(CPHCollideValidator::DoCollideStatic(*this)) CollideStatic(dSpacedGeom(),this); + m_flags.set(st_dirty,FALSE); +} +void CPHObject:: CollideDynamics () +{ + g_SpatialSpacePhysic->q_box (ph_world->r_spatial,0,STYPE_PHYSIC,spatial.sphere.P,AABB); + qResultVec& result=ph_world->r_spatial ; + qResultIt i=result.begin(),e=result.end(); + for(;i!=e;++i) { + CPHObject* obj2=static_cast(*i); + if(obj2==this || !obj2->m_flags.test(st_dirty)) continue; + if(CPHCollideValidator::DoCollide(*this,*obj2)) NearCallback(this,obj2,dSpacedGeom(),obj2->dSpacedGeom()); + } +} +void CPHObject::reinit_single() +{ + IslandReinit (); + qResultVec& result=ph_world->r_spatial ; + qResultIt i=result.begin(),e=result.end(); + for(;i!=e;++i) + { + CPHObject* obj=static_cast(*i); + obj->IslandReinit(); + } + result.clear_not_free(); + dJointGroupEmpty(ContactGroup); + ContactFeedBacks.empty(); + ContactEffectors.empty(); +} + +void CPHObject:: step_prediction (float time) +{ + //general idea: + //perform normal step by time as local as possible for this object then return world to + //the pervious state + +} +bool CPHObject::step_single(dReal step) +{ + + CollideDynamics (); + bool ret=!m_island.IsObjGroun (); + if(ret) + { + //PhTune (step); + IslandStep (step); + reinit_single (); + //PhDataUpdate (step); + spatial_move (); + CollideDynamics (); + ret =!m_island.IsObjGroun (); + } + reinit_single (); + return ret ; +} + +void CPHObject:: step( float time ) //it is still not a true step for object because it collide the object only not subsequent collision is doing +{ + ph_world->r_spatial.clear_not_free (); + reinit_single (); + Collide (); + IslandStep ( time ); + reinit_single (); +} + +bool CPHObject:: DoCollideObj () +{ + CollideDynamics (); + bool ret=m_island.IsObjGroun (); + reinit_single(); + return ret; +} + +void CPHObject::FreezeContent() +{ + R_ASSERT(!m_flags.test(st_freezed)); + m_flags.set(st_freezed,TRUE); + m_flags.set(st_activated,FALSE); + vis_update_deactivate(); +} +void CPHObject::UnFreezeContent() +{ + R_ASSERT(m_flags.test(st_freezed)); + m_flags.set(st_freezed,FALSE); + m_flags.set(st_activated,TRUE); + vis_update_activate(); +} + +void CPHObject::spatial_register() +{ + get_spatial_params(); + ISpatial::spatial_register(); + m_flags.set(st_dirty,TRUE); +} + +void CPHObject::collision_disable() +{ + ISpatial::spatial_unregister(); +} +void CPHObject::collision_enable() +{ + ISpatial::spatial_register(); +} + +void CPHObject::Freeze() +{ + if(!m_flags.test(st_activated))return; + ph_world->RemoveObject(this); + ph_world->AddFreezedObject(this); + FreezeContent(); +} + +void CPHObject::UnFreeze() +{ + if(!m_flags.test(st_freezed)) return; + UnFreezeContent(); + ph_world->RemoveFreezedObject(this); + ph_world->AddObject(this); +} + + + +CPHUpdateObject::CPHUpdateObject() +{ + b_activated=false; +} + +void CPHUpdateObject::Activate() +{ + if(b_activated)return; + ph_world->AddUpdateObject(this); + b_activated=true; +} + +void CPHUpdateObject::Deactivate() +{ + if(!b_activated)return; + ph_world->RemoveUpdateObject(this); + b_activated=false; +} + + diff --git a/xrPhysics/PHObject.h b/xrPhysics/PHObject.h new file mode 100644 index 00000000000..276b78cc8dc --- /dev/null +++ b/xrPhysics/PHObject.h @@ -0,0 +1,136 @@ +#pragma once +#ifndef CPHOBJECT +#define CPHOBJECT +#include "../xrcdb/ispatial.h" +#include "PHItemList.h" +#include "PHIsland.h" +typedef u32 CLClassBits; +typedef u32 CLBits; +class ISpatial; +DEFINE_VECTOR(ISpatial*,qResultVec,qResultIt) +class CPHObject; +class CPHUpdateObject; +class CPHMoveStorage; +class CPHSynchronize; + +typedef void CollideCallback(CPHObject* obj1,CPHObject* obj2, dGeomID o1, dGeomID o2); +#ifdef DEBUG +class IPhysicsShellHolder; +#endif +class CPHObject : + public ISpatial +{ +#ifdef DEBUG + friend struct SPHObjDBGDraw; +#endif + DECLARE_PHLIST_ITEM(CPHObject) + + Flags8 m_flags; + + enum{ + st_activated =(1<<0), + st_freezed =(1<<1), + st_dirty =(1<<2), + st_net_interpolation =(1<<3), + fl_ray_motions =(1<<4), + st_recently_deactivated =(1<<5) + }; + + CPHIsland m_island; + CLBits m_collide_bits; + u8 m_check_count; + _flags m_collide_class_bits; + +public: + enum ECastType + { + tpNotDefinite, + tpShell, + tpCharacter, + tpStaticShell + }; +protected: + Fvector AABB; +protected: + + virtual dGeomID dSpacedGeom () =0; + virtual void get_spatial_params () =0; + virtual void spatial_register () ; + void SetRayMotions () {m_flags.set(fl_ray_motions,TRUE);} + void UnsetRayMotions () {m_flags.set(fl_ray_motions,FALSE);} + + void SetPrefereExactIntegration () {m_island.SetPrefereExactIntegration();} + + + + CPHObject* SelfPointer () {return this;} +public: + IC BOOL IsRayMotion () {return m_flags.test(fl_ray_motions);} + void IslandReinit () {m_island.Unmerge();} + void IslandStep (dReal step) {m_island.Step(step);} + void MergeIsland (CPHObject* obj) {m_island.Merge(&obj->m_island);} + CPHIsland& Island () {return m_island;} + dWorldID DActiveWorld () {return m_island.DActiveWorld();} + CPHIsland* DActiveIsland () {return m_island.DActiveIsland();} + dWorldID DWorld () {return m_island.DWorld();} + + virtual void FreezeContent () ; + virtual void UnFreezeContent () ; + virtual void EnableObject (CPHObject* obj) ; + virtual bool DoCollideObj () ; + virtual bool step_single (dReal step) ; + void reinit_single () ; + void step_prediction (float time) ; + void step (float time) ; + virtual void PhDataUpdate (dReal step) =0; + virtual void PhTune (dReal step) =0; + virtual void spatial_move () ; + virtual void InitContact (dContact* c,bool& do_collide,u16 /*material_idx_1*/,u16 /*material_idx_2*/) =0; + virtual void CutVelocity (float l_limit,float a_limit) {}; + + void Freeze () ; + void UnFreeze () ; + IC bool IsFreezed () {return !!(m_flags.test(st_freezed));} + void NetInterpolationON () {m_flags.set(st_net_interpolation,TRUE);} + void NetInterpolationOFF () {m_flags.set(st_net_interpolation,TRUE);} + bool NetInterpolation () {return !!(m_flags.test(st_net_interpolation));} + virtual u16 get_elements_number () = 0; + virtual CPHSynchronize *get_element_sync (u16 element) = 0; + //virtual void StepFrameUpdate(dReal step)=0; + + + CPHObject () ; + void activate () ; + IC bool is_active () const {return !!m_flags.test(st_activated)/*b_activated*/;} + void deactivate () ; + void put_in_recently_deactivated () ; + void remove_from_recently_deactivated() ; + void check_recently_deactivated () ; + void collision_disable () ; + void collision_enable () ; +virtual void ClearRecentlyDeactivated () {;} +virtual void Collide () ; +virtual void near_callback (CPHObject* obj) {;} +virtual void RMotionsQuery (qResultVec &res) {;} +virtual CPHMoveStorage* MoveStorage () {return NULL;} +virtual ECastType CastType (){return tpNotDefinite;} +virtual void vis_update_activate () {} +virtual void vis_update_deactivate () {} + +#ifdef DEBUG +virtual IPhysicsShellHolder *ref_object () =0; +#endif + +IC CLBits& collide_bits () {return m_collide_bits;} +IC _flags& collide_class_bits () {return m_collide_class_bits;} +IC const CLBits& collide_bits ()const {return m_collide_bits;} +IC const _flags& collide_class_bits ()const {return m_collide_class_bits;} + void CollideDynamics () ; +}; + + + + +DEFINE_PHITEM_LIST(CPHObject,PH_OBJECT_STORAGE,PH_OBJECT_I) + +#endif//CPHOBJECT \ No newline at end of file diff --git a/xrPhysics/PHShell.cpp b/xrPhysics/PHShell.cpp new file mode 100644 index 00000000000..1cedcfa0091 --- /dev/null +++ b/xrPhysics/PHShell.cpp @@ -0,0 +1,1751 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +#include "StdAfx.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PHShellSplitter.h" +#include "PHFracture.h" +#include "PHJointDestroyInfo.h" +#include "SpaceUtils.h" +#include "MathUtils.h" +#include "iPhysicsShellHolder.h" +#include "../Include/xrRender/Kinematics.h" +#include "PHCollideValidator.h" +#include "../xrengine/bone.h" +//#include "game_object_space.h" +//#pragma warning(disable:4995) +//#pragma warning(disable:4267) +//#include "../3rd party/ode/ode/src/collision_kernel.h" +//#pragma warning(default:4995) +//#pragma warning(default:4267) +/////////////////////////////////////////////////////////////// +///#pragma warning(disable:4995) + +//#include "../3rd party/ode/ode/src/joint.h" +//#include "../3rd party/ode/ode/src/objects.h" + +//#pragma warning(default:4995) +/////////////////////////////////////////////////////////////////// + +#include "ExtendedGeom.h" +#include "PHElement.h" +#include "PHShell.h" +#include "PHCollideValidator.h" +#include "PHElementInline.h" +#include "PhysicsShellAnimator.h" +#include "phshellbuildjoint.h" +#include +#ifdef DEBUG +#include "debug_output.h" +#endif +IC bool PhOutOfBoundaries (const Fvector& v) +{ + return v.y < phBoundaries.y1; +} +CPHShell::~CPHShell () +{ + + m_pKinematics = 0; + VERIFY(!isActive()); + + xr_vector::iterator i; + for(i=elements.begin();elements.end()!=i;++i) + xr_delete(*i); + elements.clear(); + + xr_vector::iterator j; + for(j=joints.begin();joints.end()!=j;++j) + xr_delete(*j); + joints.clear(); + if(m_spliter_holder)xr_delete(m_spliter_holder); + +} +CPHShell::CPHShell() +{ + //bActive=false; + //bActivating=false; + m_flags.assign(0); + m_flags.set(flActivating,FALSE); + m_flags.set(flActive,FALSE); + m_space=NULL; + m_pKinematics=NULL; + m_spliter_holder=NULL; + m_object_in_root.identity(); + m_active_count=0; + m_pPhysicsShellAnimatorC=NULL; +} + +void CPHShell::EnableObject(CPHObject* obj) +{ + CPHObject::activate(); + if(m_spliter_holder)m_spliter_holder->Activate(); +} +void CPHShell::DisableObject() +{ + + IPhysicsShellHolder* ref_object=(*elements.begin())->PhysicsRefObject(); +//. if (!ref_object) return; + + if (ref_object) + ref_object->on_physics_disable (); + + //InterpolateGlobalTransform(&mXFORM); + CPHObject::deactivate(); + if(m_spliter_holder)m_spliter_holder->Deactivate(); + if(m_flags.test(flRemoveCharacterCollisionAfterDisable)) + DisableCharacterCollision (); +} +void CPHShell:: DisableCharacterCollision () +{ + CPHCollideValidator::SetCharacterClassNotCollide(*this); +} +void CPHShell::Disable() +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + DisableObject(); + for( ;i!=e;++i) + { + (*i)->Disable(); + } + ClearCashedTries(); +} +void CPHShell::DisableCollision() +{ + CPHObject::collision_disable(); +} +void CPHShell::EnableCollision() +{ + CPHObject::collision_enable(); +} +void CPHShell::ReanableObject() +{ + //if(b_contacts_saved) dJointGroupEmpty(m_saved_contacts); + //b_contacts_saved=false; + +} + +void CPHShell::vis_update_activate() +{ + ++m_active_count; + IPhysicsShellHolder* ref_object=(*elements.begin())->PhysicsRefObject(); + if(ref_object&&m_active_count>0) + { + m_active_count=0; + ref_object->ObjectProcessingActivate(); + } +} + +void CPHShell::vis_update_deactivate() +{ + --m_active_count; + //IPhysicsShellHolder* ref_object=(*elements.begin())->PhysicsRefObject(); + //if(ref_object&&!m_flags.test(flProcessigDeactivated)) + //{ + // //ref_object->processing_deactivate(); + // m_flags.set(flProcessigDeactivate,TRUE); + //} +} +void CPHShell::setDensity(float M) +{ + ELEMENT_I i; + //float volume=0.f; + //for(i=elements.begin();elements.end() != i;++i) volume+=(*i)->get_volume(); + + for(i=elements.begin();elements.end() != i;++i) + (*i)->setDensity(M); +} + + +void CPHShell::setMass(float M){ + ELEMENT_I i; + float volume=0.f; + for(i=elements.begin();elements.end() != i;++i) volume+=(*i)->get_volume(); + + for(i=elements.begin();elements.end() != i;++i) + (*i)->setMass( + (*i)->get_volume()/volume*M + ); +} + +void CPHShell::setMass1(float M){ + ELEMENT_I i; + + + for(i=elements.begin();elements.end() != i;++i) + (*i)->setMass( + M/elements.size() + ); +} + + +void CPHShell:: MassAddBox ( float mass, const Fvector &full_size ) +{ + dMass m; + dMassSetBox( &m, mass, full_size.x,full_size.y,full_size.z); // mass = m_Shell->getMass()/100.f, full_size (1,1,1) + addEquelInertiaToEls(m); +} + + +float CPHShell::getMass() +{ + float m=0.f; + + ELEMENT_I i; + + for(i=elements.begin();elements.end() != i;++i) m+=(*i)->getMass(); + + return m; +} + +void CPHShell::get_spatial_params() +{ + spatialParsFromDGeom((dGeomID)m_space,spatial.sphere.P,AABB,spatial.sphere.R); +} + +float CPHShell::getVolume() +{ + float v=0.f; + + ELEMENT_I i; + + for(i=elements.begin();elements.end() != i;++i) v+=(*i)->getVolume(); + + return v; +} + +float CPHShell::getDensity() +{ + return getMass()/getVolume(); +} + + + + +void CPHShell::PhDataUpdate(dReal step){ + + ELEMENT_I i=elements.begin(),e=elements.end(); + bool disable=true; + for(; e!=i ;++i) + { + (*i)->PhDataUpdate(step); + dBodyID body=(*i)->get_body(); + if(body&&disable&&dBodyIsEnabled(body)) + disable=false; + } + if(disable) + { + DisableObject(); + CPHObject::put_in_recently_deactivated(); + } + else + ReanableObject(); +#if 0 + DBG_OpenCashedDraw(); + dbg_draw_velocity ( 0.1f, D3DCOLOR_XRGB( 255, 0, 0 ) ); + dbg_draw_force ( 0.1f, D3DCOLOR_XRGB( 0, 0, 255 ) ); + DBG_ClosedCashedDraw( 10000 ); + //dbg_draw_geometry +#endif + if(PhOutOfBoundaries(cast_fv(dBodyGetPosition((*elements.begin())->get_body())))) + Disable(); + +} + + + +void CPHShell::PhTune(dReal step){ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(; e!=i ;++i) + (*i)->PhTune(step); +} + +void CPHShell::Update(){ + if(!isActive()) return; + if(m_flags.test(flActivating)) m_flags.set(flActivating,FALSE); + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->Update(); + + mXFORM.set((*elements.begin())->mXFORM); + VERIFY2(_valid(mXFORM),"invalid position in update"); +} + +void CPHShell::Freeze() +{ + CPHObject::Freeze(); +} +void CPHShell::UnFreeze() +{ + CPHObject::UnFreeze(); +} +void CPHShell::FreezeContent() +{ + + CPHObject::FreezeContent(); + ELEMENT_I i=elements.begin(),e=elements.end(); + for(; e!=i ;++i) + (*i)->Freeze(); + +} +void CPHShell::UnFreezeContent() +{ + CPHObject::UnFreezeContent(); + ELEMENT_I i=elements.begin(),e=elements.end(); + for(; e!=i ;++i) + (*i)->UnFreeze(); + +} +void CPHShell:: applyForce (const Fvector& dir, float val) +{ + if(!isActive()) return; + ELEMENT_I i=elements.begin(),e=elements.end(); + val/=getMass(); + for(; e!=i ;++i) + (*i)->applyForce( dir, val*(*i)->getMass()); + EnableObject(0); +}; +void CPHShell:: applyForce (float x,float y,float z) +{ +Fvector dir;dir.set(x,y,z); +float val=dir.magnitude(); + if(!fis_zero(val)) + { + dir.mul(1.f/val); + applyForce(dir,val); + } +}; +void CPHShell:: applyImpulse (const Fvector& dir, float val) +{ + if(!isActive()) return; + (*elements.begin())->applyImpulse ( dir, val); + EnableObject(0); +}; +void CPHShell:: applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val){ + if(!isActive()) return; + (*elements.begin())->applyImpulseTrace ( pos, dir, val, 0); + EnableObject(0); +} + +void CPHShell:: applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val,const u16 id){ + if(!isActive()) return; + VERIFY(m_pKinematics); + CBoneInstance& instance=m_pKinematics->LL_GetBoneInstance (id); + if(instance.callback_type()!=bctPhysics || !instance.callback_param()) return; + + ((CPhysicsElement*)instance.callback_param())->applyImpulseTrace ( pos, dir, val, id); + EnableObject(0); +} + +CPhysicsElement* CPHShell::get_Element (const shared_str & bone_name) +{ + VERIFY(m_pKinematics); + return get_Element(m_pKinematics->LL_BoneID(bone_name)); +} +CPhysicsElement* CPHShell::get_Element (LPCSTR bone_name) +{ + return get_Element((const shared_str&)(bone_name)); +} +CPhysicsElement* CPHShell::get_ElementByStoreOrder(u16 num) +{ + R_ASSERT2(num(elements[element]); +} + +CPhysicsElement* CPHShell::get_PhysicsParrentElement( u16 bone_id ) +{ + VERIFY( PKinematics() ); + CPhysicsElement* E = get_Element( bone_id ); + u16 bid = bone_id; + while( !E && bid != PKinematics()->LL_GetBoneRoot() ) + { + CBoneData &bd = PKinematics()->LL_GetData( bid ); + bid = bd.GetParentID(); + E = get_Element( bid ); + } + return E; +} + +CPhysicsElement* CPHShell::get_Element( u16 bone_id ) +{ + if(m_pKinematics&& isActive()) + { + CBoneInstance& instance=m_pKinematics->LL_GetBoneInstance (bone_id); + if(instance.callback()==BonesCallback||instance.callback()==StataticRootBonesCallBack) + { + return (instance.callback_type()==bctPhysics)?(CPhysicsElement*)instance.callback_param():NULL; + } + } + + ELEMENT_I i=elements.begin(),e=elements.end(); + for(; e!=i ;++i) + if((*i)->m_SelfID==bone_id) + return (CPhysicsElement*)(*i); + return NULL; +} + +CPhysicsJoint* CPHShell::get_Joint(u16 bone_id) +{ + JOINT_I i= joints.begin(),e=joints.end(); + for(;e!=i;i++) + if((*i)->BoneID()==bone_id) + return (CPhysicsJoint*)(*i); + return NULL; +} +CPhysicsJoint* CPHShell::get_Joint(const shared_str &bone_name) +{ + VERIFY(m_pKinematics); + return get_Joint(m_pKinematics->LL_BoneID(bone_name)); +} + +CPhysicsJoint* CPHShell::get_Joint(LPCSTR bone_name) +{ + return get_Joint((const shared_str&)bone_name); +} + +CPhysicsJoint* CPHShell::get_JointByStoreOrder (u16 num) +{ + R_ASSERT( num < joints.size() ); + return (CPhysicsJoint*) joints[num]; +} + +u16 CPHShell::get_JointsNumber () +{ + return u16(joints.size()); +} + +void CPHShell:: update_root_transforms () +{ + u16 anim_root = PKinematics()->LL_GetBoneRoot(); + u16 phys_root = root_element().m_SelfID; + VERIFY( BI_NONE != anim_root ); + VERIFY( BI_NONE != phys_root ); + + if( anim_root == phys_root ) + { + mXFORM.set( root_element().mXFORM ); + return; + } + + + //Fmatrix anim_root_transform = PKinematics()->LL_GetBindTransform( anim_root ); + + +} + +void CPHShell:: BonesCallback ( CBoneInstance* B ){ + ///CPHElement* E = smart_cast (static_cast(B->Callback_Param)); + + CPHElement* E = cast_PHElement( B->callback_param() ); + //if( E == &root_element() ) + //{ + + //} + E->BonesCallBack(B); + VERIFY2( _valid(B->mTransform), "CPHShell:: BonesCallback" ); +} + + +void CPHShell::StataticRootBonesCallBack (CBoneInstance* B){ + ///CPHElement* E = smart_cast (static_cast(B->Callback_Param)); + + CPHElement* E = cast_PHElement(B->callback_param()); + E->StataticRootBonesCallBack(B); +} + + +void CPHShell::SetTransform (const Fmatrix& m0, motion_history_state history_state ){ + + mXFORM.set(m0); + ELEMENT_I i=elements.begin(); + for( ;elements.end() != i; ++i) + { + (*i)->SetTransform(m0, history_state ); + } + spatial_move(); +} + + +void CPHShell::Enable() +{ + if(!isActive()) + return; + + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + //if(dBodyIsEnabled((*i)->get_body())) return; + for( ;i!=e;++i) + (*i)->Enable(); + EnableObject(0); +} + +void CPHShell::set_PhysicsRefObject (IPhysicsShellHolder* ref_object) +{ + + + if(elements.empty()) return; + if((*elements.begin())->PhysicsRefObject()==ref_object) return; + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + { + (*i)->set_PhysicsRefObject(ref_object); + } + + + +} + + + +void CPHShell::set_ContactCallback(ContactCallbackFun* callback) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->set_ContactCallback(callback); +} + + +void CPHShell::set_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->set_ObjectContactCallback(callback); +} +void CPHShell::add_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->add_ObjectContactCallback(callback); +} +void CPHShell::remove_ObjectContactCallback(ObjectContactCallbackFun* callback) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->remove_ObjectContactCallback(callback); +} +void CPHShell::set_CallbackData(void *cd) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->set_CallbackData(cd); +} +void CPHShell::SetPhObjectInElements() +{ + if(!isActive()) return; + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i ) + (*i)->SetPhObjectInGeomData((CPHObject*)this); +} + +void CPHShell::SetMaterial(LPCSTR m) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + { + (*i)->SetMaterial(m); + } +} + +void CPHShell::SetMaterial(u16 m) +{ + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + { + (*i)->SetMaterial(m); + } +} + +void CPHShell::get_LinearVel(Fvector& velocity) const +{ + + (*elements.begin())->get_LinearVel(velocity); +} + +void CPHShell::get_AngularVel(Fvector& velocity) const +{ + + (*elements.begin())->get_AngularVel(velocity); +} + +void CPHShell::set_LinearVel(const Fvector& velocity) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;i++) (*i)->set_LinearVel(velocity); +} + +void CPHShell::set_AngularVel(const Fvector& velocity) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;i++) (*i)->set_AngularVel(velocity); +} + + +void CPHShell::TransformPosition(const Fmatrix &form, motion_history_state history_state ) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;i++) (*i)->TransformPosition(form, history_state); +} + +void CPHShell::SetGlTransformDynamic(const Fmatrix &form) +{ + VERIFY(isActive()); + VERIFY(_valid(form)); + Fmatrix current,replace; + GetGlobalTransformDynamic(¤t); + current.invert(); + replace.mul(form,current); + TransformPosition(replace, mh_clear ); +} +void CPHShell::SmoothElementsInertia(float k) +{ + dMass m_avrg; + dReal krc=1.f-k; + dMassSetZero(&m_avrg); + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + { + + dMassAdd(&m_avrg,(*i)->getMassTensor()); + + } + int n = (int)elements.size(); + m_avrg.mass*=k/float(n); + for(int j=0;j<4*3;++j) m_avrg.I[j]*=k/float(n); + + for(i=elements.begin();elements.end() != i;++i) + { + dVector3 tmp; + dMass* m=(*i)->getMassTensor(); + dVectorSet(tmp,m->c); + + m->mass*=krc; + for(int j=0;j<4*3;++j) m->I[j]*=krc; + dMassAdd(m,&m_avrg); + + dVectorSet(m->c,tmp); + } +} + +void CPHShell::setEquelInertiaForEls(const dMass& M) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i) + { + (*i)->setInertia(M); + } +} + +void CPHShell::addEquelInertiaToEls(const dMass& M) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i) + { + (*i)->addInertia(M); + } +} +static BONE_P_MAP* spGetingMap=NULL; +void CPHShell::build_FromKinematics(IKinematics* K,BONE_P_MAP* p_geting_map) +{ + VERIFY( K ); + phys_shell_verify_model ( *K ); + m_pKinematics =K; + spGetingMap =p_geting_map; + //CBoneData& bone_data = m_pKinematics->LL_GetData(0); + if(!m_spliter_holder) m_spliter_holder=xr_new(this); + bool vis_check = false; + AddElementRecursive(0,m_pKinematics->LL_GetBoneRoot(),Fidentity,0,&vis_check); + //R_ASSERT2((*elements.begin())->numberOfGeoms(),"No physics shapes was assigned for model or no shapes in main root bone!!!"); + //SetCallbacks(BonesCallback); + if(m_spliter_holder->isEmpty())ClearBreakInfo(); +} + +void CPHShell::preBuild_FromKinematics(IKinematics* K,BONE_P_MAP* p_geting_map) +{ + VERIFY( K ); + phys_shell_verify_model ( *K ); + m_pKinematics =K; + spGetingMap =p_geting_map; + //CBoneData& bone_data = m_pKinematics->LL_GetData(0); + if(!m_spliter_holder) m_spliter_holder=xr_new(this); + bool vis_check=false; + AddElementRecursive(0,m_pKinematics->LL_GetBoneRoot(),Fidentity,0,&vis_check); + //R_ASSERT2((*elements.begin())->numberOfGeoms(),"No physics shapes was assigned for model or no shapes in main root bone!!!"); + if(m_spliter_holder->isEmpty())ClearBreakInfo(); + m_pKinematics=0; +} +void CPHShell::ClearBreakInfo() +{ + { + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i)(*i)->ClearDestroyInfo(); + } + + { + JOINT_I i=joints.begin(),e=joints.end(); + for(;i!=e;++i) (*i)->ClearDestroyInfo(); + } + xr_delete(m_spliter_holder); +} + + +ICF bool no_physics_shape(const SBoneShape& shape) +{ + return shape.type==SBoneShape::stNone||shape.flags.test(SBoneShape::sfNoPhysics); +} + +bool shape_is_physic( const SBoneShape& shape ) +{ + return !no_physics_shape( shape ); +} + +void CPHShell::AddElementRecursive(CPhysicsElement* root_e, u16 id,Fmatrix global_parent,u16 element_number,bool* vis_check) +{ + + //CBoneInstance& B = m_pKinematics->LL_GetBoneInstance(u16(id)); +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + const IBoneData& bone_data= m_pKinematics->GetBoneData(u16(id)); + const SJointIKData& joint_data=bone_data.get_IK_data(); + Fmatrix fm_position; + fm_position.set (bone_data.get_bind_transform()); + fm_position.mulA_43 (global_parent); + Flags64 mask; + mask.assign(m_pKinematics->LL_GetBonesVisible()); + bool no_visible=!mask.is(1ui64<<(u64)id); + bool lvis_check=false; + if(no_visible) + { + + //for (vecBonesIt it=bone_data.children.begin(); bone_data.children.end() != it; ++it) + //AddElementRecursive (root_e,(*it)->GetSelfID(),fm_position,element_number,&lvis_check); + //IBoneData &ibone_data = bone_data; + u16 num_children =bone_data.GetNumChildren(); + for(u16 i = 0;imXFORM); + vs_root_position.invert(); + vs_root_position.mulB_43(fm_position); + + E=root_e; + if(breakable) + { + CPHFracture fracture; + fracture.m_bone_id =id; + R_ASSERT2(id<64,"ower 64 bones in breacable are not supported"); + fracture.m_start_geom_num =E->numberOfGeoms(); + fracture.m_end_geom_num =u16(-1); + fracture.m_start_el_num =u16(elements.size()); + fracture.m_start_jt_num =u16(joints.size()); + fracture.MassSetFirst (*(E->getMassTensor())); + fracture.m_pos_in_element .set(vs_root_position.c); + VERIFY (u16(-1)!=fracture.m_start_geom_num); + fracture.m_break_force =joint_data.break_force; + fracture.m_break_torque =joint_data.break_torque; + root_e->add_Shape(bone_data.get_shape(),vs_root_position); + root_e->add_Mass(bone_data.get_shape(),vs_root_position,bone_data.get_center_of_mass(),bone_data.get_mass(),&fracture); + + fracture_num=E->setGeomFracturable(fracture); + } + else + { + root_e->add_Shape(bone_data.get_shape(),vs_root_position); + root_e->add_Mass(bone_data.get_shape(),vs_root_position,bone_data.get_center_of_mass(),bone_data.get_mass()); + } + + + //B.Callback_Param=root_e; + //B.Callback=NULL; + + } + else // + { + E = P_create_Element(); + E->m_SelfID=id; + E->mXFORM.set (fm_position); + E->SetMaterial (bone_data.get_game_mtl_idx()); + //Fvector mc; + //fm_position.transform_tiny(mc,bone_data.center_of_mass); + E->set_ParentElement(root_e); + ///B.set_callback(BonesCallback1,E); + if(!no_physics_shape(bone_data.get_shape())){ + E->add_Shape(bone_data.get_shape()); + E->setMassMC(bone_data.get_mass(),bone_data.get_center_of_mass()); + } + element_number=u16(elements.size()); + add_Element(E); + element_added=true; + + + if(root_e) + { + + J = BuildJoint( bone_data, root_e, E ); + if(J) + { + + //J->SetForceAndVelocity(joint_data.friction);//joint_data.friction + SetJointRootGeom(root_e,J); + J->SetBoneID(id); + add_Joint (J); + if(breakable) + { + setEndJointSplitter(); + J->SetBreakable(joint_data.break_force,joint_data.break_torque); + } + } + } + if(m_spliter_holder) + { + splitter_position=u16(m_spliter_holder->m_splitters.size()); + } + } + } + else + { + //B.set_callback(0,root_e); + E=root_e; + } + + if(!no_physics_shape(bone_data.get_shape())) + { + CODEGeom* added_geom = E->last_geom(); + if(added_geom) + { + added_geom->set_bone_id(id); + added_geom->set_shape_flags( bone_data.get_shape().flags ); + } + } +#ifdef DEBUG + if(E->last_geom()) + VERIFY(E->last_geom()->bone_id()!=u16(-1)); +#endif + if(m_spliter_holder&&E->has_geoms()) + { + m_spliter_holder->AddToGeomMap(mk_pair(id,E->last_geom())); + } + + if(spGetingMap) + { + const BONE_P_PAIR_IT c_iter= spGetingMap->find(id); + if(spGetingMap->end()!=c_iter) + { + c_iter->second.joint=J; + c_iter->second.element=E; + } + } + + + ///////////////////////////////////////////////////////////////////////////////////// + //for (vecBonesIt it=bone_data.children.begin(); bone_data.children.end() != it; ++it) + // AddElementRecursive (E,(*it)->GetSelfID(),fm_position,element_number,arg_check); + //IBoneData &ibone_data = bone_data; + u16 num_children = bone_data.GetNumChildren(); + for(u16 i = 0;iFracture(fracture_num); + fracture.m_bone_id =id; + fracture.m_end_geom_num =E->numberOfGeoms(); + fracture.m_end_el_num =u16(elements.size());//just after this el = current+1 + fracture.m_end_jt_num =u16(joints.size()); //current+1 + + } + else + { + if(J) + { + J->JointDestroyInfo()->m_end_element=u16(elements.size()); + J->JointDestroyInfo()->m_end_joint=u16(joints.size()); + } + } + } + + if(element_added&&E->isBreakable())setElementSplitter(element_number,splitter_position); +#ifdef DEBUG + bool bbb = lvis_check||(!breakable && root_e); + if(!bbb) + { + IKinematics* K = m_pKinematics; + + Msg("all bones transform:--------"); + + for(u16 ii=0; iiLL_BoneCount();++ii){ + Fmatrix tr; + + tr = K->LL_GetTransform(ii); + Log("bone ",K->LL_BoneName_dbg(ii)); + Log("bone_matrix",tr); + } + Log("end-------"); + } + + VERIFY3(bbb,dbg_obj->ObjectNameVisual(),"has breaking parts with no vertexes or size less than 1mm");// +#endif + +} + +void CPHShell::ResetCallbacks(u16 id,Flags64 &mask) +{ + ResetCallbacksRecursive(id,u16(-1),mask); +} + +void CPHShell::ResetCallbacksRecursive(u16 id,u16 element,Flags64 &mask) +{ + + //if(elements.size()==element) return; + CBoneInstance& B = m_pKinematics->LL_GetBoneInstance(u16(id)); + const IBoneData& bone_data= m_pKinematics->GetBoneData(u16(id)); + const SJointIKData& joint_data=bone_data.get_IK_data(); + + if( mask.is(1ui64<<(u64)id) ) + { + + if(no_physics_shape(bone_data.get_shape())||joint_data.type==jtRigid&& element!=u16(-1)) + { + + B.set_callback(bctPhysics,0,cast_PhysicsElement(elements[element])); + } + else + { + + element++; + R_ASSERT2(elementGetSelfID(),element,mask); + //IBoneData &ibone_data = bone_data; + u16 num_children = bone_data.GetNumChildren(); + for(u16 i = 0;iLL_GetBoneInstance((*i)->m_SelfID); + B.set_callback_overwrite(TRUE); + } + }else ZeroCallbacks(); +} + + + +template< typename T> +void for_each_bone_id( IKinematics &K, T op ) +{ + u16 bn = K.LL_BoneCount(); + for(u16 i = 0; i < bn; ++i ) + op( i ); +} + +CPHElement* get_physics_parent( IKinematics &k, u16 id ) +{ + VERIFY( BI_NONE != id ); + + while( true ) + { + CBoneInstance & B = k.LL_GetBoneInstance( u16(id) ); + const IBoneData & bone_data = k.GetBoneData( u16(id) ); + if( B.callback_type() == bctPhysics && B.callback_param() ) + return cast_PHElement( B.callback_param() ); + + if( k.LL_GetBoneRoot() == id ) + return 0; + + id = bone_data.GetParentID(); + + if( BI_NONE == id ) + return 0; + } +} +static u16 element_position_in_set_calbacks=u16(-1); +void CPHShell::SetCallbacks( ) +{ + + struct set_bone_callback + { + void operator() ( CPHElement* e){e->SetBoneCallback(); } + }; + std::for_each( elements.begin(), elements.end(), set_bone_callback() ); + + struct set_bone_reference: private boost::noncopyable + { + IKinematics &K; + set_bone_reference( IKinematics &K_ ): K( K_ ){} + void operator() ( u16 id ) + { + CBoneInstance &bi = K.LL_GetBoneInstance(id); + if(!bi.callback() || bi.callback_type() != bctPhysics ) + { + CPHElement *root_e = get_physics_parent( K, id ); + if( root_e && K.LL_GetBoneVisible( id ) ) + bi.set_callback( bctPhysics, 0, cast_PhysicsElement( root_e ) ); + } + } + }; + for_each_bone_id( *PKinematics(), set_bone_reference( *PKinematics() ) ); + + //element_position_in_set_calbacks=u16(-1); + + //SetCallbacksRecursive(m_pKinematics->LL_GetBoneRoot(),element_position_in_set_calbacks); +} + + + +void CPHShell::SetCallbacksRecursive(u16 id,u16 element) +{ + VERIFY( false ); + //if(elements.size()==element) return; + CBoneInstance& B = m_pKinematics->LL_GetBoneInstance(u16(id)); + const IBoneData& bone_data= m_pKinematics->GetBoneData(u16(id)); + const SJointIKData& joint_data=bone_data.get_IK_data(); + Flags64 mask; + mask.assign(m_pKinematics->LL_GetBonesVisible()); + if(mask.is(1ui64<<(u64)id)) + { + if((no_physics_shape(bone_data.get_shape())||joint_data.type==jtRigid) && element!=u16(-1)){ + B.set_callback(bctPhysics,0,cast_PhysicsElement(elements[element])); + }else{ + element_position_in_set_calbacks++; + element=element_position_in_set_calbacks; + R_ASSERT2(elementGetSelfID(),element); + //IBoneData &ibone_data = bone_data; + u16 num_children = bone_data.GetNumChildren(); + for(u16 i = 0;iLL_GetBoneRoot()); +} +void CPHShell::ZeroCallbacksRecursive(u16 id) +{ + CBoneInstance& B = m_pKinematics->LL_GetBoneInstance(u16(id)); + const IBoneData& bone_data= m_pKinematics->GetBoneData(u16(id)); + if(B.callback_type() == bctPhysics) + { + B.reset_callback (); + } + //for (vecBonesIt it=bone_data.children.begin(); bone_data.children.end() != it; ++it) + // ZeroCallbacksRecursive ((*it)->GetSelfID()); + //IBoneData &ibone_data = bone_data; + u16 num_children = bone_data.GetNumChildren(); + for(u16 i = 0;iset_DynamicLimits(l_limit,w_limit); +} + +void CPHShell::set_DynamicScales(float l_scale/* =default_l_scale */,float w_scale/* =default_w_scale */) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->set_DynamicScales(l_scale,w_scale); +} + +void CPHShell::set_DisableParams(const SAllDDOParams& params) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->set_DisableParams(params); +} + +void CPHShell::UpdateRoot() +{ + + ELEMENT_I i=elements.begin(); + if( !(*i)->isFullActive()) return; + + (*i)->InterpolateGlobalTransform(&mXFORM); + +} + +Fmatrix& CPHShell::get_animation_root_matrix( Fmatrix& m ) +{ + + return m; +} + +void CPHShell::InterpolateGlobalTransform(Fmatrix* m) +{ + + //if(!CPHObject::is_active()&&!CPHObject::NetInterpolation()) return; + + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->InterpolateGlobalTransform(&(*i)->mXFORM); + + m->set( root_element().mXFORM ); + + m->mulB_43 (m_object_in_root); + + mXFORM.set(*m); + + VERIFY2(_valid(*m),"not valide transform"); + + IPhysicsShellHolder* ref_object=(*elements.begin())->PhysicsRefObject(); + if(ref_object&&m_active_count<0) + { + ref_object->ObjectProcessingDeactivate(); + ref_object->ObjectSpatialMove(); + m_active_count=0; + } + +} + +void CPHShell::GetGlobalTransformDynamic(Fmatrix* m) +{ + ELEMENT_CI i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->GetGlobalTransformDynamic(&(*i)->mXFORM); + m->set((*elements.begin())->mXFORM); + + m->mulB_43 (m_object_in_root); + mXFORM.set(*m); + + VERIFY2(_valid(*m),"not valide transform"); + +} +void CPHShell::InterpolateGlobalPosition(Fvector* v) +{ + (*elements.begin())->InterpolateGlobalPosition(v); + + v->add(m_object_in_root.c); + + VERIFY2(_valid(*v),"not valide result position"); +} + +void CPHShell::GetGlobalPositionDynamic(Fvector* v) +{ + (*elements.begin())->GetGlobalPositionDynamic(v); + VERIFY2(_valid(*v),"not valide result position"); +} + + +void CPHShell::ObjectToRootForm(const Fmatrix& form) +{ + Fmatrix M; + Fmatrix ILF; + (*elements.begin())->InverceLocalForm(ILF); + M.mul(m_object_in_root,ILF); + M.invert(); + mXFORM.mul(form,M); + VERIFY2(_valid(form),"not valide transform"); + +} + + + +CPhysicsElement* CPHShell::NearestToPoint(const Fvector& point, NearestToPointCallback *cb /*=0*/) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + float min_distance =dInfinity; + CPHElement* nearest_element=NULL; + for( ; i!=e; ++i ) + { + Fvector tmp; + float distance; + if( cb && ! (*cb)( *i ) ) + continue; + (*i)->GetGlobalPositionDynamic(&tmp); + tmp.sub(point); + distance=tmp.magnitude(); + if(distanceelements.empty()) (*i_from)->set_ParentElement(dest->elements.back()); + else (*i_from)->set_ParentElement(NULL); + } + for(ELEMENT_I i=i_from;i!=e;++i) + { + dGeomID spaced_geom=(*i)->dSpacedGeometry(); + if(spaced_geom)//for active elems + { + dSpaceRemove (m_space,spaced_geom ); + dSpaceAdd(dest->m_space,spaced_geom); + } + VERIFY(_valid(dest->mXFORM)); + (*i)->SetShell(dest); + } + dest->elements.insert(dest->elements.end(),i_from,e); + elements.erase(i_from,e); + +} + +void CPHShell::PassEndJoints(u16 from,u16 to,CPHShell *dest) +{ + JOINT_I i_from=joints.begin()+from,e=joints.begin()+to; + JOINT_I i=i_from; + for(;i!=e;i++) + { + (*i)->SetShell(dest); + } + dest->joints.insert(dest->joints.end(),i_from,e); + joints.erase(i_from,e); +} + +void CPHShell::DeleteElement(u16 element) +{ + elements[element]->Deactivate(); + xr_delete(elements[element]); + elements.erase(elements.begin()+element); +} +void CPHShell::DeleteJoint(u16 joint) +{ + joints[joint]->Deactivate(); + xr_delete(joints[joint]); + joints.erase(joints.begin()+joint); +} + +void CPHShell::setEndElementSplitter() +{ + + if(!elements.back()->FracturesHolder())//adding fracture for element supposed before adding splitter. Need only one splitter for an element + AddSplitter(CPHShellSplitter::splElement,u16(elements.size()-1),u16(joints.size()-1)); +} + +void CPHShell::setElementSplitter(u16 element_number,u16 splitter_position) +{ + AddSplitter(CPHShellSplitter::splElement,element_number,element_number-1,splitter_position); +} +void CPHShell::AddSplitter(CPHShellSplitter::EType type,u16 element,u16 joint) +{ + if(!m_spliter_holder) m_spliter_holder=xr_new(this); + m_spliter_holder->AddSplitter(type,element,joint); +} + +void CPHShell::AddSplitter(CPHShellSplitter::EType type,u16 element,u16 joint,u16 position) +{ + if(!m_spliter_holder) m_spliter_holder=xr_new(this); + m_spliter_holder->AddSplitter(type,element,joint,position); +} +void CPHShell::setEndJointSplitter() +{ + if(!joints.back()->JointDestroyInfo())//setting joint breacable supposed before adding splitter. Need only one splitter for a joint + AddSplitter(CPHShellSplitter::splJoint,u16(elements.size()-1),u16(joints.size()-1)); +} + +bool CPHShell::isBreakable() +{ + return (m_spliter_holder&&!m_spliter_holder->IsUnbreakable()); +} + +bool CPHShell::isFractured() +{ + return(m_spliter_holder&&m_spliter_holder->Breaked()); +} + +void CPHShell::SplitProcess(PHSHELL_PAIR_VECTOR &out_shels) +{ + if(! m_spliter_holder) return; + m_spliter_holder->SplitProcess(out_shels); + if(!m_spliter_holder->m_splitters.size()) xr_delete(m_spliter_holder); +} +void CPHShell::SplitterHolderActivate() +{ + CPHShellSplitterHolder*sh= SplitterHolder(); + if(sh) + sh->Activate(); +} +void CPHShell::SplitterHolderDeactivate() +{ + + CPHShellSplitterHolder*sh= SplitterHolder(); + if(sh) + sh->Deactivate(); +} + +u16 CPHShell::BoneIdToRootGeom(u16 id) +{ + if(! m_spliter_holder)return u16(-1); + return m_spliter_holder->FindRootGeom(id); +} + +void CPHShell::SetJointRootGeom(CPhysicsElement* root_e,CPhysicsJoint* J) +{ + R_ASSERT(root_e); + R_ASSERT( J ); + CPHElement* e=cast_PHElement(root_e); + CPHJoint* j=static_cast(J); + + CPHFracturesHolder* f_holder=e->FracturesHolder(); + if(!f_holder) return; + j->RootGeom()=e->Geom(f_holder->LastFracture().m_start_geom_num); +} + +void CPHShell::set_ApplyByGravity(bool flag) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->set_ApplyByGravity(flag); +} + +bool CPHShell::get_ApplyByGravity() +{ + if (elements.empty()) + return (false); + + VERIFY (elements.front()); + return (elements.front()->get_ApplyByGravity()); +} + +void CPHShell::applyGravityAccel(const Fvector& accel) +{ + if(!isActive())return; + ELEMENT_I i,e; + Fvector a; + a.set(accel); + a.mul((float)elements.size()); + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->applyGravityAccel(a); + EnableObject(0); +} + +void CPHShell::PlaceBindToElForms() +{ + Flags64 mask; + mask.assign(m_pKinematics->LL_GetBonesVisible()); + PlaceBindToElFormsRecursive(Fidentity,m_pKinematics->LL_GetBoneRoot(),0,mask); +} +void CPHShell:: setTorque (const Fvector& torque) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->setTorque(torque); +} +void CPHShell:: setForce (const Fvector& force) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->setForce(force); +} +void CPHShell::PlaceBindToElFormsRecursive(Fmatrix parent,u16 id,u16 element,Flags64 &mask) +{ + + + CBoneData& bone_data= m_pKinematics->LL_GetData(u16(id)); + SJointIKData& joint_data=bone_data.IK_data; + + if(mask.is(1ui64<<(u64)id)) + { + + if(no_physics_shape(bone_data.shape)||joint_data.type==jtRigid&& element!=u16(-1)) + { + + + } + else + { + + element++; + R_ASSERT2(elementmXFORM.mul(parent,bone_data.bind_transform); + + } + } + //for (vecBonesIt it=bone_data.children.begin(); it!=bone_data.children.end(); ++it) + // PlaceBindToElFormsRecursive(mXFORM,(*it)->GetSelfID(),element,mask); + IBoneData &ibone_data = bone_data; + u16 num_children = ibone_data.GetNumChildren(); + for(u16 i = 0;iLL_GetBoneInstance(id); + CBoneData& bone_data= m_pKinematics->LL_GetData(u16(id)); + + bone_instance.mTransform.mul(parent,bone_data.bind_transform); + +// for (vecBonesIt it=bone_data.children.begin(); it!=bone_data.children.end(); ++it) +// BonesBindCalculateRecursive(bone_instance.mTransform,(*it)->GetSelfID()); + IBoneData &ibone_data = bone_data; + u16 num_children = ibone_data.GetNumChildren(); + for(u16 i = 0;iGeom(geom); + g->set_ph_object(this); + m_traced_geoms.add(g); + EnableGeomTrace (); +} +void CPHShell::SetAllGeomTraced() +{ + ELEMENT_I i, e, b; + b = elements.begin(); e=elements.end(); + for( i=b ;i!=e; ++i ) + { + u16 gn=(*i)->numberOfGeoms(); + for(u16 j=0;jSetShell(this); + elements.push_back(ph_element); + +} + +void CPHShell::add_Joint (CPhysicsJoint* J) { + if(!J)return; + joints.push_back(static_cast(J)); + joints.back()->SetShell(this); +} + +CODEGeom* CPHShell::get_GeomByID(u16 bone_id) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + { + CODEGeom* ret=(*i)->GeomByBoneID(bone_id); + if(ret) return ret; + } + return NULL; +} +void CPHShell::PureStep(float step) +{ + //CPHObject::Island().Step(step); + //PhDataUpdate(step); + CPHObject::step( step ); +} +void CPHShell::CollideAll() +{ + CPHObject::Collide(); + CPHObject::reinit_single(); +} + +void CPHShell::RegisterToCLGroup (CGID g) +{ + CPHCollideValidator::RegisterObjToGroup(g,*static_cast(this)); +} + +bool CPHShell::IsGroupObject() +{ + return CPHCollideValidator::IsGroupObject(*this); +}; + +void CPHShell::SetIgnoreStatic() +{ + CPHCollideValidator::SetStaticNotCollide(*this); +} + +void CPHShell::SetIgnoreDynamic() +{ + CPHCollideValidator::SetDynamicNotCollide(*this); +} + +void CPHShell::SetRagDoll() +{ + CPHCollideValidator::SetRagDollClass(*this); +} + +void CPHShell::SetIgnoreRagDoll() +{ + CPHCollideValidator::SetRagDollClassNotCollide(*this); +} + + + //������ ������ ���������� ����� ������������� +void CPHShell::CreateShellAnimator( CInifile const * ini, LPCSTR section ) +{ + //��� ������� �������� ������� ������ ������ � ������ ������������� + CPHCollideValidator::SetAnimatedClass(*this); + m_pPhysicsShellAnimatorC=xr_new( this, ini, section ); + VERIFY( PhysicsRefObject( ) ); + PhysicsRefObject()->ObjectProcessingActivate(); + //m_pPhysicsShellAnimatorC->ResetCallbacks(); +} + +//����������� ������ �������� �� ������������� ������������� ������� +//����������� ������� � ������������� ���������� �������� +void CPHShell::SetIgnoreAnimated() +{ + //��� ������� �������� ���������, ��� ������ + //���������� ������ ���������� ������������� ���������� ���� + + CPHCollideValidator::SetAnimatedClassNotCollide(*this); +} + +//������ ���������� � ��� �������� �� ������ ������ ������������� + + +void CPHShell:: SetSmall() +{ + CPHCollideValidator::SetClassSmall(*this); +} + +void CPHShell:: SetIgnoreSmall() +{ + CPHCollideValidator::SetClassSmallNotCollide(*this); +} +void CPHShell::CutVelocity(float l_limit,float a_limit) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i)(*i)->CutVelocity(l_limit,a_limit); +} + +void CPHShell::ClearRecentlyDeactivated() +{ + ClearCashedTries(); +} + +void CPHShell::ClearCashedTries() +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i)(*i)->clear_cashed_tries(); +} + +void CPHShell::get_Extensions(const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext) const +{ + t_get_extensions( elements, axis, center_prg, lo_ext, hi_ext ); + /* + lo_ext=dInfinity;hi_ext=-dInfinity; + ELEMENT_CI i=elements.begin(),e=elements.end(); + for(;i!=e;++i) + { + float temp_lo_ext,temp_hi_ext; + (*i)->get_Extensions(axis,center_prg,temp_lo_ext,temp_hi_ext); + if(lo_ext>temp_lo_ext)lo_ext=temp_lo_ext; + if(hi_extget_CallbackData(); +} + +void CPHShell:: SetBonesCallbacksOverwrite(bool v) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ;i!=e;++i) + (*i)->SetBoneCallbackOverwrite(v); +} + + +void CPHShell:: ToAnimBonesPositions ( motion_history_state history_state ) +{ + VERIFY( PKinematics() ); + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + for( ; i!=e; ++i ) + (*i)->ToBonePos( &PKinematics()->LL_GetBoneInstance( (*i)->m_SelfID ), history_state ); +} + +bool CPHShell:: AnimToVelocityState ( float dt, float l_limit, float a_limit ) +{ + ELEMENT_I i,e; + i=elements.begin(); e=elements.end(); + bool ret = true; + for( ;i!=e; ++i ) + ret =(*i)->AnimToVel( dt, l_limit, a_limit ) && ret; + return ret; +} + +void CPHShell::SetAnimated( bool v ) +{ + ELEMENT_I i, e; + i = elements.begin(); e=elements.end(); + for( ; i!=e; ++i ) + (*i)->SetAnimated( v ); + +} + + +void CPHShell:: AnimatorOnFrame () +{ + VERIFY( PPhysicsShellAnimator() ); + PPhysicsShellAnimator()->OnFrame(); +} + + + + + +#ifdef DEBUG + +void CPHShell:: dbg_draw_velocity ( float scale, u32 color ) +{ + ELEMENT_I i, e; + i = elements.begin(); e=elements.end(); + for( ; i!=e; ++i ) + (*i)->dbg_draw_velocity( scale, color ); + +} +void CPHShell:: dbg_draw_force ( float scale, u32 color ) +{ + ELEMENT_I i, e; + i = elements.begin(); e=elements.end(); + for( ; i!=e; ++i ) + (*i)->dbg_draw_force( scale, color ); +} + +void CPHShell::dbg_draw_geometry ( float scale, u32 color, Flags32 flags /*= Flags32().assign( 0 )*/ ) const +{ + ELEMENT_CI i, e; + i = elements.begin(); e=elements.end(); + for( ; i!=e; ++i ) + (*i)->dbg_draw_geometry( scale, color, flags ); +} + +#endif diff --git a/xrPhysics/PHShell.h b/xrPhysics/PHShell.h new file mode 100644 index 00000000000..8e6ce9ce24d --- /dev/null +++ b/xrPhysics/PHShell.h @@ -0,0 +1,313 @@ +/////////////////////////////////////////////////////////////////////// + +#ifndef PH_SHELL +#define PH_SHELL + +class CPHShell; +class CPHShellSplitterHolder; +#include "PHJoint.h" +#include "PHElement.h" +#include "PHDefs.h" +#include "PHShellSplitter.h" +#include "phmovestorage.h" +#include "physics_scripted.h" + + +class CPhysicsShellAnimator; + + +class CPHShell: + public CPhysicsShell, + public CPHObject, + public cphysics_scripted +{ + + friend class CPHShellSplitterHolder; + enum + { + flActive = 1<<0, + flActivating = 1<<1, + flRemoveCharacterCollisionAfterDisable = 1<<2, + }; + s16 m_active_count; + Flags8 m_flags; + ELEMENT_STORAGE elements; + JOINT_STORAGE joints; + CPHShellSplitterHolder *m_spliter_holder; + CPHMoveStorage m_traced_geoms; + + + CPhysicsShellAnimator* m_pPhysicsShellAnimatorC; + +private: + +#ifdef DEBUG + virtual IPhysicsShellHolder *ref_object () { return PhysicsRefObject() ;} +#endif + +protected: + dSpaceID m_space; +public: + Fmatrix m_object_in_root; + CPHShell (); + virtual ~CPHShell (); + virtual void applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val,const u16 id); + virtual void applyHit (const Fvector& pos, const Fvector& dir, float val,const u16 id,ALife::EHitType hit_type); + + static void _BCL BonesCallback (CBoneInstance* B); + static void _BCL StataticRootBonesCallBack (CBoneInstance* B); + virtual BoneCallbackFun* GetBonesCallback () {return BonesCallback ;} + virtual BoneCallbackFun* GetStaticObjectBonesCallback() { VERIFY( false ); return StataticRootBonesCallBack; } + virtual void add_Element (CPhysicsElement* E); + virtual void ToAnimBonesPositions ( motion_history_state history_state ); + virtual bool AnimToVelocityState (float dt, float l_limit, float a_limit ); + virtual void SetBonesCallbacksOverwrite(bool v); + void SetPhObjectInElements (); + virtual void EnableObject (CPHObject* obj); + virtual void DisableObject (); + virtual void SetAirResistance (dReal linear=default_k_l, dReal angular=default_k_w) + { + xr_vector::iterator i; + for(i=elements.begin();elements.end()!=i;++i) + (*i)->SetAirResistance(linear,angular); + } + virtual void GetAirResistance (float& linear, float& angular) + { + (*elements.begin())->GetAirResistance(linear,angular); + } + virtual void add_Joint (CPhysicsJoint* J); + + virtual CPHIsland* PIsland (){return &Island();}; + virtual void applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val) ; + + virtual void Update () ; + + virtual void Activate (const Fmatrix& m0, float dt01, const Fmatrix& m2,bool disable=false); + virtual void Activate (const Fmatrix &transform,const Fvector& lin_vel,const Fvector& ang_vel,bool disable=false); + virtual void Activate (bool disable=false, bool not_set_bone_callbacks = false); + virtual void Activate (const Fmatrix& start_from, bool disable=false){}; + + + virtual CPhysicsShellAnimator* PPhysicsShellAnimator(){return m_pPhysicsShellAnimatorC;}; + +private: + void activate (bool disable); +public: + virtual void Build (bool disable=false); + virtual void RunSimulation (bool place_current_forms=true); + virtual void net_Import (NET_Packet& P); + virtual void net_Export (NET_Packet& P); + void PresetActive (); + void AfterSetActive (); + void PureActivate (); + virtual void Deactivate (); + virtual const CGID& GetCLGroup ()const; + virtual void RegisterToCLGroup (CGID g) ; + virtual bool IsGroupObject () ; + virtual void SetIgnoreStatic () ; + virtual void SetIgnoreDynamic () ; + virtual void SetRagDoll () ; + virtual void SetIgnoreRagDoll () ; + + virtual void CreateShellAnimator ( CInifile const * ini, LPCSTR section ) ; + virtual void SetIgnoreAnimated () ; + + virtual void SetSmall () ; + virtual void SetIgnoreSmall () ; + + virtual const CLBits& collide_bits ()const { return CPHObject::collide_bits();}; + virtual const _flags& collide_class_bits ()const {return CPHObject::collide_class_bits(); } + + virtual void setMass (float M) ; + + virtual void setMass1 (float M) ; + virtual void setEquelInertiaForEls (const dMass& M) ; + virtual void addEquelInertiaToEls (const dMass& M) ; + virtual void MassAddBox ( float mass, const Fvector &full_size ) ; + virtual float getMass () ; + virtual void setDensity (float M) ; + virtual float getDensity () ; + virtual float getVolume () ; + virtual void get_Extensions (const Fvector& axis,float center_prg,float& lo_ext, float& hi_ext) const; + virtual void applyForce (const Fvector& dir, float val) ; + virtual void applyForce (float x,float y,float z) ; + virtual void applyImpulse (const Fvector& dir, float val) ; + virtual void _BCL applyGravityAccel (const Fvector& accel); + virtual void setTorque (const Fvector& torque); + virtual void setForce (const Fvector& force); + virtual void set_JointResistance (float force) + { + JOINT_I i; + for(i=joints.begin();joints.end() != i;++i) + { + (*i)->SetForce(force); + (*i)->SetVelocity(); + } + //(*i)->SetForceAndVelocity(force); + } + virtual void set_DynamicLimits (float l_limit=default_l_limit,float w_limit=default_w_limit); + virtual void set_DynamicScales (float l_scale=default_l_scale,float w_scale=default_w_scale); + virtual void set_ContactCallback (ContactCallbackFun* callback); + virtual void set_ObjectContactCallback (ObjectContactCallbackFun* callback); + virtual void SetAnimated ( bool v ); + virtual void add_ObjectContactCallback (ObjectContactCallbackFun* callback); + virtual void remove_ObjectContactCallback (ObjectContactCallbackFun* callback); + virtual void set_CallbackData (void * cd); + virtual void *get_CallbackData (); + virtual void set_PhysicsRefObject (IPhysicsShellHolder* ref_object); + IPhysicsShellHolder*PhysicsRefObject (){ return (*elements.begin())->PhysicsRefObject(); } + + //breakbable interface + virtual bool isBreakable (); + virtual bool isFractured (); + virtual CPHShellSplitterHolder* SplitterHolder (){return m_spliter_holder;} + virtual void SplitterHolderActivate (); + virtual void SplitterHolderDeactivate (); + virtual void SplitProcess (PHSHELL_PAIR_VECTOR &out_shels); + virtual void BlockBreaking (){if(m_spliter_holder)m_spliter_holder->SetUnbreakable();} + virtual void UnblockBreaking (){if(m_spliter_holder)m_spliter_holder->SetBreakable();} + virtual bool IsBreakingBlocked (){return m_spliter_holder&&m_spliter_holder->IsUnbreakable();} + /////// //////////////////////////////////////////////////////////////////////////////////////////// + virtual void get_LinearVel (Fvector& velocity) const ; + virtual void get_AngularVel (Fvector& velocity) const ; + virtual void set_LinearVel (const Fvector& velocity); + virtual void set_AngularVel (const Fvector& velocity); + virtual void TransformPosition (const Fmatrix &form, motion_history_state history_state ); + virtual void SetGlTransformDynamic (const Fmatrix &form); + virtual void set_ApplyByGravity (bool flag); + virtual bool get_ApplyByGravity (); + virtual void SetMaterial (u16 m); + virtual void SetMaterial (LPCSTR m); + virtual ELEMENT_STORAGE &Elements (){return elements;} + virtual CPhysicsElement *get_Element (u16 bone_id); + virtual CPhysicsElement *get_Element (const shared_str & bone_name); + virtual CPhysicsElement *get_Element (LPCSTR bone_name); + virtual const CPhysicsElement *get_ElementByStoreOrder (u16 num) const; + virtual CPhysicsElement *get_ElementByStoreOrder (u16 num); + CPhysicsElement *get_PhysicsParrentElement ( u16 bone_id ); + virtual u16 get_ElementsNumber ()const{return (u16)elements.size();} + virtual CPHSynchronize *get_ElementSync (u16 element); + virtual u16 get_elements_number (){return get_ElementsNumber();} + virtual CPHSynchronize *get_element_sync (u16 element){return get_ElementSync(element);} + virtual CPhysicsElement *NearestToPoint (const Fvector& point, NearestToPointCallback *cb = 0 ); + virtual CPhysicsJoint *get_Joint (u16 bone_id); + virtual CPhysicsJoint *get_Joint (const shared_str & bone_name); + virtual CPhysicsJoint *get_Joint (LPCSTR bone_name); + virtual CPhysicsJoint *get_JointByStoreOrder (u16 num); + virtual u16 get_JointsNumber (); + virtual CODEGeom *get_GeomByID (u16 bone_id); + + virtual void Enable (); + virtual void Disable (); + virtual void DisableCollision (); + virtual void EnableCollision (); + virtual void DisableCharacterCollision (); + virtual void SetRemoveCharacterCollLADisable (){m_flags.set(flRemoveCharacterCollisionAfterDisable,TRUE);} + virtual bool isEnabled ()const {return CPHObject::is_active();} + virtual bool isActive ()const {return !!m_flags.test(flActive);} + virtual bool isFullActive ()const {return isActive()&&!m_flags.test(flActivating);} + void SetNotActivating (){m_flags.set(flActivating,FALSE);} + IC void SetObjVsShellTransform (const Fmatrix & root_transform); +//CPHObject + virtual void vis_update_activate (); + virtual void vis_update_deactivate (); + virtual void PureStep (float step); + virtual void CollideAll (); + virtual void PhDataUpdate (dReal step); + virtual void PhTune (dReal step); + virtual void InitContact (dContact* c,bool &do_collide,u16 /*material_idx_1*/,u16 /*material_idx_2*/){}; + virtual void FreezeContent (); + virtual void UnFreezeContent (); + virtual void Freeze (); + virtual void UnFreeze (); + virtual void NetInterpolationModeON (){CPHObject::NetInterpolationON();} + virtual void NetInterpolationModeOFF (){CPHObject::NetInterpolationOFF();} + virtual void StepFrameUpdate (dReal step){}; + virtual CPHMoveStorage* MoveStorage (){return &m_traced_geoms;} + virtual void build_FromKinematics (IKinematics* K,BONE_P_MAP* p_geting_map=NULL); + virtual void preBuild_FromKinematics (IKinematics* K,BONE_P_MAP* p_geting_map); + virtual void _BCL ActivatingBonePoses (IKinematics &K); + virtual void ZeroCallbacks (); + virtual void ResetCallbacks (u16 id,Flags64 &mask); + void PlaceBindToElForms (); + virtual void SetCallbacks ( ); + virtual void EnabledCallbacks (BOOL val); + virtual void set_DisableParams (const SAllDDOParams& params); + virtual void UpdateRoot (); + virtual void SmoothElementsInertia (float k); + virtual void _BCL InterpolateGlobalTransform (Fmatrix* m); + virtual void InterpolateGlobalPosition (Fvector* v); + virtual void AnimatorOnFrame (); + virtual void GetGlobalTransformDynamic (Fmatrix* m) ; + virtual void GetGlobalPositionDynamic (Fvector* v); + virtual Fmatrix& ObjectInRoot (){return m_object_in_root;} + virtual void ObjectToRootForm (const Fmatrix& form); + virtual dSpaceID dSpace (){return m_space;} + virtual void SetTransform (const Fmatrix& m0, motion_history_state history_state ); + + virtual void AddTracedGeom (u16 element=0,u16 geom=0); + virtual void SetAllGeomTraced (); + + virtual void ClearTracedGeoms (); + virtual void DisableGeomTrace (); + virtual void EnableGeomTrace (); + virtual bool HasTracedGeoms (){ return !m_traced_geoms.empty(); } + + virtual void SetPrefereExactIntegration (); + virtual void CutVelocity (float l_limit,float a_limit); +/////////// ////////////////////////////////////////////////////////////////////////////////////////// + void CreateSpace () ; + void PassEndElements (u16 from,u16 to,CPHShell *dest) ; + void PassEndJoints (u16 from,u16 to,CPHShell *dest) ; + void DeleteElement (u16 element) ; + void DeleteJoint (u16 joint) ; + u16 BoneIdToRootGeom (u16 id) ; +///////////////////////////////////////////////////////////////////////////////////////////////////// +protected: + virtual void get_spatial_params () ; + virtual dGeomID dSpacedGeom () {return (dGeomID)m_space;} + + virtual void ClearRecentlyDeactivated () ; + void ClearCashedTries () ; +private: + //breakable + void setEndElementSplitter () ; + void setElementSplitter (u16 element_number,u16 splitter_position) ; + void setEndJointSplitter () ; + void AddSplitter (CPHShellSplitter::EType type,u16 element,u16 joint) ; + void AddSplitter (CPHShellSplitter::EType type,u16 element,u16 joint,u16 position) ; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void AddElementRecursive (CPhysicsElement* root_e, u16 id,Fmatrix global_parent,u16 element_number,bool *vis_check) ; + void PlaceBindToElFormsRecursive (Fmatrix parent,u16 id,u16 element,Flags64 &mask); + void BonesBindCalculate (u16 id_from=0); + void BonesBindCalculateRecursive (Fmatrix parent,u16 id); + void ZeroCallbacksRecursive (u16 id) ; + void SetCallbacksRecursive (u16 id,u16 element) ; + void ResetCallbacksRecursive (u16 id,u16 element,Flags64 &mask) ; + void SetJointRootGeom (CPhysicsElement* root_e,CPhysicsJoint* J) ; + void ReanableObject () ; + void ExplosionHit (const Fvector& pos, const Fvector& dir, float val,const u16 id) ; + void ClearBreakInfo (); + Fmatrix& get_animation_root_matrix ( Fmatrix& m ); + void update_root_transforms (); +IC CPHElement &root_element () { VERIFY( !elements.empty() ); return *(*elements.begin()); } + private: + virtual iphysics_scripted &get_scripted () { return *this ;} + public: +#ifdef DEBUG + virtual void dbg_draw_velocity ( float scale, u32 color ); + virtual void dbg_draw_force ( float scale, u32 color ); + virtual void dbg_draw_geometry ( float scale, u32 color, Flags32 flags = Flags32().assign( 0 ) ) const ; +#endif +}; + + +IC void CPHShell::SetObjVsShellTransform (const Fmatrix & root_transform) +{ + m_object_in_root.set( root_transform ); + m_object_in_root.invert( ); + SetNotActivating( ); +} + + +#endif \ No newline at end of file diff --git a/xrPhysics/PHShellActivate.cpp b/xrPhysics/PHShellActivate.cpp new file mode 100644 index 00000000000..d0d0994c2e1 --- /dev/null +++ b/xrPhysics/PHShellActivate.cpp @@ -0,0 +1,299 @@ +#include "StdAfx.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PHShellSplitter.h" +#include "PHFracture.h" +#include "PHJointDestroyInfo.h" +#include "PHCollideValidator.h" +//#include "Level.h" +#include "iphysicsshellholder.h" +#include "PhysicsShellAnimator.h" +#include "../Include/xrRender/Kinematics.h" + +/////////////////////////////////////////////////////////////// +///#pragma warning(disable:4995) +//#include "../3rd party/ode/ode/src/collision_kernel.h" +//#include "../3rd party/ode/ode/src/joint.h" +//#include "../3rd party/ode/ode/src/objects.h" + +//#pragma warning(default:4995) +/////////////////////////////////////////////////////////////////// + +#include "ExtendedGeom.h" + +#include "PHElement.h" +#include "PHShell.h" +void CPHShell::activate(bool disable) +{ + PresetActive(); + if(!CPHObject::is_active()) vis_update_deactivate(); + if(!disable)EnableObject(0); + +} +void CPHShell::Activate(const Fmatrix &m0,float dt01,const Fmatrix &m2,bool disable){ + + if(isActive())return; + activate(disable); +// ELEMENT_I i; + mXFORM.set(m0); + //for(i=elements.begin();elements.end() != i;++i){ + + // (*i)->Activate(m0,dt01, m2, disable); + //} + + { + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i)(*i)->Activate(mXFORM,disable); + } + + { + JOINT_I i=joints.begin(),e=joints.end(); + for(;i!=e;++i) (*i)->Activate(); + } + + Fmatrix m; + { + Fmatrix old_m = mXFORM;//+GetGlobalTransformDynamic update mXFORM; + GetGlobalTransformDynamic (&m); + mXFORM = old_m; + } + m.invert();m.mulA_43 (mXFORM); + TransformPosition( m, mh_unspecified ); + if(PKinematics()) + { + SetCallbacks( ); + } + + //bActive=true; + //bActivating=true; + m_flags.set(flActive,TRUE); + m_flags.set(flActivating,TRUE); + spatial_register(); +/////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + //mXFORM.set(m0); + //Activate(disable); + Fvector lin_vel; + lin_vel.sub(m2.c,m0.c); + set_LinearVel(lin_vel); +} + + + +void CPHShell::Activate(const Fmatrix &transform,const Fvector& lin_vel,const Fvector& ang_vel,bool disable){ + + if(isActive())return; + activate(disable); + + ELEMENT_I i; + mXFORM.set(transform); + for(i=elements.begin();elements.end() != i;++i){ + (*i)->Activate(transform,lin_vel, ang_vel); + } + + { + JOINT_I i=joints.begin(),e=joints.end(); + for(;i!=e;++i) (*i)->Activate(); + } + + if(PKinematics()) + { + SetCallbacks( ); + } + spatial_register(); + //bActive=true; + //bActivating=true; + m_flags.set(flActivating,TRUE); + m_flags.set(flActive,TRUE); +///////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////// + //mXFORM.set(transform); + //Activate(disable); + //set_LinearVel(lin_vel); + //set_AngularVel(ang_vel); + +} + + + +void CPHShell::Activate(bool disable, bool not_set_bone_callbacks /*= false*/) +{ + if(isActive())return; + + activate(disable); + { + IKinematics* K = m_pKinematics; + if(not_set_bone_callbacks) + m_pKinematics = 0; + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i)(*i)->Activate(mXFORM,disable); + m_pKinematics = K; + } + + { + JOINT_I i=joints.begin(),e=joints.end(); + for(;i!=e;++i) (*i)->Activate(); + } + + if(PKinematics() && !not_set_bone_callbacks ) + { + SetCallbacks( ); + } + spatial_register(); + m_flags.set(flActivating,TRUE); + m_flags.set(flActive,TRUE); + +} + + +void CPHShell::Build(bool disable/*false*/) +{ + if(isActive())return; + + PresetActive(); + m_flags.set(flActivating,TRUE); + m_flags.set(flActive,TRUE); + + { + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i) + { + (*i)->build(disable); + } + } + + { + JOINT_I i=joints.begin(),e=joints.end(); + for(;i!=e;++i) (*i)->Create(); + } + +} + +void CPHShell::RunSimulation(bool place_current_forms/*true*/) +{ + if(!CPHObject::is_active()) vis_update_deactivate(); + EnableObject(0); + + + dSpaceSetCleanup(m_space,0); + + { + ELEMENT_I i=elements.begin(),e=elements.end(); + if(place_current_forms) for(;i!=e;++i)(*i)->RunSimulation(mXFORM); + } + { + JOINT_I i=joints.begin(),e=joints.end(); + for(;i!=e;++i) (*i)->RunSimulation(); + } + + spatial_register(); +} + +void CPHShell::AfterSetActive() +{ + if(isActive()) return; + PureActivate(); + //bActive=true; + m_flags.set(flActive,TRUE); + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i)(*i)->PresetActive(); + +} + +void CPHShell::PureActivate() +{ + if(isActive()) return; + //bActive=true; + m_flags.set(flActive,TRUE); + if(!CPHObject::is_active()) vis_update_deactivate(); + EnableObject(0); + m_object_in_root.identity(); + spatial_register(); +} + +void CPHShell::PresetActive() +{ + VERIFY(!isActive()); + if(!m_space) + { + m_space=dSimpleSpaceCreate(0); + dSpaceSetCleanup(m_space,0); + + } +} + + + +void CPHShell::Deactivate(){ + + VERIFY(ph_world); + ph_world->NetRelcase(this); + + if (m_pPhysicsShellAnimatorC) + { + VERIFY( PhysicsRefObject( ) ); + PhysicsRefObject( )->ObjectProcessingDeactivate(); + xr_delete(m_pPhysicsShellAnimatorC); + } + + + if(!isActive())return; + R_ASSERT2(!ph_world->Processing(),"can not deactivate physics shell during physics processing!!!"); + R_ASSERT2(!ph_world->IsFreezed(),"can not deactivate physics shell when ph world is freezed!!!"); + R_ASSERT2(!CPHObject::IsFreezed(),"can not deactivate freezed !!!"); + ZeroCallbacks(); + VERIFY(ph_world&&ph_world->Exist()); + if(isFullActive()) + { + vis_update_deactivate(); + CPHObject::activate(); + ph_world->Freeze(); + CPHObject::UnFreeze(); + ph_world->StepTouch(); + ph_world->UnFreeze(); + //Fmatrix m; + //InterpolateGlobalTransform(&m); + } + spatial_unregister(); + + vis_update_activate(); + //if(ref_object && !CPHObject::is_active() && m_active_count == 0) + //{ + // ref_object->processing_activate(); + //} + DisableObject(); + CPHObject::remove_from_recently_deactivated(); + + + ELEMENT_I i; + for(i=elements.begin();elements.end() != i;++i) + (*i)->Deactivate(); + + JOINT_I j; + for(j=joints.begin();joints.end() != j;++j) + (*j)->Deactivate(); + + + + if(m_space) { + dSpaceDestroy(m_space); + m_space=NULL; + } + //bActive=false; + //bActivating=false; + m_flags.set(flActivating,FALSE); + m_flags.set(flActive,FALSE); + m_traced_geoms.clear(); + CPHObject::UnsetRayMotions(); +} + + +void CPHShell::ActivatingBonePoses( IKinematics &K ) +{ + ELEMENT_I i, e; + i = elements.begin(); e=elements.end(); + for( ; i!=e; ++i ) + (*i)->ActivatingPos( K.LL_GetTransform( (*i)->m_SelfID ) ); + +} \ No newline at end of file diff --git a/xrPhysics/PHShellBuildJoint.h b/xrPhysics/PHShellBuildJoint.h new file mode 100644 index 00000000000..8fd41b34350 --- /dev/null +++ b/xrPhysics/PHShellBuildJoint.h @@ -0,0 +1,241 @@ +#pragma once + +#include "../xrengine/bone.h" + +#include "PHJoint.h" +//#include "PHElement.h" + +static const Fvector X = { 1, 0, 0 }; +static const Fvector Y = { 0, 1, 0 }; +static const Fvector Z = { 0, 0, 1 }; +static const Fvector basis[3] = { X, Y, Z }; + +IC void SetJoint( CPhysicsJoint &J, const SJointIKData& joint_data ) +{ + J.SetAnchorVsSecondElement (0,0,0); + J.SetJointSDfactors(joint_data.spring_factor,joint_data.damping_factor); +} + + +IC void SetJointLimit( CPhysicsJoint &J, const IBoneData &bone_data, u8 limit_num, u8 axis_num ) +{ + const SJointIKData& joint_data = bone_data.get_IK_data(); + const SJointLimit& limit = joint_data.limits[limit_num]; + float lo = bone_data.lo_limit(limit_num);//limit.x; + float hi = bone_data.hi_limit(limit_num);//limit.y; + + J.SetLimits(lo,hi,axis_num); + J.SetAxisSDfactors(limit.spring_factor,limit.damping_factor,axis_num); + +} + +IC bool IsFreeRLimit( const IBoneData &bone_data, u8 limit_num ) +{ + //const SJointIKData& joint_data = bone_data.get_IK_data(); + //const SJointLimit& limit = joint_data.limits[limit_num]; + float lo = bone_data.lo_limit(limit_num);//limit.x; + float hi = bone_data.hi_limit(limit_num);//limit.y; + return !(hi-loSetLimits(lo,hi,axis_num); + //J->SetAxisSDfactors(limit.spring_factor,limit.damping_factor,axis_num); + } +} + + + + + +IC CPhysicsJoint *CtreateHinge(const IBoneData &bone_data, u8 limit_num, CPhysicsElement* root_e, CPhysicsElement* E ) +{ + u8 axis_num =0; + const Fvector axis = basis[ limit_num ]; + + + const SJointIKData& joint_data=bone_data.get_IK_data(); + CPhysicsJoint * J = P_create_Joint(CPhysicsJoint::hinge,root_e,E); + //J= P_create_Joint(CPhysicsJoint::hinge,root_e,E); + + SetJoint( *J, joint_data ); + + J->SetAxisDirVsSecondElement ( axis.x, axis.y, axis.z, axis_num ); + + + SetJointLimit( *J, bone_data, limit_num, axis_num ); + return J; +} + +IC CPhysicsJoint *CtreateFullControl(const IBoneData &bone_data, u8 limit_num[3], CPhysicsElement* root_e, CPhysicsElement* E ) +{ + + + + const SJointIKData& joint_data=bone_data.get_IK_data(); + //CPhysicsJoint * J = P_create_Joint(CPhysicsJoint::hinge,root_e,E); + CPhysicsJoint *J= P_create_Joint(CPhysicsJoint::full_control,root_e,E); + SetJoint( *J, joint_data ); + //J->SetAnchorVsSecondElement (0,0,0); + //J->SetJointSDfactors(joint_data.spring_factor,joint_data.damping_factor); + + + const bool set_axis[3] = { true, false, true }; + for( u8 i = 0; i < 3; ++i ) + if(set_axis[i]) + J->SetAxisDirVsSecondElement(basis[limit_num[i]],i); + + for( u8 i = 0; i < 3; ++i ) + SetJointLimit( *J, bone_data, limit_num[i], i ); + + return J; + + +} + +IC CPhysicsJoint *BuildWheelJoint( const IBoneData &bone_data, CPhysicsElement* root_e, CPhysicsElement* E ) + { + const SJointIKData& joint_data=bone_data.get_IK_data(); + CPhysicsJoint *J= P_create_Joint(CPhysicsJoint::hinge2,root_e,E); + + //J->SetAnchorVsSecondElement (0,0,0); + //J->SetJointSDfactors(joint_data.spring_factor,joint_data.damping_factor); + SetJoint( *J, joint_data ); + + + J->SetAxisDirVsSecondElement(1,0,0,0); + J->SetAxisDirVsSecondElement(0,0,1,1); + + //if(joint_data.limits[0].limit.y-joint_data.limits[0].limit.xSetLimits(joint_data.limits[0].limit.x,joint_data.limits[0].limit.y,0); + // J->SetAxisSDfactors(joint_data.limits[0].spring_factor,joint_data.limits[0].damping_factor,0); + //} + SetJointLimit( *J, bone_data, 0, 0 ); + return J; + } +IC CPhysicsJoint *BuildSliderJoint( const IBoneData &bone_data, CPhysicsElement* root_e, CPhysicsElement* E ) +{ + const SJointIKData& joint_data=bone_data.get_IK_data(); + CPhysicsJoint *J= P_create_Joint(CPhysicsJoint::slider,root_e,E); + ///////////////////////////////////////////////////////////////////////////////////// + //J->SetAnchorVsSecondElement (0,0,0); + //J->SetJointSDfactors(joint_data.spring_factor,joint_data.damping_factor); + SetJoint( *J, joint_data ); + + J->SetLimits(joint_data.limits[0].limit.x,joint_data.limits[0].limit.y,0); + J->SetAxisSDfactors(joint_data.limits[0].spring_factor,joint_data.limits[0].damping_factor,0); + + //if(joint_data.limits[1].limit.y-joint_data.limits[1].limit.xSetLimits(joint_data.limits[1].limit.x,joint_data.limits[1].limit.y,1); + // J->SetAxisSDfactors(joint_data.limits[1].spring_factor,joint_data.limits[1].damping_factor,1); + //} + SetJointLimit( *J, bone_data, 1, 1 ); + return J; +} + +IC CPhysicsJoint *BuildBallJoint( const IBoneData &bone_data, CPhysicsElement* root_e, CPhysicsElement* E ) +{ + const SJointIKData& joint_data=bone_data.get_IK_data(); + CPhysicsJoint *J= P_create_Joint(CPhysicsJoint::ball,root_e,E); + SetJoint( *J, joint_data ); + //J->SetAnchorVsSecondElement (0,0,0); + //J->SetJointSDfactors(joint_data.spring_factor,joint_data.damping_factor); + return J; +} + +IC CPhysicsJoint *BuildGenericJoint( const IBoneData &bone_data, CPhysicsElement* root_e, CPhysicsElement* E ) +{ + const SJointIKData& joint_data=bone_data.get_IK_data(); + + + bool eqx=!!fsimilar(joint_data.limits[0].limit.x,joint_data.limits[0].limit.y), + eqy=!!fsimilar(joint_data.limits[1].limit.x,joint_data.limits[1].limit.y), + eqz=!!fsimilar(joint_data.limits[2].limit.x,joint_data.limits[2].limit.y); + + if(eqx) + { + if(eqy) + { + + return CtreateHinge( bone_data, 2, root_e, E ); + } + if(eqz) + { + + return CtreateHinge( bone_data, 1, root_e, E ); + + } + + + u8 axis_limits[3] = { 2, 0, 1 }; + return CtreateFullControl( bone_data, axis_limits , root_e, E ); + } + + if(eqy) + { + if(eqz) + { + + return CtreateHinge( bone_data, 0, root_e, E ); + } + + + u8 axis_limits[3] = { 2, 1, 0 }; + return CtreateFullControl( bone_data, axis_limits , root_e, E ); + + } + + if(eqz) + { + + u8 axis_limits[3] = { 0, 2, 1 }; + return CtreateFullControl( bone_data, axis_limits , root_e, E ); + + } + + + u8 axis_limits[3] = { 2, 0, 1 }; + return CtreateFullControl( bone_data, axis_limits , root_e, E ); + + //return J; +} +IC CPhysicsJoint *BuildJoint( const IBoneData &bone_data, CPhysicsElement* root_e, CPhysicsElement* E ) +{ + CPhysicsJoint *J= 0; + const SJointIKData& joint_data=bone_data.get_IK_data(); + switch(joint_data.type) + { + case jtSlider: + J =BuildSliderJoint( bone_data, root_e,E ); + VERIFY(J); + break; + case jtCloth: + J =BuildBallJoint( bone_data, root_e,E ); + VERIFY(J); + break; + case jtJoint: + J = BuildGenericJoint( bone_data, root_e,E ); + VERIFY(J); + break; + case jtWheel: + J = BuildWheelJoint( bone_data, root_e, E ); + VERIFY(J); + break; + case jtNone: break; + + default: NODEFAULT; + } + + if(J) + J->SetForceAndVelocity(joint_data.friction);//joint_data.friction + + + + return J; +} \ No newline at end of file diff --git a/xrPhysics/PHShellNetState.cpp b/xrPhysics/PHShellNetState.cpp new file mode 100644 index 00000000000..2f6d3c63d48 --- /dev/null +++ b/xrPhysics/PHShellNetState.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" +#include "physicsshell.h" +#include "phinterpolation.h" +#include "phobject.h" +#include "phworld.h" +#include "phshell.h" + +void CPHShell::net_Import(NET_Packet& P) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i) + { + (*i)->net_Import(P); + } +} + +void CPHShell::net_Export(NET_Packet& P) +{ + ELEMENT_I i=elements.begin(),e=elements.end(); + for(;i!=e;++i) + { + (*i)->net_Export(P); + } +} \ No newline at end of file diff --git a/xrPhysics/PHShellSplitter.cpp b/xrPhysics/PHShellSplitter.cpp new file mode 100644 index 00000000000..817e679c9ae --- /dev/null +++ b/xrPhysics/PHShellSplitter.cpp @@ -0,0 +1,537 @@ +#include "stdafx.h" +#include "Physics.h" +#include "PHShell.h" +#include "PHShellSplitter.h" +#include "PHFracture.h" +#include "PHJointDestroyInfo.h" +#include "Geometry.h" +#include "MathUtils.h" +#include "../Include/xrRender/Kinematics.h" +#include "PHCollideValidator.h" +#include "ph_valid_ode.h" +CPHShellSplitterHolder::CPHShellSplitterHolder(CPHShell* shell) +{ + m_pShell=shell; + m_has_breaks=false; + m_unbreakable=false; +} + +CPHShellSplitterHolder::~CPHShellSplitterHolder() +{ + Deactivate(); + m_splitters.clear(); + m_geom_root_map.clear(); +} +//the simpliest case - a joint to be destroied +shell_root CPHShellSplitterHolder::SplitJoint(u16 aspl) +{ + //create _new physics shell + + CPhysicsShell *new_shell=P_create_Shell(); + CPHShell *new_shell_desc=smart_cast(new_shell); + new_shell_desc->mXFORM.set(m_pShell->mXFORM); + new_shell_desc->m_object_in_root.set(m_pShell->m_object_in_root); + SPLITTER_I splitter=m_splitters.begin()+aspl; + u16 start_element=splitter->m_element; + u16 start_joint=splitter->m_joint; + + u16 end_element=m_pShell->joints[start_joint]->JointDestroyInfo()->m_end_element; + u16 end_joint=m_pShell->joints[start_joint]->JointDestroyInfo()->m_end_joint; + + + shell_root ret = mk_pair(new_shell,(m_pShell->joints[start_joint])->BoneID()); + + + + CShellSplitInfo split_inf; + split_inf.m_bone_id=m_pShell->joints[start_joint]->BoneID(); + split_inf.m_start_el_num=start_element; + split_inf.m_end_el_num=end_element; + split_inf.m_start_jt_num=start_joint; + split_inf.m_end_jt_num=end_joint; + + m_splitters.erase(splitter); + PassEndSplitters(split_inf,new_shell_desc,1,0); + + InitNewShell(new_shell_desc); + m_pShell->PassEndElements(start_element,end_element,new_shell_desc); + m_pShell->PassEndJoints(start_joint+1,end_joint,new_shell_desc); + new_shell_desc->set_PhysicsRefObject(0); + new_shell_desc->PureActivate(); + //new_shell_desc->ObjectInRoot().identity(); + m_pShell->DeleteJoint(start_joint); + new_shell->set_ObjectContactCallback(NULL); + new_shell->set_PhysicsRefObject(NULL); + return ret; +} + +void CPHShellSplitterHolder::PassEndSplitters(const CShellSplitInfo& spl_inf,CPHShell* dest,u16 jt_add_shift,u16 el_add_shift) +{ + + + CPHShellSplitterHolder* &dest_holder=dest->m_spliter_holder; + if(!dest_holder)dest_holder=xr_new(dest); + + ELEMENT_STORAGE &source_elements=m_pShell->elements; + ELEMENT_STORAGE &dest_elements=dest->elements; + ELEMENT_I i_elem=source_elements.begin(),e_elem=source_elements.begin()+spl_inf.m_start_el_num; + u16 shift_e=spl_inf.m_end_el_num-spl_inf.m_start_el_num; + u16 shift_j=spl_inf.m_end_jt_num-spl_inf.m_start_jt_num; + + R_ASSERT2(source_elements.size()>=spl_inf.m_start_el_num&&source_elements.size()>=spl_inf.m_end_el_num,"wrong spl_inf"); + + + for(;i_elem!=e_elem;++i_elem) //until start elem in both joint or elem split fractures + //end elems have to be corrected + //if grater then end elem in moving diapason + { + CPHFracturesHolder *fracturesHolder=(*i_elem)->FracturesHolder(); + if(!fracturesHolder) continue; + FRACTURE_I f_i=fracturesHolder->m_fractures.begin(),f_e=fracturesHolder->m_fractures.end(); + for(;f_i!=f_e;++f_i) + { + + u16 &end_el_num=f_i->m_end_el_num; + u16 &start_el_num=f_i->m_start_el_num; + if(end_el_num>=spl_inf.m_end_el_num) end_el_num=end_el_num-shift_e; + if(start_el_num>=spl_inf.m_end_el_num) start_el_num=start_el_num-shift_e; + + u16 &end_jt_num=f_i->m_end_jt_num; + u16 &start_jt_num=f_i->m_start_jt_num; + if(end_jt_num>=spl_inf.m_end_jt_num) end_jt_num=end_jt_num-shift_j; + if(start_jt_num>=spl_inf.m_end_jt_num) start_jt_num=start_jt_num-shift_j; + } + } + + //same for joints + JOINT_STORAGE &source_joints=m_pShell->joints; + JOINT_I i_joint=source_joints.begin(),e_joint; + if(u16(-1)!=spl_inf.m_start_jt_num) + { + R_ASSERT2(source_joints.size()>=spl_inf.m_start_jt_num&&source_joints.size()>=spl_inf.m_end_jt_num,"wrong spl_inf"); + e_joint=source_joints.begin()+spl_inf.m_start_jt_num; + for(;i_joint!=e_joint;i_joint++) + { + CPHJointDestroyInfo* jointDestroyInfo=(*i_joint)->JointDestroyInfo(); + if(!jointDestroyInfo) continue; + u16 &end_element = jointDestroyInfo->m_end_element; + if(end_element>=spl_inf.m_end_el_num) end_element=end_element-shift_e; + u16 &end_joint = jointDestroyInfo->m_end_joint; + if(end_joint>=spl_inf.m_end_jt_num) end_joint=end_joint-shift_j; + } + } + + + //now process diapason that tobe unsplited + + e_elem=source_elements.begin()+spl_inf.m_end_el_num; + u16 passed_shift_e=spl_inf.m_start_el_num-u16(dest_elements.size()); + u16 passed_shift_j = u16(-1) & (spl_inf.m_start_jt_num + jt_add_shift); + for(;i_elem!=e_elem;++i_elem) + + { + CPHFracturesHolder *fracturesHolder=(*i_elem)->FracturesHolder(); + if(!fracturesHolder) continue; + FRACTURE_I f_i=fracturesHolder->m_fractures.begin(),f_e=fracturesHolder->m_fractures.end(); + for(;f_i!=f_e;++f_i) + { + u16 &end_el_num=f_i->m_end_el_num; + u16 &start_el_num=f_i->m_start_el_num; + end_el_num=end_el_num-passed_shift_e; + start_el_num=start_el_num-passed_shift_e; + + u16 &end_jt_num=f_i->m_end_jt_num; + u16 &start_jt_num=f_i->m_start_jt_num; + end_jt_num=end_jt_num-passed_shift_j; + start_jt_num=start_jt_num-passed_shift_j; + } + } + +//////correct data in fractures for elements allready added to dest with fractures from source/////// +ELEMENT_I i_dest_elem=dest_elements.begin(),e_dest_elem=dest_elements.end(); +for(;i_dest_elem!=e_dest_elem;++i_dest_elem) +{ + CPHFracturesHolder *fracturesHolder=(*i_dest_elem)->FracturesHolder(); + if(!fracturesHolder) continue; + FRACTURE_I f_i=fracturesHolder->m_fractures.begin(),f_e=fracturesHolder->m_fractures.end(); + for(;f_i!=f_e;f_i++) + { + u16 &end_el_num=f_i->m_end_el_num; + u16 &start_el_num=f_i->m_start_el_num; + end_el_num=end_el_num-passed_shift_e; + start_el_num=start_el_num-passed_shift_e; + + u16 &end_jt_num=f_i->m_end_jt_num; + u16 &start_jt_num=f_i->m_start_jt_num; + end_jt_num=end_jt_num-passed_shift_j; + start_jt_num=start_jt_num-passed_shift_j; + } +} +///////////////////////////////////////////////////////////////////////////////////////////////////// + +if(spl_inf.m_end_jt_num!=u16(-1)) +{ + e_joint=source_joints.begin()+spl_inf.m_end_jt_num; + for(;i_joint!=e_joint;++i_joint) + { + CPHJointDestroyInfo* jointDestroyInfo=(*i_joint)->JointDestroyInfo(); + if(!jointDestroyInfo) continue; + u16 &end_element = jointDestroyInfo->m_end_element; + u16 &end_joint = jointDestroyInfo->m_end_joint; + end_element=end_element-passed_shift_e; + end_joint=end_joint-passed_shift_j; + } +} + //the rest unconditionaly shift end & begin + e_elem=source_elements.end(); + for(;i_elem!=e_elem;++i_elem) + + { + CPHFracturesHolder *fracturesHolder=(*i_elem)->FracturesHolder(); + if(!fracturesHolder) continue; + FRACTURE_I f_i=fracturesHolder->m_fractures.begin(),f_e=fracturesHolder->m_fractures.end(); + for(;f_i!=f_e;++f_i) + { + u16 &end_el_num=f_i->m_end_el_num; + u16 &start_el_num=f_i->m_start_el_num; + end_el_num=end_el_num-shift_e; + start_el_num=start_el_num-shift_e; + + u16 &end_jt_num=f_i->m_end_jt_num; + u16 &start_jt_num=f_i->m_start_jt_num; + end_jt_num=end_jt_num-shift_j; + start_jt_num=start_jt_num-shift_j; + } + } + + e_joint=source_joints.end(); + for(;i_joint!=e_joint;++i_joint) + { + CPHJointDestroyInfo* jointDestroyInfo=(*i_joint)->JointDestroyInfo(); + if(!jointDestroyInfo) continue; + u16 &end_element = jointDestroyInfo->m_end_element; + u16 &end_joint = jointDestroyInfo->m_end_joint; + if(end_element>spl_inf.m_end_el_num) end_element=end_element-shift_e; + if(end_joint>spl_inf.m_end_jt_num) end_joint=end_joint-shift_j; + } + // at rest!! pass splitters it is very similar passing fractures + // correct data for splitters before passed and find start splitter to pass + SPLITTER_I spl_e=m_splitters.end(),spl_i=m_splitters.begin(); + for(;spl_i!=spl_e;++spl_i) + { + u16 &elem = spl_i->m_element; + u16 &joint = spl_i->m_joint; + if(spl_i->m_type==CPHShellSplitter::splElement) + { + if( elem!=u16(-1) && elem>=spl_inf.m_start_el_num) break;//we at begining + } + else + { + if( joint!=u16(-1) && joint>=spl_inf.m_start_jt_num) break;//we at begining + } + if(elem!=u16(-1) && elem>spl_inf.m_end_el_num) elem=elem-shift_e; + if(joint!=u16(-1) && joint>spl_inf.m_end_jt_num) joint=joint-shift_j; + } + SPLITTER_I i_from = spl_i; + //correct data for passing splitters and find last splitter to pass + for(;spl_i!=spl_e;++spl_i) + { + u16 &elem = spl_i->m_element; + u16 &joint = spl_i->m_joint; + if(spl_i->m_type==CPHShellSplitter::splElement) + { + if(elem!=u16(-1) && elem>=spl_inf.m_end_el_num) break;//we after begining + } + else + { + if(joint!=u16(-1) && joint>=spl_inf.m_end_jt_num) break;//we after begining + } + if(elem!=u16(-1) ) elem=elem-passed_shift_e; + if(joint!=u16(-1)) joint=joint-passed_shift_j; + + } + + SPLITTER_I i_to = spl_i; + + //corect data for all rest splitters + for(;spl_i!=spl_e;++spl_i) + { + u16 &elem = spl_i->m_element; + u16 &joint = spl_i->m_joint; + if(elem!=u16(-1)) elem=elem-shift_e; + if(joint!=u16(-1)) joint=joint-shift_j; + } + + dest_holder->m_splitters.insert(dest_holder->m_splitters.end(),i_from,i_to); + m_splitters.erase(i_from,i_to); +} + +static ELEMENT_PAIR_VECTOR new_elements; +DEFINE_VECTOR(Fmatrix,TRANSFORM_VECTOR,TRANSFORM_I) +static TRANSFORM_VECTOR bones_bind_forms; +shell_root CPHShellSplitterHolder::ElementSingleSplit(const element_fracture &split_elem,const CPHElement* source_element) +{ + + //const CPHShellSplitter& splitter=m_splitters[aspl]; + //CPHElement* element=m_pShell->elements[splitter.m_element]; + CPhysicsShell *new_shell_last=P_create_Shell(); + CPHShell *new_shell_last_desc=smart_cast(new_shell_last); + new_shell_last->mXFORM.set(m_pShell->mXFORM); const u16 start_joint=split_elem.second.m_start_jt_num; + R_ASSERT(_valid(new_shell_last->mXFORM)); + const u16 end_joint=split_elem.second.m_end_jt_num; + //it is not right for multiple joints attached to the unsplited part becource all these need to be reattached + if(start_joint!=end_joint) + { + JOINT_STORAGE& joints=m_pShell->joints; + JOINT_I i=joints.begin()+ start_joint,e=joints.begin()+ end_joint; + for(;i!=e;++i) + { + + CPHJoint* joint=(*i); + if(joint->PFirst_element()==source_element) + { + IKinematics* K = m_pShell->PKinematics(); + dVector3 safe_pos1, safe_pos2; + dQuaternion safe_q1, safe_q2; + //CPhysicsElement* el1=cast_PhysicsElement(split_elem.first),*el2=joint->PSecond_element(); + VERIFY(smart_cast(joint->PSecond_element())); + + CPHElement* el1=(split_elem.first),*el2= static_cast( joint->PSecond_element() ); + + dBodyID body1=el1->get_body(), body2=el2->get_body(); + dVectorSet(safe_pos1,dBodyGetPosition(body1)); + dVectorSet(safe_pos2,dBodyGetPosition(body2)); + + dQuaternionSet(safe_q1,dBodyGetQuaternion(body1)); + dQuaternionSet(safe_q2,dBodyGetQuaternion(body2)); + + //m_pShell->PlaceBindToElForms(); + + K->LL_GetBindTransform(bones_bind_forms); + el1->SetTransform(bones_bind_forms[el1->m_SelfID], mh_unspecified ); + el2->SetTransform(bones_bind_forms[el2->m_SelfID], mh_unspecified ); + joint->ReattachFirstElement(split_elem.first); + + dVectorSet(const_cast(dBodyGetPosition(body1)),safe_pos1); + dVectorSet(const_cast(dBodyGetPosition(body2)),safe_pos2); + + dQuaternionSet(const_cast(dBodyGetQuaternion(body1)),safe_q1); + dQuaternionSet(const_cast(dBodyGetQuaternion(body2)),safe_q2); + + dBodySetPosition(body1,safe_pos1[0],safe_pos1[1],safe_pos1[2]); + dBodySetPosition(body2,safe_pos2[0],safe_pos2[1],safe_pos2[2]); + dBodySetQuaternion(body1,safe_q1); + dBodySetQuaternion(body2,safe_q2); + } + } + // m_pShell->joints[split_elem.second.m_start_jt_num]->ReattachFirstElement(split_elem.first); + } + + //the last new shell will have all splitted old elements end joints and one new element reattached to old joint + //m_splitters.erase(m_splitters.begin()+aspl); + //now aspl points to the next splitter + if((split_elem.first)->FracturesHolder())//if this element can be splitted add a splitter for it + new_shell_last_desc->AddSplitter(CPHShellSplitter::splElement,0,u16(-1));// + + new_shell_last_desc->add_Element(split_elem.first); + //pass splitters taking into account that one element was olready added + PassEndSplitters(split_elem.second,new_shell_last_desc,0,0); + + + InitNewShell(new_shell_last_desc); + m_pShell->PassEndElements(split_elem.second.m_start_el_num,split_elem.second.m_end_el_num,new_shell_last_desc); + + + + m_pShell->PassEndJoints(split_elem.second.m_start_jt_num,split_elem.second.m_end_jt_num,new_shell_last_desc); + new_shell_last_desc->set_PhysicsRefObject(0); +///////////////////temporary for initialization set old Kinematics in new shell///////////////// + new_shell_last->set_Kinematics(m_pShell->PKinematics()); + new_shell_last_desc->AfterSetActive(); + new_shell_last->set_Kinematics(NULL); + VERIFY2(split_elem.second.m_bone_id<64,"strange root"); + VERIFY(_valid(new_shell_last->mXFORM)); + VERIFY(dBodyStateValide(source_element->get_bodyConst())); + VERIFY(dBodyStateValide(split_elem.first->get_body())); + new_shell_last->set_ObjectContactCallback(NULL); + new_shell_last->set_PhysicsRefObject(NULL); + return mk_pair(new_shell_last,split_elem.second.m_bone_id); + +} + + +IC void correct_diapasones(ELEMENT_PAIR_VECTOR& element_pairs) +{ + ELEMENT_PAIR_I i,b=element_pairs.begin(),e=element_pairs.end(); + + for(i=b;i!=e;++i) + { + ELEMENT_PAIR_I j=i+1; + for(;j!=e;++j) + { + j->second.sub_diapasone(CShellSplitInfo(i->second)); + } + + } + +} + +void CPHShellSplitterHolder::SplitElement(u16 aspl,PHSHELL_PAIR_VECTOR &out_shels) +{ + + new_elements.clear(); + SPLITTER_I spl_i=(m_splitters.begin()+aspl); + CPHElement* E= m_pShell->elements[spl_i->m_element]; + E->SplitProcess(new_elements); + + correct_diapasones(new_elements); + + ELEMENT_PAIR_I i=new_elements.begin(),e=new_elements.end(); + + for(;i!=e;++i) + { + out_shels.push_back(ElementSingleSplit(*i,E)); + CPhysicsElement* ee = out_shels.back().first->get_ElementByStoreOrder(0); + VERIFY( ee ); + VERIFY( smart_cast(ee) ); + CPHElement * e = static_cast (ee); + VERIFY(dBodyStateValide(e->get_body())); + } + + if(!E->FracturesHolder()) m_splitters.erase(spl_i);//delete splitter if the element no longer have fractures + else spl_i->m_breaked=false;//it is no longer breaked + +} + +void CPHShellSplitterHolder::SplitProcess(PHSHELL_PAIR_VECTOR &out_shels) +{ + //any split process must start from the end of the elment storage + //this based on that all childs in the bone hierarchy was added after their parrent + + u16 i=u16(m_splitters.size()-1); + for(;u16(-1)!=i;--i) + { + if(m_splitters[i].m_breaked) + switch(m_splitters[i].m_type) + { + case CPHShellSplitter::splJoint: + out_shels.push_back(SplitJoint(i)); + + break; + case CPHShellSplitter::splElement: + SplitElement(i,out_shels); + break; + default: NODEFAULT; + } + } + //VERIFY(dBodyStateValide(out_shels.back().first->get_ElementByStoreOrder(0)->get_body())); + m_has_breaks=false; +} +void CPHShellSplitterHolder::InitNewShell(CPHShell* shell) +{ + shell->PresetActive(); + if(m_pShell->IsGroupObject()) + CPHCollideValidator::RegisterObjToGroup(m_pShell->collide_bits(),*static_cast(shell)); +} + +void CPHShellSplitterHolder::PhTune(dReal step) +{ + SPLITTER_I i=m_splitters.begin(),e=m_splitters.end(); + for(;i!=e;++i) + { + switch(i->m_type) + { + case CPHShellSplitter::splElement: + { + CPHElement* element=m_pShell->elements[i->m_element]; + element->FracturesHolder()->PhTune(element->get_body()); + break; + } + case CPHShellSplitter::splJoint: + { + break; + } + default: NODEFAULT; + } + } +} +void CPHShellSplitterHolder::PhDataUpdate(dReal step) +{ + SPLITTER_I i=m_splitters.begin(),e=m_splitters.end(); + for(;i!=e;++i) + { + switch(i->m_type) + { + case CPHShellSplitter::splElement: + { + CPHElement* element=m_pShell->elements[i->m_element]; + dBodyID body=element->get_body();//!element->EnabledStateOnStep() + if(!dBodyIsEnabled(body)) return;// + i->m_breaked=(element->FracturesHolder()->PhDataUpdate(element))||i->m_breaked; + break; + } + case CPHShellSplitter::splJoint: + { + CPHJoint *j=m_pShell->joints[i->m_joint]; + //if(j->bActive) + i->m_breaked=j->JointDestroyInfo()->Update()||i->m_breaked; + break; + } + default: NODEFAULT; + } + m_has_breaks=m_has_breaks||i->m_breaked; + } +} +void CPHShellSplitterHolder::Activate() +{ + if(m_unbreakable) return; + CPHUpdateObject::Activate(); + if(m_pShell->isActive())PhTune(fixed_step); +} + +void CPHShellSplitterHolder::Deactivate() +{ + CPHUpdateObject::Deactivate(); +} +void CPHShellSplitterHolder::AddSplitter(CPHShellSplitter::EType type,u16 element,u16 joint) +{ + m_splitters.push_back(CPHShellSplitter(type,element,joint)); +} +void CPHShellSplitterHolder::AddSplitter(CPHShellSplitter::EType type,u16 element,u16 joint,u16 position) +{ + m_splitters.insert(m_splitters.begin()+position,CPHShellSplitter(type,element,joint)); +} +CPHShellSplitter::CPHShellSplitter(CPHShellSplitter::EType type,u16 element,u16 joint) +{ + m_breaked=false; + m_type=type; + m_element=element; + m_joint=joint; +} + +void CPHShellSplitterHolder::AddToGeomMap(const id_geom& id_rootgeom) +{ + m_geom_root_map.insert(id_rootgeom); +} + +u16 CPHShellSplitterHolder::FindRootGeom(u16 bone_id) +{ + GEOM_MAP_I iter=m_geom_root_map.find(bone_id); + if(iter==m_geom_root_map.end()) return u16(-1); + + return iter->second->element_position(); + +} +void CPHShellSplitterHolder::SetUnbreakable() +{ + Deactivate();m_unbreakable=true; +} +void CPHShellSplitterHolder::SetBreakable() +{ + m_unbreakable=false;if(m_pShell->isEnabled())Activate(); +} +CPHShellSplitter::CPHShellSplitter() +{ + m_breaked=false; +} + diff --git a/xrPhysics/PHShellSplitter.h b/xrPhysics/PHShellSplitter.h new file mode 100644 index 00000000000..1588bfa9c0f --- /dev/null +++ b/xrPhysics/PHShellSplitter.h @@ -0,0 +1,69 @@ +#ifndef PHSHELL_SPLITTER_H +#define PHSHELL_SPLITTER_H +#include "PHDefs.h" +//#include "PHObject.h" +#include "PHFracture.h" +#include "phupdateobject.h" +class CPHShellSplitter; + +class CPHShell; +class CODEGeom; +typedef std::pair id_geom; +DEFINE_MAP(u16,CODEGeom*,GEOM_MAP,GEOM_MAP_I) + +class CPHShellSplitter +{ + friend class CPHShellSplitterHolder; + friend class CPHShell; + +public: + enum EType {splElement,splJoint} ; +private: + bool m_breaked ; + EType m_type ; + u16 m_element ; + u16 m_joint ; + CPHShellSplitter (CPHShellSplitter::EType type,u16 element,u16 joint) ; + CPHShellSplitter () ; +}; + +DEFINE_VECTOR(CPHShellSplitter,SPLITTER_STORAGE,SPLITTER_I) +typedef xr_vector::reverse_iterator SPLITTER_RI; + + +class CPHShellSplitterHolder : public CPHUpdateObject //call all Fractures and Breakable Joints Updates +{ +friend class CPHShell; +bool m_has_breaks ; +bool m_unbreakable ; +CPHShell* m_pShell ; //purpose: to extract elements and joints corresponded splitters +SPLITTER_STORAGE m_splitters ; // +GEOM_MAP m_geom_root_map ; //to find geom pointer by bone id +virtual void PhTune (dReal step) ; //call fractures PhTune for element splitters m_pShell->m_elements[m_splitters[i]->m_element]->m_pFracturesHolder->PhTune() +virtual void PhDataUpdate (dReal step) ; //call fractures PhDataUpdate for element splitters m_pShell->m_elements[m_splitters[i]->m_element]->m_pFracturesHolder->PhDataUpdate() + bool CheckSplitter (u16 aspl) ; // + shell_root SplitJoint (u16 aspl) ; //create new shell moving into it departed elements and joints + shell_root ElementSingleSplit (const element_fracture &split_elem,const CPHElement* source_element) ; + void SplitElement (u16 aspl,PHSHELL_PAIR_VECTOR &out_shels) ;// + void PassEndSplitters (const CShellSplitInfo& spl_inf,CPHShell* dest,u16 jt_add_shift,u16 el_add_shift) ; + void InitNewShell (CPHShell* shell) ; //inits new active shell +public: + CPHShellSplitterHolder (CPHShell* shell) ; +virtual ~CPHShellSplitterHolder () ; + void Activate () ; + void Deactivate () ; + void AddSplitter (CPHShellSplitter::EType type,u16 element,u16 joint) ; + void AddSplitter (CPHShellSplitter::EType type,u16 element,u16 joint,u16 position) ; + void SplitProcess (PHSHELL_PAIR_VECTOR &out_shels) ; + void AddToGeomMap (const id_geom& id_rootgeom) ; + u16 FindRootGeom (u16 bone_id) ; +IC bool Breaked () {return m_has_breaks;} +IC bool isEmpty () {return m_splitters.empty() ;} + void SetUnbreakable () ; + void SetBreakable () ; + bool IsUnbreakable () {return m_unbreakable ;} +}; + + + +#endif \ No newline at end of file diff --git a/xrPhysics/PHSimpleCharacter.cpp b/xrPhysics/PHSimpleCharacter.cpp new file mode 100644 index 00000000000..0b41bb3a360 --- /dev/null +++ b/xrPhysics/PHSimpleCharacter.cpp @@ -0,0 +1,2039 @@ +#include "stdafx.h" + +#include "PHDynamicData.h" +#include "ExtendedGeom.h" +#include "../xrEngine/cl_intersect.h" +#include "../xrEngine/xr_object_list.h" +#include "tri-colliderKNoOPC\__aabb_tri.h" +#include "PHSimpleCharacter.h" +#include "PHContactBodyEffector.h" +//#include "ui/uistatic.h" +#include "SpaceUtils.h" +//#include "PhysicsGamePars.h" +#include "params.h" +#include "MathUtils.h" +//#include "level.h" +#include "../xrEngine/gamemtllib.h" +//#include "gameobject.h" +#include "iphysicsshellholder.h" +#include "../Include/xrRender/Kinematics.h" +#include "PHSimpleCharacterInline.h" +#include "DamageSource.h" +#include "PHCollideValidator.h" +#include "CalculateTriangle.h" +//#include "game_base_space.h" +#include "geometry.h" + +//#include "phvalide.h" + +#include "../xrengine/bone.h" +#include "../xrengine/xr_object.h" +#include "ph_valid_ode.h" + +IC bool PhOutOfBoundaries (const Fvector& v) +{ + return v.y < phBoundaries.y1; +} +//#ifdef DEBUG +//# include "debug_renderer.h" +//#endif + +const float LOSE_CONTROL_DISTANCE=0.5f; //fly distance to lose control +const float CLAMB_DISTANCE=0.5f; +const float CLIMB_GETUP_HEIGHT=0.3f; + +float IC sgn(float v) +{ + return v<0.f ? -1.f:1.f; +} +bool test_sides(const Fvector ¢er,const Fvector &side_dir,const Fvector &fv_dir,const Fvector &box,int tri_id) +{ + Triangle tri; + CalculateInitTriangle( inl_ph_world().ObjectSpace().GetStaticTris()+tri_id, tri,inl_ph_world().ObjectSpace().GetStaticVerts() ); + Fvector* verts=inl_ph_world().ObjectSpace().GetStaticVerts(); + { + float dist=cast_fv(tri.norm).dotproduct(center)-tri.dist; + //if(dist<0.f)return false; + //////////////////////////////////////////////tri norm + float fvn=cast_fv(tri.norm).dotproduct(fv_dir);float sg_fvn= sgn(fvn); + float sdn=cast_fv(tri.norm).dotproduct(side_dir);float sg_sdn= sgn(sdn); + if(sg_fvn*fvn*box.z+sg_sdn*sdn*box.x+_abs(tri.norm[1])*box.y>_abs(dist))return false; + } + { + + ///////////////////////////////////////////////side/////////////////////////////////////////////////////////////////////////////////////////////////// + float sdc=side_dir.dotproduct(center); + float sd0=cast_fv(tri.side0).dotproduct(side_dir);float sg_sd0=sgn(sd0); + float sd1=cast_fv(tri.side1).dotproduct(side_dir);float sg_sd1=sgn(sd1); + float abs_sd0=sg_sd0*sd0; + float abs_sd1=sg_sd1*sd1; + + float sd,abs_sd,sg_sd; + u32 v; + if(sg_sd0==sg_sd1) + { + sd=-sd0-sd1; + abs_sd=abs_sd0+abs_sd1; + sg_sd=-sg_sd0; + v=tri.T->verts[2]; + }else if(abs_sd0>abs_sd1) + { + sd=sd0;abs_sd=abs_sd0;sg_sd=sg_sd0; + v=tri.T->verts[0]; + }else + { + sd=sd1;abs_sd=abs_sd1;sg_sd=sg_sd1; + v=tri.T->verts[1]; + } + + float vp=side_dir.dotproduct(verts[v]); + float dist=vp-sdc; + float sg_dist=sgn(dist); + float abs_dist=sg_dist*dist; + + if(sg_dist!=sg_sd) + { + if(abs_dist-abs_sd>box.x)return false; + }else + { + if(abs_dist>box.x) return false; + } + } +////sides cross/////////////////////////////////////////////////////////////////////////////////////////////// + Fvector crses[3]; + crses[0].set(-tri.side0[2],0,tri.side0[0]); + crses[1].set(-tri.side1[2],0,tri.side1[0]); + const Fvector& v2=verts[tri.T->verts[2]]; + const Fvector& v0=verts[tri.T->verts[0]]; + crses[2].x=-(v0.z-v2.z); + crses[2].y=0.f; + crses[2].z=v0.x-v2.x; + for(u8 i=0;3>i;++i) + { + const Fvector &crs=crses[i]; + u32 sv=tri.T->verts[i%3]; + u32 ov=tri.T->verts[(i+2)%3]; + + float c_prg=crs.dotproduct(center); + float sv_prg=crs.dotproduct(verts[sv]); + float ov_prg=crs.dotproduct(verts[ov]); + float dist=c_prg-sv_prg; + float sg_dist=sgn(dist); + if(sgn(ov_prg-c_prg)!=sg_dist) + { + if(_abs(fv_dir.dotproduct(crs))*box.z+_abs(side_dir.dotproduct(crs))*box.x(retrieveGeomUserData(c.geom.g1)->ph_object); + }else + { + ch=static_cast(retrieveGeomUserData(c.geom.g2)->ph_object); + } + VERIFY(ch); + ch->b_side_contact=true; +} + +void CPHSimpleCharacter::SetBox(const dVector3 &sizes) +{ + m_radius=_min(sizes[0],sizes[2])/2.f; + m_cyl_hight=sizes[1]-2.f*m_radius; + if (m_cyl_hight<0.f) m_cyl_hight=0.01f; + const dReal k=1.20f; + dReal doun=m_radius*_sqrt(1.f-1.f/k/k)/2.f; + //m_geom_shell=dCreateCylinder(0,m_radius/k,m_cyl_hight+doun); + dGeomCylinderSetParams(m_geom_shell,m_radius/k,m_cyl_hight+doun); + //m_wheel=dCreateSphere(0,m_radius); + dGeomSphereSetRadius(m_wheel,m_radius); + //m_hat=dCreateSphere(0,m_radius/k); + dGeomSphereSetRadius(m_hat,m_radius/k); + + dGeomSetPosition(m_hat,0.f,m_cyl_hight,0.f); + dGeomSetPosition(m_geom_shell,0.f,m_cyl_hight/2.f-doun,0.f); + + float test_radius=m_radius*2.f; + float test_height=test_radius+m_radius/2.f; + //m_cap=dCreateSphere(0,test_radius); + dGeomSphereSetRadius(m_cap,test_radius); + dGeomSetPosition(m_cap,0.f,test_height,0.f); +} +void CPHSimpleCharacter::get_Box ( Fvector& sz, Fvector& c )const +{ + float r,h; + dGeomCylinderGetParams( m_geom_shell, &r, &h ); + sz.set( 2*r, 2*r + h, 2*r ); + const dReal *rot =NULL ; + const dReal *pos =NULL ; + dMatrix3 rr ; + CODEGeom::get_final_tx( m_shell_transform,pos, rot, cast_fp( c ), rr ); +} + +void CPHSimpleCharacter::Create(dVector3 sizes){ + + if(b_exist) return; + + b_air_contact_state = false ; + lastMaterialIDX = GAMEMTL_NONE_IDX ; + injuriousMaterialIDX= GAMEMTL_NONE_IDX ; + m_creation_step = ph_world->m_steps_num; + //////////////////////////////////////////////////////// + + m_radius=_min(sizes[0],sizes[2])/2.f; + m_current_object_radius=m_radius; + m_cyl_hight=sizes[1]-2.f*m_radius; + if (m_cyl_hight<0.f) m_cyl_hight=0.01f; + + b_exist=true; + const dReal k=1.20f; + dReal doun=m_radius*_sqrt(1.f-1.f/k/k)/2.f; + + m_geom_shell=dCreateCylinder(0,m_radius/k,m_cyl_hight+doun); + + m_wheel=dCreateSphere(0,m_radius); + m_hat=dCreateSphere(0,m_radius/k); + + + + + m_shell_transform=dCreateGeomTransform(0); + dGeomTransformSetCleanup(m_shell_transform,0); + m_hat_transform=dCreateGeomTransform(0); + dGeomTransformSetCleanup(m_hat_transform,0); + //m_wheel_transform=dCreateGeomTransform(0); + + dGeomTransformSetInfo(m_shell_transform,1); + dGeomTransformSetInfo(m_hat_transform,1); + //dGeomTransformSetInfo(m_wheel_transform,1); + //////////////////////////////////////////////////////////////////////// + + + dGeomSetPosition(m_hat,0.f,m_cyl_hight,0.f); + //////////////////////////////////////////////////////////////////////// + + //dGeomSetPosition(chSphera2,0.f,-0.7f,0.f); + + //////////////////////////////////////////////////////////////////////// + dGeomSetPosition(m_geom_shell,0.f,m_cyl_hight/2.f-doun,0.f); + + dGeomTransformSetGeom(m_hat_transform,m_hat); + + dGeomTransformSetGeom(m_shell_transform,m_geom_shell); + m_body=dBodyCreate(0); + Island().AddBody(m_body); + + dGeomSetBody(m_shell_transform,m_body); + dGeomSetBody(m_hat_transform,m_body); + dGeomSetBody(m_wheel,m_body); + + dGeomCreateUserData(m_geom_shell); + + dGeomCreateUserData(m_wheel); + dGeomCreateUserData(m_hat); + + dGeomUserDataSetPhObject(m_wheel,(CPHObject*)this); + dGeomUserDataSetPhObject(m_geom_shell,(CPHObject*)this); + dGeomUserDataSetPhObject(m_hat,(CPHObject*)this); + + ///////////////////////////////////////////////////////////////////////// + dMass m; + dMassSetBox(&m,1,1000000.f,1000000.f,1000000.f); + dMassAdjust(&m,m_mass); + dBodySetMass(m_body,&m); + + m_space=dSimpleSpaceCreate(0); + //dGeomGroupAdd(m_geom_group,m_wheel_transform); + dSpaceAdd(m_space,m_wheel); + + dSpaceAdd(m_space,m_shell_transform); + dSpaceAdd(m_space,m_hat_transform); + //dGeomGroupAdd(chRGeomGroup,chRCylinder); + m_body_interpolation.SetBody(m_body); + + + + float test_radius=m_radius*2.f; + float test_height=test_radius+m_radius/2.f; + m_cap=dCreateSphere(0,test_radius); + dGeomSetPosition(m_cap,0.f,test_height,0.f); + m_cap_transform=dCreateGeomTransform(0); + dGeomTransformSetCleanup(m_cap_transform,0); + dGeomTransformSetInfo(m_cap_transform,1); + dGeomTransformSetGeom(m_cap_transform,m_cap); + dGeomCreateUserData(m_cap); + dGeomGetUserData(m_cap)->b_static_colide=false; + + dGeomUserDataSetPhObject(m_cap,(CPHObject*)this); + dSpaceAdd(m_space,m_cap_transform); + dGeomSetBody(m_cap_transform,m_body); + dGeomUserDataSetObjectContactCallback(m_cap,TestPathCallback); + dGeomGetUserData(m_cap)->b_static_colide=false; + if(m_phys_ref_object) + { + SetPhysicsRefObject(m_phys_ref_object); + } + if(m_object_contact_callback) + { + SetObjectContactCallback(m_object_contact_callback); + } + VERIFY( ph_world ); + SetStaticContactCallBack(ph_world->default_character_contact_shotmark()); + //SetStaticContactCallBack(CharacterContactShotMark); + m_elevator_state.SetCharacter(static_cast(this)); + CPHObject::activate(); + spatial_register(); + m_last_move.set(0,0,0) ; + CPHCollideValidator::SetCharacterClass(*this); + m_collision_damage_info.Construct(); + m_last_environment_update = Fvector().set( -FLT_MAX, -FLT_MAX, -FLT_MAX ); + m_last_picked_material = GAMEMTL_NONE_IDX; +} +void CPHSimpleCharacter::SwitchOFFInitContact() +{ + VERIFY(b_exist); + dGeomUserDataSetPhObject(m_wheel,0); + dGeomUserDataSetPhObject(m_geom_shell,0); + dGeomUserDataSetPhObject(m_hat,0); + b_lose_control=true; + b_any_contacts=false; + is_contact=false; + b_foot_mtl_check =true ; + b_on_ground=b_valide_ground_contact=false; +} +void CPHSimpleCharacter::SwitchInInitContact() +{ + VERIFY(b_exist); + dGeomUserDataSetPhObject(m_wheel,(CPHObject*)this); + dGeomUserDataSetPhObject(m_geom_shell,(CPHObject*)this); + dGeomUserDataSetPhObject(m_hat,(CPHObject*)this); + +} +void CPHSimpleCharacter::Destroy(){ + if(!b_exist) return; + b_exist=false; + R_ASSERT2(!ph_world->Processing(),"can not deactivate physics character shell during physics processing!!!");//if(ph_world) + R_ASSERT2(!ph_world->IsFreezed(),"can not deactivate physics character when ph world is freezed!!!"); + R_ASSERT2(!CPHObject::IsFreezed(),"can not deactivate freezed !!!"); + m_elevator_state.Deactivate(); + + spatial_unregister(); + CPHObject::deactivate(); + + + if(m_cap) { + dGeomDestroyUserData(m_cap); + dGeomDestroy(m_cap); + m_cap=NULL; + } + + if(m_cap_transform){ + dGeomDestroyUserData(m_cap_transform); + dGeomDestroy(m_cap_transform); + m_cap_transform=NULL; + } + + if(m_geom_shell){ + dGeomDestroyUserData(m_geom_shell); + dGeomDestroy(m_geom_shell); + m_geom_shell=NULL; + } + + if(m_wheel) { + dGeomDestroyUserData(m_wheel); + dGeomDestroy(m_wheel); + m_wheel=NULL; + } + + if(m_shell_transform){ + dGeomDestroyUserData(m_shell_transform); + dGeomDestroy(m_shell_transform); + m_shell_transform=NULL; + } + + + + + if(m_wheel_transform){ + dGeomDestroyUserData(m_wheel_transform); + dGeomDestroy(m_wheel_transform); + m_wheel_transform=NULL; + } + + + if(m_hat){ + dGeomDestroyUserData(m_hat); + dGeomDestroy(m_hat); + m_hat=NULL; + } + if(m_hat_transform){ + dGeomDestroyUserData(m_hat_transform); + dGeomDestroy(m_hat_transform); + m_hat_transform=NULL; + } + + if(m_space){ + dSpaceDestroy(m_space); + m_space=NULL; + } + + if(m_body) { + Island().RemoveBody(m_body); + dBodyDestroy(m_body); + m_body=NULL; + } + + +} +const static u64 impulse_time_constant=30; +void CPHSimpleCharacter::ApplyImpulse(const Fvector& dir,dReal P) +{ + if(!b_exist||b_external_impulse) return; + //if(!dBodyIsEnabled(m_body)) dBodyEnable(m_body); + m_ext_imulse.set(dir); + if(b_lose_control||b_jumping||b_jump) + { + //m_ext_imulse.y-=3.f ; + //m_ext_imulse.normalize_safe() ; + m_ext_imulse.set(0,-1,0); + //P*=0.3f ; + } + Enable(); + b_lose_control=true; + b_external_impulse=true; + m_ext_impuls_stop_step=ph_world->m_steps_num+impulse_time_constant; + //m_ext_imulse.set(Fvector().mul(dir,P/fixed_step/impulse_time_constant)); + dBodySetLinearVel(m_body,0,0,0); + dBodySetForce(m_body,m_ext_imulse.x*P/fixed_step,m_ext_imulse.y*P/fixed_step,m_ext_imulse.z*P/fixed_step); +} + +void CPHSimpleCharacter::ApplyForce(const Fvector& force) +{ + + ApplyForce(force.x,force.y,force.z); +} + +void CPHSimpleCharacter::ApplyForce(float x, float y, float z) +{ + if(!b_exist) return; + Enable(); + //if( !b_external_impulse ) + dBodyAddForce(m_body,x,y,z); + //BodyCutForce(m_body,5.f,0.f); +} + +void CPHSimpleCharacter::ApplyForce(const Fvector& dir,float force) +{ + ApplyForce(dir.x*force,dir.y*force,dir.z*force); +} + +void CPHSimpleCharacter::PhDataUpdate(dReal /**step/**/){ + /////////////////// + + + SafeAndLimitVelocity(); + + if( !dBodyIsEnabled(m_body)) { + if(!ph_world->IsFreezed())b_lose_control=false; + return; + } + if(is_contact&&!is_control&&!b_lose_ground) + Disabling(); + + + /////////////////////// + if(ph_world->m_steps_num>m_ext_impuls_stop_step) + { + b_external_impulse = false ; + m_ext_impuls_stop_step = u64(-1) ; + m_ext_imulse .set(0,0,0) ; + Fvector vel ; + GetVelocity (vel) ; + dVectorLimit (cast_fp(vel),m_max_velocity,cast_fp(vel)); + SetVelocity(Fvector().set(0,0,0)) ; + } + was_contact = is_contact ; + was_control = is_control ; + b_was_side_contact = b_side_contact ; + is_contact = false ; + b_side_contact = false ; + b_any_contacts = false ; + b_valide_ground_contact = false ; + b_valide_wall_contact = false ; + + + b_was_on_object = b_on_object ; + b_on_object = false ; + b_death_pos = false ; + m_contact_count = 0 ; + m_friction_factor = 0.f ; + b_collision_restrictor_touch= false ; + b_foot_mtl_check = true ; + b_depart_control = false ; + dMatrix3 R; + dRSetIdentity (R); + dBodySetAngularVel(m_body,0.f,0.f,0.f); + dBodySetRotation(m_body,R); + + dMass mass; + const float *linear_velocity =dBodyGetLinearVel(m_body); + dReal linear_velocity_mag =_sqrt(dDOT(linear_velocity,linear_velocity)); + dBodyGetMass(m_body,&mass); + dReal l_air=linear_velocity_mag*default_k_l;//force/velocity !!! + if(l_air>mass.mass/fixed_step) l_air=mass.mass/fixed_step;//validate + + if(!fis_zero(l_air)) + dBodyAddForce( + m_body, + -linear_velocity[0]*l_air, + -linear_velocity[1]*l_air, + -linear_velocity[2]*l_air + ); + if(b_non_interactive) + { + Disable(); + dBodySetPosition( m_body, m_last_move.x, m_last_move.y, m_last_move.z ); + } + m_last_move.sub(cast_fv(dBodyGetPosition(m_body)),m_last_move); + m_last_move.mul(1.f/fixed_step); + VERIFY2(dBodyStateValide(m_body),"WRONG BODYSTATE IN PhDataUpdate"); + if(PhOutOfBoundaries(cast_fv(dBodyGetPosition(m_body))))Disable(); + VERIFY_BOUNDARIES(cast_fv(dBodyGetPosition(m_body)),phBoundaries,PhysicsRefObject()); + m_body_interpolation.UpdatePositions(); +} + +void CPHSimpleCharacter::PhTune(dReal step){ + + //if(b_non_interactive) + //{ + // dGeomSetBody(m_shell_transform,m_body); + // dGeomSetBody(m_hat_transform,m_body); + // dGeomSetBody(m_wheel,m_body); + // dGeomSetBody(m_cap_transform,m_body); + //} + + m_last_move.set(cast_fv(dBodyGetPosition(m_body))); + m_elevator_state.PhTune(step); + + + + b_air_contact_state=!is_contact; + + +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgCharacterControl)) + { + if(b_air_contact_state) + debug_output().DBG_DrawPoint(cast_fv(dBodyGetPosition(m_body)),m_radius,D3DCOLOR_XRGB(255,0,0)); + + } +#endif + bool b_good_graund=b_valide_ground_contact&&m_ground_contact_normal[1]>M_SQRT1_2; + + dxGeomUserData *ud=dGeomGetUserData(m_wheel); + if((ud->pushing_neg||ud->pushing_b_neg)&&!b_death_pos) + { + b_death_pos=true; +//#ifdef DEBUG +// Msg("death pos %f2.2,%f2.2,%f2.2",ud->last_pos[0],ud->last_pos[1],ud->last_pos[2]); +//#endif + Fvector pos;pos.set(cast_fv(dBodyGetPosition(m_body))); + Fvector d;d.set(cast_fv(dBodyGetLinearVel(m_body)));d.mul(fixed_step); + pos.sub(d); + if(!ud->pushing_b_neg) + { + //Fvector movement;movement.sub(cast_fv(dGeomGetPosition(m_wheel)),cast_fv(ud->last_pos)); + + dVectorSet(m_death_position,cast_fp(pos)); + } + else + { + dVectorSet(m_death_position,cast_fp(pos)); + } + } + + if(b_death_pos&&!(ud->pushing_neg||ud->pushing_b_neg)) + { + b_death_pos=false; + } + + CPHContactBodyEffector* contact_effector= + (CPHContactBodyEffector*) dBodyGetData(m_body); + if(contact_effector)contact_effector->Apply(); + + if(!dBodyIsEnabled(m_body)) + { + if(!ph_world->IsFreezed())b_lose_control=false; + return; + } + + if(m_acceleration.magnitude()>0.1f) is_control=true; + else is_control=false; + + b_depart=was_contact&&(!is_contact); + b_stop_control=was_control&&(!is_control); + b_meet=(!was_contact)&&(is_contact); + if(b_lose_control&&(is_contact||m_elevator_state.ClimbingState())) + b_meet_control=true; + b_on_ground=b_valide_ground_contact ||(b_meet&&(!b_depart)); + + + if(m_elevator_state.ClimbingState()) + { + b_side_contact=false; + m_friction_factor=1.f; + if(b_stop_control) + dBodySetLinearVel(m_body,0.f,0.f,0.f); + } + + //save depart position + if(b_depart) + dVectorSet(m_depart_position,dBodyGetPosition(m_body)); + + const dReal* velocity=dBodyGetLinearVel(m_body); + dReal linear_vel_smag=dDOT(velocity,velocity); + if(b_lose_control && + ( + b_on_ground && + m_ground_contact_normal[1]>M_SQRT1_2/2.f + //&& +// !b_external_impulse + /*&& + dSqrt(velocity[0]*velocity[0]+velocity[2]*velocity[2])<5.*/|| + fis_zero(linear_vel_smag) || + m_elevator_state.ClimbingState() + ) + ) + b_lose_control=false; + + + if(b_jumping&&b_good_graund ||(m_elevator_state.ClimbingState()&&b_valide_wall_contact)) //b_good_graund=b_valide_ground_contact&&m_ground_contact_normal[1]>M_SQRT1_2 + b_jumping=false; + + //deside if control lost + if(!b_on_ground && !m_elevator_state.ClimbingState()) + { + const dReal* current_pos=dBodyGetPosition(m_body); + dVector3 dif={current_pos[0]-m_depart_position[0], + current_pos[1]-m_depart_position[1], + current_pos[2]-m_depart_position[2]}; + if(dDOT(dif,dif)> + LOSE_CONTROL_DISTANCE* + LOSE_CONTROL_DISTANCE&&dFabs(dif[1])>0.1) + { + b_lose_control=true; + b_depart_control=true; + } + } + + ValidateWalkOn(); + + //jump + if(b_jump) + { + b_lose_control=true; + b_depart_control = true; + dBodySetLinearVel(m_body,m_jump_accel.x,m_jump_accel.y,m_jump_accel.z);//vel[1]+ + //Log("jmp",m_jump_accel); + dVectorSet(m_jump_depart_position,dBodyGetPosition(m_body)); + //m_jump_accel=m_acceleration; + b_jump=false; + b_jumping=true; + m_elevator_state.Depart(); + Enable(); + } + + b_lose_ground=!(b_good_graund||m_elevator_state.ClimbingState())||b_lose_control; + + + + ApplyAcceleration(); + + + + dReal* chVel=const_cast(dBodyGetLinearVel(m_body)); + //if(b_jump) + // dBodyAddForce(m_body,0.f,m_control_force[1],0.f);//+2.f*9.8f*70.f + //else + dMass m; + dBodyGetMass(m_body,&m); + if(is_control){ + dVector3 sidedir; + dVector3 y={0.,1.,0.}; + dCROSS(sidedir,=,m_control_force,y); + accurate_normalize(sidedir); + dReal vProj=dDOT(sidedir,chVel); + + dBodyAddForce(m_body,m_control_force[0],m_control_force[1],m_control_force[2]);//+2.f*9.8f*70.f + if(!b_lose_control||b_clamb_jump)//)&&!b_external_impulse + dBodyAddForce(m_body, + -sidedir[0]*vProj*(500.f+200.f*b_clamb_jump)*m_friction_factor, + -m.mass*(50.f)*(!b_lose_control&&!(is_contact||(b_any_contacts))),//&&!b_climb + -sidedir[2]*vProj*(500.f+200.f*b_clamb_jump)*m_friction_factor + ); +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgCharacterControl)) + { + const Fvector dipsp = Fvector().set(0,0.02f,0); + debug_output().DBG_DrawLine(cast_fv(dBodyGetPosition(m_body)),Fvector().add(cast_fv(dBodyGetPosition(m_body)),Fvector().mul(cast_fv(sidedir),1.f)),D3DCOLOR_XRGB(0,0,255)); + debug_output().DBG_DrawLine(cast_fv(dBodyGetPosition(m_body)),Fvector().add(cast_fv(dBodyGetPosition(m_body)),Fvector().mul(cast_fv(m_control_force),1.f/1000.f)),D3DCOLOR_XRGB(0,0,255)); + debug_output().DBG_DrawLine(Fvector().add(cast_fv(dBodyGetPosition(m_body)),dipsp), + Fvector().add(Fvector().add(cast_fv(dBodyGetPosition(m_body)),dipsp),Fvector().mul(cast_fv(dBodyGetForce(m_body)),1.f/1000.f)),D3DCOLOR_XRGB(255,0,0)); + } +#endif + //if(b_clamb_jump){ + //accurate_normalize(m_control_force); + //dReal proj=dDOT(m_control_force,chVel); + //if(proj<0.f) + // dBodyAddForce(m_body,-chVel[0]*500.f,-chVel[1]*500.f,-chVel[2]*500.f); + // } + } + + + if(b_jumping) + { + + float air_factor = 1.f; + if( b_lose_control && CastActorCharacter() )// + air_factor = 10.f*m_air_control_factor; + + dReal proj=m_acceleration.x*chVel[0]+m_acceleration.z*chVel[2]; + + const dReal* current_pos=dBodyGetPosition(m_body); + dVector3 dif={current_pos[0]-m_jump_depart_position[0], + current_pos[1]-m_jump_depart_position[1], + current_pos[2]-m_jump_depart_position[2]}; + dReal amag =_sqrt(m_acceleration.x*m_acceleration.x+m_acceleration.z*m_acceleration.z); + if(amag>0.f) + if(dif[0]*m_acceleration.x/amag+dif[2]*m_acceleration.z/amag<0.3f) + { + Fvector jump_fv = m_acceleration;//{ m_acceleration.x/amag*1000.f,0,m_acceleration.z/amag*1000.f } + jump_fv.mul( 1000.f/amag * air_factor ); + dBodyAddForce( m_body, jump_fv.x, 0, jump_fv.z ); + } + if(proj<0.f){ + + dReal vmag=chVel[0]*chVel[0]+chVel[2]*chVel[2]; + + Fvector jump_fv = cast_fv( chVel ); + jump_fv.mul( 3000.f*air_factor/vmag/amag*proj ); + dBodyAddForce(m_body,jump_fv.x,0,jump_fv.z); + } + } + //else + //dBodyAddForce(m_body,-chVel[0]*10.f,-20.f*70.f*(!is_contact),-chVel[2]*10.f); + + //if(b_depart&&!b_clamb_jump&&!b_jump&&!b_jumping&&is_control&&!b_external_impulse&&!m_elevator_state.Active()){ + // dBodyAddForce(m_body,0,-m.mass*ph_world->Gravity()/fixed_step,0); + //} + + BodyCutForce(m_body,5.f,0.f); +// + + +// +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgCharacterControl)) + { + const Fvector dipsp = Fvector().set(0,0.02f,0); + debug_output().DBG_DrawLine(Fvector().add(cast_fv(dBodyGetPosition(m_body)),dipsp), + Fvector().add(Fvector().add(cast_fv(dBodyGetPosition(m_body)),dipsp),Fvector().mul(cast_fv(dBodyGetForce(m_body)),1.f/1000.f)),D3DCOLOR_XRGB(255,0,0)); + } +#endif +} + + + +const float CHWON_ACCLEL_SHIFT=0.4f; +const float CHWON_AABB_FACTOR =1.f; +const float CHWON_ANG_COS =M_SQRT1_2; +const float CHWON_CALL_UP_SHIFT=0.05f; +const float CHWON_CALL_FB_HIGHT=1.5f; +const float CHWON_AABB_FB_FACTOR =1.f; + +void CPHSimpleCharacter::ValidateWalkOn() +{ + if(b_on_object||b_was_on_object) + { + b_clamb_jump=ValidateWalkOnMesh(); + ValidateWalkOnObject(); + } + else b_clamb_jump=ValidateWalkOnMesh()&&!m_elevator_state.NearDown(); +} +bool CPHSimpleCharacter::ValidateWalkOnObject() +{ + //deside to stop clamb + if(b_clamb_jump){ + const dReal* current_pos=dBodyGetPosition(m_body); + dVector3 dif={current_pos[0]-m_clamb_depart_position[0], + current_pos[1]-m_clamb_depart_position[1], + current_pos[2]-m_clamb_depart_position[2]}; + if( //!b_valide_wall_contact|| + //(dDOT(dif,dif)>CLAMB_DISTANCE*CLAMB_DISTANCE)) // (m_wall_contact_normal[1]> M_SQRT1_2) || ] + dFabs(dif[1])>CLAMB_DISTANCE){ + b_clamb_jump=false; + // dBodySetLinearVel(m_body,0.f,0.f,0.f); + } + } + + //decide to clamb + if(!m_elevator_state.Active() &&b_valide_wall_contact && (m_contact_count>1)&&(m_wall_contact_normal[1]0.001f) + if(((m_wall_contact_position[0]-m_ground_contact_position[0])*m_control_force[0]+ + (m_wall_contact_position[2]-m_ground_contact_position[2])*m_control_force[2])>0.05f && + m_wall_contact_position[1]-m_ground_contact_position[1]>0.01f) + b_clamb_jump=true; + + + } + + if(b_valide_wall_contact && (m_contact_count>1)&& b_clamb_jump) + if( + dFabs((m_wall_contact_position[0]-m_ground_contact_position[0])+ //*m_control_force[0] + (m_wall_contact_position[2]-m_ground_contact_position[2]))>0.05f &&//0.01f//*m_control_force[2] + m_wall_contact_position[1]-m_ground_contact_position[1]>0.01f) + dVectorSet(m_clamb_depart_position,dBodyGetPosition(m_body)); + return b_clamb_jump; +} +bool CPHSimpleCharacter::ValidateWalkOnMesh() +{ + Fvector AABB,AABB_forbid,center,center_forbid,accel_add,accel; + + AABB.x=m_radius; + AABB.y=m_radius; + AABB.z=m_radius; + + AABB_forbid.set(AABB); + //AABB_forbid.x*=0.7f; + //AABB_forbid.z*=0.7f; + AABB_forbid.y+=m_radius; + AABB_forbid.mul(CHWON_AABB_FB_FACTOR); + + accel_add.set(m_acceleration); + float mag=accel_add.magnitude(); + if(!(mag>0.f)) return + true; + accel_add.mul(CHWON_ACCLEL_SHIFT/mag); + accel.set(accel_add); + accel.div(CHWON_ACCLEL_SHIFT); + AABB.mul(CHWON_AABB_FACTOR); + GetPosition(center); + center.add(accel_add); + center_forbid.set(center); + center_forbid.y+=CHWON_CALL_FB_HIGHT; + center.y+=m_radius+CHWON_CALL_UP_SHIFT; + + // perform single query / two usages + Fbox query,tmp ; + Fvector q_c, q_d ; + query.set (center_forbid,center_forbid); + query.grow (AABB_forbid ); + tmp.set (center,center ); + tmp.grow (AABB ); + query.merge (tmp); + query.get_CD (q_c,q_d); + + XRC.box_options (0); + XRC.box_query (inl_ph_world().ObjectSpace().GetStaticModel(),q_c,q_d); + //Fvector fv_dir;fv_dir.mul(accel,1.f/mag); + Fvector sd_dir;sd_dir.set(-accel.z,0,accel.x); + Fvector obb_fb;obb_fb.set(m_radius*0.5f,m_radius*2.f,m_radius*0.7f); + Fvector obb;obb.set(m_radius*0.5f,m_radius,m_radius*0.7f); +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgCharacterControl)) + { + Fmatrix m;m.identity(); + m.i.set(sd_dir); + m.k.set(accel); + m.c.set(center); + debug_output().DBG_DrawOBB(m,obb,D3DCOLOR_XRGB(0,255,0)); + m.c.set(center_forbid); + debug_output().DBG_DrawOBB(m,obb_fb,D3DCOLOR_XRGB(255,0,0)); + } +#endif + + //if(XRC.r_end()!=XRC.r_begin()) return false; + CDB::RESULT* R_begin = XRC.r_begin(); + CDB::RESULT* R_end = XRC.r_end(); + for (CDB::RESULT* Res=R_begin; Res!=R_end; ++Res) + { + SGameMtl* m = GMLibrary().GetMaterialByIdx(Res->material); + if(m->Flags.test(SGameMtl::flPassable))continue; + //CDB::TRI* T = T_array + Res->id; + Point vertices[3]={Point((dReal*)&Res->verts[0]),Point((dReal*)&Res->verts[1]),Point((dReal*)&Res->verts[2])}; + if(__aabb_tri(Point((float*)¢er_forbid),Point((float*)&AABB_forbid),vertices)) + { + + + if( test_sides(center_forbid,sd_dir,accel,obb_fb,Res->id)) + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgCharacterControl)) + { + debug_output().DBG_DrawTri(Res,D3DCOLOR_XRGB(255,0,0)); + } +#endif + b_side_contact=true; + return + false; + } + //cast_fv(side0).sub(Res->verts[1],Res->verts[0]); + //cast_fv(side1).sub(Res->verts[2],Res->verts[1]); + //dCROSS(norm,=,side0,side1);//optimize it !!! + //cast_fv(norm).normalize(); + + //if(dDOT(norm,(float*)&accel)<-CHWON_ANG_COS) + + } + } + + for (CDB::RESULT* Res=R_begin; Res!=R_end; ++Res) + { + //CDB::TRI* T = T_array + Res->id; + SGameMtl* m = GMLibrary().GetMaterialByIdx(Res->material); + if(m->Flags.test(SGameMtl::flPassable))continue; + Point vertices[3]={Point((dReal*)&Res->verts[0]),Point((dReal*)&Res->verts[1]),Point((dReal*)&Res->verts[2])}; + if(__aabb_tri(Point((float*)¢er),Point((float*)&AABB),vertices)){ + if(test_sides(center,sd_dir,accel,obb,Res->id)) + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgCharacterControl)) + { + debug_output().DBG_DrawTri(Res,D3DCOLOR_XRGB(0,255,0)); + } +#endif + return true; + } + } + } + return + false; +} +void CPHSimpleCharacter::SetAcceleration(Fvector accel){ + if(!b_exist) return; + + if(!dBodyIsEnabled( m_body)) + if(!fsimilar(0.f,accel.magnitude())) + Enable(); + m_acceleration=accel; +} +void CPHSimpleCharacter::SetCamDir(const Fvector& cam_dir) +{ + m_cam_dir.set(cam_dir); +} + +static const float pull_force=25.f; +void CPHSimpleCharacter::ApplyAcceleration() +{ + + dVectorSetZero(m_control_force); + //if(m_max_velocityM_SQRT1_2)){//M_SQRT1_2//0.8660f + dCROSS(fvdir,=,sidedir,m_ground_contact_normal); + accurate_normalize(fvdir); + dVectorAddMul(m_control_force,fvdir,m.mass*pull_force); + } + else{ + dVectorSet(fvdir,accel); + accurate_normalize(fvdir); + dVectorAddMul(m_control_force,fvdir,m.mass*pull_force*1.5f); + } + + } + if(!m_elevator_state.ClimbingState()&&b_clamb_jump){//&&m_wall_contact_normal[1]=0.f ? m_control_force[0] : -m_control_force[0]; + m_control_force[2]=m_control_force[2]*accel[2]>=0.f ? m_control_force[2] : -m_control_force[2]; + } + dVectorMul(m_control_force,m_friction_factor); +} + + +void CPHSimpleCharacter::IPosition(Fvector& pos) { + + if(!b_exist){ + pos.set(cast_fv(m_safe_position)); + } + else{ + m_body_interpolation.InterpolatePosition(pos); + pos.y-=m_radius; + } + VERIFY_BOUNDARIES(pos,phBoundaries,PhysicsRefObject()); + return; +} + +void CPHSimpleCharacter::SetPosition(const Fvector &pos){ + VERIFY_BOUNDARIES(pos,phBoundaries,PhysicsRefObject()); + if(!b_exist) return; + m_death_position[0]=pos.x; + m_death_position[1]=pos.y+m_radius; + m_death_position[2]=pos.z; + m_safe_position[0]=pos.x; + m_safe_position[1]=pos.y+m_radius; + m_safe_position[2]=pos.z; + b_death_pos=false; + + dGeomGetUserData(m_wheel)->pushing_b_neg=false; + dGeomGetUserData(m_hat)->pushing_b_neg=false; + dGeomGetUserData(m_geom_shell)->pushing_b_neg=false; + dGeomGetUserData(m_hat)->pushing_b_neg=false; + dGeomGetUserData(m_wheel)->pushing_neg=false; + dGeomGetUserData(m_hat)->pushing_neg=false; + dGeomGetUserData(m_geom_shell)->pushing_neg=false; + dGeomGetUserData(m_hat)->pushing_neg=false; + + dBodySetPosition(m_body,pos.x,pos.y+m_radius,pos.z); + CPHDisablingTranslational::Reinit(); + m_body_interpolation.ResetPositions(); + CPHObject::spatial_move(); +} + + + +void CPHSimpleCharacter::GetPosition(Fvector& vpos) +{ + if(!b_exist){ + vpos.set(m_safe_position[0],m_safe_position[1]-m_radius,m_safe_position[2]); + } + else{ + const dReal* pos=dBodyGetPosition(m_body); + dVectorSet((dReal*)&vpos,pos); + vpos.y-=m_radius; + } + + VERIFY_BOUNDARIES(vpos,phBoundaries,PhysicsRefObject()); +} +void CPHSimpleCharacter:: GetPreviousPosition (Fvector& pos) +{ + VERIFY(b_exist); + VERIFY(!ph_world->Processing()); + m_body_interpolation.GetPosition(pos,0); +} +void CPHSimpleCharacter::GetVelocity(Fvector& vvel) const +{ + if(!b_exist){ + + vvel.set(m_safe_velocity[0],m_safe_velocity[1],m_safe_velocity[2]); + return ; + } + const dReal* vel=dBodyGetLinearVel(m_body); + dVectorSet((dReal*)&vvel,vel); + return; +} + + +void CPHSimpleCharacter::SetVelocity(Fvector vel) +{ + if(!b_exist) return; + float sq_mag=vel.square_magnitude(); + if(sq_mag>default_l_limit*default_l_limit) + { + float mag=_sqrt(sq_mag); + vel.mul(default_l_limit/mag); +#ifdef DEBUG + Msg("set velocity magnitude is too large %f",mag); +#endif + } + dBodySetLinearVel(m_body,vel.x,vel.y,vel.z); +} + + +void CPHSimpleCharacter::SetMas(dReal mass){ + m_mass=mass; + if(!b_exist) return; + dMass m; + //dMassSetBox(&m,1,1000000.f,1000000.f,1000000.f); + dMassSetSphere(&m,1,1000000.f/2.f); + dMassAdjust(&m,mass); + dBodySetMass(m_body,&m); +} +#ifdef DEBUG +void CPHSimpleCharacter::OnRender(){ +#if 0 + if(!b_exist) return; + Fmatrix m; + m.identity(); + Fvector n=*(Fvector*)m_ground_contact_normal; + n.mul(100.f); + Fvector pos; + GetPosition(pos); + pos.y+=m_radius; + + GLevel().debug_renderer().draw_line(m,pos,*(Fvector*)m_control_force, color_rgba(256,0,0,1)); + GLevel().debug_renderer().draw_line(m,pos,n, 0xefffffff); + + + Fvector scale; + scale.set(0.35f,0.35f,0.35f); + Fmatrix M; + M.identity(); + M.scale(scale); + M.c.set(pos); + + + GLevel().debug_renderer().draw_ellipse(M, 0xffffffff); + +#ifdef DRAW_BOXES + GLevel().debug_renderer().draw_aabb (m_bcenter,m_AABB.x,m_AABB.y,m_AABB.z,D3DCOLOR_XRGB(0,0,255)); + GLevel().debug_renderer().draw_aabb (m_bcenter_forbid,m_AABB_forbid.x,m_AABB_forbid.y,m_AABB_forbid.z,D3DCOLOR_XRGB(255,0,0)); +#endif + ///M.c.set(0.f,1.f,0.f); + //Level().debug_renderer().draw_ellipse(M, 0xffffffff); +#endif +} +#endif + + +EEnvironment CPHSimpleCharacter::CheckInvironment() +{ + //if(b_on_ground||(is_control&&!b_lose_control)) + if(b_lose_control) + return peInAir; + //else return peAtWall; + else if(m_elevator_state.ClimbingState()) + return peAtWall; + + return peOnGround; + +} + + + +void CPHSimpleCharacter::SetPhysicsRefObject (IPhysicsShellHolder* ref_object) +{ + m_phys_ref_object=ref_object; + if(b_exist) + { + dGeomUserDataSetPhysicsRefObject(m_geom_shell,ref_object); + dGeomUserDataSetPhysicsRefObject(m_wheel,ref_object); + dGeomUserDataSetPhysicsRefObject(m_hat,ref_object); + dGeomUserDataSetPhysicsRefObject(m_cap,m_phys_ref_object); + } +} + + +/* +void CPHSimpleCharacter::CaptureObject(dBodyID body,const dReal* anchor) +{ + m_capture_joint=dJointCreateBall(0,0); + Island().AddJoint(m_capture_joint); + dJointAttach(m_capture_joint,m_body,body); + dJointSetBallAnchor(m_capture_joint,anchor[0],anchor[1],anchor[2]); + dJointSetFeedback(m_capture_joint,&m_capture_joint_feedback); +} +*/ +/* +void CPHSimpleCharacter::CapturedSetPosition(const dReal* position) +{ + //if(!m_capture_joint) return; + //dJointSetBallAnchor(m_capture_joint,position[0],position[1],position[2]); +} + +void CPHSimpleCharacter::CheckCaptureJoint() +{ + //m_capture_joint_feedback +} + +void CPHSimpleCharacter::doCaptureExist(bool& do_exist) +{ + do_exist=!!m_capture_joint; +} +*/ +//float max_hit_vel_limit = 3000.f; +void CPHSimpleCharacter::SafeAndLimitVelocity() +{ + + const float *linear_velocity =dBodyGetLinearVel(m_body); + if(dV_valid(linear_velocity)) + { + dReal mag=_sqrt(linear_velocity[0]*linear_velocity[0]+linear_velocity[1]*linear_velocity[1]+linear_velocity[2]*linear_velocity[2]);//; + //limit velocity + dReal l_limit; + if(is_control&&!b_lose_control) + l_limit = m_max_velocity/phTimefactor; + else + l_limit=default_l_limit; + + if(b_external_impulse) + { + float sq_mag=m_acceleration.square_magnitude(); + float ll_limit=m_ext_imulse.dotproduct(cast_fv(linear_velocity))*10.f/fixed_step; + if(sq_mag>EPS_L) + { + Fvector acc;acc.set(Fvector().mul(m_acceleration,1.f/_sqrt(sq_mag))); + Fvector vll;vll.mul(cast_fv(linear_velocity),1.f/mag); + float mxa=vll.dotproduct(acc); + if(mxa*ll_limit>l_limit&&!fis_zero(mxa)){ + ll_limit=l_limit/mxa; + } + + } + //clamp(ll_limit,0.f,max_hit_vel_limit); + if(ll_limit>l_limit) + l_limit=ll_limit; + } +//////////////////////////////////////////////////////////////////////////////////////////// + m_mean_y=m_mean_y*0.9999f+linear_velocity[1]*0.0001f; + if(mag>l_limit) + { //CutVelocity(m_l_limit,m_w_limit); + if(!fis_zero(l_limit)) + { + + dReal f=mag/l_limit; + + if(b_lose_ground&&linear_velocity[1]<0.f&&linear_velocity[1]>-default_l_limit) + dBodySetLinearVel(m_body,linear_velocity[0]/f,linear_velocity[1],linear_velocity[2]/f);///f + else + CutVelocity(l_limit,0.f); + //dBodySetLinearVel(m_body,linear_velocity[0]/f,linear_velocity[1]/f,linear_velocity[2]/f);///f + if(is_control&&!b_lose_control) + { + dBodySetPosition(m_body, + m_safe_position[0]+linear_velocity[0]*fixed_step, + m_safe_position[1]+linear_velocity[1]*fixed_step, + m_safe_position[2]+linear_velocity[2]*fixed_step); + VERIFY_BOUNDARIES(cast_fv(dBodyGetPosition(m_body)),phBoundaries,PhysicsRefObject()); + } + }else dBodySetLinearVel(m_body,0,0,0); + + + } + } + else + { + dBodySetLinearVel(m_body,m_safe_velocity[0],m_safe_velocity[1],m_safe_velocity[2]); + } + + if(!dV_valid(dBodyGetPosition(m_body))) + dBodySetPosition(m_body,m_safe_position[0]-m_safe_velocity[0]*fixed_step, + m_safe_position[1]-m_safe_velocity[1]*fixed_step, + m_safe_position[2]-m_safe_velocity[2]*fixed_step); + + + dVectorSet(m_safe_position,dBodyGetPosition(m_body)); + dVectorSet(m_safe_velocity,linear_velocity); + +} + +void CPHSimpleCharacter::SetObjectContactCallback(ObjectContactCallbackFun* callback) +{ + m_object_contact_callback=callback; + if(!b_exist)return; + + dGeomUserDataSetObjectContactCallback(m_hat,callback); + dGeomUserDataSetObjectContactCallback(m_geom_shell,callback); + dGeomUserDataSetObjectContactCallback(m_wheel,callback); +} +void CPHSimpleCharacter::SetObjectContactCallbackData( void* data ) +{ + VERIFY( b_exist ); + dGeomUserDataSetCallbackData(m_hat,data); + dGeomUserDataSetCallbackData(m_geom_shell,data); + dGeomUserDataSetCallbackData(m_wheel,data); +} + +void CPHSimpleCharacter::AddObjectContactCallback(ObjectContactCallbackFun* callback) +{ + + VERIFY(b_exist); + + dGeomUserDataAddObjectContactCallback(m_hat,callback); + dGeomUserDataAddObjectContactCallback(m_geom_shell,callback); + dGeomUserDataAddObjectContactCallback(m_wheel,callback); +} +void CPHSimpleCharacter::RemoveObjectContactCallback(ObjectContactCallbackFun* callback) +{ + VERIFY(m_object_contact_callback!=callback); + if(!b_exist) return; + + dGeomUserDataRemoveObjectContactCallback(m_hat,callback); + dGeomUserDataRemoveObjectContactCallback(m_geom_shell,callback); + dGeomUserDataRemoveObjectContactCallback(m_wheel,callback); +} + +void CPHSimpleCharacter::Disable() +{ + //if(is_contact&&!is_control&&!b_lose_ground) + { + dGeomGetUserData(m_wheel)->pushing_neg =false; + dGeomGetUserData(m_wheel)->pushing_b_neg =false; + dGeomGetUserData(m_geom_shell)->pushing_neg =false; + dGeomGetUserData(m_geom_shell)->pushing_b_neg =false; + dGeomGetUserData(m_hat)->pushing_neg =false; + dGeomGetUserData(m_hat)->pushing_b_neg =false; + dGeomGetUserData(m_cap)->pushing_neg =false; + dGeomGetUserData(m_cap)->pushing_b_neg =false; + CPHCharacter::Disable(); + } +} +void CPHSimpleCharacter::Enable() +{ + if(!b_exist)return; + dGeomGetUserData(m_wheel)->pushing_neg =false; + dGeomGetUserData(m_wheel)->pushing_b_neg =false; + dGeomGetUserData(m_geom_shell)->pushing_neg =false; + dGeomGetUserData(m_geom_shell)->pushing_b_neg =false; + dGeomGetUserData(m_hat)->pushing_neg =false; + dGeomGetUserData(m_hat)->pushing_b_neg =false; + dGeomGetUserData(m_cap)->pushing_neg =false; + dGeomGetUserData(m_cap)->pushing_b_neg =false; + CPHCharacter::Enable(); +} +void CPHSimpleCharacter::EnableObject(CPHObject* obj) +{ + dGeomGetUserData(m_wheel)->pushing_neg =false; + dGeomGetUserData(m_wheel)->pushing_b_neg =false; + dGeomGetUserData(m_geom_shell)->pushing_neg =false; + dGeomGetUserData(m_geom_shell)->pushing_b_neg =false; + dGeomGetUserData(m_hat)->pushing_neg =false; + dGeomGetUserData(m_hat)->pushing_b_neg =false; + dGeomGetUserData(m_cap)->pushing_neg =false; + dGeomGetUserData(m_cap)->pushing_b_neg =false; + CPHCharacter::EnableObject(obj); +} +void CPHSimpleCharacter::SetWheelContactCallback (ObjectContactCallbackFun* callback) +{ + VERIFY(b_exist); + dGeomUserDataSetObjectContactCallback(m_wheel,callback); +} +void CPHSimpleCharacter::SetStaticContactCallBack(ContactCallbackFun* callback) +{ + if(!b_exist) return; + + dGeomUserDataSetContactCallback(m_hat,callback); + dGeomUserDataSetContactCallback(m_geom_shell,callback); + dGeomUserDataSetContactCallback(m_wheel,callback); +} + +ObjectContactCallbackFun* CPHSimpleCharacter::ObjectContactCallBack() +{ + return m_object_contact_callback; +} + +u16 CPHSimpleCharacter::RetriveContactBone() +{ + Fvector dir; + m_collision_damage_info.HitDir(dir); + collide::ray_defs Q(m_collision_damage_info.HitPos(), dir, m_radius, CDB::OPT_ONLYNEAREST|CDB::OPT_CULL,collide::rqtBoth); // CDB::OPT_ONLYFIRST CDB::OPT_ONLYNEAREST + RQR.r_clear (); + u16 contact_bone = 0; +// CObject* object = smart_cast(m_phys_ref_object); + //VERIFY (object) ; + VERIFY (!fis_zero(Q.dir.square_magnitude())); + if (inl_ph_world().ObjectSpace().RayQuery(RQR,m_phys_ref_object->ObjectCollisionModel(),Q)) { + collide::rq_result* R = RQR.r_begin() ; + contact_bone=(u16)R->element ; + //int y=result.r_count(); + //for (int k=0; kelement,i)) + // { + // i->second.Use(); + // return false; + + // } + //} + + } + else + { + //IKinematics* K=smart_cast(m_phys_ref_object->ObjectVisual()); + IKinematics* K=m_phys_ref_object->ObjectKinematics(); + u16 count=K->LL_BoneCount(); + CBoneInstance* bone_instances=&K->LL_GetBoneInstance(0); + Fvector pos_in_object; + pos_in_object.sub(m_collision_damage_info.HitPos(),m_phys_ref_object->ObjectPosition());//vector from object center to contact position currently in global frame + Fmatrix object_form; + object_form.set(m_phys_ref_object->ObjectXFORM()); + object_form.transpose(); + object_form.transform_dir(pos_in_object); //project pos_in_object on object axes now it is position of contact in object frame + float sq_dist=dInfinity; + for(u16 i=0;igeom.normal; + const dReal* pos=c->geom.pos; + const dGeomID g1=c->geom.g1; + const dGeomID g2=c->geom.g2; + bool bo1=(g1==m_wheel)||g1==m_cap_transform||g1==m_shell_transform||g1==m_hat_transform; + + //SGameMtl* tri_material=GMLibrary().GetMaterialByIdx((u16)c->surface.mode); + + u16 contact_material=bo1 ? material_idx_2:material_idx_1; + SGameMtl* tri_material=GMLibrary().GetMaterialByIdx(contact_material); + + bool bClimable=!!tri_material->Flags.test(SGameMtl::flClimable); + if(is_control&&m_elevator_state.ClimbingState()) + { + c->surface.mu=0.f; + c->surface.soft_cfm=world_cfm*2.f; + c->surface.soft_erp=world_erp; + b_any_contacts=true; + is_contact=true; + } + u16 foot_material_idx = ((dxGeomUserData*)dGeomGetData(m_wheel))->tri_material; + if(tri_material->Flags.test(SGameMtl::flPassable)&&!do_collide) + { + + UpdateStaticDamage(c,tri_material,bo1); + foot_material_update(contact_material,foot_material_idx); + return; + } + if(do_collide) + { + b_any_contacts=true; + is_contact=true; + } + dReal spring_rate=def_spring_rate; + dReal dumping_rate=def_dumping_rate; + bool object=(dGeomGetBody(g1)&&dGeomGetBody(g2)); + b_on_object=b_on_object||object; + + +////////////////////////����� �������� �������!! +////////////// + FootProcess(c,do_collide,bo1); + if(!do_collide) return; + if(g1==m_hat_transform||g2==m_hat_transform) + { + b_side_contact=true; + MulSprDmp(c->surface.soft_cfm,c->surface.soft_erp,spring_rate,dumping_rate); + c->surface.mu =0.00f; + } + + if(object){ + spring_rate*=10.f; + dBodyID b; + u16 obj_material_idx=u16(-1); + if(bo1) + { + b=dGeomGetBody(c->geom.g2); + obj_material_idx=material_idx_2; + } + else + { + b=dGeomGetBody(c->geom.g1); + obj_material_idx=material_idx_1; + } + UpdateDynamicDamage(c,obj_material_idx,b,bo1); + if(g1==m_wheel||g2==m_wheel) + { + dxGeomUserData *ud=bo1 ? retrieveGeomUserData(c->geom.g2) : retrieveGeomUserData(c->geom.g1); + foot_material_idx = ud->material; + } + contact_material=obj_material_idx; + } + + foot_material_update(contact_material,foot_material_idx); + + //if(!((g1==m_wheel) || (g2==m_wheel)||(m_elevator_state.ClimbingState()) ))// + // return; + + float friction=1.f; + if(!object && !b_side_contact) + { + friction=c->surface.mu; + } + if(m_friction_factorm_ground_contact_normal[1]||!b_valide_ground_contact)// + { + dVectorSet(m_ground_contact_normal,normal); + dVectorSet(m_ground_contact_position,pos); + b_valide_ground_contact=true; + } + if(dXZDot(normal,cast_fp(m_acceleration))geom.normal); + dVectorSet(m_wall_contact_position,c->geom.pos); + b_valide_wall_contact=true; + } + } + else{ + + if(normal[1]<-m_ground_contact_normal[1]||!b_valide_ground_contact)// + { + dVectorSetInvert(m_ground_contact_normal,normal); + dVectorSet(m_ground_contact_position,pos); + b_valide_ground_contact=true; + } + if(dXZDot(normal,cast_fp(m_acceleration)) > -dXZDot(m_wall_contact_normal,cast_fp(m_acceleration))||!b_valide_wall_contact)// + { + dVectorSetInvert(m_wall_contact_normal,normal); + dVectorSet(m_wall_contact_position,pos); + b_valide_wall_contact=true; + } + } + float soft_param=dumping_rate+normal[1]*(1.f-dumping_rate);//=(1.f-normal[1])*dumping_rate +normal[1] + if(is_control){//&&!b_lose_control||b_jumping + if(g1==m_wheel||g2==m_wheel&&!bClimable) + { + c->surface.mu = 0.f;//0.00f; + + } + else{ + c->surface.mu = 0.00f; + } + MulSprDmp(c->surface.soft_cfm,c->surface.soft_erp ,spring_rate,soft_param); + } + else + { + MulSprDmp(c->surface.soft_cfm,c->surface.soft_erp,spring_rate,soft_param); + c->surface.mu *= (1.f+b_clamb_jump*3.f)*m_friction_factor; + } + UpdateStaticDamage(c,tri_material,bo1); +} + +void CPHSimpleCharacter::FootProcess(dContact* c,bool &do_collide ,bool bo) +{ + + + const dGeomID g1 =c->geom.g1 ; + const dGeomID g2 =c->geom.g2 ; + dGeomID g =g1 ; + float sign =1.f ; + dReal* normal =c->geom.normal ; + if(!bo) {g=g2; sign=-1.f; } + if(m_elevator_state.ClimbingState() ||!is_control||!b_clamb_jump||b_was_side_contact||b_side_contact||b_jumping||b_jump) + { + if(g==m_wheel&&sign*normal[1]<0.f) do_collide=false; + return; + } + +/////////////////////////////////////////////////////////////////////////////////// + + dReal* pos =c->geom.pos ; + + + float c_pos =pos[1]-dBodyGetPosition(m_body)[1] ; + + +///////////////////////////////////////////////////////////////////////////////////// + + + if(dXZDot(m_acceleration,cast_fv(normal))*sign>0.f)return; + if(g==m_wheel) + { + if(sign*normal[1]<=0.f) + { + normal[0]=normal[2]=0.f;normal[1]=sign; + c->geom.depth=c_pos+m_radius; + } + } + + if(g==m_shell_transform) + { + if(c_pos<0.f) + { + normal[0]=normal[2]=0.f;normal[1]=sign; + c->geom.depth=c_pos+m_radius; + } + } +} +void CPHSimpleCharacter::GroundNormal(Fvector &norm) +{ + if(m_elevator_state.ClimbingState()) + { + m_elevator_state.GetLeaderNormal(norm); + + } + else + { + norm.set(*((Fvector*)m_ground_contact_normal)); + } +} +u16 CPHSimpleCharacter::ContactBone() +{ + return RetriveContactBone(); +} +void CPHSimpleCharacter::SetMaterial (u16 material) +{ + if(!b_exist) return; + dGeomGetUserData(m_geom_shell)->material=material; + dGeomGetUserData(m_wheel)->material =material; + dGeomGetUserData(m_cap)->material =material; + dGeomGetUserData(m_hat)->material =material; +} +void CPHSimpleCharacter::get_State(SPHNetState& state) +{ + CPHCharacter::get_State(state); + + state.previous_position.y-=m_radius; +} +void CPHSimpleCharacter::set_State(const SPHNetState& state) +{ + CPHCharacter::set_State (state); +} + +void CPHSimpleCharacter::get_spatial_params() +{ + spatialParsFromDGeom((dGeomID)m_space,spatial.sphere.P,AABB,spatial.sphere.R); +} + +float CPHSimpleCharacter::FootRadius() +{ + if(b_exist) return m_radius; + else return 0.f; + +} +void CPHSimpleCharacter::DeathPosition(Fvector& deathPos) +{ + if(!b_exist)return; + + if(b_death_pos) + deathPos.set(m_death_position); + else + { + deathPos.set(cast_fv(dBodyGetPosition(m_body))); + if(!_valid(deathPos))deathPos.set(m_safe_position); + } + deathPos.y-=m_radius; +} +void CPHSimpleCharacter:: AddControlVel (const Fvector& vel) +{ + m_acceleration.add(vel); + m_max_velocity+=vel.magnitude(); +} +void CPHSimpleCharacter::SetInitiated () +{ + m_collision_damage_info.is_initiated = true; +} +bool CPHSimpleCharacter::IsInitiated ()const +{ + return m_collision_damage_info.is_initiated; +} +u16 CPHSimpleCharacter::DamageInitiatorID()const +{ + u16 ret=u16(-1);//m_collision_damage_info.DamageInitiatorID(); + + IPhysicsShellHolder* object = 0; + if( m_collision_damage_info.m_obj_id != u16(-1) ) + { + CObject * obj = inl_ph_world().LevelObjects().net_Find(m_collision_damage_info.m_obj_id); + VERIFY(!obj|| smart_cast(obj) ); + object=smart_cast(obj); + } + if(object&&!object->ObjectGetDestroy()) + { + IDamageSource* ds=object->ObjectCastIDamageSource(); + if(ds) ret= ds->Initiator(); + } + // return u16(-1); + + if(ret==u16(-1)) ret = m_phys_ref_object->ObjectID(); + return ret; +} + +CObject* CPHSimpleCharacter::DamageInitiator() const +{ + VERIFY(m_phys_ref_object); + if( m_collision_damage_info.m_dmc_type==SCollisionDamageInfo::ctStatic ) + return smart_cast (m_phys_ref_object); + u16 initiator_id=DamageInitiatorID(); + VERIFY(initiator_id!=u16(-1)); + if(initiator_id==m_phys_ref_object->ObjectID()) + return smart_cast (m_phys_ref_object); + else + { + return inl_ph_world ().LevelObjects().net_Find(initiator_id); + } +} + +CPHSimpleCharacter::SCollisionDamageInfo::SCollisionDamageInfo() +{ + Construct(); +} +void CPHSimpleCharacter::SCollisionDamageInfo::Construct() +{ + m_contact_velocity=0.f; + SCollisionDamageInfo::Reinit(); + m_hit_type = ALife::eHitTypeStrike; + //m_damege_contact; + + //m_dmc_signum; + //m_dmc_type; + +} +float CPHSimpleCharacter::SCollisionDamageInfo::ContactVelocity()const +{ + dReal ret= m_contact_velocity; + m_contact_velocity=0; + return ret; +} + +void CPHSimpleCharacter::SCollisionDamageInfo::HitDir(Fvector& dir) const +{ + dir.set(m_damege_contact.geom.normal[0]*m_dmc_signum,m_damege_contact.geom.normal[1]*m_dmc_signum,m_damege_contact.geom.normal[2]*m_dmc_signum); +} + +//u16 CPHSimpleCharacter::SCollisionDamageInfo::DamageInitiatorID() const +//{ +// //if(!m_object) +// //return u16(-1); +// IPhysicsShellHolder* object =static_cast(Level().Objects.net_Find(m_obj_id)); +// if(!object)return u16(-1); +// IDamageSource* ds=m_object->cast_IDamageSource(); +// if(ds) return ds->Initiator(); +// return u16(-1); +//} +void CPHSimpleCharacter::SCollisionDamageInfo::Reinit() +{ + //m_damege_contact; + + m_obj_id =u16(-1); + m_hit_callback=NULL; + m_contact_velocity=0; + is_initiated=false; + + //float m_dmc_signum; + //enum{ctStatic,ctObject} m_dmc_type; +} +bool CPHSimpleCharacter::GetAndResetInitiated () +{ + bool ret = m_collision_damage_info.is_initiated; + m_collision_damage_info.is_initiated = false; + return ret; +} +void CPHSimpleCharacter::GetSmothedVelocity(Fvector& vvel) +{ + if(!b_exist) {vvel.set(0,0,0);return;} + vvel.set(m_last_move); + + //if(IsEnabled()&&m_countph_object) return; + if(obj_data->ph_object->CastType()!=tpCharacter) return; + CPHActorCharacter *actor_character =(static_cast(obj_data->ph_object))->CastActorCharacter(); + if(!actor_character) return; + CPHSimpleCharacter *ch_this =static_cast(retrieveGeomUserData(g_this)->ph_object); + VERIFY(ch_this); + save_max(restrictor_depth,c.geom.depth); + do_colide=true; + c.surface.mu=0.f; +} + +bool CPHSimpleCharacter:: UpdateRestrictionType(CPHCharacter* ach) +{ + VERIFY(ph_world); + VERIFY(ph_world->Exist()); + if(m_restriction_type==m_new_restriction_type) return true; + ach->Enable(); + Enable(); + restrictor_depth=0.f; + //bool state=IsEnabled(); + + ph_world->Freeze(); + ERestrictionType old=m_restriction_type; + m_restriction_type=m_new_restriction_type; + AddObjectContactCallback(TestRestrictorContactCallbackFun); + UnFreeze(); + ph_world->StepTouch(); + ach->SwitchOFFInitContact(); + if(restrictor_depthUnFreeze(); + ach->SwitchInInitContact(); + //if(!state)Disable(); + return true; + } + u16 num_steps=2*(u16)iCeil(restrictor_depth/resolve_depth); + for(u16 i=0;num_steps>i;++i) + { + //Calculate(Fvector().set(0,0,0),Fvector().set(1,0,0),0,0,0,0); + restrictor_depth=0.f; + ach->Enable(); + Enable(); + //ach->ApplyForce(0,ph_world->Gravity()*ach->Mass(),0); + ph_world->Step(); + + if(restrictor_depthUnFreeze(); + ach->SwitchInInitContact(); + //if(!state)Disable(); + return true; + } + } + RemoveObjectContactCallback(TestRestrictorContactCallbackFun); + ach->SwitchInInitContact(); + ph_world->UnFreeze(); + //if(!state)Disable(); + m_new_restriction_type=old; +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask1().test(ph_m1_DbgActorRestriction)) + Msg("restriction can not change change small -> large"); +#endif + return false; +} +bool CPHSimpleCharacter:: TouchRestrictor (ERestrictionType rttype) +{ + b_collision_restrictor_touch=true; + return rttype==RestrictionType(); +} + + + +IC bool valide_res( u16& res_material_idx, const collide::rq_result &R ) +{ + if(!R.O) + { + CDB::TRI * tri = inl_ph_world().ObjectSpace().GetStaticTris( ) + R.element; + VERIFY( tri ); + res_material_idx = tri->material; + return !ignore_material( res_material_idx ); + } + IRenderVisual* V =R.O->Visual(); + if( !V ) + return false; + IKinematics *K = V->dcast_PKinematics(); + CBoneData &bd = K->LL_GetData( (u16)R.element ); + res_material_idx= bd.game_mtl_idx; + return true; +} + +bool PickMaterial( u16& res_material_idx, const Fvector &pos_, const Fvector &dir_,float range_, CObject* ignore_object ) +{ + Fvector pos = pos_; pos.y+=EPS_L; + Fvector dir = dir_; + float range = range_; + collide::rq_result R; + res_material_idx = GAMEMTL_NONE_IDX; + while( inl_ph_world().ObjectSpace().RayPick( pos, dir, range, collide::rqtBoth, R, ignore_object ) ) + { + float r_range = R.range + EPS_L; + Fvector next_pos = pos.mad( dir, r_range ) ; + float next_range = range - r_range; + if( valide_res( res_material_idx, R ) ) + return true; + range = next_range; + pos = next_pos; + if( range < EPS_L ) + return false; + } + return false; +} +const float material_pick_dist = 0.5f; +const float material_pick_upset = 0.5f; +const float material_update_tolerance = 0.1f; +void CPHSimpleCharacter::update_last_material() +{ + //if( ignore_material( *p_lastMaterialIDX ) ) + //{ + Fvector pos;GetPosition( pos );pos.y += material_pick_upset; + if( m_last_picked_material != GAMEMTL_NONE_IDX && pos.similar( m_last_environment_update, material_update_tolerance ) ) + { + *p_lastMaterialIDX = m_last_picked_material; + return; + } + u16 new_material; + VERIFY(!PhysicsRefObject() || smart_cast( PhysicsRefObject() ) ); + if( PickMaterial( new_material, pos, Fvector().set( 0, -1, 0 ), material_pick_dist + material_pick_upset, smart_cast( PhysicsRefObject() ) ) ) + { + m_last_picked_material = new_material; + *p_lastMaterialIDX = new_material; + m_last_environment_update = pos; + } + //} + //m->flActorObstacle +} + +void CPHSimpleCharacter::SetNonInteractive (bool v) +{ + b_non_interactive = v; +} + +void CPHSimpleCharacter::Collide () +{ + OnStartCollidePhase(); + + inherited::Collide(); + if( injuriousMaterialIDX == GAMEMTL_NONE_IDX && (*p_lastMaterialIDX)!=GAMEMTL_NONE_IDX && GMLibrary().GetMaterialByIdx(*p_lastMaterialIDX)->Flags.test(SGameMtl::flInjurious) ) + injuriousMaterialIDX = *p_lastMaterialIDX; + +} +void CPHSimpleCharacter::OnStartCollidePhase () +{ + injuriousMaterialIDX = GAMEMTL_NONE_IDX; + +} + + +void CPHSimpleCharacter::NetRelcase ( IPhysicsShellHolder* O ) +{ + inherited::NetRelcase( O ); + m_elevator_state.NetRelcase( O ); +} \ No newline at end of file diff --git a/xrPhysics/PHSimpleCharacter.h b/xrPhysics/PHSimpleCharacter.h new file mode 100644 index 00000000000..86eb3ce12d4 --- /dev/null +++ b/xrPhysics/PHSimpleCharacter.h @@ -0,0 +1,274 @@ +#pragma once +#include "PHCharacter.h" +#include "Physics.h" +#include "MathUtils.h" +#include "ElevatorState.h" +#include "IColisiondamageInfo.h" +#include "../xrEngine/gamemtllib.h" +namespace ALife { + enum EHitType; +}; +#ifdef DEBUG +#include "debug_output.h" +#endif +class ICollisionHitCallback; + +class CPHSimpleCharacter : + public CPHCharacter, + ICollisionDamageInfo +{ + typedef CPHCharacter inherited; +private: + + collide::rq_results RQR; + +protected: + CElevatorState m_elevator_state; + ////////////////////////////damage//////////////////////////////////////// +#ifdef DEBUG + public: +#endif + struct SCollisionDamageInfo + { + SCollisionDamageInfo () ; + void Construct () ; + float ContactVelocity () const ; + void HitDir (Fvector &dir) const ; + IC const Fvector& HitPos () const {return cast_fv(m_damege_contact.geom.pos);} + void Reinit () ; + dContact m_damege_contact; + ICollisionHitCallback *m_hit_callback; + u16 m_obj_id; + float m_dmc_signum; + enum{ctStatic,ctObject} m_dmc_type; + ALife::EHitType m_hit_type; + bool is_initiated; + mutable float m_contact_velocity; + }; +#ifdef DEBUG + SCollisionDamageInfo& dbg_get_collision_dmg_info(){ return m_collision_damage_info ;} +#endif +protected: + SCollisionDamageInfo m_collision_damage_info; + /////////////////////////// callback + ObjectContactCallbackFun* m_object_contact_callback; + ////////////////////////// geometry + Fvector m_last_move; + dGeomID m_geom_shell; + dGeomID m_wheel; + dGeomID m_hat; + dGeomID m_cap; + + dGeomID m_hat_transform; + dGeomID m_wheel_transform; + dGeomID m_shell_transform; + dGeomID m_cap_transform; + + dSpaceID m_space; + + dReal m_radius; + dReal m_cyl_hight; + /////////////////////////////////// + //dJointID m_capture_joint; + //dJointFeedback m_capture_joint_feedback; + ////////////////////////// movement + dVector3 m_control_force; + Fvector m_acceleration; + Fvector m_cam_dir; + dVector3 m_wall_contact_normal; + dVector3 m_ground_contact_normal; + dVector3 m_clamb_depart_position; + dVector3 m_depart_position; + dVector3 m_wall_contact_position; + dVector3 m_ground_contact_position; + dReal jump_up_velocity;//=6.0f;//5.6f; + dReal m_collision_damage_factor; + dReal m_max_velocity; + + float m_air_control_factor; + + dVector3 m_jump_depart_position; + dVector3 m_death_position; + Fvector m_jump_accel; + + Fvector m_last_environment_update; + u16 m_last_picked_material; + //movement state + bool is_contact ; + bool was_contact ; + bool b_depart ; + bool b_meet ; + bool b_side_contact ; + bool b_was_side_contact ; + bool b_any_contacts ; + bool b_air_contact_state ; + + bool b_valide_ground_contact ; + bool b_valide_wall_contact ; + bool b_on_object ; + bool b_was_on_object ; + bool b_on_ground ; + bool b_lose_ground ; + bool b_collision_restrictor_touch; + u32 m_contact_count ; + + bool is_control ; + bool b_meet_control ; + bool b_lose_control ; + bool was_control ; + bool b_stop_control ; + bool b_depart_control ; + bool b_jump ; + bool b_jumping ; + bool b_clamb_jump ; + bool b_external_impulse ; + u64 m_ext_impuls_stop_step ; + Fvector m_ext_imulse ; + bool b_death_pos ; + bool b_foot_mtl_check ; + dReal m_friction_factor ; + bool b_non_interactive ; +public: + CPHSimpleCharacter () ; + virtual ~CPHSimpleCharacter () {Destroy();} + + /////////////////CPHObject////////////////////////////////////////////// + virtual void PhDataUpdate (dReal step) ; + virtual void PhTune (dReal step) ; + virtual void InitContact (dContact* c,bool &do_collide,u16 /*material_idx_1*/,u16 /*material_idx_2*/) ; + virtual dSpaceID dSpace () {return m_space;} + virtual dGeomID dSpacedGeom () {return (dGeomID)m_space;} + virtual void get_spatial_params () ; + /////////////////CPHCharacter//////////////////////////////////////////// +public: + //update + + + //Check state + virtual bool ContactWas () {if(b_meet_control) {b_meet_control=false;return true;} else return false;} + virtual EEnvironment CheckInvironment () ; + virtual void GroundNormal (Fvector &norm) ; + virtual const ICollisionDamageInfo *CollisionDamageInfo ()const {return this;} + virtual ICollisionDamageInfo *CollisionDamageInfo (){return this;} +private: + virtual float ContactVelocity ()const {return m_collision_damage_info.ContactVelocity();} + virtual void HitDir (Fvector& dir)const {return m_collision_damage_info.HitDir(dir);} + virtual const Fvector& HitPos ()const {return m_collision_damage_info.HitPos();} + virtual u16 DamageInitiatorID ()const ; + virtual CObject *DamageInitiator ()const ; + virtual ALife::EHitType HitType ()const {return m_collision_damage_info.m_hit_type; }; + virtual void SetInitiated (); + virtual bool IsInitiated ()const ; + virtual bool GetAndResetInitiated () ; + virtual void SetHitType (ALife::EHitType type){ m_collision_damage_info.m_hit_type = type; }; + virtual ICollisionHitCallback *HitCallback ()const ; + virtual void Reinit () {m_collision_damage_info.Reinit();}; +public: + //Creating + virtual void Create (dVector3 sizes) ; + virtual void Destroy (void) ; + virtual void Disable () ; + virtual void EnableObject (CPHObject* obj) ; + virtual void Enable () ; + virtual void SetBox (const dVector3 &sizes); + virtual bool UpdateRestrictionType (CPHCharacter* ach); + //get-set + virtual void SetObjectContactCallback (ObjectContactCallbackFun* callback); + virtual void SetObjectContactCallbackData ( void* data ); + virtual void SetWheelContactCallback (ObjectContactCallbackFun* callback); +private: + void RemoveObjectContactCallback (ObjectContactCallbackFun* callback); + void AddObjectContactCallback (ObjectContactCallbackFun* callback); +static void TestRestrictorContactCallbackFun (bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2); +public: + virtual ObjectContactCallbackFun* ObjectContactCallBack (); + virtual void SetStaticContactCallBack (ContactCallbackFun* calback); + virtual void SwitchOFFInitContact () ; + virtual void SwitchInInitContact () ; + virtual void SetAcceleration (Fvector accel) ; + virtual Fvector GetAcceleration () { return m_acceleration; }; + virtual void SetCamDir (const Fvector& cam_dir); + virtual const Fvector& CamDir ()const {return m_cam_dir;} + virtual void SetMaterial (u16 material) ; + virtual void SetPosition (const Fvector &pos); + virtual void GetVelocity (Fvector& vvel)const; + virtual void GetSmothedVelocity (Fvector& vvel) ; + virtual void SetVelocity (Fvector vel) ; + virtual void SetAirControlFactor (float factor) {m_air_control_factor=factor;} + virtual void SetElevator (IClimableObject* climable){m_elevator_state.SetElevator(climable);}; + virtual CElevatorState *ElevatorState () ; + virtual void SetCollisionDamageFactor (float f) {m_collision_damage_factor=f;} + virtual void GetPosition (Fvector& vpos) ; + virtual void GetPreviousPosition (Fvector& pos) ; + virtual float FootRadius () ; + virtual void DeathPosition (Fvector& deathPos) ; + virtual void IPosition (Fvector& pos) ; + virtual u16 ContactBone (); + virtual void ApplyImpulse (const Fvector& dir, const dReal P); + virtual void ApplyForce (const Fvector& force); + virtual void ApplyForce (const Fvector& dir,float force); + virtual void ApplyForce (float x,float y, float z); + virtual void AddControlVel (const Fvector& vel); + virtual void SetMaximumVelocity (dReal vel) {m_max_velocity=vel;} + virtual dReal GetMaximumVelocity () { return m_max_velocity;} + virtual void SetJupmUpVelocity (dReal velocity) {jump_up_velocity=velocity;} + virtual bool JumpState () { + return b_jumping||b_jump; + }; + virtual const Fvector& ControlAccel ()const {return m_acceleration;} + virtual bool TouchRestrictor (ERestrictionType rttype); + virtual float &FrictionFactor () {return m_friction_factor;} + virtual void SetMas (dReal mass) ; + virtual float Mass () {return m_mass;}; + virtual void SetPhysicsRefObject (IPhysicsShellHolder* ref_object); + virtual void SetNonInteractive (bool v); + virtual bool IsEnabled () { if(!b_exist)return false; return !!dBodyIsEnabled(m_body);} + virtual void GetBodyPosition (Fvector& vpos) { VERIFY(b_exist); vpos = cast_fv(dBodyGetPosition(m_body)); } + const Fvector &BodyPosition ()const {VERIFY(b_exist && m_body); return cast_fv(dBodyGetPosition(m_body)); } + //virtual void CaptureObject (dBodyID body,const dReal* anchor); + //virtual void CapturedSetPosition (const dReal* position); + //virtual void doCaptureExist (bool& do_exist); + + virtual void get_State ( SPHNetState& state) ; + virtual void set_State (const SPHNetState& state) ; + virtual void ValidateWalkOn (); + bool ValidateWalkOnMesh () ; + bool ValidateWalkOnObject () ; +private: + void CheckCaptureJoint (); + void ApplyAcceleration (); + + u16 RetriveContactBone (); + void SafeAndLimitVelocity (); +virtual void UpdateStaticDamage (dContact* c,SGameMtl* tri_material,bool bo1); + void UpdateDynamicDamage (dContact* c,u16 obj_material_idx,dBodyID b,bool bo1); +IC void FootProcess (dContact* c,bool &do_collide ,bool bo); +IC void foot_material_update (u16 tri_material,u16 foot_material_idx); + static void TestPathCallback(bool& do_colide,bool bo1,dContact& c,SGameMtl * /*material_1*/,SGameMtl * /*material_2*/); +virtual void Collide (); + void OnStartCollidePhase (); +private: + virtual void Freeze () { CPHObject::Freeze(); } + virtual void UnFreeze () { CPHObject::UnFreeze(); } + virtual void step (float dt) { CPHObject::step( dt ); } + virtual void collision_disable () { CPHObject::collision_disable(); } + virtual void collision_enable () { CPHObject::collision_enable(); } + virtual void NetRelcase ( IPhysicsShellHolder* O ); +protected: +virtual void get_Box ( Fvector& sz, Fvector& c )const; + protected: +virtual void update_last_material (); +public: +#ifdef DEBUG + virtual void OnRender (); +#endif +}; + +const dReal def_spring_rate=0.5f; +const dReal def_dumping_rate=20.1f; + +IC bool ignore_material( u16 material_idx ) +{ + SGameMtl* material=GMLibrary().GetMaterialByIdx( material_idx ); + return !!material->Flags.test( SGameMtl::flActorObstacle ); +} \ No newline at end of file diff --git a/xrPhysics/PHSimpleCharacterInline.h b/xrPhysics/PHSimpleCharacterInline.h new file mode 100644 index 00000000000..73867d4944a --- /dev/null +++ b/xrPhysics/PHSimpleCharacterInline.h @@ -0,0 +1,161 @@ +void CPHSimpleCharacter::UpdateStaticDamage(dContact* c,SGameMtl* tri_material,bool bo1) +{ + const dReal *v = dBodyGetLinearVel(m_body); + dReal norm_prg = dFabs(dDOT(v,c->geom.normal)); + dReal smag = dDOT(v,v); + dReal plane_pgr = _sqrt(smag-norm_prg*norm_prg); + dReal mag = 0.f; + if(tri_material->Flags.test(SGameMtl::flPassable)) + { + mag = _sqrt(smag)*tri_material->fBounceDamageFactor; + } + else + { + float vel_prg;vel_prg=_max(plane_pgr*tri_material->fPHFriction,norm_prg); + mag = (vel_prg)*tri_material->fBounceDamageFactor; + } + if(mag>m_collision_damage_info.m_contact_velocity) + { + m_collision_damage_info.m_contact_velocity = mag; + m_collision_damage_info.m_dmc_signum = bo1 ? 1.f : -1.f; + m_collision_damage_info.m_dmc_type = SCollisionDamageInfo::ctStatic; + m_collision_damage_info.m_damege_contact = *c; + //m_collision_damage_info.m_object = 0; + m_collision_damage_info.m_obj_id = u16(-1); + } +} + +void CPHSimpleCharacter::UpdateDynamicDamage(dContact* c,u16 obj_material_idx,dBodyID b,bool bo1) +{ + + //if(ph_world ->IsFreezed()) + //return; + const dReal* vel=dBodyGetLinearVel(m_body); + dReal c_vel; + dMass m; + dBodyGetMass(b,&m); + + const dReal* obj_vel=dBodyGetLinearVel(b); + const dReal* norm=c->geom.normal; + dReal norm_vel=dDOT(vel,norm); + dReal norm_obj_vel=dDOT(obj_vel,norm); + + if((bo1&&norm_vel>norm_obj_vel)|| + (!bo1&&norm_obj_vel>norm_vel) + ) return ; + + + dVector3 Pc={vel[0]*m_mass+obj_vel[0]*m.mass,vel[1]*m_mass+obj_vel[1]*m.mass,vel[2]*m_mass+obj_vel[2]*m.mass}; + //dVectorMul(Vc,1.f/(m_mass+m.mass)); + //dVector3 vc_obj={obj_vel[0]-Vc[0],obj_vel[1]-Vc[1],obj_vel[2]-Vc[2]}; + //dVector3 vc_self={vel[0]-Vc[0],vel[1]-Vc[1],vel[2]-Vc[2]}; + //dReal vc_obj_norm=dDOT(vc_obj,norm); + //dReal vc_self_norm=dDOT(vc_self,norm); + + dReal Kself=norm_vel*norm_vel*m_mass/2.f; + dReal Kobj=norm_obj_vel*norm_obj_vel*m.mass/2.f; + + dReal Pcnorm=dDOT(Pc,norm); + dReal KK=Pcnorm*Pcnorm/(m_mass+m.mass)/2.f; + dReal accepted_energy=Kself*m_collision_damage_factor+Kobj*object_damage_factor-KK; + //DeltaK=m1*m2*(v1-v2)^2/(2*(m1+m2)) + if(accepted_energy>0.f) + { + SGameMtl *obj_material=GMLibrary().GetMaterialByIdx(obj_material_idx); + c_vel=dSqrt(accepted_energy/m_mass*2.f)*obj_material->fBounceDamageFactor; + } + else c_vel=0.f; +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDispObjCollisionDammage)&&c_vel>debug_output().dbg_vel_collid_damage_to_display()) + { + float dbg_my_norm_vell=norm_vel; + float dbg_obj_norm_vell=norm_obj_vel; + float dbg_my_kinetic_e=Kself; + float dbg_obj_kinetic_e=Kobj; + float dbg_my_effective_e=Kself*m_collision_damage_factor; + float dbg_obj_effective_e=Kobj*object_damage_factor; + float dbg_free_energy=KK; + LPCSTR name= PhysicsRefObject()->ObjectName(); + + Msg("-----------------------------------------------------------------------------------------"); + Msg("cd %s -effective vell %f", name, c_vel); + Msg("cd %s -my_norm_vell %f", name, dbg_my_norm_vell); + Msg("cd %s -obj_norm_vell %f", name, dbg_obj_norm_vell); + Msg("cd %s -my_kinetic_e %f", name, dbg_my_kinetic_e); + Msg("cd %s -obj_kinetic_e %f", name, dbg_obj_kinetic_e); + Msg("cd %s -my_effective_e %f", name, dbg_my_effective_e); + Msg("cd %s -obj_effective_e %f", name, dbg_obj_effective_e); + Msg("cd %s -effective_acceted_e %f",name, accepted_energy); + Msg("cd %s -real_acceted_e %f", name, Kself+Kobj-KK); + Msg("cd %s -free_energy %f", name, dbg_free_energy); + Msg("-----------------------------------------------------------------------------------------"); + /* + static float dbg_my_norm_vell=0.f; + static float dbg_obj_norm_vell=0.f; + static float dbg_my_kinetic_e=0.f; + static float dbg_obj_kinetic_e=0.f; + static float dbg_my_effective_e=0.f; + static float dbg_obj_effective_e=0.f; + static float dbg_free_energy=0.f; + if() + dbg_my_norm_vell=norm_vel; + dbg_obj_norm_vell=norm_obj_vel; + dbg_my_kinetic_e=Kself; + dbg_obj_kinetic_e=Kobj; + dbg_my_effective_e=Kself*m_collision_damage_factor; + dbg_obj_effective_e=Kobj*object_damage_factor; + dbg_free_energy=KK; + DBG_OutText("-----dbg obj collision damage-------"); + DBG_OutText("my_norm_vell %f",dbg_my_norm_vell); + DBG_OutText("obj_norm_vell %f",dbg_obj_norm_vell); + DBG_OutText("my_kinetic_e %f",dbg_my_kinetic_e); + DBG_OutText("obj_kinetic_e %f", dbg_obj_kinetic_e); + DBG_OutText("my_effective_e %f",dbg_my_effective_e); + DBG_OutText("obj_effective_e %f",dbg_obj_effective_e); + DBG_OutText("free_energy %f",dbg_free_energy); + DBG_OutText("-----------------------------------"); + */ + } +#endif + if(c_vel>m_collision_damage_info.m_contact_velocity) + { + IPhysicsShellHolder* obj=bo1 ? retrieveRefObject(c->geom.g2) : retrieveRefObject(c->geom.g1); + VERIFY(obj); + if(!obj->ObjectGetDestroy()) + { + m_collision_damage_info.m_contact_velocity=c_vel; + m_collision_damage_info.m_dmc_signum=bo1 ? 1.f : -1.f; + m_collision_damage_info.m_dmc_type=SCollisionDamageInfo::ctObject; + m_collision_damage_info.m_damege_contact=*c; + m_collision_damage_info.m_hit_callback=obj->ObjectGetCollisionHitCallback(); + m_collision_damage_info.m_obj_id=obj->ObjectID(); + } + } +} + + +IC void CPHSimpleCharacter::foot_material_update(u16 contact_material_idx,u16 foot_material_idx) +{ + if( m_elevator_state.UpdateMaterial( *p_lastMaterialIDX ) ) + return; + if( *p_lastMaterialIDX!=u16(-1)&& + GMLibrary().GetMaterialByIdx( *p_lastMaterialIDX)->Flags.test(SGameMtl:: flPassable)&& + !b_foot_mtl_check ) + return ; + b_foot_mtl_check =false ; + + const SGameMtl* contact_material = GMLibrary().GetMaterialByIdx(contact_material_idx); + + if(contact_material->Flags.test(SGameMtl::flPassable)) + { + if(contact_material->Flags.test(SGameMtl::flInjurious)) + injuriousMaterialIDX = contact_material_idx ; + else + *p_lastMaterialIDX = contact_material_idx ; + + } + else + *p_lastMaterialIDX=foot_material_idx ; + +} + diff --git a/xrPhysics/PHSplitedShell.cpp b/xrPhysics/PHSplitedShell.cpp new file mode 100644 index 00000000000..7ce8fdaa480 --- /dev/null +++ b/xrPhysics/PHSplitedShell.cpp @@ -0,0 +1,28 @@ +#include "stdafx.h" +#include "PhysicsShell.h" +#include "PHObject.h" +#include "PHWorld.h" +#include "PHInterpolation.h" +#include "PHShell.h" +#include "PHJoint.h" +#include "PHElement.h" +#include "PHSplitedShell.h" +#include "Physics.h" +#include "SpaceUtils.h" +void CPHSplitedShell::Collide() +{ + /////////////////////////////// + CollideStatic(dSpacedGeom(),CPHObject::SelfPointer()); + //near_callback(this,0,(dGeomID)dSpace(),ph_world->GetMeshGeom()); +} + +void CPHSplitedShell::get_spatial_params() +{ + spatialParsFromDGeom((dGeomID)m_space,spatial.sphere.P,AABB,spatial.sphere.R); + if(spatial.sphere.R>m_max_AABBradius) spatial.sphere.R=m_max_AABBradius; +} + +void CPHSplitedShell::DisableObject() +{ + CPHObject::deactivate(); +} diff --git a/xrPhysics/PHSplitedShell.h b/xrPhysics/PHSplitedShell.h new file mode 100644 index 00000000000..4cd7affe3ab --- /dev/null +++ b/xrPhysics/PHSplitedShell.h @@ -0,0 +1,20 @@ +#ifndef PH_SPLITED_SELL +#define PH_SPLITED_SELL + +#include "PHShell.h" + +class CPHSplitedShell: + public CPHShell +{ + float m_max_AABBradius; + virtual void SetMaxAABBRadius (float size){m_max_AABBradius=size;} +protected: + virtual void Collide () ; + virtual void get_spatial_params () ; + virtual void DisableObject () ; +private: +public: + CPHSplitedShell (){m_max_AABBradius=dInfinity;} +}; + +#endif \ No newline at end of file diff --git a/xrPhysics/PHStaticGeomShell.cpp b/xrPhysics/PHStaticGeomShell.cpp new file mode 100644 index 00000000000..4bd52267610 --- /dev/null +++ b/xrPhysics/PHStaticGeomShell.cpp @@ -0,0 +1,138 @@ +#include "stdafx.h" +#include "PHStaticGeomShell.h" +#include "SpaceUtils.h" +//#include "GameObject.h" +#include "IPhysicsShellHolder.h" +#include "phcharacter.h" +#include "iclimableobject.h" + +#include "../Include/xrRender/Kinematics.h" +#include "PHCollideValidator.h" +#include "../xrengine/xr_object.h" +#include "../xrengine/bone.h" + +//#include "game_object_space.h" + +void CPHStaticGeomShell::get_spatial_params() +{ + Fvector AABB; + spatialParsFromDGeom (dSpacedGeometry(),spatial.sphere.P,AABB,spatial.sphere.R); +} + +void CPHStaticGeomShell::PhDataUpdate (dReal step) +{ + Island().Step(step); + Island().Unmerge(); + PhysicsRefObject()->enable_notificate(); + CPHUpdateObject::Deactivate(); +} +void CPHStaticGeomShell::Activate(const Fmatrix& form) +{ + build(); + setStaticForm(form); + get_spatial_params(); + spatial_register(); +} + +void CPHStaticGeomShell::Deactivate() +{ + spatial_unregister(); + CPHUpdateObject::Deactivate(); + destroy(); +} + +CPHStaticGeomShell::CPHStaticGeomShell() +{ + spatial.type|=STYPE_PHYSIC; +} + +void _BCL cb(CBoneInstance* B) +{ + +} + +void P_BuildStaticGeomShell(CPHStaticGeomShell* pUnbrokenObject,IPhysicsShellHolder* obj,ObjectContactCallbackFun* object_contact_callback,const Fobb &b) +{ + pUnbrokenObject->add_Box (b); + pUnbrokenObject->Activate (obj->ObjectXFORM()); + + pUnbrokenObject->set_PhysicsRefObject(obj); + //m_pUnbrokenObject->SetPhObjectInGeomData(m_pUnbrokenObject); + pUnbrokenObject->set_ObjectContactCallback(object_contact_callback); + CPHCollideValidator::SetNonDynamicObject(*pUnbrokenObject); +} +CPHStaticGeomShell* P_BuildStaticGeomShell(IPhysicsShellHolder* obj,ObjectContactCallbackFun* object_contact_callback,const Fobb &b) +{ + CPHStaticGeomShell* pUnbrokenObject=xr_new(); + P_BuildStaticGeomShell(pUnbrokenObject,obj,object_contact_callback,b); + return pUnbrokenObject; +} + +IPHStaticGeomShell* P_BuildStaticGeomShell(IPhysicsShellHolder* obj,ObjectContactCallbackFun* object_contact_callback) +{ + Fobb b; + //IRenderVisual* V=obj->ObjectVisual(); + //R_ASSERT2(V,"need visual to build"); + IKinematics* K =obj->ObjectKinematics(); + R_ASSERT2(K,"need visual to build"); + K->CalculateBones (TRUE); //. bForce - was TRUE + + //V->getVisData().box.getradius (b.m_halfsize); + K->GetBox().getradius (b.m_halfsize); + + b.xform_set (Fidentity); + CPHStaticGeomShell* pUnbrokenObject =P_BuildStaticGeomShell(obj,object_contact_callback,b); + + + //IKinematics* K=smart_cast(V); VERIFY(K); + K->CalculateBones(TRUE); + for (u16 k=0; kLL_BoneCount(); k++){ + K->LL_GetBoneInstance(k).set_callback( bctPhysics,cb,K->LL_GetBoneInstance(k).callback_param(), TRUE); + //K->LL_GetBoneInstance(k).Callback_overwrite = TRUE; + //K->LL_GetBoneInstance(k).Callback = cb; + } + return pUnbrokenObject; +} + +void DestroyStaticGeomShell(IPHStaticGeomShell* &UnbrokenObject) +{ + if( !UnbrokenObject ) + return; + CPHStaticGeomShell* gs = static_cast( UnbrokenObject ); + gs->Deactivate(); + xr_delete(gs); + UnbrokenObject = 0; +} + + +class IClimableObject; +class CPHLeaderGeomShell: public CPHStaticGeomShell +{ +IClimableObject *m_pClimable; +public: + CPHLeaderGeomShell (IClimableObject* climable); +void near_callback (CPHObject* obj); +}; + +IPHStaticGeomShell *P_BuildLeaderGeomShell( IClimableObject* obj, ObjectContactCallbackFun* callback, const Fobb &b ) +{ + CPHLeaderGeomShell * pStaticShell=xr_new(obj); + P_BuildStaticGeomShell( smart_cast(pStaticShell), smart_cast(obj), 0, b ); + pStaticShell->SetMaterial(obj->Material()); + pStaticShell->set_ObjectContactCallback( callback ); + return pStaticShell; +} + + +CPHLeaderGeomShell::CPHLeaderGeomShell(IClimableObject* climable) +{ + m_pClimable=climable; +} +void CPHLeaderGeomShell::near_callback (CPHObject* obj) +{ + if(obj && obj->CastType()==CPHObject::tpCharacter) + { + CPHCharacter* ch=static_cast(obj); + ch->SetElevator(m_pClimable); + } +} diff --git a/xrPhysics/PHStaticGeomShell.h b/xrPhysics/PHStaticGeomShell.h new file mode 100644 index 00000000000..e9098dda5d0 --- /dev/null +++ b/xrPhysics/PHStaticGeomShell.h @@ -0,0 +1,36 @@ +#ifndef PH_STATIC_GEOM_SHELL_H +#define PH_STATIC_GEOM_SHELL_H +#include "PHGeometryOwner.h" +#include "PHObject.h" +#include "phupdateobject.h" +#include "iphstaticgeomshell.h" +class CPHStaticGeomShell: + public CPHGeometryOwner, + public CPHObject, + public CPHUpdateObject, + public IPHStaticGeomShell +{ + +#ifdef DEBUG + virtual IPhysicsShellHolder *ref_object () { return CPHGeometryOwner::PhysicsRefObject() ;} +#endif + + void get_spatial_params (); +virtual void EnableObject (CPHObject* obj){CPHUpdateObject::Activate();} +virtual dGeomID dSpacedGeom (){return dSpacedGeometry();} +virtual void PhDataUpdate (dReal step); +virtual void PhTune (dReal step){} +virtual void InitContact (dContact* c,bool& do_collide,u16 /*material_idx_1*/,u16 /*material_idx_2*/){} +virtual u16 get_elements_number () {return 0;}; +virtual CPHSynchronize *get_element_sync (u16 element) {return NULL;}; +public: + void Activate (const Fmatrix& form); + void Deactivate (); + CPHStaticGeomShell (); +virtual ~CPHStaticGeomShell (){}; +}; + +//CPHStaticGeomShell* P_BuildStaticGeomShell(CGameObject* obj,ObjectContactCallbackFun* object_contact_callback); +//CPHStaticGeomShell* P_BuildStaticGeomShell(CGameObject* obj,ObjectContactCallbackFun* object_contact_callback,Fobb &b); +//void P_BuildStaticGeomShell(CPHStaticGeomShell* shell,CGameObject* obj,ObjectContactCallbackFun* object_contact_callback,Fobb &b); +#endif \ No newline at end of file diff --git a/xrPhysics/PHUpdateObject.h b/xrPhysics/PHUpdateObject.h new file mode 100644 index 00000000000..b3d2d99e01e --- /dev/null +++ b/xrPhysics/PHUpdateObject.h @@ -0,0 +1,20 @@ +#pragma once +#include "PHItemList.h" + +class CPhysicsShell; +class XRPHYSICS_API CPHUpdateObject +{ + DECLARE_PHLIST_ITEM(CPHUpdateObject) + bool b_activated ; + +public: + CPHUpdateObject () ; + virtual ~CPHUpdateObject() {Deactivate();} + void Activate () ; + void Deactivate () ; +IC bool IsActive () {return b_activated;} + virtual void PhDataUpdate (float step) =0; + virtual void PhTune (float step) =0; + virtual void NetRelcase (CPhysicsShell *s) {}; +}; +DEFINE_PHITEM_LIST(CPHUpdateObject,PH_UPDATE_OBJECT_STORAGE,PH_UPDATE_OBJECT_I) \ No newline at end of file diff --git a/xrPhysics/PHValideValues.h b/xrPhysics/PHValideValues.h new file mode 100644 index 00000000000..f43d2ccc5c4 --- /dev/null +++ b/xrPhysics/PHValideValues.h @@ -0,0 +1,147 @@ +#ifndef PH_VALIDE_VALUES +#define PH_VALIDE_VALUES + +#include "mathutilsode.h" +#include "ph_valid_ode.h" +class CSafeValue +{ + float m_safe_value ; +public: + CSafeValue (float val) + { + R_ASSERT(_valid(val));m_safe_value=val; + } + CSafeValue () + { + m_safe_value=0.f; + } + IC void new_val (float& val) + { + if(_valid(val))m_safe_value=val;else val=m_safe_value; + } + +}; + + +class CSafeVector3 +{ + CSafeValue m_safe_values [3] ; +public: + + IC void new_val (float *val) + { + m_safe_values[0].new_val(val[0]); + m_safe_values[1].new_val(val[1]); + m_safe_values[2].new_val(val[2]); + } +}; + +class CSafeVector4 +{ + CSafeValue m_safe_values [4] ; +public: + + IC void new_val (float *val) + { + m_safe_values[0].new_val(val[0]); + m_safe_values[1].new_val(val[1]); + m_safe_values[2].new_val(val[2]); + m_safe_values[3].new_val(val[3]); + } +}; + +class CSafeBodyLinearState +{ + CSafeVector3 m_safe_position ; + CSafeVector3 m_safe_linear_vel ; +public: + IC void create (dBodyID b) + { + R_ASSERT(dBodyStateValide(b)); + new_state(b); + } + IC void new_state (dBodyID b) + { + dVector3 v; + dVectorSet(v,dBodyGetPosition(b)); + m_safe_position.new_val(v); + dBodySetPosition(b,v[0],v[1],v[2]); + + dVectorSet(v,dBodyGetLinearVel(b)); + m_safe_linear_vel.new_val(v); + dBodySetLinearVel(b,v[0],v[1],v[2]); + + } +}; + +class CSafeFixedRotationState +{ + dMatrix3 rotation; + CSafeBodyLinearState m_safe_linear_state; +public: + CSafeFixedRotationState() + { + dRSetIdentity( rotation ); + } + IC void create (dBodyID b) + { + R_ASSERT(dBodyStateValide(b)); + std::copy_n( dBodyGetRotation(b), sizeof(rotation)/sizeof(dReal), rotation ); + new_state(b); + } + IC void set_rotation ( const dMatrix3 r ) + { + VERIFY( sizeof(rotation) == sizeof(dMatrix3) ); + std::copy_n( r, sizeof(rotation)/sizeof(dReal), rotation ); + } + IC void new_state (dBodyID b) + { + + dBodySetRotation(b,rotation); + dBodySetAngularVel(b,0.f,0.f,0.f); + m_safe_linear_state.new_state(b); + } +}; +class CSafeBodyAngularState +{ + CSafeVector3 m_safe_angular_vel ; + CSafeVector4 m_safe_quaternion ; +public: + IC void create (dBodyID b) + { + R_ASSERT(dBodyStateValide(b)); + new_state(b); + } + IC void new_state (dBodyID b) + { + dVector3 v; + + dVectorSet(v,dBodyGetAngularVel(b)); + m_safe_angular_vel.new_val(v); + dBodySetAngularVel(b,v[0],v[1],v[2]); + + dQuaternion q; + dQuaternionSet(q,dBodyGetQuaternion(b)); + m_safe_quaternion.new_val(q); + dBodySetQuaternion(b,q); + } +}; + +class CSafeBodyState +{ + CSafeBodyLinearState m_safe_linear_state; + CSafeBodyAngularState m_safe_angular_state; +public: + IC void create (dBodyID b) + { + R_ASSERT(dBodyStateValide(b)); + new_state(b); + } + IC void new_state (dBodyID b) + { + m_safe_linear_state.new_state(b); + m_safe_angular_state.new_state(b); + } + +}; +#endif \ No newline at end of file diff --git a/xrPhysics/PHWorld.cpp b/xrPhysics/PHWorld.cpp new file mode 100644 index 00000000000..5c90d4b70dd --- /dev/null +++ b/xrPhysics/PHWorld.cpp @@ -0,0 +1,692 @@ +#include "stdafx.h" + +#include "PHWorld.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PhysicsCommon.h" +//#include "Level.h" +#include "ExtendedGeom.h" +#include "draymotions.h" +#include "PHCollideValidator.h" +#include "../xrEngine/gamemtllib.h" +//#include "PhysicsGamePars.h" +#include "params.h" +#ifdef DEBUG +# include "debug_output.h" +#endif +//#include "PHCommander.h" +//#include "PHSimpleCalls.h" +#include "../xrserverentities/PHSynchronize.h" +#include "../xrserverentities/phnetstate.h" +#include "geometrybits.h" +#include "console_vars.h" +#include "../xrengine/device.h" +#include "../xrengine/defines.h" +#include "../xrcdb/xr_area.h" +#include "../xrcore/fs_internal.h" +#ifdef DEBUG +// void DBG_ObjAfterPhDataUpdate ( CPHObject *obj ); +// void DBG_ObjBeforePhDataUpdate ( CPHObject *obj ); +// void DBG_ObjAfterStep ( CPHObject *obj ); +// void DBG_ObjBeforeStep ( CPHObject *obj ); +// void DBG_ObjeAfterPhTune ( CPHObject *obj ); +// void DBG_ObjBeforePhTune ( CPHObject *obj ); +// void DBG_ObjAfterCollision ( CPHObject *obj ); +// void DBG_ObjBeforeCollision ( CPHObject *obj ); +#endif +////////////////////////////////////////////////////////////// +//////////////CPHMesh/////////////////////////////////////////// +/////////////////////////////////////////////////////////// +//BOOL g_bDebugDumpPhysicsStep = 0; +CPHWorld *ph_world = 0; + +IPHWorld * __stdcall physics_world() +{ + return ph_world; +} + +void __stdcall create_physics_world( bool mt, CObjectSpace *os, CObjectList *lo, CRenderDeviceBase *dv ) //IPHWorldUpdateCallbck &commander, +{ + ph_world = xr_new(); //&commander + VERIFY( os ); +// VERIFY( lo ); + VERIFY( dv ); + ph_world->Create (mt, os, lo, dv); +} + +void __stdcall destroy_physics_world() +{ + ph_world->Destroy (); + xr_delete (ph_world); +} + +CObjectSpace* __stdcall create_object_space() +{ + //CFileReader* fr = xr_new("D:/STALKER/resources/gamedata/levels/stohe_selo/level.cform"); + CFileReader* fr = xr_new("ActorEditorLevel.cform"); + CObjectSpace* os = xr_new(); + g_SpatialSpace = xr_new (); + g_SpatialSpacePhysic = xr_new (); + os->Load( fr, 0 ); + //xr_delete(fr); + return os; +} +CObjectSpace* __stdcall mesh_create_object_space(Fvector* verts, CDB::TRI* tris, const hdrCFORM &H, CDB::build_callback build_callback) +{ + CObjectSpace* os = xr_new(); + g_SpatialSpace = xr_new (); + g_SpatialSpacePhysic = xr_new (); + os->Create( verts, tris, H, build_callback ); + return os; +} +void __stdcall set_mtl_lib(CGameMtlLibrary * l) +{ + PGMLib = l; +} +void __stdcall destroy_object_space(CObjectSpace* &os) +{ + xr_delete(os); +} + +void CPHMesh ::Create(dSpaceID space, dWorldID world){ + Geom = dCreateTriList(space, 0, 0); + CPHGeometryBits::init_geom( *this ); +} +///////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////// + +void CPHMesh ::Destroy(){ + + dGeomDestroy(Geom); + dTriListClass=-1; + +} + + + +//////////////////////////////////////////////////////////////////////////// +///////////CPHWorld///////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +//#define PH_PLAIN +#ifdef PH_PLAIN +dGeomID plane; +#endif + +#ifdef DEBUG + +void CPHWorld::OnRender() +{ + + debug_output().PH_DBG_Render(); +} +#endif + +static struct sempty_update_callback: +public IPHWorldUpdateCallbck +{ + void update_step (){}; + void phys_shell_relcase (CPhysicsShell* sh){}; +} empty_update_callback; + + + +CPHWorld::CPHWorld( ): // IPHWorldUpdateCallbck *_update_callback + m_update_callback( &empty_update_callback ), + m_default_contact_shotmark(0), + m_default_character_contact_shotmark(0), + physics_step_time_callback(0), + m_object_space( 0 ), + m_level_objects( 0 ), + m_device( 0 ) +{ + + disable_count=0; + m_frame_time=0.f; + m_previous_frame_time=0.f; + b_frame_mark=false; + m_steps_num=0; + m_steps_short_num = 0; + m_frame_sum=0.f; + m_delay=0; + m_previous_delay=0; + m_reduce_delay=0; + m_update_delay_count=0; + b_world_freezed=false; + b_processing=false; + m_gravity =default_world_gravity; + b_exist=false; +} +void CPHWorld::SetStep(float s) +{ + fixed_step = s; + world_cfm = CFM(SPRING_S(base_cfm,base_erp,base_fixed_step),DAMPING(base_cfm,base_erp)); + world_erp = ERP(SPRING_S(base_cfm,base_erp,base_fixed_step),DAMPING(base_cfm,base_erp)); + world_spring = 1.0f*SPRING (world_cfm,world_erp); + world_damping = 1.0f*DAMPING(world_cfm,world_erp); + if(ph_world&&ph_world->Exist()) + { + float frame_time = Device().fTimeDelta; + u32 it_number = iFloor (frame_time /fixed_step); + frame_time -= it_number*fixed_step; + ph_world->m_previous_frame_time = frame_time; + ph_world->m_frame_time = frame_time; + } +} +void CPHWorld::Create( bool mt, CObjectSpace * os, CObjectList *lo, CRenderDeviceBase *dv ) +{ + LoadParams (); + dWorldID phWorld=0; + m_object_space = os; + m_level_objects = lo; + m_device = dv; + //if (psDeviceFlags.test(mtPhysics)) Device.seqFrameMT.Add (this,REG_PRIORITY_HIGH); + //else Device.seqFrame.Add (this,REG_PRIORITY_LOW); + + //if ( mt ) + // Device().seqFrameMT.Add (this,REG_PRIORITY_HIGH); + //else + // Device().seqFrame.Add (this,REG_PRIORITY_LOW); + + Device().AddSeqFrame( this, mt ); + + //m_commander =xr_new(); + //dVector3 extensions={2048,256,2048}; + /* + Fbox level_box = Level().ObjectSpace.GetBoundingVolume(); + Fvector level_size,level_center; + level_box . getsize (level_size); + level_box . getcenter (level_center); + dVector3 extensions = { level_size.x ,256.f,level_size.z}; + dVector3 center = {level_center.x,0.f,level_center.z}; + */ + +#ifdef ODE_SLOW_SOLVER +#else + + dWorldSetAutoEnableDepthSF1(phWorld, 100000000); + ///dWorldSetContactSurfaceLayer(phWorld,0.f); + //phWorld->contactp.min_depth =0.f; + +#endif + ContactGroup = dJointGroupCreate(0); + dWorldSetGravity (phWorld, 0,-Gravity(), 0);//-2.f*9.81f + Mesh.Create (0,phWorld); +#ifdef PH_PLAIN + plane=dCreatePlane(Space,0,1,0,0.3f); +#endif + + //const dReal k_p=2400000.f;//550000.f;///1000000.f; + //const dReal k_d=200000.f; + dWorldSetERP(phWorld, ERP(world_spring,world_damping) ); + dWorldSetCFM(phWorld, CFM(world_spring,world_damping)); + //dWorldSetERP(phWorld, 0.2f); + //dWorldSetCFM(phWorld, 0.000001f); + disable_count=0; + m_motion_ray=dCreateRayMotions(0); + phBoundaries.set(inl_ph_world().ObjectSpace().GetBoundingVolume()); + phBoundaries.y1-=30.f; + CPHCollideValidator::Init(); + b_exist=true; + + StepNumIterations( phIterations ); + SetStep( ph_console::ph_step_time ); +} + +///////////////////////////////////////////////////////////////////////////// + +void CPHWorld::Destroy() +{ + r_spatial.clear(); + //xr_delete(m_commander); + Mesh.Destroy(); +#ifdef PH_PLAIN + dGeomDestroy(plane); +#endif +#ifdef DEBUG + debug_output().PH_DBG_Clear(); +#endif + dGeomDestroy(m_motion_ray); + dJointGroupEmpty(ContactGroup); + dJointGroupDestroy(ContactGroup); + ContactFeedBacks.clear(); + ContactEffectors.clear(); + dCloseODE(); + dCylinderClassUser=-1; + dRayMotionsClassUser=-1; + +// Device().seqFrameMT.Remove (this); +// Device().seqFrame.Remove (this); + Device().RemoveSeqFrame( this ); + b_exist=false; +} +void CPHWorld::SetGravity(float g) +{ + m_gravity =g; + dWorldID phWorld =0; + dWorldSetGravity (phWorld, 0,-m_gravity, 0);//-2.f*9.81f + +} + +void CPHWorld::OnFrame() +{ + // Msg ("------------- physics: %d / %d",u32(Device.dwFrame),u32(m_steps_num)); + //���������� ����� ���� + /* + Device.Statistic->TEST0.Begin (); + Level().BulletManager().Update (); + Device.Statistic->TEST0.End (); + */ +#ifdef DEBUG + //DBG_DrawFrameStart(); + //DBG_DrawStatBeforeFrameStep(); +#endif + Device().StatPhysics()->Physics.Begin (); + FrameStep (Device().fTimeDelta); + Device().StatPhysics()->Physics.End (); +#ifdef DEBUG + //DBG_DrawStatAfterFrameStep(); + +#endif +} + +////////////////////////////////////////////////////////////////////////////// +//static dReal frame_time=0.f; +static u32 start_time=0; +void CPHWorld::Step() +{ +#ifdef DEBUG + debug_output().dbg_reused_queries_per_step() =0 ; + debug_output().dbg_new_queries_per_step() =0 ; +#endif + + VERIFY(b_processing||IsFreezed()); + + PH_OBJECT_I i_object; + PH_UPDATE_OBJECT_I i_update_object; + + if(disable_count==0) + { + disable_count=worldDisablingParams.objects_params.L2frames; + for(i_object=m_recently_disabled_objects.begin();m_recently_disabled_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + obj->check_recently_deactivated(); + ++i_object; + } + } + if(!IsFreezed()) + --disable_count; + + ++m_steps_num; + ++m_steps_short_num; + Device().StatPhysics()->ph_collision.Begin (); + + + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); +#ifdef DEBUG + debug_output().DBG_ObjBeforeCollision( obj ); +#endif + obj->Collide(); +#ifdef DEBUG + debug_output().DBG_ObjAfterCollision( obj ); +#endif + ++i_object; + } + + + + Device().StatPhysics()->ph_collision.End (); + +#ifdef DEBUG + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + if( debug_output().ph_dbg_draw_mask().test(phDbgDrawEnabledAABBS) ) + debug_output().DBG_DrawPHObject(obj); + ++i_object; + } +#endif + + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + ++i_object; + +#ifdef DEBUG + debug_output().DBG_ObjBeforePhTune( obj ); +#endif + + obj->PhTune(fixed_step); + +#ifdef DEBUG + debug_output().DBG_ObjeAfterPhTune( obj ); +#endif + + } + + for(i_update_object=m_update_objects.begin();m_update_objects.end() != i_update_object;) + { CPHUpdateObject* obj=(*i_update_object); + ++i_update_object; + obj->PhTune(fixed_step); + } + + Device().StatPhysics()->ph_core.Begin (); + +#ifdef DEBUG + debug_output().dbg_bodies_num()=0; + debug_output().dbg_joints_num()=0; + debug_output().dbg_islands_num()=0; +#endif +////////////////////////////////////////////////////////////////////// + VERIFY( m_update_callback ); + m_update_callback->update_step(); +// m_commander ->update(); +////////////////////////////////////////////////////////////////////// + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + ++i_object; +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawObjectStatistics)) + { + if(obj->Island().IsActive()) + { + debug_output().dbg_islands_num()++; + debug_output().dbg_joints_num()+=obj->Island().nj; + debug_output().dbg_bodies_num()+=obj->Island().nb; + } + } +#endif + +#ifdef DEBUG + debug_output().DBG_ObjBeforeStep( obj ); +#endif + obj->IslandStep(fixed_step); + +#ifdef DEBUG + debug_output().DBG_ObjAfterStep( obj ); +#endif + } + + Device().StatPhysics()->ph_core.End (); + + + + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + ++i_object; + obj->IslandReinit(); + +#ifdef DEBUG + debug_output().DBG_ObjBeforePhDataUpdate( obj ); +#endif + + obj->PhDataUpdate(fixed_step); + +#ifdef DEBUG + debug_output().DBG_ObjAfterPhDataUpdate( obj ); +#endif + + obj->spatial_move(); + } + + for(i_update_object=m_update_objects.begin();m_update_objects.end() != i_update_object;) + { + CPHUpdateObject* obj=*i_update_object; + ++i_update_object; + obj->PhDataUpdate(fixed_step); + } + + + +#ifdef DEBUG + debug_output().dbg_contacts_num()=ContactGroup->num; +#endif + dJointGroupEmpty(ContactGroup);//this is to be called after PhDataUpdate!!!-the order is critical!!! + ContactFeedBacks.empty(); + ContactEffectors.empty(); + + + + if(physics_step_time_callback) + { + physics_step_time_callback(start_time,start_time+u32(fixed_step*1000)); + start_time += u32(fixed_step*1000); + }; +} + +void CPHWorld::StepTouch() +{ + PH_OBJECT_I i_object; + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + obj->Collide(); + + ++i_object; + } + + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + ++i_object; + obj->Island().Enable(); + } + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + ++i_object; + obj->IslandReinit(); + obj->spatial_move(); + } + dJointGroupEmpty(ContactGroup); + ContactFeedBacks.empty(); + ContactEffectors.empty(); +} + +u32 CPHWorld::CalcNumSteps (u32 dTime) +{ + if (dTime < m_frame_time*1000) return 0; + u32 res = iCeil((float(dTime) - m_frame_time*1000) / (fixed_step*1000)); +// if (dTime < fixed_step*1000) return 0; +// u32 res = iFloor((float(dTime) / 1000 / fixed_step)+0.5f); + return res; +}; + +void CPHWorld::FrameStep(dReal step) +{ + if(IsFreezed()) return; + + VERIFY (_valid(step)) ; + step *= phTimefactor ; + // compute contact joints and forces + + //step+=astep; + + //const dReal k_p=24000000.f;//550000.f;///1000000.f; + //const dReal k_d=400000.f; + u32 it_number; + float frame_time=m_frame_time; + frame_time+=step; + //m_frame_sum+=step; +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawObjectStatistics)) + { + static float dbg_iterations=0.f; + dbg_iterations=dbg_iterations*0.9f+step/fixed_step*0.1f; + b_processing=true; + debug_output().DBG_OutText("phys steps per frame %2.1f",dbg_iterations); + b_processing=false; + } +#endif + if(!(frame_time 20 ) + Msg("!!!TOO MANY PHYSICS STEPS PER FRAME = %d !!!",it_number); + for( UINT i=0; i < it_number;++i ) + Step(); + b_processing=false; +#ifdef DEBUG + debug_output().DBG_DrawStatAfterFrameStep(); +#endif +} + +void CPHWorld::AddObject(CPHObject* object){ + m_objects.push_back(object); + //xr_list ::iterator i= m_objects.end(); + //return (--m_objects.end()); +}; +void CPHWorld::AddRecentlyDisabled(CPHObject* object) +{ + m_recently_disabled_objects.push_back(object); +} +void CPHWorld::RemoveFromRecentlyDisabled(PH_OBJECT_I i) +{ + m_recently_disabled_objects.erase(i); +} + +void CPHWorld::AddUpdateObject(CPHUpdateObject* object) +{ +//. if(object->IsFreezed())m_freezed_update_objects.erase(i); + m_update_objects.push_back(object); +} + +void CPHWorld::RemoveUpdateObject(PH_UPDATE_OBJECT_I i) +{ + m_update_objects.erase(i); +} + +void CPHWorld::RemoveObject(PH_OBJECT_I i){ + m_objects.erase((i)); +}; + +void CPHWorld::AddFreezedObject(CPHObject* obj) +{ + m_freezed_objects.push_back(obj); +} + +void CPHWorld::RemoveFreezedObject(PH_OBJECT_I i) +{ + m_freezed_objects.erase(i); +} +void CPHWorld::Freeze() +{ + R_ASSERT2(!b_world_freezed,"already freezed!!!"); + m_freezed_objects.move_items(m_objects); + + PH_OBJECT_I iter=m_freezed_objects.begin(), + e= m_freezed_objects.end() ; + + + + for(; e != iter;++iter) + (*iter)->FreezeContent(); + + m_freezed_update_objects.move_items(m_update_objects); + + b_world_freezed=true; +} +void CPHWorld::UnFreeze() +{ + R_ASSERT2(b_world_freezed,"is not freezed!!!"); + PH_OBJECT_I iter=m_freezed_objects.begin(), + e= m_freezed_objects.end() ; + for(; e != iter;++iter) + (*iter)->UnFreezeContent(); + + m_objects.move_items(m_freezed_objects); + + m_update_objects.move_items(m_freezed_update_objects); + b_world_freezed=false; +} +bool CPHWorld::IsFreezed() +{ + return b_world_freezed; +} + +void CPHWorld::CutVelocity(float l_limit,float a_limit) +{ + PH_OBJECT_I i_object; + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + obj->CutVelocity(l_limit,a_limit); + ++i_object; + } +} +void CPHWorld::NetRelcase(CPhysicsShell *s) +{ +/* + CPHReqComparerHasShell c(s); + m_commander->remove_calls(&c); +*/ + VERIFY( m_update_callback ); + m_update_callback->phys_shell_relcase(s); + PH_UPDATE_OBJECT_I i_update_object; + for(i_update_object=m_update_objects.begin();m_update_objects.end() != i_update_object;) + { CPHUpdateObject* obj=(*i_update_object); + ++i_update_object; + obj->NetRelcase( s ); + //obj->PhTune(fixed_step); + } + +} +/* +void CPHWorld::AddCall(CPHCondition*c,CPHAction*a) +{ + m_commander->add_call(c,a); +} +*/ +u16 CPHWorld::ObjectsNumber() +{ + return m_objects.count(); +} +u16 CPHWorld::UpdateObjectsNumber() +{ + return m_update_objects.count(); +} +void CPHWorld::GetState(V_PH_WORLD_STATE& state) +{ + state.clear(); + PH_OBJECT_I i_object; + for(i_object=m_objects.begin();m_objects.end() != i_object;) + { + CPHObject* obj=(*i_object); + const u16 els=obj->get_elements_number(); + for(u16 i=0;els>i;++i) + { + std::pair s; + s.first=obj->get_element_sync(i); + s.first->get_State(s.second); + state.push_back(s); + } + ++i_object; + } +} + +void CPHWorld::StepNumIterations( int num_it ) +{ + dWorldSetQuickStepNumIterations( NULL, num_it ); +} \ No newline at end of file diff --git a/xrPhysics/PHWorld.h b/xrPhysics/PHWorld.h new file mode 100644 index 00000000000..05778d1d236 --- /dev/null +++ b/xrPhysics/PHWorld.h @@ -0,0 +1,149 @@ +#ifndef PH_WORLD_H +#define PH_WORLD_H +#include "Physics.h" +#include "phupdateobject.h" +#include "IPHWorld.h" +#include +#include "physics_scripted.h" +#include "../xrEngine/pure.h" +// refs +struct SGameMtlPair; +//class CPHCommander; +//class CPHCondition; +//class CPHAction; +struct SPHNetState; +class CPHSynchronize; +typedef xr_vector > V_PH_WORLD_STATE; +class CPHMesh { + dGeomID Geom; +public: + dGeomID GetGeom(){return Geom;} + void Create(dSpaceID space, dWorldID world); + void Destroy(); +}; + +#define PHWORLD_SOUND_CACHE_SIZE 8 + +//////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +class CObjectSpace; +class CObjectList; +class CPHWorld : public pureFrame, + public IPHWorld, + public cphysics_scripted, + private boost::noncopyable + #ifdef DEBUG + , public pureRender + #endif +{ + double m_start_time ; + u32 m_delay ; + u32 m_previous_delay ; + u32 m_reduce_delay ; + u32 m_update_delay_count ; + bool b_world_freezed ; + bool b_processing; + bool b_exist; + static const u32 update_delay=1 ; +/// dSpaceID Space ; + + CPHMesh Mesh ; + PH_OBJECT_STORAGE m_objects ; + PH_OBJECT_STORAGE m_freezed_objects ; + PH_OBJECT_STORAGE m_recently_disabled_objects ; + PH_UPDATE_OBJECT_STORAGE m_update_objects ; + PH_UPDATE_OBJECT_STORAGE m_freezed_update_objects ; + dGeomID m_motion_ray; + //CPHCommander *m_commander; + IPHWorldUpdateCallbck *m_update_callback ; + CObjectSpace *m_object_space ; + CObjectList *m_level_objects ; + CRenderDeviceBase *m_device; ; +public: + xr_vector r_spatial; +public: + u64 m_steps_num ; +private: + u16 m_steps_short_num ; +public: + double m_frame_sum ; + dReal m_previous_frame_time ; + bool b_frame_mark ; + dReal m_frame_time ; + float m_update_time ; + u16 disable_count ; + float m_gravity ; +private: + ContactCallbackFun *m_default_contact_shotmark ; + ContactCallbackFun *m_default_character_contact_shotmark ; + PhysicsStepTimeCallback *physics_step_time_callback ; +public: + + CPHWorld ( ) ; + virtual ~CPHWorld (){} ; + +//IC dSpaceID GetSpace () {return Space;} ; +IC bool Exist () {return b_exist ;} + void Create (bool mt, CObjectSpace * os, CObjectList *lo, CRenderDeviceBase* dv ); + void SetGravity (float g) ; +IC float Gravity () {return m_gravity;} + void AddObject (CPHObject* object) ; + void AddUpdateObject (CPHUpdateObject* object) ; + void AddRecentlyDisabled (CPHObject* object) ; + void RemoveFromRecentlyDisabled (PH_OBJECT_I i) ; + void RemoveObject (PH_OBJECT_I i) ; + void RemoveUpdateObject (PH_UPDATE_OBJECT_I i) ; + dGeomID GetMeshGeom () {return Mesh.GetGeom();} +IC dGeomID GetMotionRayGeom () {return m_motion_ray;} + void SetStep ( float s ) ; + void Destroy () ; +IC float FrameTime (bool frame_mark){return b_frame_mark==frame_mark ? m_frame_time :m_previous_frame_time;} + + void FrameStep (dReal step=0.025f) ; + void Step () ; + void StepTouch () ; + void CutVelocity (float l_limit, float a_limit); + void GetState (V_PH_WORLD_STATE& state) ; + void Freeze () ; + void UnFreeze () ; + void AddFreezedObject (CPHObject* obj) ; + void RemoveFreezedObject (PH_OBJECT_I i) ; + bool IsFreezed () ; +IC bool Processing () {return b_processing;} + u32 CalcNumSteps (u32 dTime) ; + u16 ObjectsNumber () ; + u16 UpdateObjectsNumber () ; +IC u16 StepsShortCnt () {return m_steps_short_num;} + u64 &StepsNum () {return m_steps_num;} + float FrameTime () {return m_frame_time;} +ContactCallbackFun *default_contact_shotmark () { return m_default_contact_shotmark; } +ContactCallbackFun *default_character_contact_shotmark() { return m_default_character_contact_shotmark; } + + void set_default_contact_shotmark (ContactCallbackFun *f) { m_default_contact_shotmark = f; } + void set_default_character_contact_shotmark(ContactCallbackFun *f){ m_default_character_contact_shotmark = f; } + void NetRelcase (CPhysicsShell* s) ; + CObjectSpace &ObjectSpace () { VERIFY( m_object_space ); return *m_object_space; } + CObjectList &LevelObjects () { VERIFY( m_level_objects ); return *m_level_objects; } + CRenderDeviceBase &Device () { VERIFY( m_device ); return *m_device; } + +// void AddCall (CPHCondition*c,CPHAction*a); +#ifdef DEBUG + virtual void OnRender () ; +#endif + virtual void _BCL OnFrame () ; +private: + void StepNumIterations ( int num_it ) ; + iphysics_scripted &get_scripted () { return *this; } + void set_step_time_callback (PhysicsStepTimeCallback* cb ){ physics_step_time_callback = cb; } + void set_update_callback ( IPHWorldUpdateCallbck* cb ){ VERIFY( cb ); m_update_callback = cb; } +// DECLARE_SCRIPT_REGISTER_FUNCTION +}; +//add_to_type_list(CPHWorld) +//#undef script_type_list +//#define script_type_list save_type_list(CPHWorld) +extern CPHWorld *ph_world ; +IC CPHWorld& inl_ph_world () +{ + return *ph_world; +} +#endif \ No newline at end of file diff --git a/xrPhysics/Physics.cpp b/xrPhysics/Physics.cpp new file mode 100644 index 00000000000..fd71a00fd1a --- /dev/null +++ b/xrPhysics/Physics.cpp @@ -0,0 +1,542 @@ +#include "StdAfx.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PHContactBodyEffector.h" +#include "../xrEngine/gamemtllib.h" +//#include "gameobject.h" +//#include "PhysicsShellHolder.h" +#include "PHCollideValidator.h" +#ifdef DEBUG +#include "debug_output.h" +#endif +/////////////////////////////////////////////////////////////// +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/ode/src/collision_kernel.h" +#include "../3rd party/ode/ode/src/joint.h" +#include "../3rd party/ode/ode/src/objects.h" +#pragma warning(default:4267) +#pragma warning(default:4995) + +extern CPHWorld *ph_world; +/////////////////////////////////////////////////////////////////// + +#include "ExtendedGeom.h" +//union dInfBytes dInfinityValue = {{0,0,0x80,0x7f}}; +//PhysicsStepTimeCallback *physics_step_time_callback = 0; + +const float default_w_limit = 9.8174770f;//(M_PI/16.f/(fixed_step=0.02f)); +const float default_l_limit = 150.f;//(3.f/fixed_step=0.02f); +const float default_l_scale = 1.01f; +const float default_w_scale = 1.01f; +const float default_k_l = 0.0002f;//square resistance !! +const float default_k_w = 0.05f; + + +extern const u16 max_joint_allowed_for_exeact_integration = 30; + +//base params +const float base_fixed_step = 0.02f ; +const float base_erp = 0.54545456f ; +const float base_cfm = 1.1363636e-006f ; +//base params +float fixed_step = 0.01f; +float world_cfm = CFM(SPRING_S(base_cfm,base_erp,base_fixed_step),DAMPING(base_cfm,base_erp)); +float world_erp = ERP(SPRING_S(base_cfm,base_erp,base_fixed_step),DAMPING(base_cfm,base_erp)); +float world_spring = 1.0f*SPRING (world_cfm,world_erp); +float world_damping = 1.0f*DAMPING(world_cfm,world_erp); + + +const float default_world_gravity = 2*9.81f; + + +///////////////////////////////////////////////////// + +int phIterations = 18; +float phTimefactor = 1.f; +//float phBreakCommonFactor = 0.01f; +//float phRigidBreakWeaponFactor = 1.f; +Fbox phBoundaries = {1000.f,1000.f,-1000.f,-1000.f}; +//float ph_tri_query_ex_aabb_rate = 1.3f; +//int ph_tri_clear_disable_count = 10; +dWorldID phWorld; + +///////////////////////////////////// +dJointGroupID ContactGroup; +CBlockAllocator ContactFeedBacks; +CBlockAllocator ContactEffectors; + +/////////////////////////////////////////////////////////// +class SApplyBodyEffectorPred +{ + +public: + SApplyBodyEffectorPred() + { + } + + void operator ()(CPHContactBodyEffector* pointer) const + { + pointer->Apply(); + } +}; +///////////////////////////////////////////////////////////////////////////// +IC void add_contact_body_effector(dBodyID body,const dContact& c,SGameMtl* material) +{ + CPHContactBodyEffector* effector=(CPHContactBodyEffector*)dBodyGetData(body); + if(effector) + effector->Merge(c,material); + else + { + effector=ContactEffectors.add(); + effector->Init(body,c,material); + dBodySetData(body,(void*)effector); + } +} + + + + + + + + +IC static int CollideIntoGroup(dGeomID o1, dGeomID o2,dJointGroupID jointGroup,CPHIsland* world,const int &MAX_CONTACTS) +{ + const int RS= 800+10; + const int N = RS; + + static dContact contacts[RS]; + int collided_contacts=0; + // get the contacts up to a maximum of N contacts + int n; + + VERIFY (o1); + VERIFY (o2); + VERIFY(&contacts[0].geom); + n = dCollide(o1, o2, N, &contacts[0].geom, sizeof(dContact)); + + if(n>N-1) + n=N-1; + int i; + + + for(i = 0; i < n; ++i) + { + dContact &c =contacts[i]; + dContactGeom &cgeom =c.geom; + dSurfaceParameters &surface=c.surface; + dGeomID g1 =cgeom.g1; + dGeomID g2 =cgeom.g2; + bool pushing_neg= false; + bool do_collide = true; + dxGeomUserData* usr_data_1 =NULL; + dxGeomUserData* usr_data_2 =NULL; + u16 material_idx_1 =0; + u16 material_idx_2 =0; + + surface.mu =1.f;// 5000.f; + surface.soft_erp=1.f;//ERP(world_spring,world_damping); + surface.soft_cfm=1.f;//CFM(world_spring,world_damping); + surface.bounce = 0.01f;//0.1f; + surface.bounce_vel =1.5f;//0.005f; + usr_data_1 = retrieveGeomUserData(g1); + usr_data_2 = retrieveGeomUserData(g2); + /////////////////////////////////////////////////////////////////////////////////////////////////// + if(usr_data_2) material_idx_2=usr_data_2->material; + if(usr_data_1) material_idx_1=usr_data_1->material; + bool is_tri_1=dTriListClass == dGeomGetClass(g1); + bool is_tri_2=dTriListClass == dGeomGetClass(g2); + if(!is_tri_2&&!is_tri_1) surface.mode=0; + if(is_tri_1) material_idx_1=(u16)surface.mode; + if(is_tri_2) material_idx_2=(u16)surface.mode; + SGameMtl* material_1=GMLibrary().GetMaterialByIdx(material_idx_1); + SGameMtl* material_2=GMLibrary().GetMaterialByIdx(material_idx_2); + ////////////////params can be changed in callbacks////////////////////////////////////////////////////////////////////////// + surface.mode =dContactApprox1|dContactSoftERP|dContactSoftCFM; + float spring =material_2->fPHSpring*material_1->fPHSpring*world_spring; + float damping =material_2->fPHDamping*material_1->fPHDamping*world_damping; + surface.soft_erp=ERP(spring,damping); + surface.soft_cfm=CFM(spring,damping); + surface.mu=material_2->fPHFriction*material_1->fPHFriction; + ///////////////////////////////////////////////////////////////////////////////////////////////// + + + Flags32 &flags_1=material_1->Flags; + Flags32 &flags_2=material_2->Flags; + + if(is_tri_1) + { +#pragma warning(push) +#pragma warning(disable:4245) + if(material_1->Flags.test(SGameMtl::flSlowDown)&&!(usr_data_2->pushing_neg||usr_data_2->pushing_b_neg)) +#pragma warning(pop) + { + dBodyID body=dGeomGetBody(g2); + R_ASSERT2(body,"static - static collision !!!"); + if(material_1->Flags.test(SGameMtl::flLiquid)) + { + add_contact_body_effector(body,c,material_1); + } + else + { + if(!usr_data_2 || !usr_data_2->ph_object || !usr_data_2->ph_object->IsRayMotion()) + { + add_contact_body_effector(body,c,material_1); + } + } + + } + if(material_1->Flags.test(SGameMtl::flPassable)) + do_collide=false; + // if(material_2->Flags.is(SGameMtl::flClimable)) + // do_collide=false; + } + if(is_tri_2) + { +#pragma warning(push) +#pragma warning(disable:4245) + if(material_2->Flags.test(SGameMtl::flSlowDown)&&!(usr_data_1->pushing_neg||usr_data_1->pushing_b_neg)) +#pragma warning(pop) + { + + dBodyID body=dGeomGetBody(g1); + R_ASSERT2(body,"static - static collision !!!"); + if(material_2->Flags.test(SGameMtl::flLiquid)) + { + add_contact_body_effector(body,c,material_2); + } + else + { + if(!usr_data_1 || !usr_data_1->ph_object || !usr_data_1->ph_object->IsRayMotion()) + { + add_contact_body_effector(body,c,material_2); + } + } + + } + if(material_2->Flags.test(SGameMtl::flPassable)) + do_collide=false; + + } + + if(flags_1.test(SGameMtl::flBounceable)&&flags_2.test(SGameMtl::flBounceable)) + { + surface.mode |= dContactBounce; + surface.bounce_vel = _max(material_1->fPHBounceStartVelocity,material_2->fPHBounceStartVelocity); + surface.bounce = _min(material_1->fPHBouncing,material_2->fPHBouncing); + } + ///////////////////////////////////////////////////////////////////////////////////////////////// + if(usr_data_2&&usr_data_2->object_callbacks){ + usr_data_2->object_callbacks->Call(do_collide,false,c,material_1,material_2); + } + + if(usr_data_1&&usr_data_1->object_callbacks){ + usr_data_1->object_callbacks->Call(do_collide,true,c,material_1,material_2); + } + + if(usr_data_2){ + usr_data_2->pushing_b_neg = usr_data_2->pushing_b_neg && !GMLibrary().GetMaterialByIdx(usr_data_2->b_neg_tri->material)->Flags.test(SGameMtl::flPassable); + usr_data_2->pushing_neg = usr_data_2->pushing_neg && !GMLibrary().GetMaterialByIdx(usr_data_2->neg_tri->material)->Flags.test(SGameMtl::flPassable); + pushing_neg=usr_data_2->pushing_b_neg||usr_data_2->pushing_neg; + if(usr_data_2->ph_object){ + usr_data_2->ph_object->InitContact(&c,do_collide,material_idx_1,material_idx_2); + } + + } + /////////////////////////////////////////////////////////////////////////////////////// + if(usr_data_1){ + usr_data_1->pushing_b_neg = usr_data_1->pushing_b_neg && !GMLibrary().GetMaterialByIdx(usr_data_1->b_neg_tri->material)->Flags.test(SGameMtl::flPassable); + usr_data_1->pushing_neg = usr_data_1->pushing_neg && !GMLibrary().GetMaterialByIdx(usr_data_1->neg_tri->material)->Flags.test(SGameMtl::flPassable); + pushing_neg=usr_data_1->pushing_b_neg||usr_data_1->pushing_neg; + if(usr_data_1->ph_object){ + usr_data_1->ph_object->InitContact(&c,do_collide,material_idx_1,material_idx_2); + + } + } + + + if (pushing_neg) + surface.mu=dInfinity; + if (do_collide && collided_contactsConnectJoint(contact_joint); + dJointAttach (contact_joint, dGeomGetBody(g1), dGeomGetBody(g2)); + } + } + return collided_contacts; +} + +void NearCallback(CPHObject* obj1,CPHObject* obj2, dGeomID o1, dGeomID o2) +{ + + CPHIsland* island1=obj1->DActiveIsland(); + CPHIsland* island2=obj2->DActiveIsland(); + obj2->near_callback(obj1); + int MAX_CONTACTS=-1; + if(!island1->CanMerge(island2,MAX_CONTACTS)) return; + if(CollideIntoGroup(o1,o2,ContactGroup,island1,MAX_CONTACTS)!=0) + { + obj1->MergeIsland(obj2); + if(!obj2->is_active())obj2->EnableObject(obj1); + } +} + +void CollideStatic(dGeomID o2,CPHObject* obj2) +{ + + CPHIsland* island2=obj2->DActiveIsland(); + CollideIntoGroup(ph_world->GetMeshGeom(),o2,ContactGroup,island2,island2->MaxJoints()); +} + + + + +//half square time + +/* +void BodyCutForce(dBodyID body) +{ +dReal linear_limit=l_limit; +//applyed force +const dReal* force= dBodyGetForce(body); + +//body mass +dMass m; +dBodyGetMass(body,&m); + +//accceleration correspondent to the force +dVector3 a={force[0]/m.mass,force[1]/m.mass,force[2]/m.mass}; + +//current velocity +const dReal* start_vel=dBodyGetLinearVel(body); + +//velocity adding during one step +dVector3 add_vel={a[0]*fixed_step,a[1]*fixed_step,a[2]*fixed_step}; + +//result velocity +dVector3 vel={start_vel[0]+add_vel[0],start_vel[1]+add_vel[1],start_vel[2]+add_vel[2]}; + +//result velocity magnitude +dReal speed=dSqrt(dDOT(vel,vel)); + +if(speed>linear_limit) //then we need to cut applied force +{ +//solve the triangle - cutted velocity - current veocity - add velocity +//to find cutted adding velocity + +//add_vell magnitude +dReal add_speed=dSqrt(dDOT(add_vel,add_vel)); + +//current velocity magnitude +dReal start_speed=dSqrt(dDOT(start_vel,start_vel)); + +//cosinus of the angle between vel ang add_vell +dReal cosinus1=dFabs(dDOT(add_vel,start_vel)/start_speed/add_speed); + +dReal cosinus1_2=cosinus1*cosinus1; +if(cosinus1_2>1.f) +cosinus1_2=1.f; +dReal cutted_add_speed; +if(cosinus1_2==1.f) +cutted_add_speed=linear_limit-start_speed; +else +{ +//sinus +dReal sinus1_2=1.f-cosinus1_2; + + +dReal sinus1=dSqrt(sinus1_2); + + +//sinus of the angle between cutted velocity and adding velociity (sinus theorem) +dReal sinus2=sinus1/linear_limit*start_speed; +dReal sinus2_2=sinus2*sinus2; +if(sinus2_2>1.f)sinus2_2=1.f; + +dReal cosinus2_2=1.f-sinus2_2; +dReal cosinus2=dSqrt(cosinus2_2); + +//sinus of 180-ang1-ang2 +dReal sinus3=sinus1*cosinus2+cosinus1*sinus2; + +//cutted adding velocity magnitude (sinus theorem) + +cutted_add_speed=linear_limit/sinus1*sinus3; +} +//substitude force + +dBodyAddForce(body, +cutted_add_speed/add_speed/fixed_step*m.mass*add_vel[0]-force[0], +cutted_add_speed/add_speed/fixed_step*m.mass*add_vel[1]-force[1], +cutted_add_speed/add_speed/fixed_step*m.mass*add_vel[2]-force[2] +); +} + +} +*/ +//limit for angular accel +void dBodyAngAccelFromTorqu(const dBodyID body, dReal* ang_accel, const dReal* torque){ + dMass m; + dMatrix3 invI; + dBodyGetMass(body,&m); + dInvertPDMatrix (m.I, invI, 3); + dMULTIPLY1_333(ang_accel,invI, torque); +} +void FixBody(dBodyID body,float ext_param,float mass_param) +{ + dMass m; + dMassSetSphere(&m,1.f,ext_param); + dMassAdjust(&m,mass_param); + dBodySetMass(body,&m); + dBodySetGravityMode(body,0); + dBodySetLinearVel(body,0,0,0); + dBodySetAngularVel(body,0,0,0); + dBodySetForce(body,0,0,0); + dBodySetTorque(body,0,0,0); +} +void FixBody(dBodyID body) +{ + FixBody(body,fix_ext_param,fix_mass_param); +} + + +void BodyCutForce(dBodyID body,float l_limit,float w_limit) +{ + const dReal wa_limit=w_limit/fixed_step; + const dReal* force= dBodyGetForce(body); + dReal force_mag=dSqrt(dDOT(force,force)); + + //body mass + dMass m; + dBodyGetMass(body,&m); + + dReal force_limit =l_limit/fixed_step*m.mass; + + if(force_mag>force_limit) + { + dBodySetForce(body, + force[0]/force_mag*force_limit, + force[1]/force_mag*force_limit, + force[2]/force_mag*force_limit + ); + } + + + const dReal* torque=dBodyGetTorque(body); + dReal torque_mag=dSqrt(dDOT(torque,torque)); + + if(torque_mag<0.001f) return; + + dMatrix3 tmp,invI,I; + + // compute inertia tensor in global frame + dMULTIPLY2_333 (tmp,m.I,body->R); + dMULTIPLY0_333 (I,body->R,tmp); + + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp,body->invI,body->R); + dMULTIPLY0_333 (invI,body->R,tmp); + + //angular accel + dVector3 wa; + dMULTIPLY0_331(wa,invI,torque); + dReal wa_mag=dSqrt(dDOT(wa,wa)); + + if(wa_mag>wa_limit) + { + //scale w + for(int i=0;i<3;++i)wa[i]*=wa_limit/wa_mag; + dVector3 new_torqu; + + dMULTIPLY0_331(new_torqu,I,wa); + + dBodySetTorque + ( + body, + new_torqu[0], + new_torqu[1], + new_torqu[2] + ); + } +} + +void dMassSub(dMass *a,const dMass *b) +{ + int i; + VERIFY (a && b); + dReal denom = dRecip (a->mass-b->mass); + for (i=0; i<3; ++i) a->c[i] = (a->c[i]*a->mass - b->c[i]*b->mass)*denom; + a->mass-=b->mass; + for (i=0; i<12; ++i) a->I[i] -= b->I[i]; +} + + +////Energy of non Elastic collision; +//body - static case +float E_NlS(dBodyID body,const dReal* norm,float norm_sign)//if body c.geom.g1 norm_sign + else - +{ //norm*norm_sign - to body + const dReal* vel=dBodyGetLinearVel(body); + dReal prg=-dDOT(vel,norm)*norm_sign; + prg=prg<0.f ? prg=0.f : prg; + dMass mass; + dBodyGetMass(body,&mass); + return mass.mass*prg*prg/2; +} + +//body - body case +float E_NLD(dBodyID b1,dBodyID b2,const dReal* norm)// norm - from 2 to 1 +{ + dMass m1,m2; + dBodyGetMass(b1,&m1);dBodyGetMass(b2,&m2); + const dReal* vel1 =dBodyGetLinearVel(b1); + const dReal* vel2 =dBodyGetLinearVel(b2); + + dReal vel_pr1=dDOT(vel1,norm); + dReal vel_pr2=dDOT(vel2,norm); + + if(vel_pr1>vel_pr2) return 0.f; //exit if the bodies are departing + + dVector3 impuls1={vel1[0]*m1.mass,vel1[1]*m1.mass,vel1[2]*m1.mass}; + dVector3 impuls2={vel2[0]*m2.mass,vel2[1]*m2.mass,vel2[2]*m2.mass}; + + dVector3 c_mas_impuls={impuls1[0]+impuls2[0],impuls1[1]+impuls2[1],impuls1[2]+impuls2[2]}; + dReal cmass=m1.mass+m2.mass; + dVector3 c_mass_vel={c_mas_impuls[0]/cmass,c_mas_impuls[1]/cmass,c_mas_impuls[2]/cmass}; + + dReal c_mass_vel_prg=dDOT(c_mass_vel,norm); + + dReal kin_energy_start=vel_pr1*vel_pr1*m1.mass/2.f+vel_pr2*vel_pr2*m2.mass/2.f; + dReal kin_energy_end=c_mass_vel_prg*c_mass_vel_prg*cmass/2.f; + + return (kin_energy_start-kin_energy_end); +} +float E_NL(dBodyID b1,dBodyID b2,const dReal* norm) +{ + VERIFY(b1||b2); + if(b1) + { + if(b2)return E_NLD(b1,b2,norm);else return E_NlS(b1,norm,1); + }else return E_NlS(b2,norm,-1); +} +void ApplyGravityAccel(dBodyID body,const dReal* accel) +{ + dMass m; + dBodyGetMass(body,&m); + dBodyAddForce(body,accel[0]*m.mass,accel[1]*m.mass,accel[2]*m.mass); +} + +const dReal* dJointGetPositionContact(dJointID joint) +{ + VERIFY2(dJointGetType(joint)==dJointTypeContact,"not a contact!"); + dxJointContact* c_joint=(dxJointContact*)joint; + return c_joint->contact.geom.pos; + +} diff --git a/xrPhysics/Physics.h b/xrPhysics/Physics.h new file mode 100644 index 00000000000..ea34ecb92a7 --- /dev/null +++ b/xrPhysics/Physics.h @@ -0,0 +1,55 @@ +#ifndef PHYSICS_H +#define PHYSICS_H + + +#include "dCylinder/dCylinder.h" +#include "PhysicsShell.h" +#include "PHObject.h" +#include "PHInterpolation.h" +#include "../xrcore/_cylinder.h" +#include "BlockAllocator.h" +#include "PhysicsCommon.h" +#include "PHWorld.h" +#include "PHContactBodyEffector.h" +#include "phvalide.h" +//#define ODE_SLOW_SOLVER +/////////////////////////////////////////////////////////////////////////////// + + void BodyCutForce (dBodyID body,float l_limit,float w_limit) ; + void dBodyAngAccelFromTorqu (const dBodyID body, dReal* ang_accel, const dReal* torque) ; +// float E_NlS (dBodyID body,const dReal* norm,float norm_sign) ; + float E_NLD (dBodyID b1,dBodyID b2,const dReal* norm); + + +// float E_NL( dBodyID b1, dBodyID b2, const dReal* norm ); + + void ApplyGravityAccel (dBodyID body,const dReal* accel); +const dReal fix_ext_param =10000.f; +const dReal fix_mass_param =100000000.f; + void FixBody (dBodyID body) ; + void dMassSub (dMass *a,const dMass *b) ; + void SaveContacts (dGeomID o1, dGeomID o2,dJointGroupID jointGroup) ; +const dReal *dJointGetPositionContact (dJointID joint); + + + +//const dReal world_spring=24000000.f;//2400000.f;//550000.f;///1000000.f;; +//const dReal world_damping=400000.f;//erp/cfm1.1363636e-006f,0.54545456f + + +extern class CBlockAllocator ContactFeedBacks; +extern CBlockAllocator ContactEffectors; +//void NearCallback(void* /*data*/, dGeomID o1, dGeomID o2); +void NearCallback(CPHObject* obj1,CPHObject* obj2, dGeomID o1, dGeomID o2); +void CollideStatic(dGeomID o2,CPHObject* obj2); + + + +class CPHElement; +class CPHShell; +extern dJointGroupID ContactGroup; +extern Fbox phBoundaries; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif PHYSICS_H \ No newline at end of file diff --git a/xrPhysics/PhysicsCommon.h b/xrPhysics/PhysicsCommon.h new file mode 100644 index 00000000000..ca7cb4c1eff --- /dev/null +++ b/xrPhysics/PhysicsCommon.h @@ -0,0 +1,63 @@ +#ifndef PHYSICS_COMMON_H +#define PHYSICS_COMMON_H + +#include "DisablingParams.h" +#include "physicsexternalcommon.h" +//#include "ode_include.h" +//#include "../3rd party/ode/include/ode/common.h" + +extern XRPHYSICS_API const float default_l_limit ; +extern XRPHYSICS_API const float default_w_limit ; +extern XRPHYSICS_API const float default_k_l ; +extern XRPHYSICS_API const float default_k_w ; +extern const float default_l_scale ; +extern const float default_w_scale ; + +extern const float base_fixed_step ; +extern const float base_erp ; +extern const float base_cfm ; + +extern XRPHYSICS_API float fixed_step ; +extern float world_cfm ; +extern float world_erp ; +extern float world_spring ; +extern float world_damping ; + +//extern const float mass_limit ; +extern const u16 max_joint_allowed_for_exeact_integration ; +extern XRPHYSICS_API const float default_world_gravity ; +extern XRPHYSICS_API float phTimefactor ; +extern XRPHYSICS_API int phIterations ; +//extern float phBreakCommonFactor ; +//extern float phRigidBreakWeaponFactor ; +//extern float ph_tri_query_ex_aabb_rate ; +//extern int ph_tri_clear_disable_count ; + +struct SGameMtl; +#define ERP_S(k_p,k_d,s) ((s*(k_p)) / (((s)*(k_p)) + (k_d))) +#define CFM_S(k_p,k_d,s) (1.f / (((s)*(k_p)) + (k_d))) +#define SPRING_S(cfm,erp,s) ((erp)/(cfm)/s) + +////////////////////////////////////////////////////////////////////////////////// +#define DAMPING(cfm,erp) ((1.f-(erp))/(cfm)) +#define ERP(k_p,k_d) ERP_S(k_p,k_d,fixed_step) +#define CFM(k_p,k_d) CFM_S(k_p,k_d,fixed_step) +#define SPRING(cfm,erp) SPRING_S(cfm,erp,fixed_step) + + + + +IC float Erp(float k_p,float k_d,float s=fixed_step) {return ((s*(k_p)) / (((s)*(k_p)) + (k_d)));} +IC float Cfm(float k_p,float k_d,float s=fixed_step) {return (1.f / (((s)*(k_p)) + (k_d)));} +IC float Spring(float cfm,float erp,float s=fixed_step) {return ((erp)/(cfm)/s);} +IC float Damping(float cfm,float erp) {return ((1.f-(erp))/(cfm));} +IC void MulSprDmp(float &cfm,float &erp,float mul_spring,float mul_damping) +{ + float factor=1.f/(mul_spring*erp+mul_damping*(1-erp)); + cfm*=factor; + erp*=(factor*mul_spring); +} + + + +#endif //PHYSICS_COMMON_H \ No newline at end of file diff --git a/xrPhysics/PhysicsExternalCommon.cpp b/xrPhysics/PhysicsExternalCommon.cpp new file mode 100644 index 00000000000..a7911c32f3e --- /dev/null +++ b/xrPhysics/PhysicsExternalCommon.cpp @@ -0,0 +1,29 @@ +#include "stdafx.h" +#include "physicsexternalcommon.h" +#include "extendedgeom.h" +#include "mathutilsode.h" +bool ContactShotMarkGetEffectPars(dContactGeom* c, dxGeomUserData* &data, float &vel_cret, bool &b_invert_normal ) +{ + dBodyID b=dGeomGetBody(c->g1); + + b_invert_normal=false; + if(!b) + { + b=dGeomGetBody(c->g2); + data=dGeomGetUserData(c->g2); + b_invert_normal=true; + } + else + { + data=dGeomGetUserData(c->g1); + } + if(!b) + return false; + + dVector3 vel; + dMass m; + dBodyGetMass(b,&m); + dBodyGetPointVel(b,c->pos[0],c->pos[1],c->pos[2],vel); + vel_cret=_abs(dDOT(vel,c->normal))* _sqrt(m.mass); + return true; +} \ No newline at end of file diff --git a/xrPhysics/PhysicsExternalCommon.h b/xrPhysics/PhysicsExternalCommon.h new file mode 100644 index 00000000000..edcbfe3ba8c --- /dev/null +++ b/xrPhysics/PhysicsExternalCommon.h @@ -0,0 +1,50 @@ +#ifndef _PHYSICS_EXTERNAL_COMMON_ +#define _PHYSICS_EXTERNAL_COMMON_ +#pragma once +struct dContactGeom; +struct dContact; +struct SGameMtl; +namespace CDB{ class TRI; } +class CBoneInstance; + +typedef void ContactCallbackFun(CDB::TRI* T,dContactGeom* c); +typedef void ObjectContactCallbackFun(bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2); + + +typedef void _BCL BoneCallbackFun(CBoneInstance* B); + + + + + +typedef void PhysicsStepTimeCallback (u32 step_start,u32 step_end); +//extern PhysicsStepTimeCallback *physics_step_time_callback; +struct dxGeomUserData; +struct dContactGeom; +XRPHYSICS_API bool ContactShotMarkGetEffectPars(dContactGeom *c, dxGeomUserData* &data, float &vel_cret, bool &b_invert_normal ); + +template +void t_get_box( const geom_type* shell, const Fmatrix& form, Fvector& sz, Fvector& c ) +{ + c.set(0,0,0); + VERIFY( sizeof( form.i ) + sizeof( form._14_ ) == 4* sizeof( float ) ); + for(int i=0;3>i;++i) + { + float lo,hi; + const Fvector &ax=cast_fv(((const float*)&form+i*4)); + shell->get_Extensions(ax,0,lo,hi); + sz[i]=hi-lo;c.add(Fvector().mul(ax,(lo+hi)/2)); + } +} + +enum ERestrictionType +{ + + rtStalker =0 , + rtStalkerSmall , + rtMonsterMedium , + rtNone , + rtActor +}; +#endif + diff --git a/xrPhysics/PhysicsShell.cpp b/xrPhysics/PhysicsShell.cpp new file mode 100644 index 00000000000..6f9b0d4e7f2 --- /dev/null +++ b/xrPhysics/PhysicsShell.cpp @@ -0,0 +1,375 @@ +#include "stdafx.h" +#pragma hdrstop +#include "physicsshell.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "PHJoint.h" +#include "PHShell.h" +#include "PHJoint.h" +#include "PHJointDestroyInfo.h" +#include "PHSplitedShell.h" + +//#include "gameobject.h" +#include "iphysicsshellholder.h" + +//#include "objectdump.h" +#include "phvalide.h" + +#include "../Include/xrRender/Kinematics.h" +#include "../xrengine/xr_object.h" +#include "../xrengine/bone.h" + +extern CPHWorld *ph_world; +CPhysicsShell::~CPhysicsShell() +{ + + //if(ph_world)ph_world->NetRelcase(this); +} + +CPhysicsElement* P_create_Element () +{ + CPHElement* element=xr_new (); + return element; +} + +CPhysicsShell* P_create_Shell () +{ + CPhysicsShell* shell=xr_new (); + return shell; +} + +CPhysicsShell* P_create_splited_Shell () +{ + CPhysicsShell* shell=xr_new (); + return shell; +} + +CPhysicsJoint* P_create_Joint ( CPhysicsJoint::enumType type, CPhysicsElement* first, CPhysicsElement* second ) +{ + CPhysicsJoint* joint=xr_new ( type , first, second ); + return joint; +} + + +CPhysicsShell* __stdcall P_build_Shell ( IPhysicsShellHolder* obj, bool not_active_state, BONE_P_MAP* bone_map, bool not_set_bone_callbacks ) +{ + VERIFY( obj ); + phys_shell_verify_object_model( *obj ); + //IRenderVisual* V = obj->ObjectVisual(); + //IKinematics* pKinematics=smart_cast(V); + //IKinematics* pKinematics = V->dcast_PKinematics (); + IKinematics* pKinematics = obj->ObjectKinematics(); + + CPhysicsShell* pPhysicsShell = P_create_Shell(); +#ifdef DEBUG + pPhysicsShell->dbg_obj=obj; +#endif + pPhysicsShell->build_FromKinematics(pKinematics,bone_map); + + pPhysicsShell->set_PhysicsRefObject( obj ); + pPhysicsShell->mXFORM.set( obj->ObjectXFORM() ); + pPhysicsShell->Activate( not_active_state, not_set_bone_callbacks );//, + //m_pPhysicsShell->SmoothElementsInertia(0.3f); + pPhysicsShell->SetAirResistance();//0.0014f,1.5f + + return pPhysicsShell; +} + +void fix_bones( LPCSTR fixed_bones, CPhysicsShell* shell ) +{ + VERIFY(fixed_bones); + VERIFY(shell); + IKinematics *pKinematics = shell->PKinematics(); + VERIFY(pKinematics); + int count = _GetItemCount(fixed_bones); + for (int i=0 ;iLL_BoneID(fixed_bone) ; + R_ASSERT2(BI_NONE!=fixed_bone_id,"wrong fixed bone") ; + CPhysicsElement* E = shell->get_Element(fixed_bone_id) ; + if(E) + E->Fix(); + } +} +CPhysicsShell* P_build_Shell( IPhysicsShellHolder* obj, bool not_active_state,BONE_P_MAP* p_bone_map, LPCSTR fixed_bones ) +{ + CPhysicsShell* pPhysicsShell = 0; + //IKinematics* pKinematics=smart_cast(obj->ObjectVisual()); + IKinematics* pKinematics=obj->ObjectKinematics(); + if(fixed_bones) + { + + + int count = _GetItemCount(fixed_bones); + for (int i=0 ;iLL_BoneID(fixed_bone) ; + R_ASSERT2(BI_NONE!=fixed_bone_id,"wrong fixed bone") ; + p_bone_map->insert(mk_pair(fixed_bone_id,physicsBone())) ; + } + + pPhysicsShell=P_build_Shell(obj,not_active_state,p_bone_map); + + //m_pPhysicsShell->add_Joint(P_create_Joint(CPhysicsJoint::enumType::full_control,0,fixed_element)); + } + else + pPhysicsShell=P_build_Shell(obj,not_active_state); + + + BONE_P_PAIR_IT i=p_bone_map->begin(),e=p_bone_map->end(); + if(i!=e) pPhysicsShell->SetPrefereExactIntegration(); + for(;i!=e;i++) + { + CPhysicsElement* fixed_element=i->second.element; + R_ASSERT2(fixed_element,"fixed bone has no physics"); + //if(!fixed_element) continue; + fixed_element->Fix(); + } + return pPhysicsShell; +} + +CPhysicsShell* P_build_Shell( IPhysicsShellHolder* obj, bool not_active_state, LPCSTR fixed_bones ) +{ + U16Vec f_bones; + if(fixed_bones){ + //IKinematics* K = smart_cast(obj->ObjectVisual()); + IKinematics* K =obj->ObjectKinematics(); + VERIFY( K ); + int count = _GetItemCount(fixed_bones); + for (int i=0 ;iLL_BoneID(fixed_bone)); + R_ASSERT2(BI_NONE!=f_bones.back(),"wrong fixed bone") ; + } + } + return P_build_Shell (obj,not_active_state,f_bones); +} + +static BONE_P_MAP bone_map=BONE_P_MAP(); +CPhysicsShell* P_build_Shell ( IPhysicsShellHolder* obj, bool not_active_state, U16Vec& fixed_bones ) +{ + bone_map.clear (); + CPhysicsShell* pPhysicsShell = 0; + if(!fixed_bones.empty()) + for ( U16It it=fixed_bones.begin(); it!=fixed_bones.end(); it++ ) + bone_map.insert( mk_pair( *it, physicsBone() ) ); + pPhysicsShell=P_build_Shell( obj, not_active_state, &bone_map ); + + // fix bones + BONE_P_PAIR_IT i=bone_map.begin(), e=bone_map.end(); + if( i!=e ) + pPhysicsShell->SetPrefereExactIntegration(); + for(;i!=e;i++) + { + CPhysicsElement* fixed_element=i->second.element; + //R_ASSERT2(fixed_element,"fixed bone has no physics"); + if(!fixed_element) continue; + fixed_element->Fix(); + } + return pPhysicsShell; +} + +CPhysicsShell* P_build_SimpleShell( IPhysicsShellHolder* obj, float mass, bool not_active_state ) +{ + CPhysicsShell* pPhysicsShell = P_create_Shell(); +#ifdef DEBUG + pPhysicsShell->dbg_obj=(obj); +#endif + //Fobb obb; obj->ObjectVisual()->getVisData().box.get_CD( obb.m_translate, obb.m_halfsize ); + VERIFY( obj ); + VERIFY( obj->ObjectKinematics() ); + + Fobb obb; obj->ObjectKinematics()->GetBox().get_CD( obb.m_translate, obb.m_halfsize ); + obb.m_rotate.identity(); + CPhysicsElement* E = P_create_Element(); R_ASSERT( E ); E->add_Box( obb ); + pPhysicsShell->add_Element( E ); + pPhysicsShell->setMass( mass ); + pPhysicsShell->set_PhysicsRefObject( obj ); + if( !obj->has_parent_object() ) + pPhysicsShell->Activate( obj->ObjectXFORM(), 0, obj->ObjectXFORM(), not_active_state ); + return pPhysicsShell; +} + +void ApplySpawnIniToPhysicShell( CInifile const * ini, CPhysicsShell* physics_shell, bool fixed ) +{ + if(!ini) + return; + if(ini->section_exist("physics_common")) + { + fixed = fixed || (ini->line_exist("physics_common","fixed_bones")) ; +#pragma todo("not ignore static if non realy fixed! ") + fix_bones(ini->r_string("physics_common","fixed_bones"),physics_shell); + } + if(ini->section_exist("collide")) + { + + if((ini->line_exist("collide","ignore_static")&&fixed)||(ini->line_exist("collide","ignore_static")&&ini->section_exist("animated_object"))) + { + physics_shell->SetIgnoreStatic(); + } + if(ini->line_exist("collide","small_object")) + { + physics_shell->SetSmall(); + } + if(ini->line_exist("collide","ignore_small_objects")) + { + physics_shell->SetIgnoreSmall(); + } + if(ini->line_exist("collide","ignore_ragdoll")) + { + physics_shell->SetIgnoreRagDoll(); + } + + + //If need, then show here that it is needed to ignore collisions with "animated_object" + if (ini->line_exist("collide","ignore_animated_objects")) + { + physics_shell->SetIgnoreAnimated(); + } + + } + //If next section is available then given "PhysicShell" is classified + //as animated and we read options for his animation + + if (ini->section_exist("animated_object")) + { + //Show that given "PhysicShell" animated + physics_shell->CreateShellAnimator( ini, "animated_object" ); + } + +} + + + +void get_box( const CPhysicsBase* shell, const Fmatrix& form, Fvector& sz, Fvector& c ) +{ + t_get_box( shell, form, sz, c ); +} + + + + +void __stdcall destroy_physics_shell( CPhysicsShell* &p ) +{ + if (p) + p->Deactivate(); + xr_delete(p); +} + +bool bone_has_pysics( IKinematics& K, u16 bone_id ) +{ + + //CBoneData * pBonedata1 = &K.LL_GetData( bone_id ); + //CBoneData * pBonedata2 = K.LL_GetBoneData( bone_id ); + + //u32 sz = sizeof(vecBones); + //u32 sz1= sizeof(pBonedata1->children); + + // VERIFY(pBonedata1 == pBonedata2); + return K.LL_GetBoneVisible( bone_id ) && shape_is_physic( K.GetBoneData( bone_id ).get_shape() ); +} + +bool has_physics_collision_shapes( IKinematics& K ) +{ + u16 nbb = K.LL_BoneCount(); + for(u16 i = 0; i < nbb; ++i ) + if( bone_has_pysics( K, i ) ) + return true; + return false; +} + +void phys_shell_verify_model( IKinematics& K ) +{ + //IRenderVisual* V = K.dcast_RenderVisual(); + //VERIFY( V ); + VERIFY2( has_physics_collision_shapes( K ), make_string( "Can not create physics shell for model %s because it has no physics collision shapes set", K.getDebugName().c_str() ) ); +} + +void phys_shell_verify_object_model( IPhysicsShellHolder& O ) +{ + //IRenderVisual *V = O.ObjectVisual(); + + //VERIFY2( V, make_string( "Can not create physics shell for object %s it has no model", O.ObjectName() )/*+ make_string("\n object dump: \n") + dbg_object_full_dump_string( &O )*/ ); + + //IKinematics *K = V->dcast_PKinematics(); + + IKinematics* K =O.ObjectKinematics(); + + VERIFY2( K, make_string( "Can not create physics shell for object %s, model %s is not skeleton", O.ObjectName(), O.ObjectNameVisual() ) ); + + VERIFY2( has_physics_collision_shapes( *K ), make_string( "Can not create physics shell for object %s, model %s has no physics collision shapes set", O.ObjectName(), O.ObjectNameVisual() )/*+ make_string("\n object dump: \n") + dbg_object_full_dump_string( &O )*/ ); + + VERIFY2( _valid( O.ObjectXFORM() ), make_string( "create physics shell: object matrix is not valid" ) /*+ make_string("\n object dump: \n") + dbg_object_full_dump_string( &O )*/ ); + + VERIFY2(valid_pos( O.ObjectXFORM().c ), dbg_valide_pos_string( O.ObjectXFORM().c, &O, "create physics shell" ) ); +} + +bool __stdcall can_create_phys_shell( string1024 &reason, IPhysicsShellHolder& O ) +{ + xr_strcpy(reason, "ok" ); + bool result = true; + IKinematics* K =O.ObjectKinematics(); + if(!K) + { + xr_strcpy( reason, make_string( "Can not create physics shell for object %s, model %s is not skeleton", O.ObjectName(), O.ObjectNameVisual() ).c_str() ); + return false; + } + if(!has_physics_collision_shapes( *K )) + { + xr_strcpy( reason, make_string( "Can not create physics shell for object %s, model %s has no physics collision shapes set", O.ObjectName(), O.ObjectNameVisual() ).c_str() ); + return false; + } + if(!_valid( O.ObjectXFORM() )) + { + xr_strcpy( reason, make_string( "create physics shell: object matrix is not valid" ).c_str() ); + return false; + } + if(!valid_pos( O.ObjectXFORM().c )) + { +#ifdef DEBUG + xr_strcpy( reason, dbg_valide_pos_string( O.ObjectXFORM().c, &O, "create physics shell" ).c_str() ); +#else + xr_strcpy( reason, make_string( "create physics shell: object position is not valid" ).c_str() ); +#endif + return false; + } + return result; +} + + + + + +float NonElasticCollisionEnergy( CPhysicsElement *e1, CPhysicsElement *e2, const Fvector &norm)// norm - from 2 to 1 +{ + VERIFY( e1 ); + VERIFY( e2 ); + dBodyID b1 = static_cast (e1)->get_body(); + VERIFY(b1); + dBodyID b2 = static_cast (e2)->get_body(); + VERIFY(b2); + return E_NL( b1, b2, cast_fp( norm ) ); +} + + +void StaticEnvironmentCB ( bool& do_colide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ) +{ + dJointID contact_joint = dJointCreateContact(0, ContactGroup, &c); + + if(bo1) + { + ((CPHIsland*)(retrieveGeomUserData(c.geom.g1)->callback_data))->DActiveIsland()->ConnectJoint(contact_joint); + dJointAttach (contact_joint, dGeomGetBody(c.geom.g1), 0); + } + else + { + ((CPHIsland*)(retrieveGeomUserData(c.geom.g2)->callback_data))->DActiveIsland()->ConnectJoint(contact_joint); + dJointAttach (contact_joint, 0, dGeomGetBody(c.geom.g2)); + } + do_colide=false; +} \ No newline at end of file diff --git a/xrPhysics/PhysicsShell.h b/xrPhysics/PhysicsShell.h new file mode 100644 index 00000000000..e644f38fdf6 --- /dev/null +++ b/xrPhysics/PhysicsShell.h @@ -0,0 +1,450 @@ +#ifndef PhysicsShellH +#define PhysicsShellH +#pragma once + +#include "PHDefs.h" +#include "PhysicsCommon.h" +#include "icollidevalidator.h" +#include "../xrserverentities/alife_space.h" +//#include "script_export_space.h" +#include "../xrEngine/iphysicsshell.h" +#include "iphysics_scripted.h" +class CPhysicsJoint; +class CPhysicsElement; +class CPhysicsShell; +class CPHFracture; +class CPHJointDestroyInfo; +class CODEGeom; +class CPHSynchronize; +class IPhysicsShellHolder; +class CGameObject; +class NET_Packet; +struct SBoneShape; +struct NearestToPointCallback; +class CPHShellSplitterHolder; +class IKinematics; +typedef u32 CLClassBits; +typedef u32 CLBits; + +struct dMass; + + +enum motion_history_state +{ + mh_clear = 0, + mh_unspecified, + mh_not_clear, +}; + +struct physicsBone +{ + CPhysicsJoint* joint; + CPhysicsElement* element; + physicsBone() + { + joint=NULL; + element=NULL; + } +}; +DEFINE_MAP (u16, physicsBone, BONE_P_MAP, BONE_P_PAIR_IT); +typedef const BONE_P_MAP :: iterator BONE_P_PAIR_CIT; +// ABSTRACT: +class CPhysicsBase ; +extern XRPHYSICS_API void get_box( const CPhysicsBase* shell, const Fmatrix& form, Fvector& sz, Fvector& c ); + +class XRPHYSICS_API CPhysicsBase: + public iphysics_scripted_class +{ + +public: + Fmatrix mXFORM ; // In parent space +public: + virtual void Activate (const Fmatrix& m0, float dt01, const Fmatrix& m2,bool disable=false) = 0; + virtual void Activate (const Fmatrix &transform,const Fvector& lin_vel,const Fvector& ang_vel,bool disable=false) = 0; + virtual void Activate (bool disable=false, bool not_set_bone_callbacks = false) = 0; + virtual void Activate (const Fmatrix& form,bool disable=false) = 0; + virtual const Fmatrix &XFORM ()const { return mXFORM; } + virtual void get_xform ( Fmatrix& form ) const { form.set( XFORM() ); } + virtual void _BCL InterpolateGlobalTransform (Fmatrix* m) = 0; +// virtual void GetGlobalTransformDynamic (Fmatrix* m) const = 0; + virtual void InterpolateGlobalPosition (Fvector* v) = 0; + + virtual void net_Import (NET_Packet& P) = 0; + virtual void net_Export (NET_Packet& P) = 0; + virtual void GetGlobalPositionDynamic (Fvector* v) = 0; + virtual bool isBreakable () = 0; + virtual bool isEnabled () const = 0; + virtual bool isActive () const = 0; + virtual bool isFullActive () const = 0; + virtual void Deactivate () = 0; + virtual void Enable () = 0; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void setMass (float M) = 0; + virtual void setDensity (float M) = 0; + virtual float getMass () = 0; + virtual float getDensity () = 0; + virtual float getVolume () = 0; + virtual void get_Extensions ( const Fvector& axis, float center_prg, float& lo_ext, float& hi_ext ) const = 0; + virtual void get_Box ( Fvector& sz, Fvector& c )const { get_box( this, mXFORM, sz, c ); } +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void applyForce (const Fvector& dir, float val) = 0; + virtual void applyForce (float x,float y,float z) = 0; + virtual void applyImpulse (const Fvector& dir, float val) = 0; + virtual void setTorque (const Fvector& torque) = 0; + virtual void setForce (const Fvector& force) = 0; + virtual void _BCL applyGravityAccel (const Fvector& accel) = 0; + virtual void SetAirResistance (float linear=default_k_l, float angular=default_k_w) = 0; + virtual void GetAirResistance (float &linear, float &angular) = 0; + virtual void set_DynamicLimits (float l_limit=default_l_limit,float w_limit=default_w_limit) = 0; + virtual void set_DynamicScales (float l_scale=default_l_scale,float w_scale=default_w_scale) = 0; + virtual void set_ContactCallback (ContactCallbackFun* callback) = 0; + virtual void set_ObjectContactCallback (ObjectContactCallbackFun* callback) = 0; + virtual void SetAnimated ( bool v ) = 0; + virtual void add_ObjectContactCallback (ObjectContactCallbackFun* callback) = 0; + virtual void remove_ObjectContactCallback (ObjectContactCallbackFun* callback) = 0; + virtual void set_CallbackData (void * cd) = 0; + virtual void *get_CallbackData () = 0; + virtual void set_PhysicsRefObject (IPhysicsShellHolder* ref_object) = 0; +// virtual void get_LinearVel (Fvector& velocity) const = 0; +// virtual void get_AngularVel (Fvector& velocity) const = 0; + virtual void set_LinearVel (const Fvector& velocity) = 0; + virtual void set_AngularVel (const Fvector& velocity) = 0; + virtual void TransformPosition (const Fmatrix &form, motion_history_state history_state) = 0; + virtual void set_ApplyByGravity (bool flag) = 0; + virtual bool get_ApplyByGravity () = 0; + + virtual void SetMaterial (u16 m) = 0; + virtual void SetMaterial (LPCSTR m) = 0; + virtual void set_DisableParams (const SAllDDOParams& params) = 0; + virtual void SetTransform (const Fmatrix& m0, motion_history_state history_state ) = 0; +#ifdef DEBUG + virtual void dbg_draw_velocity ( float scale, u32 color ) = 0; + virtual void dbg_draw_force ( float scale, u32 color ) = 0; + virtual void dbg_draw_geometry ( float scale, u32 color, Flags32 flags = Flags32().assign( 0 ) ) const = 0; +#endif + virtual ~CPhysicsBase () {}; +}; + +// ABSTRACT: +// Element is fully Rigid and consists of one or more forms, such as sphere, box, cylinder, etc. +class XRPHYSICS_API CPhysicsElement : + public CPhysicsBase, + public IPhysicsElement +{ + +public: + u16 m_SelfID ; + virtual CPhysicsShell *PhysicsShell () = 0; + virtual void set_ContactCallback (ContactCallbackFun *callback) = 0; + virtual IPhysicsShellHolder *PhysicsRefObject () = 0; + virtual void add_Sphere (const Fsphere& V) = 0; + virtual void add_Box (const Fobb& V) = 0; + virtual void add_Cylinder (const Fcylinder& V) = 0; + virtual void add_Shape (const SBoneShape& shape) = 0; + virtual void add_Shape (const SBoneShape& shape,const Fmatrix& offset) = 0; + virtual CODEGeom *last_geom () = 0; + virtual CODEGeom* geometry ( u16 i ) = 0; + virtual void add_geom ( CODEGeom* g ) = 0; + virtual void remove_geom ( CODEGeom* g ) = 0; + virtual const IPhysicsGeometry* geometry ( u16 i )const = 0; +#ifdef DEBUG + virtual CPhysicsElement* parent_element () = 0; +#endif + virtual bool has_geoms () = 0; + virtual void add_Mass (const SBoneShape& shape,const Fmatrix& offset,const Fvector& mass_center,float mass,CPHFracture* fracture=NULL) = 0; + virtual void set_ParentElement (CPhysicsElement* p) = 0; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void set_BoxMass (const Fobb& box, float mass) = 0; + virtual void setInertia (const dMass& M) = 0; + virtual void addInertia (const dMass& M) = 0; + virtual void setMassMC (float M,const Fvector& mass_center) = 0; + virtual void applyImpulseVsMC (const Fvector& pos,const Fvector& dir, float val) = 0; + virtual void applyImpulseVsGF (const Fvector& pos,const Fvector& dir, float val) = 0; + virtual void applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val,const u16 id) = 0; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void setDensityMC (float M,const Fvector& mass_center) = 0; + virtual void set_local_mass_center (const Fvector &mc ) = 0; + virtual void setQuaternion (const Fquaternion& quaternion) = 0; + virtual u16 setGeomFracturable (CPHFracture &fracture) = 0; + virtual CPHFracture &Fracture (u16 num) = 0; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual u16 numberOfGeoms ()const = 0; +// virtual dBodyID get_body () = 0; + virtual const Fvector &mass_Center ()const = 0; + virtual const Fvector &local_mass_Center () = 0; + virtual float getRadius () = 0; + virtual void GetGlobalTransformDynamic (Fmatrix* m) const = 0; + virtual dMass *getMassTensor () = 0; + virtual void get_MaxAreaDir (Fvector& dir) = 0; + virtual ObjectContactCallbackFun *get_ObjectContactCallback () = 0; + virtual void Fix () = 0; + virtual void ReleaseFixed () = 0; + virtual bool isFixed () = 0; +////////////////////////////////////////////////////////////////IPhysicsElement//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual const Fmatrix &XFORM () const { return CPhysicsBase::XFORM(); } + //virtual void _BCL CalculateBoneTransform ( Fmatrix &bone_transform )const = 0; + virtual void GetPointVel ( Fvector &res_vel, const Fvector & point ) const = 0; +// virtual void get_LinearVel ( Fvector& velocity ) const { get_LinearVel( velocity ); } +// virtual void get_AngularVel ( Fvector& velocity ) const { get_AngularVel( velocity ); } + virtual void get_Box ( Fvector& sz, Fvector& c )const { return CPhysicsBase::get_Box( sz, c ); } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~CPhysicsElement () {}; +// DECLARE_SCRIPT_REGISTER_FUNCTION +}; + +//add_to_type_list(CPhysicsElement) +//#undef script_type_list +//#define script_type_list save_type_list(CPhysicsElement) + + +XRPHYSICS_API float NonElasticCollisionEnergy( CPhysicsElement *e1, CPhysicsElement *e2, const Fvector &norm);// norm - from 2 to 1 + +//ABSTRACT: +// Joint between two elements + +class XRPHYSICS_API CPhysicsJoint: + public iphysics_scripted_class +{ + +public: + bool bActive ; + enum eVs { //coordinate system + vs_first , //in first local + vs_second , //in second local + vs_global //in global + }; + enum enumType{ //joint type + ball , // ball-socket + hinge , // standart hinge 1 - axis + hinge2 , // for car wheels 2-axes + full_control , // 3 - axes control (eiler - angles) + slider + }; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + enumType eType ; //type of the joint +public: + virtual ~CPhysicsJoint () {}; + virtual u16 BoneID () =0; + virtual void SetBoneID (u16 bone_id) =0; + virtual CPhysicsElement* PFirst_element () =0; + virtual CPhysicsElement* PSecond_element () =0; + virtual u16 GetAxesNumber () =0; + virtual void Activate () =0; + virtual void Create () =0; + virtual void RunSimulation () =0; + virtual void Deactivate () =0; + virtual void SetBackRef (CPhysicsJoint** j) =0; + virtual void SetAnchor (const Fvector& position) =0; + virtual void SetAxisSDfactors (float spring_factor,float damping_factor,int axis_num) =0; + virtual void SetJointSDfactors (float spring_factor,float damping_factor) =0; + virtual void SetJointFudgefactorActive ( float factor ) =0; + virtual void SetAnchorVsFirstElement (const Fvector& position) =0; + virtual void SetAnchorVsSecondElement (const Fvector& position) =0; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAxisDir (const Fvector& orientation,const int axis_num) =0; + virtual void SetAxisDirVsFirstElement (const Fvector& orientation,const int axis_num) =0; + virtual void SetAxisDirVsSecondElement (const Fvector& orientation,const int axis_num) =0; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAnchor (const float x,const float y,const float z) =0; + virtual void SetAnchorVsFirstElement (const float x,const float y,const float z) =0; + virtual void SetAnchorVsSecondElement (const float x,const float y,const float z) =0; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetAxisDir (const float x,const float y,const float z,const int axis_num) =0; + virtual void SetAxisDirVsFirstElement (const float x,const float y,const float z,const int axis_num) =0; + virtual void SetAxisDirVsSecondElement (const float x,const float y,const float z,const int axis_num) =0; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetLimits (const float low,const float high,const int axis_num) =0; + virtual void SetLimitsVsFirstElement (const float low,const float high,const int axis_num) =0; + virtual void SetLimitsVsSecondElement (const float low,const float high,const int axis_num) =0; + virtual void SetHiLimitDynamic (int axis_num, float limit ) =0; + virtual void SetLoLimitDynamic (int axis_num, float limit ) =0; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetBreakable (float force, float torque) =0; + virtual CPHJointDestroyInfo *JointDestroyInfo () =0; + virtual bool isBreakable () =0; + virtual void SetForceAndVelocity (const float force,const float velocity=0.f,const int axis_num=-1) =0; + virtual void GetMaxForceAndVelocity (float &force,float &velocity,int axis_num) =0; + virtual float GetAxisAngle (int axis_num) =0; + virtual float GetAxisAngleRate (int axis_num) =0; +// virtual dJointID GetDJoint () =0; + virtual void GetAxisSDfactors (float& spring_factor,float& damping_factor,int axis_num) =0; + virtual void GetJointSDfactors (float& spring_factor,float& damping_factor) =0; + virtual void GetLimits (float& lo_limit,float& hi_limit,int axis_num) =0; + virtual void GetAxisDir (int num,Fvector& axis,eVs& vs) =0; + virtual void GetAxisDirDynamic (int num,Fvector& axis) =0; + virtual void GetAnchorDynamic (Fvector& anchor) =0; + virtual bool IsWheelJoint () =0; + virtual bool IsHingeJoint () =0; + virtual void SetForce (const float force,const int axis_num=-1) =0; + virtual void SetVelocity (const float velocity=0.f,const int axis_num=-1) =0; +// DECLARE_SCRIPT_REGISTER_FUNCTION +}; +//add_to_type_list(CPhysicsJoint) +//#undef script_type_list +//#define script_type_list save_type_list(CPhysicsJoint) +// ABSTRACT: +class CPHIsland; +class CPhysicsShellAnimator; + +class XRPHYSICS_API CPhysicsShell : + public CPhysicsBase, + public IPhysicsShell +{ +protected: + IKinematics *m_pKinematics ; +public: +#ifdef DEBUG + IPhysicsShellHolder *dbg_obj ; +#endif +public: +IC IKinematics *PKinematics () {return m_pKinematics ;} +////////////////////////////////////////////////////IPhysicsShell/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +virtual const Fmatrix &XFORM ()const { return CPhysicsBase::XFORM(); } +virtual const IPhysicsElement &Element ( u16 index ) const { return *get_ElementByStoreOrder( index ); }; +virtual void GetGlobalTransformDynamic (Fmatrix* m) = 0; +//virtual u16 get_ElementsNumber ( ) const = 0; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual CPhysicsShellAnimator* PPhysicsShellAnimator () = 0; + void set_Kinematics (IKinematics* p) {m_pKinematics=p ;} + virtual void set_JointResistance (float force) = 0; + virtual void add_Element (CPhysicsElement* E) = 0; + virtual void add_Joint (CPhysicsJoint* E) = 0; + virtual CPHIsland *PIsland () = 0; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////// + virtual const CGID &GetCLGroup ()const = 0; + virtual void RegisterToCLGroup (CGID g) = 0; + virtual bool IsGroupObject () = 0; + virtual void SetIgnoreStatic () = 0; + virtual void SetIgnoreDynamic () = 0; + virtual void SetRagDoll () = 0; + virtual void SetIgnoreRagDoll () = 0; + virtual const CLBits& collide_bits ()const = 0; + virtual const _flags& collide_class_bits ()const = 0; + virtual void CreateShellAnimator ( CInifile const * ini, LPCSTR section ) = 0; + virtual void SetIgnoreAnimated () = 0; +// virtual bool Animated () = 0; + virtual void AnimatorOnFrame () = 0; + virtual void SetSmall () = 0; + virtual void SetIgnoreSmall () = 0; + virtual bool isFractured () = 0; + virtual CPHShellSplitterHolder *SplitterHolder () = 0; + virtual void SplitterHolderActivate () = 0; + virtual void SplitterHolderDeactivate () = 0; + virtual void SplitProcess (PHSHELL_PAIR_VECTOR &out_shels) = 0; + virtual void BlockBreaking () = 0; + virtual void UnblockBreaking () = 0; + virtual bool IsBreakingBlocked () = 0; + virtual void applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val) = 0; + virtual void applyImpulseTrace (const Fvector& pos, const Fvector& dir, float val,const u16 id) = 0; + virtual void applyHit (const Fvector& pos, const Fvector& dir, float val,const u16 id,ALife::EHitType hit_type) = 0; + virtual BoneCallbackFun* GetBonesCallback () = 0; + virtual BoneCallbackFun* GetStaticObjectBonesCallback () = 0; + virtual void Update () = 0; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void get_LinearVel (Fvector& velocity) const = 0; + virtual void get_AngularVel (Fvector& velocity) const = 0; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void setMass1 (float M) = 0; + virtual void SmoothElementsInertia (float k) = 0; + virtual void setEquelInertiaForEls (const dMass& M) = 0; + virtual void addEquelInertiaToEls (const dMass& M) = 0; + virtual void MassAddBox ( float mass, const Fvector &full_size ) = 0; + virtual ELEMENT_STORAGE &Elements () = 0; + virtual CPhysicsElement *get_Element (u16 bone_id) = 0; + virtual CPhysicsElement *get_Element (const shared_str & bone_name) = 0; + virtual CPhysicsElement *get_Element (LPCSTR bone_name) = 0; + virtual CPhysicsElement *get_ElementByStoreOrder (u16 num) = 0; + virtual const CPhysicsElement *get_ElementByStoreOrder (u16 num) const = 0; + virtual CPhysicsElement *get_PhysicsParrentElement ( u16 bone_id ) = 0; + virtual u16 get_ElementsNumber ()const = 0; + virtual CPHSynchronize *get_ElementSync (u16 element) = 0; + virtual CPhysicsJoint *get_Joint (u16 bone_id) = 0; + virtual CPhysicsJoint *get_Joint (const shared_str & bone_name) = 0; + virtual CPhysicsJoint *get_Joint (LPCSTR bone_name) = 0; + virtual CPhysicsJoint *get_JointByStoreOrder (u16 num) = 0; + virtual u16 get_JointsNumber () = 0; + virtual CODEGeom *get_GeomByID (u16 bone_id) = 0; + virtual void Freeze () = 0; + virtual void UnFreeze () = 0; + virtual void NetInterpolationModeON () = 0; + virtual void NetInterpolationModeOFF () = 0; + virtual void Disable () = 0; + virtual void DisableCollision () = 0; + virtual void EnableCollision () = 0; + virtual void SetRemoveCharacterCollLADisable () = 0; + virtual void DisableCharacterCollision () = 0; + virtual void PureStep (float step = fixed_step) = 0; + virtual void SetGlTransformDynamic (const Fmatrix &form) = 0; + virtual void CollideAll () = 0; + virtual CPhysicsElement *NearestToPoint (const Fvector& point, NearestToPointCallback *cb = 0 ) = 0; + virtual void build_FromKinematics (IKinematics* K,BONE_P_MAP* p_geting_map=NULL) = 0; + virtual void preBuild_FromKinematics (IKinematics* K,BONE_P_MAP* p_geting_map=NULL) = 0; + virtual void Build (bool disable=false) = 0; + virtual void _BCL ActivatingBonePoses (IKinematics &K) = 0; + virtual void SetMaxAABBRadius (float size) {}; + + virtual void AddTracedGeom (u16 element=0,u16 geom=0) = 0; + virtual void SetAllGeomTraced () = 0; + virtual void ClearTracedGeoms () = 0; + virtual void DisableGeomTrace () = 0; + virtual void EnableGeomTrace () = 0; + virtual bool HasTracedGeoms () = 0; + + virtual void RunSimulation (bool place_current_forms=true) = 0; + virtual void UpdateRoot () = 0; + virtual void ZeroCallbacks () = 0; + virtual void ResetCallbacks (u16 id,Flags64 &mask) = 0; + virtual void SetCallbacks ( ) = 0; + virtual void EnabledCallbacks (BOOL val) = 0; + virtual void ToAnimBonesPositions ( motion_history_state history_state ) = 0; + virtual bool AnimToVelocityState (float dt, float l_limit, float a_limit ) = 0; + virtual void SetBonesCallbacksOverwrite (bool v) = 0; + virtual Fmatrix &ObjectInRoot () = 0; + virtual void ObjectToRootForm (const Fmatrix& form) = 0; + virtual void SetPrefereExactIntegration () = 0; + virtual ~CPhysicsShell () ; + //build_FromKinematics in returns elements & joint pointers according bone IDs; +// DECLARE_SCRIPT_REGISTER_FUNCTION + }; +//add_to_type_list(CPhysicsShell) +//#undef script_type_list +//#define script_type_list save_type_list(CPhysicsShell) + +struct dContact; +struct SGameMtl; +XRPHYSICS_API void StaticEnvironmentCB ( bool& do_colide, bool bo1, dContact& c, SGameMtl* material_1, SGameMtl* material_2 ); + +// Implementation creator +XRPHYSICS_API CPhysicsJoint* P_create_Joint (CPhysicsJoint::enumType type ,CPhysicsElement* first,CPhysicsElement* second) ; +XRPHYSICS_API CPhysicsElement* P_create_Element () ; +XRPHYSICS_API CPhysicsShell* P_create_Shell () ; +XRPHYSICS_API CPhysicsShell* P_create_splited_Shell () ; +XRPHYSICS_API CPhysicsShell* P_build_Shell (IPhysicsShellHolder* obj,bool not_active_state,LPCSTR fixed_bones) ; +XRPHYSICS_API CPhysicsShell* P_build_Shell (IPhysicsShellHolder* obj,bool not_active_state,U16Vec& fixed_bones) ; +XRPHYSICS_API CPhysicsShell* P_build_Shell (IPhysicsShellHolder* obj,bool not_active_state,BONE_P_MAP* bone_map, LPCSTR fixed_bones) ; + +extern "C" XRPHYSICS_API CPhysicsShell* __stdcall P_build_Shell (IPhysicsShellHolder* obj,bool not_active_state,BONE_P_MAP* bone_map = 0, bool not_set_bone_callbacks = false) ; + +XRPHYSICS_API CPhysicsShell* P_build_SimpleShell (IPhysicsShellHolder* obj,float mass,bool not_active_state) ; +XRPHYSICS_API void ApplySpawnIniToPhysicShell (CInifile const * ini,CPhysicsShell* physics_shell,bool fixed) ; + void fix_bones (LPCSTR fixed_bones,CPhysicsShell* shell ) ; + +extern "C" XRPHYSICS_API void __stdcall destroy_physics_shell (CPhysicsShell* &p) ; + +extern "C" XRPHYSICS_API bool __stdcall can_create_phys_shell( string1024 &reason, IPhysicsShellHolder& O ); + +struct NearestToPointCallback +{ + virtual bool operator() ( CPhysicsElement* e ) = 0; +}; + bool shape_is_physic ( const SBoneShape& shape ); + bool has_physics_collision_shapes ( IKinematics& K ); +XRPHYSICS_API void phys_shell_verify_object_model ( IPhysicsShellHolder& O ); + + + + void phys_shell_verify_model ( IKinematics& K ); +#endif // PhysicsShellH \ No newline at end of file diff --git a/xrPhysics/PhysicsShellAnimator.cpp b/xrPhysics/PhysicsShellAnimator.cpp new file mode 100644 index 00000000000..fc4bb8c1975 --- /dev/null +++ b/xrPhysics/PhysicsShellAnimator.cpp @@ -0,0 +1,103 @@ +#include "StdAfx.h" +#include "PhysicsShellAnimator.h" +#include "PhysicsShellAnimatorBoneData.h" +#include "../Include/xrRender/KinematicsAnimated.h" +#include "../Include/xrRender/Kinematics.h" +#include "PHDynamicData.h" +//#include "game_object_space.h" +#include "IPhysicsShellHolder.h" +#include "../xrEngine/bone.h" + + + + +CPhysicsShellAnimator::CPhysicsShellAnimator( CPhysicsShell* _pPhysicsShell, CInifile const* ini, LPCSTR section ) : m_pPhysicsShell( _pPhysicsShell ) +{ + VERIFY( ini->section_exist( section ) ); + IPhysicsShellHolder *obj = (*(_pPhysicsShell->Elements().begin()))->PhysicsRefObject(); + m_StartXFORM.set( obj->ObjectXFORM() ); + bool all_bones = true; + if( ini->line_exist( section, "controled_bones" ) ) + { + LPCSTR controled = ini->r_string( section, "controled_bones" ); + all_bones = xr_strcmp( controled , "all" ) == 0; + if( !all_bones ) + CreateJoints( controled ); + } + + if( all_bones ) + for (xr_vector::iterator i=m_pPhysicsShell->Elements().begin();i!=m_pPhysicsShell->Elements().end();i++) + CreateJoint(*i); + + if( ini->line_exist( section, "leave_joints" ) && xr_strcmp( ini->r_string( section, "leave_joints" ), "all" ) == 0 ) + return ; + + for (u16 i=0;iget_JointsNumber();i++) + { + ((CPHShell*)(m_pPhysicsShell))->DeleteJoint(i); + } + +} + +CPhysicsShellAnimator::~CPhysicsShellAnimator() +{ + for (xr_vector::iterator i=m_bones_data.begin();i!=m_bones_data.end();i++) + { + ((CPHShell*)(m_pPhysicsShell))->Island().DActiveIsland()->RemoveJoint(i->m_anim_fixed_dJointID); + dJointDestroy(i->m_anim_fixed_dJointID); + } +} +void CPhysicsShellAnimator:: CreateJoints( LPCSTR controled ) +{ + IPhysicsShellHolder *obj = (*(m_pPhysicsShell->Elements().begin()))->PhysicsRefObject(); + const u16 nb =( u16 )_GetItemCount( controled ); + for(u16 i = 0 ; nb > i ; ++i ) + { + string64 n; + _GetItem( controled, i, n ); + u16 bid = m_pPhysicsShell->PKinematics()->LL_BoneID(n); + VERIFY2( bid != BI_NONE, make_string( "shell_animation - controled bone %s not found! object: %s, model: %s", n, obj->ObjectName(), obj->ObjectNameVisual()) ); + CPHElement *e = smart_cast( m_pPhysicsShell->get_Element( bid ) ); + VERIFY2( e, make_string( "shell_animation - controled bone %s has no physics collision! object: %s, model: %s", n, obj->ObjectName(), obj->ObjectNameVisual() ) ); + CreateJoint( e ); + } +} +void CPhysicsShellAnimator:: CreateJoint( CPHElement *e ) +{ + CPhysicsShellAnimatorBoneData PhysicsShellAnimatorBoneDataC; + PhysicsShellAnimatorBoneDataC.m_element=e; + PhysicsShellAnimatorBoneDataC.m_anim_fixed_dJointID=dJointCreateFixed(0,0); + ((CPHShell*)(m_pPhysicsShell))->Island().DActiveIsland()->AddJoint(PhysicsShellAnimatorBoneDataC.m_anim_fixed_dJointID); + dJointAttach(PhysicsShellAnimatorBoneDataC.m_anim_fixed_dJointID,PhysicsShellAnimatorBoneDataC.m_element->get_body(),0); + dJointSetFixed(PhysicsShellAnimatorBoneDataC.m_anim_fixed_dJointID); + m_bones_data.push_back(PhysicsShellAnimatorBoneDataC); +} +void CPhysicsShellAnimator::OnFrame() +{ + + + m_pPhysicsShell->Enable(); + + for (xr_vector::iterator i=m_bones_data.begin();i!=m_bones_data.end();i++) + { + Fmatrix target_obj_posFmatrixS; + CBoneInstance& B=m_pPhysicsShell->PKinematics()->LL_GetBoneInstance(i->m_element->m_SelfID); + //B.Callback_overwrite = FALSE; + //B.Callback = 0; + #pragma todo("reset callback?") + B.set_callback(B.callback_type(),0,B.callback_param(),FALSE); + + m_pPhysicsShell->PKinematics()->CalculateBones_Invalidate(); + m_pPhysicsShell->PKinematics()->CalculateBones(TRUE); + + target_obj_posFmatrixS.mul_43(m_StartXFORM,B.mTransform); + dQuaternion target_obj_quat_dQuaternionS; + dMatrix3 ph_mat; + PHDynamicData::FMXtoDMX(target_obj_posFmatrixS,ph_mat); + dQfromR(target_obj_quat_dQuaternionS,ph_mat); + Fvector mc; + i->m_element->CPHGeometryOwner::get_mc_vs_transform(mc,target_obj_posFmatrixS); + dJointSetFixedQuaternionPos(i->m_anim_fixed_dJointID,target_obj_quat_dQuaternionS,&mc.x); + } + //(*(m_pPhysicsShell->Elements().begin()))->PhysicsRefObject()->XFORM().set(m_pPhysicsShell->mXFORM); +} \ No newline at end of file diff --git a/xrPhysics/PhysicsShellAnimator.h b/xrPhysics/PhysicsShellAnimator.h new file mode 100644 index 00000000000..487f4a1328e --- /dev/null +++ b/xrPhysics/PhysicsShellAnimator.h @@ -0,0 +1,21 @@ +#pragma once + +#include "PhysicsShell.h" +#include "PhysicsShellAnimatorBoneData.h" +class animation_movement_controller; +class CPhysicsShellAnimator +{ + friend class CPhysicsShellAnimatorBoneData; + xr_vector m_bones_data; + CPhysicsShell* m_pPhysicsShell; + Fmatrix m_StartXFORM; + + void CreateJoints( LPCSTR controled ); + void CreateJoint( CPHElement *e ); +public: + CPhysicsShellAnimator ( CPhysicsShell* _pPhysicsShell, CInifile const * ini, LPCSTR section ); + ~CPhysicsShellAnimator (); + void OnFrame (); +}; + + diff --git a/xrPhysics/PhysicsShellAnimatorBoneData.h b/xrPhysics/PhysicsShellAnimatorBoneData.h new file mode 100644 index 00000000000..c78f997a268 --- /dev/null +++ b/xrPhysics/PhysicsShellAnimatorBoneData.h @@ -0,0 +1,10 @@ +#pragma once + +#include "PHShell.h" + +class CPhysicsShellAnimatorBoneData//�������� ���������� �� ������� ������� �������� +{ + friend class CPhysicsShellAnimator; + dJointID m_anim_fixed_dJointID; + CPHElement* m_element; +}; \ No newline at end of file diff --git a/xrPhysics/ShellHit.cpp b/xrPhysics/ShellHit.cpp new file mode 100644 index 00000000000..548d7916e48 --- /dev/null +++ b/xrPhysics/ShellHit.cpp @@ -0,0 +1,65 @@ +#include "StdAfx.h" +#include "PHDynamicData.h" +#include "Physics.h" +#include "tri-colliderknoopc/dTriList.h" +#include "PHShellSplitter.h" +#include "PHFracture.h" +#include "PHJointDestroyInfo.h" +#include "ExtendedGeom.h" + +#include "PHElement.h" +#include "PHShell.h" + + +void CPHShell::applyHit(const Fvector& pos, const Fvector& dir, float val,const u16 id,ALife::EHitType hit_type) +{ + if(id==u16(-1)) return;// +#pragma todo("Kosya to kosya:this code shold treat all hit types") + if(!m_pKinematics) + { + applyImpulseTrace(pos,dir,val); + return; + } + switch(hit_type) { + case ALife::eHitTypeExplosion: + ExplosionHit(pos,dir,val,id); + break; + default: applyImpulseTrace(pos,dir,val,id); + } +} + +void CPHShell::ExplosionHit(const Fvector& pos, const Fvector& dir, float val,const u16 id) +{ + if(!isActive()) return; + EnableObject(0); + //Fvector local_pos;local_pos.set(0.f,0.f,0.f); + ELEMENT_I i=elements.begin(),e=elements.end(); + float impulse=val/_sqrt(_sqrt((float)elements.size())); + for(;i!=e;i++) + { + //Fvector max_area_dir; + CPHElement* element=(*i); + //element->get_MaxAreaDir(max_area_dir); + //float sign=max_area_dir.dotproduct(dir)>0.f ? 1.f : -1.f; + //max_area_dir.mul(sign); + u16 gn=element->CPHGeometryOwner::numberOfGeoms(); + float g_impulse=impulse/gn; + for(u16 j=0;jgetRadius(); + r_box.set(rad,rad,rad); + r_pos.random_point(r_box); + r_dir.random_dir(); + if(!fis_zero(pos.magnitude(),EPS_L)) + { + r_dir.mul(0.5f); + r_dir.add(dir); + } + + r_dir.normalize_safe();//safe??? + element->applyImpulseTrace(r_pos,r_dir,g_impulse,element->CPHGeometryOwner::Geom(j)->bone_id()); + } + } +} diff --git a/xrPhysics/SpaceUtils.h b/xrPhysics/SpaceUtils.h new file mode 100644 index 00000000000..8392c9fde4b --- /dev/null +++ b/xrPhysics/SpaceUtils.h @@ -0,0 +1,21 @@ +#ifndef SPACE_UTILS_H +#define SPACE_UTILS_H +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/ode/src/collision_kernel.h" +#pragma warning(default:4995) +#pragma warning(default:4267) +IC void spatialParsFromDGeom(dGeomID d_space,Fvector& center,Fvector& AABB,float& radius) +{ + + d_space->computeAABB(); + dReal* dAABB=d_space->aabb; + center.set( + (dAABB[0]+dAABB[1])/2.f, + (dAABB[2]+dAABB[3])/2.f, + (dAABB[4]+dAABB[5])/2.f + ); + AABB.x=dAABB[1]-center.x,AABB.y=dAABB[3]-center.y,AABB.z=dAABB[5]-center.z; + radius=_max(AABB.x,_max(AABB.y,AABB.z)); +} +#endif \ No newline at end of file diff --git a/xrPhysics/collisiondamagereceiver.cpp b/xrPhysics/collisiondamagereceiver.cpp new file mode 100644 index 00000000000..1a2941dd5aa --- /dev/null +++ b/xrPhysics/collisiondamagereceiver.cpp @@ -0,0 +1,140 @@ +#include "stdafx.h" + +#include "icollisiondamagereceiver.h" +#include "iphysicsshellholder.h" + +#include "extendedgeom.h" +#include "mathutilsode.h" + +#include "../xrengine/gamemtllib.h" + + + +void DamageReceiverCollisionCallback(bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2) +{ + if(material_1->Flags.test(SGameMtl::flPassable)||material_2->Flags.test(SGameMtl::flPassable))return; + dBodyID b1 = dGeomGetBody(c.geom.g1) ; + dBodyID b2 = dGeomGetBody(c.geom.g2) ; + dxGeomUserData *ud_self = bo1 ? retrieveGeomUserData(c.geom.g1):retrieveGeomUserData(c.geom.g2); + dxGeomUserData *ud_damager = bo1 ? retrieveGeomUserData(c.geom.g2):retrieveGeomUserData(c.geom.g1); + + SGameMtl *material_self = bo1 ? material_1:material_2; + SGameMtl *material_damager = bo1 ? material_2:material_1; + VERIFY (ud_self); + IPhysicsShellHolder *o_self = ud_self->ph_ref_object; + IPhysicsShellHolder *o_damager = NULL;if(ud_damager)o_damager=ud_damager->ph_ref_object; + u16 source_id = o_damager ? o_damager->ObjectID():u16(-1); + + //CPHCollisionDamageReceiver *dr = static_cast( o_self )->PHCollisionDamageReceiver(); + ICollisionDamageReceiver *dr = ( o_self )->ObjectPhCollisionDamageReceiver(); + VERIFY2(dr,"wrong callback"); + + float damager_material_factor = material_damager->fBounceDamageFactor; + + if( ud_damager&&ud_damager->ph_object&& + ud_damager->ph_object->CastType() == CPHObject::tpCharacter ) + o_damager->BonceDamagerCallback( damager_material_factor ); + + //CCharacterPhysicsSupport* phs=static_cast(o_damager)->character_physics_support(); + //if(phs->IsSpecificDamager())damager_material_factor=phs->BonceDamageFactor(); + + + float dfs=(material_self->fBounceDamageFactor+damager_material_factor); + if(fis_zero(dfs)) return; + Fvector dir;dir.set(*(Fvector*)c.geom.normal); + Fvector pos; + pos.sub(*(Fvector*)c.geom.pos,*(Fvector*)dGeomGetPosition(bo1 ? c.geom.g1:c.geom.g2));//it is not true pos in bone space + + dr->CollisionHit( source_id, ud_self->bone_id, E_NL( b1, b2, c.geom.normal )*damager_material_factor/dfs, dir, pos ); + +} + + +void BreakableObjectCollisionCallback(bool&/**do_colide/**/,bool bo1,dContact& c,SGameMtl * /*material_1*/,SGameMtl * /*material_2*/) +{ + dxGeomUserData* usr_data_1= retrieveGeomUserData(c.geom.g1); + dxGeomUserData* usr_data_2=retrieveGeomUserData(c.geom.g2); + VERIFY( usr_data_1 ); + VERIFY( usr_data_2 ); + //CBreakableObject* this_object = 0; + ICollisionDamageReceiver* damag_receiver = 0; + + + + + dBodyID body = 0; + float norm_sign = 0; + + if(bo1) + { + VERIFY( usr_data_1->ph_ref_object ); + damag_receiver = usr_data_1->ph_ref_object->ObjectPhCollisionDamageReceiver(); + body = dGeomGetBody( c.geom.g2 ); + norm_sign=-1.f; + } + else + { + VERIFY( usr_data_2->ph_ref_object ); + damag_receiver = usr_data_2->ph_ref_object->ObjectPhCollisionDamageReceiver(); + body = dGeomGetBody( c.geom.g1 ); + norm_sign=1.f; + } + VERIFY( damag_receiver ); + +/* + + CBreakableObject* this_object1 = 0; + CBreakableObject* this_object2 = 0; + VERIFY( usr_data_1 ); + VERIFY( usr_data_2 ); + this_object1 = smart_cast( usr_data_1->ph_ref_object ); + this_object2 = smart_cast( usr_data_2->ph_ref_object ); + if( + usr_data_1&& + usr_data_1->ph_ref_object&& + this_object1 + ) + { + body=dGeomGetBody(c.geom.g2); + if(!body) return; + this_object = this_object1; + norm_sign=-1.f; + } + else if( + usr_data_2&& + usr_data_2->ph_ref_object&& + this_object2 + ) + { + body=dGeomGetBody(c.geom.g1); + if(!body) return; + this_object = this_object2; + norm_sign=1.f; + } + else return; + + */ + //if(!this_object->m_pUnbrokenObject) return; + + float c_damage=E_NlS(body,c.geom.normal,norm_sign); + Fvector dir = Fvector().set(-c.geom.normal[0]*norm_sign,-c.geom.normal[1]*norm_sign,-c.geom.normal[2]*norm_sign); + Fvector pos = Fvector().set(c.geom.pos[0],c.geom.pos[1],c.geom.pos[2]); + + damag_receiver->CollisionHit( u16(-1), u16(-1), c_damage, dir, pos ); + + //VERIFY( this_object->m_pUnbrokenObject ); + + + + //if(this_object->m_damage_thresholdm_max_frame_damageb_resived_damage=true; + // this_object->m_max_frame_damage=c_damage; + // //this_object->m_contact_damage_pos.set(c.geom.pos[0],c.geom.pos[1],c.geom.pos[2]); + // this_object->m_contact_damage_pos.set( pos ); + // //this_object->m_contact_damage_dir.set(-c.geom.normal[0]*norm_sign,-c.geom.normal[1]*norm_sign,-c.geom.normal[2]*norm_sign); + // this_object->m_contact_damage_dir.set( dir ); + // } +} + diff --git a/xrPhysics/console_vars.cpp b/xrPhysics/console_vars.cpp new file mode 100644 index 00000000000..7810abeee53 --- /dev/null +++ b/xrPhysics/console_vars.cpp @@ -0,0 +1,13 @@ +#include "stdafx.h" +#include "console_vars.h" + +#include "physicscommon.h" + +BOOL ph_console::g_bDebugDumpPhysicsStep = 0; +float ph_console::ph_tri_query_ex_aabb_rate = 1.3f; +int ph_console::ph_tri_clear_disable_count = 10; + +float ph_console::phBreakCommonFactor = 0.01f; +float ph_console::phRigidBreakWeaponFactor = 1.f; + +float ph_console::ph_step_time =fixed_step; \ No newline at end of file diff --git a/xrPhysics/console_vars.h b/xrPhysics/console_vars.h new file mode 100644 index 00000000000..7710ab5753f --- /dev/null +++ b/xrPhysics/console_vars.h @@ -0,0 +1,11 @@ +#pragma once + +struct XRPHYSICS_API ph_console +{ + static BOOL g_bDebugDumpPhysicsStep ;//= 0; + static float ph_tri_query_ex_aabb_rate ;//= 1.3f; + static int ph_tri_clear_disable_count ;//= 10; + static float phBreakCommonFactor ;//= 0.01f; + static float phRigidBreakWeaponFactor ;//= 1.f; + static float ph_step_time ;//=fixed_step; +}; \ No newline at end of file diff --git a/xrPhysics/dRayMotions.cpp b/xrPhysics/dRayMotions.cpp new file mode 100644 index 00000000000..a79ed3a7592 --- /dev/null +++ b/xrPhysics/dRayMotions.cpp @@ -0,0 +1,136 @@ +#include "stdafx.h" +#include "dCylinder/dCylinder.h" +struct dContactGeom; +int dCollideCylRay(dxGeom *o1, dxGeom *o2, int flags,dContactGeom *contact, int skip); +//#pragma warning(disable:4995) +//#pragma warning(disable:4267) +//#include "../3rd party/ode/ode/src/collision_kernel.h" +//#pragma warning(default:4995) +//#pragma warning(default:4267) + +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/ode/src/collision_std.h" +#pragma warning(default:4995) +#pragma warning(default:4267) +struct dxRayMotions +{ + dGeomID ray; + dGeomID ray_ownwer; + dxRayMotions() + { + ray=0; + ray_ownwer=0; + } +}; + +int dRayMotionsClassUser = -1; + +#define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) + + + + + + +int dCollideRMB (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dxRayMotions *rm = (dxRayMotions*) dGeomGetClassData(o1); + int ret= dCollideRayBox (rm->ray,o2, flags,contact,skip); + for (int i=0; ig1 = rm->ray_ownwer; + //c->depth*=60.f; + } + return ret; +} + +int dCollideRMS(dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dxRayMotions *rm = (dxRayMotions*) dGeomGetClassData(o1); + int ret= dCollideRaySphere (rm->ray, o2,flags, contact, skip); + for (int i=0; ig1 = rm->ray_ownwer; + //c->depth*=60.f; + } + return ret; +} +inline void revert_contact(dContactGeom *c) +{ + c->normal[0] = -c->normal[0]; + c->normal[1] = -c->normal[1]; + c->normal[2] = -c->normal[2]; + dxGeom *tmp = c->g1; + c->g1 = c->g2; + c->g2 = tmp; +} +int dCollideRMCyl (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dxRayMotions *rm = (dxRayMotions*) dGeomGetClassData(o1); + int ret= dCollideCylRay (o2,rm->ray,flags,contact,skip); + for (int i=0; ig1 = rm->ray_ownwer; + } + return ret; +} + +static dColliderFn * dRayMotionsColliderFn (int num) +{ + if (num == dBoxClass) return (dColliderFn *) &dCollideRMB; + if (num == dSphereClass) return (dColliderFn *) &dCollideRMS; + if (num == dCylinderClassUser) return (dColliderFn *) &dCollideRMCyl; + return 0; +} + + +static void dRayMotionsAABB (dxGeom *geom, dReal aabb[6]) +{ + dxRayMotions *c = (dxRayMotions*) dGeomGetClassData(geom); + dGeomGetAABB(c->ray,aabb); + ///dInfiniteAABB(geom,aabb); +} +void dGeomRayMotionDestroy (dGeomID ray) +{ + dGeomDestroy(((dxRayMotions*)dGeomGetClassData(ray))->ray); +} +dxGeom *dCreateRayMotions (dSpaceID space) +{ + if (dRayMotionsClassUser == -1) + { + dGeomClass c; + c.bytes = sizeof (dxRayMotions); + c.collider = &dRayMotionsColliderFn; + c.aabb = &dRayMotionsAABB; + c.aabb_test = 0; + c.dtor = &dGeomRayMotionDestroy; + dRayMotionsClassUser =dCreateGeomClass (&c); + + } + dGeomID g = dCreateGeom (dRayMotionsClassUser); + if (space) dSpaceAdd (space,g); + dxRayMotions *c = (dxRayMotions*) dGeomGetClassData(g); + c->ray=dCreateRay(space,REAL(1.)); + return g; +} + +void dGeomRayMotionsSet (dGeomID g,const dReal* p,const dReal* d, dReal l) +{ + dxRayMotions *c = (dxRayMotions*) dGeomGetClassData(g); + dGeomRaySetLength (c->ray, l); + dGeomRaySet (c->ray, p[0], p[1], p[2], + d[0], d[1], d[2]); + dGeomMoved(g); + +} + +void dGeomRayMotionSetGeom(dGeomID rm,dGeomID g) +{ + dxRayMotions *c = (dxRayMotions*) dGeomGetClassData(rm); + c->ray_ownwer=g; +} diff --git a/xrPhysics/dRayMotions.h b/xrPhysics/dRayMotions.h new file mode 100644 index 00000000000..c2ec12fe6fb --- /dev/null +++ b/xrPhysics/dRayMotions.h @@ -0,0 +1,12 @@ +#ifndef dRayMotions_h +#define dRayMotions_h + +struct dxRayMotions; +extern int dRayMotionsClassUser; + + +dxGeom *dCreateRayMotions (dSpaceID space); +void dGeomRayMotionsSet (dGeomID g,const dReal* p,const dReal* d, dReal l); +void dGeomRayMotionSetGeom(dGeomID rm,dGeomID g); + +#endif //dRayMotions_h \ No newline at end of file diff --git a/xrPhysics/dcylinder/dCylinder.cpp b/xrPhysics/dcylinder/dCylinder.cpp new file mode 100644 index 00000000000..d9d337534ee --- /dev/null +++ b/xrPhysics/dcylinder/dCylinder.cpp @@ -0,0 +1,1549 @@ +#include "stdafx.h" + +#include "dCylinder.h" + +#include "../ode_include.h" + +// given a pointer `p' to a dContactGeom, return the dContactGeom at +// p + skip bytes. + +#define M_SIN_PI_3 REAL(0.8660254037844386467637231707529362) +#define M_COS_PI_3 REAL(0.5000000000000000000000000000000000) + +struct dxCylinder { // cylinder + dReal radius,lz; // radius, length along y axis // +}; + +int dCylinderClassUser = -1; + +#define NUMC_MASK (0xffff) + +#define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) + +///////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////circleIntersection////////////////////////////////////////////////// +//this does following: +//takes two circles as normals to planes n1,n2, center points cp1,cp2,and radiuses r1,r2 +//finds line on which circles' planes intersect +//finds four points O1,O2 - intersection between the line and sphere with center cp1 radius r1 +// O3,O4 - intersection between the line and sphere with center cp2 radius r2 +//returns false if there is no intersection +//computes distances O1-O3, O1-O4, O2-O3, O2-O4 +//in "point" returns mean point between intersection points with smallest distance +///////////////////////////////////////////////////////////////////////////////////////////////// +inline bool circleIntersection(const dReal* n1,const dReal* cp1,dReal r1,const dReal* n2,const dReal* cp2,dReal r2,dVector3 point){ +dReal c1=dDOT14(cp1,n1); +dReal c2=dDOT14(cp2,n2); +dReal _cos=dDOT44(n1,n2); +dReal cos_2=_cos*_cos; +dReal sin_2=1.f-cos_2; +dReal p1=(c1-c2*_cos)/sin_2; +dReal p2=(c2-c1*_cos)/sin_2; +dVector3 lp={p1*n1[0]+p2*n2[0],p1*n1[4]+p2*n2[4],p1*n1[8]+p2*n2[8]}; +dVector3 n; +dCROSS144(n,=,n1,n2); +dVector3 LC1={lp[0]-cp1[0],lp[1]-cp1[1],lp[2]-cp1[2]}; +dVector3 LC2={lp[0]-cp2[0],lp[1]-cp2[1],lp[2]-cp2[2]}; +dReal A,B,C,B_A,B_A_2,D; +dReal t1,t2,t3,t4; +A=dDOT(n,n); +B=dDOT(LC1,n); +C=dDOT(LC1,LC1)-r1*r1; +B_A=B/A; +B_A_2=B_A*B_A; +D=B_A_2-C; +if(D<0.f){ //somewhat strange solution + //- it is needed to set some + //axis to sepparate cylinders + //when their edges approach + t1=-B_A+dSqrt(-D); + t2=-B_A-dSqrt(-D); +// return false; + } +else{ +t1=-B_A-dSqrt(D); +t2=-B_A+dSqrt(D); +} +B=dDOT(LC2,n); +C=dDOT(LC2,LC2)-r2*r2; +B_A=B/A; +B_A_2=B_A*B_A; +D=B_A_2-C; + +if(D<0.f) { + t3=-B_A+dSqrt(-D); + t4=-B_A-dSqrt(-D); +// return false; + } +else{ +t3=-B_A-dSqrt(D); +t4=-B_A+dSqrt(D); +} +dVector3 O1={lp[0]+n[0]*t1,lp[1]+n[1]*t1,lp[2]+n[2]*t1}; +dVector3 O2={lp[0]+n[0]*t2,lp[1]+n[1]*t2,lp[2]+n[2]*t2}; + +dVector3 O3={lp[0]+n[0]*t3,lp[1]+n[1]*t3,lp[2]+n[2]*t3}; +dVector3 O4={lp[0]+n[0]*t4,lp[1]+n[1]*t4,lp[2]+n[2]*t4}; + +dVector3 L1_3={O3[0]-O1[0],O3[1]-O1[1],O3[2]-O1[2]}; +dVector3 L1_4={O4[0]-O1[0],O4[1]-O1[1],O4[2]-O1[2]}; + +dVector3 L2_3={O3[0]-O2[0],O3[1]-O2[1],O3[2]-O2[2]}; +dVector3 L2_4={O4[0]-O2[0],O4[1]-O2[1],O4[2]-O2[2]}; + + +dReal l1_3=dDOT(L1_3,L1_3); +dReal l1_4=dDOT(L1_4,L1_4); + +dReal l2_3=dDOT(L2_3,L2_3); +dReal l2_4=dDOT(L2_4,L2_4); + + +if (l1_3 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = norm; \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } + + s = -dInfinity; + invert_normal = 0; + *code = 0; + + // separating axis = cylinder ax u2 + //used when a box vertex touches a flat face of the cylinder + TEST (pp[1],(hlz + B1*Q21 + B2*Q22 + B3*Q23),R1+1,0); + + + // separating axis = box axis v1,v2,v3 + //used when cylinder edge touches box face + //there is two ways to compute sQ: sQ21=dSqrt(1.f-Q21*Q21); or sQ21=dSqrt(Q23*Q23+Q22*Q22); + //if we did not need Q23 and Q22 the first way might be used to quiken the routine but then it need to + //check if Q21<=1.f, becouse it may slightly exeed 1.f. + + + sQ21=dSqrt(Q23*Q23+Q22*Q22); + TEST (dDOT41(R2+0,p),(radius*sQ21 + hlz*Q21 + B1),R2+0,1); + + sQ22=dSqrt(Q23*Q23+Q21*Q21); + TEST (dDOT41(R2+1,p),(radius*sQ22 + hlz*Q22 + B2),R2+1,2); + + sQ23=dSqrt(Q22*Q22+Q21*Q21); + TEST (dDOT41(R2+2,p),(radius*sQ23 + hlz*Q23 + B3),R2+2,3); + + +#undef TEST +#define TEST(expr1,expr2,n1,n2,n3,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = 0; \ + normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } + + + +// separating axis is a normal to the cylinder axis passing across the nearest box vertex +//used when a box vertex touches the lateral surface of the cylinder + +dReal proj,boxProj,_cos,_sin,cos1,cos3; +dVector3 tAx,Ax,pb; +{ +//making Ax which is perpendicular to cyl ax to box position// +proj=dDOT14(p2,R1+1)-dDOT14(p1,R1+1); + +Ax[0]=p2[0]-p1[0]-R1[1]*proj; +Ax[1]=p2[1]-p1[1]-R1[5]*proj; +Ax[2]=p2[2]-p1[2]-R1[9]*proj; +dNormalize3(Ax); +//using Ax find box vertex which is nearest to the cylinder axis + dReal sign; + + for (i=0; i<3; ++i) pb[i] = p2[i]; + sign = (dDOT14(Ax,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) pb[i] += sign * B1 * R2[i*4]; + sign = (dDOT14(Ax,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) pb[i] += sign * B2 * R2[i*4+1]; + sign = (dDOT14(Ax,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) pb[i] += sign * B3 * R2[i*4+2]; + +//building axis which is normal to cylinder ax to the nearest box vertex +proj=dDOT14(pb,R1+1)-dDOT14(p1,R1+1); + +Ax[0]=pb[0]-p1[0]-R1[1]*proj; +Ax[1]=pb[1]-p1[1]-R1[5]*proj; +Ax[2]=pb[2]-p1[2]-R1[9]*proj; +dNormalize3(Ax); +} + +boxProj=dFabs(dDOT14(Ax,R2+0)*B1)+ + dFabs(dDOT14(Ax,R2+1)*B2)+ + dFabs(dDOT14(Ax,R2+2)*B3); + +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(radius+boxProj),Ax[0],Ax[1],Ax[2],4); + + +//next three test used to handle collisions between cylinder circles and box ages +proj=dDOT14(p1,R2+0)-dDOT14(p2,R2+0); + +tAx[0]=-p1[0]+p2[0]+R2[0]*proj; +tAx[1]=-p1[1]+p2[1]+R2[4]*proj; +tAx[2]=-p1[2]+p2[2]+R2[8]*proj; +dNormalize3(tAx); + +//now tAx is normal to first ax of the box to cylinder center +//making perpendicular to tAx lying in the plane which is normal to the cylinder axis +//it is tangent in the point where projection of tAx on cylinder's ring intersect edge circle + +_cos=dDOT14(tAx,R1+0); +_sin=dDOT14(tAx,R1+2); +tAx[0]=R1[2]*_cos-R1[0]*_sin; +tAx[1]=R1[6]*_cos-R1[4]*_sin; +tAx[2]=R1[10]*_cos-R1[8]*_sin; + + +//use cross between tAx and first ax of the box as separating axix + +dCROSS114(Ax,=,tAx,R2+0); +dNormalize3(Ax); + +boxProj=dFabs(dDOT14(Ax,R2+1)*B2)+ + dFabs(dDOT14(Ax,R2+0)*B1)+ + dFabs(dDOT14(Ax,R2+2)*B3); + + _cos=dFabs(dDOT14(Ax,R1+1)); + cos1=dDOT14(Ax,R1+0); + cos3=dDOT14(Ax,R1+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); + +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(_sin*radius+_cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],5); + + +//same thing with the second axis of the box +proj=dDOT14(p1,R2+1)-dDOT14(p2,R2+1); + +tAx[0]=-p1[0]+p2[0]+R2[1]*proj; +tAx[1]=-p1[1]+p2[1]+R2[5]*proj; +tAx[2]=-p1[2]+p2[2]+R2[9]*proj; +dNormalize3(tAx); + + +_cos=dDOT14(tAx,R1+0); +_sin=dDOT14(tAx,R1+2); +tAx[0]=R1[2]*_cos-R1[0]*_sin; +tAx[1]=R1[6]*_cos-R1[4]*_sin; +tAx[2]=R1[10]*_cos-R1[8]*_sin; + +dCROSS114(Ax,=,tAx,R2+1); +dNormalize3(Ax); + +boxProj=dFabs(dDOT14(Ax,R2+0)*B1)+ + dFabs(dDOT14(Ax,R2+1)*B2)+ + dFabs(dDOT14(Ax,R2+2)*B3); + + _cos=dFabs(dDOT14(Ax,R1+1)); + cos1=dDOT14(Ax,R1+0); + cos3=dDOT14(Ax,R1+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(_sin*radius+_cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],6); + +//same thing with the third axis of the box +proj=dDOT14(p1,R2+2)-dDOT14(p2,R2+2); + +Ax[0]=-p1[0]+p2[0]+R2[2]*proj; +Ax[1]=-p1[1]+p2[1]+R2[6]*proj; +Ax[2]=-p1[2]+p2[2]+R2[10]*proj; +dNormalize3(tAx); + +_cos=dDOT14(tAx,R1+0); +_sin=dDOT14(tAx,R1+2); +tAx[0]=R1[2]*_cos-R1[0]*_sin; +tAx[1]=R1[6]*_cos-R1[4]*_sin; +tAx[2]=R1[10]*_cos-R1[8]*_sin; + +dCROSS114(Ax,=,tAx,R2+2); +dNormalize3(Ax); +boxProj=dFabs(dDOT14(Ax,R2+1)*B2)+ + dFabs(dDOT14(Ax,R2+2)*B3)+ + dFabs(dDOT14(Ax,R2+0)*B1); + + _cos=dFabs(dDOT14(Ax,R1+1)); + cos1=dDOT14(Ax,R1+0); + cos3=dDOT14(Ax,R1+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(_sin*radius+_cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],7); + + +#undef TEST + +// note: cross product axes need to be scaled when s is computed. +// normal (n1,n2,n3) is relative to box 1. + +#define TEST(expr1,expr2,n1,n2,n3,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ + if (l > 0) { \ + s2 /= l; \ + if (s2 > s) { \ + s = s2; \ + normalR = 0; \ + normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } \ + } + +//crosses between cylinder axis and box axes + // separating axis = u2 x (v1,v2,v3) + TEST(pp[0]*R31-pp[2]*R11,(radius+B2*Q23+B3*Q22),R31,0,-R11,8); + TEST(pp[0]*R32-pp[2]*R12,(radius+B1*Q23+B3*Q21),R32,0,-R12,9); + TEST(pp[0]*R33-pp[2]*R13,(radius+B1*Q22+B2*Q21),R33,0,-R13,10); + + +#undef TEST + + // if we get to this point, the boxes interpenetrate. compute the normal + // in global coordinates. + if (normalR) { + normal[0] = normalR[0]; + normal[1] = normalR[4]; + normal[2] = normalR[8]; + } + else { + if(*code>7) dMULTIPLY0_331 (normal,R1,normalC); + else {normal[0] =normalC[0];normal[1] = normalC[1];normal[2] = normalC[2];} + } + + if (invert_normal) { + normal[0] = -normal[0]; + normal[1] = -normal[1]; + normal[2] = -normal[2]; + } + *depth = -s; + + // compute contact point(s) + + if (*code > 7) { + //find point on the cylinder pa deepest along normal + dVector3 pa; + dReal sign, cos1,cos3,factor; + + + for (i=0; i<3; ++i) pa[i] = p1[i]; + + cos1 = dDOT14(normal,R1+0); + cos3 = dDOT14(normal,R1+2) ; + factor=dSqrt(cos1*cos1+cos3*cos3); + + cos1/=factor; + cos3/=factor; + + for (i=0; i<3; ++i) pa[i] += cos1 * radius * R1[i*4]; + + sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) pa[i] += sign * hlz * R1[i*4+1]; + + + for (i=0; i<3; ++i) pa[i] += cos3 * radius * R1[i*4+2]; + + // find vertex of the box deepest along normal + dVector3 pb; + for (i=0; i<3; ++i) pb[i] = p2[i]; + sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) pb[i] += sign * B1 * R2[i*4]; + sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) pb[i] += sign * B2 * R2[i*4+1]; + sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) pb[i] += sign * B3 * R2[i*4+2]; + + + dReal alpha,beta; + dVector3 ua,ub; + for (i=0; i<3; ++i) ua[i] = R1[1 + i*4]; + for (i=0; i<3; ++i) ub[i] = R2[*code-8 + i*4]; + + lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); + for (i=0; i<3; ++i) pa[i] += ua[i]*alpha; + for (i=0; i<3; ++i) pb[i] += ub[i]*beta; + + for (i=0; i<3; ++i) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); + contact[0].depth = *depth; + return 1; + } + + + if(*code==4){ + for (i=0; i<3; ++i) contact[0].pos[i] = pb[i]; + contact[0].depth = *depth; + return 1; + } + + + dVector3 vertex; + if (*code == 0) { + + dReal sign; + for (i=0; i<3; ++i) vertex[i] = p2[i]; + sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) vertex[i] += sign * B1 * R2[i*4]; + sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) vertex[i] += sign * B2 * R2[i*4+1]; + sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; ++i) vertex[i] += sign * B3 * R2[i*4+2]; + } + else { + + dReal sign,cos1,cos3,factor; + dVector3 center; + cos1 = dDOT14(normal,R1+0) ; + cos3 = dDOT14(normal,R1+2); + factor=dSqrt(cos1*cos1+cos3*cos3); + factor= factor ? factor : 1.f; + cos1/=factor; + cos3/=factor; + sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + + for (i=0; i<3; ++i) center[i] = p1[i]+sign * hlz * R1[i*4+1]; + for (i=0; i<3; ++i) vertex[i] = center[i]+cos1 * radius * R1[i*4]; + for (i=0; i<3; ++i) vertex[i] += cos3 * radius * R1[i*4+2]; + if(*code<4) + { + + dReal A1,A3,centerDepth,Q1,Q3,sQ2; + + + Q1=Q11;Q3=Q31;sQ2=sQ21; + int ret=1; + switch(*code) { + //case 1: + // centerDepth=*depth-radius*sQ21; + // Q1=Q11;Q3=Q31; + // break; + case 2: + sQ2=sQ22; + Q1=Q12;Q3=Q32; + break; + case 3: + sQ2=sQ23; + Q1=Q13;Q3=Q33; + break; + + } + + if(sQ2pos[0]=center[0]+A1*R1[0]+A3*R1[2]; + CONTACT(contact,ret*skip)->pos[1]=center[1]+A1*R1[4]+A3*R1[6]; + CONTACT(contact,ret*skip)->pos[2]=center[2]+A1*R1[8]+A3*R1[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+Q1*A1+Q3*A3; + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + + A1=(-cos1*M_COS_PI_3+cos3*M_SIN_PI_3)*radius; + A3=(-cos3*M_COS_PI_3-cos1*M_SIN_PI_3)*radius; + CONTACT(contact,ret*skip)->pos[0]=center[0]+A1*R1[0]+A3*R1[2]; + CONTACT(contact,ret*skip)->pos[1]=center[1]+A1*R1[4]+A3*R1[6]; + CONTACT(contact,ret*skip)->pos[2]=center[2]+A1*R1[8]+A3*R1[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+Q1*A1+Q3*A3; + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + } + + for (i=0; i<3; ++i) contact[0].pos[i] = vertex[i]; + contact[0].depth = *depth; + return ret; + } + + } + for (i=0; i<3; ++i) contact[0].pos[i] = vertex[i]; + contact[0].depth = *depth; + return 1; +} + +//**************************************************************************** + +extern "C" int dCylCyl (const dVector3 p1, const dMatrix3 R1, + const dReal radius1,const dReal lz1, const dVector3 p2, + const dMatrix3 R2, const dReal radius2,const dReal lz2, + dVector3 normal, dReal *depth, int *code, + int maxc, dContactGeom *contact, int skip) +{ + dVector3 p,pp1,pp2,normalC; + const dReal *normalR = 0; + dReal hlz1,hlz2,s,s2; + int i,invert_normal; + + // get vector3 from centers of box 1 to box 2, relative to box 1 + p[0] = p2[0] - p1[0]; + p[1] = p2[1] - p1[1]; + p[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (pp1,R1,p); // get pp1 = p relative to body 1 + dMULTIPLY1_331 (pp2,R2,p); + // get side lengths / 2 + hlz1 = lz1*REAL(0.5); + hlz2 = lz2*REAL(0.5); + + dReal proj,cos1,cos3; + + + +#define TEST(expr1,expr2,norm,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = norm; \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } + + s = -dInfinity; + invert_normal = 0; + *code = 0; + + dReal c_cos=dFabs(dDOT44(R1+1,R2+1)); + dReal c_sin=dSqrt(1.f-(c_cos>1.f ? 1.f : c_cos)); + + TEST (pp1[1],(hlz1 + radius2*c_sin + hlz2*c_cos ),R1+1,0);//pp + + /// TEST (pp2[1],(radius1*c_sin + hlz1*c_cos + hlz2),R2+1,1); + + + + // note: cross product axes need to be scaled when s is computed. + +#undef TEST +#define TEST(expr1,expr2,n1,n2,n3,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = 0; \ + normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } + + +dVector3 tAx,Ax,pa,pb; + +//cross between cylinders' axes +dCROSS144(Ax,=,R1+1,R2+1); +dNormalize3(Ax); +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius1+radius2,Ax[0],Ax[1],Ax[2],6); + + +{ + + dReal sign, factor; + + //making ax which is perpendicular to cyl1 ax passing across cyl2 position// + //(project p on cyl1 flat surface ) + for (i=0; i<3; ++i) pb[i] = p2[i]; + //cos1 = dDOT14(p,R1+0); + //cos3 = dDOT14(p,R1+2) ; + tAx[0]=pp1[0]*R1[0]+pp1[2]*R1[2]; + tAx[1]=pp1[0]*R1[4]+pp1[2]*R1[6]; + tAx[2]=pp1[0]*R1[8]+pp1[2]*R1[10]; + dNormalize3(tAx); + +//find deepest point pb of cyl2 on opposite direction of tAx + cos1 = dDOT14(tAx,R2+0); + cos3 = dDOT14(tAx,R2+2) ; + factor=dSqrt(cos1*cos1+cos3*cos3); + cos1/=factor; + cos3/=factor; + for (i=0; i<3; ++i) pb[i] -= cos1 * radius2 * R2[i*4]; + + sign = (dDOT14(tAx,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) pb[i] -= sign * hlz2 * R2[i*4+1]; + + for (i=0; i<3; ++i) pb[i] -= cos3 * radius2 * R2[i*4+2]; + +//making perpendicular to cyl1 ax passing across pb + proj=dDOT14(pb,R1+1)-dDOT14(p1,R1+1); + + Ax[0]=pb[0]-p1[0]-R1[1]*proj; + Ax[1]=pb[1]-p1[1]-R1[5]*proj; + Ax[2]=pb[2]-p1[2]-R1[9]*proj; + +} + +dNormalize3(Ax); + + + dReal _cos=dFabs(dDOT14(Ax,R2+1)); + cos1=dDOT14(Ax,R2+0); + cos3=dDOT14(Ax,R2+2); + dReal _sin=dSqrt(cos1*cos1+cos3*cos3); + +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius1+_cos*hlz2+_sin*radius2,Ax[0],Ax[1],Ax[2],3); + + + +{ + + dReal sign, factor; + + for (i=0; i<3; ++i) pa[i] = p1[i]; + + //making ax which is perpendicular to cyl2 ax passing across cyl1 position// + //(project p on cyl2 flat surface ) + //cos1 = dDOT14(p,R2+0); + //cos3 = dDOT14(p,R2+2) ; + tAx[0]=pp2[0]*R2[0]+pp2[2]*R2[2]; + tAx[1]=pp2[0]*R2[4]+pp2[2]*R2[6]; + tAx[2]=pp2[0]*R2[8]+pp2[2]*R2[10]; + dNormalize3(tAx); + + cos1 = dDOT14(tAx,R1+0); + cos3 = dDOT14(tAx,R1+2) ; + factor=dSqrt(cos1*cos1+cos3*cos3); + cos1/=factor; + cos3/=factor; + +//find deepest point pa of cyl2 on direction of tAx + for (i=0; i<3; ++i) pa[i] += cos1 * radius1 * R1[i*4]; + + sign = (dDOT14(tAx,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) pa[i] += sign * hlz1 * R1[i*4+1]; + + + for (i=0; i<3; ++i) pa[i] += cos3 * radius1 * R1[i*4+2]; + + proj=dDOT14(pa,R2+1)-dDOT14(p2,R2+1); + + Ax[0]=pa[0]-p2[0]-R2[1]*proj; + Ax[1]=pa[1]-p2[1]-R2[5]*proj; + Ax[2]=pa[2]-p2[2]-R2[9]*proj; + +} +dNormalize3(Ax); + + + + _cos=dFabs(dDOT14(Ax,R1+1)); + cos1=dDOT14(Ax,R1+0); + cos3=dDOT14(Ax,R1+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); + +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius2+_cos*hlz1+_sin*radius1,Ax[0],Ax[1],Ax[2],4); + + +////test circl + +//@ this needed to set right normal when cylinders edges intersect +//@ the most precise axis for this test may be found as a line between nearest points of two +//@ circles. But it needs comparatively a lot of computation. +//@ I use a trick which lets not to solve quadric equation. +//@ In the case when cylinder eidges touches the test below rather accurate. +//@ I still not sure about problems with sepparation but they have not been revealed during testing. +dVector3 point; +{ + dVector3 ca,cb; + dReal sign; + for (i=0; i<3; ++i) ca[i] = p1[i]; + for (i=0; i<3; ++i) cb[i] = p2[i]; +//find two nearest flat rings + sign = (pp1[1] > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) ca[i] += sign * hlz1 * R1[i*4+1]; + + sign = (pp2[1] > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) cb[i] -= sign * hlz2 * R2[i*4+1]; + + dVector3 tAx,tAx1; + circleIntersection(R1+1,ca,radius1,R2+1,cb,radius2,point); + + Ax[0]=point[0]-ca[0]; + Ax[1]=point[1]-ca[1]; + Ax[2]=point[2]-ca[2]; + + cos1 = dDOT14(Ax,R1+0); + cos3 = dDOT14(Ax,R1+2) ; + + tAx[0]=cos3*R1[0]-cos1*R1[2]; + tAx[1]=cos3*R1[4]-cos1*R1[6]; + tAx[2]=cos3*R1[8]-cos1*R1[10]; + + Ax[0]=point[0]-cb[0]; + Ax[1]=point[1]-cb[1]; + Ax[2]=point[2]-cb[2]; + + + cos1 = dDOT14(Ax,R2+0); + cos3 = dDOT14(Ax,R2+2) ; + + tAx1[0]=cos3*R2[0]-cos1*R2[2]; + tAx1[1]=cos3*R2[4]-cos1*R2[6]; + tAx1[2]=cos3*R2[8]-cos1*R2[10]; + dCROSS(Ax,=,tAx,tAx1); + + + + +dNormalize3(Ax); +dReal cyl1Pr,cyl2Pr; + + _cos=dFabs(dDOT14(Ax,R1+1)); + cos1=dDOT14(Ax,R1+0); + cos3=dDOT14(Ax,R1+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); + cyl1Pr=_cos*hlz1+_sin*radius1; + + _cos=dFabs(dDOT14(Ax,R2+1)); + cos1=dDOT14(Ax,R2+0); + cos3=dDOT14(Ax,R2+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); + cyl2Pr=_cos*hlz2+_sin*radius2; +TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],cyl1Pr+cyl2Pr,Ax[0],Ax[1],Ax[2],5); + + +} + + +#undef TEST + + + + // if we get to this point, the cylinders interpenetrate. compute the normal + // in global coordinates. + if (normalR) { + normal[0] = normalR[0]; + normal[1] = normalR[4]; + normal[2] = normalR[8]; + } + else { + normal[0] =normalC[0];normal[1] = normalC[1];normal[2] = normalC[2]; + } + if (invert_normal) { + normal[0] = -normal[0]; + normal[1] = -normal[1]; + normal[2] = -normal[2]; + } + + *depth = -s; + + // compute contact point(s) + + if(*code==3){ + for (i=0; i<3; ++i) contact[0].pos[i] = pb[i]; + contact[0].depth = *depth; + return 1; + } + + if(*code==4){ + for (i=0; i<3; ++i) contact[0].pos[i] = pa[i]; + contact[0].depth = *depth; + return 1; + } + + if(*code==5){ + for (i=0; i<3; ++i) contact[0].pos[i] = point[i]; + contact[0].depth = *depth; + return 1; + } + +if (*code == 6) { + dVector3 pa; + dReal sign, cos1,cos3,factor; + + + for (i=0; i<3; ++i) pa[i] = p1[i]; + + cos1 = dDOT14(normal,R1+0); + cos3 = dDOT14(normal,R1+2) ; + factor=dSqrt(cos1*cos1+cos3*cos3); + if(factor>0.f) + { + cos1/=factor; + cos3/=factor; + } + for (i=0; i<3; ++i) pa[i] += cos1 * radius1 * R1[i*4]; + + sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) pa[i] += sign * hlz1 * R1[i*4+1]; + + + for (i=0; i<3; ++i) pa[i] += cos3 * radius1 * R1[i*4+2]; + + // find a point pb on the intersecting edge of cylinder 2 + dVector3 pb; + for (i=0; i<3; ++i) pb[i] = p2[i]; + cos1 = dDOT14(normal,R2+0); + cos3 = dDOT14(normal,R2+2) ; + factor=dSqrt(cos1*cos1+cos3*cos3); + if(factor>0.f) + { + cos1/=factor; + cos3/=factor; + } + for (i=0; i<3; ++i) pb[i] -= cos1 * radius2 * R2[i*4]; + + sign = (dDOT14(normal,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) pb[i] -= sign * hlz2 * R2[i*4+1]; + + + for (i=0; i<3; ++i) pb[i] -= cos3 * radius2 * R2[i*4+2]; + + + dReal alpha,beta; + dVector3 ua,ub; + for (i=0; i<3; ++i) ua[i] = R1[1 + i*4]; + for (i=0; i<3; ++i) ub[i] = R2[1 + i*4]; + lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); + for (i=0; i<3; ++i) pa[i] += ua[i]*alpha; + for (i=0; i<3; ++i) pb[i] += ub[i]*beta; + + for (i=0; i<3; ++i) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); + contact[0].depth = *depth; + return 1; + } + + // okay, we have a face-something intersection (because the separating + // axis is perpendicular to a face). + + // @@@ temporary: make deepest point on the "other" cylinder the contact point. + // @@@ this kind of works, but we need multiple contact points for stability, + // @@@ especially for face-face contact. + + dVector3 vertex; + int ret=1; + if (*code == 0) { + + // flat face from cylinder 1 touches a edge/face from cylinder 2. + dReal sign,cos1,cos3,factor; + // for (i=0; i<3; ++i) vertex[i] = p2[i]; + cos1 = dDOT14(normal,R2+0) ; + cos3 = dDOT14(normal,R2+2); + factor=dSqrt(cos1*cos1+cos3*cos3); + if(factor>0.f) + { + cos1/=factor; + cos3/=factor; + } + dVector3 center; + + sign = (dDOT14(normal,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) center[i] =p2[i]- sign * hlz2 * R2[i*4+1]; + + for (i=0; i<3; ++i) vertex[i] =center[i]- cos1 * radius2 * R2[i*4]; + + for (i=0; i<3; ++i) vertex[i] -=cos3 * radius2 * R2[i*4+2]; + + + dReal A1,A3,centerDepth,Q1,Q3; + centerDepth=*depth-radius2*(factor); + Q1=-(dDOT14(normal,R2+0));Q3=-(dDOT14(normal,R2+2)); + + A1=-(-cos1*M_COS_PI_3-cos3*M_SIN_PI_3)*radius2; + A3=-(-cos3*M_COS_PI_3+cos1*M_SIN_PI_3)*radius2; + CONTACT(contact,ret*skip)->pos[0]=center[0]+A1*R2[0]+A3*R2[2]; + CONTACT(contact,ret*skip)->pos[1]=center[1]+A1*R2[4]+A3*R2[6]; + CONTACT(contact,ret*skip)->pos[2]=center[2]+A1*R2[8]+A3*R2[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+(Q1*A1)+(Q3*A3); + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + + A1=-(-cos1*M_COS_PI_3+cos3*M_SIN_PI_3)*radius2; + A3=-(-cos3*M_COS_PI_3-cos1*M_SIN_PI_3)*radius2; + CONTACT(contact,ret*skip)->pos[0]=center[0]+A1*R2[0]+A3*R2[2]; + CONTACT(contact,ret*skip)->pos[1]=center[1]+A1*R2[4]+A3*R2[6]; + CONTACT(contact,ret*skip)->pos[2]=center[2]+A1*R2[8]+A3*R2[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+(Q1*A1)+(Q3*A3); + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + + } + else { + // flat face from cylinder 2 touches a edge/face from cylinder 1. + dReal sign,cos1,cos3,factor; + // for (i=0; i<3; ++i) vertex[i] = p1[i]; + cos1 = dDOT14(normal,R1+0) ; + cos3 = dDOT14(normal,R1+2); + factor=dSqrt(cos1*cos1+cos3*cos3); + if(factor>0.f) + { + cos1/=factor; + cos3/=factor; + } + + dVector3 center; + + sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) center[i] =p1[i]+sign * hlz1 * R1[i*4+1]; + + + for (i=0; i<3; ++i) vertex[i] =center[i]+cos1 * radius1 * R1[i*4]; + for (i=0; i<3; ++i) vertex[i] += cos3 * radius1 * R1[i*4+2]; + + + dReal A1,A3,centerDepth,Q1,Q3; + centerDepth=*depth-radius1*(factor); + Q1=(dDOT(R2+1,R1+0));Q3=(dDOT(R2+1,R1+2)); + + + A1=(-cos1*M_COS_PI_3-cos3*M_SIN_PI_3)*radius1; + A3=(-cos3*M_COS_PI_3+cos1*M_SIN_PI_3)*radius1; + CONTACT(contact,ret*skip)->pos[0]=center[0]+A1*R1[0]+A3*R1[2]; + CONTACT(contact,ret*skip)->pos[1]=center[1]+A1*R1[4]+A3*R1[6]; + CONTACT(contact,ret*skip)->pos[2]=center[2]+A1*R1[8]+A3*R1[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+dFabs(Q1*A1)+dFabs(Q3*A3); + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + + A1=(-cos1*M_COS_PI_3+cos3*M_SIN_PI_3)*radius1; + A3=(-cos3*M_COS_PI_3-cos1*M_SIN_PI_3)*radius1; + CONTACT(contact,ret*skip)->pos[0]=center[0]+A1*R1[0]+A3*R1[2]; + CONTACT(contact,ret*skip)->pos[1]=center[1]+A1*R1[4]+A3*R1[6]; + CONTACT(contact,ret*skip)->pos[2]=center[2]+A1*R1[8]+A3*R1[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+dFabs(Q1*A1)+dFabs(Q3*A3); + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + + + } + for (i=0; i<3; ++i) contact[0].pos[i] = vertex[i]; + contact[0].depth = *depth; + return ret; +} + +#pragma todo(optimize factor==0.f) +//**************************************************************************** + + +int dCollideCylS (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + + + VERIFY (skip >= (int)sizeof(dContactGeom)); + VERIFY (dGeomGetClass(o2) == dSphereClass); + VERIFY (dGeomGetClass(o1) == dCylinderClassUser); + const dReal* p1=dGeomGetPosition(o1); + const dReal* p2=dGeomGetPosition(o2); + const dReal* R=dGeomGetRotation(o1); + dVector3 p,normalC,normal; + const dReal *normalR = 0; + dReal cylRadius; + dReal hl; + dGeomCylinderGetParams(o1,&cylRadius,&hl); + hl/=2.f; + dReal sphereRadius; + sphereRadius=dGeomSphereGetRadius(o2); + + int i,invert_normal; + + // get vector3 from centers of cyl to shere + p[0] = p2[0] - p1[0]; + p[1] = p2[1] - p1[1]; + p[2] = p2[2] - p1[2]; + +dReal s,s2; +unsigned char code; +#define TEST(expr1,expr2,norm,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = norm; \ + invert_normal = ((expr1) < 0); \ + code = (cc); \ + } + + s = -dInfinity; + invert_normal = 0; + code = 0; + + // separating axis cyl ax + + TEST (dDOT14(p,R+1),sphereRadius+hl,R+1,2); + // note: cross product axes need to be scaled when s is computed. + // normal (n1,n2,n3) is relative to +#undef TEST +#define TEST(expr1,expr2,n1,n2,n3,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = 0; \ + normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ + invert_normal = ((expr1) < 0); \ + code = (cc); \ + } + +//making ax which is perpendicular to cyl1 ax to sphere center// + +dReal proj,_cos,_sin,cos1,cos3; +dVector3 Ax; + proj=dDOT14(p2,R+1)-dDOT14(p1,R+1); + + Ax[0]=p2[0]-p1[0]-R[1]*proj; + Ax[1]=p2[1]-p1[1]-R[5]*proj; + Ax[2]=p2[2]-p1[2]-R[9]*proj; +dNormalize3(Ax); +TEST(dDOT(p,Ax),sphereRadius+cylRadius,Ax[0],Ax[1],Ax[2],9); + + +Ax[0]=p[0]; +Ax[1]=p[1]; +Ax[2]=p[2]; +dNormalize3(Ax); + + dVector3 pa; + dReal sign, factor; + for (i=0; i<3; ++i) pa[i] = p1[i]; + + cos1 = dDOT14(Ax,R+0); + cos3 = dDOT14(Ax,R+2) ; + factor=dSqrt(cos1*cos1+cos3*cos3); + cos1/=factor; + cos3/=factor; + for (i=0; i<3; ++i) pa[i] += cos1 * cylRadius * R[i*4]; + sign = (dDOT14(Ax,R+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; ++i) pa[i] += sign * hl * R[i*4+1]; + for (i=0; i<3; ++i) pa[i] += cos3 * cylRadius * R[i*4+2]; + +Ax[0]=p2[0]-pa[0]; +Ax[1]=p2[1]-pa[1]; +Ax[2]=p2[2]-pa[2]; +dNormalize3(Ax); + + _cos=dFabs(dDOT14(Ax,R+1)); + cos1=dDOT14(Ax,R+0); + cos3=dDOT14(Ax,R+2); + _sin=dSqrt(cos1*cos1+cos3*cos3); +TEST(dDOT(p,Ax),sphereRadius+cylRadius*_sin+hl*_cos,Ax[0],Ax[1],Ax[2],14); + + +#undef TEST + + if (normalR) { + normal[0] = normalR[0]; + normal[1] = normalR[4]; + normal[2] = normalR[8]; + } + else { + + normal[0] = normalC[0]; + normal[1] = normalC[1]; + normal[2] = normalC[2]; + } + if (invert_normal) { + normal[0] = -normal[0]; + normal[1] = -normal[1]; + normal[2] = -normal[2]; + } + // compute contact point(s) +contact->depth=-s; +contact->normal[0]=-normal[0]; +contact->normal[1]=-normal[1]; +contact->normal[2]=-normal[2]; +contact->g1=const_cast (o1); +contact->g2=const_cast (o2); +contact->pos[0]=p2[0]-normal[0]*sphereRadius; +contact->pos[1]=p2[1]-normal[1]*sphereRadius; +contact->pos[2]=p2[2]-normal[2]*sphereRadius; +return 1; +} + + + +int dCollideCylB (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dVector3 normal; + dReal depth; + int code; + dReal cylRadius,cylLength; + dVector3 boxSides; + dGeomCylinderGetParams(o1,&cylRadius,&cylLength); + dGeomBoxGetLengths(o2,boxSides); + int num = dCylBox(dGeomGetPosition(o1),dGeomGetRotation(o1),cylRadius,cylLength, + dGeomGetPosition(o2),dGeomGetRotation(o2),boxSides, + normal,&depth,&code,flags & NUMC_MASK,contact,skip); + for (int i=0; inormal[0] = -normal[0]; + CONTACT(contact,i*skip)->normal[1] = -normal[1]; + CONTACT(contact,i*skip)->normal[2] = -normal[2]; + CONTACT(contact,i*skip)->g1 = const_cast (o1); + CONTACT(contact,i*skip)->g2 = const_cast (o2); + } + return num; +} + +int dCollideCylCyl (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dVector3 normal; + dReal depth; + int code; +dReal cylRadius1,cylRadius2; +dReal cylLength1,cylLength2; +dGeomCylinderGetParams(o1,&cylRadius1,&cylLength1); +dGeomCylinderGetParams(o2,&cylRadius2,&cylLength2); +int num = dCylCyl (dGeomGetPosition(o1),dGeomGetRotation(o1),cylRadius1,cylLength1, + dGeomGetPosition(o2),dGeomGetRotation(o2),cylRadius2,cylLength2, + normal,&depth,&code,flags & NUMC_MASK,contact,skip); + + for (int i=0; inormal[0] = -normal[0]; + CONTACT(contact,i*skip)->normal[1] = -normal[1]; + CONTACT(contact,i*skip)->normal[2] = -normal[2]; + CONTACT(contact,i*skip)->g1 = const_cast (o1); + CONTACT(contact,i*skip)->g2 = const_cast (o2); + } + return num; +} + +struct dxPlane { + dReal p[4]; +}; + + +int dCollideCylPlane + ( + dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip){ + VERIFY (skip >= (int)sizeof(dContactGeom)); + VERIFY (dGeomGetClass(o1) == dCylinderClassUser); + VERIFY (dGeomGetClass(o2) == dPlaneClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + + unsigned int ret = 0; + + dReal radius; + dReal hlz; + dGeomCylinderGetParams(o1,&radius,&hlz); + hlz/=REAL(2.); + const dReal *R = dGeomGetRotation(o1);// rotation of cylinder + const dReal* p = dGeomGetPosition(o1); + dVector4 n; // normal vector3 + dReal pp; + dGeomPlaneGetParams (o2, n); + pp=n[3]; + dReal cos1,sin1; + cos1=dFabs(dDOT14(n,R+1)); + +cos1=cos10 ? hlz*R[1]:-hlz*R[1]; + pos[1]-= A2>0 ? hlz*R[5]:-hlz*R[5]; + pos[2]-= A2>0 ? hlz*R[9]:-hlz*R[9]; + + + + contact->pos[0] = pos[0]; + contact->pos[1] = pos[1]; + contact->pos[2] = pos[2]; + contact->depth = outDepth; + ret=1; + +if(dFabs(Q2)>M_SQRT1_2){ + + CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A1*R[0]; + CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A1*R[4]; + CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A1*R[8]; + CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q1*2.f*A1); + + if(CONTACT(contact,ret*skip)->depth>0.f) + ++ret; + + + CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A3*R[2]; + CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A3*R[6]; + CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A3*R[10]; + CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q3*2.f*A3); + + if(CONTACT(contact,ret*skip)->depth>0.f) ++ret; +} else { + + CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*(A2>0 ? hlz*R[1]:-hlz*R[1]); + CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*(A2>0 ? hlz*R[5]:-hlz*R[5]); + CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*(A2>0 ? hlz*R[9]:-hlz*R[9]); + CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q2*2.f*A2); + + if(CONTACT(contact,ret*skip)->depth>0.f) ++ret; +} + + + + for (unsigned int i=0; ig1 = const_cast (o1); + CONTACT(contact,i*skip)->g2 = const_cast (o2); + CONTACT(contact,i*skip)->normal[0] =n[0]; + CONTACT(contact,i*skip)->normal[1] =n[1]; + CONTACT(contact,i*skip)->normal[2] =n[2]; + } + return ret; +} + +int dCollideCylRay(dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) { + VERIFY (skip >= (int)sizeof(dContactGeom)); + VERIFY (dGeomGetClass(o1) == dCylinderClassUser); + VERIFY (dGeomGetClass(o2) == dRayClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dReal radius; + dReal lz; + dGeomCylinderGetParams(o1,&radius,&lz); + dReal lz2=lz*REAL(0.5); + const dReal *R = dGeomGetRotation(o1); // rotation of the cylinder + const dReal *p = dGeomGetPosition(o1); // position of the cylinder + dVector3 start,dir; + dGeomRayGet(o2,start,dir); // position and orientation of the ray + dReal length = dGeomRayGetLength(o2); + + // compute some useful info + dVector3 cs,q,r; + dReal C,k; + cs[0] = start[0] - p[0]; + cs[1] = start[1] - p[1]; + cs[2] = start[2] - p[2]; + k = dDOT41(R+1,cs); // position of ray start along cyl axis (Y) + q[0] = k*R[0*4+1] - cs[0]; + q[1] = k*R[1*4+1] - cs[1]; + q[2] = k*R[2*4+1] - cs[2]; + C = dDOT(q,q) - radius*radius; + // if C < 0 then ray start position within infinite extension of cylinder + // if ray start position is inside the cylinder + int inside_cyl=0; + if (C<0 && !(k<-lz2 || k>lz2)) inside_cyl=1; + // compute ray collision with infinite cylinder, except for the case where + // the ray is outside the cylinder but within the infinite cylinder + // (it that case the ray can only hit endcaps) + if (!inside_cyl && C < 0) { + // set k to cap position to check + if (k < 0) k = -lz2; else k = lz2; + } + else { + dReal uv = dDOT41(R+1,dir); + r[0] = uv*R[0*4+1] - dir[0]; + r[1] = uv*R[1*4+1] - dir[1]; + r[2] = uv*R[2*4+1] - dir[2]; + dReal A = dDOT(r,r); + dReal B = 2*dDOT(q,r); + k = B*B-4*A*C; + if (k < 0) { + // the ray does not intersect the infinite cylinder, but if the ray is + // inside and parallel to the cylinder axis it may intersect the end + // caps. set k to cap position to check. + if (!inside_cyl) return 0; + if (uv < 0) k = -lz2; else k = lz2; + } + else { + k = dSqrt(k); + A = dRecip (2*A); + dReal alpha = (-B-k)*A; + if (alpha < 0) { + alpha = (-B+k)*A; + if (alpha<0) return 0; + } + if (alpha>length) return 0; + // the ray intersects the infinite cylinder. check to see if the + // intersection point is between the caps + contact->pos[0] = start[0] + alpha*dir[0]; + contact->pos[1] = start[1] + alpha*dir[1]; + contact->pos[2] = start[2] + alpha*dir[2]; + q[0] = contact->pos[0] - p[0]; + q[1] = contact->pos[1] - p[1]; + q[2] = contact->pos[2] - p[2]; + k = dDOT14(q,R+1); + dReal nsign = inside_cyl ? -REAL(1.) :REAL(1.); + if (k >= -lz2 && k <= lz2) { + contact->normal[0] = nsign * (contact->pos[0] - + (p[0] + k*R[0*4+1])); + contact->normal[1] = nsign * (contact->pos[1] - + (p[1] + k*R[1*4+1])); + contact->normal[2] = nsign * (contact->pos[2] - + (p[2] + k*R[2*4+1])); + dNormalize3 (contact->normal); + contact->depth = alpha; + return 1; + } + // the infinite cylinder intersection point is not between the caps. + // set k to cap position to check. + if (k < 0) k = -lz2; else k = lz2; + } + } + // check for ray intersection with the caps. k must indicate the cap + // position to check + // perform a ray plan interesection + // R+1 is the plan normal + q[0] = start[0] - (p[0] + k*R[0*4+1]); + q[1] = start[1] - (p[1] + k*R[1*4+1]); + q[2] = start[2] - (p[2] + k*R[2*4+1]); + dReal alpha = -dDOT14(q,R+1); + dReal k2 = dDOT14(dir,R+1); + if (k2==0) return 0; // ray parallel to the plane + alpha/=k2; + if (alpha<0 || alpha>length) return 0; // too short + contact->pos[0]=start[0]+alpha*dir[0]; + contact->pos[1]=start[1]+alpha*dir[1]; + contact->pos[2]=start[2]+alpha*dir[2]; + dReal nsign = (k<0)?-REAL(1.):REAL(1.); + contact->normal[0]=nsign*R[0*4+1]; + contact->normal[1]=nsign*R[1*4+1]; + contact->normal[2]=nsign*R[2*4+1]; + contact->depth=alpha; + return 1; + } + +static dColliderFn * dCylinderColliderFn (int num) +{ + if (num == dBoxClass) return (dColliderFn *) &dCollideCylB; + if (num == dSphereClass) return (dColliderFn *) &dCollideCylS; + if (num == dCylinderClassUser) return (dColliderFn *) &dCollideCylCyl; + if (num == dPlaneClass) return (dColliderFn *) &dCollideCylPlane; + return 0; +} + + +static void dCylinderAABB (dxGeom *geom, dReal aabb[6]) +{ + dReal radius,lz; + dGeomCylinderGetParams(geom,&radius,&lz); +const dReal* R= dGeomGetRotation(geom); +const dReal* pos= dGeomGetPosition(geom); + + + dReal xrange = REAL(0.5) * dFabs (R[1] * lz) + (dSqrt(R[0]*R[0]+R[2]*R[2]) * radius); + + dReal yrange = REAL(0.5) * dFabs (R[5] * lz) + (dSqrt(R[4]*R[4]+R[6]*R[6]) * radius); + + dReal zrange = REAL(0.5) * dFabs (R[9] * lz) + (dSqrt(R[8]*R[8]+R[10]*R[10]) * radius); + + aabb[0] = pos[0] - xrange; + aabb[1] = pos[0] + xrange; + aabb[2] = pos[1] - yrange; + aabb[3] = pos[1] + yrange; + aabb[4] = pos[2] - zrange; + aabb[5] = pos[2] + zrange; +} + +dxGeom *dCreateCylinder (dSpaceID space, dReal r, dReal lz) +{ + VERIFY (r > 0 && lz > 0); + if (dCylinderClassUser == -1) + { + dGeomClass c; + c.bytes = sizeof (dxCylinder); + c.collider = &dCylinderColliderFn; + c.aabb = &dCylinderAABB; + c.aabb_test = 0; + c.dtor = 0; + dCylinderClassUser=dCreateGeomClass (&c); + + } + + dGeomID g = dCreateGeom (dCylinderClassUser); + if (space) dSpaceAdd (space,g); + dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); + + c->radius = r; + c->lz = lz; + return g; +} + + + +void dGeomCylinderSetParams (dGeomID g, dReal radius, dReal length) +{ + VERIFY2 (g && dGeomGetClass(g) == dCylinderClassUser ,"argument not a cylinder"); + VERIFY (radius > 0 && length > 0); + dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); + c->radius = radius; + c->lz = length; +} + + + +void dGeomCylinderGetParams (dGeomID g, dReal *radius, dReal *length) +{ + VERIFY2 (g && dGeomGetClass(g) == dCylinderClassUser ,"argument not a cylinder"); + dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); + *radius = c->radius; + *length = c->lz; +} + diff --git a/xrPhysics/dcylinder/dCylinder.h b/xrPhysics/dcylinder/dCylinder.h new file mode 100644 index 00000000000..3582fe61d3a --- /dev/null +++ b/xrPhysics/dcylinder/dCylinder.h @@ -0,0 +1,17 @@ + +#ifndef dCylinder_h +#define dCylinder_h + + + +#include "../../3rd party/ode/include/ode/common.h" + +struct dxCylinder; +extern int dCylinderClassUser; + + +dxGeom *dCreateCylinder (dSpaceID space, dReal r, dReal lz); +void dGeomCylinderSetParams (dGeomID g, dReal radius, dReal length); + +void dGeomCylinderGetParams (dGeomID g, dReal *radius, dReal *length); +#endif //dCylinder_h \ No newline at end of file diff --git a/xrPhysics/debug_output.cpp b/xrPhysics/debug_output.cpp new file mode 100644 index 00000000000..ca9e38cabac --- /dev/null +++ b/xrPhysics/debug_output.cpp @@ -0,0 +1,178 @@ +#include "stdafx.h" +#include "debug_output.h" +#ifdef DEBUG + +static class DebugOutputEmptyImpl: + public IDebugOutput +{ + Flags32 m1; + Flags32 m2; + +virtual const Flags32 &ph_dbg_draw_mask ()const +{ + return m1; +}; +virtual const Flags32 &ph_dbg_draw_mask1 ()const +{ + return m2; +} + + +virtual void DBG_DrawStatBeforeFrameStep( ) +{ + +} +virtual void DBG_DrawStatAfterFrameStep( ) +{ + +} +//virtual void DBG_RenderUpdate( ) =0; +virtual void DBG_OpenCashedDraw( ) +{ + +} +virtual void DBG_ClosedCashedDraw( u32 remove_time ) +{ + +} +//virtual void DBG_DrawPHAbstruct( SPHDBGDrawAbsract* a ) =0; +virtual void DBG_DrawPHObject( const CPHObject *obj ) +{ + +} +virtual void DBG_DrawContact ( const dContact &c ) +{ + +} +virtual void DBG_DrawTri( CDB::RESULT *T, u32 c ) +{ + +} +virtual void DBG_DrawTri(CDB::TRI *T, const Fvector *V_verts, u32 c ) +{ + +} +virtual void DBG_DrawLine( const Fvector &p0, const Fvector &p1, u32 c ) +{ + +} +virtual void DBG_DrawAABB( const Fvector ¢er, const Fvector& AABB, u32 c ) +{ + +} +virtual void DBG_DrawOBB( const Fmatrix &m, const Fvector h, u32 c ) +{ + +} +virtual void DBG_DrawPoint( const Fvector& p, float size, u32 c ) +{ + +} +virtual void DBG_DrawMatrix( const Fmatrix &m, float size, u8 a=255 ) +{ + +} +//virtual void DBG_DrawRotationX( const Fmatrix &m, float ang0, float ang1, float size, u32 ac, bool solid = false, u32 tessel = 7 ) = 0; +//virtual void DBG_DrawRotationY( const Fmatrix &m, float ang0, float ang1, float size, u32 ac, bool solid = false, u32 tessel = 7 ) = 0; +//virtual void DBG_DrawRotationZ( const Fmatrix &m, float ang0, float ang1, float size, u32 ac, bool solid = false, u32 tessel = 7 ) = 0; +virtual void _cdecl DBG_OutText( LPCSTR s,... ) +{ + +} +//virtual void DBG_TextOutSet( float x, float y ) =0; +//virtual void DBG_TextSetColor( u32 color ) =0; +//virtual void DBG_DrawBind( CObject &O ) =0; +//virtual void DBG_PhysBones( CObject &O ) =0; +//virtual void DBG_DrawBones( CObject &O ) =0; +virtual void DBG_DrawFrameStart( ) +{ + +} +virtual void PH_DBG_Render( ) +{ + +} +virtual void PH_DBG_Clear( ) +{ + +} + +virtual LPCSTR PH_DBG_ObjectTrackName( ) +{ + return "none"; +} + +//virtual bool draw_frame ()=0; +u32 tries_num; +virtual u32 &dbg_tries_num () +{ + return tries_num; +} +u32 saved_tries_for_active_objects; +virtual u32 &dbg_saved_tries_for_active_objects () +{ + return saved_tries_for_active_objects; +} +u32 total_saved_tries; +virtual u32 &dbg_total_saved_tries () +{ + return total_saved_tries; +} +u32 reused_queries_per_step; +virtual u32 &dbg_reused_queries_per_step () +{ + return reused_queries_per_step; +} +u32 new_queries_per_step; +virtual u32 &dbg_new_queries_per_step () +{ + return new_queries_per_step; +} +u32 bodies_num; +virtual u32 &dbg_bodies_num () +{ + return bodies_num; +} +u32 joints_num; +virtual u32 &dbg_joints_num () +{ + return joints_num; +} +u32 islands_num; +virtual u32 &dbg_islands_num () +{ + return islands_num; +} +u32 contacts_num; +virtual u32 &dbg_contacts_num () +{ + return contacts_num; +} +float vel_collid_damage_to_display; +virtual float dbg_vel_collid_damage_to_display() +{ + return vel_collid_damage_to_display; +} + +virtual void DBG_ObjAfterPhDataUpdate ( CPHObject *obj ){} +virtual void DBG_ObjBeforePhDataUpdate ( CPHObject *obj ){} +virtual void DBG_ObjAfterStep ( CPHObject *obj ){} +virtual void DBG_ObjBeforeStep ( CPHObject *obj ){} +virtual void DBG_ObjeAfterPhTune ( CPHObject *obj ){} +virtual void DBG_ObjBeforePhTune ( CPHObject *obj ){} +virtual void DBG_ObjAfterCollision ( CPHObject *obj ){} +virtual void DBG_ObjBeforeCollision ( CPHObject *obj ){} + + +} dbg_output_empty; + + + + + + + + + +IDebugOutput *ph_debug_output = &dbg_output_empty; +#endif \ No newline at end of file diff --git a/xrPhysics/debug_output.h b/xrPhysics/debug_output.h new file mode 100644 index 00000000000..97d17790633 --- /dev/null +++ b/xrPhysics/debug_output.h @@ -0,0 +1,138 @@ +#pragma once +#ifdef DEBUG + + enum +{ + phDbgDrawContacts = 1<<0, + phDbgDrawEnabledAABBS = 1<<1, + phDBgDrawIntersectedTries = 1<<2, + phDbgDrawSavedTries = 1<<3, + phDbgDrawTriTrace = 1<<4, + phDBgDrawNegativeTries = 1<<5, + phDBgDrawPositiveTries = 1<<6, + phDbgDrawTriTestAABB = 1<<7, + phDBgDrawTriesChangesSign = 1<<8, + phDbgDrawTriPoint = 1<<9, + phDbgDrawExplosionPos = 1<<10, + phDbgDrawObjectStatistics = 1<<11, + phDbgDrawMassCenters = 1<<12, + phDbgDrawDeathActivationBox = 1<<14, + phHitApplicationPoints = 1<<15, + phDbgDrawCashedTriesStat = 1<<16, + phDbgDrawCarDynamics = 1<<17, + phDbgDrawCarPlots = 1<<18, + phDbgLadder = 1<<19, + phDbgDrawExplosions = 1<<20, + phDbgDrawCarAllTrnsm = 1<<21, + phDbgDrawZDisable = 1<<22, + phDbgAlwaysUseAiPhMove = 1<<23, + phDbgNeverUseAiPhMove = 1<<24, + phDbgDispObjCollisionDammage= 1<<25, + phDbgIK = 1<<26, + phDbgDrawIKGoal = 1<<27, + phDbgIKLimits = 1<<28, + phDbgCharacterControl = 1<<29, + phDbgDrawRayMotions = 1<<30, + phDbgTrackObject = 1<<31 + +}; +///ph_dbg_draw_mask1 ne pereputat by blin! +enum +{ + ph_m1_DbgTrackObject = 1<<0, + ph_m1_DbgActorRestriction = 1<<1, + phDbgIKOff = 1<<2, + phDbgHitAnims = 1<<3, + phDbgDrawIKLimits = 1<<4, + phDbgDrawIKPredict = 1<<5, + phDbgDrawIKSHiftObject = 1<<6, + phDbgDrawIKCollision = 1<<7, + phDbgDrawIKBlending = 1<<8 +}; + +enum +{ + dbg_track_obj_blends_bp_0 = 1<< 0, + dbg_track_obj_blends_bp_1 = 1<< 1, + dbg_track_obj_blends_bp_2 = 1<< 2, + dbg_track_obj_blends_bp_3 = 1<< 3, + dbg_track_obj_blends_motion_name = 1<< 4, + dbg_track_obj_blends_time = 1<< 5, + dbg_track_obj_blends_ammount = 1<< 6, + dbg_track_obj_blends_mix_params = 1<< 7, + dbg_track_obj_blends_flags = 1<< 8, + dbg_track_obj_blends_state = 1<< 9, + dbg_track_obj_blends_dump = 1<< 10 +}; +struct dContact; +class CPHObject; +class IDebugOutput +{ +public: +virtual const Flags32 &ph_dbg_draw_mask ()const = 0; +virtual const Flags32 &ph_dbg_draw_mask1 ()const = 0; + + +virtual void DBG_DrawStatBeforeFrameStep( ) =0; +virtual void DBG_DrawStatAfterFrameStep( ) =0; +//virtual void DBG_RenderUpdate( ) =0; +virtual void DBG_OpenCashedDraw( ) =0; +virtual void DBG_ClosedCashedDraw( u32 remove_time ) =0; +//virtual void DBG_DrawPHAbstruct( SPHDBGDrawAbsract* a ) =0; +virtual void DBG_DrawPHObject( const CPHObject *obj ) =0; +virtual void DBG_DrawContact ( const dContact &c ) =0; +virtual void DBG_DrawTri( CDB::RESULT *T, u32 c ) =0; +virtual void DBG_DrawTri(CDB::TRI *T, const Fvector *V_verts, u32 c ) =0; +virtual void DBG_DrawLine( const Fvector &p0, const Fvector &p1, u32 c ) =0; +virtual void DBG_DrawAABB( const Fvector ¢er, const Fvector& AABB, u32 c ) =0; +virtual void DBG_DrawOBB( const Fmatrix &m, const Fvector h, u32 c ) =0; +virtual void DBG_DrawPoint( const Fvector& p, float size, u32 c ) =0; +virtual void DBG_DrawMatrix( const Fmatrix &m, float size, u8 a=255 ) =0; +//virtual void DBG_DrawRotationX( const Fmatrix &m, float ang0, float ang1, float size, u32 ac, bool solid = false, u32 tessel = 7 ) = 0; +//virtual void DBG_DrawRotationY( const Fmatrix &m, float ang0, float ang1, float size, u32 ac, bool solid = false, u32 tessel = 7 ) = 0; +//virtual void DBG_DrawRotationZ( const Fmatrix &m, float ang0, float ang1, float size, u32 ac, bool solid = false, u32 tessel = 7 ) = 0; +virtual void _cdecl DBG_OutText( LPCSTR s,... ) =0; +//virtual void DBG_TextOutSet( float x, float y ) =0; +//virtual void DBG_TextSetColor( u32 color ) =0; +//virtual void DBG_DrawBind( CObject &O ) =0; +//virtual void DBG_PhysBones( CObject &O ) =0; +//virtual void DBG_DrawBones( CObject &O ) =0; +virtual void DBG_DrawFrameStart( ) =0; +virtual void PH_DBG_Render( ) =0; +virtual void PH_DBG_Clear( ) =0; +virtual LPCSTR PH_DBG_ObjectTrackName( ) =0; + +//virtual bool draw_frame ()=0; +virtual u32 &dbg_tries_num ()=0; +virtual u32 &dbg_saved_tries_for_active_objects ()=0; +virtual u32 &dbg_total_saved_tries ()=0; +virtual u32 &dbg_reused_queries_per_step ()=0; +virtual u32 &dbg_new_queries_per_step ()=0; +virtual u32 &dbg_bodies_num ()=0; +virtual u32 &dbg_joints_num ()=0; +virtual u32 &dbg_islands_num ()=0; +virtual u32 &dbg_contacts_num ()=0; + +virtual float dbg_vel_collid_damage_to_display() =0; + +virtual void DBG_ObjAfterPhDataUpdate ( CPHObject *obj )=0; +virtual void DBG_ObjBeforePhDataUpdate ( CPHObject *obj )=0; +virtual void DBG_ObjAfterStep ( CPHObject *obj )=0; +virtual void DBG_ObjBeforeStep ( CPHObject *obj )=0; +virtual void DBG_ObjeAfterPhTune ( CPHObject *obj )=0; +virtual void DBG_ObjBeforePhTune ( CPHObject *obj )=0; +virtual void DBG_ObjAfterCollision ( CPHObject *obj )=0; +virtual void DBG_ObjBeforeCollision ( CPHObject *obj )=0; + + +}; + +extern XRPHYSICS_API IDebugOutput *ph_debug_output; + +IC IDebugOutput &debug_output() +{ + VERIFY(ph_debug_output); + return *ph_debug_output; +} + +#endif \ No newline at end of file diff --git a/xrPhysics/iclimableobject.h b/xrPhysics/iclimableobject.h new file mode 100644 index 00000000000..9516302fc50 --- /dev/null +++ b/xrPhysics/iclimableobject.h @@ -0,0 +1,43 @@ +#pragma once +class IPhysicsShellHolder; +class CPHCharacter; +class IClimableObject +{ +public: +//virtual const Fvector& Axis ()const =0; +virtual float DDAxis (Fvector& dir)const=0; +// +//virtual const Fvector& Side ()const=0; +virtual float DDSide (Fvector& dir)const=0; +// +virtual const Fvector& Norm ()const=0; +virtual float DDNorm (Fvector &dir)const=0; +virtual bool BeforeLadder (CPHCharacter *actor,float tolerance=0.f)const=0; +virtual float DDLowerP (CPHCharacter *actor,Fvector &out_dir)const=0;//returns distance and dir to lover point +virtual float DDUpperP (CPHCharacter *actor,Fvector &out_dir)const=0;//returns distance and dir to upper point +// +//virtual void DToAxis (CPHCharacter *actor,Fvector &dir)const=0; +virtual float DDToAxis (CPHCharacter *actor,Fvector &out_dir)const=0;//returns distance and dir to ladder axis +//virtual void POnAxis (CPHCharacter *actor,Fvector &P)const=0; +// +virtual float AxDistToUpperP (CPHCharacter *actor)const=0; +virtual float AxDistToLowerP (CPHCharacter *actor)const=0; +// +//virtual void DSideToAxis (CPHCharacter *actor,Fvector &dir)const=0; +//virtual float DDSideToAxis (CPHCharacter *actor,Fvector &dir)const=0; +// +virtual void DToPlain (CPHCharacter *actor,Fvector &dist)const=0; +virtual float DDToPlain (CPHCharacter *actor,Fvector &dir)const=0; +//virtual bool InRange (CPHCharacter *actor)const=0; +virtual bool InTouch (CPHCharacter *actor)const=0; +virtual u16 Material ()const=0; +// +//virtual void LowerPoint (Fvector &P)const=0; +//virtual void UpperPoint (Fvector &P)const=0; +//virtual void DefineClimbState (CPHCharacter *actor)const=0; + +virtual IPhysicsShellHolder *cast_IPhysicsShellHolder ()=0; + +protected: + virtual ~IClimableObject() =0 {} +}; \ No newline at end of file diff --git a/xrPhysics/icollisiondamagereceiver.h b/xrPhysics/icollisiondamagereceiver.h new file mode 100644 index 00000000000..f1e08e4444c --- /dev/null +++ b/xrPhysics/icollisiondamagereceiver.h @@ -0,0 +1,15 @@ +#pragma once + +class ICollisionDamageReceiver +{ +public: + + virtual void CollisionHit( u16 source_id, u16 bone_id, float power, const Fvector &dir, Fvector &pos ) =0; +protected: + virtual ~ICollisionDamageReceiver() =0{}; +}; + +struct dContact; +struct SGameMtl; +XRPHYSICS_API void DamageReceiverCollisionCallback (bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2); +XRPHYSICS_API void BreakableObjectCollisionCallback(bool& do_colide,bool bo1,dContact& c,SGameMtl* material_1,SGameMtl* material_2); \ No newline at end of file diff --git a/xrPhysics/iphysics_scripted.h b/xrPhysics/iphysics_scripted.h new file mode 100644 index 00000000000..1e28c2d2d4d --- /dev/null +++ b/xrPhysics/iphysics_scripted.h @@ -0,0 +1,85 @@ +#ifndef _IPHYSICS_SCRIPTED_ +#define _IPHYSICS_SCRIPTED_ + +#pragma once +//#include + + + + +class iphysics_scripted; +class iphysics_game_scripted +{ +public: + virtual ~iphysics_game_scripted () {}; + virtual iphysics_scripted &iphysics_impl () =0; +//protected: +// virtual ~iphysics_game_scripted () =0 {} +}; + +class iphysics_scripted +{ +public: + virtual void set ( iphysics_game_scripted *g ) =0; + virtual iphysics_game_scripted * get () =0; + virtual ~iphysics_scripted () {}; +}; + +class iphysics_scripted_class +{ +public: + //virtual ~iphysics_scripted_class () = 0; + virtual iphysics_scripted &get_scripted () = 0; +protected: +#ifdef _EDITOR + virtual ~iphysics_scripted_class (){} +#else + virtual ~iphysics_scripted_class ()=0{} +#endif +}; + +namespace non_copy +{ + class noncopyable + { + protected: + noncopyable() {} + ~noncopyable() {} + private: // emphasize the following members are private + noncopyable( const noncopyable& ); + const noncopyable& operator=( const noncopyable& ); + }; +}; + +template +class cphysics_game_scripted: + public iphysics_game_scripted, + private non_copy::noncopyable +{ + T &impl; +public: + cphysics_game_scripted ( T* im ):impl(*im){} + virtual ~cphysics_game_scripted () { }; + virtual iphysics_scripted &iphysics_impl () { return impl.get_scripted(); } +protected: + virtual T &physics_impl () { return impl; } + virtual const T &physics_impl () const { return impl; } +public: + typedef T type_impl; +}; + +template< class wrap > +wrap *get_script_wrapper( typename wrap::type_impl &E ) +{ + wrap* e = smart_cast(E.get_scripted().get()); + if( e ) + return e; + + e = xr_new( &E ); + E.get_scripted().set( e ); + + VERIFY( smart_cast(E.get_scripted().get()) == e ); + + return e; +} +#endif diff --git a/xrPhysics/matrix_utils.h b/xrPhysics/matrix_utils.h new file mode 100644 index 00000000000..59f66becfa0 --- /dev/null +++ b/xrPhysics/matrix_utils.h @@ -0,0 +1,101 @@ +#pragma once +IC float clamp_rotation( Fquaternion &q, float v ) +{ + float angl;Fvector ax; + q.get_axis_angle( ax, angl ); + float abs_angl = _abs( angl ); + if( abs_angl > v ) + { + if( angl < 0.f ) v = -v; + q.rotation( ax, v ); + q.normalize( ); + } + return abs_angl; +} + +IC float clamp_rotation( Fmatrix &m, float v ) +{ + Fquaternion q; + q.set(m); + float r = clamp_rotation( q, v ); + Fvector c = m.c; + m.rotation( q ); + m.c = c; + return r; +} + +IC void get_axis_angle( const Fmatrix &m, Fvector &ax, float &angl ) +{ + Fquaternion q; + q.set( m ); + q.get_axis_angle( ax, angl ); +} + +IC bool clamp_change( Fmatrix& m, const Fmatrix &start, float ml, float ma, float tl, float ta ) +{ + Fmatrix diff; diff.mul_43( Fmatrix( ).invert( start ), m ); + float linear_ch = diff.c.magnitude( ); + bool ret = linear_ch < tl; + + if( linear_ch > ml ) + diff.c.mul( ml/linear_ch ); + + if( clamp_rotation( diff, ma ) > ta ) + ret = false; + + if(!ret) + m.mul_43( start, diff ); + return ret; +} + +IC void get_diff_value( const Fmatrix & m0, const Fmatrix &m1, float &l, float &a ) +{ + Fmatrix diff; diff.mul_43( Fmatrix( ).invert( m1 ), m0 ); + l = diff.c.magnitude( ); + Fvector ax; + get_axis_angle( diff, ax, a ); + a = _abs( a ); +} + +IC void cmp_matrix( bool &eq_linear, bool &eq_angular, const Fmatrix &m0, const Fmatrix &m1, float tl, float ta ) +{ + float l,a; + get_diff_value( m0, m1, l, a ); + eq_linear = l < tl; eq_angular = a < ta; +} + +IC bool cmp_matrix( const Fmatrix &m0, const Fmatrix &m1, float tl, float ta ) +{ + bool l =false, a =false; + cmp_matrix( l, a, m0, m1, tl, ta ); + return l && a; +} + +IC void angular_diff( Fvector &aw, const Fmatrix &diff, float dt ) +{ + aw.set( ( diff._32-diff._23 )/2.f/dt, + ( diff._13-diff._31 )/2.f/dt, + ( diff._21-diff._12 )/2.f/dt + ); +} + +IC void linear_diff( Fvector &lv, const Fvector &diff, float dt ) +{ + lv.mul( diff, (1.f/dt) ); +} + +IC void linear_diff( Fvector &lv, const Fvector &mc1, const Fvector &mc0, float dt ) +{ + linear_diff( lv, Fvector().sub( mc1, mc0 ), dt ); +} + +IC void matrix_diff( Fvector &lv, Fvector &aw, const Fmatrix &diff, float dt ) +{ + angular_diff( aw, diff, dt ); + linear_diff( lv, diff.c, dt ); +} + +IC void matrix_diff( Fvector &lv, Fvector &aw, const Fmatrix &m0, const Fmatrix &m1, float dt ) +{ + matrix_diff( lv, aw, Fmatrix().mul_43( Fmatrix().invert( m0 ), m1 ), dt ); +} \ No newline at end of file diff --git a/xrPhysics/ode_include.h b/xrPhysics/ode_include.h new file mode 100644 index 00000000000..b9b4cedc121 --- /dev/null +++ b/xrPhysics/ode_include.h @@ -0,0 +1,9 @@ +#ifndef dSINGLE + #define dSINGLE +#endif +#pragma warning(disable:4995) +#pragma warning(disable:4267) +#include "../3rd party/ode/include/ode/ode.h" +#pragma warning(default:4995) +#pragma warning(default:4267) +#include "ode_redefine.h" \ No newline at end of file diff --git a/xrPhysics/ode_redefine.h b/xrPhysics/ode_redefine.h new file mode 100644 index 00000000000..13407a17fd1 --- /dev/null +++ b/xrPhysics/ode_redefine.h @@ -0,0 +1,33 @@ +#ifndef ODE_REDEFINE +#define ODE_REDEFINE + +#ifdef XRPHYSICS_EXPORTS + +#ifdef dSqrt +#undef dSqrt +#define dSqrt(x) ((float)_sqrt(x)) /* square root */ +#endif + +#ifdef dRecipSqrt +#undef dRecipSqrt +#define dRecipSqrt(x) ((float)(1.0f/_sqrt(x))) /* reciprocal square root */ +#endif + +#ifdef dSin +#undef dSin +#define dSin(x) ((float)_sin(x)) /* sine */ +#endif + +#ifdef dCos +#undef dCos +#define dCos(x) ((float)_cos(x)) /* cosine */ +#endif + +#ifdef dFabs +#undef dFabs +#define dFabs(x) ((float)_abs(x)) /* absolute value */ +#endif + +#endif//XRGAME_EXPORTS + +#endif//ODE_REDEFINE \ No newline at end of file diff --git a/xrPhysics/params.cpp b/xrPhysics/params.cpp new file mode 100644 index 00000000000..6332b15a82b --- /dev/null +++ b/xrPhysics/params.cpp @@ -0,0 +1,14 @@ +#include "stdafx.h" + +#include "params.h" +float object_damage_factor = 1.f ; //times increace damage from object collision +void LoadParams() +{ + if(!pSettings) + return; + + //collide_volume_min=pSettings->r_float("sound","snd_collide_min_volume"); + //collide_volume_max=pSettings->r_float("sound","snd_collide_max_volume"); + object_damage_factor=pSettings->r_float("physics","object_damage_factor"); + object_damage_factor*=object_damage_factor; +} \ No newline at end of file diff --git a/xrPhysics/params.h b/xrPhysics/params.h new file mode 100644 index 00000000000..1edb02ca8c2 --- /dev/null +++ b/xrPhysics/params.h @@ -0,0 +1,8 @@ +#pragma once + + +extern float object_damage_factor; + +void LoadParams(); + + diff --git a/xrPhysics/ph_valid_ode.h b/xrPhysics/ph_valid_ode.h new file mode 100644 index 00000000000..ee67a1f1fd0 --- /dev/null +++ b/xrPhysics/ph_valid_ode.h @@ -0,0 +1,43 @@ +#pragma once + +//#include "ode_include.h" +#include "../3rd party/ode/include/ode/common.h" +#include "../3rd party/ode/include/ode/mass.h" +#include "../3rd party/ode/include/ode/objects.h" +IC BOOL dV_valid (const dReal * v) +{ + return _valid(v[0])&&_valid(v[1])&&_valid(v[2]); +} + +IC BOOL dM_valid (const dReal* m) +{ + return _valid(m[0])&&_valid(m[1])&&_valid(m[2])&& + _valid(m[4])&&_valid(m[5])&&_valid(m[6])&& + _valid(m[8])&&_valid(m[9])&&_valid(m[10]); +} + +IC BOOL dV4_valid (const dReal* v4) +{ + return _valid(v4[0])&&_valid(v4[1])&& + _valid(v4[2])&&_valid(v4[3]); +} +IC BOOL dQ_valid (const dReal* q) +{ + return dV4_valid(q); +} +IC BOOL dMass_valide(const dMass* m) +{ + return _valid(m->mass)&& + dV_valid(m->c)&& + dM_valid(m->I); +} +IC BOOL dBodyStateValide(const dBodyID body) +{ + return dM_valid(dBodyGetRotation(body)) && + dV_valid(dBodyGetPosition(body))&& + dV_valid(dBodyGetLinearVel(body))&& + dV_valid(dBodyGetAngularVel(body))&& + dV_valid(dBodyGetTorque(body))&& + dV_valid(dBodyGetForce(body)) + ; +} \ No newline at end of file diff --git a/xrPhysics/phvalide.cpp b/xrPhysics/phvalide.cpp new file mode 100644 index 00000000000..b8e4d89949d --- /dev/null +++ b/xrPhysics/phvalide.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" + +#include "phvalide.h" +#include "mathutils.h" +#include "iphysicsshellholder.h" +//#include "objectdump.h" + + +extern Fbox phBoundaries; + +bool valid_pos( const Fvector &P ) +{ + return valid_pos( P, phBoundaries ); +} +const Fbox &ph_boundaries() +{ + return phBoundaries; +} +/* + Msg(" %s \n", msg);\ + Msg(" pos: %e,%e,%e, seems to be invalid", pos.x,pos.y,pos.z);\ + Msg("Level box: %e,%e,%e-%e,%e,%e,",bounds.x1,bounds.y1,bounds.z1,bounds.x2,bounds.y2,bounds.z2);\ + Msg("Object: %s",(obj->cName().c_str()));\ + Msg("Visual: %s",(obj->cNameVisual().c_str()));\ +*/ + + +#ifdef DEBUG +std::string dbg_valide_pos_string( const Fvector &pos,const Fbox &bounds, const IPhysicsShellHolder *obj, LPCSTR msg ) +{ + return std::string( msg ) + + make_string( "\n pos: %s , seems to be invalid ", get_string( pos ).c_str() ) + + make_string( "\n Level box: %s ", get_string( bounds ).c_str() ) + + std::string( "\n object dump: \n" ) + + ( obj ? obj->dump( full ) : std::string("") ); +} +std::string dbg_valide_pos_string( const Fvector &pos, const IPhysicsShellHolder *obj, LPCSTR msg ) +{ + return dbg_valide_pos_string( pos, phBoundaries, obj, msg ); +} +#endif diff --git a/xrPhysics/phvalide.h b/xrPhysics/phvalide.h new file mode 100644 index 00000000000..5dd93f0729c --- /dev/null +++ b/xrPhysics/phvalide.h @@ -0,0 +1,18 @@ +#pragma once + + +XRPHYSICS_API bool valid_pos( const Fvector &P ); +XRPHYSICS_API const Fbox &ph_boundaries(); +#ifdef DEBUG +class IPhysicsShellHolder; +XRPHYSICS_API std::string dbg_valide_pos_string( const Fvector &pos,const Fbox &bounds, const IPhysicsShellHolder *obj, LPCSTR msg ); +XRPHYSICS_API std::string dbg_valide_pos_string( const Fvector &pos, const IPhysicsShellHolder *obj, LPCSTR msg ); + +#define VERIFY_BOUNDARIES2(pos,bounds,obj,msg) VERIFY2( valid_pos( pos, bounds ), dbg_valide_pos_string( pos, bounds, obj, msg ) ) +#define VERIFY_BOUNDARIES(pos,bounds,obj) VERIFY_BOUNDARIES2(pos,bounds,obj," ") + +#else +#define VERIFY_BOUNDARIES(pos,bounds,obj) +#define VERIFY_BOUNDARIES2(pos,bounds,obj,msg) +#endif + diff --git a/xrPhysics/physics_scripted.cpp b/xrPhysics/physics_scripted.cpp new file mode 100644 index 00000000000..9c7bc43367e --- /dev/null +++ b/xrPhysics/physics_scripted.cpp @@ -0,0 +1,16 @@ +#include "stdafx.h" + +#include "physics_scripted.h" + +cphysics_scripted:: ~cphysics_scripted() +{ + xr_delete( m_game_scripted ); +} + +void cphysics_scripted::set( iphysics_game_scripted *g ) +{ + R_ASSERT( g ); + R_ASSERT( !m_game_scripted ); + R_ASSERT ( &(g->iphysics_impl()) == this ) ; + m_game_scripted = g; +} \ No newline at end of file diff --git a/xrPhysics/physics_scripted.h b/xrPhysics/physics_scripted.h new file mode 100644 index 00000000000..914a0bbca70 --- /dev/null +++ b/xrPhysics/physics_scripted.h @@ -0,0 +1,14 @@ +#pragma once + +#include "iphysics_scripted.h" + +class cphysics_scripted: + public iphysics_scripted +{ + iphysics_game_scripted *m_game_scripted; + public: + cphysics_scripted ():m_game_scripted(0){} + virtual ~cphysics_scripted (); + virtual void set ( iphysics_game_scripted *g ); + virtual iphysics_game_scripted * get (){ return m_game_scripted; }; +}; \ No newline at end of file diff --git a/xrPhysics/stdafx.cpp b/xrPhysics/stdafx.cpp new file mode 100644 index 00000000000..2ed840ff924 --- /dev/null +++ b/xrPhysics/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// xrPhysics.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/xrPhysics/stdafx.h b/xrPhysics/stdafx.h new file mode 100644 index 00000000000..37e1696bb39 --- /dev/null +++ b/xrPhysics/stdafx.h @@ -0,0 +1,40 @@ + +#pragma once + +#define MTL_EXPORT_API +#define ENGINE_API +#define DLL_API +#define ECORE_API +//#include "../xrEngine/stdafx.h" + +#include "../xrCore/xrCore.h" + +#include "../xrServerEntities/smart_cast.h" +//#include "../xrEngine/pure.h" +//#include "../xrEngine/engineapi.h" +//#include "../xrEngine/eventapi.h" + + +#include "../xrcdb/xrcdb.h" +#include "../xrsound/sound.h" +//#include "../xrengine/IGame_Level.h" + +#pragma comment( lib, "xrCore.lib" ) + +#include "xrPhysics.h" + +#include "../include/xrapi/xrapi.h" +#ifdef DEBUG +#include "d3d9types.h" +#endif +//IC IGame_Level &GLevel() +//{ +// VERIFY( g_pGameLevel ); +// return *g_pGameLevel; +//} +class CGameMtlLibrary; +IC CGameMtlLibrary &GMLibrary() +{ + VERIFY(PGMLib); + return *PGMLib; +} \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/TriPrimitiveCollideClassDef.h b/xrPhysics/tri-colliderknoopc/TriPrimitiveCollideClassDef.h new file mode 100644 index 00000000000..63417d94d49 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/TriPrimitiveCollideClassDef.h @@ -0,0 +1,51 @@ +#ifndef TRI_PRIMITIVE_COLIDE_CLASS_DEF +#define TRI_PRIMITIVE_COLIDE_CLASS_DEF + +#define TRI_PRIMITIVE_COLIDE_CLASS_DECLARE(primitive) \ +class primitive##Tri\ +{\ + dcTriListCollider &m_tri_list ;\ + primitive##Tri& operator = (primitive##Tri& nx_nado) {;} \ +public:\ + explicit primitive##Tri (dcTriListCollider &tri_list):m_tri_list(tri_list) {};\ + IC float Proj (dxGeom* o,const dReal* normal);\ + IC int Collide(\ + const dReal* v0,const dReal* v1,const dReal* v2,\ + Triangle* T,\ + dxGeom *o1,dxGeom *o2,\ + int flags, dContactGeom *contact, int skip\ + );\ + IC int CollidePlain(\ + const dReal* triSideAx0,const dReal* triSideAx1,\ + const dReal* triAx,\ + CDB::TRI* T,\ + dReal dist,\ + dxGeom *o1, dxGeom *o2,\ + int flags, dContactGeom *contact, int skip\ + );\ +\ +}; + + +#define TRI_PRIMITIVE_COLIDE_CLASS_IMPLEMENT(primitive) \ + IC float dcTriListCollider::primitive##Tri:: Proj (dxGeom* o,const dReal* normal){return m_tri_list.d##primitive##Proj(o,normal);}\ + IC int dcTriListCollider::primitive##Tri:: Collide(\ + const dReal* v0,const dReal* v1,const dReal* v2,\ + Triangle* T,\ + dxGeom *o1,dxGeom *o2,\ + int flags, dContactGeom *contact, int skip\ + ){\ + return m_tri_list.dTri##primitive(v0,v1,v2,T,o1,o2,flags,contact,skip);\ + }\ + IC int dcTriListCollider::primitive##Tri::CollidePlain(\ + const dReal* triSideAx0,const dReal* triSideAx1,\ + const dReal* triAx,\ + CDB::TRI* T,\ + dReal dist,\ + dxGeom *o1, dxGeom *o2,\ + int flags, dContactGeom *contact, int skip\ + )\ + {\ + return m_tri_list.dSortedTri##primitive(triSideAx0,triSideAx1,triAx,T,dist,o1,o2,flags,contact,skip);\ + } +#endif \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/__aabb_tri.h b/xrPhysics/tri-colliderknoopc/__aabb_tri.h new file mode 100644 index 00000000000..421b700cdc7 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/__aabb_tri.h @@ -0,0 +1,329 @@ +#pragma once + + class Point + { + public: + + //! Empty constructor + IC Point() {} + //! Constructor from floats + IC Point(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} + //! Constructor from array + IC Point(float f[3]) : x(f[0]), y(f[1]), z(f[2]) {} + //! Constructor from array + IC Point(const float f[3]) : x(f[0]), y(f[1]), z(f[2]) {} + //! Copy constructor + IC Point(const Point& p) : x(p.x), y(p.y), z(p.z) {} + //! Destructor + IC ~Point() {} + + //! Returns MIN(x, y, z); + //IC float Min() const { return MIN(x, MIN(y, z)); } + //! Returns MAX(x, y, z); + //IC float Max() const { return MAX(x, MAX(y, z)); } + //! TO BE DOCUMENTED + //IC Point& Min(const Point& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); return *this; } + //! TO BE DOCUMENTED + //IC Point& Max(const Point& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); return *this; } + + //! Computes square magnitude + IC float SquareMagnitude() const { return x*x + y*y + z*z; } + //! Computes magnitude + IC float Magnitude() const { return _sqrt(x*x + y*y + z*z); } + + //! Return largest axis + IC u32 LargestAxis() const + { + const float* Vals = &x; + u32 m = 0; + if(Vals[1] > Vals[m]) m = 1; + if(Vals[2] > Vals[m]) m = 2; + return m; + } + + // Arithmetic operators + //! Operator for Point Negate = - Point + ICF Point operator-() const { return Point(-x, -y, -z); } + + //! Operator for Point Plus = Point + Point. + ICF Point operator+(const Point& p) const { return Point(x + p.x, y + p.y, z + p.z); } + //! Operator for Point Minus = Point - Point. + ICF Point operator-(const Point& p) const { return Point(x - p.x, y - p.y, z - p.z); } + //! Operator for Point Scale = Point * float. + ICF Point operator*(float s) const { return Point(x * s, y * s, z * s ); } + //! Operator for Point Scale = float * Point. + friend Point operator*(float s, const Point& p) { return Point(s * p.x, s * p.y, s * p.z); } + //! Operator for Point Scale = Point / float. + ICF Point operator/(float s) const { s = 1.0f / s; return Point(x * s, y * s, z * s); } + + //! Operator for float DotProd = Point | Point. + ICF float operator|(const Point& p) const { return x*p.x + y*p.y + z*p.z; } + //! Operator for Point VecProd = Point ^ Point. + ICF Point operator^(const Point& p) const + { + return Point( + y * p.z - z * p.y, + z * p.x - x * p.z, + x * p.y - y * p.x ); + } + + //! Operator for Point += Point. + ICF Point& operator+=(const Point& p) { x += p.x; y += p.y; z += p.z; return *this; } + //! Operator for Point += float. + ICF Point& operator+=(float s) { x += s; y += s; z += s; return *this; } + + //! Operator for Point -= Point. + ICF Point& operator-=(const Point& p) { x -= p.x; y -= p.y; z -= p.z; return *this; } + //! Operator for Point -= float. + ICF Point& operator-=(float s) { x -= s; y -= s; z -= s; return *this; } + //! Operator for Point *= float. + ICF Point& operator*=(float s) { x *= s; y *= s; z *= s; return *this; } + //! Operator for Point /= float. + ICF Point& operator/=(float s) { s = 1.0f/s; x *= s; y *= s; z *= s; return *this; } + + // Arithmetic operators + //! Operator for Point Mul = Point * Matrix3x3. + // Point operator*(const Matrix3x3& mat) const; + //! Operator for Point Mul = Point * Matrix4x4. + // Point operator*(const Matrix4x4& mat) const; + //! Operator for Point *= Matrix3x3. + /// Point& operator*=(const Matrix3x3& mat); + //! Operator for Point *= Matrix4x4. + // Point& operator*=(const Matrix4x4& mat); + + //! Access as array + ICF operator const float*() const { return &x; } + //! Access as array + ICF operator float*() { return &x; } + + public: + float x; //!< x coordinate + float y; //!< y coordinate + float z; //!< z coordinate + }; +//using namespace CDB; +using namespace Opcode; +//typedef float* Point; +//typedef dVector3 Point +//! This macro quickly finds the min & max values among 3 variables +#define FINDMINMAX(x0, x1, x2, min, max) \ + min = max = x0; \ + if(x1max) max=x1; \ + if(x2max) max=x2; + +#define EXITMINMAX(x0, x1, x2, min, max) \ + if(x0max&&x1>max&&x2>max)return false; + +//! TO BE DOCUMENTED +ICF bool planeBoxOverlap_slow(const Point& normal, const float d, const Point& maxbox) +{ + Point vmin, vmax; + if(normal[0]>0.0f) { vmin[0] =-maxbox[0]; vmax[0]= maxbox[0]; } + else { vmin[0] = maxbox[0]; vmax[0]=-maxbox[0]; } + if(normal[1]>0.0f) { vmin[1] =-maxbox[1]; vmax[1]= maxbox[1]; } + else { vmin[1] = maxbox[1]; vmax[1]=-maxbox[1]; } + if(normal[2]>0.0f) { vmin[2] =-maxbox[2]; vmax[2]= maxbox[2]; } + else { vmin[2] = maxbox[2]; vmax[2]=-maxbox[2]; } + if((normal|vmin)+d >= 0.0f) return false; + if((normal|vmax)+d > 0.0f) return true; + return false ; +} + +ICF bool planeBoxOverlap(const Point& normal, const float d, const Point& maxbox) +{ + float norm_box_proj=_abs(maxbox.x*normal.x)+_abs(maxbox.y*normal.y)+_abs(maxbox.z*normal.z); + if(d>-norm_box_proj&&dmax) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.y + fb * extents.z; \ + if(min>rad || max<-rad) return false; + +//! TO BE DOCUMENTED +#define AXISTEST_X2(a, b, fa, fb) \ + min = a*v0.y - b*v0.z; \ + max = a*v1.y - b*v1.z; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.y + fb * extents.z; \ + if(min>rad || max<-rad) return false; + +//! TO BE DOCUMENTED +#define AXISTEST_Y02(a, b, fa, fb) \ + min = b*v0.z - a*v0.x; \ + max = b*v2.z - a*v2.x; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.z; \ + if(min>rad || max<-rad) return false; + +//! TO BE DOCUMENTED +#define AXISTEST_Y1(a, b, fa, fb) \ + min = b*v0.z - a*v0.x; \ + max = b*v1.z - a*v1.x; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.z; \ + if(min>rad || max<-rad) return false; + +//! TO BE DOCUMENTED +#define AXISTEST_Z12(a, b, fa, fb) \ + min = a*v1.x - b*v1.y; \ + max = a*v2.x - b*v2.y; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.y; \ + if(min>rad || max<-rad) return false; + +//! TO BE DOCUMENTED +#define AXISTEST_Z0(a, b, fa, fb) \ + min = a*v0.x - b*v0.y; \ + max = a*v1.x - b*v1.y; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.y; \ + if(min>rad || max<-rad) return false; + + + +IC bool aabb_tri_aabb(Point center,Point extents,const Point* mLeafVerts) +{ + Point v0, v1, v2; + //Fvector v0,v1,v2; + v0.x = mLeafVerts[0].x - center.x; + v1.x = mLeafVerts[1].x - center.x; + v2.x = mLeafVerts[2].x - center.x; + + // First, test overlap in the {x,y,z}-directions + //float min,max; + // Find min, max of the triangle in x-direction, and test for overlap in X + //FINDMINMAX(v0.x, v1.x, v2.x, min, max); + //if(min>extents.x || max<-extents.x) return false; + EXITMINMAX(v0.x, v1.x, v2.x,-extents.x,extents.x) + // Same for Y + v0.y = mLeafVerts[0].y - center.y; + v1.y = mLeafVerts[1].y - center.y; + v2.y = mLeafVerts[2].y - center.y; + + //FINDMINMAX(v0.y, v1.y, v2.y, min, max); + //if(min>extents.y || max<-extents.y) return false; + EXITMINMAX(v0.y, v1.y, v2.y,-extents.y,extents.y) + // Same for Z + v0.z = mLeafVerts[0].z - center.z; + v1.z = mLeafVerts[1].z - center.z; + v2.z = mLeafVerts[2].z - center.z; + + //FINDMINMAX(v0.z, v1.z, v2.z, min, max); + //if(min>extents.z || max<-extents.z) return false; + EXITMINMAX(v0.z, v1.z, v2.z,-extents.z,extents.z) + // 2) Test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + // ### could be precomputed since we use the same leaf triangle several times + const Point e0 = v1 - v0; + const Point e1 = v2 - v1; + const Point normal = e0 ^ e1; + const float d = -normal|v0; + bool r0 = planeBoxOverlap(normal, d, extents); + +#ifdef DEBUG + if (r0 != planeBoxOverlap_slow(normal, d, extents)) + { + Msg("planeBoxOverlap != planeBoxOverlap_slow"); + Msg("normal %f,%f,%f", normal.x,normal.y,normal.z); + Msg("dist %f",d); + Msg("extents %f,%f,%f", extents.x,extents.y,extents.z); + } +#endif + if(!r0) return false; + return true; +} +IC bool __aabb_tri (Point center,Point extents,const Point* mLeafVerts) + { + // move everything so that the boxcenter is in (0,0,0) + Point v0, v1, v2; + //Fvector v0,v1,v2; + v0.x = mLeafVerts[0].x - center.x; + v1.x = mLeafVerts[1].x - center.x; + v2.x = mLeafVerts[2].x - center.x; + + // First, test overlap in the {x,y,z}-directions + float min,max; + // Find min, max of the triangle in x-direction, and test for overlap in X + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if(min>extents.x || max<-extents.x) return false; + + // Same for Y + v0.y = mLeafVerts[0].y - center.y; + v1.y = mLeafVerts[1].y - center.y; + v2.y = mLeafVerts[2].y - center.y; + + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if(min>extents.y || max<-extents.y) return false; + + // Same for Z + v0.z = mLeafVerts[0].z - center.z; + v1.z = mLeafVerts[1].z - center.z; + v2.z = mLeafVerts[2].z - center.z; + + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if(min>extents.z || max<-extents.z) return false; + + // 2) Test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + // ### could be precomputed since we use the same leaf triangle several times + const Point e0 = v1 - v0; + const Point e1 = v2 - v1; + const Point normal = e0 ^ e1; + const float d = -normal|v0; + bool r0 = planeBoxOverlap(normal, d, extents); +#ifdef DEBUG + if (r0 != planeBoxOverlap_slow(normal, d, extents)) + { + Msg("planeBoxOverlap != planeBoxOverlap_slow"); + Msg("normal %f,%f,%f", normal.x,normal.y,normal.z); + Msg("dist %f",d); + Msg("extents %f,%f,%f", extents.x,extents.y,extents.z); + } +#endif + if (!r0) return false; + + // 3) "Class III" tests + //if(bClass3) + { + float rad; + float min, max; + // compute triangle edges + // - edges lazy evaluated to take advantage of early exits + // - fabs precomputed (half less work, possible since extents are always >0) + // - customized macros to take advantage of the null component + // - axis vector3 discarded, possibly saves useless movs + + const float fey0 = _abs(e0.y); + const float fez0 = _abs(e0.z); + AXISTEST_X01(e0.z, e0.y, fez0, fey0); + const float fex0 = _abs(e0.x); + AXISTEST_Y02(e0.z, e0.x, fez0, fex0); + AXISTEST_Z12(e0.y, e0.x, fey0, fex0); + + const float fey1 = _abs(e1.y); + const float fez1 = _abs(e1.z); + AXISTEST_X01(e1.z, e1.y, fez1, fey1); + const float fex1 = _abs(e1.x); + AXISTEST_Y02(e1.z, e1.x, fez1, fex1); + AXISTEST_Z0(e1.y, e1.x, fey1, fex1); + + const Point e2 = mLeafVerts[0] - mLeafVerts[2]; + const float fey2 = _abs(e2.y); + const float fez2 = _abs(e2.z); + AXISTEST_X2(e2.z, e2.y, fez2, fey2); + const float fex2 = _abs(e2.x); + AXISTEST_Y1(e2.z, e2.x, fez2, fex2); + AXISTEST_Z12(e2.y, e2.x, fey2, fex2); + } + return true; + } + + diff --git a/xrPhysics/tri-colliderknoopc/dSortTriPrimitive.cpp b/xrPhysics/tri-colliderknoopc/dSortTriPrimitive.cpp new file mode 100644 index 00000000000..c4364afc9b1 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dSortTriPrimitive.cpp @@ -0,0 +1,2 @@ +#include "stdafx.h" +//#include "dSortTriPrimitive.h" diff --git a/xrPhysics/tri-colliderknoopc/dSortTriPrimitive.h b/xrPhysics/tri-colliderknoopc/dSortTriPrimitive.h new file mode 100644 index 00000000000..a2b48955080 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dSortTriPrimitive.h @@ -0,0 +1,443 @@ +#ifndef D_SORT_TRI_PRIMITIVE_H +#define D_SORT_TRI_PRIMITIVE_H +#include "dTriCollideK.h" +#include "dTriColliderCommon.h" +#include "dTriColliderMath.h" +#include "__aabb_tri.h" +#include "../MathUtils.h" +#include "../console_vars.h" +#include "../phworld.h" +#include "../../xrcdb/xr_area.h" +#include "../../xrEngine/gamemtllib.h" +#ifdef DEBUG +#include "../debug_output.h" +#endif + +IC bool negative_tri_set_ignored_by_positive_tri(const Triangle &neg_tri, const Triangle &pos_tri, const Fvector* V_array ) +{ + + bool common0 = neg_tri.T->verts[0] == pos_tri.T->verts[0] || + neg_tri.T->verts[0] == pos_tri.T->verts[1] || + neg_tri.T->verts[0] == pos_tri.T->verts[2] ; + + bool common1 = neg_tri.T->verts[1] == pos_tri.T->verts[0] || + neg_tri.T->verts[1] == pos_tri.T->verts[1] || + neg_tri.T->verts[1] == pos_tri.T->verts[2] ; + + bool common2 = neg_tri.T->verts[2] == pos_tri.T->verts[0] || + neg_tri.T->verts[2] == pos_tri.T->verts[1] || + neg_tri.T->verts[2] == pos_tri.T->verts[2] ; + + return (common0 && common1 && common2 ) || + !common0 && !( dDOT( neg_tri.norm,(dReal*)&V_array[pos_tri.T->verts[0]] ) > neg_tri.pos )|| + !common1 && !( dDOT( neg_tri.norm,(dReal*)&V_array[pos_tri.T->verts[1]] ) > neg_tri.pos )|| + !common2 && !( dDOT( neg_tri.norm,(dReal*)&V_array[pos_tri.T->verts[2]] ) > neg_tri.pos ); + + +} + +int SetBackTrajectoryCnt(const dReal* p,const dReal*last_pos,Triangle &neg_tri, dxGeom *o1, dxGeom *o2, dContactGeom* Contacts ) +{ + + + + Contacts->g1 = const_cast (o2); + Contacts->g2 = const_cast (o1); + Contacts->normal[0] = -(last_pos[0]-p[0]); + Contacts->normal[1] = -(last_pos[1]-p[1]); + Contacts->normal[2] = -(last_pos[2]-p[2]); + + dReal sq_mag = dDOT(Contacts->normal,Contacts->normal); + if(sq_magnormal[0] = 0; + Contacts->normal[1] = -1; + Contacts->normal[2] = 0; + Contacts->depth = 0.f; + } else + { + Contacts->depth = dSqrt( sq_mag );//neg_tri.depth;// + dReal r_mag = 1.f/Contacts->depth; + Contacts->normal[0] *= r_mag; + Contacts->normal[1] *= r_mag; + Contacts->normal[2] *= r_mag; + } + + Contacts->pos[0] = p[0]; + Contacts->pos[1] = p[1]; + Contacts->pos[2] = p[2]; + + SURFACE(Contacts,0)->mode=neg_tri.T->material; + + if(dGeomGetUserData(o1)->callback) + dGeomGetUserData(o1)->callback(neg_tri.T,Contacts); + return 1; +} + +template +IC int dcTriListCollider::dSortTriPrimitiveCollide ( + T primitive, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip, + const Fvector& AABB + ) +{ + dxGeomUserData* data=dGeomGetUserData(o1); + dReal* last_pos=data->last_pos; + bool no_last_pos =last_pos[0]==-dInfinity; + const dReal* p=dGeomGetPosition(o1); + + Fbox last_box;last_box.setb(data->last_aabb_pos,data->last_aabb_size); + Fbox box;box.setb(cast_fv(p),AABB); + + //VERIFY( g_pGameLevel ); + CDB::TRI* T_array = inl_ph_world().ObjectSpace().GetStaticTris(); + const Fvector* V_array = inl_ph_world().ObjectSpace().GetStaticVerts(); + if(no_last_pos||!last_box.contains(box)) + { + + Fvector aabb;aabb.set(AABB); + aabb.mul(ph_console::ph_tri_query_ex_aabb_rate); + /////////////////////////////////////////////////////////////////////////////////////////////// + XRC.box_options (0); + //VERIFY( g_pGameLevel ); + XRC.box_query (inl_ph_world().ObjectSpace().GetStaticModel(),cast_fv(p),aabb); + + CDB::RESULT* R_begin = XRC.r_begin() ; + CDB::RESULT* R_end = XRC.r_end() ; +#ifdef DEBUG + + debug_output().dbg_total_saved_tries()-=data->cashed_tries.size(); + debug_output().dbg_new_queries_per_step()++; +#endif + data->cashed_tries .clear_not_free() ; + for (CDB::RESULT* Res=R_begin; Res!=R_end; ++Res) + { + data->cashed_tries.push_back(Res->id); + } +#ifdef DEBUG + debug_output().dbg_total_saved_tries()+=data->cashed_tries.size(); +#endif + data->last_aabb_pos.set(cast_fv(p)); + data->last_aabb_size.set(aabb); + } +#ifdef DEBUG + else + debug_output().dbg_reused_queries_per_step()++; +#endif +/////////////////////////////////////////////////////////////////////////////////////////////// + int ret = 0; + + pos_tries.clear (); + dReal neg_depth=dInfinity,b_neg_depth=dInfinity; + UINT b_count =0 ; + bool intersect = false ; + +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawTriTestAABB)) + debug_output().DBG_DrawAABB(cast_fv(p),AABB,D3DCOLOR_XRGB(0,0,255)); +#endif + + + bool* pushing_neg=&data->pushing_neg; + bool* pushing_b_neg=&data->pushing_b_neg; + bool spushing_neg=*pushing_neg; + bool spushing_b_neg=*pushing_b_neg; + Triangle neg_tri;//=&(data->neg_tri); + Triangle b_neg_tri;//=&(data->b_neg_tri); + bool neg_tri_contains_point = true; + if(*pushing_neg){ + CalculateTri(data->neg_tri,p,neg_tri,V_array); + const dReal* neg_vertices[3]={cast_fp(V_array[neg_tri.T->verts[0]]),cast_fp(V_array[neg_tri.T->verts[1]]),cast_fp(V_array[neg_tri.T->verts[2]])}; + neg_tri_contains_point = TriContainPoint(neg_vertices[0],neg_vertices[1],neg_vertices[2], neg_tri.norm,neg_tri.side0, + neg_tri.side1,p); + bool b_neg_dist = neg_tri.dist<0.f; + if( b_neg_dist || ( !neg_tri_contains_point && !no_last_pos ) ) + { + dReal sidePr=primitive.Proj(o1,neg_tri.norm); + neg_tri.depth=sidePr-neg_tri.dist; + neg_depth=neg_tri.depth; + intersect = true; + } else + { + *pushing_neg=false; + } + +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawSavedTries)) + debug_output().DBG_DrawTri(neg_tri.T,V_array,D3DCOLOR_XRGB(255,0,0)); +#endif + + } + + if(*pushing_b_neg){ + CalculateTri(data->b_neg_tri,p,b_neg_tri,V_array); + if(b_neg_tri.dist<0.f) + { + dReal sidePr=primitive.Proj(o1,b_neg_tri.norm); + b_neg_tri.depth=sidePr-b_neg_tri.dist; + b_neg_depth=b_neg_tri.depth; + } + else + { + *pushing_b_neg=false; + } + +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawSavedTries)) + debug_output().DBG_DrawTri(b_neg_tri.T,V_array,D3DCOLOR_XRGB(0,0,255)); +#endif + + } + + bool b_pushing=*pushing_neg;//||*pushing_b_neg; + gl_cl_tries_state.resize(data->cashed_tries.size(),Flags8().assign(0)); + B=data->cashed_tries.begin(),E=data->cashed_tries.end(); + bool gb_pased = false; + for (I=B; I!=E; ++I) + { +#ifdef DEBUG + debug_output().dbg_saved_tries_for_active_objects()++; +#endif + //if(ignored_tries[I-B])continue; + CDB::TRI* T = T_array + *I; + const Point vertices[3]={Point((dReal*)&V_array[T->verts[0]]),Point((dReal*)&V_array[T->verts[1]]),Point((dReal*)&V_array[T->verts[2]])}; + if(!aabb_tri_aabb(Point(p),Point((float*)&AABB),vertices)) + continue; +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDBgDrawIntersectedTries)) + debug_output().DBG_DrawTri(T,V_array,D3DCOLOR_XRGB(0,255,0)); + debug_output().dbg_tries_num()++; +#endif + Triangle tri; + CalculateTri(T,p,tri,vertices); + if(tri.dist<0.f){ +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDBgDrawNegativeTries)) + debug_output().DBG_DrawTri(T,V_array,D3DCOLOR_XRGB(0,0,255)); +#endif + float last_pos_dist=dDOT(last_pos,tri.norm)- tri.pos ; + if((!(last_pos_dist<0.f))||b_pushing) + if(__aabb_tri(Point(p),Point((float*)&AABB),vertices)) + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDBgDrawTriesChangesSign)) + debug_output().DBG_DrawTri(T,V_array,D3DCOLOR_XRGB(0,255,0)); +#endif + SGameMtl* material=GMLibrary().GetMaterialByIdx(T->material); + VERIFY( material ); + bool b_passable = !!material->Flags.test(SGameMtl::flPassable); + bool contain_pos=TriContainPoint( + vertices[0], + vertices[1], + vertices[2], + tri.norm,tri.side0, + tri.side1,p); + bool b_pased = false; + if(!b_pushing&&!gb_pased) + { + if( !no_last_pos && !b_passable ) + { +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawTriTrace)) + debug_output().DBG_DrawLine(cast_fv(last_pos),cast_fv(p),D3DCOLOR_XRGB(255,0,255)); +#endif + dVector3 tri_point; + PlanePoint(tri,last_pos,p,last_pos_dist,tri_point); +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDbgDrawTriPoint)) + debug_output().DBG_DrawPoint(cast_fv(tri_point),0.01f,D3DCOLOR_XRGB(255,0,255)); +#endif + bool was_intersect = intersect; + intersect=intersect||TriContainPoint( + vertices[0], + vertices[1], + vertices[2], + tri.norm,tri.side0, + tri.side1,tri_point); + b_pased = intersect && !was_intersect; + gb_pased = b_pased || gb_pased; +#ifdef DEBUG + if( b_pased && debug_output().ph_dbg_draw_mask().test(phDbgDrawTriPoint) ) + { + dVectorSet( last_pos, tri_point ); + debug_output().DBG_OpenCashedDraw( ); + debug_output().DBG_DrawPoint( cast_fv(tri_point), 0.01f, D3DCOLOR_XRGB(255,0,255) ); + debug_output().DBG_ClosedCashedDraw( 1000000 ); + } +#endif + } + else + { + if(contain_pos&&primitive.Proj(o1,tri.norm)>-tri.dist) + intersect=true; + } + } + else + { + intersect=true; + } + + if( !b_passable && ( b_pased || + contain_pos && no_last_pos ) + ){ + dReal sidePr=primitive.Proj(o1,tri.norm); + tri.depth=sidePr-tri.dist; + if(neg_depth>tri.depth&&(!(*pushing_neg||spushing_neg)||dDOT(neg_tri.norm,tri.norm)>-M_SQRT1_2)&&(!(*pushing_b_neg||spushing_b_neg)||dDOT(b_neg_tri.norm,tri.norm)>-M_SQRT1_2))//exclude switching on opposite side &&(!*pushing_b_neg||dDOT(b_neg_tri->norm,tri.norm)>-M_SQRT1_2) + { + neg_depth=tri.depth; + neg_tri=tri; + data->neg_tri=tri.T; + //ret=0; + //if(intersect)*pushing_neg=true; + } + + + } + + if(!b_pased && b_passable ){//!contain_pos&& + ++b_count; + dReal sidePr=primitive.Proj(o1,tri.norm); + tri.depth=sidePr-tri.dist; + if(b_neg_depth>tri.depth&&(!(*pushing_b_neg||spushing_b_neg)||dDOT(b_neg_tri.norm,tri.norm)>-M_SQRT1_2)&&((!*pushing_neg||!spushing_neg)||dDOT(neg_tri.norm,tri.norm)>-M_SQRT1_2)){//exclude switching on opposite side &&(!*pushing_neg||dDOT(neg_tri->norm,tri.norm)>-M_SQRT1_2) + b_neg_depth=tri.depth; + b_neg_tri=tri; + data->b_neg_tri=tri.T; + //ret=0; + //if(intersect)*pushing_b_neg=true; + } + } + } + } + else{ +#ifdef DEBUG + if(debug_output().ph_dbg_draw_mask().test(phDBgDrawPositiveTries)) + debug_output().DBG_DrawTri(T,V_array,D3DCOLOR_XRGB(255,0,0)); +#endif + if(ret>flags-10) + continue; + if(!b_pushing&&(!intersect||no_last_pos)) + ret+=primitive.Collide( + vertices[0], + vertices[1], + vertices[2], + &tri, + o1, + o2, + 3, + CONTACT(contact, ret * skip), skip); + if(no_last_pos) + pos_tries.push_back(tri); + } + } + + //if(intersect) ret=0; + xr_vector::iterator i; + + if(intersect) + { + + if(neg_depthT->verts[0]], + (dReal*)&V_array[i->T->verts[1]], + (dReal*)&V_array[i->T->verts[2]], + i->norm,i->side0, + i->side1,p)) + if( + negative_tri_set_ignored_by_positive_tri( neg_tri, *i, V_array ) + ){ + include=false; + break; + } + }; + + if(include){ + VERIFY(neg_tri.T&&neg_tri.dist!=-dInfinity); + //const dReal* neg_vertices[3]={cast_fp(V_array[neg_tri.T->verts[0]]),cast_fp(V_array[neg_tri.T->verts[1]]),cast_fp(V_array[neg_tri.T->verts[2]])}; + //neg_tri_contains_point = TriContainPoint(neg_vertices[0],neg_vertices[1],neg_vertices[2], neg_tri.norm,neg_tri.side0, + //neg_tri.side1,p); + if(neg_tri_contains_point) + { + int bret=primitive.CollidePlain( + neg_tri.side0,neg_tri.side1,neg_tri.norm, + neg_tri.T, + neg_tri.dist, + o1,o2,flags, + CONTACT(contact, 0), + skip); + *pushing_neg=!!bret; + if(*pushing_neg) + ret=bret; + } + else + ret = SetBackTrajectoryCnt(p,last_pos,neg_tri,o1,o2,CONTACT(contact, 0)); + } + + } + + + //for(i=pos_tries.begin();pos_tries.end() != i;++i){ + // CDB::TRI* T=i->T; + // ret+=dTriPrimitive( + // (const dReal*)&V_array[T->verts[0]], + // (const dReal*)&V_array[T->verts[1]], + // (const dReal*)&V_array[T->verts[2]], + // T, + // o1, + // o2, + // 3, + // CONTACT(contact, ret * skip), skip); + + //} + + + + } + + if(b_neg_depth= (int)sizeof(dContactGeom)); + VERIFY (dGeomGetClass(o1) == dBoxClass); + + + + const dReal *R = dGeomGetRotation(o1); + const dReal* p=dGeomGetPosition(o1); + dVector3 hside; + dGeomBoxGetLengths(o1,hside); + hside[0]/=2.f;hside[1]/=2.f;hside[2]/=2.f; + // find number of contacts requested + int maxc = flags & NUMC_MASK; + if (maxc < 1) maxc = 1; + if (maxc > 3) maxc = 3; // no more than 3 contacts per box allowed + + int code=0; + dReal outDepth; + char signum;//,sn; + + + dReal sidePr= + dFabs(dDOT14(triAx,R+0)*hside[0])+ + dFabs(dDOT14(triAx,R+1)*hside[1])+ + dFabs(dDOT14(triAx,R+2)*hside[2]); + + +dReal depth=sidePr-dist;//dFabs(dist); +outDepth=depth; +signum=-1;//dist<0.f ? -1 : 1; +code=0; + +if(depth<0.f) return 0; + +unsigned int i; + +dVector3 norm,pos; +unsigned int ret=1; + +if(code==0){ + norm[0]=triAx[0]*signum; + norm[1]=triAx[1]*signum; + norm[2]=triAx[2]*signum; + +/////////////////////////////////////////// from geom.cpp dCollideBP + dReal Q1 = -signum*dDOT14(triAx,R+0); + dReal Q2 = -signum*dDOT14(triAx,R+1); + dReal Q3 = -signum*dDOT14(triAx,R+2); + dReal A1 = 2.f*hside[0] * Q1; + dReal A2 = 2.f*hside[1] * Q2; + dReal A3 = 2.f*hside[2] * Q3; + dReal B1 = dFabs(A1); + dReal B2 = dFabs(A2); + dReal B3 = dFabs(A3); + + pos[0]=p[0]; + pos[1]=p[1]; + pos[2]=p[2]; + +#define FOO(i,op) \ + pos[0] op hside[i] * R[0+i]; \ + pos[1] op hside[i] * R[4+i]; \ + pos[2] op hside[i] * R[8+i]; +#define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) } + BAR(0,1); + BAR(1,2); + BAR(2,3); +#undef FOO +#undef BAR + +/////////////////////////////////////////////////////////// + + +if (maxc == 1) goto done; + + // get the second and third contact points by starting from `p' and going + // along the two sides with the smallest projected length. + +//(@slipch) it is not perfectly right for triangle collision +//because it need to check if additional points are in the triangle but it seems cause no problem + +#define FOO(i,j,op) \ + CONTACT(contact,i*skip)->pos[0] = pos[0] op 2.f*hside[j] * R[0+j]; \ + CONTACT(contact,i*skip)->pos[1] = pos[1] op 2.f*hside[j] * R[4+j]; \ + CONTACT(contact,i*skip)->pos[2] = pos[2] op 2.f*hside[j] * R[8+j]; +#define BAR(ctact,side,sideinc) \ + depth -= B ## sideinc; \ + if (depth < 0) goto done; \ + if (A ## sideinc > 0) { FOO(ctact,side,+) } else { FOO(ctact,side,-) } \ + CONTACT(contact,ctact*skip)->depth = depth; \ + ++ret; + + CONTACT(contact,skip)->normal[0] = triAx[0]*signum; + CONTACT(contact,skip)->normal[1] = triAx[1]*signum; + CONTACT(contact,skip)->normal[2] = triAx[2]*signum; + if (maxc == 3) { + CONTACT(contact,2*skip)->normal[0] = triAx[0]*signum; + CONTACT(contact,2*skip)->normal[1] = triAx[1]*signum; + CONTACT(contact,2*skip)->normal[2] = triAx[2]*signum; + } + + if (B1 < B2) { + if (B3 < B1) goto use_side_3; else { + BAR(1,0,1); // use side 1 + if (maxc == 2) goto done; + if (B2 < B3) goto contact2_2; else goto contact2_3; + } + } + else { + if (B3 < B2) { + use_side_3: // use side 3 + BAR(1,2,3); + if (maxc == 2) goto done; + if (B1 < B2) goto contact2_1; else goto contact2_2; + } + else { + BAR(1,1,2); // use side 2 + if (maxc == 2) goto done; + if (B1 < B3) goto contact2_1; else goto contact2_3; + } + } + + contact2_1: BAR(2,0,1); goto done; + contact2_2: BAR(2,1,2); goto done; + contact2_3: BAR(2,2,3); goto done; +#undef FOO +#undef BAR + + done: ; + +////////////////////////////////////////////////////////////// end (from geom.cpp dCollideBP) + + } + + +contact->pos[0] = pos[0]; +contact->pos[1] = pos[1]; +contact->pos[2] = pos[2]; + +contact->depth = outDepth; + + for (i=0; ig1 = const_cast (o2); + CONTACT(contact,i*skip)->g2 = const_cast (o1); + CONTACT(contact,i*skip)->normal[0] = norm[0]; + CONTACT(contact,i*skip)->normal[1] = norm[1]; + CONTACT(contact,i*skip)->normal[2] = norm[2]; + SURFACE(contact,i*skip)->mode=T->material; + } + if(ret&&dGeomGetUserData(o1)->callback)dGeomGetUserData(o1)->callback(T,contact); + return ret; + +} + +/* +bool test_cross_side( dReal* outAx, dReal& outDepth, dReal *pos, dReal& outSignum, int &code, u8 c, const dReal* R, const dReal* hside, const dReal* p, const dReal* triSideAx, const dReal* vax, const dReal* vox ) +{ + +for( u8 i=0;i<3;++i){ + dVector3 axis; + dCROSS114(axis,=,triSideAx ,R+i ); + accurate_normalize(axis); + int ix1=(i+1)%3; + int ix2=(i+2)%3; + dReal sidePr= + dFabs(dDOT14(axis,R+ix1)*hside[ix1])+ + dFabs(dDOT14(axis,R+ix2)*hside[ix2]); + + dReal dist_ax=dDOT(vax,axis)-dDOT(p,axis); + dReal dist_ox=dDOT(vox,axis)-dDOT(p,axis); + + bool isPdistax=dist_ax>0.f; + bool isPdistox=dist_ox>0.f; + if(isPdistax != isPdistox) continue; + + dReal depth_ax=sidePr-dFabs(dist_ax); + dReal depth_ox=sidePr-dFabs(dist_ox); + if( depth_ax>depth_ox ){ + if(depth_ax>0.f){ + if(depth_ax*1.05f= (int)sizeof(dContactGeom)); + VERIFY (dGeomGetClass(o1) == dBoxClass); + + + + const dReal *R = dGeomGetRotation(o1); + const dReal* p=dGeomGetPosition(o1); + dVector3 hside; + dGeomBoxGetLengths(o1,hside); + hside[0]/=2.f;hside[1]/=2.f;hside[2]/=2.f; + + // find number of contacts requested + int maxc = flags & NUMC_MASK; + if (maxc < 1) maxc = 1; + if (maxc > 3) maxc = 3; // no more than 3 contacts per box allowed + + //dVector3 triAx; + const dReal* triSideAx0=T->side0;//{v1[0]-v0[0],v1[1]-v0[1],v1[2]-v0[2]}; + const dReal* triSideAx1=T->side1;//{v2[0]-v1[0],v2[1]-v1[1],v2[2]-v1[2]}; + dVector3 triSideAx2={v0[0]-v2[0],v0[1]-v2[1],v0[2]-v2[2]}; + //dCROSS(triAx,=,triSideAx0,triSideAx1); + int code=0; + dReal outDepth; + dReal signum; + //sepparation along tri plane normal; + const dReal *triAx =T->norm; + //accurate_normalize(triAx); + + + dReal sidePr= + dFabs(dDOT14(triAx,R+0)*hside[0])+ + dFabs(dDOT14(triAx,R+1)*hside[1])+ + dFabs(dDOT14(triAx,R+2)*hside[2]); + +dReal dist=-T->dist; +//dist=dDOT(triAx,v0)-dDOT(triAx,p); +dReal depth=sidePr-dFabs(dist); +outDepth=depth; +signum=dist<0.f ? -1.f : 1.f; +code=0; +if(depth<0.f) return 0; + + +bool isPdist0,isPdist1,isPdist2; +bool test0=true,test1=true,test2=true; +bool test00,test01,test02; +bool test10,test11,test12; +bool test20,test21,test22; + +dReal depth0,depth1,depth2; +dReal dist0,dist1,dist2; + + + +#define CMP(sd,c) \ +if(depth0>depth1)\ + if(depth0>depth2) \ + if(test0##sd){\ + if(test0)\ + if(depth0depth2)\ + if(test1##sd){\ + if(test1)\ + if(depth10.f;\ +isPdist1=dist1>0.f;\ +isPdist2=dist2>0.f;\ +\ +depth0=hside[sd]-dFabs(dist0);\ +depth1=hside[sd]-dFabs(dist1);\ +depth2=hside[sd]-dFabs(dist2);\ +test0##sd = depth0>0.f;\ +test1##sd = depth1>0.f;\ +test2##sd = depth2>0.f;\ +\ +test0 =test0 && test0##sd;\ +test1 =test1 && test1##sd;\ +test2 =test2 && test2##sd;\ +\ +if(isPdist0==isPdist1 && isPdist1==isPdist2)\ +{\ +CMP(sd,c)\ +} + +TEST(0,1) +TEST(1,4) +TEST(2,7) + +#undef CMP +#undef TEST + +unsigned int i; + +dVector3 axis,outAx; + +/* +#define TEST(ax,ox,c) \ +for(i=0;i<3;++i){\ + dCROSS114(axis,=,triSideAx##ax,R+i);\ + accurate_normalize(axis);\ + int ix1=(i+1)%3;\ + int ix2=(i+2)%3;\ + sidePr=\ + dFabs(dDOT14(axis,R+ix1)*hside[ix1])+\ + dFabs(dDOT14(axis,R+ix2)*hside[ix2]);\ +\ + dist##ax=(dDOT(v##ax,axis)-dDOT(p,axis));\ + dist##ox=(dDOT(v##ox,axis)-dDOT(p,axis));\ + signum=dist##ox<0.f ? -1.f : 1.f;\ +\ +depth##ax=sidePr-signum*dist##ax;\ +depth##ox=sidePr-signum*dist##ox;\ + if(depth##ax0.f){\ + if(depth##ax0.f;\ +isPdist##ox=dist##ox>0.f;\ +if(isPdist##ax != isPdist##ox) continue;\ +\ +depth##ax=sidePr-dFabs(dist##ax);\ +depth##ox=sidePr-dFabs(dist##ox);\ + if(depth##ax>depth##ox){\ + if(depth##ax>0.f){\ + if(depth##ax*1.05f 0) { FOO(i,-=) } else { FOO(i,+=) } + BAR(0,1); + BAR(1,2); + BAR(2,3); +#undef FOO +#undef BAR + +/////////////////////////////////////////////////////////// + + +#define TRI_CONTAIN_POINT(pos) {\ + dVector3 cross0, cross1, cross2;\ + dReal ds0,ds1,ds2;\ + \ + dCROSS(cross0,=,triAx,triSideAx0);\ + ds0=dDOT(cross0,v0);\ +\ + dCROSS(cross1,=,triAx,triSideAx1);\ + ds1=dDOT(cross1,v1);\ +\ + dCROSS(cross2,=,triAx,triSideAx2);\ + ds2=dDOT(cross2,v2);\ +\ + if(dDOT(cross0,pos)-ds0>0.f && \ + dDOT(cross1,pos)-ds1>0.f && \ + dDOT(cross2,pos)-ds2>0.f) ++ret;\ +} +/////////////////////////////////////////////////////////// + + + // get the second and third contact points by starting from `p' and going + // along the two sides with the smallest projected length. + +dReal* pdepth; +dContactGeom* prc,*c=CONTACT(contact,ret*skip); +prc=c; +#define FOO(j,op,spoint) \ + c->pos[0] = spoint##[0] op 2.f*hside[j] * R[0+j]; \ + c->pos[1] = spoint##[1] op 2.f*hside[j] * R[4+j]; \ + c->pos[2] = spoint##[2] op 2.f*hside[j] * R[8+j]; +#define BAR(side,sideinc,spos,sdepth) \ + {\ + pdepth=&(c->depth);\ + *pdepth =sdepth-B ## sideinc; \ + if (A ## sideinc > 0) { FOO(side,+,spos) } else { FOO(side,-,spos) } \ + prc=c;\ + if (!(*pdepth < 0)) \ + {\ + ++ret;\ + c=CONTACT(contact,ret*skip);\ + }\ + } + //TRI_CONTAIN_POINT(CONTACT(contact,ret*skip)->pos) + + if(B1pos,prc->depth); + + } + else + { + BAR(2,3,pos,depth); + BAR(0,1,prc->pos,prc->depth); + } + } + else + { + BAR(1,2,pos,depth); + if(B1pos,prc->depth); + } + else + { + BAR(2,3,pos,depth); + BAR(1,2,prc->pos,prc->depth); + } + } + /* + + if (B1 < B2) { + if (B3 < B1) goto use_side_3; else { + BAR(0,1,pos); // use side 1 + if (maxc == 2) goto done; + if (B2 < B3) goto contact2_2; else goto contact2_3; + } + } + else { + if (B3 < B2) { + use_side_3: // use side 3 + BAR(2,3,pos); + if (maxc == 2) goto done; + if (B1 < B2) goto contact2_1; else goto contact2_2; + } + else { + BAR(1,2,pos); // use side 2 + if (maxc == 2) goto done; + if (B1 < B3) goto contact2_1; else goto contact2_3; + } + } + + contact2_1: BAR(0,1,pos); goto done; + contact2_2: BAR(1,2,pos); goto done; + contact2_3: BAR(2,3,pos); goto done; +*/ +#undef FOO +#undef FOO1 +#undef BAR +#undef TRI_CONTAIN_POINT + //done: ; + +////////////////////////////////////////////////////////////// end (from geom.cpp dCollideBP) + + } +else + if(code<=9) +{ + switch((code-1)%3){ + case 0: + pos[0]=v0[0]; + pos[1]=v0[1]; + pos[2]=v0[2]; + break; + case 1: + pos[0]=v1[0]; + pos[1]=v1[1]; + pos[2]=v1[2]; + break; + case 2: + pos[0]=v2[0]; + pos[1]=v2[1]; + pos[2]=v2[2]; + break; + } +switch((code-1)/3){ + case 0: + { + norm[0]=R[0]*signum; + norm[1]=R[4]*signum; + norm[2]=R[8]*signum; + } + break; + + case 1: + { + norm[0]=R[1]*signum; + norm[1]=R[5]*signum; + norm[2]=R[9]*signum; + } + break; + case 2: + { + norm[0]=R[2]*signum; + norm[1]=R[6]*signum; + norm[2]=R[10]*signum; + } + break; + } +} +else { + norm[0]=outAx[0]*signum; + norm[1]=outAx[1]*signum; + norm[2]=outAx[2]*signum; + + //pos[0]=crpos[0]; + //pos[1]=crpos[1]; + //pos[2]=crpos[2]; + + +///////////// +/* + dReal Q1 = -signum*dDOT14(outAx,R+0); + dReal Q2 = -signum*dDOT14(outAx,R+1); + dReal Q3 = -signum*dDOT14(outAx,R+2); + dReal A1 = 2.f*hside[0] * Q1; + dReal A2 = 2.f*hside[1] * Q2; + dReal A3 = 2.f*hside[2] * Q3; + pos[0]=p[0]; + pos[1]=p[1]; + pos[2]=p[2]; + +#define FOO(i,op) \ + pos[0] op hside[i] * R[0+i]; \ + pos[1] op hside[i] * R[4+i]; \ + pos[2] op hside[i] * R[8+i]; +#define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) } + BAR(0,1); + BAR(1,2); + BAR(2,3); +#undef FOO +#undef BAR +//////////////// + + +switch((code-10)/3){ + +case 0: + CrossProjLine1(v0,triSideAx0,pos,R+(code-10),pos); + if(pos[0]==dInfinity){ + pos[0]=(v1[0]+v0[0])/2.f; + pos[1]=(v1[1]+v0[1])/2.f; + pos[2]=(v1[2]+v0[2])/2.f; + } +break; + +case 1: + CrossProjLine1(v1,triSideAx1,pos,R+(code-13),pos); + if(pos[0]==dInfinity){ + pos[0]=(v2[0]+v1[0])/2.f; + pos[1]=(v2[1]+v1[1])/2.f; + pos[2]=(v2[2]+v1[2])/2.f; + } +break; + +case 2: + CrossProjLine1(v0,triSideAx2,pos,R+(code-16),pos); + if(pos[0]==dInfinity){ + pos[0]=(v2[0]+v0[0])/2.f; + pos[1]=(v2[1]+v0[1])/2.f; + pos[2]=(v2[2]+v0[2])/2.f; + } + +} +*/ +} + +if(dDOT(norm,triAx)>0.f) return 0; + + +//if(0!=code){ +contact->pos[0] = pos[0]; +contact->pos[1] = pos[1]; +contact->pos[2] = pos[2]; + + +//contact->pos[0] = crossprg[0]; +//contact->pos[1] = crossprg[1]; +//contact->pos[2] = crossprg[2]; + +contact->depth = outDepth; + +//} + for (u32 i=0; ig1 = const_cast (o2); + CONTACT(contact,i*skip)->g2 = const_cast (o1); + CONTACT(contact,i*skip)->normal[0] = norm[0]; + CONTACT(contact,i*skip)->normal[1] = norm[1]; + CONTACT(contact,i*skip)->normal[2] = norm[2]; + SURFACE(contact,i*skip)->mode=T->T->material; + } + if(ret&&dGeomGetUserData(o1)->callback)dGeomGetUserData(o1)->callback(T->T,contact); + return ret; + +} + diff --git a/xrPhysics/tri-colliderknoopc/dTriBox.h b/xrPhysics/tri-colliderknoopc/dTriBox.h new file mode 100644 index 00000000000..9d728e07c27 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriBox.h @@ -0,0 +1,383 @@ +#ifndef D_TRI_BOX_H +#define D_TRI_BOX_H + +#include "TriPrimitiveCollideClassDef.h" +#include "../ode_include.h" +#include "../MathUtilsOde.h" +#include "dcTriListCollider.h" +struct Triangle; +struct dxBox { + dVector3 side; // side lengths (x,y,z) +}; + +IC float dcTriListCollider:: dBoxProj(dxGeom* box,const dReal* normal) +{ + VERIFY (dGeomGetClass(box)== dBoxClass); + float hside[3]; + dGeomBoxGetLengths(box,hside); + hside[0]*=.5f;hside[1]*=0.5f;hside[2]*=0.5f; + const dReal* R=dGeomGetRotation(box); + return + dFabs(dDOT14(normal,R+0)*hside[0])+ + dFabs(dDOT14(normal,R+1)*hside[1])+ + dFabs(dDOT14(normal,R+2)*hside[2]); +} + + + +IC void dcTriListCollider::CrossProjLine(const dReal* pt1,const dReal* vc1,const dReal* pt2,const dReal* vc2,dReal* proj){ + dVector3 ac={pt1[0]-pt2[0],pt1[1]-pt2[1],pt1[2]-pt2[2]}; + dReal factor=(dDOT(vc2,vc2)*dDOT44(vc1,vc1)-dDOT14(vc2,vc1)*dDOT14(vc2,vc1)); + if(factor==0.f){ + proj[0]=dInfinity; + //proj[1]=dInfinity; + //proj[2]=dInfinity; + return; + } + dReal t=(dDOT(ac,vc2)*dDOT41(vc1,vc2)-dDOT41(vc1,ac)*dDOT(vc2,vc2)) + / + factor; + + proj[0]=pt1[0]+vc1[0]*t; + proj[1]=pt1[1]+vc1[4]*t; + proj[2]=pt1[2]+vc1[8]*t; + + +} + +IC void dcTriListCollider::CrossProjLine1(const dReal* pt1,const dReal* vc1,const dReal* pt2,const dReal* vc2,dReal* proj){ + dVector3 ac={pt1[0]-pt2[0],pt1[1]-pt2[1],pt1[2]-pt2[2]}; + dReal factor=(dDOT44(vc2,vc2)*dDOT(vc1,vc1)-dDOT41(vc2,vc1)*dDOT41(vc2,vc1)); + if(factor==0.f){ + proj[0]=dInfinity; + //proj[1]=dInfinity; + //proj[2]=dInfinity; + return; + } + dReal t=(dDOT14(ac,vc2)*dDOT14(vc1,vc2)-dDOT(vc1,ac)*dDOT44(vc2,vc2)) + / + factor; + + proj[0]=pt1[0]+vc1[0]*t; + proj[1]=pt1[1]+vc1[1]*t; + proj[2]=pt1[2]+vc1[2]*t; + + +} + + +IC bool dcTriListCollider:: CrossProjLine14(const dReal* pt1,const dReal* vc1,const dReal* pt2,const dReal* vc2,dReal hside,dReal* proj){ + dVector3 ac={pt1[0]-pt2[0],pt1[1]-pt2[1],pt1[2]-pt2[2]}; + + //dReal vc2_2=dDOT44(vc2,vc2); + dReal vc1_vc2=dDOT41(vc2,vc1); + dReal vc1_2=dDOT(vc1,vc1); + + dReal factor=/*vc2_2*/vc1_2-vc1_vc2*vc1_vc2; + if(factor==0.f){ + //proj[0]=dInfinity; + //proj[1]=dInfinity; + //proj[2]=dInfinity; + return false; + } + dReal ac_vc1=dDOT(vc1,ac); + dReal ac_vc2=dDOT14(ac,vc2); + dReal t1=(ac_vc2*vc1_vc2-ac_vc1/*vc2_2*/) + / + factor; + + if(t1<0.f) return false; + if(t1>1.f) return false; + + dReal t2=(ac_vc1*vc1_vc2-ac_vc2*vc1_2) + /factor; + + dReal nt2=t2;//*_sqrt(vc2_2); + if(nt2>hside || nt2 < -hside) return false; + + proj[0]=pt1[0]+vc1[0]*t1; + proj[1]=pt1[1]+vc1[1]*t1; + proj[2]=pt1[2]+vc1[2]*t1; + + return true; +} +//is point in Box +IC bool dcTriListCollider::IsPtInBx(const dReal* Pt,const dReal* BxP,const dReal* BxEx,const dReal* BxR){ + dVector3 BxPR,PtR; + + dMULTIPLY1_331 (BxPR,BxR,BxP); + dMULTIPLY1_331 (PtR,BxR,Pt); + return + + dFabs(BxPR[0]-PtR[0])0.f + && + (dDOT(fragmentonAx,Pt1)-BxPPr+BxExPr/2.f)* + (dDOT(fragmentonAx,Pt2)-BxPPr+BxExPr/2.f)>0.f + ) return -1.f; + + + dVector3 crossAx0; + dCROSS114(crossAx0,=,fragmentonAx,R+0); + accurate_normalize(crossAx0); + BxExPr= + dFabs(dDOT14(crossAx0,R+0)*BxEx[0])+ + dFabs(dDOT14(crossAx0,R+1)*BxEx[1])+ + dFabs(dDOT14(crossAx0,R+2)*BxEx[2]); + dReal distance0=dDOT(crossAx0,Pt1)-dDOT(crossAx0,BxP); + if(dFabs(distance0)>BxExPr/2.f) return -1.f; + dReal depth0=BxExPr/2.f-dFabs(distance0); + + dVector3 crossAx1; + dCROSS114(crossAx1,=,fragmentonAx,R+1); + accurate_normalize(crossAx1); + BxExPr= + dFabs(dDOT14(crossAx1,R+0)*BxEx[0])+ + dFabs(dDOT14(crossAx1,R+1)*BxEx[1])+ + dFabs(dDOT14(crossAx1,R+2)*BxEx[2]); + dReal distance1=dDOT(crossAx1,Pt1)-dDOT(crossAx1,BxP); + if(dFabs(distance1)>BxExPr/2.f) return -1.f; + dReal depth1=BxExPr/2.f-dFabs(distance1); + + dVector3 crossAx2; + dCROSS114(crossAx2,=,fragmentonAx,R+2); + accurate_normalize(crossAx2); + BxExPr= + dFabs(dDOT14(crossAx2,R+0)*BxEx[0])+ + dFabs(dDOT14(crossAx2,R+1)*BxEx[1])+ + dFabs(dDOT14(crossAx2,R+2)*BxEx[2]); + dReal distance2=dDOT(crossAx2,Pt1)-dDOT(crossAx2,BxP); + if(dFabs(distance2)>BxExPr/2.f) return -1.f; + dReal depth2=BxExPr/2.f-dFabs(distance2); + + + if(depth00.f +&& +(currentDistance+BxExPr/2.f)* +(distance+BxExPr/2.f)>0.f +) return -1.f; + +if(depth<0.f&¤tDepth>=0.f) { +depth=currentDepth; +distance=currentDistance; +} +else +dVector3 crossAx0; +dCROSS114(crossAx0,=,fragmentonAx,R+0); +accurate_normalize(crossAx0); +BxExPr= +dFabs(dDOT14(crossAx0,R+0)*BxEx[0])+ +dFabs(dDOT14(crossAx0,R+1)*BxEx[1])+ +dFabs(dDOT14(crossAx0,R+2)*BxEx[2]); +dReal distance0=dDOT(crossAx0,Pt1)-dDOT(crossAx0,BxP); +if(dFabs(distance0)>BxExPr/2.f) return -1.f; +dReal depth0=BxExPr/2.f-dFabs(distance0); + +dVector3 crossAx1; +dCROSS114(crossAx1,=,fragmentonAx,R+1); +accurate_normalize(crossAx1); +BxExPr= +dFabs(dDOT14(crossAx1,R+0)*BxEx[0])+ +dFabs(dDOT14(crossAx1,R+1)*BxEx[1])+ +dFabs(dDOT14(crossAx1,R+2)*BxEx[2]); +dReal distance1=dDOT(crossAx1,Pt1)-dDOT(crossAx1,BxP); +if(dFabs(distance1)>BxExPr/2.f) return -1.f; +dReal depth1=BxExPr/2.f-dFabs(distance1); + +dVector3 crossAx2; +dCROSS114(crossAx2,=,fragmentonAx,R+2); +accurate_normalize(crossAx2); +BxExPr= +dFabs(dDOT14(crossAx2,R+0)*BxEx[0])+ +dFabs(dDOT14(crossAx2,R+1)*BxEx[1])+ +dFabs(dDOT14(crossAx2,R+2)*BxEx[2]); +dReal distance2=dDOT(crossAx2,Pt1)-dDOT(crossAx2,BxP); +if(dFabs(distance2)>BxExPr/2.f) return -1.f; +dReal depth2=BxExPr/2.f-dFabs(distance2); + + +if(depth0 gl_cl_tries_state ; + +//extern xr_vector::iterator I,E,B ; + + +#define CONTACT(Ptr, Stride) ((dContactGeom*) (((char*)Ptr) + (Stride))) +#define SURFACE(Ptr, Stride) ((dSurfaceParameters*) (((char*)Ptr) + (Stride-sizeof(dSurfaceParameters)))) +#define NUMC_MASK (0xffff) + +#define M_SIN_PI_3 REAL(0.8660254037844386467637231707529362) +#define M_COS_PI_3 REAL(0.5000000000000000000000000000000000) +#endif diff --git a/xrPhysics/tri-colliderknoopc/dTriColliderMath.h b/xrPhysics/tri-colliderknoopc/dTriColliderMath.h new file mode 100644 index 00000000000..b1c9abaa745 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriColliderMath.h @@ -0,0 +1,114 @@ +#ifndef D_TRI_COLLIDER_MATH_H +#define D_TRI_COLLIDER_MATH_H +#include "__aabb_tri.h" +//#include "../ode_include.h" +#include "../../3rd party/ode/include/ode/common.h" +#include "../mathutilsode.h" +#include "dcTriangle.h" + +inline bool TriContainPoint(const dReal* v0,const dReal* v1,const dReal* v2, + const dReal* triSideAx0,const dReal* triSideAx1,const dReal* triSideAx2, + const dReal* triAx, const dReal* pos){ + dVector3 cross0, cross1, cross2; + dCROSS(cross0,=,triAx,triSideAx0); + if(dDOT(cross0,pos)0.f) return true; + else return false; + + + } + + inline bool TriPlaneContainPoint(const dReal* triAx,const dReal* v0, const dReal* pos){ + + + if(dDOT(triAx,pos)-dDOT(triAx,v0)>0.f) return true; + else return false; + + + } + + inline bool TriPlaneContainPoint(Triangle* T) + { + return T->dist>0.f; + } + + inline void PlanePoint(const Triangle& tri,const dReal* from,const dReal* to,float from_dist,dReal* point) + { + dVector3 dir = {to[0]-from[0],to[1]-from[1],to[2]-from[2]} ; + dReal cosinus = (tri.dist-from_dist) ; + VERIFY2(cosinus<0.f,"wrong positions") ; + dReal mul=(from_dist)/cosinus ; + dir[0]*=mul; dir[1]*=mul; dir[2]*=mul ; + point[0]=from[0]-dir[0] ; + point[1]=from[1]-dir[1] ; + point[2]=from[2]-dir[2] ; + + } + + + ICF void InitTriangle(CDB::TRI* XTri,Triangle& triangle,const Point* VRT) + { + dVectorSub(triangle.side0,VRT[1],VRT[0]) ; + dVectorSub(triangle.side1,VRT[2],VRT[1]) ; + triangle.T=XTri ; + dCROSS(triangle.norm,=,triangle.side0,triangle.side1) ; + cast_fv(triangle.norm).normalize() ; + triangle.pos=dDOT(VRT[0],triangle.norm) ; + } + ICF void InitTriangle(CDB::TRI* XTri,Triangle& triangle,const Fvector* V_array) + { + const Point vertices[3]={Point((dReal*)&V_array[XTri->verts[0]]),Point((dReal*)&V_array[XTri->verts[1]]),Point((dReal*)&V_array[XTri->verts[2]])}; + InitTriangle(XTri,triangle,vertices); + } + + ICF void CalculateTri(CDB::TRI* XTri,const float* pos,Triangle& triangle,const Fvector* V_array) + { + InitTriangle(XTri,triangle,V_array); + triangle.dist=dDOT(pos,triangle.norm)-triangle.pos; + } + + ICF void CalculateTri(CDB::TRI* XTri,const float* pos,Triangle& triangle,const Point* VRT) + { + InitTriangle(XTri,triangle,VRT); + triangle.dist=dDOT(pos,triangle.norm)-triangle.pos; + } + #endif \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/dTriCylinder.cpp b/xrPhysics/tri-colliderknoopc/dTriCylinder.cpp new file mode 100644 index 00000000000..79b515e3993 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriCylinder.cpp @@ -0,0 +1,810 @@ +#include "stdafx.h" +#include "dTriColliderCommon.h" +#include "../dCylinder/dCylinder.h" +#include "dTriCylinder.h" +#include "../MathUtils.h" +#include "dcTrilistCollider.h" +#include "../phworld.h" +#include "../../xrcdb/xr_area.h" +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + +/*(lp+t*lv-cp)^2=r^2 => t1,t2 =>O1=lp+t1*lv;O2=lp+t2*lv */ +//O1,O2 seems to be sphere line intersections +bool dcTriListCollider::circleLineIntersection(const dReal* cn,const dReal* cp,dReal r,const dReal* lv,const dReal* lp,dReal sign,dVector3 point){ + + dVector3 LC={lp[0]-cp[0],lp[1]-cp[1],lp[2]-cp[2]}; + + dReal A,B,C,B_A,B_A_2,D; + dReal t1,t2; + A=dDOT(lv,lv); + B=dDOT(LC,lv); + C=dDOT(LC,LC)-r*r; + B_A=B/A; + B_A_2=B_A*B_A; + D=B_A_2-C; + if(D<0.f){ + + point[0]=lp[0]-lv[0]*B; + point[1]=lp[1]-lv[1]*B; + point[2]=lp[2]-lv[2]*B; + return false; + + } + else{ + t1=-B_A-_sqrt(D); + t2=-B_A+_sqrt(D); + + dVector3 O1={lp[0]+lv[0]*t1,lp[1]+lv[1]*t1,lp[2]+lv[2]*t1}; + dVector3 O2={lp[0]+lv[0]*t2,lp[1]+lv[1]*t2,lp[2]+lv[2]*t2}; + //dVector3 test1={O1[0]-cp[0],O1[1]-cp[1],O1[2]-cp[2]}; + //dVector3 test2={O2[0]-cp[0],O2[1]-cp[1],O2[2]-cp[2]}; + //dReal t=_sqrt(dDOT(test1,test1)); + //t=_sqrt(dDOT(test2,test2)); + + dReal cpPr=sign*dDOT(cn,cp); + + dReal dist1=(sign*dDOT41(cn,O1)-cpPr); + dReal dist2=(sign*dDOT41(cn,O2)-cpPr); + + if(dist1 3) maxc = 3; // no more than 3 contacts per box allowed + + dReal signum, outDepth,cos1,sin1; + //////////////////////////////////////////////////////////////////////////// + //sepparation along tri plane normal;/////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + + //cos0=dDOT14(triAx,R+0); + cos1=dFabs(dDOT14(triAx,R+1)); + //cos2=dDOT14(triAx,R+2); + + //sin1=_sqrt(cos0*cos0+cos2*cos2); + + //////////////////////// + //another way ////////// + cos1=cos10.f) + return 0; + dReal depth=sidePr-dist; + outDepth=depth; + signum=-1.f; + + int code=0; + if(depth<0.f) return 0; + + dVector3 norm; + unsigned int ret=0; + dVector3 pos; + if(code==0){ + norm[0]=triAx[0]*signum; + norm[1]=triAx[1]*signum; + norm[2]=triAx[2]*signum; + + + dReal Q1 = signum*dDOT14(triAx,R+0); + dReal Q2 = signum*dDOT14(triAx,R+1); + dReal Q3 = signum*dDOT14(triAx,R+2); + dReal factor =_sqrt(Q1*Q1+Q3*Q3); + dReal C1,C3; + dReal centerDepth;//depth in the cirle centre + if(factor>0.f) + { + C1=Q1/factor; + C3=Q3/factor; + + } + else + { + C1=1.f; + C3=0.f; + + } + + dReal A1 = radius * C1;//cosinus + dReal A2 = hlz*Q2; + dReal A3 = radius * C3;//sinus + + if(factor>0.f) centerDepth=outDepth-A1*Q1-A3*Q3; else centerDepth=outDepth; + + pos[0]=p[0]; + pos[1]=p[1]; + pos[2]=p[2]; + + pos[0]+= A2>0 ? hlz*R[1]:-hlz*R[1]; + pos[1]+= A2>0 ? hlz*R[5]:-hlz*R[5]; + pos[2]+= A2>0 ? hlz*R[9]:-hlz*R[9]; + + + + + ret=0; + contact->pos[0] = pos[0]+A1*R[0]+A3*R[2]; + contact->pos[1] = pos[1]+A1*R[4]+A3*R[6]; + contact->pos[2] = pos[2]+A1*R[8]+A3*R[10]; + + { + contact->depth = outDepth; + ret=1; + } + + if(dFabs(Q2)>M_SQRT1_2){ + + A1=(-C1*M_COS_PI_3-C3*M_SIN_PI_3)*radius; + A3=(-C3*M_COS_PI_3+C1*M_SIN_PI_3)*radius; + CONTACT(contact,ret*skip)->pos[0]=pos[0]+A1*R[0]+A3*R[2]; + CONTACT(contact,ret*skip)->pos[1]=pos[1]+A1*R[4]+A3*R[6]; + CONTACT(contact,ret*skip)->pos[2]=pos[2]+A1*R[8]+A3*R[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+Q1*A1+Q3*A3; + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + + A1=(-C1*M_COS_PI_3+C3*M_SIN_PI_3)*radius; + A3=(-C3*M_COS_PI_3-C1*M_SIN_PI_3)*radius; + CONTACT(contact,ret*skip)->pos[0]=pos[0]+A1*R[0]+A3*R[2]; + CONTACT(contact,ret*skip)->pos[1]=pos[1]+A1*R[4]+A3*R[6]; + CONTACT(contact,ret*skip)->pos[2]=pos[2]+A1*R[8]+A3*R[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+Q1*A1+Q3*A3; + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + } else { + + CONTACT(contact,ret*skip)->pos[0]=contact->pos[0]-2.f*(A2>0 ? hlz*R[1]:-hlz*R[1]); + CONTACT(contact,ret*skip)->pos[1]=contact->pos[1]-2.f*(A2>0 ? hlz*R[5]:-hlz*R[5]); + CONTACT(contact,ret*skip)->pos[2]=contact->pos[2]-2.f*(A2>0 ? hlz*R[9]:-hlz*R[9]); + CONTACT(contact,ret*skip)->depth=outDepth-Q2*2.f*A2; + + if(CONTACT(contact,ret*skip)->depth>0.f)++ret; + } + } + + if((int)ret>maxc) ret=(unsigned int)maxc; + + for (unsigned int i=0; ig1 = const_cast (o2); + CONTACT(contact,i*skip)->g2 = const_cast (o1); + CONTACT(contact,i*skip)->normal[0] = norm[0]; + CONTACT(contact,i*skip)->normal[1] = norm[1]; + CONTACT(contact,i*skip)->normal[2] = norm[2]; + SURFACE(contact,i*skip)->mode=T->material; + } + if(ret&&dGeomGetUserData(o1)->callback)dGeomGetUserData(o1)->callback(T,contact); + return ret; +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +IC bool dcTriListCollider::cylinderCrossesLine(const dReal* p,const dReal* R,dReal hlz, + const dReal* v0,const dReal* v1,const dReal* l,dVector3 pos){ + dReal _cos=dDOT14(l,R); + + if(!(dFabs(_cos)<1.f)) return false; + + dReal sin2=1.f-_cos*_cos; + + dVector3 vp={v0[0]-p[0],v0[1]-p[1],v0[2]-p[2]}; + dReal c1=dDOT(vp,l); + dReal c2=dDOT14(vp,R); + + dReal t=(c2*_cos-c1)/sin2; + dReal q=(c2-c1*_cos)/sin2; + + if(dFabs(q)>hlz) return false; + + dVector3 v01={v1[0]-v0[0],v1[1]-v0[1],v1[2]-v0[2]}; + dReal sidelength2=dDOT(v01,v01); + + if(t*t>sidelength2) return false; + + pos[0]=v0[0]+l[0]*t; + pos[1]=v0[1]+l[1]*t; + pos[2]=v0[2]+l[2]*t; + + return true; + +} +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +//#define CHECK_EXIT +#ifdef CHECK_EXIT + int Check (int check) + { + return check; + } + #define RETURN0 return Check(0) +#else + #define RETURN0 return 0 +#endif + +int dcTriListCollider::dTriCyl ( + const dReal* v0,const dReal* v1,const dReal* v2, + Triangle* T, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip + ) +{ + + // VERIFY (skip >= (int)sizeof(dContactGeom)); + VERIFY (dGeomGetClass(o1)== dCylinderClassUser); + + + + + const dReal *R = dGeomGetRotation(o1); + const dReal* p=dGeomGetPosition(o1); + dReal radius; + dReal hlz; + dGeomCylinderGetParams(o1,&radius,&hlz); + hlz/=2.f; + + // find number of contacts requested + int maxc = flags & NUMC_MASK; + if (maxc < 1) maxc = 1; + if (maxc > 3) maxc = 3; // no more than 3 contacts per box allowed + + + const dVector3 &triAx=T->norm; + dVector3 triSideAx0={T->side0[0],T->side0[1],T->side0[2]}; //{v1[0]-v0[0],v1[1]-v0[1],v1[2]-v0[2]}; + dVector3 triSideAx1={T->side1[0],T->side1[1],T->side1[2]}; //{v2[0]-v1[0],v2[1]-v1[1],v2[2]-v1[2]}; + dVector3 triSideAx2={v0[0]-v2[0],v0[1]-v2[1],v0[2]-v2[2]}; + //dCROSS(triAx,=,triSideAx0,triSideAx1); + int code=0; + dReal signum, outDepth,cos0,cos1,cos2,sin1; +//////////////////////////////////////////////////////////////////////////// +//sepparation along tri plane normal;/////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//accurate_normalize(triAx); + +//cos0=dDOT14(triAx,R+0); +cos1=dFabs(dDOT14(triAx,R+1)); +//cos2=dDOT14(triAx,R+2); + +//sin1=_sqrt(cos0*cos0+cos2*cos2); + +//////////////////////// +//another way ////////// +cos1=cos1dist; //dDOT(triAx,v0)-dDOT(triAx,p); +if(dist>0.f) RETURN0; +dReal depth=sidePr-dFabs(dist); +outDepth=depth; +signum=dist>0.f ? 1.f : -1.f; + +code=0; +if(depth<0.f) RETURN0; + +dReal depth0,depth1,depth2,dist0,dist1,dist2; +bool isPdist0,isPdist1,isPdist2; +bool testV0,testV1,testV2; +bool sideTestV00,sideTestV01,sideTestV02; +bool sideTestV10,sideTestV11,sideTestV12; +bool sideTestV20,sideTestV21,sideTestV22; + + +////////////////////////////////////////////////////////////////////////////// +//cylinder axis - one of the triangle vertexes touches cylinder's flat surface +////////////////////////////////////////////////////////////////////////////// +dist0=dDOT14(v0,R+1)-dDOT14(p,R+1); +dist1=dDOT14(v1,R+1)-dDOT14(p,R+1); +dist2=dDOT14(v2,R+1)-dDOT14(p,R+1); + +isPdist0=dist0>0.f; +isPdist1=dist1>0.f; +isPdist2=dist2>0.f; + +depth0=hlz-dFabs(dist0); +depth1=hlz-dFabs(dist1); +depth2=hlz-dFabs(dist2); + +testV0=depth0>0.f; +testV1=depth1>0.f; +testV2=depth2>0.f; + +if(isPdist0==isPdist1 && isPdist1== isPdist2) //(here and lower) check the tryangle is on one side of the cylinder + +{ +if(depth0>depth1) + if(depth0>depth2) + if(testV0){ + if(depth0depth2) + if(testV1){ + if(depth10.f;\ + isPdist1=dist1>0.f;\ + isPdist2=dist2>0.f;\ +\ + depth0=radius-dFabs(dist0);\ + depth1=radius-dFabs(dist1);\ + depth2=radius-dFabs(dist2);\ +\ + sideTestV##vx##0=depth0>0.f;\ + sideTestV##vx##1=depth1>0.f;\ + sideTestV##vx##2=depth2>0.f;\ +\ + if(isPdist0==isPdist1 && isPdist1== isPdist2)\ +\ + {\ + if(sideTestV##vx##0||sideTestV##vx##1||sideTestV##vx##2){\ + if(!(depth##vx pointDepth)\ + {\ + pointDepth=depth##vx;\ + signum= isPdist##vx ? 1.f : -1.f;\ + outAx[0]=axis[0];\ + outAx[1]=axis[1];\ + outAx[2]=axis[2];\ + code=c;\ + }\ + }\ + }\ + else RETURN0;\ + \ +\ +\ + }\ +} + +if(testV0) TEST(0,1,2,4) +if(testV1 ) TEST(1,2,0,5) +//&& sideTestV01 +if(testV2 ) TEST(2,0,1,6) +//&& sideTestV02 && sideTestV12 +#undef TEST + +dVector3 tpos,pos; +if(code>3) outDepth=pointDepth; //deepest vertex axis used if its depth less than outDepth +//else{ +//bool outV0=!(testV0&&sideTestV00&&sideTestV10&&sideTestV20); +//bool outV1=!(testV1&&sideTestV01&&sideTestV11&&sideTestV21); +//bool outV2=!(testV2&&sideTestV02&&sideTestV12&&sideTestV22); +bool outV0=true; +bool outV1=true; +bool outV2=true; +///////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +///crosses between triangle sides and cylinder axis////////////////////////// +///////////////////////////////////////////////////////////////////////////// +#define TEST(ax,nx,ox,c) if(cylinderCrossesLine(p,R+1,hlz,v##ax,v##nx,triSideAx##ax,tpos)) {\ + dCROSS114(axis,=,triSideAx##ax,R+1);\ + accurate_normalize(axis);\ + dist##ax=dDOT(v##ax,axis)-dDOT(p,axis);\ + dist##ox=dDOT(v##ox,axis)-dDOT(p,axis);\ +\ + isPdist##ax=dist##ax>0.f;\ + isPdist##ox=dist##ox>0.f;\ +\ + if(isPdist##ax == isPdist##ox)\ +{\ +depth##ax=radius-dFabs(dist##ax);\ +depth##ox=radius-dFabs(dist##ox);\ + \ + if(depth##ax>0.f){\ + if(depth##ax<=outDepth && depth##ax>=depth##ox) \ + {\ + outDepth=depth##ax;\ + signum= isPdist##ax ? 1.f : -1.f;\ + outAx[0]=axis[0];\ + outAx[1]=axis[1];\ + outAx[2]=axis[2];\ + pos[0]=tpos[0];\ + pos[1]=tpos[1];\ + pos[2]=tpos[2];\ + code=c;\ + }\ + }\ + else if(depth##ox<0.f) RETURN0;\ +\ +}\ +} + +accurate_normalize(triSideAx0); +if(outV0&&outV1) +TEST(0,1,2,7) + +accurate_normalize(triSideAx1); +if(outV1&&outV2) +TEST(1,2,0,8) + +accurate_normalize(triSideAx2); +if(outV2&&outV0) +TEST(2,0,1,9) +#undef TEST + +//////////////////////////////////// +//test cylinder rings on triangle sides//// +//////////////////////////////////// + +dVector3 tAx,cen; +dReal sign; +bool cs; + +#define TEST(ax,nx,ox,c) \ +{\ +posProj=dDOT(p,triSideAx##ax)-dDOT(v##ax,triSideAx##ax);\ +axis[0]=p[0]-v0[0]-triSideAx##ax[0]*posProj;\ +axis[1]=p[1]-v0[1]-triSideAx##ax[1]*posProj;\ +axis[2]=p[2]-v0[2]-triSideAx##ax[2]*posProj;\ + \ +sign=dDOT14(axis,R+1)>0.f ? 1.f :-1.f;\ +cen[0]=p[0]-sign*R[1]*hlz;\ +cen[1]=p[1]-sign*R[5]*hlz;\ +cen[2]=p[2]-sign*R[9]*hlz;\ +\ +cs=circleLineIntersection(R+1,cen,radius,triSideAx##ax,v##ax,-sign,tpos);\ +\ +axis[0]=tpos[0]-cen[0];\ +axis[1]=tpos[1]-cen[1];\ +axis[2]=tpos[2]-cen[2];\ +\ +if(cs){ \ +\ +cos0=dDOT14(axis,R+0);\ +cos2=dDOT14(axis,R+2);\ +tAx[0]=R[2]*cos0-R[0]*cos2;\ +tAx[1]=R[6]*cos0-R[4]*cos2;\ +tAx[2]=R[10]*cos0-R[8]*cos2;\ +\ +dCROSS(axis,=,triSideAx##ax,tAx);\ +\ +}\ +accurate_normalize(axis);\ +dist##ax=dDOT(v##ax,axis)-dDOT(p,axis);\ +if(dist##ax*dDOT(axis,triSideAx##nx)>0.f){\ +\ +cos0=dDOT14(axis,R+0);\ +cos1=dFabs(dDOT14(axis,R+1));\ +cos2=dDOT14(axis,R+2);\ +\ +\ +sin1=_sqrt(cos0*cos0+cos2*cos2);\ +\ +sidePr=cos1*hlz+sin1*radius;\ +\ +\ + dist##ox=dDOT(v##ox,axis)-dDOT(p,axis);\ +\ + isPdist##ax=dist##ax>0.f;\ + isPdist##ox=dist##ox>0.f;\ +\ + if(isPdist##ax == isPdist##ox) \ +\ +{\ +depth##ax=sidePr-dFabs(dist##ax);\ +depth##ox=sidePr-dFabs(dist##ox);\ + \ + if(depth##ax>0.f){\ + if(depth##ax0.f) + { + C1=Q1/factor; + C3=Q3/factor; + + } + else + { + C1=1.f; + C3=0.f; + + } + + dReal A1 = radius * C1;//cosinus + dReal A2 = hlz;//Q2 + dReal A3 = radius * C3;//sinus + + if(factor>0.f) centerDepth=outDepth-A1*Q1-A3*Q3; else centerDepth=outDepth; + + pos[0]=p[0]; + pos[1]=p[1]; + pos[2]=p[2]; + + pos[0]+= Q2>0 ? hlz*R[1]:-hlz*R[1]; + pos[1]+= Q2>0 ? hlz*R[5]:-hlz*R[5]; + pos[2]+= Q2>0 ? hlz*R[9]:-hlz*R[9]; + + + + + ret=0; + dVector3 cross0, cross1, cross2; + dReal ds0,ds1,ds2; + + dCROSS(cross0,=,triAx,triSideAx0); + ds0=dDOT(cross0,v0); + + dCROSS(cross1,=,triAx,triSideAx1); + ds1=dDOT(cross1,v1); + + dCROSS(cross2,=,triAx,triSideAx2); + ds2=dDOT(cross2,v2); + + contact->pos[0] = pos[0]+A1*R[0]+A3*R[2]; + contact->pos[1] = pos[1]+A1*R[4]+A3*R[6]; + contact->pos[2] = pos[2]+A1*R[8]+A3*R[10]; + + if(dDOT(cross0,contact->pos)-ds0>0.f && + dDOT(cross1,contact->pos)-ds1>0.f && + dDOT(cross2,contact->pos)-ds2>0.f){ + contact->depth = outDepth; + ret=1; + } + +if(dFabs(Q2)>M_SQRT1_2){ + + A1=(-C1*M_COS_PI_3-C3*M_SIN_PI_3)*radius; + A3=(-C3*M_COS_PI_3+C1*M_SIN_PI_3)*radius; + CONTACT(contact,ret*skip)->pos[0]=pos[0]+A1*R[0]+A3*R[2]; + CONTACT(contact,ret*skip)->pos[1]=pos[1]+A1*R[4]+A3*R[6]; + CONTACT(contact,ret*skip)->pos[2]=pos[2]+A1*R[8]+A3*R[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+Q1*A1+Q3*A3; + + if(CONTACT(contact,ret*skip)->depth>0.f) + if(dDOT(cross0,CONTACT(contact,ret*skip)->pos)-ds0>0.f && + dDOT(cross1,CONTACT(contact,ret*skip)->pos)-ds1>0.f && + dDOT(cross2,CONTACT(contact,ret*skip)->pos)-ds2>0.f) ++ret; + + A1=(-C1*M_COS_PI_3+C3*M_SIN_PI_3)*radius; + A3=(-C3*M_COS_PI_3-C1*M_SIN_PI_3)*radius; + CONTACT(contact,ret*skip)->pos[0]=pos[0]+A1*R[0]+A3*R[2]; + CONTACT(contact,ret*skip)->pos[1]=pos[1]+A1*R[4]+A3*R[6]; + CONTACT(contact,ret*skip)->pos[2]=pos[2]+A1*R[8]+A3*R[10]; + CONTACT(contact,ret*skip)->depth=centerDepth+Q1*A1+Q3*A3; + + if(CONTACT(contact,ret*skip)->depth>0.f) + if(dDOT(cross0,CONTACT(contact,ret*skip)->pos)-ds0>0.f && + dDOT(cross1,CONTACT(contact,ret*skip)->pos)-ds1>0.f && + dDOT(cross2,CONTACT(contact,ret*skip)->pos)-ds2>0.f) ++ret; +} else { + + CONTACT(contact,ret*skip)->pos[0]=contact->pos[0]-2.f*(Q2>0 ? hlz*R[1]:-hlz*R[1]); + CONTACT(contact,ret*skip)->pos[1]=contact->pos[1]-2.f*(Q2>0 ? hlz*R[5]:-hlz*R[5]); + CONTACT(contact,ret*skip)->pos[2]=contact->pos[2]-2.f*(Q2>0 ? hlz*R[9]:-hlz*R[9]); + CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q2*2.f*A2); + + if(CONTACT(contact,ret*skip)->depth>0.f) + if(dDOT(cross0,CONTACT(contact,ret*skip)->pos)-ds0>0.f && + dDOT(cross1,CONTACT(contact,ret*skip)->pos)-ds1>0.f && + dDOT(cross2,CONTACT(contact,ret*skip)->pos)-ds2>0.f) ++ret; +} + } +else if(code<7)//1-6 + { + ret=1; + contact->depth = outDepth; + switch((code-1)%3){ + case 0: + if(gl_state.test(fl_engaged_v0))RETURN0; + VxToGlClTriState(T->T->verts[0],T_array); + contact->pos[0]=v0[0]; + contact->pos[1]=v0[1]; + contact->pos[2]=v0[2]; + break; + case 1: + if(gl_state.test(fl_engaged_v1))RETURN0; + VxToGlClTriState(T->T->verts[1],T_array); + contact->pos[0]=v1[0]; + contact->pos[1]=v1[1]; + contact->pos[2]=v1[2]; + break; + case 2: + if(gl_state.test(fl_engaged_v2)) + RETURN0; + VxToGlClTriState(T->T->verts[2],T_array); + contact->pos[0]=v2[0]; + contact->pos[1]=v2[1]; + contact->pos[2]=v2[2]; + break; + } + +if(code<4){//1-3 + norm[0]=R[1]*signum; + norm[1]=R[5]*signum; + norm[2]=R[9]*signum; + } +else { + norm[0]=outAx[0]*signum; + norm[1]=outAx[1]*signum; + norm[2]=outAx[2]*signum; + } +} + +else {//7-12 + ret=1; + int iv0=(code-7)%3; + int iv1=(iv0+1)%3; + int flag=fl_engaged_s0<<(iv0); + if(gl_state.test(u8(flag&0xff))) + RETURN0; + SideToGlClTriState(T->T->verts[iv0],T->T->verts[iv1],T_array); + contact->depth = outDepth; + norm[0]=outAx[0]*signum; + norm[1]=outAx[1]*signum; + norm[2]=outAx[2]*signum; + contact->pos[0] = pos[0]; + contact->pos[1] = pos[1]; + contact->pos[2] = pos[2]; +} + + if((int)ret>maxc) ret=(unsigned int)maxc; + + for (unsigned int i=0; ig1 = const_cast (o2); + CONTACT(contact,i*skip)->g2 = const_cast (o1); + CONTACT(contact,i*skip)->normal[0] = norm[0]; + CONTACT(contact,i*skip)->normal[1] = norm[1]; + CONTACT(contact,i*skip)->normal[2] = norm[2]; + SURFACE(contact,i*skip)->mode=T->T->material; + } + if(ret&&dGeomGetUserData(o1)->callback)dGeomGetUserData(o1)->callback(T->T,contact); + return ret; +} + diff --git a/xrPhysics/tri-colliderknoopc/dTriCylinder.h b/xrPhysics/tri-colliderknoopc/dTriCylinder.h new file mode 100644 index 00000000000..ec74ceab2e5 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriCylinder.h @@ -0,0 +1,27 @@ +#ifndef D_TRI_CYLINDER_H +#define D_TRI_CYLINDER_H +#include "../dCylinder/dCylinder.h" +#include "TriPrimitiveCollideClassDef.h" +#include "dcTriListCollider.h" +struct dxCylinder { // cylinder + dReal radius,lz; // radius, length along z axis */ +}; + + + +IC float dcTriListCollider:: dCylProj(dxGeom* cylinder,const dReal* normal) +{ + VERIFY(dGeomGetClass(cylinder)== dCylinderClassUser); + float hlz,radius; + dGeomCylinderGetParams(cylinder,&radius,&hlz); + const dReal* R=dGeomGetRotation(cylinder); + hlz*=0.5f; + float cos1=dFabs(dDOT14(normal,R+1)); + cos1=cos1Collider; + +} + + + +inline bool ValidateCollision(dxGeom* o1, dxGeom* o2){ + return dGeomGetUserData(o1)->b_static_colide; + /* + dxBody* b1 = dGeomGetBody(o1); + + dxBody* b2 = dGeomGetBody(o2); + + + + if (b1){ + + if (!dBodyIsEnabled(b1)){ + + b1 = 0; + + } + + } + + if (b2){ + + if (!dBodyIsEnabled(b2)){ + + b2 = 0; + + } + + } + + return b1 || b2; + */ + //return true; +} + + + +int dCollideSTL(dxGeom* TriList, dxGeom* Sphere, int Flags, dContactGeom* Contact, int Stride) throw() +{ + + if (ValidateCollision(Sphere, TriList)){ + + return GetData(TriList)->CollideSphere(Sphere, Flags, Contact, Stride); + + } + + else return 0; + +} + + + +int dCollideBTL(dxGeom* TriList, dxGeom* Box, int Flags, dContactGeom* Contact, int Stride)throw() +{ + + if (ValidateCollision(Box, TriList)){ + + return GetData(TriList)->CollideBox(Box, Flags, Contact, Stride); + + } + + else return 0; + +} + +int dCollideCTL(dxGeom* TriList, dxGeom* Cyl, int Flags, dContactGeom* Contact, int Stride)throw() +{ + + if (ValidateCollision(Cyl, TriList)){ + + return GetData(TriList)->CollideCylinder(Cyl, Flags, Contact, Stride); + + } + + else return 0; + +} + + + +dColliderFn* dTriListColliderFn(int num) +{ + // Log("in dTriListColliderFn "); + // Msg("num=%d",num); + if (num ==dBoxClass){ + return (dColliderFn*)&dCollideBTL; + } + if (num ==dSphereClass) { + return (dColliderFn*)&dCollideSTL; + } + + if (num == dCylinderClassUser) return (dColliderFn*)&dCollideCTL; + + return 0; + +} + +int dAABBTestTL(dxGeom* TriList, dxGeom* Object, dReal AABB[6]) throw() +{ + + return 1; +} + +void dDestroyTriList(dGeomID g){ + + xr_delete(((dxTriList*)dGeomGetClassData(g))->Collider); +} + + + +/* External functions */ + +void dGeomTriListSetCallback(dGeomID g, dTriCallback* Callback){ + + dxTriList* Data = (dxTriList*)dGeomGetClassData(g); + + Data->Callback = Callback; + +} + + + +dTriCallback* dGeomTriListGetCallback(dGeomID g){ + + dxTriList* Data = (dxTriList*)dGeomGetClassData(g); + + return Data->Callback; + +} + + + +void dGeomTriListSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback){ + + dxTriList* Data = (dxTriList*)dGeomGetClassData(g); + + Data->ArrayCallback = ArrayCallback; + +} + + + +dTriArrayCallback* dGeomTriListGetArrayCallback(dGeomID g){ + + dxTriList* Data = (dxTriList*)dGeomGetClassData(g); + + return Data->ArrayCallback; + +} + + + +dxGeom* dCreateTriList(dSpaceID space, dTriCallback* Callback, dTriArrayCallback* ArrayCallback){ + + if (dTriListClass == -1){ + + dGeomClass c; + + c.bytes = sizeof(dxTriList); + + c.collider = &dTriListColliderFn; + + c.aabb = &dInfiniteAABB; + + c.aabb_test = &dAABBTestTL; + + // c.aabb_test=NULL; + c.dtor = &dDestroyTriList; + + + + dTriListClass = dCreateGeomClass(&c); + + } + + + + dxGeom* g = dCreateGeom(dTriListClass); + + if (space) dSpaceAdd(space, g); + + + + dxTriList* Data = (dxTriList*)dGeomGetClassData(g); + + Data->Callback = Callback; + + Data->ArrayCallback = ArrayCallback; + + Data->Collider = xr_new(g); + + + + return g; + +} + + + diff --git a/xrPhysics/tri-colliderknoopc/dTriList.h b/xrPhysics/tri-colliderknoopc/dTriList.h new file mode 100644 index 00000000000..28ae70eaeab --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriList.h @@ -0,0 +1,55 @@ +//#include "stdafx.h" +//#include "ode_include.h" +#include "../../3rd party/ode/include/ode/common.h" + +/* Class ID */ + +extern int dTriListClass; + + + +/* Single precision, no padding vector3 used for storage */ + +struct dcVector3{ + + float x, y, z; + +}; + + + +/* Per triangle callback */ + +typedef int dTriCallback(dGeomID TriList, dGeomID RefObject, int TriangleIndex); + +void dGeomTriListSetCallback(dGeomID g, dTriCallback* Callback); + +dTriCallback* dGeomTriListGetCallback(dGeomID g); + + + +/* Per object callback */ + +typedef void dTriArrayCallback(dGeomID TriList, dGeomID RefObject, const int* TriIndices, int TriCount); + +void dGeomTriListSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback); + +dTriArrayCallback* dGeomTriListGetArrayCallback(dGeomID g); + + + +/* Construction */ + +dxGeom* dCreateTriList(dSpaceID space, dTriCallback* Callback, dTriArrayCallback* ArrayCallback); + + + +/* Setting data */ + +void dGeomTriListBuild(dGeomID g, const dcVector3* Vertices, int VertexCount, const int* Indices, int IndexCount); + + + +/* Getting data */ + +void dGeomTriListGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2); \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/dTriSphere.cpp b/xrPhysics/tri-colliderknoopc/dTriSphere.cpp new file mode 100644 index 00000000000..84c91d9ddb7 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriSphere.cpp @@ -0,0 +1,257 @@ +#include "stdafx.h" +#include "dTriColliderCommon.h" +#include "dTriColliderMath.h" +#include "dTriSphere.h" +#include "dctrilistcollider.h" +#include "../phworld.h" +#include "../../xrcdb/xr_area.h" +//////////////////////////////////////////////////////////////////////////// +IC dReal dcTriListCollider::PointSphereTest(const dReal* center, const dReal radius, + const dReal* pt,dReal* norm) +{ + + norm[0]=center[0]-pt[0]; + norm[1]=center[1]-pt[1]; + norm[2]=center[2]-pt[2]; + dReal mag=dSqrt(dDOT(norm,norm)); + dReal depth=radius-mag; + if(depth<0.f) return -1.f; + if(mag>0.f) + { + norm[0]/=mag;norm[1]/=mag;norm[2]/=mag; + } + else + { + norm[0]=0;norm[1]=1;norm[2]=0; + } + return depth; + +} + + +inline dReal dcTriListCollider::FragmentonSphereTest(const dReal* center, const dReal radius, + const dReal* pt1, const dReal* pt2,dReal* norm) +{ + dVector3 direction={pt2[0]-pt1[0],pt2[1]-pt1[1],pt2[2]-pt1[2]}; + cast_fv(direction).normalize(); + dReal center_prg=dDOT(center,direction); + dReal pt1_prg=dDOT(pt1,direction); + dReal pt2_prg=dDOT(pt2,direction); + dReal from1_dist=center_prg-pt1_prg; + if(center_prgpt2_prg) return -1; + dVector3 line_to_center={ + -pt1[0]-direction[0]*from1_dist+center[0], + -pt1[1]-direction[1]*from1_dist+center[1], + -pt1[2]-direction[2]*from1_dist+center[2] + }; + + float mag=dSqrt(dDOT(line_to_center,line_to_center)); + //dNormalize3(norm); + + + dReal depth=radius-mag; + if(depth<0.f) return -1.f; + if(mag>0.f) + { + norm[0]=line_to_center[0]/mag; + norm[1]=line_to_center[1]/mag; + norm[2]=line_to_center[2]/mag; + } + else + { + norm[0]=0; + norm[1]=1; + norm[2]=0; + } + return depth; +} + + +/////////////////////////////////////////////////////////////////////////////// +IC bool dcTriListCollider::FragmentonSphereTest(const dReal* center, const dReal radius, + const dReal* pt1, const dReal* pt2,dReal* norm,dReal& depth) +{ + dVector3 V={pt2[0]-pt1[0],pt2[1]-pt1[1],pt2[2]-pt1[2]}; + dVector3 L={pt1[0]-center[0],pt1[1]-center[1],pt1[2]-center[2]}; + dReal sq_mag_V=dDOT(V,V); + dReal dot_L_V=dDOT(L,V); + dReal t=-dot_L_V/sq_mag_V;//t + if(t<0.f||t>1.f)return false; + dVector3 Pc={pt1[0]+t*V[0],pt1[1]+t*V[1],pt1[2]+t*V[2]}; + dVector3 Dc={center[0]-Pc[0],center[1]-Pc[1],center[2]-Pc[2]}; + dReal sq_mag_Dc=dDOT(Dc,Dc); + if(sq_mag_Dc>radius*radius)return false; + //dReal dot_V_Pc=dDOT(V,Pc); + //if(dDOT(V,pt1)>dot_V_Pc||dDOT(V,pt2)0.f) + { + norm[0]=Dc[0]/mag; + norm[1]=Dc[1]/mag; + norm[2]=Dc[2]/mag; + } + else + { + norm[0]=0; + norm[1]=1; + norm[2]=0; + } + return true; +} + +IC bool dcTriListCollider:: PointSphereTest(const dReal* center, const dReal radius, + const dReal* pt,dReal* norm,dReal &depth) +{ + + norm[0]=center[0]-pt[0]; + norm[1]=center[1]-pt[1]; + norm[2]=center[2]-pt[2]; + dReal smag=dDOT(norm,norm); + if(smag >radius*radius)return false; + float mag=dSqrt(smag); + depth=radius-mag; + if(mag>0.f) + { + norm[0]/=mag;norm[1]/=mag;norm[2]/=mag; + } + else + { + norm[0]=0;norm[1]=1;norm[2]=0; + } + return true; + +} +///////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +int dcTriListCollider::dSortedTriSphere(const dReal* /**v1/**/,const dReal* /**v2/**/, + const dReal* triAx, + CDB::TRI* T, + dReal dist, + dxGeom* Sphere, + dxGeom* Geometry, + int Flags, + dContactGeom* Contacts, + int skip + ){ + + + //const dReal* v1=(dReal*)T->verts[1]; + //const dReal* v2=(dReal*)T->verts[2]; + const dReal* SphereCenter=dGeomGetPosition(Sphere); + const float SphereRadius = dGeomSphereGetRadius(Sphere); + + + + // dNormalize3(triAx); + const dReal *ContactNormal=triAx;//{triAx[0],triAx[1],triAx[2]}; + dVector3 ContactPos={SphereCenter[0]-triAx[0]* SphereRadius,SphereCenter[1]-triAx[1]* SphereRadius,SphereCenter[2]-triAx[2]* SphereRadius}; + + float ContactDepth= -dist + SphereRadius; + if (ContactDepth >= 0){ + + Contacts->normal[0] =-ContactNormal[0]; + Contacts->normal[1] =-ContactNormal[1]; + Contacts->normal[2] =-ContactNormal[2]; + Contacts->depth = ContactDepth; + //////////////////// + + Contacts->pos[0]=ContactPos[0]; + Contacts->pos[1]=ContactPos[1]; + Contacts->pos[2]=ContactPos[2]; + Contacts->g1 = Geometry; + Contacts->g2 = Sphere; + ((dxGeomUserData*)dGeomGetData(Sphere))->tri_material=T->material; + if(dGeomGetUserData(Sphere)->callback)dGeomGetUserData(Sphere)->callback(T,Contacts); + SURFACE(Contacts,0)->mode=T->material; + ////////////////////////////////// + return 1; + + } + + return 0; + } + + +int dcTriListCollider::dTriSphere(const dReal* v0,const dReal* v1,const dReal* v2, + Triangle* T, + dxGeom* Sphere,dxGeom* Geometry, int Flags, + dContactGeom* Contacts,int /**skip/**/) + { + + + const dVector3 &triSideAx0 =T->side0 ; + const dVector3 &triSideAx1 =T->side1 ; + const dVector3 &triAx =T->norm ; + + //if(!TriPlaneContainPoint(triAx,v0,SphereCenter)) return 0; + + + const dReal radius=dGeomSphereGetRadius(Sphere); + float Depth=-T->dist+radius; + if(Depth<0.f) return 0; + const dReal* pos=dGeomGetPosition(Sphere); + dVector3 ContactNormal; + if(TriContainPoint(v0,v1,v2,triAx,triSideAx0,triSideAx1,pos)) + { + ContactNormal[0]=triAx[0];ContactNormal[1]=triAx[1];ContactNormal[2]=triAx[2]; + //dVector3 ContactPos={pos[0]-triAx[0]* radius,pos[1]-triAx[1]* radius,pos[2]-triAx[2]* radius}; + } + else + { + //VERIFY( g_pGameLevel ); + CDB::TRI* T_array = inl_ph_world().ObjectSpace().GetStaticTris(); + flags8& gl_state=gl_cl_tries_state[I-B]; + if(gl_state.test(fl_engaged_s0)||gl_state.test(fl_engaged_s1)||gl_state.test(fl_engaged_s2)) + return 0; + if(FragmentonSphereTest(pos,radius,v0,v1,ContactNormal,Depth)) + { + SideToGlClTriState(T->T->verts[0],T->T->verts[1],T_array); + } + else if(FragmentonSphereTest(pos,radius,v1,v2,ContactNormal,Depth)) + { + SideToGlClTriState(T->T->verts[1],T->T->verts[2],T_array ); + } + else if(FragmentonSphereTest(pos,radius,v2,v0,ContactNormal,Depth)) + { + SideToGlClTriState(T->T->verts[2],T->T->verts[0],T_array ); + } + else{ + if(gl_state.test(fl_engaged_v0)||gl_state.test(fl_engaged_v1)||gl_state.test(fl_engaged_v2)) + return 0; + if(PointSphereTest(pos,radius,v0,ContactNormal,Depth)) + { + VxToGlClTriState(T->T->verts[0],T_array ); + } + else if(PointSphereTest(pos,radius,v1,ContactNormal,Depth)) + { + VxToGlClTriState(T->T->verts[1],T_array ); + } + else if(PointSphereTest(pos,radius,v2,ContactNormal,Depth)) + { + VxToGlClTriState(T->T->verts[2],T_array ); + } + else return 0; + } + } + + Contacts->normal[0] =-ContactNormal[0]; + Contacts->normal[1] =-ContactNormal[1]; + Contacts->normal[2] =-ContactNormal[2]; + Contacts->depth = Depth; + //////////////////// + + Contacts->pos[0]=pos[0]-ContactNormal[0]*radius; + Contacts->pos[1]=pos[1]-ContactNormal[1]*radius; + Contacts->pos[2]=pos[2]-ContactNormal[2]*radius; + Contacts->g1 = Geometry; + Contacts->g2 = Sphere; + ((dxGeomUserData*)dGeomGetData(Sphere))->tri_material=T->T->material; + if(dGeomGetUserData(Sphere)->callback)dGeomGetUserData(Sphere)->callback(T->T,Contacts); + SURFACE(Contacts,0)->mode=T->T->material; + ////////////////////////////////// + // ++OutTriCount; + return 1; + } + diff --git a/xrPhysics/tri-colliderknoopc/dTriSphere.h b/xrPhysics/tri-colliderknoopc/dTriSphere.h new file mode 100644 index 00000000000..a3be876c595 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dTriSphere.h @@ -0,0 +1,9 @@ +#ifndef D_TRI_SPHERE_H +#define D_TRI_SPHERE_H +#include "TriPrimitiveCollideClassDef.h" +#include "../MathUtils.h" + + + + +#endif \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/dcTriListCollider.cpp b/xrPhysics/tri-colliderknoopc/dcTriListCollider.cpp new file mode 100644 index 00000000000..10bbbd3a54d --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dcTriListCollider.cpp @@ -0,0 +1,132 @@ +// Do NOT build this file seperately. It is included in dTriList.cpp automatically. + + +#include "../../xrEngine/cl_intersect.h" +#include "dTriCollideK.h" +#include "dSortTriPrimitive.h" +#include "../dCylinder/dCylinder.h" +#include "../MathUtils.h" +//#include "../level.h" +#ifdef DEBUG +#include "../debug_output.h" +#endif + +dcTriListCollider::dcTriListCollider(dxGeom* Geometry) +{ + this->Geometry = Geometry; + GeomData = (dxTriList*)dGeomGetClassData(Geometry); + + +} + +dcTriListCollider::~dcTriListCollider() +{ + +} + +int dCollideBP (const dxGeom* o1, const dxGeom* o2, int flags, dContactGeom *contact, int skip); // ODE internal function + + + +//#define CONTACT(Ptr, Stride) ((dContactGeom*) (((byte*)Ptr) + (Stride))) +//#define SURFACE(Ptr, Stride) ((dSurfaceParameters*) (((byte*)Ptr) + (Stride-sizeof(dSurfaceParameters)))) + +int dcTriListCollider::CollideBox(dxGeom* Box, int Flags, dContactGeom* Contacts, int Stride) +{ + Fvector AABB; + dVector3 BoxSides; + dGeomBoxGetLengths(Box,BoxSides); + dReal* R=const_cast(dGeomGetRotation(Box)); + AABB.x=(dFabs(BoxSides[0]*R[0])+dFabs(BoxSides[1]*R[1])+dFabs(BoxSides[2]*R[2]))/2.f +10.f*EPS_L; + AABB.y=(dFabs(BoxSides[0]*R[4])+dFabs(BoxSides[1]*R[5])+dFabs(BoxSides[2]*R[6]))/2.f +10.f*EPS_L; + AABB.z=(dFabs(BoxSides[0]*R[8])+dFabs(BoxSides[1]*R[9])+dFabs(BoxSides[2]*R[10]))/2.f+10.f*EPS_L; + dBodyID box_body=dGeomGetBody(Box); + if(box_body) { + const dReal*velocity=dBodyGetLinearVel(box_body); + AABB.x+=dFabs(velocity[0])*0.04f; + AABB.y+=dFabs(velocity[1])*0.04f; + AABB.z+=dFabs(velocity[2])*0.04f; + + } + + + BoxTri bt(*this); + return dSortTriPrimitiveCollide + (bt, + Box, + Geometry, + Flags, + Contacts, + Stride, + AABB + ); +} + + + +int dcTriListCollider::CollideCylinder(dxGeom* Cylinder, int Flags, dContactGeom* Contacts, int Stride){ + + + + Fvector AABB; + dReal CylinderRadius,CylinderLength; + + + dGeomCylinderGetParams (Cylinder, &CylinderRadius,&CylinderLength); + + dReal* R=const_cast(dGeomGetRotation(Cylinder)); + + AABB.x = REAL(0.5) * dFabs (R[1] * CylinderLength) + (_sqrt(R[0]*R[0]+R[2]*R[2]) * CylinderRadius); + + AABB.y = REAL(0.5) * dFabs (R[5] * CylinderLength) + (_sqrt(R[4]*R[4]+R[6]*R[6]) * CylinderRadius); + + AABB.z = REAL(0.5) * dFabs (R[9] * CylinderLength) + (_sqrt(R[8]*R[8]+R[10]*R[10]) * CylinderRadius); + + const dReal*velocity=dBodyGetLinearVel(dGeomGetBody(Cylinder)); + AABB.x+=dFabs(velocity[0])*0.04f; + AABB.y+=dFabs(velocity[1])*0.04f; + AABB.z+=dFabs(velocity[2])*0.04f; + + CylTri ct(*this); + return dSortTriPrimitiveCollide + ( + ct, + Cylinder, + Geometry, + Flags, + Contacts, + Stride, + AABB + ); + +} + + + //////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + int dcTriListCollider::CollideSphere(dxGeom* Sphere, int Flags, dContactGeom* Contacts, int Stride){ + + const float SphereRadius = dGeomSphereGetRadius(Sphere); + Fvector AABB; + + + // Make AABB + AABB.x=SphereRadius; + AABB.y=SphereRadius; + AABB.z=SphereRadius; + + const dReal*velocity=dBodyGetLinearVel(dGeomGetBody(Sphere)); + AABB.x+=dFabs(velocity[0])*0.04f; + AABB.y+=dFabs(velocity[1])*0.04f; + AABB.z+=dFabs(velocity[2])*0.04f; + SphereTri st(*this); + return dSortTriPrimitiveCollide(st,Sphere,Geometry,Flags,Contacts,Stride, + AABB); + + } + + + + + diff --git a/xrPhysics/tri-colliderknoopc/dcTriListCollider.h b/xrPhysics/tri-colliderknoopc/dcTriListCollider.h new file mode 100644 index 00000000000..f131ef231b9 --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dcTriListCollider.h @@ -0,0 +1,162 @@ +//#include "stdafx.h" +#ifndef __DCTRILISTCOLLIDER_INCLUDED__ +#define __DCTRILISTCOLLIDER_INCLUDED__ +#include "dcTriangle.h" +struct dxGeom; +struct dxTriList; +enum{ + fl_engaged_v0 =1<<0, + fl_engaged_v1 =1<<1, + fl_engaged_v2 =1<<2, + fl_engaged_s0 =1<<3, + fl_engaged_s1 =1<<4, + fl_engaged_s2 =1<<5, +}; +class dcTriListCollider; +class dcTriListCollider +{ + dxGeom* Geometry; // The geom object + dxTriList* GeomData; // Buffered pointer to classdata + + xr_vector pos_tries ; + xr_vector neg_tries ; + xr_vector< flags8 > gl_cl_tries_state ; + xr_vector::iterator I,E,B ; +public: + dcTriListCollider(dxGeom* Geometry); + ~dcTriListCollider(); + int CollideBox(dxGeom* Box, int Flags, dContactGeom* Contact, int Stride); + int CollideSphere(dxGeom* Sphere, int Flags, dContactGeom* Contact, int Stride); + int CollideCylinder(dxGeom* Cylinder, int Flags, dContactGeom* Contacts, int Stride); +private: + IC void VxToGlClTriState(u32 v,CDB::TRI* T_array); + IC void SideToGlClTriState(u32 v0,u32 v1,CDB::TRI* T_array); + template +IC int dSortTriPrimitiveCollide (T primitive, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip, + const Fvector& AABB + ); + IC dReal PointSphereTest(const dReal* center, const dReal radius, + const dReal* pt,dReal* norm); + IC dReal FragmentonSphereTest(const dReal* center, const dReal radius, + const dReal* pt1, const dReal* pt2,dReal* norm); + IC bool FragmentonSphereTest(const dReal* center, const dReal radius, + const dReal* pt1, const dReal* pt2,dReal* norm,dReal& depth); + IC bool PointSphereTest(const dReal* center, const dReal radius, + const dReal* pt,dReal* norm,dReal &depth); + int dSortedTriSphere(const dReal* /**v1/**/,const dReal* /**v2/**/, + const dReal* triAx, + CDB::TRI* T, + dReal dist, + dxGeom* Sphere, + dxGeom* Geometry, + int Flags, + dContactGeom* Contacts, + int skip + ); +IC float dSphereProj(dxGeom* sphere,const dReal* /**normal/**/) + { + VERIFY (dGeomGetClass(sphere)== dSphereClass); + return dGeomSphereGetRadius(sphere); + } +int dTriSphere(const dReal* v0,const dReal* v1,const dReal* v2, + Triangle* T, + dxGeom* Sphere,dxGeom* Geometry, int Flags, + dContactGeom* Contacts,int /**skip/**/); +IC float dBoxProj(dxGeom* box,const dReal* normal); +IC void CrossProjLine(const dReal* pt1,const dReal* vc1,const dReal* pt2,const dReal* vc2,dReal* proj); +IC void CrossProjLine1(const dReal* pt1,const dReal* vc1,const dReal* pt2,const dReal* vc2,dReal* proj); +IC bool CrossProjLine14(const dReal* pt1,const dReal* vc1,const dReal* pt2,const dReal* vc2,dReal hside,dReal* proj); +IC bool IsPtInBx(const dReal* Pt,const dReal* BxP,const dReal* BxEx,const dReal* BxR); +IC dReal FragmentonBoxTest(const dReal* Pt1,const dReal* Pt2,const dReal* BxP,const dReal* BxEx,const dReal* R,dReal* norm,dReal* pos); + int dSortedTriBox ( + const dReal* triSideAx0,const dReal* triSideAx1, + const dReal* triAx, + //const dReal* v0, + //const dReal* v1, + //const dReal* v2, + CDB::TRI* T, + dReal dist, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip + ); +int dTriBox ( + const dReal* v0,const dReal* v1,const dReal* v2, + Triangle* T, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip + ); +IC bool circleLineIntersection(const dReal* cn,const dReal* cp,dReal r,const dReal* lv,const dReal* lp,dReal sign,dVector3 point); +IC float dCylProj(dxGeom* cylinder,const dReal* normal); + int dSortedTriCyl ( + const dReal* triSideAx0,const dReal* triSideAx1, + const dReal* triAx, + //const dReal* v0, + //const dReal* v1, + //const dReal* v2, + CDB::TRI* T, + dReal dist, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip + ); + int dTriCyl ( + const dReal* v0,const dReal* v1,const dReal* v2, + Triangle* T, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip + ); +IC bool cylinderCrossesLine(const dReal* p,const dReal* R,dReal hlz, + const dReal* v0,const dReal* v1,const dReal* l,dVector3 pos); +IC float Proj (dxGeom* o,const dReal* normal); +IC int Collide( + const dReal* v0,const dReal* v1,const dReal* v2, + Triangle* T, + dxGeom *o1,dxGeom *o2, + int flags, dContactGeom *contact, int skip + ); +IC int CollidePlain( + const dReal* triSideAx0,const dReal* triSideAx1, + const dReal* triAx, + CDB::TRI* T, + dReal dist, + dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip + ); +TRI_PRIMITIVE_COLIDE_CLASS_DECLARE(Cyl) +TRI_PRIMITIVE_COLIDE_CLASS_DECLARE(Sphere) +TRI_PRIMITIVE_COLIDE_CLASS_DECLARE(Box) +}; + +TRI_PRIMITIVE_COLIDE_CLASS_IMPLEMENT(Box) +TRI_PRIMITIVE_COLIDE_CLASS_IMPLEMENT(Cyl) + TRI_PRIMITIVE_COLIDE_CLASS_IMPLEMENT(Sphere) +IC void dcTriListCollider::VxToGlClTriState(u32 v,CDB::TRI* T_array) +{ + //CDB::TRI* T_array = Level().ObjectSpace.GetStaticTris(); + xr_vector::iterator LI=I+1; + for(;E!=LI;++LI) + { + u32* verts=T_array[*LI].verts; + flags8 &state =gl_cl_tries_state[LI-B]; + if(verts[0]==v)state.set(fl_engaged_v0,TRUE); + if(verts[1]==v)state.set(fl_engaged_v1,TRUE); + if(verts[2]==v)state.set(fl_engaged_v2,TRUE); + } +} +IC void dcTriListCollider::SideToGlClTriState(u32 v0,u32 v1,CDB::TRI* T_array) +{ + // = Level().ObjectSpace.GetStaticTris(); + xr_vector::iterator LI=I+1; + for(;E!=LI;++LI) + { + u32* verts=T_array[*LI].verts; + flags8 &state =gl_cl_tries_state[LI-B]; + if(verts[0]==v1&&verts[1]==v0)state.set(fl_engaged_s0,TRUE); + if(verts[1]==v1&&verts[2]==v0)state.set(fl_engaged_s1,TRUE); + if(verts[2]==v1&&verts[0]==v0)state.set(fl_engaged_s2,TRUE); + } +} + + +#endif //__DCTRILISTCOLLIDER_INCLUDED__( \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/dcTriangle.h b/xrPhysics/tri-colliderknoopc/dcTriangle.h new file mode 100644 index 00000000000..2fa2128560e --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dcTriangle.h @@ -0,0 +1,22 @@ +#pragma once +struct Triangle +{ + //dReal* v0; + //dReal* v1; + //dReal* v2; + dVector3 side0; + dVector3 side1; + dVector3 norm; + dReal dist; + dReal pos; + dReal depth; + CDB::TRI* T ; + Triangle() + { + T =NULL; +#ifdef DEBUG + depth =-dInfinity; + dist =-dInfinity; +#endif + } +}; \ No newline at end of file diff --git a/xrPhysics/tri-colliderknoopc/dxTriList.h b/xrPhysics/tri-colliderknoopc/dxTriList.h new file mode 100644 index 00000000000..3f019d1cd3f --- /dev/null +++ b/xrPhysics/tri-colliderknoopc/dxTriList.h @@ -0,0 +1,475 @@ +//#include "stdafx.h" +#ifndef __DXTRILIST_INCLUDED__ + +#define __DXTRILIST_INCLUDED__ + + +//#include "../ode_include.h" +#include "../../3rd party/ode/include/ode/common.h" + + + +struct dcVector3{ + + float x, y, z; + + + + dcVector3(){} + + dcVector3(dReal x, dReal y, dReal z){ + + this->x = (float)x; + + this->y = (float)y; + + this->z = (float)z; + + } + + + + dcVector3(const dReal* v){ + + x = (float)v[0]; + + y = (float)v[1]; + + z = (float)v[2]; + + } + + + + ~dcVector3(){} + + + + + operator float* (){ //&slipch + + return reinterpret_cast(this); + } + /* Add */ + + dcVector3 operator+(const dcVector3& v) const{ + + dcVector3 Out; + + Out.x = x + v.x; + + Out.y = y + v.y; + + Out.z = z + v.z; + + return Out; + + } + + + + dcVector3& operator+=(const dcVector3& v){ + + x += v.x; + + y += v.y; + + z += v.z; + + return *this; + + } + + + + /* Sub */ + + dcVector3 operator-(const dcVector3& v) const{ + + dcVector3 Out; + + Out.x = x - v.x; + + Out.y = y - v.y; + + Out.z = z - v.z; + + return Out; + + } + + + + dcVector3& operator-=(const dcVector3& v){ + + x -= v.x; + + y -= v.y; + + z -= v.z; + + return *this; + + } + + + + /* Mul */ + + dcVector3 operator*(const dcVector3& v) const{ + + dcVector3 Out; + + Out.x = x * v.x; + + Out.y = y * v.y; + + Out.z = z * v.z; + + return Out; + + } + + + + dcVector3 operator*(float Scalar) const{ + + dcVector3 Out; + + Out.x = x * Scalar; + + Out.y = y * Scalar; + + Out.z = z * Scalar; + + return Out; + + } + + + + dcVector3& operator*=(const dcVector3& v){ + + x *= v.x; + + y *= v.y; + + z *= v.z; + + return *this; + + } + + + + dcVector3& operator*=(float Scalar){ + + x *= Scalar; + + y *= Scalar; + + z *= Scalar; + + return *this; + + } + + + + /* Div */ + + dcVector3 operator/(const dcVector3& v) const{ + + dcVector3 Out; + + Out.x = x / v.x; + + Out.y = y / v.y; + + Out.z = z / v.z; + + return Out; + + } + + + + dcVector3 operator/(float Scalar) const{ + + dcVector3 Out; + + Out.x = x / Scalar; + + Out.y = y / Scalar; + + Out.z = z / Scalar; + + return Out; + + } + + + + dcVector3& operator/=(const dcVector3& v){ + + x /= v.x; + + y /= v.y; + + z /= v.z; + + return *this; + + } + + + + dcVector3& operator/=(float Scalar){ + + x /= Scalar; + + y /= Scalar; + + z /= Scalar; + + return *this; + + } + + + + /* Negative */ + + dcVector3& operator-(){ + + x = -x; + + y = -y; + + z = -z; + + return *this; + + } + + + + /* Comparison */ + + bool operator==(const dcVector3& v) const{ + + return x == v.x && y == v.y && z == v.z; + + } + + + + bool operator!=(const dcVector3& v) const{ + + return v.x != x || v.y != y || v.z != z; + + } + + + + float DotProduct(const dcVector3& v) const{ + + return x * v.x + y * v.y + z * v.z; + + } + + + + dcVector3 CrossProduct(const dcVector3& v) const{ + + dcVector3 Out; + + Out.x = y * v.z - z * v.y; + + Out.y = z * v.x - x * v.z; + + Out.z = x * v.y - y * v.x; + + return Out; + + } + + + + float MagnitudeSq() const{ + + return DotProduct(*this); + + } + + + + float Magnitude() const{ + + return _sqrt(MagnitudeSq()); + + } + + + + void Normalize(){ + + operator/=(Magnitude()); + + } + + + + /* Member access */ + + float& operator[](int Index){ + + return *(&x + Index); + + } + + + + float operator[](int Index) const{ + + return *(&x + Index); + + } + +}; + + + + + +/* Class ID */ + +extern int dTriListClass; + + + +/* Per triangle callback */ + +typedef int dTriCallback(dGeomID TriList, dGeomID RefObject, int TriangleIndex); + +void dGeomTriListSetCallback(dGeomID g, dTriCallback* Callback); + +dTriCallback* dGeomTriListGetCallback(dGeomID g); + + + +/* Per object callback */ + +typedef void dTriArrayCallback(dGeomID TriList, dGeomID RefObject, const int* TriIndices, int TriCount); + +void dGeomTriListSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback); + +dTriArrayCallback* dGeomTriListGetArrayCallback(dGeomID g); + + + +/* Construction */ + +dxGeom* dCreateTriList(dSpaceID space, dTriCallback* Callback, dTriArrayCallback* ArrayCallback); + + + +/* Setting data */ + +void dGeomTriListBuild(dGeomID g, const dcVector3* Vertices, int VertexCount, const int* Indices, int IndexCount); + + + +/* Getting data */ + +void dGeomTriListGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2); + + + +/* Internal types */ + +class dcTriListCollider; + + + +struct dxTriList{ + + dReal p[4]; // dxPlane + + dTriCallback* Callback; + + dTriArrayCallback* ArrayCallback; + + dcTriListCollider* Collider; + +}; + + + +struct dcPlane{ + + dcVector3 Normal; + + float Distance; + + + + dcPlane(){} + + dcPlane(const dcVector3& v0, const dcVector3& v1, const dcVector3& v2){ + + dcVector3 u = v1 - v0; + + dcVector3 v = v2 - v0; + + + + Normal = u.CrossProduct(v); + + Distance = v0.DotProduct(Normal); + + Normalize(); + + } + + + + void Normalize(){ + + float Factor = 1.0f / Normal.Magnitude(); + + Normal *= Factor; + + Distance *= Factor; + + } + + + + bool Contains(const dcVector3& RefObject, float Epsilon = 0.0f) const{ + + return Normal.DotProduct(RefObject) - Distance >= - Epsilon; //@slipch ">=" instead ">" + + } + +}; + + + +template const T& dcMAX(const T& x, const T& y){ + + return x > y ? x : y; + +} + + + +template const T& dcMIN(const T& x, const T& y){ + + return x < y ? x : y; + +} + + + +#endif //__DXTRILIST_INCLUDED__ \ No newline at end of file diff --git a/xrPhysics/xrPhysics.cpp b/xrPhysics/xrPhysics.cpp new file mode 100644 index 00000000000..af3c8366adc --- /dev/null +++ b/xrPhysics/xrPhysics.cpp @@ -0,0 +1,61 @@ +// xrPhysics.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" +#include "xrPhysics.h" + +#include "../3rd party/ode/include/ode/memory.h" + +#pragma comment(lib,"ode.lib") +#pragma comment(lib,"xrCDB.lib") +#pragma comment( lib, "xrSound.lib" ) +#pragma comment( lib, "xrAPI.lib" ) +//#pragma comment(lib,"xrEngine.lib") + + + + +#ifdef _MANAGED +#pragma managed(push, off) +#endif + + +#ifdef DEBUG_MEMORY_MANAGER + static void * ode_alloc (size_t size) { return Memory.mem_alloc(size,"ODE"); } + static void * ode_realloc (void *ptr, size_t oldsize, size_t newsize) { return Memory.mem_realloc(ptr,newsize,"ODE"); } + static void ode_free (void *ptr, size_t size) { return xr_free(ptr); } +#else // DEBUG_MEMORY_MANAGER + static void * ode_alloc (size_t size) { return xr_malloc(size); } + static void * ode_realloc (void *ptr, size_t oldsize, size_t newsize) { return xr_realloc(ptr,newsize); } + static void ode_free (void *ptr, size_t size) { return xr_free(ptr); } +#endif // DEBUG_MEMORY_MANAGER + + + + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + lpReserved; + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + + dSetAllocHandler (ode_alloc ); + dSetReallocHandler (ode_realloc ); + dSetFreeHandler (ode_free ); + + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; + +} + +#ifdef _MANAGED +#pragma managed(pop) +#endif + diff --git a/xrPhysics/xrPhysics.h b/xrPhysics/xrPhysics.h new file mode 100644 index 00000000000..d4f8ded832c --- /dev/null +++ b/xrPhysics/xrPhysics.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef XRPHYSICS_EXPORTS +#define XRPHYSICS_API __declspec(dllexport) +#else +#define XRPHYSICS_API __declspec(dllimport) + #ifndef _EDITOR + #pragma comment( lib, "xrPhysics.lib" ) + #else + #pragma comment( lib, "xrPhysicsB.lib" ) + #endif +#endif + diff --git a/xrPhysics/xrPhysics.vcproj b/xrPhysics/xrPhysics.vcproj new file mode 100644 index 00000000000..118688ffd94 --- /dev/null +++ b/xrPhysics/xrPhysics.vcproj @@ -0,0 +1,1445 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xrServerEntities/InfoPortionDefs.h b/xrServerEntities/InfoPortionDefs.h new file mode 100644 index 00000000000..38d5f0a5dd8 --- /dev/null +++ b/xrServerEntities/InfoPortionDefs.h @@ -0,0 +1,14 @@ +#pragma once + + +typedef shared_str INFO_DATA; +DEFINE_VECTOR(INFO_DATA, KNOWN_INFO_VECTOR, KNOWN_INFO_VECTOR_IT); + +class CFindByIDPred +{ +public: + CFindByIDPred(shared_str element_to_find) {element = element_to_find;} + IC bool operator () (const INFO_DATA& data) const {return data == element;} +private: + shared_str element; +}; diff --git a/xrServerEntities/ItemListTypes.h b/xrServerEntities/ItemListTypes.h new file mode 100644 index 00000000000..8179c65e252 --- /dev/null +++ b/xrServerEntities/ItemListTypes.h @@ -0,0 +1,53 @@ +//--------------------------------------------------------------------------- +#ifndef ItemListTypesH +#define ItemListTypesH + +//--------------------------------------------------------------------------- + +class ListItem{ + friend class CListHelper; + friend class TItemList; + shared_str key; + int type; + void* item; +public: + typedef fastdelegate::FastDelegate1 TOnListItemFocused; + typedef fastdelegate::FastDelegate1 TOnClick; + TOnClick OnClickEvent; + TOnListItemFocused OnItemFocused; + TOnDrawThumbnail OnDrawThumbnail; +public: + int tag; + LPVOID m_Object; + int icon_index; + u32 prop_color; +public: + enum{ + flShowCB = (1<<0), + flCBChecked = (1<<1), + flDrawThumbnail = (1<<2), + flDrawCanvas = (1<<3), + flSorted = (1<<4), + flHidden = (1<<5), + }; + Flags32 m_Flags; +public: + ListItem (int _type):type(_type),prop_color(0),item(0),key(0),tag(0),icon_index(-1),OnDrawThumbnail(0),OnItemFocused(0),m_Object(0){m_Flags.zero();} + virtual ~ListItem (){}; + void SetName (LPCSTR _key){key=_key;} + + IC void Visible (BOOL val){m_Flags.set(flHidden, !val);} + IC BOOL Visible () const{ return !m_Flags.test(flHidden);} + IC int Type (){return type;} + IC void* Item (){return item;} + IC LPCSTR Key (){return *key;} + IC void SetIcon (int index){icon_index=index;} +}; + +DEFINE_VECTOR (ListItem*,ListItemsVec,ListItemsIt); +//--------------------------------------------------------------------------- +#endif + + + + diff --git a/xrServerEntities/LevelGameDef.cpp b/xrServerEntities/LevelGameDef.cpp new file mode 100644 index 00000000000..2164e2196ac --- /dev/null +++ b/xrServerEntities/LevelGameDef.cpp @@ -0,0 +1,13 @@ +#include "stdafx.h" +#pragma hdrstop + +#include "LevelGameDef.h" + +xr_token rpoint_type[]={ + { "Actor Spawn", rptActorSpawn }, + { "Artefact Spawn", rptArtefactSpawn }, + { "Item Spawn", rptItemSpawn }, + { 0, 0 } +}; + + diff --git a/xrServerEntities/LevelGameDef.h b/xrServerEntities/LevelGameDef.h new file mode 100644 index 00000000000..9d0e29f11b2 --- /dev/null +++ b/xrServerEntities/LevelGameDef.h @@ -0,0 +1,103 @@ +//--------------------------------------------------------------------------- +#ifndef LevelGameDefH +#define LevelGameDefH + +#define RPOINT_CHOOSE_NAME "$rpoint" +#define ENVMOD_CHOOSE_NAME "$env_mod" + +enum EPointType{ + ptRPoint=0, + ptEnvMod, + ptSpawnPoint, + ptMaxType, + pt_force_dword=u32(-1) +}; + +enum EWayType{ + wtPatrolPath=0, + wtMaxType, + wt_force_dword=u32(-1) +}; + +enum ERPpointType{ // [0..255] + rptActorSpawn = 0, + rptArtefactSpawn , + rptItemSpawn , +}; + +enum EEnvModUsedParams{ eViewDist =(1<<0), + eFogColor =(1<<1), + eFogDensity =(1<<2), + eAmbientColor =(1<<3), + eSkyColor =(1<<4), + eHemiColor =(1<<5) +}; + +extern ECORE_API xr_token rpoint_type[]; +extern ECORE_API xr_token rpoint_game_type[]; + +// BASE offset +#define WAY_BASE 0x1000 +#define POINT_BASE 0x2000 + +// POINT chunks +#define RPOINT_CHUNK POINT_BASE+ptRPoint + +// WAY chunks +#define WAY_PATROLPATH_CHUNK WAY_BASE+wtPatrolPath +//---------------------------------------------------- + +#define WAYOBJECT_VERSION 0x0013 +//---------------------------------------------------- +#define WAYOBJECT_CHUNK_VERSION 0x0001 +#define WAYOBJECT_CHUNK_POINTS 0x0002 +#define WAYOBJECT_CHUNK_LINKS 0x0003 +#define WAYOBJECT_CHUNK_TYPE 0x0004 +#define WAYOBJECT_CHUNK_NAME 0x0005 + +/* +- chunk RPOINT_CHUNK + - chunk #0 + vector3 (PPosition); + vector3 (PRotation); + u8 (team_id); + u8 (type) + u16 (reserved) + ... + - chunk #n + +- chunk WAY_PATH_CHUNK + - chunk #0 + chunk WAYOBJECT_CHUNK_VERSION + word (version) + chunk WAYOBJECT_CHUNK_NAME + stringZ (Name) + chunk WAY_CHUNK_TYPE + dword EWayType (type) + chunk WAY_CHUNK_POINTS + word (count) + for (i=0; i +static void r_vec_q8(src& P,Fvector& vec,const Fvector& min,const Fvector& max) +{ + vec.x=P.r_float_q8(min.x,max.x); + vec.y=P.r_float_q8(min.y,max.y); + vec.z=P.r_float_q8(min.z,max.z); + + clamp(vec.x,min.x,max.x); + clamp(vec.y,min.y,max.y); + clamp(vec.z,min.z,max.z); +} +static void w_qt_q8(NET_Packet& P,const Fquaternion& q) +{ + //Fvector Q; + //Q.set(q.x,q.y,q.z); + //if(q.w<0.f) Q.invert(); + //P.w_float_q8(Q.x,-1.f,1.f); + //P.w_float_q8(Q.y,-1.f,1.f); + //P.w_float_q8(Q.z,-1.f,1.f); +/////////////////////////////////////////////////// + P.w_float_q8(q.x,-1.f,1.f); + P.w_float_q8(q.y,-1.f,1.f); + P.w_float_q8(q.z,-1.f,1.f); + P.w_float_q8(q.w,-1.f,1.f); + +/////////////////////////////////////////// + + + //P.w_float_q8(q.x,-1.f,1.f); + //P.w_float_q8(q.y,-1.f,1.f); + //P.w_float_q8(q.z,-1.f,1.f); + //P.w(sign()) +} + +template +static void r_qt_q8(src& P,Fquaternion& q) +{ + //// x^2 + y^2 + z^2 + w^2 = 1 + //P.r_float_q8(q.x,-1.f,1.f); + //P.r_float_q8(q.y,-1.f,1.f); + //P.r_float_q8(q.z,-1.f,1.f); + //float w2=1.f-q.x*q.x-q.y*q.y-q.z*q.z; + //w2=w2<0.f ? 0.f : w2; + //q.w=_sqrt(w2); +///////////////////////////////////////////////////// + /////////////////////////////////////////////////// + q.x=P.r_float_q8(-1.f,1.f); + q.y=P.r_float_q8(-1.f,1.f); + q.z=P.r_float_q8(-1.f,1.f); + q.w=P.r_float_q8(-1.f,1.f); + + clamp(q.x,-1.f,1.f); + clamp(q.y,-1.f,1.f); + clamp(q.z,-1.f,1.f); + clamp(q.w,-1.f,1.f); +} + +#ifdef XRGAME_EXPORTS +/////////////////////////////////16//////////////////////////////////////////////////////////////// +static void w_vec_q16(NET_Packet& P,const Fvector& vec,const Fvector& min,const Fvector& max) +{ + P.w_float_q16(vec.x,min.x,max.x); + P.w_float_q16(vec.y,min.y,max.y); + P.w_float_q16(vec.z,min.z,max.z); +} +static void r_vec_q16(NET_Packet& P,Fvector& vec,const Fvector& min,const Fvector& max) +{ + P.r_float_q16(vec.x,min.x,max.x); + P.r_float_q16(vec.y,min.y,max.y); + P.r_float_q16(vec.z,min.z,max.z); + + //clamp(vec.x,min.x,max.x); + //clamp(vec.y,min.y,max.y); + //clamp(vec.z,min.z,max.z); +} +template +static void w_qt_q16(src& P,const Fquaternion& q) +{ + //Fvector Q; + //Q.set(q.x,q.y,q.z); + //if(q.w<0.f) Q.invert(); + //P.w_float_q16(Q.x,-1.f,1.f); + //P.w_float_q16(Q.y,-1.f,1.f); + //P.w_float_q16(Q.z,-1.f,1.f); + /////////////////////////////////////////// + P.w_float_q16(q.x,-1.f,1.f); + P.w_float_q16(q.y,-1.f,1.f); + P.w_float_q16(q.z,-1.f,1.f); + P.w_float_q16(q.w,-1.f,1.f); +} + +static void r_qt_q16(NET_Packet& P,Fquaternion& q) +{ + // x^2 + y^2 + z^2 + w^2 = 1 + //P.r_float_q16(q.x,-1.f,1.f); + //P.r_float_q16(q.y,-1.f,1.f); + //P.r_float_q16(q.z,-1.f,1.f); + //float w2=1.f-q.x*q.x-q.y*q.y-q.z*q.z; + //w2=w2<0.f ? 0.f : w2; + //q.w=_sqrt(w2); +/////////////////////////////////////////////////// + P.r_float_q16(q.x,-1.f,1.f); + P.r_float_q16(q.y,-1.f,1.f); + P.r_float_q16(q.z,-1.f,1.f); + P.r_float_q16(q.w,-1.f,1.f); + + //clamp(q.x,-1.f,1.f); + //clamp(q.y,-1.f,1.f); + //clamp(q.z,-1.f,1.f); + //clamp(q.w,-1.f,1.f); +} +#endif +/////////////////////////////////////////////////////////////////////////////////// +void SPHNetState::net_Export(NET_Packet& P) +{ + P.w_vec3(linear_vel); + //P.w_vec3(angular_vel); + //P.w_vec3(force); + //P.w_vec3(torque); + P.w_vec3(position); + P.w_vec4(*((Fvector4*)&quaternion)); + //P.w_vec4(*((Fvector4*)&previous_quaternion)); + P.w_u8 ((u8)enabled); + +} +template +void SPHNetState::read (src& P) +{ + linear_vel=P.r_vec3(); + angular_vel.set(0.f,0.f,0.f); //P.r_vec3(angular_vel); + force.set(0.f,0.f,0.f); //P.r_vec3(force); + torque.set(0.f,0.f,0.f); //P.r_vec3(torque); + position=P.r_vec3(); + *((Fvector4*)&quaternion)=P.r_vec4(); + previous_quaternion.set(quaternion);//P.r_vec4(*((Fvector4*)&previous_quaternion)); + enabled=!!P.r_u8 (); +} + +void SPHNetState::net_Import(NET_Packet& P) +{ + read(P); +} +void SPHNetState::net_Import(IReader& P) +{ + read(P); +} + +void SPHNetState::net_Save(NET_Packet &P) +{ + net_Export(P); +} + +void SPHNetState::net_Load(NET_Packet &P) +{ + net_Import(P); + previous_position.set(position); +} +void SPHNetState::net_Load(IReader &P) +{ + net_Import(P); + previous_position.set(position); +} +void SPHNetState::net_Save(NET_Packet &P,const Fvector& min,const Fvector& max) +{ + //P.w_vec3(linear_vel); + //P.w_vec3(angular_vel); + //P.w_vec3(force); + //P.w_vec3(torque); + //P.w_vec3(position); + w_vec_q8(P,position,min,max); + w_qt_q8(P,quaternion); + //P.w_vec4(*((Fvector4*)&quaternion)); + //P.w_vec4(*((Fvector4*)&previous_quaternion)); + P.w_u8 ((u8)enabled); +} +template +void SPHNetState::read(src &P,const Fvector& min,const Fvector& max) +{ +VERIFY( !(fsimilar(min.x,max.x)&&fsimilar(min.y,max.y)&&fsimilar(min.z,max.z)) ); + linear_vel.set(0.f,0.f,0.f); + angular_vel.set(0.f,0.f,0.f); + force.set(0.f,0.f,0.f); + torque.set(0.f,0.f,0.f); + r_vec_q8(P,position,min,max); + previous_position.set(position); + r_qt_q8(P,quaternion); + previous_quaternion.set(quaternion); + enabled=!!P.r_u8(); + +} + +void SPHNetState::net_Load(NET_Packet &P,const Fvector& min,const Fvector& max) +{ +VERIFY( !(fsimilar(min.x,max.x)&&fsimilar(min.y,max.y)&&fsimilar(min.z,max.z)) ); + read(P,min,max); +} +void SPHNetState::net_Load(IReader &P,const Fvector& min,const Fvector& max) +{ +VERIFY( !(fsimilar(min.x,max.x)&&fsimilar(min.y,max.y)&&fsimilar(min.z,max.z)) ); + read(P,min,max); +} +SPHBonesData::SPHBonesData() +{ + bones_mask =u64(-1); + root_bone =0; + + Fvector _mn, _mx; + + _mn.set (-100.f,-100.f,-100.f); + _mx.set (100.f,100.f,100.f); + set_min_max (_mn, _mx); +} +void SPHBonesData::net_Save(NET_Packet &P) +{ + P.w_u64 (bones_mask); + P.w_u16 (root_bone); + + P.w_vec3 (get_min()); + P.w_vec3 (get_max()); + P.w_u16 ((u16)bones.size());//bones number; + PHNETSTATE_I i=bones.begin(),e=bones.end(); + for(;e!=i;i++) + { + (*i).net_Save(P,get_min(),get_max()); + } + // this comment is added by Dima (correct me if this is wrong) + // if we call 2 times in a row StateWrite then we get different results + // WHY??? + // bones.clear (); +} + +void SPHBonesData::net_Load(NET_Packet &P) +{ + bones.clear (); + + bones_mask =P.r_u64(); + root_bone =P.r_u16(); + Fvector _mn, _mx; + P.r_vec3 (_mn); + P.r_vec3 (_mx); + set_min_max (_mn, _mx); + + u16 bones_number =P.r_u16();//bones number /**/ + for(int i=0;i + void read ( src& P); +template + void read ( src& P,const Fvector& min,const Fvector& max); +}; + +DEFINE_VECTOR(SPHNetState,PHNETSTATE_VECTOR,PHNETSTATE_I); + +struct SPHBonesData +{ + u64 bones_mask; + u16 root_bone; + PHNETSTATE_VECTOR bones; + Fvector m_min; + Fvector m_max; +public: + SPHBonesData () ; + void net_Save ( NET_Packet& P); + void net_Load ( NET_Packet& P); + void net_Load ( IReader& P); + void set_min_max (const Fvector& _min, const Fvector& _max); + const Fvector& get_min () const {return m_min;} + const Fvector& get_max () const {return m_max;} +}; +#endif \ No newline at end of file diff --git a/xrServerEntities/PHSynchronize.cpp b/xrServerEntities/PHSynchronize.cpp new file mode 100644 index 00000000000..35c700f273a --- /dev/null +++ b/xrServerEntities/PHSynchronize.cpp @@ -0,0 +1,4 @@ +#include "stdafx.h" +#include "PHSynchronize.h" + + diff --git a/xrServerEntities/PHSynchronize.h b/xrServerEntities/PHSynchronize.h new file mode 100644 index 00000000000..d090b690fe5 --- /dev/null +++ b/xrServerEntities/PHSynchronize.h @@ -0,0 +1,23 @@ +#ifndef PH_SYNCHRONIZE_H +#define PH_SYNCHRONIZE_H + +#include "../xrserverentities/PHNetState.h" + +class NET_Packet; + +class CPHSynchronize +{ +public: + virtual void net_Export ( NET_Packet& P) {}; // export to server + virtual void net_Import ( NET_Packet& P) {}; + virtual void get_State ( SPHNetState& state) =0; + virtual void set_State (const SPHNetState& state) =0; + virtual void cv2obj_Xfrom (const Fquaternion& q,const Fvector& pos, Fmatrix& xform) =0; + virtual void cv2bone_Xfrom (const Fquaternion& q,const Fvector& pos, Fmatrix& xform) =0; +protected: +private: +}; + + + +#endif \ No newline at end of file diff --git a/xrServerEntities/PropertiesListHelper.h b/xrServerEntities/PropertiesListHelper.h new file mode 100644 index 00000000000..bab39cfac18 --- /dev/null +++ b/xrServerEntities/PropertiesListHelper.h @@ -0,0 +1,79 @@ +//--------------------------------------------------------------------------- +#ifndef PropertiesListHelperH +#define PropertiesListHelperH + +// refs +class ListItem; + +//--------------------------------------------------------------------------- +class CPropHelper:public IPropHelper{ + PropItem* CreateItem (PropItemVec& items, const shared_str& key, EPropType type, u32 item_flags=0); + PropValue* AppendValue (PropItemVec& items, const shared_str& key, PropValue* val, EPropType type, u32 item_flags=0); +public: + virtual PropItem* __stdcall FindItem (PropItemVec& items, shared_str key, EPropType type=PROP_UNDEF); +public: +//------------------------------------------------------------------------------ +// predefind event routines + virtual bool __stdcall FvectorRDOnAfterEdit(PropValue* sender, Fvector& edit_val); + virtual void __stdcall FvectorRDOnBeforeEdit(PropValue* sender,Fvector& edit_val); + virtual void __stdcall FvectorRDOnDraw (PropValue* sender, xr_string& draw_val); + virtual bool __stdcall floatRDOnAfterEdit (PropValue* sender, float& edit_val); + virtual void __stdcall floatRDOnBeforeEdit (PropValue* sender, float& edit_val); + virtual void __stdcall floatRDOnDraw (PropValue* sender, xr_string& draw_val); +// R-name edit + virtual void __stdcall NameBeforeEdit (PropValue* sender, shared_str& edit_val); + virtual bool __stdcall NameAfterEdit (PropValue* sender, shared_str& edit_val); + virtual void __stdcall NameDraw (PropValue* sender, xr_string& draw_val); +// C-name edit + virtual void __stdcall CNameBeforeEdit (PropValue* sender, xr_string& edit_val); + virtual bool __stdcall CNameAfterEdit (PropValue* sender, xr_string& edit_val); + virtual void __stdcall CNameDraw (PropValue* sender, xr_string& draw_val); +public: + virtual CaptionValue* __stdcall CreateCaption (PropItemVec& items, shared_str key, shared_str val); + virtual CanvasValue* __stdcall CreateCanvas (PropItemVec& items, shared_str key, shared_str val, int height); + virtual ButtonValue* __stdcall CreateButton (PropItemVec& items, shared_str key, shared_str val, u32 flags, ButtonValue::TOnBtnClick onclick=0); + virtual ChooseValue* __stdcall CreateChoose (PropItemVec& items, shared_str key, shared_str* val, u32 mode, LPCSTR path=0, void* fill_param=0, u32 sub_item_count=1, u32 choose_flags=cfAllowNone); + virtual S8Value* __stdcall CreateS8 (PropItemVec& items, shared_str key, s8* val, s8 mn=0, s8 mx=100, s8 inc=1); + virtual S16Value* __stdcall CreateS16 (PropItemVec& items, shared_str key, s16* val, s16 mn=0, s16 mx=100, s16 inc=1); + virtual S32Value* __stdcall CreateS32 (PropItemVec& items, shared_str key, s32* val, s32 mn=0, s32 mx=100, s32 inc=1); + virtual U8Value* __stdcall CreateU8 (PropItemVec& items, shared_str key, u8* val, u8 mn=0, u8 mx=100, u8 inc=1); + virtual U16Value* __stdcall CreateU16 (PropItemVec& items, shared_str key, u16* val, u16 mn=0, u16 mx=100, u16 inc=1); + virtual U32Value* __stdcall CreateU32 (PropItemVec& items, shared_str key, u32* val, u32 mn=0, u32 mx=100, u32 inc=1); + virtual FloatValue* __stdcall CreateFloat (PropItemVec& items, shared_str key, float* val, float mn=0.f, float mx=1.f, float inc=0.01f, int decim=2); + virtual BOOLValue* __stdcall CreateBOOL (PropItemVec& items, shared_str key, BOOL* val); + virtual VectorValue* __stdcall CreateVector (PropItemVec& items, shared_str key, Fvector* val, float mn=0.f, float mx=1.f, float inc=0.01f, int decim=2); + virtual Flag8Value* __stdcall CreateFlag8 (PropItemVec& items, shared_str key, Flags8* val, u8 mask, LPCSTR c0=0, LPCSTR c1=0, u32 flags=0); + virtual Flag16Value* __stdcall CreateFlag16 (PropItemVec& items, shared_str key, Flags16* val, u16 mask, LPCSTR c0=0, LPCSTR c1=0, u32 flags=0); + virtual Flag32Value* __stdcall CreateFlag32 (PropItemVec& items, shared_str key, Flags32* val, u32 mask, LPCSTR c0=0, LPCSTR c1=0, u32 flags=0); + virtual Token8Value* __stdcall CreateToken8 (PropItemVec& items, shared_str key, u8* val, xr_token* token); + virtual Token16Value* __stdcall CreateToken16 (PropItemVec& items, shared_str key, u16* val, xr_token* token); + virtual Token32Value* __stdcall CreateToken32 (PropItemVec& items, shared_str key, u32* val, xr_token* token); + virtual RToken8Value* __stdcall CreateRToken8 (PropItemVec& items, shared_str key, u8* val, xr_rtoken* token, u32 t_cnt); + virtual RToken16Value* __stdcall CreateRToken16 (PropItemVec& items, shared_str key, u16* val, xr_rtoken* token, u32 t_cnt); + virtual RToken32Value* __stdcall CreateRToken32 (PropItemVec& items, shared_str key, u32* val, xr_rtoken* token, u32 t_cnt); + virtual RListValue* __stdcall CreateRList (PropItemVec& items, shared_str key, shared_str* val, shared_str* lst, u32 cnt); + virtual U32Value* __stdcall CreateColor (PropItemVec& items, shared_str key, u32* val); + virtual ColorValue* __stdcall CreateFColor (PropItemVec& items, shared_str key, Fcolor* val); + virtual VectorValue* __stdcall CreateVColor (PropItemVec& items, shared_str key, Fvector* val); + virtual RTextValue* __stdcall CreateRText (PropItemVec& items, shared_str key, shared_str* val); + virtual STextValue* __stdcall CreateSText (PropItemVec& items, shared_str key, xr_string* val); + virtual WaveValue* __stdcall CreateWave (PropItemVec& items, shared_str key, WaveForm* val); + virtual FloatValue* __stdcall CreateTime (PropItemVec& items, shared_str key, float* val, float mn=0.f, float mx=86400.f); + virtual ShortcutValue* __stdcall CreateShortcut (PropItemVec& items, shared_str key, xr_shortcut* val); + + virtual FloatValue* __stdcall CreateAngle (PropItemVec& items, shared_str key, float* val, float mn=flt_min, float mx=flt_max, float inc=0.01f, int decim=2); + virtual VectorValue* __stdcall CreateAngle3 (PropItemVec& items, shared_str key, Fvector* val, float mn=flt_min, float mx=flt_max, float inc=0.01f, int decim=2); + virtual RTextValue* __stdcall CreateName (PropItemVec& items, shared_str key, shared_str* val, ListItem* owner); + virtual RTextValue* __stdcall CreateNameCB (PropItemVec& items, shared_str key, shared_str* val, TOnDrawTextEvent=0, RTextValue::TOnBeforeEditEvent=0, RTextValue::TOnAfterEditEvent=0); + + virtual GameTypeValue* __stdcall CreateGameType (PropItemVec& items, shared_str key, GameTypeChooser* val); + + // obsolette + virtual CTextValue* __stdcall CreateCText (PropItemVec& items, shared_str key, LPSTR val, u32 sz); + virtual CListValue* __stdcall CreateCList (PropItemVec& items, shared_str key, LPSTR val, u32 sz, xr_string* lst, u32 cnt); + virtual CTextValue* __stdcall CreateCName (PropItemVec& items, shared_str key, LPSTR val, u32 sz, ListItem* owner); + virtual TokenValueSH* __stdcall CreateTokenSH (PropItemVec& items, shared_str key, u32* val, const TokenValueSH::Item* lst, u32 cnt); + virtual CTextValue* __stdcall CreateTexture (PropItemVec& items, shared_str key, LPSTR val, u32 sz); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/xrServerEntities/PropertiesListTypes.h b/xrServerEntities/PropertiesListTypes.h new file mode 100644 index 00000000000..3ed61012386 --- /dev/null +++ b/xrServerEntities/PropertiesListTypes.h @@ -0,0 +1,693 @@ +//--------------------------------------------------------------------------- +#ifndef PropertiesListTypesH +#define PropertiesListTypesH + + +#include "WaveForm.H" +#include "gametype_chooser.h" + +#ifdef __BORLANDC__ +# include "ElTree.hpp" +#endif + +#pragma pack( push,1 ) + +//--------------------------------------------------------------------------- +enum EPropType{ + PROP_UNDEF = -1, + PROP_CAPTION = 0x1000, + PROP_SHORTCUT, + PROP_BUTTON, + PROP_CHOOSE, + PROP_NUMERIC, // {u8,u16,u32,s8,s16,s32,f32} + PROP_BOOLEAN, + PROP_FLAG, + PROP_VECTOR, + PROP_TOKEN, + PROP_RTOKEN, + PROP_RLIST, + PROP_COLOR, + PROP_FCOLOR, + PROP_VCOLOR, + PROP_RTEXT, + PROP_STEXT, + PROP_WAVE, + PROP_CANVAS, + PROP_TIME, + + PROP_CTEXT, + PROP_CLIST, + PROP_SH_TOKEN, + PROP_TEXTURE2, + PROP_GAMETYPE, +}; + +// refs +struct xr_token; +class PropValue; +class PropItem; +DEFINE_VECTOR (PropItem*,PropItemVec,PropItemIt); + +//------------------------------------------------------------------------------ +#include "../xrcore/ChooseTypes.H" +//------------------------------------------------------------------------------ +typedef fastdelegate::FastDelegate2 TOnDrawTextEvent; +typedef fastdelegate::FastDelegate1 TOnClick; +//------------------------------------------------------------------------------ + +class PropValue +{ + friend class CPropHelper; + friend class PropItem; +protected: + PropItem* m_Owner; +public: + u32 tag; +public: + // base events + typedef fastdelegate::FastDelegate1 TOnChange; + TOnChange OnChangeEvent; +public: + PropValue ():tag(0),m_Owner(0),OnChangeEvent(0){;} + virtual ~PropValue (){} + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText)=0; + virtual void ResetValue ()=0; + virtual bool Equal (PropValue* prop)=0; + IC PropItem* Owner (){return m_Owner;} +}; +//------------------------------------------------------------------------------ + +template +IC void set_value(T& val, const T& _val) +{ + val = _val; +}; + +template +class CustomValue: public PropValue +{ +public: + typedef T TYPE; +public: + TYPE init_value; + TYPE* value; +public: + typedef fastdelegate::FastDelegate2 TOnBeforeEditEvent; + typedef fastdelegate::FastDelegate2 TOnAfterEditEvent; + TOnBeforeEditEvent OnBeforeEditEvent; + TOnAfterEditEvent OnAfterEditEvent; +public: + CustomValue (T* val) + { + OnBeforeEditEvent = 0; + OnAfterEditEvent = 0; + set_value (value,val); + set_value (init_value,*val); + }; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText){return "";} + virtual bool Equal (PropValue* val) + { + CustomValue* prop = (CustomValue*)val; + return (*value==*prop->value); + } + virtual const T& GetValue (){return *value; } + virtual void ResetValue (){set_value(*value,init_value);} + bool ApplyValue (const T& val) + { + if (!(*value==val)){ + set_value (*value,val); + return true; + } + return false; + } +}; + +class PropItem +{ + friend class CPropHelper; + friend class TProperties; + shared_str key; + EPropType type; + void* item; +public: + DEFINE_VECTOR (PropValue*,PropValueVec,PropValueIt); +private: + PropValueVec values; + TProperties* m_Owner; +// events +public: + typedef fastdelegate::FastDelegate1 TOnPropItemFocused; + TOnDrawTextEvent OnDrawTextEvent; + TOnPropItemFocused OnItemFocused; + TOnClick OnClickEvent; +public: + u32 prop_color; + u32 val_color; + Irect draw_rect; +public: + enum{ + flDisabled = (1<<0), + flShowCB = (1<<1), + flCBChecked = (1<<2), + flMixed = (1<<3), + flDrawThumbnail = (1<<4), + flSorted = (1<<5), + }; + Flags32 m_Flags; +public: + PropItem (EPropType _type):type(_type),prop_color(0),val_color(0),item(0),key(0),OnClickEvent(0),OnDrawTextEvent(0),OnItemFocused(0){m_Flags.zero();} + virtual ~PropItem () + { + for (PropValueIt it=values.begin(); values.end() != it; ++it) + xr_delete (*it); + }; + IC TProperties* Owner (){return m_Owner;} + void SetName (const shared_str& name) + { + key=name; + } + IC void ResetValues () + { + for (PropValueIt it=values.begin(); values.end() != it; ++it) + (*it)->ResetValue(); + CheckMixed (); + } + IC void AppendValue (PropValue* value) + { + if (!values.empty()&&!value->Equal(values.front())) + m_Flags.set (flMixed,TRUE); + values.push_back(value); + } + IC xr_string GetDrawText () + { + VERIFY(!values.empty()); + return m_Flags.is(flMixed)?xr_string("(mixed)"):values.front()->GetDrawText(OnDrawTextEvent); + } + IC void CheckMixed () + { + m_Flags.set (flMixed,FALSE); + if (values.size()>1){ + PropValueIt F = values.begin(); + PropValueIt it = F; ++it; + for (; values.end() != it; ++it){ + if (!(*it)->Equal(*F)){ + m_Flags.set(flMixed,TRUE); + break; + } + } + } + } + + template + IC void BeforeEdit (T2& val) + { + T1* CV = smart_cast(values.front()); VERIFY(CV); + if (!CV->OnBeforeEditEvent.empty()) CV->OnBeforeEditEvent(CV,val); + } + template + IC bool AfterEdit (T2& val) + { + T1* CV = smart_cast(values.front()); VERIFY(CV); + if (!CV->OnAfterEditEvent.empty()) return CV->OnAfterEditEvent(CV,val); + return true; + } + template + IC bool ApplyValue (const T2& val) + { + bool bChanged = false; + m_Flags.set (flMixed,FALSE); + for (PropValueIt it=values.begin(); values.end() != it; ++it){ + T1* CV = smart_cast(*it); VERIFY(CV); + if (CV->ApplyValue(val)){ + bChanged = true; + if (!CV->OnChangeEvent.empty()) CV->OnChangeEvent(*it); + } + if (!CV->Equal(values.front())) + m_Flags.set (flMixed,TRUE); + } + return bChanged; + } + IC PropValueVec& Values (){return values;} + IC PropValue* GetFrontValue (){VERIFY(!values.empty()); return values.front(); }; + IC EPropType Type (){return type;} +#ifdef __BORLANDC__ + IC TElTreeItem* Item (){return (TElTreeItem*)item;} +#endif + IC LPCSTR Key (){return key.c_str();} + IC void Enable (BOOL val){m_Flags.set(flDisabled,!val);} + IC BOOL Enabled (){return !m_Flags.is(flDisabled);} + IC void OnChange () + { + for (PropValueIt it=values.begin(); values.end() != it; ++it) + if (!(*it)->OnChangeEvent.empty()) + (*it)->OnChangeEvent(*it); + } +/* + template + IC void OnBeforeEdit () + { + for (PropValueIt it=values.begin(); values.end() != it; ++it){ + T1* CV = smart_cast(*it); VERIFY(CV); + if (CV->OnChangeEvent) CV->OnChangeEvent(*it); + } + } +*/ +}; + +//------------------------------------------------------------------------------ +// values +//------------------------------------------------------------------------------ +class CaptionValue: public PropValue{ + shared_str value; +public: + CaptionValue (const shared_str& val){value=val;} + virtual xr_string GetDrawText (TOnDrawTextEvent) {return value.c_str()?value.c_str():"";} + virtual void ResetValue (){;} + virtual bool Equal (PropValue* val) {return (value==((CaptionValue*)val)->value);} + bool ApplyValue (const shared_str& val){value=val; return false;} +}; + +class CanvasValue: public PropValue{ + shared_str value; +public: + typedef fastdelegate::FastDelegate3 TOnTestEqual; + typedef fastdelegate::FastDelegate3 TOnDrawCanvasEvent; +public: + int height; + TOnTestEqual OnTestEqual; + TOnDrawCanvasEvent OnDrawCanvasEvent; +public: + CanvasValue (const shared_str& val, int h):OnDrawCanvasEvent(0),OnTestEqual(0),height(h){value=val;} + virtual xr_string GetDrawText (TOnDrawTextEvent){return value.c_str()?value.c_str():"";} + virtual void ResetValue (){;} + virtual bool Equal (PropValue* val) + { + if (!OnTestEqual.empty()){bool res=true; OnTestEqual(this,(CanvasValue*)val,res); return res;} + return false; + } +}; + +class ButtonValue: public PropValue{ +public: + RStringVec value; + int btn_num; + typedef fastdelegate::FastDelegate3 TOnBtnClick; + TOnBtnClick OnBtnClickEvent; + enum{ + flFirstOnly = (1<<0) + }; + Flags32 m_Flags; +public: + ButtonValue (const shared_str& val, u32 flags) + { + m_Flags.assign (flags); + OnBtnClickEvent = 0; + btn_num = -1; + xr_string v; + int cnt =_GetItemCount(val.c_str()); + for (int k=0; k{ +public: + typedef fastdelegate::FastDelegate3 TOnValidateResult; + TOnValidateResult OnValidateResultEvent; +public: + ShortcutValue (TYPE* val):CustomValue(val){} + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText); + bool ApplyValue (const xr_shortcut& val) + { + if (!(*value==val)){ + bool allow = true; + if (!OnValidateResultEvent.empty()) + OnValidateResultEvent(this,val,allow); + if (allow){ + set_value (*value,val); + return true; + } + } + return false; + } +}; +class RTextValue: public CustomValue{ +public: + RTextValue (TYPE* val):CustomValue(val){}; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string txt = GetValue().c_str()?GetValue().c_str():""; + if (!OnDrawText.empty())OnDrawText(this, txt); + return txt; + } +}; +class STextValue: public CustomValue{ +public: + STextValue (TYPE* val):CustomValue(val){}; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string txt = GetValue(); + if (!OnDrawText.empty())OnDrawText(this, txt); + return txt; + } +}; + +class CTextValue: public PropValue{ + xr_string init_value; +public: + LPSTR value; +public: + typedef fastdelegate::FastDelegate2 TOnBeforeEditEvent; + typedef fastdelegate::FastDelegate2 TOnAfterEditEvent; + TOnBeforeEditEvent OnBeforeEditEvent; + TOnAfterEditEvent OnAfterEditEvent; +public: + int lim; +public: + CTextValue (LPSTR val, int _lim):value(val),init_value(val),lim(_lim) + { + OnBeforeEditEvent = 0; + OnAfterEditEvent = 0; + }; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string txt = GetValue(); + if (!OnDrawText.empty())OnDrawText(this, txt); + return txt; + } + virtual bool Equal (PropValue* val) + { + return (0==xr_strcmp(value,((CTextValue*)val)->value)); + } + bool ApplyValue (LPCSTR val) + { + if (0!=xr_strcmp(value,val)){ + xr_strcpy (value,xr_strlen(val)+1,val); + return true; + } + return false; + } + LPSTR GetValue (){return value;} + virtual void ResetValue (){xr_strcpy(value,init_value.size()+1,init_value.c_str());} +}; +//------------------------------------------------------------------------------ + +class ChooseValue: public RTextValue{ +public: + int subitem; + u32 m_ChooseID; + u32 m_ChooseFlags; + shared_str m_StartPath; + ChooseItemVec* m_Items; + typedef fastdelegate::FastDelegate1 TOnChooseValueFill; + TOnChooseValueFill OnChooseFillEvent; + TOnDrawThumbnail OnDrawThumbnailEvent; + void* m_FillParam; +// utils + void AppendChooseItem (LPCSTR name, LPCSTR hint){VERIFY(m_Items); m_Items->push_back(SChooseItem(name,hint));} +public: + ChooseValue (shared_str* val, u32 cid, LPCSTR path, void* param, u32 sub_item_count, u32 choose_flags):RTextValue(val),m_ChooseID(cid),m_StartPath(path),subitem(sub_item_count),m_Items(0),m_FillParam(param),OnChooseFillEvent(0),OnDrawThumbnailEvent(0),m_ChooseFlags(choose_flags){} +}; + +typedef CustomValue BOOLValue; +//------------------------------------------------------------------------------ + +IC bool operator == (const WaveForm& A, const WaveForm& B){return !!A.Similar(B);} +class WaveValue: public CustomValue{ +public: + WaveValue (TYPE* val):CustomValue(val){}; + virtual xr_string GetDrawText (TOnDrawTextEvent){return "[Wave]";} +}; + +IC bool operator == (const GameTypeChooser& A, const GameTypeChooser& B){return A.m_GameType.flags==B.m_GameType.flags;} +class GameTypeValue: public CustomValue{ +public: + GameTypeValue (TYPE* val):CustomValue(val){}; + virtual xr_string GetDrawText (TOnDrawTextEvent); +}; + +//------------------------------------------------------------------------------ + +IC bool operator == (const Fcolor& A, const Fcolor& B) +{ return !!A.similar_rgba(B); } +typedef CustomValue ColorValue; +//------------------------------------------------------------------------------ + +template +class NumericValue: public CustomValue +{ +public: + T lim_mn; + T lim_mx; + T inc; + int dec; +public: + NumericValue (T* val):CustomValue(val) + { + value = val; + init_value = *value; + dec = 0; + }; + NumericValue (T* val, T mn, T mx, T increm, int decim):CustomValue(val),lim_mn(mn),lim_mx(mx),inc(increm),dec(decim) + { + clamp (*val,lim_mn,lim_mx); + value = val; + init_value = *value; + }; + bool ApplyValue (const T& _val) + { + T val = _val; + clamp (val,lim_mn,lim_mx); + return CustomValue::ApplyValue(val); + } + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string draw_val; + if (!OnDrawText.empty()) OnDrawText(this, draw_val); + else draw_sprintf (draw_val,*value,dec); + return draw_val; + } +}; + +//------------------------------------------------------------------------------ +template +IC xr_string draw_sprintf(xr_string& s, const T& V, int tag) +{ string256 tmp; xr_sprintf(tmp,sizeof(tmp),"%d",V); s=tmp; return s;} +//------------------------------------------------------------------------------ +IC xr_string draw_sprintf(xr_string& s, const float& V, int dec) +{ + string32 fmt; xr_sprintf(fmt,sizeof(fmt),"%%.%df",dec); + string256 tmp; xr_sprintf(tmp,sizeof(tmp),fmt,V); + s = tmp; + return s; +} +//------------------------------------------------------------------------------ +IC bool operator == (const Fvector& A, const Fvector& B) +{ return !!A.similar(B); } +IC void clamp(Fvector& V, const Fvector& mn, const Fvector& mx) +{ + clamp(V.x,mn.x,mx.x); + clamp(V.y,mn.y,mx.y); + clamp(V.z,mn.z,mx.z); +} +IC xr_string draw_sprintf(xr_string& s, const Fvector& V, int dec) +{ + string128 fmt; xr_sprintf(fmt,sizeof(fmt),"{%%.%df, %%.%df, %%.%df}",dec,dec,dec); + string256 tmp; xr_sprintf(tmp,sizeof(tmp),fmt,V.x,V.y,V.z); + s = tmp; + return s; +} +//------------------------------------------------------------------------------ +typedef NumericValue U8Value; +typedef NumericValue U16Value; +typedef NumericValue U32Value; +typedef NumericValue S8Value; +typedef NumericValue S16Value; +typedef NumericValue S32Value; +typedef NumericValue FloatValue; +class VectorValue: public NumericValue{ +public: + VectorValue (Fvector* val, float mn, float mx, float increment, int decimal):NumericValue(val) + { + lim_mn.set (mn,mn,mn); + lim_mx.set (mx,mx,mx); + inc.set (increment,increment,increment); + dec = decimal; + }; +}; +//------------------------------------------------------------------------------ + +class FlagValueCustom +{ +public: + shared_str caption[2]; + enum{ + flInvertedDraw = (1<<0), + }; + Flags32 m_Flags; +public: + FlagValueCustom (u32 mask, LPCSTR c0, LPCSTR c1) + { + caption[0] = c0; + caption[1] = c1; + m_Flags.assign(mask); + } + virtual bool HaveCaption (){return caption[0].size()&&caption[1].size();} + virtual bool GetValueEx ()=0; +}; + +template +class FlagValue: public CustomValue, public FlagValueCustom +{ +public: + typedef T TYPE; + typedef typename T::TYPE FLAG_TYPE; +public: + FLAG_TYPE mask; +public: + FlagValue (T* val, FLAG_TYPE _mask, LPCSTR c0, LPCSTR c1, u32 flags):CustomValue(val),FlagValueCustom(flags,c0,c1),mask(_mask){} + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string draw_val; + if (!OnDrawText.empty()) OnDrawText(this, draw_val); + else return HaveCaption()?caption[GetValueEx()?1:0].c_str():""; + return draw_val; + } + virtual bool Equal (PropValue* val){return !!value->equal(*((FlagValue*)val)->value,mask);} + virtual const T& GetValue () {return *value; } + virtual void ResetValue () {value->set(mask,init_value.is(mask));} + virtual bool GetValueEx () {return !!value->is(mask);} + bool ApplyValue (const T& val) + { + if (!val.equal(*value,mask)){ + value->set (mask,val.is(mask)); + return true; + } + return false; + } +}; +//------------------------------------------------------------------------------ +typedef FlagValue Flag8Value; +typedef FlagValue Flag16Value; +typedef FlagValue Flag32Value; +//------------------------------------------------------------------------------ +template +bool operator == (_flags const & A, _flags const & B){return A.flags==B.flags;} +//------------------------------------------------------------------------------ + +class TokenValueCustom{ +public: + xr_token* token; + TokenValueCustom(xr_token* _token):token(_token){;} +}; +template +class TokenValue: public CustomValue, public TokenValueCustom +{ +public: + TokenValue (T* val, xr_token* _token):TokenValueCustom(_token),CustomValue(val){}; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string draw_val; + if (!OnDrawText.empty()) OnDrawText(this, draw_val); + else for(int i=0; token[i].name; i++) if (token[i].id==(int)GetValue()) return token[i].name; + return draw_val; + } +}; +//------------------------------------------------------------------------------ +typedef TokenValue Token8Value; +typedef TokenValue Token16Value; +typedef TokenValue Token32Value; +//------------------------------------------------------------------------------ + +class RTokenValueCustom{ +public: + xr_rtoken* token; + u32 token_count; + RTokenValueCustom(xr_rtoken* _token, u32 _t_cnt):token(_token),token_count(_t_cnt){;} +}; +template +class RTokenValue: public CustomValue, public RTokenValueCustom +{ +public: + RTokenValue (T* val, xr_rtoken* _token, u32 _t_cnt):CustomValue(val),RTokenValueCustom(_token,_t_cnt){}; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + xr_string draw_val; + if (!OnDrawText.empty()) OnDrawText(this, draw_val); + else for(u32 k=0; k RToken8Value; +typedef RTokenValueRToken16Value; +typedef RTokenValueRToken32Value; +//------------------------------------------------------------------------------ + +class TokenValueSH: public CustomValue{ +public: + struct Item { + u32 ID; + string64 str; + }; + u32 cnt; + const Item* items; +public: + TokenValueSH (u32* val, const Item* _items, u32 _cnt):CustomValue(val),cnt(_cnt),items(_items){}; + virtual xr_string GetDrawText (TOnDrawTextEvent OnDrawText) + { + u32 draw_val = GetValue(); + for(u32 i=0; iitems){ + m_Owner->m_Flags.set(PropItem::flDisabled,TRUE); + return false; + } + return RTextValue::Equal(val); + } +}; +class CListValue: public CTextValue{ +public: + xr_string* items; + u32 item_count; +public: + CListValue (LPSTR val, u32 sz, xr_string* _items, u32 cnt):CTextValue(val,sz),items(_items),item_count(cnt){}; + virtual bool Equal (PropValue* val) + { + if (items!=((CListValue*)val)->items){ + m_Owner->m_Flags.set(PropItem::flDisabled,TRUE); + return false; + } + return CTextValue::Equal(val); + } +}; +//------------------------------------------------------------------------------ +#pragma pack( pop ) + +#endif + + + + diff --git a/xrServerEntities/ShapeData.h b/xrServerEntities/ShapeData.h new file mode 100644 index 00000000000..fccd26da0fc --- /dev/null +++ b/xrServerEntities/ShapeData.h @@ -0,0 +1,24 @@ +#ifndef ShapeDataH +#define ShapeDataH + +struct CShapeData +{ + enum{ + cfSphere=0, + cfBox + }; + union shape_data + { + Fsphere sphere; + Fmatrix box; + }; + struct shape_def + { + u8 type; + shape_data data; + }; + DEFINE_VECTOR (shape_def,ShapeVec,ShapeIt); + ShapeVec shapes; +}; + +#endif \ No newline at end of file diff --git a/xrServerEntities/WaveForm.h b/xrServerEntities/WaveForm.h new file mode 100644 index 00000000000..1ec8e105ef8 --- /dev/null +++ b/xrServerEntities/WaveForm.h @@ -0,0 +1,64 @@ +#ifndef WAVEFORM_H +#define WAVEFORM_H +#pragma once + +#pragma pack(push,4) +struct WaveForm +{ + enum EFunction + { + fCONSTANT = 0, + fSIN, + fTRIANGLE, + fSQUARE, + fSAWTOOTH, + fINVSAWTOOTH, + fFORCE32 = u32(-1) + }; + IC float signf (float t) { return t/_abs(t); } + IC float Func (float t) + { + switch (F) + { + case fCONSTANT: return 0; + case fSIN: return _sin(t*PI_MUL_2); + case fTRIANGLE: return asinf(_sin((t-0.25f)*PI_MUL_2))/PI_DIV_2; + case fSQUARE: return signf(_cos(t*PI)); + case fSAWTOOTH: return atanf(tanf((t+0.5f)*PI))/PI_DIV_2; + case fINVSAWTOOTH: return -(atanf(tanf((t+0.5f)*PI))/PI_DIV_2); + } + return 0.f; + } +public: + EFunction F; + float arg[4]; + + IC float Calculate (float t) + { + // y = arg0 + arg1*func( (time+arg2)*arg3 ) + float x = (t+arg[2])*arg[3]; + return arg[0] + arg[1]*Func(x-floorf(x)); + } + + WaveForm() { + F = fCONSTANT; + arg[0] = 0; + arg[1] = 1; + arg[2] = 0; + arg[3] = 1; + } + + IC BOOL Similar (const WaveForm& W) const + { + if (!fsimilar(arg[0],W.arg[0],EPS_L)) return FALSE; + if (!fsimilar(arg[1],W.arg[1],EPS_L)) return FALSE; + if (fis_zero(arg[1],EPS_L)) return TRUE; + if (F != W.F) return FALSE; + if (!fsimilar(arg[2],W.arg[2],EPS_L)) return FALSE; + if (!fsimilar(arg[3],W.arg[3],EPS_L)) return FALSE; + return TRUE; + } +}; + +#pragma pack(pop) +#endif diff --git a/xrServerEntities/ai_sounds.h b/xrServerEntities/ai_sounds.h new file mode 100644 index 00000000000..66ef42b72d5 --- /dev/null +++ b/xrServerEntities/ai_sounds.h @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : ai_sounds.h +// Created : 15.08.2002 +// Modified : 15.08.2002 +// Author : Dmitriy Iassenev +// Description : Sounds for AI personalities +//////////////////////////////////////////////////////////////////////////// + +#ifndef ai_soundsH +#define ai_soundsH + +enum ESoundTypes { + SOUND_TYPE_NO_SOUND = 0x00000000ui32, + + SOUND_TYPE_WEAPON = 0x80000000ui32, + SOUND_TYPE_ITEM = 0x40000000ui32, + SOUND_TYPE_MONSTER = 0x20000000ui32, + SOUND_TYPE_ANOMALY = 0x10000000ui32, + SOUND_TYPE_WORLD = 0x08000000ui32, + + SOUND_TYPE_PICKING_UP = 0x04000000ui32, + SOUND_TYPE_DROPPING = 0x02000000ui32, + SOUND_TYPE_HIDING = 0x01000000ui32, + SOUND_TYPE_TAKING = 0x00800000ui32, + SOUND_TYPE_USING = 0x00400000ui32, + + SOUND_TYPE_SHOOTING = 0x00200000ui32, + SOUND_TYPE_EMPTY_CLICKING = 0x00100000ui32, + SOUND_TYPE_BULLET_HIT = 0x00080000ui32, + SOUND_TYPE_RECHARGING = 0x00040000ui32, + + SOUND_TYPE_DYING = 0x00020000ui32, + SOUND_TYPE_INJURING = 0x00010000ui32, + SOUND_TYPE_STEP = 0x00008000ui32, + SOUND_TYPE_TALKING = 0x00004000ui32, + SOUND_TYPE_ATTACKING = 0x00002000ui32, + SOUND_TYPE_EATING = 0x00001000ui32, + + SOUND_TYPE_IDLE = 0x00000800ui32, + + SOUND_TYPE_OBJECT_BREAKING = 0x00000400ui32, + SOUND_TYPE_OBJECT_COLLIDING = 0x00000200ui32, + SOUND_TYPE_OBJECT_EXPLODING = 0x00000100ui32, + SOUND_TYPE_AMBIENT = 0x00000080ui32, + + SOUND_TYPE_ITEM_PICKING_UP = SOUND_TYPE_ITEM | SOUND_TYPE_PICKING_UP, + SOUND_TYPE_ITEM_DROPPING = SOUND_TYPE_ITEM | SOUND_TYPE_DROPPING, + SOUND_TYPE_ITEM_HIDING = SOUND_TYPE_ITEM | SOUND_TYPE_HIDING, + SOUND_TYPE_ITEM_TAKING = SOUND_TYPE_ITEM | SOUND_TYPE_TAKING, + SOUND_TYPE_ITEM_USING = SOUND_TYPE_ITEM | SOUND_TYPE_USING, + + SOUND_TYPE_WEAPON_SHOOTING = SOUND_TYPE_WEAPON | SOUND_TYPE_SHOOTING, + SOUND_TYPE_WEAPON_EMPTY_CLICKING = SOUND_TYPE_WEAPON | SOUND_TYPE_EMPTY_CLICKING, + SOUND_TYPE_WEAPON_BULLET_HIT = SOUND_TYPE_WEAPON | SOUND_TYPE_BULLET_HIT, + SOUND_TYPE_WEAPON_RECHARGING = SOUND_TYPE_WEAPON | SOUND_TYPE_RECHARGING, + + SOUND_TYPE_MONSTER_DYING = SOUND_TYPE_MONSTER | SOUND_TYPE_DYING, + SOUND_TYPE_MONSTER_INJURING = SOUND_TYPE_MONSTER | SOUND_TYPE_INJURING, + SOUND_TYPE_MONSTER_STEP = SOUND_TYPE_MONSTER | SOUND_TYPE_STEP, + SOUND_TYPE_MONSTER_TALKING = SOUND_TYPE_MONSTER | SOUND_TYPE_TALKING, + SOUND_TYPE_MONSTER_ATTACKING = SOUND_TYPE_MONSTER | SOUND_TYPE_ATTACKING, + SOUND_TYPE_MONSTER_EATING = SOUND_TYPE_MONSTER | SOUND_TYPE_EATING, + + SOUND_TYPE_ANOMALY_IDLE = SOUND_TYPE_ANOMALY | SOUND_TYPE_IDLE, + + SOUND_TYPE_WORLD_OBJECT_BREAKING = SOUND_TYPE_WORLD | SOUND_TYPE_OBJECT_BREAKING, + SOUND_TYPE_WORLD_OBJECT_COLLIDING = SOUND_TYPE_WORLD | SOUND_TYPE_OBJECT_COLLIDING, + SOUND_TYPE_WORLD_OBJECT_EXPLODING = SOUND_TYPE_WORLD | SOUND_TYPE_OBJECT_EXPLODING, + SOUND_TYPE_WORLD_AMBIENT = SOUND_TYPE_WORLD | SOUND_TYPE_AMBIENT, + + SOUND_TYPE_WEAPON_PISTOL = SOUND_TYPE_WEAPON, + SOUND_TYPE_WEAPON_GUN = SOUND_TYPE_WEAPON, + SOUND_TYPE_WEAPON_SUBMACHINEGUN = SOUND_TYPE_WEAPON, + SOUND_TYPE_WEAPON_MACHINEGUN = SOUND_TYPE_WEAPON, + SOUND_TYPE_WEAPON_SNIPERRIFLE = SOUND_TYPE_WEAPON, + SOUND_TYPE_WEAPON_GRENADELAUNCHER = SOUND_TYPE_WEAPON, + SOUND_TYPE_WEAPON_ROCKETLAUNCHER = SOUND_TYPE_WEAPON, +}; + +#define CROUCH_SOUND_FACTOR .3f +#define ACCELERATED_SOUND_FACTOR .5f + +extern xr_token anomaly_type_token[]; + +#endif diff --git a/xrServerEntities/alife_human_brain.cpp b/xrServerEntities/alife_human_brain.cpp new file mode 100644 index 00000000000..07c0206b8cb --- /dev/null +++ b/xrServerEntities/alife_human_brain.cpp @@ -0,0 +1,115 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_human_brain.cpp +// Created : 06.10.2005 +// Modified : 06.10.2005 +// Author : Dmitriy Iassenev +// Description : ALife human brain class +//////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "alife_human_brain.h" +#include "object_broker.h" +#include "xrServer_Objects_ALife_Monsters.h" + +#ifdef XRGAME_EXPORTS +# include "alife_human_object_handler.h" +# include "alife_monster_movement_manager.h" +# include "alife_monster_detail_path_manager.h" +# include "alife_monster_patrol_path_manager.h" +# include "ai_space.h" +# include "ef_storage.h" +# include "ef_primary.h" +# include "alife_simulator.h" +# include "alife_graph_registry.h" +# include "movement_manager_space.h" +# include "alife_smart_terrain_registry.h" +# include "alife_time_manager.h" +# include "date_time.h" +# ifdef DEBUG +# include "level.h" +# include "map_location.h" +# include "map_manager.h" +# endif +#endif + +#define MAX_ITEM_FOOD_COUNT 3 +#define MAX_ITEM_MEDIKIT_COUNT 3 +#define MAX_AMMO_ATTACH_COUNT 1 + +CALifeHumanBrain::CALifeHumanBrain (object_type *object) : inherited(object) +{ + VERIFY (object); + m_object = object; + +#ifdef XRGAME_EXPORTS + m_object_handler = xr_new(object); +#endif + + m_dwTotalMoney = 0; + m_cpEquipmentPreferences.resize (5); + m_cpMainWeaponPreferences.resize(4); + +#ifdef XRGAME_EXPORTS + m_cpEquipmentPreferences.resize (iFloor(ai().ef_storage().m_pfEquipmentType->ffGetMaxResultValue() + .5f)); + m_cpMainWeaponPreferences.resize(iFloor(ai().ef_storage().m_pfMainWeaponType->ffGetMaxResultValue() + .5f)); + R_ASSERT2 ((iFloor(ai().ef_storage().m_pfEquipmentType->ffGetMaxResultValue() + .5f) == 5) && (iFloor(ai().ef_storage().m_pfMainWeaponType->ffGetMaxResultValue() + .5f) == 4),"Recompile Level Editor and xrAI and rebuild file \"game.spawn\"!"); +#endif + + for (int i=0, n=m_cpEquipmentPreferences.size(); i temp; + load_data (temp,packet); + } + } + + if (object().m_wVersion <= 35) + return; + + if (object().m_wVersion < 110) { + shared_str temp; + packet.r_stringZ (temp); + } + + if (object().m_wVersion < 118) { + ALife::OBJECT_VECTOR temp; + load_data (temp,packet); + } + + if(packet.inistream==NULL) + { + load_data (m_cpEquipmentPreferences,packet); + load_data (m_cpMainWeaponPreferences,packet); + } +} diff --git a/xrServerEntities/alife_human_brain.h b/xrServerEntities/alife_human_brain.h new file mode 100644 index 00000000000..d3d79fa61ef --- /dev/null +++ b/xrServerEntities/alife_human_brain.h @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_human_brain.h +// Created : 06.10.2005 +// Modified : 06.10.2005 +// Author : Dmitriy Iassenev +// Description : ALife human brain class +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "alife_monster_brain.h" + +class CALifeHumanObjectHandler; +class CSE_ALifeHumanAbstract; + +class CALifeHumanBrain : public CALifeMonsterBrain { +private: + typedef CALifeMonsterBrain inherited; + +public: + typedef CSE_ALifeHumanAbstract object_type; + typedef CALifeHumanObjectHandler object_handler_type; + +private: + object_type *m_object; + object_handler_type *m_object_handler; + +// old not yet obsolete stuff +public: + svector m_cpEquipmentPreferences; + svector m_cpMainWeaponPreferences; + +// old, to be obsolete +public: + u32 m_dwTotalMoney; + +public: + CALifeHumanBrain (object_type *object); + virtual ~CALifeHumanBrain (); + +public: + void on_state_write (NET_Packet &packet); + void on_state_read (NET_Packet &packet); + +public: + IC object_type &object () const; + IC object_handler_type &objects () const; + + DECLARE_SCRIPT_REGISTER_FUNCTION +}; +add_to_type_list(CALifeHumanBrain) +#undef script_type_list +#define script_type_list save_type_list(CALifeHumanBrain) + +#include "alife_human_brain_inline.h" \ No newline at end of file diff --git a/xrServerEntities/alife_human_brain_inline.h b/xrServerEntities/alife_human_brain_inline.h new file mode 100644 index 00000000000..367ec35361b --- /dev/null +++ b/xrServerEntities/alife_human_brain_inline.h @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_human_brain_inline.h +// Created : 06.10.2005 +// Modified : 06.10.2005 +// Author : Dmitriy Iassenev +// Description : ALife human brain class inline functions +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +IC CALifeHumanBrain::object_type &CALifeHumanBrain::object () const +{ + VERIFY (m_object); + return (*m_object); +} + +IC CALifeHumanBrain::object_handler_type &CALifeHumanBrain::objects () const +{ + VERIFY (m_object_handler); + return (*m_object_handler); +} diff --git a/xrServerEntities/alife_monster_brain.cpp b/xrServerEntities/alife_monster_brain.cpp new file mode 100644 index 00000000000..800f5c3ed4d --- /dev/null +++ b/xrServerEntities/alife_monster_brain.cpp @@ -0,0 +1,190 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_monster_brain.cpp +// Created : 06.10.2005 +// Modified : 22.11.2005 +// Author : Dmitriy Iassenev +// Description : ALife monster brain class +//////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "alife_monster_brain.h" +#include "object_broker.h" +#include "xrServer_Objects_ALife_Monsters.h" + +#ifdef XRGAME_EXPORTS +# include "alife_monster_movement_manager.h" +# include "alife_monster_detail_path_manager.h" +# include "alife_monster_patrol_path_manager.h" +# include "ai_space.h" +# include "ef_storage.h" +# include "ef_primary.h" +# include "alife_simulator.h" +# include "alife_graph_registry.h" +# include "movement_manager_space.h" +# include "alife_smart_terrain_registry.h" +# include "alife_time_manager.h" +# include "date_time.h" +# ifdef DEBUG +# include "level.h" +# include "map_location.h" +# include "map_manager.h" +# endif +#endif + +#define MAX_ITEM_FOOD_COUNT 3 +#define MAX_ITEM_MEDIKIT_COUNT 3 +#define MAX_AMMO_ATTACH_COUNT 1 + +CALifeMonsterBrain::CALifeMonsterBrain (object_type *object) +{ + VERIFY (object); + m_object = object; + m_last_search_time = 0; + m_smart_terrain = 0; + +#ifdef XRGAME_EXPORTS + m_movement_manager = xr_new(object); +#endif + +#ifdef XRGAME_EXPORTS + u32 hours,minutes,seconds; + sscanf (pSettings->r_string(this->object().name(),"smart_terrain_choose_interval"),"%d:%d:%d",&hours,&minutes,&seconds); + m_time_interval = (u32)generate_time(1,1,1,hours,minutes,seconds); +#endif + + m_can_choose_alife_tasks = true; +} + +CALifeMonsterBrain::~CALifeMonsterBrain () +{ +#ifdef XRGAME_EXPORTS + xr_delete (m_movement_manager); +#endif +} + +void CALifeMonsterBrain::on_state_write (NET_Packet &packet) +{ +} + +void CALifeMonsterBrain::on_state_read (NET_Packet &packet) +{ +} + +#ifdef XRGAME_EXPORTS + +bool CALifeMonsterBrain::perform_attack () +{ + return (false); +} + +ALife::EMeetActionType CALifeMonsterBrain::action_type (CSE_ALifeSchedulable *tpALifeSchedulable, const int &iGroupIndex, const bool &bMutualDetection) +{ + return (ALife::eMeetActionTypeIgnore); +} + +void CALifeMonsterBrain::on_register () +{ +} + +void CALifeMonsterBrain::on_unregister () +{ +} + +void CALifeMonsterBrain::on_location_change () +{ +} + +IC CSE_ALifeSmartZone &CALifeMonsterBrain::smart_terrain () +{ + VERIFY (object().m_smart_terrain_id != 0xffff); + if (m_smart_terrain && (object().m_smart_terrain_id == m_smart_terrain->ID)) + return (*m_smart_terrain); + + m_smart_terrain = ai().alife().smart_terrains().object(object().m_smart_terrain_id); + VERIFY (m_smart_terrain); + return (*m_smart_terrain); +} + +void CALifeMonsterBrain::process_task () +{ + CALifeSmartTerrainTask *task = smart_terrain().task(&object()); + THROW3 (task,"smart terrain returned nil task, while npc is registered in it",smart_terrain().name_replace()); + movement().path_type (MovementManager::ePathTypeGamePath); + movement().detail().target (*task); +} + +void CALifeMonsterBrain::select_task () +{ + if (object().m_smart_terrain_id != 0xffff) + return; + + if (!can_choose_alife_tasks()) + return; + + ALife::_TIME_ID current_time = ai().alife().time_manager().game_time(); + + if (m_last_search_time + m_time_interval > current_time) + return; + + m_last_search_time = current_time; + + float best_value = flt_min; + CALifeSmartTerrainRegistry::OBJECTS::const_iterator I = ai().alife().smart_terrains().objects().begin(); + CALifeSmartTerrainRegistry::OBJECTS::const_iterator E = ai().alife().smart_terrains().objects().end(); + for ( ; I != E; ++I) { + if (!(*I).second->enabled(&object())) + continue; + + float value = (*I).second->suitable(&object()); + if (value > best_value) { + best_value = value; + object().m_smart_terrain_id = (*I).second->ID; + } + } + + if (object().m_smart_terrain_id != 0xffff) { + smart_terrain().register_npc (&object()); + m_last_search_time = 0; + } +} + +void CALifeMonsterBrain::update () +{ +#if 0//def DEBUG + if (!Level().MapManager().HasMapLocation("debug_stalker",object().ID)) { + CMapLocation *map_location = + Level().MapManager().AddMapLocation( + "debug_stalker", + object().ID + ); + + map_location->SetHint (object().name_replace()); + } +#endif + + select_task (); + + if (object().m_smart_terrain_id != 0xffff) + process_task (); + else + default_behaviour (); + + movement().update (); +} + +void CALifeMonsterBrain::default_behaviour () +{ + movement().path_type (MovementManager::ePathTypeNoPath); +} + +void CALifeMonsterBrain::on_switch_online () +{ + movement().on_switch_online (); +} + +void CALifeMonsterBrain::on_switch_offline () +{ + movement().on_switch_offline (); +} + +#endif // XRGAME_EXPORTS \ No newline at end of file diff --git a/xrServerEntities/alife_monster_brain.h b/xrServerEntities/alife_monster_brain.h new file mode 100644 index 00000000000..7dfeea7f55b --- /dev/null +++ b/xrServerEntities/alife_monster_brain.h @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_monster_brain.h +// Created : 06.10.2005 +// Modified : 22.11.2005 +// Author : Dmitriy Iassenev +// Description : ALife monster brain class +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "game_graph_space.h" +#include "xrserver_space.h" +#include "alife_space.h" +#include "script_export_space.h" + +class CSE_ALifeMonsterAbstract; +class CALifeMonsterMovementManager; +class CSE_ALifeSmartZone; +class NET_Packet; + +class CALifeMonsterBrain { +public: + typedef CSE_ALifeMonsterAbstract object_type; + typedef CALifeMonsterMovementManager movement_manager_type; + +private: + object_type *m_object; + movement_manager_type *m_movement_manager; + bool m_can_choose_alife_tasks; + +public: + CSE_ALifeSmartZone *m_smart_terrain; + ALife::_TIME_ID m_last_search_time; + ALife::_TIME_ID m_time_interval; + +// sad, but true +public: + void select_task (); + +private: + void process_task (); + void default_behaviour (); + IC bool can_choose_alife_tasks () const; + +public: + CALifeMonsterBrain (object_type *object); + virtual ~CALifeMonsterBrain (); + +public: + void on_state_write (NET_Packet &packet); + void on_state_read (NET_Packet &packet); + void on_register (); + void on_unregister (); + void on_location_change (); + void on_switch_online (); + void on_switch_offline (); + +public: + void update (); + bool perform_attack (); + ALife::EMeetActionType action_type (CSE_ALifeSchedulable *tpALifeSchedulable, const int &iGroupIndex, const bool &bMutualDetection); + +public: + IC object_type &object () const; + IC movement_manager_type &movement () const; + IC CSE_ALifeSmartZone &smart_terrain (); + IC void can_choose_alife_tasks (bool value); + + DECLARE_SCRIPT_REGISTER_FUNCTION +}; +add_to_type_list(CALifeMonsterBrain) +#undef script_type_list +#define script_type_list save_type_list(CALifeMonsterBrain) + +#include "alife_monster_brain_inline.h" \ No newline at end of file diff --git a/xrServerEntities/alife_monster_brain_inline.h b/xrServerEntities/alife_monster_brain_inline.h new file mode 100644 index 00000000000..10bad40cf0b --- /dev/null +++ b/xrServerEntities/alife_monster_brain_inline.h @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_monster_brain_inline.h +// Created : 06.10.2005 +// Modified : 22.11.2005 +// Author : Dmitriy Iassenev +// Description : ALife monster brain class inline functions +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +IC CALifeMonsterBrain::object_type &CALifeMonsterBrain::object () const +{ + VERIFY (m_object); + return (*m_object); +} + +IC CALifeMonsterBrain::movement_manager_type &CALifeMonsterBrain::movement () const +{ + VERIFY (m_movement_manager); + return (*m_movement_manager); +} + +IC bool CALifeMonsterBrain::can_choose_alife_tasks () const +{ + return (m_can_choose_alife_tasks); +} + +IC void CALifeMonsterBrain::can_choose_alife_tasks (bool value) +{ + m_can_choose_alife_tasks = value; +} diff --git a/xrServerEntities/alife_movement_manager_holder.h b/xrServerEntities/alife_movement_manager_holder.h new file mode 100644 index 00000000000..0dc80da0ccb --- /dev/null +++ b/xrServerEntities/alife_movement_manager_holder.h @@ -0,0 +1,27 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_movement_manager_holder.h +// Created : 24.07.2009 +// Modified : 24.07.2009 +// Author : Plichko Alexander +// Description : movement manager holder +//////////////////////////////////////////////////////////////////////////// +#pragma once; + +class CMovementManagerHolder { +public: + GameGraph::_GRAPH_ID m_tNextGraphID; + GameGraph::_GRAPH_ID m_tPrevGraphID; + float m_fGoingSpeed; + float m_fCurrentLevelGoingSpeed; + float m_fCurSpeed; + float m_fDistanceFromPoint; + float m_fDistanceToPoint; + GameGraph::TERRAIN_VECTOR m_tpaTerrain; + +#ifdef XRGAME_EXPORTS +public: + virtual void on_location_change ( ) const = 0; + virtual CSE_ALifeDynamicObject const& get_object ( ) const = 0; + virtual CSE_ALifeDynamicObject& get_object ( ) = 0; +#endif //#ifdef XRGAME_EXPORTS +}; // CMovementManagerHolder \ No newline at end of file diff --git a/xrServerEntities/alife_space.cpp b/xrServerEntities/alife_space.cpp new file mode 100644 index 00000000000..99bb694aaa2 --- /dev/null +++ b/xrServerEntities/alife_space.cpp @@ -0,0 +1,22 @@ +#include "stdafx.h" +#include "alife_space.h" + +namespace ALife { + +xr_token hit_types_token [ ]={ + { "burn", eHitTypeBurn }, + { "shock", eHitTypeShock }, + { "strike", eHitTypeStrike }, + { "wound", eHitTypeWound }, + { "radiation", eHitTypeRadiation }, + { "telepatic", eHitTypeTelepatic }, + { "fire_wound", eHitTypeFireWound }, + { "chemical_burn", eHitTypeChemicalBurn }, + { "explosion", eHitTypeExplosion }, + { "wound_2", eHitTypeWound_2 }, +// { "physic_strike", eHitTypePhysicStrike }, + { "light_burn", eHitTypeLightBurn }, + { 0, 0 } +}; + +}; \ No newline at end of file diff --git a/xrServerEntities/alife_space.h b/xrServerEntities/alife_space.h new file mode 100644 index 00000000000..5543e1310c1 --- /dev/null +++ b/xrServerEntities/alife_space.h @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : alife_space.h +// Created : 08.01.2002 +// Modified : 08.01.2003 +// Author : Dmitriy Iassenev +// Description : ALife space +//////////////////////////////////////////////////////////////////////////// + +#ifndef XRAY_ALIFE_SPACE +#define XRAY_ALIFE_SPACE +//#include "../xrcore/_std_extensions.h" + +// ALife objects, events and tasks +#define ALIFE_VERSION 0x0006 +#define ALIFE_CHUNK_DATA 0x0000 +#define SPAWN_CHUNK_DATA 0x0001 +#define OBJECT_CHUNK_DATA 0x0002 +#define GAME_TIME_CHUNK_DATA 0x0005 +#define REGISTRY_CHUNK_DATA 0x0009 +#define SECTION_HEADER "location_" +#define SAVE_EXTENSION ".scop" +#define SPAWN_NAME "game.spawn" +// inventory rukzak size +#define MAX_ITEM_VOLUME 100 +#define INVALID_STORY_ID ALife::_STORY_ID(-1) +#define INVALID_SPAWN_STORY_ID ALife::_SPAWN_STORY_ID(-1) + +class CSE_ALifeDynamicObject; +class CSE_ALifeMonsterAbstract; +class CSE_ALifeTrader; +class CSE_ALifeInventoryItem; +class CSE_ALifeItemWeapon; +class CSE_ALifeSchedulable; +class CGameGraph; + +namespace ALife { + typedef u64 _CLASS_ID; // Class ID + typedef u16 _OBJECT_ID; // Object ID + typedef u64 _TIME_ID; // Time ID + typedef u32 _EVENT_ID; // Event ID + typedef u32 _TASK_ID; // Event ID + typedef u16 _SPAWN_ID; // Spawn ID + typedef u16 _TERRAIN_ID; // Terrain ID + typedef u32 _STORY_ID; // Story ID + typedef u32 _SPAWN_STORY_ID; // Spawn Story ID + + struct SSumStackCell { + int i1; + int i2; + int iCurrentSum; + }; + + enum ECombatResult { + eCombatResultRetreat1 = u32(0), + eCombatResultRetreat2, + eCombatResultRetreat12, + eCombatResult1Kill2, + eCombatResult2Kill1, + eCombatResultBothKilled, + eCombatDummy = u32(-1), + }; + + enum ECombatAction { + eCombatActionAttack = u32(0), + eCombatActionRetreat, + eCombatActionDummy = u32(-1), + }; + + enum EMeetActionType { + eMeetActionTypeAttack = u32(0), + eMeetActionTypeInteract, + eMeetActionTypeIgnore, + eMeetActionSmartTerrain, + eMeetActionTypeDummy = u32(-1), + }; + + enum ERelationType { + eRelationTypeFriend = u32(0), + eRelationTypeNeutral, + eRelationTypeEnemy, + eRelationTypeWorstEnemy, + eRelationTypeLast, + eRelationTypeDummy = u32(-1), + }; + + enum EHitType { + eHitTypeBurn = u32(0), + eHitTypeShock, + eHitTypeChemicalBurn, + eHitTypeRadiation, + eHitTypeTelepatic, + eHitTypeWound, + eHitTypeFireWound, + eHitTypeStrike, + eHitTypeExplosion, + eHitTypeWound_2, //knife's alternative fire +// eHitTypePhysicStrike, + eHitTypeLightBurn, + eHitTypeMax, + }; + + enum EInfluenceType { + infl_rad = u32(0), + infl_fire, + infl_acid, + infl_psi, + infl_electra, + infl_max_count + }; + + enum EConditionRestoreType { + eHealthRestoreSpeed = u32(0), + eSatietyRestoreSpeed, + ePowerRestoreSpeed, + eBleedingRestoreSpeed, + eRadiationRestoreSpeed, + eRestoreTypeMax, + }; + + enum ETakeType { + eTakeTypeAll, + eTakeTypeMin, + eTakeTypeRest, + }; + + enum EWeaponPriorityType { + eWeaponPriorityTypeKnife = u32(0), + eWeaponPriorityTypeSecondary, + eWeaponPriorityTypePrimary, + eWeaponPriorityTypeGrenade, + eWeaponPriorityTypeDummy = u32(-1), + }; + + enum ECombatType { + eCombatTypeMonsterMonster = u32(0), + eCombatTypeMonsterAnomaly, + eCombatTypeAnomalyMonster, + eCombatTypeSmartTerrain, + eCombatTypeDummy = u32(-1), + }; + + //����������� ����������� ������� + enum EWeaponAddonStatus{ + eAddonDisabled = 0, //������ ������������ + eAddonPermanent = 1, //��������� ���������� �� ��������� + eAddonAttachable = 2 //����� ������������ + }; + + IC EHitType g_tfString2HitType(LPCSTR caHitType) + { + if (!stricmp(caHitType,"burn")) + return(eHitTypeBurn); + else if (!stricmp(caHitType,"light_burn")) + return(eHitTypeLightBurn); + else if (!stricmp(caHitType,"shock")) + return(eHitTypeShock); + else if (!stricmp(caHitType,"strike")) + return(eHitTypeStrike); + else if (!stricmp(caHitType,"wound")) + return(eHitTypeWound); + else if (!stricmp(caHitType,"radiation")) + return(eHitTypeRadiation); + else if (!stricmp(caHitType,"telepatic")) + return(eHitTypeTelepatic); + else if (!stricmp(caHitType,"fire_wound")) + return(eHitTypeFireWound); + else if (!stricmp(caHitType,"chemical_burn")) + return(eHitTypeChemicalBurn); + else if (!stricmp(caHitType,"explosion")) + return(eHitTypeExplosion); + else if (!stricmp(caHitType,"wound_2")) + return(eHitTypeWound_2); + else + FATAL ("Unsupported hit type!"); + NODEFAULT; +#ifdef DEBUG + return(eHitTypeMax); +#endif + } +#ifndef _EDITOR +xr_token hit_types_token [ ]; + + IC LPCSTR g_cafHitType2String(EHitType tHitType) + { + return get_token_name(hit_types_token, tHitType); + } +#endif + DEFINE_VECTOR (int, INT_VECTOR, INT_IT); + DEFINE_VECTOR (_OBJECT_ID, OBJECT_VECTOR, OBJECT_IT); + DEFINE_VECTOR (CSE_ALifeInventoryItem*, ITEM_P_VECTOR, ITEM_P_IT); + DEFINE_VECTOR (CSE_ALifeItemWeapon*, WEAPON_P_VECTOR, WEAPON_P_IT); + DEFINE_VECTOR (CSE_ALifeSchedulable*, SCHEDULE_P_VECTOR, SCHEDULE_P_IT); + + DEFINE_MAP (_OBJECT_ID, CSE_ALifeDynamicObject*, D_OBJECT_P_MAP, D_OBJECT_P_PAIR_IT); + DEFINE_MAP (_STORY_ID, CSE_ALifeDynamicObject*, STORY_P_MAP, STORY_P_PAIR_IT); +}; + +#endif //XRAY_ALIFE_SPACE \ No newline at end of file diff --git a/xrServerEntities/associative_vector.h b/xrServerEntities/associative_vector.h new file mode 100644 index 00000000000..c8bcec6b427 --- /dev/null +++ b/xrServerEntities/associative_vector.h @@ -0,0 +1,150 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : associative_vector.h +// Created : 14.10.2005 +// Modified : 14.10.2005 +// Author : Dmitriy Iassenev +// Description : associative vector container +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "associative_vector_compare_predicate.h" + +template < + typename _key_type, + typename _data_type, + typename _compare_predicate_type = std::less<_key_type> +> +class associative_vector : + protected + xr_vector< + std::pair< + _key_type, + _data_type + > + >, + protected + associative_vector_compare_predicate< + _key_type, + _data_type, + _compare_predicate_type + > +{ +private: + typedef + associative_vector< + _key_type, + _data_type, + _compare_predicate_type + > self_type; + + typedef + xr_vector< + std::pair< + _key_type, + _data_type + > + > inherited; + +public: + typedef + associative_vector_compare_predicate< + _key_type, + _data_type, + _compare_predicate_type + > value_compare; + +public: + typedef typename inherited::allocator_type allocator_type; + typedef typename inherited::const_pointer const_pointer; + typedef typename inherited::const_reference const_reference; + typedef typename inherited::const_iterator const_iterator; + typedef typename inherited::const_reverse_iterator const_reverse_iterator; + typedef typename inherited::pointer pointer; + typedef typename inherited::reference reference; + typedef typename inherited::iterator iterator; + typedef typename inherited::reverse_iterator reverse_iterator; + typedef typename allocator_type::difference_type difference_type; + typedef _compare_predicate_type key_compare; + typedef _key_type key_type; + typedef _data_type mapped_type; + typedef typename inherited::size_type size_type; + typedef typename inherited::value_type value_type; + typedef std::pair insert_result; + typedef std::pair equal_range_result; + typedef std::pair const_equal_range_result; + +private: + IC void actualize () const; + +public: + template + IC associative_vector (_iterator_type first, _iterator_type last, const key_compare &predicate = key_compare(), const allocator_type &allocator = allocator_type()); + IC associative_vector (const key_compare &predicate = key_compare(), const allocator_type &allocator = allocator_type()); + IC explicit associative_vector (const key_compare &predicate); + IC iterator begin (); + IC iterator end (); + IC reverse_iterator rbegin (); + IC iterator rend (); + IC insert_result insert (const value_type &value); + IC iterator insert (iterator where, const value_type &value); + template + IC void insert (_iterator_type first, _iterator_type last); + IC void erase (iterator element); + IC void erase (iterator first, iterator last); + IC size_type erase (const key_type &key); + IC void clear (); + IC iterator find (const key_type &key); + IC iterator lower_bound (const key_type &key); + IC iterator upper_bound (const key_type &key); + IC equal_range_result equal_range (const key_type &key); + IC void swap (self_type &object); + +public: + IC const_iterator begin () const; + IC const_iterator end () const; + IC const_reverse_iterator rbegin () const; + IC const_reverse_iterator rend () const; + IC const_iterator find (const key_type &key) const; + IC const_iterator lower_bound (const key_type &key) const; + IC const_iterator upper_bound (const key_type &key) const; + IC const_equal_range_result equal_range (const key_type &key) const; + IC size_type count (const key_type &key) const; + IC size_type max_size () const; +// IC size_type size () const; + IC u32 size () const; + IC bool empty () const; + IC key_compare key_comp () const; + IC value_compare value_comp () const; + IC allocator_type get_allocator () const; + +public: + IC mapped_type &operator[] (const key_type &key); + IC self_type &operator= (const self_type &right); + IC bool operator< (const self_type &right) const; + IC bool operator<= (const self_type &right) const; + IC bool operator> (const self_type &right) const; + IC bool operator>= (const self_type &right) const; + IC bool operator== (const self_type &right) const; + IC bool operator!= (const self_type &right) const; +}; + +template < + typename _key_type, + typename _data_type, + typename _compare_predicate_type +> +IC void swap ( + associative_vector< + _key_type, + _data_type, + _compare_predicate_type + > &left, + associative_vector< + _key_type, + _data_type, + _compare_predicate_type + > &right + ); + +#include "associative_vector_inline.h" \ No newline at end of file diff --git a/xrServerEntities/associative_vector_compare_predicate.h b/xrServerEntities/associative_vector_compare_predicate.h new file mode 100644 index 00000000000..5893522faa7 --- /dev/null +++ b/xrServerEntities/associative_vector_compare_predicate.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : associative_vector_compare_predicate.h +// Created : 14.10.2005 +// Modified : 14.10.2005 +// Author : Dmitriy Iassenev +// Description : associative vector compare predicate template class +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +template < + typename _key_type, + typename _data_type, + typename _compare_predicate_type +> +class associative_vector_compare_predicate : public _compare_predicate_type { +private: + typedef _compare_predicate_type inherited; + +public: + typedef _key_type _key_type; + typedef _data_type _data_type; + typedef _compare_predicate_type _compare_predicate_type; + +public: + typedef std::pair<_key_type, _data_type> value_type; + +public: + IC associative_vector_compare_predicate (); + IC associative_vector_compare_predicate (const _compare_predicate_type &compare_predicate); + IC bool operator() (const _key_type &lhs, const _key_type &rhs) const; + IC bool operator() (const value_type &lhs, const value_type &rhs) const; + IC bool operator() (const value_type &lhs, const _key_type &rhs) const; + IC bool operator() (const _key_type &lhs, const value_type &rhs) const; +}; + +#include "associative_vector_compare_predicate_inline.h" \ No newline at end of file diff --git a/xrServerEntities/associative_vector_compare_predicate_inline.h b/xrServerEntities/associative_vector_compare_predicate_inline.h new file mode 100644 index 00000000000..f9e6e5b2030 --- /dev/null +++ b/xrServerEntities/associative_vector_compare_predicate_inline.h @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : associative_vector_compare_inline.h +// Created : 14.10.2005 +// Modified : 14.10.2005 +// Author : Dmitriy Iassenev +// Description : associative vector compare predicate template class inline functions +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define TEMPLATE_SPECIALIZATION \ + template <\ + typename _key_type,\ + typename _value_type,\ + typename _compare_predicate_type\ + > + +#define _associative_vector_compare_predicate \ + associative_vector_compare_predicate<\ + _key_type,\ + _value_type,\ + _compare_predicate_type\ + > + +TEMPLATE_SPECIALIZATION +IC _associative_vector_compare_predicate::associative_vector_compare_predicate () +{ +} + +TEMPLATE_SPECIALIZATION +IC _associative_vector_compare_predicate::associative_vector_compare_predicate (const _compare_predicate_type &compare_predicate) : + inherited (compare_predicate) +{ +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector_compare_predicate::operator() (const _key_type &lhs, const _key_type &rhs) const +{ + return (inherited::operator()(lhs, rhs)); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector_compare_predicate::operator() (const value_type &lhs, const value_type &rhs) const +{ + return (operator()(lhs.first, rhs.first)); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector_compare_predicate::operator() (const value_type &lhs, const _key_type &rhs) const +{ + return (operator()(lhs.first, rhs)); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector_compare_predicate::operator() (const _key_type &lhs, const value_type &rhs) const +{ + return (operator()(lhs, rhs.first)); +} + +#undef TEMPLATE_SPECIALIZATION +#undef _associative_vector_compare_predicate \ No newline at end of file diff --git a/xrServerEntities/associative_vector_inline.h b/xrServerEntities/associative_vector_inline.h new file mode 100644 index 00000000000..1b9a387cbd0 --- /dev/null +++ b/xrServerEntities/associative_vector_inline.h @@ -0,0 +1,383 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : associative_vector_inline.h +// Created : 14.10.2005 +// Modified : 14.10.2005 +// Author : Dmitriy Iassenev +// Description : associative vector container inline functions +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define TEMPLATE_SPECIALIZATION \ + template <\ + typename _key_type,\ + typename _data_type,\ + typename _compare_predicate_type\ + > + +#define _associative_vector \ + associative_vector<\ + _key_type,\ + _data_type,\ + _compare_predicate_type\ + > + +TEMPLATE_SPECIALIZATION +IC _associative_vector::associative_vector (const key_compare &predicate, const allocator_type &allocator) : +// inherited (allocator), + value_compare (predicate) +{ +} + +TEMPLATE_SPECIALIZATION +IC _associative_vector::associative_vector (const key_compare &predicate) : + value_compare (predicate) +{ +} + +TEMPLATE_SPECIALIZATION +template +IC _associative_vector::associative_vector (_iterator_type first, _iterator_type last, const key_compare &predicate = key_compare(), const allocator_type &allocator = allocator_type()) : +// inherited (first,last,allocator), + inherited (first,last), + value_compare (predicate) +{ + std::sort (begin(),end(),(value_compare&)(*this)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::begin () +{ + actualize (); + return (inherited::begin()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::end () +{ + actualize (); + return (inherited::end()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_iterator _associative_vector::begin () const +{ + actualize (); + return (inherited::begin()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_iterator _associative_vector::end () const +{ + actualize (); + return (inherited::end()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::reverse_iterator _associative_vector::rbegin () +{ + actualize (); + return (inherited::rbegin()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::rend () +{ + actualize (); + return (inherited::rend()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_reverse_iterator _associative_vector::rbegin () const +{ + actualize (); + return (inherited::rbegin()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_reverse_iterator _associative_vector::rend () const +{ + actualize (); + return (inherited::rend()); +} + +TEMPLATE_SPECIALIZATION +IC void _associative_vector::clear () +{ + inherited::clear (); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::size_type _associative_vector::max_size () const +{ + return (inherited::max_size()); +} + +TEMPLATE_SPECIALIZATION +//IC typename _associative_vector::size_type _associative_vector::size () const +IC u32 _associative_vector::size () const +{ + return (inherited::size()); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::empty () const +{ + return (inherited::empty()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::allocator_type _associative_vector::get_allocator () const +{ + return (inherited::get_allocator()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::mapped_type &_associative_vector::operator[] (const key_type &key) +{ + iterator I = find(key); + if (I != end()) + return ((*I).second); + + return (insert(value_type(key,mapped_type())).first->second); +} + +TEMPLATE_SPECIALIZATION +IC void _associative_vector::swap (self_type &right) +{ + inherited::swap (right); +} + +TEMPLATE_SPECIALIZATION +IC void swap (_associative_vector &left, _associative_vector &right) +{ + left.swap (right); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::key_compare _associative_vector::key_comp () const +{ + return (key_compare()); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::value_compare _associative_vector::value_comp () const +{ + return (value_compare(key_comp())); +} + +TEMPLATE_SPECIALIZATION +IC void _associative_vector::erase (iterator element) +{ + inherited::erase (element); +} + +TEMPLATE_SPECIALIZATION +IC void _associative_vector::erase (iterator first, iterator last) +{ + inherited::erase (first,last); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::size_type _associative_vector::erase (const key_type &key) +{ + iterator I = find(key); + if (I == end()) + return (0); + + erase (I); + return (1); +} + +TEMPLATE_SPECIALIZATION +IC void _associative_vector::actualize () const +{ +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::lower_bound (const key_type &key) +{ + actualize (); + value_compare &self = *this; + return (std::lower_bound(begin(),end(),key,self)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_iterator _associative_vector::lower_bound (const key_type &key) const +{ + actualize (); + const value_compare &self = *this; + return (std::lower_bound(begin(),end(),key,self)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::upper_bound (const key_type &key) +{ + actualize (); + value_compare &self = *this; + return (std::upper_bound(begin(),end(),key,self)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_iterator _associative_vector::upper_bound (const key_type &key) const +{ + actualize (); + const value_compare &self = *this; + return (std::upper_bound(begin(),end(),key,self)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::insert_result _associative_vector::insert (const value_type &value) +{ + actualize (); + bool found = true; + iterator I = lower_bound(value.first); + if (I == end() || operator()(value.first,(*I).first)) { + I = inherited::insert(I,value); + found = false; + } + else + *I = value; + return (insert_result(I,!found)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::insert (iterator where, const value_type &value) +{ + if ( + (where != end()) && + (operator()(*where,value)) && + ((where - begin()) == size()) && + (!operator()(value,*(where + 1))) && + (operator()(*(where + 1),value)) + ) + return (inherited::insert(where,value)); + + return (insert(val).first); +} + +TEMPLATE_SPECIALIZATION +template +IC void _associative_vector::insert (_iterator_type first, _iterator_type last) +{ + if ((last - first) < log2(size() + (last - first))) { + for ( ; first != last; ++first) + insert (*first); + + return; + } + + inherited::insert (end(),first,last); + std::sort (begin(),end(),(value_compare&)(*this)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::iterator _associative_vector::find (const key_type &key) +{ + actualize (); + iterator I = lower_bound(key); + if (I == end()) + return (end()); + + if (operator()(key,(*I).first)) + return (end()); + + return (I); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_iterator _associative_vector::find (const key_type &key) const +{ + actualize (); + const_iterator I = lower_bound(key); + if (I == end()) + return (end()); + + if (operator()(key,(*I).first)) + return (end()); + + return (I); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::size_type _associative_vector::count (const key_type &key) const +{ + actualize (); + return (find(key) == end() ? 0 : 1); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::equal_range_result _associative_vector::equal_range (const key_type &key) +{ + actualize (); + iterator I = lower_bound(key); + if (I == end()) + return (equal_range_result(end(),end())); + + if (operator()(key,(*I).first)) + return (equal_range_result(I,I)); + + VERIFY (!operator()(key,(*I).first)); + return (equal_range_result(I,I+1)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::const_equal_range_result _associative_vector::equal_range (const key_type &key) const +{ + actualize (); + const_iterator I = lower_bound(key); + if (I == end()) + return (const_equal_range_result(end(),end())); + + if (operator()(key,(*I).first)) + return (const_equal_range_result(I,I)); + + VERIFY (!operator()(key,(*I).first)); + return (const_equal_range_result(I,I+1)); +} + +TEMPLATE_SPECIALIZATION +IC typename _associative_vector::self_type &_associative_vector::operator= (const self_type &right) +{ + (inherited&)(*this) = right; + return (*this); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::operator< (const self_type &right) const +{ + return (((const inherited &)(*this)) < right); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::operator<= (const self_type &right) const +{ + return !(right < left); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::operator> (const self_type &right) const +{ + return (right < left); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::operator>= (const self_type &right) const +{ + return !(left < right); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::operator== (const self_type &right) const +{ + return (((const inherited &)(*this)) == right); +} + +TEMPLATE_SPECIALIZATION +IC bool _associative_vector::operator!= (const self_type &right) const +{ + return !(left == right); +} + +#undef TEMPLATE_SPECIALIZATION +#undef _associative_vector \ No newline at end of file diff --git a/xrServerEntities/character_info.cpp b/xrServerEntities/character_info.cpp new file mode 100644 index 00000000000..dd62f69f0c6 --- /dev/null +++ b/xrServerEntities/character_info.cpp @@ -0,0 +1,197 @@ +////////////////////////////////////////////////////////////////////////// +// character_info.cpp ������� ���������� ��� ���������� � ���� +// +////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "character_info.h" + +#ifdef XRGAME_EXPORTS +# include "ui/xrUIXmlParser.h" +# include "PhraseDialog.h" +# include "xrServer_Objects_ALife_Monsters.h" +#else // XRGAME_EXPORTS +# include "xrUIXmlParser.h" +#endif // XRGAME_EXPORTS + +////////////////////////////////////////////////////////////////////////// +SCharacterProfile::SCharacterProfile() +{ + m_CharacterId = NULL; + m_Rank = NO_RANK; + m_Reputation = NO_REPUTATION; +} + +SCharacterProfile::~SCharacterProfile() +{ +} + + + +////////////////////////////////////////////////////////////////////////// + +CCharacterInfo::CCharacterInfo() +{ + m_ProfileId = NULL; + m_SpecificCharacterId = NULL; + +#ifdef XRGAME_EXPORTS + m_CurrentRank.set(NO_RANK); + m_CurrentReputation.set(NO_REPUTATION); + m_StartDialog = NULL; + m_Sympathy = 0.0f; +#endif +} + + +CCharacterInfo::~CCharacterInfo() +{ +} + + +void CCharacterInfo::Load(shared_str id) +{ + m_ProfileId = id; + inherited_shared::load_shared(m_ProfileId, NULL); +} + +#ifdef XRGAME_EXPORTS + +void CCharacterInfo::InitSpecificCharacter (shared_str new_id) +{ + R_ASSERT(new_id.size()); + m_SpecificCharacterId = new_id; + + m_SpecificCharacter.Load(m_SpecificCharacterId); + if(Rank().value() == NO_RANK) + SetRank(m_SpecificCharacter.Rank()); + if(Reputation().value() == NO_REPUTATION) + SetReputation(m_SpecificCharacter.Reputation()); + if(Community().index() == NO_COMMUNITY_INDEX) + SetCommunity(m_SpecificCharacter.Community().index()); + if(!m_StartDialog || !m_StartDialog.size() ) + m_StartDialog = m_SpecificCharacter.data()->m_StartDialog; +} + + +#endif + +void CCharacterInfo::load_shared (LPCSTR) +{ + const ITEM_DATA& item_data = *id_to_index::GetById(m_ProfileId); + + CUIXml* pXML = item_data._xml; + pXML->SetLocalRoot (pXML->GetRoot()); + + XML_NODE* item_node = pXML->NavigateToNode(id_to_index::tag_name, item_data.pos_in_file); + R_ASSERT3(item_node, "profile id=", *item_data.id); + + pXML->SetLocalRoot(item_node); + + + + LPCSTR spec_char = pXML->Read("specific_character", 0, NULL); + if(!spec_char) + { + data()->m_CharacterId = NULL; + + LPCSTR char_class = pXML->Read ("class", 0, NULL); + + if(char_class) + { + char* buf_str = xr_strdup(char_class); + xr_strlwr(buf_str); + data()->m_Class = buf_str; + xr_free(buf_str); + } + else + data()->m_Class = NO_CHARACTER_CLASS; + + data()->m_Rank = pXML->ReadInt ("rank", 0, NO_RANK); + data()->m_Reputation = pXML->ReadInt ("reputation", 0, NO_REPUTATION); + } + else + data()->m_CharacterId = spec_char; +} + +#ifdef XRGAME_EXPORTS +void CCharacterInfo::Init (CSE_ALifeTraderAbstract* trader) +{ + SetCommunity (trader->m_community_index); + SetRank (trader->m_rank); + SetReputation (trader->m_reputation); + Load (trader->character_profile()); + InitSpecificCharacter (trader->specific_character()); +} + + +shared_str CCharacterInfo::Profile() const +{ + return m_ProfileId; +} + +LPCSTR CCharacterInfo::Name() const +{ + R_ASSERT2(m_SpecificCharacterId.size(), m_SpecificCharacter.Name()); + return m_SpecificCharacter.Name(); +} + +shared_str CCharacterInfo::Bio() const +{ + return m_SpecificCharacter.Bio(); +} + +void CCharacterInfo::SetRank (CHARACTER_RANK_VALUE rank) +{ + m_CurrentRank.set(rank); +} + +void CCharacterInfo::SetReputation (CHARACTER_REPUTATION_VALUE reputation) +{ + m_CurrentReputation.set(reputation); +} + +void CCharacterInfo::SetCommunity(CHARACTER_COMMUNITY_INDEX community) +{ + m_CurrentCommunity.set( community ); + m_Sympathy = m_CurrentCommunity.sympathy( m_CurrentCommunity.index() ); +} + +const shared_str& CCharacterInfo::IconName() const +{ + R_ASSERT(m_SpecificCharacterId.size()); + return m_SpecificCharacter.IconName(); +} + +shared_str CCharacterInfo::StartDialog () const +{ + return m_StartDialog; +} + +const DIALOG_ID_VECTOR& CCharacterInfo::ActorDialogs () const +{ + R_ASSERT(m_SpecificCharacterId.size()); + return m_SpecificCharacter.data()->m_ActorDialogs; +} + +void CCharacterInfo::load (IReader& stream) +{ + stream.r_stringZ (m_StartDialog); +} + +void CCharacterInfo::save (NET_Packet& stream) +{ + stream.w_stringZ (m_StartDialog); +} + +#endif + + + +void CCharacterInfo::InitXmlIdToIndex() +{ + if(!id_to_index::tag_name) + id_to_index::tag_name = "character"; + if(!id_to_index::file_str) + id_to_index::file_str = pSettings->r_string("profiles", "files"); +} diff --git a/xrServerEntities/character_info.h b/xrServerEntities/character_info.h new file mode 100644 index 00000000000..1d1e2410c5e --- /dev/null +++ b/xrServerEntities/character_info.h @@ -0,0 +1,140 @@ +////////////////////////////////////////////////////////////////////////// +// character_info.h ������, ��� ������������� ������������ �������� +// +////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "character_info_defs.h" +#include "shared_data.h" +#include "xml_str_id_loader.h" + +class NET_Packet; + +#ifndef AI_COMPILER + #include "specific_character.h" +#endif + +#ifdef XRGAME_EXPORTS + #include "PhraseDialogDefs.h" + #include "character_community.h" + #include "character_rank.h" + #include "character_reputation.h" + class CSE_ALifeTraderAbstract; +#endif + + +////////////////////////////////////////////////////////////////////////// +// SCharacterProfile: ������ ������� ��������� +////////////////////////////////////////////////////////////////////////// +struct SCharacterProfile : CSharedResource +{ + SCharacterProfile (); + virtual ~SCharacterProfile (); + + //���� ������, �� ���������� ������ ����� �������, + //����� ������ ��������,��������������� ������� + shared_str m_CharacterId; + + //��������� ��������� ��������� + CHARACTER_CLASS m_Class; + CHARACTER_RANK_VALUE m_Rank; + CHARACTER_REPUTATION_VALUE m_Reputation; +}; + + +class CInventoryOwner; +class CSE_ALifeTraderAbstract; + +class CCharacterInfo: public CSharedClass, + public CXML_IdToIndex +{ +private: + typedef CSharedClass inherited_shared; + typedef CXML_IdToIndex id_to_index; + + friend id_to_index; + friend CInventoryOwner; + friend CSE_ALifeTraderAbstract; +public: + + + + CCharacterInfo (); + ~CCharacterInfo (); + + virtual void Load (shared_str id); + +#ifdef XRGAME_EXPORTS + void load (IReader&); + void save (NET_Packet&); + + //������������� ������� ������������� + //�������� ���������������� CSpecificCharacter, �� + //���������� ������� + void Init (CSE_ALifeTraderAbstract* trader); + void InitSpecificCharacter (shared_str new_id); +#endif + +protected: + const SCharacterProfile* data () const { VERIFY(inherited_shared::get_sd()); return inherited_shared::get_sd();} + SCharacterProfile* data () { VERIFY(inherited_shared::get_sd()); return inherited_shared::get_sd();} + + static void InitXmlIdToIndex (); + + + //�������� �� XML ����� + virtual void load_shared (LPCSTR); + + //������ ������������ ������� + shared_str m_ProfileId; + + //������ ������ � ���������� ���������, ������� + //������������ � ������ ���������� ������ + shared_str m_SpecificCharacterId; + +#ifdef XRGAME_EXPORTS + shared_str m_StartDialog; + + //����������� ���������� � ���������� ��������� + CSpecificCharacter m_SpecificCharacter; +#endif + +public: + + +#ifdef XRGAME_EXPORTS + shared_str Profile() const; + LPCSTR Name() const; + shared_str Bio() const; + + + const CHARACTER_COMMUNITY& Community() const { return m_CurrentCommunity; } + const CHARACTER_RANK& Rank() const { return m_CurrentRank; } + const CHARACTER_REPUTATION& Reputation() const { return m_CurrentReputation; } + float Sympathy() const { return m_Sympathy; } + void SetSympathy (float sympathy) { m_Sympathy = sympathy; } + + //�������� ������ � InventoryOwner +protected: + void SetRank (CHARACTER_RANK_VALUE rank); + void SetReputation (CHARACTER_REPUTATION_VALUE reputation); + void SetCommunity (CHARACTER_COMMUNITY_INDEX community); + +public: + const shared_str& IconName () const; + + shared_str StartDialog () const; + const DIALOG_ID_VECTOR& ActorDialogs () const; +#endif + +protected: + + +#ifdef XRGAME_EXPORTS + CHARACTER_RANK m_CurrentRank; + CHARACTER_REPUTATION m_CurrentReputation; + CHARACTER_COMMUNITY m_CurrentCommunity; + float m_Sympathy; // % ������� �� ����������� +#endif +}; \ No newline at end of file diff --git a/xrServerEntities/character_info_defs.h b/xrServerEntities/character_info_defs.h new file mode 100644 index 00000000000..81ac658a4f1 --- /dev/null +++ b/xrServerEntities/character_info_defs.h @@ -0,0 +1,31 @@ +#pragma once + +#include "alife_space.h" + + +//������ ��������� (���������������) ������ ��������� � ������� - +//�������� �� -100< (������ ����������) �� >100 (����� �����������) +typedef int CHARACTER_GOODWILL; +#define NO_GOODWILL -type_max(CHARACTER_GOODWILL) +#define NEUTRAL_GOODWILL CHARACTER_GOODWILL(0) + +typedef shared_str CHARACTER_CLASS; +#define NO_CHARACTER_CLASS NULL + +//��������� ��������� - �������� �� -100 (����� ������, �������������) +//�� 100 (����� �������, �����������) +typedef int CHARACTER_REPUTATION_VALUE; +#define NO_REPUTATION -type_max(CHARACTER_REPUTATION_VALUE) +#define NEUTAL_REPUTATION 0 + +//���� ��������� - �������� �� 0 (������ ���������) +//�� >100 (����� �������) +typedef int CHARACTER_RANK_VALUE; +#define NO_RANK -type_max(CHARACTER_RANK_VALUE) + + +typedef shared_str CHARACTER_COMMUNITY_ID; +#define NO_COMMUNITY_ID CHARACTER_COMMUNITY_ID(NULL) + +typedef int CHARACTER_COMMUNITY_INDEX; +#define NO_COMMUNITY_INDEX CHARACTER_COMMUNITY_INDEX(-1) \ No newline at end of file diff --git a/xrServerEntities/clsid_game.h b/xrServerEntities/clsid_game.h new file mode 100644 index 00000000000..e233f5e5191 --- /dev/null +++ b/xrServerEntities/clsid_game.h @@ -0,0 +1,227 @@ +#pragma once + +#define CLSID_OBJECT_ACTOR MK_CLSID('O','_','A','C','T','O','R',' ') +#define CLSID_OBJECT_HLAMP MK_CLSID('O','_','H','L','A','M','P',' ') +#define CLSID_ENTITY MK_CLSID('E','N','T','I','T','Y',' ',' ') +#define CLSID_SPECTATOR MK_CLSID('S','P','E','C','T',' ',' ',' ') +#define CLSID_OBJECT_PROJECTOR MK_CLSID('O','_','S','E','A','R','C','H') + +// all the monsters +#define CLSID_LEVEL_POINT MK_CLSID('L','V','L','P','O','I','N','T') +#define CLSID_SCRIPT_OBJECT MK_CLSID('S','C','R','P','T','O','B','J') +#define CLSID_AI_GRAPH MK_CLSID('A','I','_','G','R','A','P','H') +#define CLSID_AI_CROW MK_CLSID('A','I','_','C','R','O','W',' ') + +#define CLSID_AI_ZOMBIE MK_CLSID('A','I','_','Z','O','M',' ',' ') +#define CLSID_AI_POLTERGEIST MK_CLSID('A','I','_','P','O','L','T','R') + +#define CLSID_AI_FLESH MK_CLSID('A','I','_','F','L','E','S','H') +#define CLSID_AI_FLESH_GROUP MK_CLSID('A','I','_','F','L','E','_','G') + +#define CLSID_AI_PHANTOM MK_CLSID('A','I','_','P','H','A','N','T') +#define CLSID_AI_SPONGER MK_CLSID('A','I','_','S','P','O','N','G') +#define CLSID_AI_CONTROLLER MK_CLSID('A','I','_','C','O','N','T','R') +#define CLSID_AI_BLOODSUCKER MK_CLSID('A','I','_','B','L','O','O','D') +#define CLSID_AI_STALKER MK_CLSID('A','I','_','S','T','L',' ',' ') +#define CLSID_AI_BURER MK_CLSID('A','I','_','B','U','R','E','R') +#define CLSID_AI_GIANT MK_CLSID('A','I','_','G','I','A','N','T') +#define CLSID_AI_CHIMERA MK_CLSID('A','I','_','H','I','M','E','R') +#define CLSID_AI_FRACTURE MK_CLSID('A','I','_','F','R','A','C','T') +#define CLSID_AI_DOG_BLACK MK_CLSID('A','I','_','D','O','G','_','B') +#define CLSID_AI_DOG_RED MK_CLSID('A','I','_','D','O','G','_','R') +#define CLSID_AI_DOG_PSY MK_CLSID('A','I','_','D','O','G','_','P') +#define CLSID_AI_DOG_PSY_PHANTOM MK_CLSID('A','I','_','D','O','G','_','F') +#define CLSID_AI_TRADER MK_CLSID('A','I','_','T','R','A','D','E') +#define CLSID_AI_BOAR MK_CLSID('A','I','_','B','O','A','R',' ') +#define CLSID_AI_SNORK MK_CLSID('A','I','_','S','N','O','R','K') +#define CLSID_AI_CAT MK_CLSID('A','I','_','C','A','T',' ',' ') +#define CLSID_AI_TUSHKANO MK_CLSID('A','I','_','T','U','S','H',' ') +#define CLSID_AI_RAT MK_CLSID('A','I','_','R','A','T',' ',' ') + +// vehicles +#define CLSID_CAR MK_CLSID('C','_','N','I','V','A',' ',' ') +#define CLSID_VEHICLE_HELICOPTER MK_CLSID('C','_','H','L','C','P','T','R') + +#define CLSID_EVENT MK_CLSID('E','V','E','N','T',' ',' ',' ') +#define CLSID_OBJECT_FLYER MK_CLSID('O','_','F','L','Y','E','R',' ') +#define CLSID_OBJECT_DOOR MK_CLSID('O','_','D','O','O','R',' ',' ') +#define CLSID_OBJECT_LIFT MK_CLSID('O','_','L','I','F','T',' ',' ') + +// Artefacts +#define CLSID_AF_MERCURY_BALL MK_CLSID('A','F','_','M','B','A','L','L') +#define CLSID_AF_GRAVI MK_CLSID('A','F','_','G','R','A','V','I') +#define CLSID_AF_BLACKDROPS MK_CLSID('A','F','_','B','D','R','O','P') +#define CLSID_AF_NEEDLES MK_CLSID('A','F','_','N','E','E','D','L') +#define CLSID_AF_BAST MK_CLSID('A','F','_','B','A','S','T',' ') +#define CLSID_AF_BLACK_GRAVI MK_CLSID('A','F','_','B','G','R','A','V') +#define CLSID_AF_DUMMY MK_CLSID('A','F','_','D','U','M','M','Y') +#define CLSID_AF_ZUDA MK_CLSID('A','F','_','Z','U','D','A',' ') +#define CLSID_AF_THORN MK_CLSID('A','F','_','T','H','O','R','N') +#define CLSID_AF_FADED_BALL MK_CLSID('A','F','_','F','B','A','L','L') +#define CLSID_AF_ELECTRIC_BALL MK_CLSID('A','F','_','E','B','A','L','L') +#define CLSID_AF_RUSTY_HAIR MK_CLSID('A','F','_','R','H','A','I','R') +#define CLSID_AF_GALANTINE MK_CLSID('A','F','_','G','A','L','A','N') +#define CLSID_AF_CTA MK_CLSID('A','F','_','C','T','A',' ',' ') + +#define CLSID_ARTEFACT MK_CLSID('A','R','T','E','F','A','C','T') + +// Weapons +#define CLSID_OBJECT_W_M134 MK_CLSID('W','_','M','1','3','4',' ',' ') +#define CLSID_OBJECT_W_FN2000 MK_CLSID('W','_','F','N','2','0','0','0') +#define CLSID_OBJECT_W_AK74 MK_CLSID('W','_','A','K','7','4',' ',' ') +#define CLSID_OBJECT_W_LR300 MK_CLSID('W','_','L','R','3','0','0',' ') +#define CLSID_OBJECT_W_HPSA MK_CLSID('W','_','H','P','S','A',' ',' ') +#define CLSID_OBJECT_W_PM MK_CLSID('W','_','P','M',' ',' ',' ',' ') +#define CLSID_OBJECT_W_FORT MK_CLSID('W','_','F','O','R','T',' ',' ') +#define CLSID_OBJECT_W_BINOCULAR MK_CLSID('W','_','B','I','N','O','C',' ') +#define CLSID_OBJECT_W_SHOTGUN MK_CLSID('W','_','S','H','O','T','G','N') +#define CLSID_OBJECT_W_ASHOTGUN MK_CLSID('W','_','A','S','H','T','G','N') +// [8/15/2006] +#define CLSID_OBJECT_W_MAGAZINED MK_CLSID('W','_','W','M','A','G','A','Z') +// [8/15/2006] +// [8/17/2006] +#define CLSID_OBJECT_W_MAGAZWGL MK_CLSID('W','_','W','M','A','G','G','L') +// [8/17/2006] +#define CLSID_OBJECT_W_SVD MK_CLSID('W','_','S','V','D',' ',' ',' ') +#define CLSID_OBJECT_W_SVU MK_CLSID('W','_','S','V','U',' ',' ',' ') +#define CLSID_OBJECT_W_RPG7 MK_CLSID('W','_','R','P','G','7',' ',' ') +#define CLSID_OBJECT_W_VAL MK_CLSID('W','_','V','A','L',' ',' ',' ') +#define CLSID_OBJECT_W_VINTOREZ MK_CLSID('W','_','V','I','N','T',' ',' ') +#define CLSID_OBJECT_W_WALTHER MK_CLSID('W','_','W','A','L','T','H','R') +#define CLSID_OBJECT_W_USP45 MK_CLSID('W','_','U','S','P','4','5',' ') +#define CLSID_OBJECT_W_GROZA MK_CLSID('W','_','G','R','O','Z','A',' ') +#define CLSID_OBJECT_W_KNIFE MK_CLSID('W','_','K','N','I','F','E',' ') +#define CLSID_OBJECT_W_BM16 MK_CLSID('W','_','B','M','1','6',' ',' ') +#define CLSID_OBJECT_W_RG6 MK_CLSID('W','_','R','G','6',' ',' ',' ') + +#define CLSID_OBJECT_W_STATMGUN MK_CLSID('W','_','S','T','M','G','U','N') +// Weapons Ammo +#define CLSID_OBJECT_AMMO MK_CLSID('A','M','M','O',' ',' ',' ',' ') +//----------------------------------------------------------------------------- +#define CLSID_OBJECT_A_VOG25 MK_CLSID('A','_','V','O','G','2','5',' ') +#define CLSID_OBJECT_A_OG7B MK_CLSID('A','_','O','G','7','B',' ',' ') +#define CLSID_OBJECT_A_M209 MK_CLSID('A','_','M','2','0','9',' ',' ') +//----------------------------------------------------------------------------- +// Weapons Add-ons +#define CLSID_OBJECT_W_SCOPE MK_CLSID('W','_','S','C','O','P','E',' ') +#define CLSID_OBJECT_W_SILENCER MK_CLSID('W','_','S','I','L','E','N','C') +#define CLSID_OBJECT_W_GLAUNCHER MK_CLSID('W','_','G','L','A','U','N','C') + +// Modifiers +#define CLSID_OBJECT_M_QDAMAGE MK_CLSID('O','_','Q','D','M','G',' ',' ') +#define CLSID_OBJECT_M_IMMORTAL MK_CLSID('O','_','I','M','M','O','R','T') +#define CLSID_OBJECT_M_INVIS MK_CLSID('O','_','I','N','V','I','S',' ') + +#define CLSID_OBJECT_HEALTH MK_CLSID('O','_','H','E','A','L','T','H') +#define CLSID_OBJECT_ARMOR MK_CLSID('O','_','A','R','M','O','R',' ') + +#define CLSID_OBJECT_TRIGGER MK_CLSID('O','_','T','R','I','G','E','R') + +// Targets +#define CLSID_TARGET MK_CLSID('T','_','B','A','S','E',' ',' ') +#define CLSID_TARGET_ASSAULT MK_CLSID('T','_','A','S','S',' ',' ',' ') +#define CLSID_TARGET_CS_BASE MK_CLSID('T','_','C','S','B','A','S','E') +#define CLSID_TARGET_CS MK_CLSID('T','_','C','S',' ',' ',' ',' ') +#define CLSID_TARGET_CS_CASK MK_CLSID('T','_','C','S','C','A','S','K') + +// Standard level object +#define CLSID_OBJECT_ITEM_STD MK_CLSID('O','_','I','T','E','M',' ',' ') +#define CLSID_OBJECT_BREAKABLE MK_CLSID('O','_','B','R','K','B','L',' ') +#define CLSID_OBJECT_CLIMABLE MK_CLSID('O','_','C','L','M','B','L',' ') + +// +#define CLSID_PH_SKELETON_OBJECT MK_CLSID('P','_','S','K','E','L','E','T') +#define CLSID_OBJECT_PHYSIC MK_CLSID('O','_','P','H','Y','S','I','C') +#define CLSID_PHYSICS_DESTROYABLE MK_CLSID('P','_','D','S','T','R','B','L') +#define CLSID_INVENTORY_BOX MK_CLSID('O','_','I','N','V','B','O','X') + +// Zones +#define CLSID_ZONE MK_CLSID('Z','_','Z','O','N','E',' ',' ') +#define CLSID_Z_MBALD MK_CLSID('Z','_','M','B','A','L','D',' ') +#define CLSID_Z_MINCER MK_CLSID('Z','_','M','I','N','C','E','R') +#define CLSID_Z_ACIDF MK_CLSID('Z','_','A','C','I','D','F',' ') +#define CLSID_Z_GALANT MK_CLSID('Z','_','G','A','L','A','N','T') +#define CLSID_Z_RADIO MK_CLSID('Z','_','R','A','D','I','O',' ') +#define CLSID_Z_BFUZZ MK_CLSID('Z','_','B','F','U','Z','Z',' ') +#define CLSID_Z_RUSTYH MK_CLSID('Z','_','R','U','S','T','Y','H') +#define CLSID_Z_AMEBA MK_CLSID('Z','_','A','M','E','B','A',' ') +#define CLSID_Z_NOGRAVITY MK_CLSID('Z','_','N','O','G','R','A','V') +#define CLSID_Z_FRYUP MK_CLSID('Z','_','F','R','Y','U','P ',' ') +#define CLSID_Z_DEAD MK_CLSID('Z','_','D','E','A','D',' ',' ') +#define CLSID_LEVEL_CHANGER MK_CLSID('L','V','L','C','H','N','G','R') +#define CLSID_SCRIPT_ZONE MK_CLSID('S','C','R','I','P','T','Z','N') +#define CLSID_Z_TEAM_BASE MK_CLSID('Z','_','T','E','A','M','B','S') +#define CLSID_Z_TORRID MK_CLSID('Z','_','T','O','R','R','I','D') +#define CLSID_SPACE_RESTRICTOR MK_CLSID('S','P','A','C','E','_','R','S') +#define CLSID_SMART_ZONE MK_CLSID('S','M','R','T','Z','O','N','E') +#define CLSID_Z_CAMPFIRE MK_CLSID('Z','_','C','F','I','R','E',' ') + +// Detectors +#define CLSID_DETECTOR_SIMPLE MK_CLSID('D','_','S','I','M','D','E','T') +#define CLSID_DETECTOR_ADVANCED MK_CLSID('D','_','A','D','V','A','N','C') +#define CLSID_DETECTOR_ELITE MK_CLSID('D','_','E','L','I','T','E',' ') +#define CLSID_DETECTOR_SCIENTIFIC MK_CLSID('D','_','S','C','I','E','N','T') + +// PDA +#define CLSID_DEVICE_PDA MK_CLSID('D','_','P','D','A',' ',' ',' ') + +// Devices +#define CLSID_DEVICE_TORCH MK_CLSID('D','_','T','O','R','C','H',' ') +#define CLSID_DEVICE_AF_MERGER MK_CLSID('D','_','A','F','M','E','R','G') +#define CLSID_DEVICE_FLARE MK_CLSID('D','_','F','L','A','R','E',' ') + +// Inventory items +#define CLSID_IITEM_BOLT MK_CLSID('I','I','_','B','O','L','T',' ') + +#define CLSID_IITEM_MEDKIT MK_CLSID('I','I','_','M','E','D','K','I') +#define CLSID_IITEM_BANDAGE MK_CLSID('I','I','_','B','A','N','D','G') +#define CLSID_IITEM_FOOD MK_CLSID('I','I','_','F','O','O','D',' ') +#define CLSID_IITEM_BOTTLE MK_CLSID('I','I','_','B','O','T','T','L') +#define CLSID_IITEM_ANTIRAD MK_CLSID('I','I','_','A','N','T','I','R') +#define CLSID_IITEM_EXPLOSIVE MK_CLSID('I','I','_','E','X','P','L','O') + +// Info Document +#define CLSID_IITEM_DOCUMENT MK_CLSID('I','I','_','D','O','C',' ',' ') + +#define CLSID_IITEM_ATTACH MK_CLSID('I','I','_','A','T','T','C','H') + + +// Grenades +#define CLSID_GRENADE_F1 MK_CLSID('G','_','F','1',' ',' ',' ',' ') +#define CLSID_OBJECT_G_RPG7 MK_CLSID('G','_','R','P','G','7',' ',' ') +#define CLSID_GRENADE_RGD5 MK_CLSID('G','_','R','G','D','5',' ',' ') +#define CLSID_OBJECT_G_FAKE MK_CLSID('G','_','F','A','K','E',' ',' ') + +//--------------------------------------------------------------------------------- +#define CLSID_OBJECT_PLAYERS_BAG MK_CLSID('M','P','_','P','L','B','A','G') +//--------------------------------------------------------------------------------- + +// Equipment +#define CLSID_EQUIPMENT_SIMPLE MK_CLSID('E','Q','U','_','S','M','P','L') +#define CLSID_EQUIPMENT_SCIENTIFIC MK_CLSID('E','Q','U','_','S','C','I','E') +#define CLSID_EQUIPMENT_STALKER MK_CLSID('E','Q','U','_','S','T','L','K') +#define CLSID_EQUIPMENT_MILITARY MK_CLSID('E','Q','U','_','M','L','T','R') +#define CLSID_EQUIPMENT_EXO MK_CLSID('E','Q','U','_','E','X','O',' ') +#define CLSID_EQUIPMENT_HELMET MK_CLSID('E','Q','_','H','L','M','E','T') + +// Game types +#define CLSID_SV_GAME_SINGLE MK_CLSID('S','V','_','S','I','N','G','L') +#define CLSID_SV_GAME_DEATHMATCH MK_CLSID('S','V','_','D','M',' ',' ',' ') +#define CLSID_SV_GAME_TEAMDEATHMATCH MK_CLSID('S','V','_','T','D','M',' ',' ') +#define CLSID_SV_GAME_ARTEFACTHUNT MK_CLSID('S','V','_','A','H','U','N','T') +#define CLSID_SV_GAME_CAPTURETHEARTEFACT MK_CLSID('S','V','_','C','T','A',' ',' ') +//#define CLSID_GAME_CS MK_CLSID('S','V','_','C','S',' ',' ',' ') +#define CLSID_CL_GAME_SINGLE MK_CLSID('C','L','_','S','I','N','G','L') +#define CLSID_CL_GAME_DEATHMATCH MK_CLSID('C','L','_','D','M',' ',' ',' ') +#define CLSID_CL_GAME_TEAMDEATHMATCH MK_CLSID('C','L','_','T','D','M',' ',' ') +#define CLSID_CL_GAME_ARTEFACTHUNT MK_CLSID('C','L','_','A','H','U','N','T') +#define CLSID_CL_GAME_CAPTURETHEARTEFACT MK_CLSID('C','L','_','C','T','A',' ',' ') + +// Game UI types +#define CLSID_GAME_UI_SINGLE MK_CLSID('U','I','_','S','I','N','G','L') +#define CLSID_GAME_UI_DEATHMATCH MK_CLSID('U','I','_','D','M',' ',' ',' ') +#define CLSID_GAME_UI_TEAMDEATHMATCH MK_CLSID('U','I','_','T','D','M',' ',' ') +#define CLSID_GAME_UI_ARTEFACTHUNT MK_CLSID('U','I','_','A','H','U','N','T') +#define CLSID_GAME_UI_CAPTURETHEARTEFACT MK_CLSID('U','I','_','C','T','A',' ',' ') + +#define CLSID_ONLINE_OFFLINE_GROUP MK_CLSID('O','N','_','O','F','F','_','G') diff --git a/xrServerEntities/game_base_space.h b/xrServerEntities/game_base_space.h new file mode 100644 index 00000000000..7a6aa0e0b55 --- /dev/null +++ b/xrServerEntities/game_base_space.h @@ -0,0 +1,44 @@ +#pragma once +/* +enum EGameIDs { + eGameIDNoGame = u32(0), + eGameIDSingle = u32(1) << 0, + eGameIDDeathmatch = u32(1) << 1, + eGameIDTeamDeathmatch = u32(1) << 2, + eGameIDArtefactHunt = u32(1) << 3, + eGameIDCaptureTheArtefact = u32(1) << 4, + eGameIDDominationZone = u32(1) << 5, + eGameIDTeamDominationZone = u32(1) << 6, +};*/ + +enum EGamePlayerFlags +{ + GAME_PLAYER_FLAG_LOCAL = (1<<0), + GAME_PLAYER_FLAG_READY = (1<<1), + GAME_PLAYER_FLAG_VERY_VERY_DEAD = (1<<2), + GAME_PLAYER_FLAG_SPECTATOR = (1<<3), + + GAME_PLAYER_FLAG_SCRIPT_BEGINS_FROM = (1<<4), + GAME_PLAYER_FLAG_INVINCIBLE = (1<<5), + GAME_PLAYER_FLAG_ONBASE = (1<<6), + GAME_PLAYER_FLAG_SKIP = (1<<7), + GAME_PLAYER_HAS_ADMIN_RIGHTS = (1<<8), + + GAME_PLAYER_FLAG_FORCEDWORD = u32(-1) +}; + +enum EGamePhases +{ + GAME_PHASE_NONE = 0, + GAME_PHASE_INPROGRESS, + GAME_PHASE_PENDING, + GAME_PHASE_TEAM1_SCORES, + GAME_PHASE_TEAM2_SCORES, + GAME_PHASE_TEAM1_ELIMINATED, + GAME_PHASE_TEAM2_ELIMINATED, + GAME_PHASE_TEAMS_IN_A_DRAW, + GAME_PHASE_PLAYER_SCORES, + + GAME_PHASE_SCRIPT_BEGINS_FROM, + GAME_PHASE_FORCEDWORD = u32(-1) +}; diff --git a/xrServerEntities/game_graph_space.h b/xrServerEntities/game_graph_space.h new file mode 100644 index 00000000000..7a72325329c --- /dev/null +++ b/xrServerEntities/game_graph_space.h @@ -0,0 +1,178 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : game_graph_space.h +// Created : 18.02.2003 +// Modified : 11.12.2004 +// Author : Dmitriy Iassenev +// Description : Game graph namespace +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "associative_vector.h" + +#ifdef XRGAME_EXPORTS +# include "../xrEngine/xrLevel.h" +#else +# include "../../xrEngine/xrLevel.h" +#endif + +namespace GameGraph { + typedef u16 _GRAPH_ID; + typedef u8 _LEVEL_ID; + typedef u8 _LOCATION_ID; + + enum { + LOCATION_TYPE_COUNT = 4, + LOCATION_COUNT = (u32(1) << (8*sizeof(_LOCATION_ID))), + }; + +#ifdef AI_COMPILER + struct +#else + class +#endif + SLevel { + shared_str m_name; + Fvector m_offset; + _LEVEL_ID m_id; + shared_str m_section; + xrGUID m_guid; + + public: + IC const shared_str &name () const + { + return (m_name); + } + + IC const Fvector &offset () const + { + return (m_offset); + } + + IC const _LEVEL_ID &id () const + { + return (m_id); + } + + IC const shared_str §ion () const + { + return (m_section); + } + + IC const xrGUID &guid () const + { + return (m_guid); + } + + IC void load (IReader *reader); + IC void save (IWriter *writer); + + friend class CGameGraph; + }; + + typedef associative_vector<_LEVEL_ID,SLevel> LEVEL_MAP; + +#pragma pack(push,1) +#ifdef AI_COMPILER + struct +#else + class +#endif + CEdge { + _GRAPH_ID m_vertex_id; + float m_path_distance; + public: + IC const _GRAPH_ID &vertex_id () const; + IC const float &distance () const; + }; + +#ifdef AI_COMPILER + struct +#else + class +#endif + CVertex { + Fvector tLocalPoint; + Fvector tGlobalPoint; + u32 tLevelID:8; + u32 tNodeID:24; + u8 tVertexTypes[LOCATION_TYPE_COUNT]; + u32 dwEdgeOffset; + u32 dwPointOffset; + u8 tNeighbourCount; + u8 tDeathPointCount; + public: + IC const Fvector &level_point () const; + IC const Fvector &game_point () const; + IC _LEVEL_ID level_id () const; + IC u32 level_vertex_id () const; + IC const u8 *vertex_type () const; + IC const u8 &edge_count () const; + IC const u32 &edge_offset () const; + IC const u8 &death_point_count () const; + IC const u32 &death_point_offset () const; + friend class CGameGraph; + }; + +#ifdef AI_COMPILER + struct +#else + class +#endif + CHeader { + u8 m_version; + _GRAPH_ID m_vertex_count; + u32 m_edge_count; + u32 m_death_point_count; + xrGUID m_guid; + LEVEL_MAP m_levels; + + public: + IC const u8 &version () const; + IC _LEVEL_ID level_count () const; + IC const _GRAPH_ID &vertex_count () const; + IC const u32 &edge_count () const; + IC const u32 &death_point_count () const; + IC const xrGUID &guid () const; + IC const LEVEL_MAP &levels () const; + IC const SLevel &level (const _LEVEL_ID &id) const; + IC const SLevel &level (LPCSTR level_name) const; + IC const SLevel *level (LPCSTR level_name, bool) const; + IC void load (IReader *reader); + IC void save (IWriter *reader); + friend class CGameGraph; + }; +#pragma pack(pop) + +#ifdef AI_COMPILER + struct +#else + class +#endif + CLevelPoint { + Fvector tPoint; + u32 tNodeID; + float fDistance; + public: + IC const Fvector &level_point () const + { + return (tPoint); + } + + IC u32 level_vertex_id () const + { + return (tNodeID); + } + + IC float distance () const + { + return (fDistance); + } + }; + + struct STerrainPlace{ + svector<_LOCATION_ID,LOCATION_TYPE_COUNT> tMask; + }; + + DEFINE_VECTOR (STerrainPlace, TERRAIN_VECTOR, TERRAIN_IT); +} \ No newline at end of file diff --git a/xrServerEntities/gametype_chooser.cpp b/xrServerEntities/gametype_chooser.cpp new file mode 100644 index 00000000000..f9d3697f6c0 --- /dev/null +++ b/xrServerEntities/gametype_chooser.cpp @@ -0,0 +1,89 @@ +#include "stdafx.h" +#pragma hdrstop + + +#include "gametype_chooser.h" +#include "xrServer_Objects_Abstract.h" +//old +enum ERPGameType{ // [0..255] + rpgtGameAny = u8(0), + rpgtGameDeathmatch, + rpgtGameTeamDeathmatch, + rpgtGameArtefactHunt, + rpgtGameCaptureTheArtefact, + rpgtGameCount, +}; + +xr_token rpoint_game_type[]={ + { "Any game", rpgtGameAny }, + { "Deathmatch", rpgtGameDeathmatch }, + { "TeamDeathmatch", rpgtGameTeamDeathmatch }, + { "ArtefactHunt", rpgtGameArtefactHunt }, + { "CaptureTheArtefact", rpgtGameCaptureTheArtefact }, + { 0, 0 } +}; + + +#ifdef _EDITOR +bool GameTypeChooser::LoadStream(IReader& F) +{ + m_GameType.assign (F.r_u16()); + + return true; +} + +bool GameTypeChooser::LoadLTX(CInifile& ini, LPCSTR sect_name, bool bOldFormat) +{ + if(bOldFormat/*version==0x0014*/) + { + u8 tmp = ini.r_u8 (sect_name, "game_type"); + m_GameType.zero (); + switch(tmp) + { + case rpgtGameAny: + m_GameType.one(); + break; + case rpgtGameDeathmatch: + m_GameType.set(eGameIDDeathmatch,TRUE); + break; + case rpgtGameTeamDeathmatch: + m_GameType.set(eGameIDTeamDeathmatch,TRUE); + break; + case rpgtGameArtefactHunt: + m_GameType.set(eGameIDArtefactHunt,TRUE); + break; + case rpgtGameCaptureTheArtefact: + m_GameType.set(eGameIDCaptureTheArtefact,TRUE); + break; + } + }else + m_GameType.assign (ini.r_u16 (sect_name, "game_type")); + return true; +} + +void GameTypeChooser::SaveStream(IWriter& F) +{ + F.w_u16 (m_GameType.get()); +} + +void GameTypeChooser::SaveLTX(CInifile& ini, LPCSTR sect_name) +{ + ini.w_u16(sect_name, "game_type", m_GameType.get()); +} +#endif + +#ifndef XRGAME_EXPORTS +void GameTypeChooser::FillProp(LPCSTR pref, PropItemVec& items) +{ + PHelper().CreateGameType (items, PrepareKey(pref, "Game Type"), this); +/* + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\single"), &m_GameType, eGameIDSingle); + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\deathmatch"), &m_GameType, eGameIDDeathmatch); + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\team deathmatch"), &m_GameType, eGameIDTeamDeathmatch); + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\artefact hunt"), &m_GameType, eGameIDArtefactHunt); + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\capture the artefact"), &m_GameType, eGameIDCaptureTheArtefact); + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\domination zone"), &m_GameType, eGameIDDominationZone); + PHelper().CreateFlag16 (items, PrepareKey(pref, "Game Type\\team domination zone"), &m_GameType, eGameIDTeamDominationZone); +*/ + } +#endif // #ifndef XRGAME_EXPORTS \ No newline at end of file diff --git a/xrServerEntities/gametype_chooser.h b/xrServerEntities/gametype_chooser.h new file mode 100644 index 00000000000..024bb221785 --- /dev/null +++ b/xrServerEntities/gametype_chooser.h @@ -0,0 +1,39 @@ +#ifndef GAMETYPE_CHOOSER_INCLUDED +#define GAMETYPE_CHOOSER_INCLUDED + +#pragma once + +//new +enum EGameIDs { + eGameIDNoGame = u32(0), + eGameIDSingle = u32(1) << 0, + eGameIDDeathmatch = u32(1) << 1, + eGameIDTeamDeathmatch = u32(1) << 2, + eGameIDArtefactHunt = u32(1) << 3, + eGameIDCaptureTheArtefact = u32(1) << 4, + eGameIDDominationZone = u32(1) << 5, + eGameIDTeamDominationZone = u32(1) << 6, +}; + +class PropValue; +class PropItem; +DEFINE_VECTOR (PropItem*,PropItemVec,PropItemIt); + +struct GameTypeChooser +{ + Flags16 m_GameType; +#ifndef XRGAME_EXPORTS + void FillProp (LPCSTR pref, PropItemVec& items); +#endif // #ifndef XRGAME_EXPORTS + +#ifdef _EDITOR + bool LoadStream (IReader&F); + bool LoadLTX (CInifile& ini, LPCSTR sect_name, bool bOldFormat); + void SaveStream (IWriter&); + void SaveLTX (CInifile& ini, LPCSTR sect_name); +#endif + void SetDefaults () {m_GameType.one();} + bool MatchType (const u16 t) const {return (t==eGameIDNoGame) || !!m_GameType.test(t);}; +}; + +#endif \ No newline at end of file diff --git a/xrServerEntities/inventory_space.h b/xrServerEntities/inventory_space.h new file mode 100644 index 00000000000..544394c35b8 --- /dev/null +++ b/xrServerEntities/inventory_space.h @@ -0,0 +1,82 @@ +#pragma once + +#define CMD_START (1<<0) +#define CMD_STOP (1<<1) + +enum{ + NO_ACTIVE_SLOT = 0, + KNIFE_SLOT = 1,//btn1 was (0) !!! + INV_SLOT_2, //btn2 PISTOL_SLOT was (1) + INV_SLOT_3, //btn3 RIFLE_SLOT was (2) + GRENADE_SLOT, //btn4 GRENADE_SLOT was (3) + BINOCULAR_SLOT, //btn5 BINOCULAR_SLOT + BOLT_SLOT, //btn6 BOLT_SLOT + OUTFIT_SLOT, // outfit + PDA_SLOT, // pda + DETECTOR_SLOT, // detector + TORCH_SLOT, // torch + ARTEFACT_SLOT, // artefact + HELMET_SLOT, + LAST_SLOT = HELMET_SLOT +}; + +#define RUCK_HEIGHT 280 +#define RUCK_WIDTH 7 + +class CInventoryItem; +class CInventory; + +typedef CInventoryItem* PIItem; +typedef xr_vector TIItemContainer; + + +enum eItemPlace +{ + eItemPlaceUndefined = 0, + eItemPlaceSlot, + eItemPlaceBelt, + eItemPlaceRuck +}; + +struct SInvItemPlace +{ + union{ + struct{ + u16 type : 4; + u16 slot_id : 6; + u16 base_slot_id : 6; + }; + u16 value; + }; +}; + +extern u16 INV_STATE_LADDER; +extern u16 INV_STATE_CAR; +extern u16 INV_STATE_BLOCK_ALL; +extern u16 INV_STATE_INV_WND; +extern u16 INV_STATE_BUY_MENU; + +struct II_BriefInfo +{ + shared_str name; + shared_str icon; + shared_str cur_ammo; + shared_str fmj_ammo; + shared_str ap_ammo; + shared_str fire_mode; + + shared_str grenade; + + II_BriefInfo() { clear(); } + + IC void clear() + { + name = ""; + icon = ""; + cur_ammo = ""; + fmj_ammo = ""; + ap_ammo = ""; + fire_mode = ""; + grenade = ""; + } +}; diff --git a/xrServerEntities/lua_studio.cpp b/xrServerEntities/lua_studio.cpp new file mode 100644 index 00000000000..5a5476807fa --- /dev/null +++ b/xrServerEntities/lua_studio.cpp @@ -0,0 +1,812 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : lua_studio.cpp +// Created : 21.08.2008 +// Modified : 21.08.2008 +// Author : Dmitriy Iassenev +// Description : lua studio engine class (copied from the lua studio SDK) +//////////////////////////////////////////////////////////////////////////// + +#include "pch_script.h" +#include "lua_studio.h" + +#define pstr LPSTR +#define pcstr LPCSTR +#define pcvoid void const* +#define sz_cmp xr_strcmp +#define vector_class luabind::internal_vector +#define engine lua_studio_engine + +inline pstr sz_cpy (pstr destination, const u32 &size, pcstr source) +{ + xr_strcpy (destination,size,source); + return (destination); +} + +template +inline pstr sz_cpy (char (&destination)[size], pcstr source) +{ + xr_strcpy (destination,size,source); + return (destination); +} + +inline pstr sz_cat (pstr destination, const u32 &size, pcstr source) +{ + xr_strcat (destination,size,source); + return (destination); +} + +template +inline pstr sz_cat (char (&destination)[size], pcstr source) +{ + xr_strcat (destination,size,source); + return (destination); +} + +inline u32 sz_len (pcstr string) +{ + return ((u32)xr_strlen(string)); +} + +//////////////////////////////////////////////////////////////////////////// + +int engine::luaL_loadstring (lua_State *L, const char *s) +{ + return (::luaL_loadstring(L, s)); +} + +int engine::luaL_newmetatable (lua_State *L, const char *tname) +{ + return (::luaL_newmetatable(L, tname)); +} + +void engine::lua_createtable (lua_State *L, int narray, int nrec) +{ + return (::lua_createtable(L, narray, nrec)); +} + +int engine::lua_sethook (lua_State *L, lua_Hook func, lua_mask_type mask, int count) +{ + return (::lua_sethook(L, func, mask, count)); +} + +engine::lua_Hook engine::lua_gethook (lua_State *L) +{ + return (::lua_gethook(L)); +} + +int engine::lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) +{ + return (::lua_getinfo(L, what, ar)); +} + +void engine::lua_getfenv (lua_State *L, int idx) +{ + return (::lua_getfenv(L, idx)); +} + +void engine::lua_getfield (lua_State *L, int idx, const char *k) +{ + return (::lua_getfield(L, idx, k)); +} + +char const* engine::lua_getlocal (lua_State *L, const lua_Debug *ar, int n) +{ + return (::lua_getlocal(L, ar, n)); +} + +void engine::lua_gettable (lua_State *L, int idx) +{ + return (::lua_gettable(L, idx)); +} + +int engine::lua_getstack (lua_State *L, int level, lua_Debug *ar) +{ + return (::lua_getstack(L, level, ar)); +} + +int engine::lua_gettop (lua_State *L) +{ + return (::lua_gettop(L)); +} + +char const* engine::lua_getupvalue (lua_State *L, int funcindex, int n) +{ + return (::lua_getupvalue(L, funcindex, n)); +} + +int engine::lua_iscfunction (lua_State *L, int idx) +{ + return (::lua_iscfunction(L, idx)); +} + +int engine::lua_next (lua_State *L, int idx) +{ + return (::lua_next(L, idx)); +} + +int engine::lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) +{ + return (::lua_pcall(L, nargs, nresults, errfunc)); +} + +void engine::lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) +{ + return (::lua_pushcclosure(L, fn, n)); +} + +void engine::lua_pushnil (lua_State *L) +{ + return (::lua_pushnil(L)); +} + +void engine::lua_pushstring (lua_State *L, const char *s) +{ + return (::lua_pushstring(L, s)); +} + +void engine::lua_pushvalue (lua_State *L, int idx) +{ + return (::lua_pushvalue(L, idx)); +} + +void engine::lua_pushnumber (lua_State *L, lua_Number idx) +{ + return (::lua_pushnumber(L, idx)); +} + +void engine::lua_remove (lua_State *L, int idx) +{ + return (::lua_remove(L, idx)); +} + +void engine::lua_replace (lua_State *L, int idx) +{ + return (::lua_replace(L, idx)); +} + +int engine::lua_setfenv (lua_State *L, int idx) +{ + return (::lua_setfenv(L, idx)); +} + +int engine::lua_setmetatable (lua_State *L, int objindex) +{ + return (::lua_setmetatable(L, objindex)); +} + +void engine::lua_settable (lua_State *L, int idx) +{ + return (::lua_settable(L, idx)); +} + +void engine::lua_settop (lua_State *L, int idx) +{ + return (::lua_settop(L, idx)); +} + +int engine::lua_toboolean (lua_State *L, int idx) +{ + return (::lua_toboolean(L, idx)); +} + +engine::lua_Integer engine::lua_tointeger (lua_State *L, int idx) +{ + return (::lua_tointeger(L, idx)); +} + +char const* engine::lua_tolstring (lua_State *L, int idx, size_t *len) +{ + return (::lua_tolstring(L, idx, len)); +} + +lua_Number engine::lua_tonumber (lua_State *L, int idx) +{ + return (::lua_tonumber(L, idx)); +} + +const void* engine::lua_topointer (lua_State *L, int idx) +{ + return (::lua_topointer(L, idx)); +} + +bool engine::lua_isnumber (lua_State *L, int idx) +{ + return (!!::lua_isnumber(L, idx)); +} + +int engine::lua_type (lua_State *L, int idx) +{ + return (::lua_type(L, idx)); +} + +char const* engine::lua_typename (lua_State *L, int t) +{ + return (::lua_typename(L, t)); +} + +lua_Debug* engine::lua_debug_create () +{ + VERIFY (m_instance_count < sizeof(m_instances)/sizeof(m_instances[0])); + return (&m_instances[m_instance_count++]); +} + +void engine::lua_debug_destroy (lua_Debug*& instance) +{ + instance = 0; + --m_instance_count; +} + +char const* engine::lua_debug_get_name (lua_Debug& instance) +{ + return (instance.name); +} + +char const* engine::lua_debug_get_source (lua_Debug& instance) +{ + return (instance.source); +} + +char const* engine::lua_debug_get_short_source (lua_Debug& instance) +{ + return (instance.short_src); +} + +int engine::lua_debug_get_current_line (lua_Debug& instance) +{ + return (instance.currentline); +} + +void engine::log (log_message_types const message_type, char const* const message) +{ +} + +char* engine::class_name (char* const buffer, unsigned int const size, luabind::detail::class_rep &class_rep) +{ + switch (class_rep.get_class_type()) { + case luabind::detail::class_rep::cpp_class : { + return (sz_cpy(buffer, size, "C++ class")); + } + case luabind::detail::class_rep::lua_class : { + return (sz_cpy(buffer, size, "Lua class")); + } + default : NODEFAULT; + } +#ifdef DEBUG + return (sz_cpy(buffer, size, "unknown user data")); +#endif // #ifdef DEBUG +} + +void engine::type_convert_class (char* const buffer, unsigned int const size, lua_State *state, int index) +{ + luabind::detail::object_rep *object = luabind::detail::is_class_object(state, index); + VERIFY2 (object, "invalid object userdata"); + + sz_cpy (buffer, size, ""); + sz_cat (buffer, size, "class \""); + sz_cat (buffer, size, object->crep()->name()); + sz_cat (buffer, size, "\" ("); + + u32 const length = sz_len(buffer); + class_name (buffer + length, size - length, *object->crep()); + + sz_cat (buffer, size, " instance)"); +} + +static bool is_luabind_class (lua_State* state, int const index) +{ + luabind::detail::class_rep *class_rep = static_cast(lua_touserdata(state, index)); + if (!class_rep) + return (false); + + if (class_rep->get_class_type() == luabind::detail::class_rep::lua_class) + return (true); + + if (luabind::detail::class_registry::get_registry(state)->find_class(class_rep->type()) != class_rep) + return (false); + + return (true); +} + +bool engine::type_convert_instance (char *buffer, unsigned int const size, lua_State *state, int index) +{ + if (!is_luabind_class(state, index)) + return (false); + + class_name (buffer, size, *static_cast(lua_touserdata(state, index))); + + return (true); +} + +void engine::type_convert_userdata (char *buffer, unsigned int const size, lua_State *state, int index) +{ + if (luabind::detail::is_class_object(state, index)) { + type_convert_class (buffer, size, state, index); + return; + } + + if (type_convert_instance(buffer, size, state, index)) + return; + + sz_cpy (buffer, size, "unrecognized user data"); +} + +bool engine::type_to_string (char* const buffer, unsigned int const size, lua_State* const state, int const index, bool &use_in_description) +{ + switch (lua_type(state, index)) { + case engine::lua_type_string : + case engine::lua_type_table : + case engine::lua_type_nil : + case engine::lua_type_boolean : + case engine::lua_type_number : + case engine::lua_type_function : + case engine::lua_type_coroutine : + return (false); + case engine::lua_type_light_user_data : + case engine::lua_type_user_data : { + type_convert_userdata(buffer, size, state, index); + return (true); + } + default : NODEFAULT; + } // switch (lua_type(state, index)) + +#ifdef DEBUG + return (false); +#endif // #ifdef DEBUG +} + +void engine::fill_class_info (cs::lua_studio::backend& backend, char* const buffer, unsigned int const size, luabind::detail::object_rep *object, luabind::detail::class_rep *class_rep, lua_State* state) +{ + pstr stream = buffer; + + stream += xr_sprintf(stream, size - (stream - buffer), "{"); + + typedef luabind::detail::class_rep::property_map property_map; + property_map::const_iterator I = class_rep->properties().begin(); + property_map::const_iterator E = class_rep->properties().end(); + for (u32 i=0; I != E; ++I) { + if (i == 3) { + stream += xr_sprintf(stream, size - (stream - buffer), "..."); + break; + } + lua_pushstring (state,(*I).first); + lua_insert (state,1); + lua_pushlightuserdata (state,object); + lua_insert (state,1); + (*I).second.func (state,(*I).second.pointer_offset); + + string4096 type; + bool use_in_description; + backend.type_to_string (type, sizeof(type), state, -1, use_in_description); + + string4096 value; + cs::lua_studio::icon_type icon_type; + backend.value_to_string (value, sizeof(value), state, -1, icon_type, false); + + lua_pop_value (state,1); + lua_remove (state,1); + lua_remove (state,1); + + if (use_in_description) + stream += xr_sprintf(stream, size - (stream - buffer), "%s[%s]=%s ", (*I).first, type, value); + else + stream += xr_sprintf(stream, size - (stream - buffer), "%s=%s ", (*I).first, value); + + ++i; + } + + stream += xr_sprintf(stream, size - (stream - buffer), "}%c",0); +} + +void engine::value_convert_class (cs::lua_studio::backend& backend, char* buffer, unsigned int size, luabind::detail::class_rep *class_rep, lua_State* state, int index, cs::lua_studio::icon_type& icon_type, bool const full_description) +{ + icon_type = cs::lua_studio::icon_type_class; + + if (!full_description) { + sz_cpy (buffer, size, "{...}"); + return; + } + + if (!class_rep->bases().empty()) { + sz_cpy (buffer, size, "{...}"); + return; + } + + if (class_rep->properties().empty()) { + sz_cpy (buffer, size, "{}"); + return; + } + + luabind::detail::object_rep *object = luabind::detail::is_class_object(state, index); + if (!object) { + sz_cpy (buffer, size, "{...}"); + return; + } + + fill_class_info (backend, buffer, size, object, class_rep, state); +} + +bool engine::value_convert_instance (cs::lua_studio::backend& backend, char* buffer, unsigned int size, luabind::detail::object_rep *object, lua_State* state) +{ + typedef luabind::detail::lua_reference lua_reference; + lua_reference const &tbl = object->get_lua_table(); + if (!tbl.is_valid()) + return (false); + + pstr stream = buffer; + stream += xr_sprintf(stream, size - (stream - buffer), "{"); + + tbl.get (state); + int i; + lua_pushnil (state); + for (i=0; lua_next(state,-2); ++i) { + if (i == 3) { + lua_pop_value (state, 2); + stream += xr_sprintf(stream, size - (stream - buffer), "..."); + break; + } + + pcstr name = lua_to_string(state,-2); + + string4096 type; + bool use_in_description; + backend.type_to_string (type, sizeof(type), state, -1, use_in_description); + + string4096 value; + cs::lua_studio::icon_type icon_type; + backend.value_to_string (value, sizeof(value), state, -1, icon_type, false); + + if (use_in_description) + stream += xr_sprintf(stream, size - (stream - buffer), "%s[%s]=%s ", name, type, value); + else + stream += xr_sprintf(stream, size - (stream - buffer), "%s=%s ", name, value); + + lua_pop_value (state, 1); + } + + lua_pop_value (state, 1); + + if (!i) + return (false); + + stream += xr_sprintf(stream, size - (stream - buffer), "}%c",0); + + return (true); +} + +bool engine::value_convert_instance (cs::lua_studio::backend& backend, char* buffer, unsigned int size, lua_State* state, int index, cs::lua_studio::icon_type& icon_type, bool full_description) +{ + luabind::detail::object_rep *object = luabind::detail::is_class_object(state, index); + if (!object) + return (false); + + if (full_description && !value_convert_instance(backend, buffer, size, object, state)) + value_convert_class (backend, buffer, size, object->crep(), state, index, icon_type, full_description); + else + sz_cpy (buffer, size, " "); + + icon_type = cs::lua_studio::icon_type_class_instance; + + return (true); +} + +bool engine::value_to_string (cs::lua_studio::backend& backend, char* const buffer, unsigned int const size, lua_State* const state, int const index, cs::lua_studio::icon_type& icon_type, bool const full_description) +{ + switch (lua_type(state, index)) { + case engine::lua_type_string : + case engine::lua_type_table : + case engine::lua_type_nil : + case engine::lua_type_boolean : + case engine::lua_type_number : + case engine::lua_type_function : + case engine::lua_type_coroutine : + return (false); + case engine::lua_type_light_user_data : + case engine::lua_type_user_data : { + if (!luabind::detail::is_class_object( state, index )) { + if (!is_luabind_class(state, index)) { + icon_type = cs::lua_studio::icon_type_unknown; + pcvoid user_data = lua_topointer(state, index); + xr_sprintf (buffer, size, "0x%08x", *(u32 const*)&user_data); + return (true); + } + + luabind::detail::class_rep *class_rep = static_cast(lua_touserdata(state,index)); + VERIFY (class_rep); + value_convert_class (backend, buffer, size, class_rep, state, index, icon_type, full_description); + return (true); + } + + if (value_convert_instance(backend, buffer, size, state, index, icon_type, full_description)) + return (true); + + icon_type = cs::lua_studio::icon_type_unknown; + pcvoid user_data = lua_topointer(state, index); + xr_sprintf (buffer, size, "0x%08x", *(u32 const*)&user_data); + return (true); + } + default : NODEFAULT; + } // switch (lua_type(state, index)) + +#ifdef DEBUG + return (false); +#endif // #ifdef DEBUG +} + +void engine::push_class (lua_State* const state, char const* const id) +{ + luabind::detail::object_rep *object = luabind::detail::is_class_object(state, -1); + VERIFY (object); + + luabind::detail::class_rep *class_rep = object->crep(); + R_ASSERT2 (class_rep, "null class userdata"); + + R_ASSERT (!sz_cmp(class_rep->name(), id)); + lua_pushlightuserdata (state, class_rep); +} + +void engine::push_class_base (lua_State* const state, char const* const id) +{ + luabind::detail::class_rep *class_rep = static_cast(lua_touserdata(state,-1)); + VERIFY (class_rep); + + typedef luabind::detail::class_rep::base_info base_info; + typedef vector_class Bases; + Bases const &bases = class_rep->bases(); + Bases::const_iterator I = bases.begin(); + Bases::const_iterator E = bases.end(); + for ( ; I != E; ++I) { + pcstr name = (*I).base->name(); + if (sz_cmp(id,name)) + continue; + + lua_pop_value (state, 1); + lua_pushlightuserdata (state, (*I).base); + return; + } + + NODEFAULT; +} + +void engine::push_class_instance (lua_State* const state, char const* const id) +{ + luabind::detail::object_rep *object = luabind::detail::is_class_object(state, -1); + if (!object) { + lua_pop_value (state, 1); + object = luabind::detail::is_class_object(state, -1); + VERIFY (object); + } + + lua_insert (state, 1); + lua_pushstring (state, id); + lua_insert (state, 2); + object->crep()->gettable (state); + lua_remove (state, 2); + lua_pushvalue (state, 1); + lua_remove (state, 1); + lua_pushvalue (state, -2); + lua_remove (state, -3); + lua_remove (state, -2); +} + +void engine::push_user_data (lua_State* const state, char const* const id, cs::lua_studio::icon_type const icon_type) +{ + switch (icon_type) { + case cs::lua_studio::icon_type_class : { + push_class (state, id); + break; + } + case cs::lua_studio::icon_type_class_base : { + push_class_base (state, id); + break; + } + case cs::lua_studio::icon_type_unknown : + case cs::lua_studio::icon_type_table : + case cs::lua_studio::icon_type_class_instance : { + push_class_instance (state, id); + break; + } + default : NODEFAULT; + } +} + +bool engine::push_value (lua_State* const state, char const* const id, cs::lua_studio::icon_type const icon_type) +{ + switch ( lua_type( state, -1 ) ) { + case engine::lua_type_table : + return (false); + case engine::lua_type_light_user_data : + case engine::lua_type_user_data : { + push_user_data (state, id, icon_type); + return (true); + } + default : NODEFAULT; + } +#ifdef DEBUG + return (false); +#endif // #ifdef DEBUG +} + +void engine::fill_class_data ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value_to_expand, + lua_State* const state + ) +{ + luabind::detail::object_rep *object = static_cast(lua_touserdata(state,-2)); + luabind::detail::class_rep *_class = static_cast(lua_touserdata(state,-1)); + R_ASSERT2 (_class, "invalid class userdata"); + + { + string4096 type; + typedef luabind::detail::class_rep::base_info base_info; + vector_class::const_iterator i = _class->bases().begin(); + vector_class::const_iterator e = _class->bases().end(); + for ( ; i != e; ++i) + value_to_expand.add_value ( + (*i).base->name(), + class_name(type, sizeof(type), *(*i).base), + "{...}", + cs::lua_studio::icon_type_class_base + ); + } + + if (!object) + return; + + typedef luabind::detail::class_rep::property_map property_map; + property_map::const_iterator i = _class->properties().begin(); + property_map::const_iterator e = _class->properties().end(); + for ( ; i != e; ++i) { + lua_pushstring (state,(*i).first); + lua_insert (state,1); + lua_pushlightuserdata (state,object); + lua_insert (state,1); + (*i).second.func (state, (*i).second.pointer_offset); + + bool use_in_description; + + string4096 type; + backend.type_to_string (type, sizeof(type), state, -1, use_in_description); + + cs::lua_studio::icon_type icon_type; + string4096 value; + backend.value_to_string (value, sizeof(value), state, -1, icon_type, true); + + lua_pop_value (state,1); + lua_remove (state,1); + lua_remove (state,1); + + value_to_expand.add_value ( + (*i).first, + type, + value, + icon_type + ); + } +} + +void engine::expand_class ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value, + lua_State* const state + ) +{ + int start = lua_gettop(state); + + luabind::detail::class_rep *class_object = static_cast(lua_touserdata(state,-1)); + R_ASSERT2 (class_object, "invalid class userdata"); + + fill_class_data (backend, value, state); + + luabind::detail::object_rep *object = luabind::detail::is_class_object(state,-2); + if (!object) + lua_pushnil (state); + + if (lua_gettop(state) <= start + 1) + return; + + lua_pop_value (state,1); +} + +void engine::expand_class_instance ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value_to_expand, + lua_State* const state + ) +{ + typedef luabind::detail::object_rep object_rep; + object_rep *object = luabind::detail::is_class_object(state,-1); + VERIFY2 (object, "invalid object userdata"); + + if (object->crep()) { + luabind::detail::class_rep *class_rep = object->crep(); + + string4096 type; + class_name (type, sizeof(type), *class_rep); + + cs::lua_studio::icon_type icon_type; + string4096 value; + backend.value_to_string (value, sizeof(value), state, -1, icon_type, true); + value_to_expand.add_value ( + class_rep->name(), + type, + value, + cs::lua_studio::icon_type_class + ); + } + + typedef luabind::detail::lua_reference lua_reference; + lua_reference const &tbl = object->get_lua_table(); + if (!tbl.is_valid()) + return; + + tbl.get (state); + int i; + lua_pushnil (state); + for (i=0; lua_next(state,-2); ++i) { + cs::lua_studio::icon_type icon_type; + bool use_in_description; + pcstr name = lua_to_string(state,-2); + + string4096 type; + backend.type_to_string (type, sizeof(type), state, -1, use_in_description); + + string4096 value; + backend.value_to_string (value, sizeof(value), state, -1, icon_type, true); + value_to_expand.add_value ( + name, + type, + value, + icon_type + ); + + lua_pop_value (state, 1); + } + + lua_pop_value (state, 1); +} + +void engine::expand_user_data ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value, + lua_State* const state + ) +{ + luabind::detail::object_rep *object = luabind::detail::is_class_object(state,-1); + if (object) { + expand_class_instance (backend, value, state); + lua_pop_value (state, 1); + return; + } + + expand_class (backend, value, state); + lua_pop_value (state, 2); +} + +bool engine::expand_value ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value, + lua_State* const state + ) +{ + switch (lua_type(state, -1)) { + case engine::lua_type_nil : + case engine::lua_type_table : + return (false); + case engine::lua_type_light_user_data : + case engine::lua_type_user_data : { + expand_user_data( backend, value, state ); + return (true); + } + default : NODEFAULT; + } + +#ifdef DEBUG + return (false); +#endif // #ifdef DEBUG +} + +engine::engine () : + m_instance_count(0) +{ +} \ No newline at end of file diff --git a/xrServerEntities/lua_studio.h b/xrServerEntities/lua_studio.h new file mode 100644 index 00000000000..82e3ac859ba --- /dev/null +++ b/xrServerEntities/lua_studio.h @@ -0,0 +1,141 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : lua_studio.h +// Created : 21.08.2008 +// Modified : 21.08.2008 +// Author : Dmitriy Iassenev +// Description : lua studio engine class (copied from the lua studio SDK) +//////////////////////////////////////////////////////////////////////////// + +#ifndef LUA_STUDIO_H_INCLUDED +#define LUA_STUDIO_H_INCLUDED + +#ifdef DEBUG +# define CS_LUA_DEBUGGER_USE_DEBUG_LIBRARY +#endif// #ifdef DEBUG + +#include +#include + +namespace luabind { + namespace detail { + class class_rep; + } // namespace detail +} // namespace luabind + +class lua_studio_engine : + public cs::lua_studio::engine, + private boost::noncopyable +{ +public: + virtual int CS_LUA_STUDIO_BACKEND_CALL luaL_loadstring (lua_State *L, const char *s); + virtual int CS_LUA_STUDIO_BACKEND_CALL luaL_newmetatable (lua_State *L, const char *tname); + +public: + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_createtable (lua_State *L, int narray, int nrec); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_sethook (lua_State *L, lua_Hook func, lua_mask_type mask, int count); + virtual lua_Hook CS_LUA_STUDIO_BACKEND_CALL lua_gethook (lua_State *L); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_getfenv (lua_State *L, int idx); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_getfield (lua_State *L, int idx, const char *k); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_getlocal (lua_State *L, const lua_Debug *ar, int n); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_gettable (lua_State *L, int idx); + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_getstack (lua_State *L, int level, lua_Debug *ar); + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_gettop (lua_State *L); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_getupvalue (lua_State *L, int funcindex, int n); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_iscfunction (lua_State *L, int idx); + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_next (lua_State *L, int idx); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); + + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_pushnil (lua_State *L); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_pushstring (lua_State *L, const char *s); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_pushvalue (lua_State *L, int idx); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_pushnumber (lua_State *L, lua_Number idx); + + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_remove (lua_State *L, int idx); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_replace (lua_State *L, int idx); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_setfenv (lua_State *L, int idx); + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_setmetatable (lua_State *L, int objindex); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_settable (lua_State *L, int idx); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_settop (lua_State *L, int idx); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_toboolean (lua_State *L, int idx); + virtual lua_Integer CS_LUA_STUDIO_BACKEND_CALL lua_tointeger (lua_State *L, int idx); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_tolstring (lua_State *L, int idx, size_t *len); + virtual lua_Number CS_LUA_STUDIO_BACKEND_CALL lua_tonumber (lua_State *L, int idx); + virtual const void* CS_LUA_STUDIO_BACKEND_CALL lua_topointer (lua_State *L, int idx); + + virtual bool CS_LUA_STUDIO_BACKEND_CALL lua_isnumber (lua_State *L, int idx); + + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_type (lua_State *L, int idx); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_typename (lua_State *L, int t); + +public: + virtual lua_Debug* CS_LUA_STUDIO_BACKEND_CALL lua_debug_create (); + virtual void CS_LUA_STUDIO_BACKEND_CALL lua_debug_destroy (lua_Debug*& instance); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_debug_get_name (lua_Debug& instance); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_debug_get_source (lua_Debug& instance); + virtual char const* CS_LUA_STUDIO_BACKEND_CALL lua_debug_get_short_source (lua_Debug& instance); + virtual int CS_LUA_STUDIO_BACKEND_CALL lua_debug_get_current_line (lua_Debug& instance); + +public: + virtual void CS_LUA_STUDIO_BACKEND_CALL log (log_message_types message_type, char const* message); + virtual bool CS_LUA_STUDIO_BACKEND_CALL type_to_string (char* buffer, unsigned int size, lua_State* state, int index, bool& use_in_description); + virtual bool CS_LUA_STUDIO_BACKEND_CALL value_to_string (cs::lua_studio::backend& backend, char* buffer, unsigned int size, lua_State* state, int index, cs::lua_studio::icon_type& icon_type, bool full_description); + virtual bool CS_LUA_STUDIO_BACKEND_CALL expand_value (cs::lua_studio::backend& backend, cs::lua_studio::value_to_expand& value, lua_State* state); + virtual bool CS_LUA_STUDIO_BACKEND_CALL push_value (lua_State* state, char const* id, cs::lua_studio::icon_type icon_type); + +public: + lua_studio_engine (); + +private: + void type_convert_class (char *buffer, unsigned int size, lua_State *state, int index); + bool type_convert_instance (char *buffer, unsigned int size, lua_State *state, int index); + void type_convert_userdata (char *buffer, unsigned int size, lua_State *state, int index); + static char* class_name (char *buffer, unsigned int size, luabind::detail::class_rep& class_rep); + +private: + void fill_class_info (cs::lua_studio::backend& backend, char* buffer, unsigned int size, luabind::detail::object_rep *object, luabind::detail::class_rep *class_rep, lua_State* state); + void value_convert_class (cs::lua_studio::backend& backend, char* buffer, unsigned int size, luabind::detail::class_rep* class_rep, lua_State* state, int index, cs::lua_studio::icon_type& icon_type, bool full_description); + bool value_convert_instance (cs::lua_studio::backend& backend, char* buffer, unsigned int size, luabind::detail::object_rep* object, lua_State* state); + bool value_convert_instance (cs::lua_studio::backend& backend, char* buffer, unsigned int size, lua_State* state, int index, cs::lua_studio::icon_type& icon_type, bool full_description); + +private: + void push_class (lua_State* state, char const* id); + void push_class_base (lua_State* state, char const* id); + void push_class_instance (lua_State* state, char const* id); + void push_user_data (lua_State* state, char const* id, cs::lua_studio::icon_type icon_type); + +private: + void fill_class_data ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value_to_expand, + lua_State* const state + ); + void expand_class ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value, + lua_State* const state + ); + void expand_class_instance ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value_to_expand, + lua_State* const state + ); + void expand_user_data ( + cs::lua_studio::backend& backend, + cs::lua_studio::value_to_expand& value, + lua_State* const state + ); + +private: + lua_Debug m_instances[2]; + u32 m_instance_count; +}; + +#endif // #ifndef LUA_STUDIO_H_INCLUDED \ No newline at end of file diff --git a/xrServerEntities/mslotutils.h b/xrServerEntities/mslotutils.h new file mode 100644 index 00000000000..7a2c2d1b332 --- /dev/null +++ b/xrServerEntities/mslotutils.h @@ -0,0 +1,175 @@ +#pragma once + +#if XRGAME_EXPORTS | XRSE_FACTORY_EXPORTS +# define _memcpy CopyMemory +# define _memset Memory.mem_fill +# define _strlen xr_strlen +#else +# define _memcpy memcpy +# define _memset memset +# define _strlen strlen +#endif + +class CMailSlotMsg { + char m_buff [2048]; + DWORD m_len; + int m_pos; + inline void Read(void* dst, int sz){ + _memcpy(dst,(void*)(&m_buff[0]+m_pos),sz); + m_pos +=sz;}; + inline void Write(const void* src, int sz){ + _memcpy((void*)(&m_buff[0]+m_pos),src,sz); + m_pos +=sz; m_len=m_pos; }; + +public: + CMailSlotMsg(){Reset();}; + inline void Reset(){ m_len=0; m_pos=0; _memset(m_buff,0,2048);}; + inline void SetBuffer(const char* b, int sz){Reset(); _memcpy(m_buff,b,sz); m_len=sz; m_pos=0;}; + inline void* GetBuffer(){return m_buff;}; + inline void SetLen(DWORD l){m_len=l;}; + inline DWORD GetLen()const{return m_len;}; + + inline BOOL r_string(char* dst){ + int sz; + r_int(sz); + Read(dst,sz+1); + return TRUE; + }; + + inline BOOL w_string(const char* dst){ + size_t sz = _strlen(dst); + w_int((int)sz); + Write(dst,(int)(sz+1)); return TRUE; + }; + + inline BOOL r_float(float& dst){ + Read(&dst,sizeof(float)); + return TRUE; + }; + + inline BOOL w_float(const float src){ + Write(&src,sizeof(float)); + return TRUE; + }; + + inline BOOL r_int(int& dst){ + Read(&dst,sizeof(int)); + return TRUE; + }; + + inline BOOL w_int(const int src){ + Write(&src,sizeof(int)); + return TRUE; + }; + + inline BOOL r_buff(void* dst, int sz){ + Read(dst,sz); + return TRUE; + }; + + inline BOOL w_buff(void* src, int sz){ + Write(src,sz); + return TRUE; + }; +}; + +inline HANDLE CreateMailSlotByName(LPSTR slotName) +{ + HANDLE hSlot = CreateMailslot(slotName, + 0, // no maximum message size + MAILSLOT_WAIT_FOREVER, // no time-out for operations + (LPSECURITY_ATTRIBUTES) NULL); // no security attributes + + return hSlot; +} +inline BOOL CheckExisting(LPSTR slotName) +{ + HANDLE hFile; + BOOL res; +hFile = CreateFile(slotName, + GENERIC_WRITE, + FILE_SHARE_READ, // required to write to a mailslot + (LPSECURITY_ATTRIBUTES) NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + (HANDLE) NULL); + + res = (hFile != INVALID_HANDLE_VALUE); + + if(res) + CloseHandle(hFile); + + return res; +} +inline BOOL SendMailslotMessage(LPSTR slotName, CMailSlotMsg& msg){ + BOOL fResult; + HANDLE hFile; + DWORD cbWritten; + +hFile = CreateFile(slotName, + GENERIC_WRITE, + FILE_SHARE_READ, // required to write to a mailslot + (LPSECURITY_ATTRIBUTES) NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + (HANDLE) NULL); + + R_ASSERT (hFile != INVALID_HANDLE_VALUE); + + if (hFile == INVALID_HANDLE_VALUE) + return false; + + +fResult = WriteFile(hFile, + msg.GetBuffer(), + msg.GetLen(), + &cbWritten, + (LPOVERLAPPED) NULL); + + R_ASSERT(fResult); + fResult = CloseHandle(hFile); + R_ASSERT(fResult); + return fResult; +} + +inline BOOL CheckMailslotMessage(HANDLE hSlot, CMailSlotMsg& msg){ + DWORD cbMessage, cMessage, cbRead; + BOOL fResult; + HANDLE hEvent; + OVERLAPPED ov; + + cbMessage = cMessage = cbRead = 0; + + hEvent = CreateEvent(NULL, FALSE, FALSE, "__Slot"); + if( NULL == hEvent ) + return FALSE; + ov.Offset = 0; + ov.OffsetHigh = 0; + ov.hEvent = hEvent; + + + fResult = GetMailslotInfo(hSlot, // mailslot handle + (LPDWORD) NULL, // no maximum message size + &cbMessage, // size of next message + &cMessage, // number of messages + (LPDWORD) NULL); // no read time-out + + R_ASSERT(fResult); + + if (!fResult || cbMessage == MAILSLOT_NO_MESSAGE) { + CloseHandle(hEvent); + return false; + } + + msg.Reset(); + fResult = ReadFile(hSlot, + msg.GetBuffer(), + cbMessage, + &cbRead, + &ov); + msg.SetLen(cbRead); + R_ASSERT(fResult); + + CloseHandle(hEvent); + return fResult; +} \ No newline at end of file diff --git a/xrServerEntities/object_broker.h b/xrServerEntities/object_broker.h new file mode 100644 index 00000000000..8e51caea4a0 --- /dev/null +++ b/xrServerEntities/object_broker.h @@ -0,0 +1,18 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : object_broker.h +// Created : 21.01.2003 +// Modified : 12.05.2004 +// Author : Dmitriy Iassenev +// Description : Object broker +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include "object_interfaces.h" +#include "object_type_traits.h" +#include "object_comparer.h" +#include "object_cloner.h" +#include "object_destroyer.h" +#include "object_loader.h" +#include "object_saver.h" diff --git a/xrServerEntities/object_cloner.h b/xrServerEntities/object_cloner.h new file mode 100644 index 00000000000..6d2a850a0ec --- /dev/null +++ b/xrServerEntities/object_cloner.h @@ -0,0 +1,188 @@ +//////////////////////////////////////////////////////////////////////////// +// Module : object_cloner.h +// Created : 13.07.2004 +// Modified : 13.07.2004 +// Author : Dmitriy Iassenev +// Description : Object cloner +//////////////////////////////////////////////////////////////////////////// + +#pragma once + +struct CCloner { + template + struct CHelper { + template + IC static void clone(const T &_1, T &_2) + { + _2 = _1; + } + + template <> + IC static void clone(const T &_1, T &_2) + { + _2 = xr_new::type>(*_1); + CCloner::clone (*_1,*_2); + } + }; + + IC static void clone(LPCSTR _1, LPCSTR &_2) + { + _2 = _1; + } + + IC static void clone(LPSTR _1, LPSTR &_2) + { + _2 = xr_strdup(_1); + } + + IC static void clone(const shared_str &_1, shared_str &_2) + { + _2 = _1; + } + + template + IC static void clone(const std::pair &_1, std::pair &_2) + { + clone(const_cast::type&>(_1.first),const_cast::type&>(_2.first)); + clone(_1.second,_2.second); + } + + template + IC static void clone(const svector &_1, svector &_2) + { + _2.resize (_1.size()); + svector::iterator J = _2.begin(); + svector::const_iterator I = _1.begin(); + svector::const_iterator E = _1.end(); + for ( ; I != E; ++I, ++J) + clone (*I,*J); + } + + template + IC static void clone(const std::queue &__1, std::queue &__2) + { + std::queue _1 = __1; + std::queue _2; + + for ( ; !_1.empty(); _1.pop()) + _2.push (_1.front()); + + while (!__2.empty()) + __2.pop(); + + for ( ; !_2.empty(); _2.pop()) { + std::queue::value_type t; + CCloner::clone (_2.front(),t); + __2.push (t); + } + } + + template